Code

Fix clipping for Cairo generated PNG's.
[inkscape.git] / src / text-context.cpp
index 4e1fa87e160c7ac808ce3c84db0d1905e0dee985..4c3329fb72e73e8fdaf74dd150f6d9679382231b 100644 (file)
@@ -182,7 +182,7 @@ sp_text_context_dispose(GObject *obj)
         tc->grabbed = NULL;
     }
 
-    Inkscape::Rubberband::get()->stop();
+    Inkscape::Rubberband::get(ec->desktop)->stop();
 
     if (ec->shape_knot_holder) {
         delete ec->shape_knot_holder;
@@ -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) {
@@ -437,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);
                 }
@@ -613,10 +613,9 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
 
                 NR::Point const button_pt(event->button.x, event->button.y);
                 tc->p0 = desktop->w2d(button_pt);
-                Inkscape::Rubberband::get()->start(desktop, tc->p0);
+                Inkscape::Rubberband::get(desktop)->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;
@@ -650,7 +649,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                 NR::Point const motion_pt(event->motion.x, event->motion.y);
                 NR::Point const p = desktop->w2d(motion_pt);
 
-                Inkscape::Rubberband::get()->move(p);
+                Inkscape::Rubberband::get(desktop)->move(p);
                 gobble_motion_events(GDK_BUTTON1_MASK);
 
                 // status text
@@ -670,7 +669,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                     tc->grabbed = NULL;
                 }
 
-                Inkscape::Rubberband::get()->stop();
+                Inkscape::Rubberband::get(desktop)->stop();
 
                 if (tc->creating && event_context->within_tolerance) {
                     /* Button 1, set X & Y & new item */
@@ -810,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) {
@@ -1011,8 +1020,11 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                         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;
                                     }
                                 }
@@ -1033,8 +1045,11 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                         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;
                                     }
                                 }
@@ -1056,8 +1071,11 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                                                _("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;
                                     }
                                 }
@@ -1079,8 +1097,11 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                                                _("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;
                                     }
                                 }
@@ -1089,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;
@@ -1099,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;
@@ -1112,7 +1151,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                                         sp_canvas_item_ungrab(tc->grabbed, GDK_CURRENT_TIME);
                                         tc->grabbed = NULL;
                                     }
-                                    Inkscape::Rubberband::get()->stop();
+                                    Inkscape::Rubberband::get(desktop)->stop();
                                 } else {
                                     sp_desktop_selection(desktop)->clear();
                                 }
@@ -1218,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) {
@@ -1247,7 +1283,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons
                             sp_canvas_item_ungrab(tc->grabbed, GDK_CURRENT_TIME);
                             tc->grabbed = NULL;
                         }
-                        Inkscape::Rubberband::get()->stop();
+                        Inkscape::Rubberband::get(desktop)->stop();
                     }
                 }
             }
@@ -1286,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>
@@ -1513,9 +1575,12 @@ sp_text_context_update_cursor(SPTextContext *tc,  bool scroll_to_see)
 
         // 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);
@@ -1534,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);
                 }
@@ -1573,11 +1638,13 @@ static void sp_text_context_update_text_selection(SPTextContext *tc)
 
     std::vector<NR::Point> quads;
     if (tc->text != NULL)
-        quads = sp_te_create_selection_quads(tc->text, tc->text_sel_start, tc->text_sel_end, from_2geom(sp_item_i2d_affine(tc->text)));
+        quads = sp_te_create_selection_quads(tc->text, tc->text_sel_start, tc->text_sel_end, sp_item_i2d_affine(tc->text));
     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);