--- orig/src/htmlcursor.c
+++ mod/src/htmlcursor.c
@@ -203,12 +203,12 @@
 
 
 static gboolean
-forward (HTMLCursor *cursor)
+forward (HTMLCursor *cursor, HTMLEngine *engine)
 {
 	gboolean retval;
 
 	retval = TRUE;
-	if (!html_object_cursor_forward (cursor->object, cursor)) {
+	if (!html_object_cursor_forward (cursor->object, cursor, engine)) {
 		HTMLObject *next;
 
 		next = html_object_next_cursor (cursor->object, &cursor->offset);
@@ -237,7 +237,7 @@
 		html_engine_spell_check_range (engine, engine->cursor, engine->cursor);
 
 	cursor->have_target_x = FALSE;
-	retval = forward (cursor);
+	retval = forward (cursor, engine);
 
 	debug_location (cursor);
 
@@ -245,12 +245,12 @@
 }
 
 static gboolean
-backward (HTMLCursor *cursor)
+backward (HTMLCursor *cursor, HTMLEngine *engine)
 {
 	gboolean retval;
 
 	retval = TRUE;
-	if (!html_object_cursor_backward (cursor->object, cursor)) {
+	if (!html_object_cursor_backward (cursor->object, cursor, engine)) {
 		HTMLObject *prev;
 
 		prev = html_object_prev_cursor (cursor->object, &cursor->offset);
@@ -280,7 +280,7 @@
 		html_engine_spell_check_range (engine, engine->cursor, engine->cursor);
 
 	cursor->have_target_x = FALSE;
-	retval = backward (cursor);
+	retval = backward (cursor, engine);
 
 	debug_location (cursor);
 
@@ -340,7 +340,7 @@
 		prev_x = x;
 		prev_y = y;
 
-		if (! backward (cursor))
+		if (! backward (cursor, engine))
 			return FALSE;
 
 		html_object_get_cursor_base (cursor->object,
@@ -562,14 +562,14 @@
 
 	html_cursor_copy (&original, cursor);
 
-	while (forward (cursor)) {
+	while (forward (cursor, engine)) {
 		if (cursor->object == object && cursor->offset == offset)
 			return TRUE;
 	}
 
 	html_cursor_copy (cursor, &original);
 
-	while (backward (cursor)) {
+	while (backward (cursor, engine)) {
 		if (cursor->object == object && cursor->offset == offset)
 			return TRUE;
 	}
@@ -593,7 +593,7 @@
 	if (engine->need_spell_check)
 		html_engine_spell_check_range (engine, engine->cursor, engine->cursor);
 
-	while (backward (cursor))
+	while (backward (cursor, engine))
 		;
 }
 
@@ -610,7 +610,7 @@
 	if (engine->need_spell_check)
 		html_engine_spell_check_range (engine, engine->cursor, engine->cursor);
 
-	while (forward (cursor))
+	while (forward (cursor, engine))
 		;
 }
 
@@ -646,12 +646,12 @@
 
 	if (cursor->position < position) {
 		while (cursor->position < position) {
-			if (! forward (cursor))
+			if (! forward (cursor, engine))
 				break;
 		}
 	} else if (cursor->position > position) {
 		while (cursor->position > position) {
-			if (! backward (cursor))
+			if (! backward (cursor, engine))
 				break;
 		}
 	}
@@ -755,7 +755,7 @@
 	while (1) {
 		if (!cursor->offset) {
 			copy = html_cursor_dup (cursor);
-			if (backward (cursor)) {
+			if (backward (cursor, engine)) {
 				new_level = html_object_get_parent_level (cursor->object);
 				if (new_level < level
 				    || (new_level == level && flow != cursor->object->parent)) {
@@ -767,7 +767,7 @@
 				break;
 		}
 			else
-				if (!backward (cursor))
+				if (!backward (cursor, engine))
 					break;
 		rv = TRUE;
 	}
@@ -794,7 +794,7 @@
 	while (1) {
 		if (cursor->offset == html_object_get_length (cursor->object)) {
 			copy = html_cursor_dup (cursor);
-			if (forward (cursor)) {
+			if (forward (cursor, engine)) {
 				new_level = html_object_get_parent_level (cursor->object);
 				if (new_level < level
 				    || (new_level == level && flow != cursor->object->parent)) {
@@ -806,7 +806,7 @@
 				break;
 		}
 			else
-				if (!forward (cursor))
+				if (!forward (cursor, engine))
 					break;
 		rv = TRUE;
 	}


--- orig/src/htmlengine-edit-cut-and-paste.c
+++ mod/src/htmlengine-edit-cut-and-paste.c
@@ -1445,14 +1445,15 @@
 				return;
 			}
 		}
-		while (len != 0) {
-			if (forward)
+		if (forward) {
+			int i;
+
+			for (i = len; i > 0; i--)
 				html_cursor_forward (e->cursor, e);
-			else
-				html_cursor_backward (e->cursor, e);
-			len --;
+			html_engine_delete (e);
+		} else {
+			html_object_backspace (e->cursor->object, e->cursor, e);
 		}
-		html_engine_delete (e);
 		html_engine_unblock_selection (e);
 		html_engine_thaw (e);	
 	}


--- orig/src/htmlobject.c
+++ mod/src/htmlobject.c
@@ -35,6 +35,7 @@
 #include "htmlcursor.h"
 #include "htmlengine.h"
 #include "htmlengine-edit.h"
+#include "htmlengine-edit-cut-and-paste.h"
 #include "htmlengine-save.h"
 #include "htmlframe.h"
 #include "htmlinterval.h"
@@ -604,7 +605,7 @@
 }
 
 static gboolean
-html_object_real_cursor_forward (HTMLObject *self, HTMLCursor *cursor)
+html_object_real_cursor_forward (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine)
 {
 	gint len;
 
@@ -645,7 +646,7 @@
 }
 
 static gboolean
-html_object_real_cursor_backward (HTMLObject *self, HTMLCursor *cursor)
+html_object_real_cursor_backward (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine)
 {
 	g_assert (self);
 	g_assert (cursor->object == self);
@@ -726,6 +727,15 @@
 	return FALSE;
 }
 
+static gboolean
+html_object_real_backspace (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine)
+{
+	html_cursor_backward (cursor, engine);
+	html_engine_delete (engine);
+
+	return TRUE;
+}
+
 static int
 html_object_real_get_right_edge_offset (HTMLObject *o, HTMLPainter *painter, int offset)
 {
@@ -813,6 +823,7 @@
 	klass->cursor_backward = html_object_real_cursor_backward;
 	klass->cursor_left = html_object_real_cursor_left;
 	klass->cursor_right = html_object_real_cursor_right;
+	klass->backspace = html_object_real_backspace;
 	klass->get_right_edge_offset = html_object_real_get_right_edge_offset;
 	klass->get_left_edge_offset = html_object_real_get_left_edge_offset;
 }
@@ -1546,15 +1557,15 @@
 }
 
 gboolean
-html_object_cursor_forward (HTMLObject *self, HTMLCursor *cursor)
+html_object_cursor_forward (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine)
 {
-	return (* HO_CLASS (self)->cursor_forward) (self, cursor);
+	return (* HO_CLASS (self)->cursor_forward) (self, cursor, engine);
 }
 
 gboolean
-html_object_cursor_backward (HTMLObject *self, HTMLCursor *cursor)
+html_object_cursor_backward (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine)
 {
-	return (* HO_CLASS (self)->cursor_backward) (self, cursor);
+	return (* HO_CLASS (self)->cursor_backward) (self, cursor, engine);
 }
 
 gboolean
@@ -1569,6 +1580,12 @@
 	return (* HO_CLASS (self)->cursor_left) (self, painter, cursor);
 }
 
+gboolean
+html_object_backspace (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine)
+{
+	return (* HO_CLASS (self)->backspace) (self, cursor, engine);
+}
+
 /*********************
  * movement on leafs
  */


--- orig/src/htmlobject.h
+++ mod/src/htmlobject.h
@@ -262,13 +262,15 @@
 
 	HTMLDirection (*get_direction)   (HTMLObject *self);
 
-	gboolean (*cursor_forward)       (HTMLObject *self, HTMLCursor *cursor);
-	gboolean (*cursor_backward)       (HTMLObject *self, HTMLCursor *cursor);
+	gboolean (*cursor_forward)       (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine);
+	gboolean (*cursor_backward)       (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine);
 	gboolean (*cursor_right)         (HTMLObject *self, HTMLPainter *painter, HTMLCursor *cursor);
 	gboolean (*cursor_left)          (HTMLObject *self, HTMLPainter *painter, HTMLCursor *cursor);
 
 	int (*get_right_edge_offset) (HTMLObject *o, HTMLPainter *painter, int offset);
 	int (*get_left_edge_offset) (HTMLObject *o, HTMLPainter *painter, int offset);
+
+	gboolean (*backspace)       (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine);
 };
 
 extern HTMLObjectClass html_object_class;
@@ -461,15 +463,20 @@
 /* Movement functions */
 /* move cursor in scope of object */
 gboolean        html_object_cursor_forward        (HTMLObject            *self,
-						   HTMLCursor            *cursor);
+						   HTMLCursor            *cursor,
+						   HTMLEngine            *engine);
 gboolean        html_object_cursor_backward       (HTMLObject            *self,
-						   HTMLCursor            *cursor);
+						   HTMLCursor            *cursor,
+						   HTMLEngine            *engine);
 gboolean        html_object_cursor_left           (HTMLObject            *self,
 						   HTMLPainter           *painter,
 						   HTMLCursor            *cursor);
 gboolean        html_object_cursor_right          (HTMLObject            *self,
 						   HTMLPainter           *painter,
 						   HTMLCursor            *cursor);
+gboolean        html_object_backspace             (HTMLObject            *self,
+						   HTMLCursor            *cursor,
+						   HTMLEngine            *engine);
 
 /* get prev/next object in scope of parent */
 HTMLObject     *html_object_next                  (HTMLObject            *self,


--- orig/src/htmltext.c
+++ mod/src/htmltext.c
@@ -33,6 +33,7 @@
 #include "htmltext.h"
 #include "htmlcolor.h"
 #include "htmlcolorset.h"
+#include "htmlcluealigned.h"
 #include "htmlclueflow.h"
 #include "htmlcursor.h"
 #include "htmlgdkpainter.h"
@@ -2501,6 +2502,96 @@
 }
 
 static gboolean
+html_text_cursor_forward (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine)
+{
+	HTMLText *text;
+	HTMLTextPangoInfo *pi = NULL;
+	gint len, attrpos = 0;
+	gboolean retval = FALSE;
+
+	g_assert (self);
+	g_assert (cursor->object == self);
+
+	if (html_object_is_container (self))
+		return FALSE;
+
+	text = HTML_TEXT (self);
+	pi = html_text_get_pango_info (text, engine->painter);
+	len = html_object_get_length (self);
+	do {
+		attrpos = cursor->offset;
+		if (attrpos < len) {
+			cursor->offset++;
+			cursor->position++;
+			retval = TRUE;
+		} else {
+			retval = FALSE;
+			break;
+		}
+	} while (attrpos < len &&
+		 !pi->attrs[attrpos].is_sentence_end &&
+		 !pi->attrs[attrpos + 1].is_cursor_position);
+
+	return retval;
+}
+
+static gboolean
+html_cursor_allow_zero_offset (HTMLCursor *cursor, HTMLObject *o)
+{
+	if (cursor->offset == 1) {
+		HTMLObject *prev;
+
+		prev = html_object_prev_not_slave (o);
+		if (!prev || HTML_IS_CLUEALIGNED (prev))
+			return TRUE;
+		else {
+			while (prev && !html_object_accepts_cursor (prev))
+				prev = html_object_prev_not_slave (prev);
+
+			if (!prev)
+				return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+static gboolean
+html_text_cursor_backward (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine)
+{
+	HTMLText *text;
+	HTMLTextPangoInfo *pi = NULL;
+	gint len, attrpos = 0;
+	gboolean retval = FALSE;
+
+	g_assert (self);
+	g_assert (cursor->object == self);
+
+	if (html_object_is_container (self))
+		return FALSE;
+
+	text = HTML_TEXT (self);
+	pi = html_text_get_pango_info (text, engine->painter);
+	len = html_object_get_length (self);
+	do {
+		attrpos = cursor->offset;
+		if (cursor->offset > 1 ||
+		    html_cursor_allow_zero_offset (cursor, self)) {
+			cursor->offset--;
+			cursor->position--;
+			retval = TRUE;
+		} else {
+			retval = FALSE;
+			break;
+		}
+	} while (attrpos > 0 &&
+		 !pi->attrs[attrpos].is_sentence_start &&
+		 !pi->attrs[attrpos - 1].is_cursor_position);
+
+	return retval;
+}
+
+static gboolean
 html_text_cursor_right (HTMLObject *self, HTMLPainter *painter, HTMLCursor *cursor)
 {
 	HTMLTextSlave *slave;
@@ -2552,6 +2643,79 @@
 	return FALSE;
 }
 
+static gboolean
+html_text_backspace (HTMLObject *self, HTMLCursor *cursor, HTMLEngine *engine)
+{
+	HTMLText *text;
+	HTMLTextPangoInfo *pi = NULL;
+	guint attrpos = 0, prevpos;
+	gboolean retval = FALSE;
+
+	g_assert (self);
+	g_assert (cursor->object == self);
+
+	text = HTML_TEXT (self);
+	pi = html_text_get_pango_info (text, engine->painter);
+	prevpos = cursor->offset;
+	do {
+		attrpos = cursor->offset;
+		if (cursor->offset > 1 ||
+		    html_cursor_allow_zero_offset (cursor, self)) {
+			cursor->offset--;
+			cursor->position--;
+			retval = TRUE;
+		} else {
+			if (cursor->offset == prevpos)
+				retval = FALSE;
+			break;
+		}
+	} while (attrpos > 0 && !pi->attrs[attrpos].is_cursor_position);
+
+	if (!retval) {
+		HTMLObject *prev;
+		gint offset = cursor->offset;
+
+		/* maybe no characters in this line. */
+		prev = html_object_prev_cursor (cursor->object, &offset);
+		cursor->offset = offset;
+		if (prev) {
+			if (!html_object_is_container (prev))
+				cursor->offset = html_object_get_length (prev);
+			cursor->object = prev;
+			cursor->position--;
+			retval = TRUE;
+		}
+	}
+	if (retval) {
+		if (pi->attrs[attrpos].backspace_deletes_character) {
+			gchar *cluster_text = &text->text[prevpos];
+			gchar *normalized_text = NULL;
+			glong len;
+			gint offset = cursor->offset, pos = cursor->position;
+
+			normalized_text = g_utf8_normalize (cluster_text,
+							    prevpos - attrpos,
+							    G_NORMALIZE_NFD);
+			len = g_utf8_strlen (normalized_text, -1);
+			html_engine_delete (engine);
+			if (len > 1) {
+				html_engine_insert_text (engine, normalized_text,
+							 g_utf8_offset_to_pointer (normalized_text, len - 1) - normalized_text);
+				html_cursor_jump_to (cursor, engine, self, offset);
+			}
+			if (normalized_text)
+				g_free (normalized_text);
+			/* restore a cursor position and offset for a split cursor */
+			engine->cursor->offset = offset;
+			engine->cursor->position = pos;
+		} else {
+			html_engine_delete (engine);
+		}
+	}
+
+	return retval;
+}
+
 static int
 html_text_get_right_edge_offset (HTMLObject *o, HTMLPainter *painter, int offset)
 {
@@ -2621,7 +2785,10 @@
 	object_class->append_selection_string = append_selection_string;
 	object_class->get_url = get_url;
 	object_class->get_target = get_target;
+	object_class->cursor_forward = html_text_cursor_forward;
+	object_class->cursor_backward = html_text_cursor_backward;
 	object_class->cursor_right = html_text_cursor_right;
 	object_class->cursor_left = html_text_cursor_left;
+	object_class->backspace = html_text_backspace;
  	object_class->get_right_edge_offset = html_text_get_right_edge_offset;
 	object_class->get_left_edge_offset = html_text_get_left_edge_offset;
