Code

remove many unnecessary to_2geom and from_2geom calls
[inkscape.git] / src / text-context.cpp
index 8f6d6f1e379ca16f6836d404382bfde68db48a09..6d26bee2b98422b0bbc92dc5330c91da7f0b893c 100644 (file)
@@ -185,7 +185,7 @@ sp_text_context_dispose(GObject *obj)
     Inkscape::Rubberband::get()->stop();
 
     if (ec->shape_knot_holder) {
-        sp_knot_holder_destroy(ec->shape_knot_holder);
+        delete ec->shape_knot_holder;
         ec->shape_knot_holder = NULL;
     }
     if (ec->shape_repr) { // remove old listener
@@ -224,7 +224,7 @@ sp_text_context_setup(SPEventContext *ec)
     SP_CTRLRECT(tc->frame)->setColor(0x0000ff7f, false, 0);
     sp_canvas_item_hide(tc->frame);
 
-    tc->timeout = gtk_timeout_add(250, (GtkFunction) sp_text_context_timeout, ec);
+    tc->timeout = gtk_timeout_add(200, (GtkFunction) sp_text_context_timeout, ec);
 
     tc->imc = gtk_im_multicontext_new();
     if (tc->imc) {
@@ -429,6 +429,7 @@ sp_text_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEve
                     sp_text_context_update_cursor(tc);
                     sp_text_context_update_text_selection(tc);
                 }
+                gobble_motion_events(GDK_BUTTON1_MASK);
                 ret = TRUE;
                 break;
             }
@@ -436,7 +437,7 @@ sp_text_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEve
             item_ungrouped = desktop->item_at_point(NR::Point(event->button.x, event->button.y), TRUE);
             if (SP_IS_TEXT(item_ungrouped) || SP_IS_FLOWTEXT(item_ungrouped)) {
                 sp_canvas_item_show(tc->indicator);
-                NR::Maybe<NR::Rect> ibbox = sp_item_bbox_desktop(item_ungrouped);
+                boost::optional<NR::Rect> ibbox = sp_item_bbox_desktop(item_ungrouped);
                 if (ibbox) {
                     SP_CTRLRECT(tc->indicator)->setRectangle(*ibbox);
                 }
@@ -503,7 +504,7 @@ sp_text_context_setup_text(SPTextContext *tc)
     Inkscape::GC::release(rtext);
     text_item->transform = SP_ITEM(ec->desktop->currentRoot())->getRelativeTransform(ec->desktop->currentLayer());
     text_item->updateRepr();
-    sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, 
+    sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT,
                      _("Create text"));
 }
 
@@ -542,7 +543,7 @@ insert_uni_char(SPTextContext *const tc)
         tc->text_sel_start = tc->text_sel_end = sp_te_replace(tc->text, tc->text_sel_start, tc->text_sel_end, u);
         sp_text_context_update_cursor(tc);
         sp_text_context_update_text_selection(tc);
-        sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_DIALOG_TRANSFORM, 
+        sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_DIALOG_TRANSFORM,
                          _("Insert Unicode character"));
     }
 }
@@ -614,8 +615,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                 tc->p0 = desktop->w2d(button_pt);
                 Inkscape::Rubberband::get()->start(desktop, tc->p0);
                 sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
-                                    GDK_KEY_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK |
-                                        GDK_POINTER_MOTION_MASK,
+                                    GDK_KEY_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK,
                                     NULL, event->button.time);
                 tc->grabbed = SP_CANVAS_ITEM(desktop->acetate);
                 tc->creating = 1;
@@ -655,7 +655,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                 // status text
                 GString *xs = SP_PX_TO_METRIC_STRING(fabs((p - tc->p0)[NR::X]), desktop->namedview->getDefaultMetric());
                 GString *ys = SP_PX_TO_METRIC_STRING(fabs((p - tc->p0)[NR::Y]), desktop->namedview->getDefaultMetric());
-                event_context->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("<b>Flowed text frame</b>: %s &#215; %s"), xs->str, ys->str);
+                event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Flowed text frame</b>: %s &#215; %s"), xs->str, ys->str);
                 g_string_free(xs, FALSE);
                 g_string_free(ys, FALSE);
 
@@ -701,7 +701,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                         sp_desktop_apply_style_tool(desktop, SP_OBJECT_REPR(ft), "tools.text", true);
                         sp_desktop_selection(desktop)->set(ft);
                         desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Flowed text is created."));
-                        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, 
+                        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT,
                                          _("Create flowed text"));
                     } else {
                         desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The frame is <b>too small</b> for the current font size. Flowed text not created."));
@@ -809,7 +809,17 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                             }
                         }
 
-                        bool (Inkscape::Text::Layout::iterator::*cursor_movement_operator)() = NULL;
+                        Inkscape::Text::Layout::iterator old_start = tc->text_sel_start;
+                        Inkscape::Text::Layout::iterator old_end = tc->text_sel_end;
+                        bool cursor_moved = false;
+                        int screenlines = 1;
+                        if (tc->text) {
+                            double spacing = sp_te_get_average_linespacing(tc->text);
+                            NR::Rect const d = desktop->get_display_area();
+                            screenlines = (int) floor(fabs(d.min()[NR::Y] - d.max()[NR::Y])/spacing) - 1;
+                            if (screenlines <= 0)
+                                screenlines = 1;
+                        }
 
                         /* Neither unimode nor IM consumed key; process text tool shortcuts */
                         switch (group0_keyval) {
@@ -831,7 +841,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                     sp_text_context_update_cursor(tc);
                                     sp_text_context_update_text_selection(tc);
                                     desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("No-break space"));
-                                    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, 
+                                    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT,
                                                      _("Insert no-break space"));
                                     return TRUE;
                                 }
@@ -868,7 +878,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                         sp_repr_css_set_property(css, "font-weight", "normal");
                                     sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css);
                                     sp_repr_css_attr_unref(css);
-                                    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, 
+                                    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT,
                                                      _("Make bold"));
                                     sp_text_context_update_cursor(tc);
                                     sp_text_context_update_text_selection(tc);
@@ -886,7 +896,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                         sp_repr_css_set_property(css, "font-style", "normal");
                                     sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css);
                                     sp_repr_css_attr_unref(css);
-                                    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, 
+                                    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT,
                                                      _("Make italic"));
                                     sp_text_context_update_cursor(tc);
                                     sp_text_context_update_text_selection(tc);
@@ -915,32 +925,33 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                     sp_text_context_setup_text(tc);
                                     tc->nascent_object = 0; // we don't need it anymore, having created a real <text>
                                 }
-                                
+
                                 iterator_pair enter_pair;
                                 bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, enter_pair);
+                                (void)success; // TODO cleanup
                                 tc->text_sel_start = tc->text_sel_end = enter_pair.first;
-                                
+
                                 tc->text_sel_start = tc->text_sel_end = sp_te_insert_line(tc->text, tc->text_sel_start);
-                                
+
                                 sp_text_context_update_cursor(tc);
                                 sp_text_context_update_text_selection(tc);
-                                sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, 
+                                sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT,
                                                  _("New line"));
                                 return TRUE;
                             }
                             case GDK_BackSpace:
                                 if (tc->text) { // if nascent_object, do nothing, but return TRUE; same for all other delete and move keys
-                                    
+
                                     bool noSelection = false;
-                                    
+
                                        if (tc->text_sel_start == tc->text_sel_end) {
                                         tc->text_sel_start.prevCursorPosition();
                                         noSelection = true;
                                     }
-                                       
+
                                        iterator_pair bspace_pair;
                                        bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, bspace_pair);
-                                    
+
                                     if (noSelection) {
                                         if (success) {
                                             tc->text_sel_start = tc->text_sel_end = bspace_pair.first;
@@ -955,10 +966,10 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                             tc->text_sel_end = bspace_pair.second;
                                         }
                                     }
-                                    
+
                                     sp_text_context_update_cursor(tc);
                                     sp_text_context_update_text_selection(tc);
-                                    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, 
+                                    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT,
                                                      _("Backspace"));
                                 }
                                 return TRUE;
@@ -966,15 +977,15 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                             case GDK_KP_Delete:
                                 if (tc->text) {
                                     bool noSelection = false;
-                                    
+
                                     if (tc->text_sel_start == tc->text_sel_end) {
                                         tc->text_sel_end.nextCursorPosition();
                                         noSelection = true;
                                     }
-                                    
+
                                     iterator_pair del_pair;
                                     bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, del_pair);
-                                    
+
                                     if (noSelection) {
                                         tc->text_sel_start = tc->text_sel_end = del_pair.first;
                                     } else {
@@ -985,11 +996,11 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                             tc->text_sel_end = del_pair.second;
                                         }
                                     }
-                                    
-                                    
+
+
                                     sp_text_context_update_cursor(tc);
                                     sp_text_context_update_text_selection(tc);
-                                    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, 
+                                    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT,
                                                      _("Delete"));
                                 }
                                 return TRUE;
@@ -998,17 +1009,22 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                             case GDK_KP_4:
                                 if (tc->text) {
                                     if (MOD__ALT) {
+                                        gint mul = 1 + gobble_key_events(
+                                            get_group0_keyval(&event->key), 0); // with any mask
                                         if (MOD__SHIFT)
-                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(-10, 0));
+                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(mul*-10, 0));
                                         else
-                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(-1, 0));
+                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(mul*-1, 0));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
-                                        sp_document_maybe_done(sp_desktop_document(desktop), "kern:left", SP_VERB_CONTEXT_TEXT, 
+                                        sp_document_maybe_done(sp_desktop_document(desktop), "kern:left", SP_VERB_CONTEXT_TEXT,
                                                                _("Kern to the left"));
                                     } else {
-                                        cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorLeftWithControl
-                                                                             : &Inkscape::Text::Layout::iterator::cursorLeft;
+                                        if (MOD__CTRL) 
+                                            tc->text_sel_end.cursorLeftWithControl();
+                                        else
+                                            tc->text_sel_end.cursorLeft();
+                                        cursor_moved = true;
                                         break;
                                     }
                                 }
@@ -1018,17 +1034,22 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                             case GDK_KP_6:
                                 if (tc->text) {
                                     if (MOD__ALT) {
+                                        gint mul = 1 + gobble_key_events(
+                                            get_group0_keyval(&event->key), 0); // with any mask
                                         if (MOD__SHIFT)
-                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(10, 0));
+                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(mul*10, 0));
                                         else
-                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(1, 0));
+                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(mul*1, 0));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
-                                        sp_document_maybe_done(sp_desktop_document(desktop), "kern:right", SP_VERB_CONTEXT_TEXT, 
+                                        sp_document_maybe_done(sp_desktop_document(desktop), "kern:right", SP_VERB_CONTEXT_TEXT,
                                                                _("Kern to the right"));
                                     } else {
-                                        cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorRightWithControl
-                                                                             : &Inkscape::Text::Layout::iterator::cursorRight;
+                                        if (MOD__CTRL)
+                                            tc->text_sel_end.cursorRightWithControl();
+                                        else
+                                            tc->text_sel_end.cursorRight();
+                                        cursor_moved = true;
                                         break;
                                     }
                                 }
@@ -1038,18 +1059,23 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                             case GDK_KP_8:
                                 if (tc->text) {
                                     if (MOD__ALT) {
+                                        gint mul = 1 + gobble_key_events(
+                                            get_group0_keyval(&event->key), 0); // with any mask
                                         if (MOD__SHIFT)
-                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(0, -10));
+                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(0, mul*-10));
                                         else
-                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(0, -1));
+                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(0, mul*-1));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
-                                        sp_document_maybe_done(sp_desktop_document(desktop), "kern:up", SP_VERB_CONTEXT_TEXT, 
+                                        sp_document_maybe_done(sp_desktop_document(desktop), "kern:up", SP_VERB_CONTEXT_TEXT,
                                                                _("Kern up"));
 
                                     } else {
-                                        cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorUpWithControl
-                                                                             : &Inkscape::Text::Layout::iterator::cursorUp;
+                                        if (MOD__CTRL)
+                                            tc->text_sel_end.cursorUpWithControl();
+                                        else
+                                            tc->text_sel_end.cursorUp();
+                                        cursor_moved = true;
                                         break;
                                     }
                                 }
@@ -1059,18 +1085,23 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                             case GDK_KP_2:
                                 if (tc->text) {
                                     if (MOD__ALT) {
+                                        gint mul = 1 + gobble_key_events(
+                                            get_group0_keyval(&event->key), 0); // with any mask
                                         if (MOD__SHIFT)
-                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(0, 10));
+                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(0, mul*10));
                                         else
-                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(0, 1));
+                                            sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, NR::Point(0, mul*1));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
-                                        sp_document_maybe_done(sp_desktop_document(desktop), "kern:down", SP_VERB_CONTEXT_TEXT, 
+                                        sp_document_maybe_done(sp_desktop_document(desktop), "kern:down", SP_VERB_CONTEXT_TEXT,
                                                                _("Kern down"));
 
                                     } else {
-                                        cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorDownWithControl
-                                                                             : &Inkscape::Text::Layout::iterator::cursorDown;
+                                        if (MOD__CTRL)
+                                            tc->text_sel_end.cursorDownWithControl();
+                                        else
+                                            tc->text_sel_end.cursorDown();
+                                        cursor_moved = true;
                                         break;
                                     }
                                 }
@@ -1079,9 +1110,10 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                             case GDK_KP_Home:
                                 if (tc->text) {
                                     if (MOD__CTRL)
-                                        cursor_movement_operator = &Inkscape::Text::Layout::iterator::thisStartOfShape;
+                                        tc->text_sel_end.thisStartOfShape();
                                     else
-                                        cursor_movement_operator = &Inkscape::Text::Layout::iterator::thisStartOfLine;
+                                        tc->text_sel_end.thisStartOfLine();
+                                    cursor_moved = true;
                                     break;
                                 }
                                 return TRUE;
@@ -1089,9 +1121,26 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                             case GDK_KP_End:
                                 if (tc->text) {
                                     if (MOD__CTRL)
-                                        cursor_movement_operator = &Inkscape::Text::Layout::iterator::nextStartOfShape;
+                                        tc->text_sel_end.nextStartOfShape();
                                     else
-                                        cursor_movement_operator = &Inkscape::Text::Layout::iterator::thisEndOfLine;
+                                        tc->text_sel_end.thisEndOfLine();
+                                    cursor_moved = true;
+                                    break;
+                                }
+                                return TRUE;
+                            case GDK_Page_Down:
+                            case GDK_KP_Page_Down:
+                                if (tc->text) {
+                                    tc->text_sel_end.cursorDown(screenlines);
+                                    cursor_moved = true;
+                                    break;
+                                }
+                                return TRUE;
+                            case GDK_Page_Up:
+                            case GDK_KP_Page_Up:
+                                if (tc->text) {
+                                    tc->text_sel_end.cursorUp(screenlines);
+                                    cursor_moved = true;
                                     break;
                                 }
                                 return TRUE;
@@ -1121,7 +1170,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                         } else {
                                             sp_te_adjust_rotation(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -90);
                                         }
-                                        sp_document_maybe_done(sp_desktop_document(desktop), "textrot:ccw", SP_VERB_CONTEXT_TEXT, 
+                                        sp_document_maybe_done(sp_desktop_document(desktop), "textrot:ccw", SP_VERB_CONTEXT_TEXT,
                                                                _("Rotate counterclockwise"));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
@@ -1142,7 +1191,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                         } else {
                                             sp_te_adjust_rotation(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 90);
                                         }
-                                        sp_document_maybe_done(sp_desktop_document(desktop), "textrot:cw", SP_VERB_CONTEXT_TEXT, 
+                                        sp_document_maybe_done(sp_desktop_document(desktop), "textrot:cw", SP_VERB_CONTEXT_TEXT,
                                                                 _("Rotate clockwise"));
                                         sp_text_context_update_cursor(tc);
                                         sp_text_context_update_text_selection(tc);
@@ -1159,7 +1208,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                                 sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -10);
                                             else
                                                 sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -1);
-                                            sp_document_maybe_done(sp_desktop_document(desktop), "linespacing:dec", SP_VERB_CONTEXT_TEXT, 
+                                            sp_document_maybe_done(sp_desktop_document(desktop), "linespacing:dec", SP_VERB_CONTEXT_TEXT,
                                                                     _("Contract line spacing"));
 
                                         } else {
@@ -1167,7 +1216,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                                 sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -10);
                                             else
                                                 sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -1);
-                                            sp_document_maybe_done(sp_desktop_document(desktop), "letterspacing:dec", SP_VERB_CONTEXT_TEXT, 
+                                            sp_document_maybe_done(sp_desktop_document(desktop), "letterspacing:dec", SP_VERB_CONTEXT_TEXT,
                                                                     _("Contract letter spacing"));
 
                                         }
@@ -1186,7 +1235,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                                 sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 10);
                                             else
                                                 sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 1);
-                                            sp_document_maybe_done(sp_desktop_document(desktop), "linespacing:inc", SP_VERB_CONTEXT_TEXT, 
+                                            sp_document_maybe_done(sp_desktop_document(desktop), "linespacing:inc", SP_VERB_CONTEXT_TEXT,
                                                                     _("Expand line spacing"));
 
                                         } else {
@@ -1194,7 +1243,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                                 sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 10);
                                             else
                                                 sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 1);
-                                            sp_document_maybe_done(sp_desktop_document(desktop), "letterspacing:inc", SP_VERB_CONTEXT_TEXT, 
+                                            sp_document_maybe_done(sp_desktop_document(desktop), "letterspacing:inc", SP_VERB_CONTEXT_TEXT,
                                                                     _("Expand letter spacing"));
 
                                         }
@@ -1208,10 +1257,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                 break;
                         }
 
-                        if (cursor_movement_operator) {
-                            Inkscape::Text::Layout::iterator old_start = tc->text_sel_start;
-                            Inkscape::Text::Layout::iterator old_end = tc->text_sel_end;
-                            (tc->text_sel_end.*cursor_movement_operator)();
+                        if (cursor_moved) {
                             if (!MOD__SHIFT)
                                 tc->text_sel_start = tc->text_sel_end;
                             if (old_start != tc->text_sel_start || old_end != tc->text_sel_end) {
@@ -1276,10 +1322,36 @@ sp_text_paste_inline(SPEventContext *ec)
         // there is an active text object in this context, or a new object was just created
 
         Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
-        Glib::ustring const text = refClipboard->wait_for_text();
-
-        if (!text.empty()) {
-
+        Glib::ustring const clip_text = refClipboard->wait_for_text();
+        
+        if (!clip_text.empty()) {
+               // Fix for 244940
+               // The XML standard defines the following as valid characters
+               // (Extensible Markup Language (XML) 1.0 (Fourth Edition) paragraph 2.2)
+               // char ::=     #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+               // Since what comes in off the paste buffer will go right into XML, clean
+               // the text here.
+               Glib::ustring text(clip_text);
+               Glib::ustring::iterator itr = text.begin();
+               gunichar paste_string_uchar;
+
+               while(itr != text.end())
+               {
+                   paste_string_uchar = *itr;
+
+                   // Make sure we don't have a control character. We should really check
+                   // for the whole range above... Add the rest of the invalid cases from
+                   // above if we find additional issues
+                   if(paste_string_uchar >= 0x00000020 ||
+                      paste_string_uchar == 0x00000009 ||
+                      paste_string_uchar == 0x0000000A ||
+                      paste_string_uchar == 0x0000000D) {
+                       itr++;
+                   } else {
+                       itr = text.erase(itr);
+                   }
+               }
+               
             if (!tc->text) { // create text if none (i.e. if nascent_object)
                 sp_text_context_setup_text(tc);
                 tc->nascent_object = 0; // we don't need it anymore, having created a real <text>
@@ -1298,7 +1370,7 @@ sp_text_paste_inline(SPEventContext *ec)
                 tc->text_sel_start = tc->text_sel_end = sp_te_insert_line(tc->text, tc->text_sel_start);
                 begin = end + 1;
             }
-            sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, 
+            sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT,
                              _("Paste text"));
 
             return true;
@@ -1338,21 +1410,21 @@ bool sp_text_delete_selection(SPEventContext *ec)
 
     if (tc->text_sel_start == tc->text_sel_end)
         return false;
-    
+
     iterator_pair pair;
     bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, pair);
-    
-    
+
+
     if (success) {
         tc->text_sel_start = tc->text_sel_end = pair.first;
     } else { // nothing deleted
         tc->text_sel_start = pair.first;
         tc->text_sel_end = pair.second;
     }
-    
+
     sp_text_context_update_cursor(tc);
     sp_text_context_update_text_selection(tc);
-    
+
     return true;
 }
 
@@ -1367,7 +1439,7 @@ sp_text_context_selection_changed(Inkscape::Selection *selection, SPTextContext
     SPEventContext *ec = SP_EVENT_CONTEXT(tc);
 
     if (ec->shape_knot_holder) { // destroy knotholder
-        sp_knot_holder_destroy(ec->shape_knot_holder);
+        delete ec->shape_knot_holder;
         ec->shape_knot_holder = NULL;
     }
 
@@ -1409,7 +1481,7 @@ sp_text_context_selection_changed(Inkscape::Selection *selection, SPTextContext
 }
 
 static void
-sp_text_context_selection_modified(Inkscape::Selection *selection, guint flags, SPTextContext *tc)
+sp_text_context_selection_modified(Inkscape::Selection */*selection*/, guint /*flags*/, SPTextContext *tc)
 {
     sp_text_context_update_cursor(tc);
     sp_text_context_update_text_selection(tc);
@@ -1424,7 +1496,7 @@ sp_text_context_style_set(SPCSSAttr const *css, SPTextContext *tc)
         return false;    // will get picked up by the parent and applied to the whole text object
 
     sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css);
-    sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_CONTEXT_TEXT, 
+    sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_CONTEXT_TEXT,
                      _("Set text style"));
     sp_text_context_update_cursor(tc);
     sp_text_context_update_text_selection(tc);
@@ -1459,8 +1531,9 @@ sp_text_context_style_query(SPStyle *style, int property, SPTextContext *tc)
         SPObject const *pos_obj = 0;
         void *rawptr = 0;
         layout->getSourceOfCharacter(it, &rawptr);
+        if (!rawptr || !SP_IS_OBJECT(rawptr))
+            continue;
         pos_obj = SP_OBJECT(rawptr);
-        if (pos_obj == 0) continue;
         while (SP_IS_STRING(pos_obj) && SP_OBJECT_PARENT(pos_obj)) {
            pos_obj = SP_OBJECT_PARENT(pos_obj);   // SPStrings don't have style
         }
@@ -1497,14 +1570,17 @@ sp_text_context_update_cursor(SPTextContext *tc,  bool scroll_to_see)
     if (tc->text) {
         NR::Point p0, p1;
         sp_te_get_cursor_coords(tc->text, tc->text_sel_end, p0, p1);
-        NR::Point const d0 = p0 * sp_item_i2d_affine(SP_ITEM(tc->text));
-        NR::Point const d1 = p1 * sp_item_i2d_affine(SP_ITEM(tc->text));
+        NR::Point const d0 = p0 * from_2geom(sp_item_i2d_affine(SP_ITEM(tc->text)));
+        NR::Point const d1 = p1 * from_2geom(sp_item_i2d_affine(SP_ITEM(tc->text)));
 
         // scroll to show cursor
         if (scroll_to_see) {
-            NR::Point const dm = (d0 + d1) / 2;
-            // unlike mouse moves, here we must scroll all the way at first shot, so we override the autoscrollspeed
-            SP_EVENT_CONTEXT(tc)->desktop->scroll_to_point(&dm, 1.0);
+            NR::Point const center = SP_EVENT_CONTEXT(tc)->desktop->get_display_area().midpoint();
+            if (NR::L2(d0 - center) > NR::L2(d1 - center))
+                // unlike mouse moves, here we must scroll all the way at first shot, so we override the autoscrollspeed
+                SP_EVENT_CONTEXT(tc)->desktop->scroll_to_point(&d0, 1.0);
+            else
+                SP_EVENT_CONTEXT(tc)->desktop->scroll_to_point(&d1, 1.0);
         }
 
         sp_canvas_item_show(tc->cursor);
@@ -1523,7 +1599,7 @@ sp_text_context_update_cursor(SPTextContext *tc,  bool scroll_to_see)
             SPItem *frame = SP_FLOWTEXT(tc->text)->get_frame (NULL); // first frame only
             if (frame) {
                 sp_canvas_item_show(tc->frame);
-                NR::Maybe<NR::Rect> frame_bbox = sp_item_bbox_desktop(frame);
+                boost::optional<NR::Rect> frame_bbox = sp_item_bbox_desktop(frame);
                 if (frame_bbox) {
                     SP_CTRLRECT(tc->frame)->setRectangle(*frame_bbox);
                 }
@@ -1566,7 +1642,9 @@ static void sp_text_context_update_text_selection(SPTextContext *tc)
     for (unsigned i = 0 ; i < quads.size() ; i += 4) {
         SPCanvasItem *quad_canvasitem;
         quad_canvasitem = sp_canvas_item_new(sp_desktop_controls(tc->desktop), SP_TYPE_CTRLQUADR, NULL);
-        sp_ctrlquadr_set_rgba32(SP_CTRLQUADR(quad_canvasitem), 0x000000ff);
+        // FIXME: make the color settable in prefs
+        // for now, use semitrasparent blue, as cairo cannot do inversion :(
+        sp_ctrlquadr_set_rgba32(SP_CTRLQUADR(quad_canvasitem), 0x00777777);
         sp_ctrlquadr_set_coords(SP_CTRLQUADR(quad_canvasitem), quads[i], quads[i+1], quads[i+2], quads[i+3]);
         sp_canvas_item_show(quad_canvasitem);
         tc->text_selection_quads.push_back(quad_canvasitem);
@@ -1594,9 +1672,15 @@ sp_text_context_forget_text(SPTextContext *tc)
 {
     if (! tc->text) return;
     SPItem *ti = tc->text;
+    (void)ti;
     /* We have to set it to zero,
      * or selection changed signal messes everything up */
     tc->text = NULL;
+
+/* FIXME: this automatic deletion when nothing is inputted crashes the XML edittor and also crashes when duplicating an empty flowtext.
+    So don't create an empty flowtext in the first place? Create it when first character is typed.
+    */
+/*
     if ((SP_IS_TEXT(ti) || SP_IS_FLOWTEXT(ti)) && sp_te_input_is_empty(ti)) {
         Inkscape::XML::Node *text_repr=SP_OBJECT_REPR(ti);
         // the repr may already have been unparented
@@ -1605,28 +1689,29 @@ sp_text_context_forget_text(SPTextContext *tc)
         // the XML editor
         if ( text_repr && sp_repr_parent(text_repr) ) {
             sp_repr_unparent(text_repr);
-            sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_CONTEXT_TEXT, 
+            sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_CONTEXT_TEXT,
                      _("Remove empty text"));
         }
     }
+*/
 }
 
 gint
-sptc_focus_in(GtkWidget *widget, GdkEventFocus *event, SPTextContext *tc)
+sptc_focus_in(GtkWidget */*widget*/, GdkEventFocus */*event*/, SPTextContext *tc)
 {
     gtk_im_context_focus_in(tc->imc);
     return FALSE;
 }
 
 gint
-sptc_focus_out(GtkWidget *widget, GdkEventFocus *event, SPTextContext *tc)
+sptc_focus_out(GtkWidget */*widget*/, GdkEventFocus */*event*/, SPTextContext *tc)
 {
     gtk_im_context_focus_out(tc->imc);
     return FALSE;
 }
 
 static void
-sptc_commit(GtkIMContext *imc, gchar *string, SPTextContext *tc)
+sptc_commit(GtkIMContext */*imc*/, gchar *string, SPTextContext *tc)
 {
     if (!tc->text) {
         sp_text_context_setup_text(tc);
@@ -1637,7 +1722,7 @@ sptc_commit(GtkIMContext *imc, gchar *string, SPTextContext *tc)
     sp_text_context_update_cursor(tc);
     sp_text_context_update_text_selection(tc);
 
-    sp_document_done(SP_OBJECT_DOCUMENT(tc->text), SP_VERB_CONTEXT_TEXT, 
+    sp_document_done(SP_OBJECT_DOCUMENT(tc->text), SP_VERB_CONTEXT_TEXT,
                      _("Type text"));
 }