[SCM] WebKit Debian packaging branch, debian/unstable, updated. debian/1.1.15-1-40151-g37bb677

kocienda kocienda at 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Sat Sep 26 08:23:26 UTC 2009


The following commit has been merged in the debian/unstable branch:
commit 5f8bdb0e4006aa243b0a7d33d4e492ad4b1ebf31
Author: kocienda <kocienda at 268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Fri Jan 23 18:55:46 2004 +0000

            Reviewed by Hyatt
    
    	Merged HTML editing progress to TOT from the branch
    	I have been maintaining.
    
            * khtml/dom/dom_position.cpp: Added.
            * khtml/dom/dom_position.h: Added.
            * khtml/editing/htmlediting.cpp: Added.
            * khtml/editing/htmlediting.h: Added.
            * khtml/khtml_selection.cpp: Added.
            * khtml/khtml_selection.h: Added.
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@5970 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog-2005-08-23 b/WebCore/ChangeLog-2005-08-23
index dedbae3..c343e44 100644
--- a/WebCore/ChangeLog-2005-08-23
+++ b/WebCore/ChangeLog-2005-08-23
@@ -1,3 +1,17 @@
+2004-01-23  Ken Kocienda  <kocienda at apple.com>
+
+        Reviewed by Hyatt
+
+	Merged HTML editing progress to TOT from the branch
+	I have been maintaining.
+
+        * khtml/dom/dom_position.cpp: Added.
+        * khtml/dom/dom_position.h: Added.
+        * khtml/editing/htmlediting.cpp: Added.
+        * khtml/editing/htmlediting.h: Added.
+        * khtml/khtml_selection.cpp: Added.
+        * khtml/khtml_selection.h: Added.
+
 2004-01-22  David Hyatt  <hyatt at apple.com>
 
 	Fix a bug I accidentally introduced in static positioned elements.  Add more margin collapsing tests.
diff --git a/WebCore/WebCore.pbproj/project.pbxproj b/WebCore/WebCore.pbproj/project.pbxproj
index bd68a2a..b369e60 100644
--- a/WebCore/WebCore.pbproj/project.pbxproj
+++ b/WebCore/WebCore.pbproj/project.pbxproj
@@ -518,6 +518,9 @@
 				BC745A1D05955F390058C893,
 				BCBDB03A0597B36E00B83B92,
 				BCBDB096059A28B100B83B92,
+				BEB1DD2805C197F800DD1F43,
+				BEB1DD3205C1980700DD1F43,
+				BEB1DD3E05C1982000DD1F43,
 			);
 			isa = PBXHeadersBuildPhase;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -788,6 +791,9 @@
 				BC745A1C05955F390058C893,
 				BCBDB0390597B36E00B83B92,
 				BCBDB095059A28B100B83B92,
+				BEB1DD2705C197F800DD1F43,
+				BEB1DD3105C1980700DD1F43,
+				BEB1DD3D05C1982000DD1F43,
 			);
 			isa = PBXSourcesBuildPhase;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -2450,6 +2456,102 @@
 				);
 			};
 		};
+		BEB1DD0805C197DF00DD1F43 = {
+			children = (
+				BEB1DD2605C197F800DD1F43,
+				BEB1DD2505C197F800DD1F43,
+			);
+			isa = PBXGroup;
+			name = editing;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		BEB1DD2505C197F800DD1F43 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.cpp.cpp;
+			name = htmlediting.cpp;
+			path = editing/htmlediting.cpp;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		BEB1DD2605C197F800DD1F43 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.c.h;
+			name = htmlediting.h;
+			path = editing/htmlediting.h;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		BEB1DD2705C197F800DD1F43 = {
+			fileRef = BEB1DD2505C197F800DD1F43;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		BEB1DD2805C197F800DD1F43 = {
+			fileRef = BEB1DD2605C197F800DD1F43;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		BEB1DD2F05C1980700DD1F43 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.cpp.cpp;
+			path = khtml_selection.cpp;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		BEB1DD3005C1980700DD1F43 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.c.h;
+			path = khtml_selection.h;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		BEB1DD3105C1980700DD1F43 = {
+			fileRef = BEB1DD2F05C1980700DD1F43;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		BEB1DD3205C1980700DD1F43 = {
+			fileRef = BEB1DD3005C1980700DD1F43;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		BEB1DD3B05C1982000DD1F43 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.cpp.cpp;
+			path = dom_position.cpp;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		BEB1DD3C05C1982000DD1F43 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.c.h;
+			path = dom_position.h;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		BEB1DD3D05C1982000DD1F43 = {
+			fileRef = BEB1DD3B05C1982000DD1F43;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		BEB1DD3E05C1982000DD1F43 = {
+			fileRef = BEB1DD3C05C1982000DD1F43;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
 //BE0
 //BE1
 //BE2
@@ -2683,6 +2785,7 @@
 				F523D18402DE42E8018635CA,
 				F523D1F302DE4324018635CA,
 				F523D23402DE436B018635CA,
+				BEB1DD0805C197DF00DD1F43,
 				F523D27702DE4398018635CA,
 				F523D29C02DE43D9018635CA,
 				F523D2F302DE443B018635CA,
@@ -2693,6 +2796,8 @@
 				F523D15402DE42AD018635CA,
 				F523D15602DE42AD018635CA,
 				F523D15302DE42AD018635CA,
+				BEB1DD2F05C1980700DD1F43,
+				BEB1DD3005C1980700DD1F43,
 				F523D15702DE42AD018635CA,
 				F523D15802DE42AD018635CA,
 			);
@@ -3714,6 +3819,8 @@
 				F523D19302DE4322018635CA,
 				F523D19402DE4322018635CA,
 				F523D19502DE4322018635CA,
+				BEB1DD3B05C1982000DD1F43,
+				BEB1DD3C05C1982000DD1F43,
 				F523D19602DE4322018635CA,
 				F523D19702DE4322018635CA,
 				F523D19802DE4322018635CA,
diff --git a/WebCore/khtml/css/cssparser.cpp b/WebCore/khtml/css/cssparser.cpp
index 783d7ea..60a94dc 100644
--- a/WebCore/khtml/css/cssparser.cpp
+++ b/WebCore/khtml/css/cssparser.cpp
@@ -1052,7 +1052,6 @@ bool CSSParser::parseValue( int propId, bool important )
     case CSS_PROP__KHTML_BOX_ORDINAL_GROUP:
         valid_primitive = validUnit(value, FInteger|FNonNeg, true);
         break;
-    
     case CSS_PROP__KHTML_MARQUEE: {
         const int properties[5] = { CSS_PROP__KHTML_MARQUEE_DIRECTION, CSS_PROP__KHTML_MARQUEE_INCREMENT,
                                     CSS_PROP__KHTML_MARQUEE_REPETITION,
@@ -1088,6 +1087,10 @@ bool CSSParser::parseValue( int propId, bool important )
         else
             valid_primitive = validUnit(value, FTime|FInteger|FNonNeg, strict&(!nonCSSHint));
         break;
+    case CSS_PROP__KHTML_USER_MODIFY:	// read-only | read-write
+        if (id == CSS_VAL_READ_ONLY || id == CSS_VAL_READ_WRITE)
+            valid_primitive = true;
+            break;
     // End of CSS3 properties
         
 	/* shorthand properties */
diff --git a/WebCore/khtml/css/cssproperties.c b/WebCore/khtml/css/cssproperties.c
index 51c7939..9de2459 100644
--- a/WebCore/khtml/css/cssproperties.c
+++ b/WebCore/khtml/css/cssproperties.c
@@ -32,7 +32,7 @@ hash_prop (register const char *str, register unsigned int len)
       1012, 1012, 1012, 1012, 1012, 1012, 1012, 1012, 1012, 1012,
       1012, 1012, 1012, 1012, 1012, 1012, 1012,   15,   10,    0,
          0,    0,  100,   50,    0,    0,   10,   10,    0,   10,
-       310,    0,   60,   50,    0,   30,    0,    5,    5,  260,
+       310,    0,   60,   50,    0,   30,    0,    5,   15,  260,
        165,  190,    0, 1012, 1012, 1012, 1012, 1012, 1012, 1012,
       1012, 1012, 1012, 1012, 1012, 1012, 1012, 1012, 1012, 1012,
       1012, 1012, 1012, 1012, 1012, 1012, 1012, 1012, 1012, 1012,
@@ -130,7 +130,7 @@ findProp (register const char *str, register unsigned int len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 130,
+      TOTAL_KEYWORDS = 131,
       MIN_WORD_LENGTH = 3,
       MAX_WORD_LENGTH = 32,
       MIN_HASH_VALUE = 5,
@@ -170,9 +170,9 @@ findProp (register const char *str, register unsigned int len)
       {"scrollbar-face-color", CSS_PROP_SCROLLBAR_FACE_COLOR},
       {"-khtml-marquee-speed", CSS_PROP__KHTML_MARQUEE_SPEED},
       {"border-style", CSS_PROP_BORDER_STYLE},
-      {"visibility", CSS_PROP_VISIBILITY},
       {"table-layout", CSS_PROP_TABLE_LAYOUT},
       {"max-height", CSS_PROP_MAX_HEIGHT},
+      {"visibility", CSS_PROP_VISIBILITY},
       {"list-style", CSS_PROP_LIST_STYLE},
       {"width", CSS_PROP_WIDTH},
       {"border-bottom-style", CSS_PROP_BORDER_BOTTOM_STYLE},
@@ -198,20 +198,21 @@ findProp (register const char *str, register unsigned int len)
       {"scrollbar-arrow-color", CSS_PROP_SCROLLBAR_ARROW_COLOR},
       {"counter-reset", CSS_PROP_COUNTER_RESET},
       {"line-height", CSS_PROP_LINE_HEIGHT},
-      {"overflow", CSS_PROP_OVERFLOW},
+      {"-khtml-user-modify", CSS_PROP__KHTML_USER_MODIFY},
       {"white-space", CSS_PROP_WHITE_SPACE},
       {"min-height", CSS_PROP_MIN_HEIGHT},
       {"scrollbar-shadow-color", CSS_PROP_SCROLLBAR_SHADOW_COLOR},
+      {"overflow", CSS_PROP_OVERFLOW},
       {"border-left-width", CSS_PROP_BORDER_LEFT_WIDTH},
       {"margin", CSS_PROP_MARGIN},
       {"-khtml-flow-mode", CSS_PROP__KHTML_FLOW_MODE},
       {"position", CSS_PROP_POSITION},
-      {"vertical-align", CSS_PROP_VERTICAL_ALIGN},
       {"background", CSS_PROP_BACKGROUND},
       {"scrollbar-darkshadow-color", CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR},
       {"font", CSS_PROP_FONT},
       {"background-color", CSS_PROP_BACKGROUND_COLOR},
       {"margin-bottom", CSS_PROP_MARGIN_BOTTOM},
+      {"vertical-align", CSS_PROP_VERTICAL_ALIGN},
       {"orphans", CSS_PROP_ORPHANS},
       {"caption-side", CSS_PROP_CAPTION_SIDE},
       {"-khtml-marquee-direction", CSS_PROP__KHTML_MARQUEE_DIRECTION},
@@ -240,11 +241,11 @@ findProp (register const char *str, register unsigned int len)
       {"page-break-inside", CSS_PROP_PAGE_BREAK_INSIDE},
       {"-khtml-box-orient", CSS_PROP__KHTML_BOX_ORIENT},
       {"-khtml-box-direction", CSS_PROP__KHTML_BOX_DIRECTION},
-      {"-khtml-border-vertical-spacing", CSS_PROP__KHTML_BORDER_VERTICAL_SPACING},
       {"padding-left", CSS_PROP_PADDING_LEFT},
       {"outline-style", CSS_PROP_OUTLINE_STYLE},
       {"text-align", CSS_PROP_TEXT_ALIGN},
       {"-khtml-box-lines", CSS_PROP__KHTML_BOX_LINES},
+      {"-khtml-border-vertical-spacing", CSS_PROP__KHTML_BORDER_VERTICAL_SPACING},
       {"widows", CSS_PROP_WIDOWS},
       {"outline-offset", CSS_PROP_OUTLINE_OFFSET},
       {"-khtml-box-align", CSS_PROP__KHTML_BOX_ALIGN},
@@ -261,8 +262,8 @@ findProp (register const char *str, register unsigned int len)
       {"font-family", CSS_PROP_FONT_FAMILY},
       {"word-spacing", CSS_PROP_WORD_SPACING},
       {"-khtml-marquee-increment", CSS_PROP__KHTML_MARQUEE_INCREMENT},
-      {"font-variant", CSS_PROP_FONT_VARIANT},
       {"background-attachment", CSS_PROP_BACKGROUND_ATTACHMENT},
+      {"font-variant", CSS_PROP_FONT_VARIANT},
       {"text-indent", CSS_PROP_TEXT_INDENT},
       {"background-position", CSS_PROP_BACKGROUND_POSITION},
       {"-khtml-border-horizontal-spacing", CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING},
@@ -297,8 +298,8 @@ findProp (register const char *str, register unsigned int len)
        29,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  30,  -1,  -1,  31,  -1,  32,  -1,  -1,
-       33,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  30,  -1,  -1,  -1,  -1,  31,  -1,  -1,
+       32,  -1,  -1,  -1,  -1,  33,  -1,  -1,  -1,  -1,
        34,  -1,  -1,  -1,  -1,  35,  -1,  -1,  -1,  36,
        -1,  -1,  37,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  38,  -1,  -1,  -1,  -1,  39,  -1,  -1,
@@ -311,54 +312,54 @@ findProp (register const char *str, register unsigned int len)
        -1,  56,  -1,  -1,  -1,  -1,  -1,  -1,  57,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  58,  -1,  59,  -1,  -1,  60,  -1,  -1,  -1,
-       61,  -1,  62,  -1,  -1,  -1,  -1,  63,  -1,  -1,
-       -1,  64,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1,  65,  -1,  66,  67,
-       68,  69,  -1,  -1,  70,  -1,  71,  -1,  72,  -1,
-       -1,  -1,  73,  -1,  -1,  -1,  -1,  74,  -1,  -1,
-       -1,  -1,  -1,  -1,  75,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  76,  -1,  -1,  -1,  -1,  77,  -1,  78,
-       -1,  -1,  79,  -1,  -1,  80,  -1,  -1,  -1,  81,
-       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  82,
-       -1,  -1,  -1,  -1,  -1,  83,  -1,  -1,  -1,  84,
-       -1,  85,  86,  -1,  -1,  -1,  -1,  -1,  -1,  87,
-       -1,  88,  89,  -1,  -1,  90,  91,  -1,  92,  -1,
-       -1,  -1,  -1,  -1,  -1,  93,  94,  -1,  -1,  -1,
-       -1,  95,  -1,  -1,  -1,  96,  97,  98,  -1,  -1,
-       -1,  -1,  99,  -1,  -1, 100,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1, 101,  -1, 102, 103,  -1,
-      104, 105,  -1,  -1,  -1,  -1, 106,  -1,  -1, 107,
-       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1, 108,  -1, 109, 110,
-       -1,  -1,  -1,  -1,  -1,  -1, 111,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1,  -1, 112,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-      113,  -1,  -1,  -1, 114,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 115,
+       61,  -1,  62,  63,  -1,  -1,  -1,  64,  -1,  -1,
+       -1,  65,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  66,  -1,  67,  -1,
+       68,  69,  -1,  -1,  70,  -1,  71,  -1,  72,  73,
+       -1,  -1,  74,  -1,  -1,  -1,  -1,  75,  -1,  -1,
+       -1,  -1,  -1,  -1,  76,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  77,  -1,  -1,  -1,  -1,  78,  -1,  79,
+       -1,  -1,  80,  -1,  -1,  81,  -1,  -1,  -1,  82,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  83,
+       -1,  -1,  -1,  -1,  -1,  84,  -1,  -1,  -1,  85,
+       -1,  86,  87,  -1,  -1,  -1,  -1,  -1,  -1,  88,
+       -1,  89,  90,  -1,  -1,  91,  92,  -1,  93,  -1,
+       -1,  -1,  -1,  -1,  -1,  94,  95,  -1,  -1,  -1,
+       -1,  96,  -1,  -1,  -1,  97,  98,  99,  -1,  -1,
+       -1,  -1, 100,  -1,  -1, 101,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1, 102, 103,  -1,
+      104, 105,  -1,  -1,  -1, 106, 107,  -1,  -1, 108,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1, 109,  -1, 110, 111,
+       -1,  -1,  -1,  -1,  -1,  -1, 112,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1, 113,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+      114,  -1,  -1,  -1, 115,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 116,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 117,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1, 118,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1, 117,  -1,  -1,  -1,  -1,  -1,
+       -1, 119,  -1,  -1,  -1,  -1, 120, 121,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1, 118,  -1,  -1,  -1,  -1, 119, 120,  -1,  -1,
+       -1,  -1,  -1,  -1, 122,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1, 121,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1,  -1, 122,  -1,  -1,
-       -1, 123,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1, 123,  -1,  -1,  -1,  -1,  -1, 124,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1, 124,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1, 125,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 125,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 126,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1, 126,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1, 127,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
@@ -369,12 +370,12 @@ findProp (register const char *str, register unsigned int len)
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1, 127,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1, 128,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1,  -1,  -1,  -1,  -1,  -1, 128,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1, 129,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
        -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-       -1, 129
+       -1, 130
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -467,6 +468,7 @@ static const char * const propertyList[] = {
 "-khtml-marquee-repetition", 
 "-khtml-marquee-speed", 
 "-khtml-marquee-style", 
+"-khtml-user-modify", 
 "max-height", 
 "max-width", 
 "min-height", 
diff --git a/WebCore/khtml/css/cssproperties.h b/WebCore/khtml/css/cssproperties.h
index 9a5d082..7f29941 100644
--- a/WebCore/khtml/css/cssproperties.h
+++ b/WebCore/khtml/css/cssproperties.h
@@ -76,69 +76,70 @@
 #define CSS_PROP__KHTML_MARQUEE_REPETITION 67
 #define CSS_PROP__KHTML_MARQUEE_SPEED 68
 #define CSS_PROP__KHTML_MARQUEE_STYLE 69
-#define CSS_PROP_MAX_HEIGHT 70
-#define CSS_PROP_MAX_WIDTH 71
-#define CSS_PROP_MIN_HEIGHT 72
-#define CSS_PROP_MIN_WIDTH 73
-#define CSS_PROP_OPACITY 74
-#define CSS_PROP_ORPHANS 75
-#define CSS_PROP_OUTLINE_COLOR 76
-#define CSS_PROP_OUTLINE_OFFSET 77
-#define CSS_PROP_OUTLINE_STYLE 78
-#define CSS_PROP_OUTLINE_WIDTH 79
-#define CSS_PROP_OVERFLOW 80
-#define CSS_PROP_PADDING_TOP 81
-#define CSS_PROP_PADDING_RIGHT 82
-#define CSS_PROP_PADDING_BOTTOM 83
-#define CSS_PROP_PADDING_LEFT 84
-#define CSS_PROP_PAGE 85
-#define CSS_PROP_PAGE_BREAK_AFTER 86
-#define CSS_PROP_PAGE_BREAK_BEFORE 87
-#define CSS_PROP_PAGE_BREAK_INSIDE 88
-#define CSS_PROP_POSITION 89
-#define CSS_PROP_QUOTES 90
-#define CSS_PROP_RIGHT 91
-#define CSS_PROP_SIZE 92
-#define CSS_PROP_TABLE_LAYOUT 93
-#define CSS_PROP_TEXT_ALIGN 94
-#define CSS_PROP_TEXT_DECORATION 95
-#define CSS_PROP_TEXT_DECORATION_COLOR 96
-#define CSS_PROP_TEXT_INDENT 97
-#define CSS_PROP_TEXT_SHADOW 98
-#define CSS_PROP_TEXT_TRANSFORM 99
-#define CSS_PROP_TOP 100
-#define CSS_PROP_UNICODE_BIDI 101
-#define CSS_PROP_VERTICAL_ALIGN 102
-#define CSS_PROP_VISIBILITY 103
-#define CSS_PROP_WHITE_SPACE 104
-#define CSS_PROP_WIDOWS 105
-#define CSS_PROP_WIDTH 106
-#define CSS_PROP_WORD_SPACING 107
-#define CSS_PROP_Z_INDEX 108
-#define CSS_PROP_BACKGROUND 109
-#define CSS_PROP_BORDER 110
-#define CSS_PROP_BORDER_COLOR 111
-#define CSS_PROP_BORDER_STYLE 112
-#define CSS_PROP_BORDER_TOP 113
-#define CSS_PROP_BORDER_RIGHT 114
-#define CSS_PROP_BORDER_BOTTOM 115
-#define CSS_PROP_BORDER_LEFT 116
-#define CSS_PROP_BORDER_WIDTH 117
-#define CSS_PROP_FONT 118
-#define CSS_PROP_LIST_STYLE 119
-#define CSS_PROP_MARGIN 120
-#define CSS_PROP_OUTLINE 121
-#define CSS_PROP_PADDING 122
-#define CSS_PROP_SCROLLBAR_FACE_COLOR 123
-#define CSS_PROP_SCROLLBAR_SHADOW_COLOR 124
-#define CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR 125
-#define CSS_PROP_SCROLLBAR_3DLIGHT_COLOR 126
-#define CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR 127
-#define CSS_PROP_SCROLLBAR_TRACK_COLOR 128
-#define CSS_PROP_SCROLLBAR_ARROW_COLOR 129
-#define CSS_PROP__KHTML_FLOW_MODE 130
+#define CSS_PROP__KHTML_USER_MODIFY 70
+#define CSS_PROP_MAX_HEIGHT 71
+#define CSS_PROP_MAX_WIDTH 72
+#define CSS_PROP_MIN_HEIGHT 73
+#define CSS_PROP_MIN_WIDTH 74
+#define CSS_PROP_OPACITY 75
+#define CSS_PROP_ORPHANS 76
+#define CSS_PROP_OUTLINE_COLOR 77
+#define CSS_PROP_OUTLINE_OFFSET 78
+#define CSS_PROP_OUTLINE_STYLE 79
+#define CSS_PROP_OUTLINE_WIDTH 80
+#define CSS_PROP_OVERFLOW 81
+#define CSS_PROP_PADDING_TOP 82
+#define CSS_PROP_PADDING_RIGHT 83
+#define CSS_PROP_PADDING_BOTTOM 84
+#define CSS_PROP_PADDING_LEFT 85
+#define CSS_PROP_PAGE 86
+#define CSS_PROP_PAGE_BREAK_AFTER 87
+#define CSS_PROP_PAGE_BREAK_BEFORE 88
+#define CSS_PROP_PAGE_BREAK_INSIDE 89
+#define CSS_PROP_POSITION 90
+#define CSS_PROP_QUOTES 91
+#define CSS_PROP_RIGHT 92
+#define CSS_PROP_SIZE 93
+#define CSS_PROP_TABLE_LAYOUT 94
+#define CSS_PROP_TEXT_ALIGN 95
+#define CSS_PROP_TEXT_DECORATION 96
+#define CSS_PROP_TEXT_DECORATION_COLOR 97
+#define CSS_PROP_TEXT_INDENT 98
+#define CSS_PROP_TEXT_SHADOW 99
+#define CSS_PROP_TEXT_TRANSFORM 100
+#define CSS_PROP_TOP 101
+#define CSS_PROP_UNICODE_BIDI 102
+#define CSS_PROP_VERTICAL_ALIGN 103
+#define CSS_PROP_VISIBILITY 104
+#define CSS_PROP_WHITE_SPACE 105
+#define CSS_PROP_WIDOWS 106
+#define CSS_PROP_WIDTH 107
+#define CSS_PROP_WORD_SPACING 108
+#define CSS_PROP_Z_INDEX 109
+#define CSS_PROP_BACKGROUND 110
+#define CSS_PROP_BORDER 111
+#define CSS_PROP_BORDER_COLOR 112
+#define CSS_PROP_BORDER_STYLE 113
+#define CSS_PROP_BORDER_TOP 114
+#define CSS_PROP_BORDER_RIGHT 115
+#define CSS_PROP_BORDER_BOTTOM 116
+#define CSS_PROP_BORDER_LEFT 117
+#define CSS_PROP_BORDER_WIDTH 118
+#define CSS_PROP_FONT 119
+#define CSS_PROP_LIST_STYLE 120
+#define CSS_PROP_MARGIN 121
+#define CSS_PROP_OUTLINE 122
+#define CSS_PROP_PADDING 123
+#define CSS_PROP_SCROLLBAR_FACE_COLOR 124
+#define CSS_PROP_SCROLLBAR_SHADOW_COLOR 125
+#define CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR 126
+#define CSS_PROP_SCROLLBAR_3DLIGHT_COLOR 127
+#define CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR 128
+#define CSS_PROP_SCROLLBAR_TRACK_COLOR 129
+#define CSS_PROP_SCROLLBAR_ARROW_COLOR 130
+#define CSS_PROP__KHTML_FLOW_MODE 131
 
 #define CSS_PROP_MAX CSS_PROP_Z_INDEX
-#define CSS_PROP_TOTAL 131
+#define CSS_PROP_TOTAL 132
 #endif
 
diff --git a/WebCore/khtml/css/cssproperties.in b/WebCore/khtml/css/cssproperties.in
index 10f4bfd..9c6a119 100644
--- a/WebCore/khtml/css/cssproperties.in
+++ b/WebCore/khtml/css/cssproperties.in
@@ -81,6 +81,7 @@ margin-left
 -khtml-marquee-repetition
 -khtml-marquee-speed
 -khtml-marquee-style
+-khtml-user-modify
 max-height
 max-width
 min-height
diff --git a/WebCore/khtml/css/cssstyleselector.cpp b/WebCore/khtml/css/cssstyleselector.cpp
index e996e9d..213bb6f 100644
--- a/WebCore/khtml/css/cssstyleselector.cpp
+++ b/WebCore/khtml/css/cssstyleselector.cpp
@@ -3489,12 +3489,18 @@ void CSSStyleSelector::applyRule( int id, DOM::CSSValueImpl *value )
         }
         break;
     }
+    case CSS_PROP__KHTML_USER_MODIFY: {
+        HANDLE_INHERIT_AND_INITIAL(userModify, UserModify)      
+        if (!primitiveValue || !primitiveValue->getIdent())
+            return;
+        style->setUserModify(EUserModify(primitiveValue->getIdent() - CSS_VAL_READ_ONLY));
+        break;
+    }
     default:
         return;
     }
 }
 
-
 void CSSStyleSelector::checkForGenericFamilyChange(RenderStyle* aStyle, RenderStyle* aParentStyle)
 {
   const FontDef& childFont = aStyle->htmlFont().fontDef;
diff --git a/WebCore/khtml/css/cssvalues.c b/WebCore/khtml/css/cssvalues.c
index eb0464d..c4bf35c 100644
--- a/WebCore/khtml/css/cssvalues.c
+++ b/WebCore/khtml/css/cssvalues.c
@@ -7,7 +7,7 @@ struct css_value {
     const char *name;
     int id;
 };
-/* maximum key range = 1641, duplicates = 1 */
+/* maximum key range = 1455, duplicates = 2 */
 
 #ifdef __GNUC__
 __inline
@@ -21,32 +21,32 @@ hash_val (register const char *str, register unsigned int len)
 {
   static const unsigned short asso_values[] =
     {
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641,   30, 1641, 1641,    0,   10,
-        15,   20,   25,   30,   35,   40,    5,    0, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641,    0,   87,   30,
-       196,  195,  102,    9,   85,   65,   10,  203,    0,   19,
-        25,  180,  104,    5,    4,    5,    0,  185,  184,   85,
-        35,    5,  120, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,
-      1641, 1641, 1641, 1641, 1641, 1641
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455,   30, 1455, 1455,    0,   10,
+        15,   20,   25,   30,   35,   40,    5,    0, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455,    0,  102,   30,
+        15,  195,  210,  124,   85,   65,    0,   14,    0,  194,
+        25,  120,   28,    5,    4,    5,    0,    9,  100,  131,
+       233,  230,   95, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455,
+      1455, 1455, 1455, 1455, 1455, 1455
     };
   register int hval = 0;
 
@@ -110,11 +110,11 @@ findValue (register const char *str, register unsigned int len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 252,
+      TOTAL_KEYWORDS = 254,
       MIN_WORD_LENGTH = 2,
       MAX_WORD_LENGTH = 22,
       MIN_HASH_VALUE = 0,
-      MAX_HASH_VALUE = 1640
+      MAX_HASH_VALUE = 1454
     };
 
   static const struct css_value wordlist_value[] =
@@ -125,430 +125,410 @@ findValue (register const char *str, register unsigned int len)
       {"800", CSS_VAL_800},
       {"start", CSS_VAL_START},
       {"100", CSS_VAL_100},
+      {"aqua", CSS_VAL_AQUA},
       {"200", CSS_VAL_200},
-      {"gray", CSS_VAL_GRAY},
       {"300", CSS_VAL_300},
-      {"small", CSS_VAL_SMALL},
       {"400", CSS_VAL_400},
       {"500", CSS_VAL_500},
       {"600", CSS_VAL_600},
+      {"up", CSS_VAL_UP},
       {"700", CSS_VAL_700},
-      {"x-small", CSS_VAL_X_SMALL},
-      {"always", CSS_VAL_ALWAYS},
+      {"katakana", CSS_VAL_KATAKANA},
       {"static", CSS_VAL_STATIC},
-      {"fast", CSS_VAL_FAST},
-      {"mix", CSS_VAL_MIX},
-      {"xx-small", CSS_VAL_XX_SMALL},
-      {"fantasy", CSS_VAL_FANTASY},
-      {"wait", CSS_VAL_WAIT},
+      {"disc", CSS_VAL_DISC},
+      {"sub", CSS_VAL_SUB},
+      {"hand", CSS_VAL_HAND},
+      {"auto", CSS_VAL_AUTO},
+      {"loud", CSS_VAL_LOUD},
+      {"black", CSS_VAL_BLACK},
+      {"top", CSS_VAL_TOP},
+      {"status-bar", CSS_VAL_STATUS_BAR},
+      {"run-in", CSS_VAL_RUN_IN},
+      {"scroll", CSS_VAL_SCROLL},
       {"italic", CSS_VAL_ITALIC},
-      {"right", CSS_VAL_RIGHT},
+      {"cross", CSS_VAL_CROSS},
       {"thin", CSS_VAL_THIN},
-      {"hiragana", CSS_VAL_HIRAGANA},
-      {"aqua", CSS_VAL_AQUA},
-      {"small-caps", CSS_VAL_SMALL_CAPS},
+      {"crop", CSS_VAL_CROP},
+      {"thick", CSS_VAL_THICK},
       {"teal", CSS_VAL_TEAL},
-      {"large", CSS_VAL_LARGE},
-      {"larger", CSS_VAL_LARGER},
-      {"grey", CSS_VAL_GREY},
-      {"navy", CSS_VAL_NAVY},
-      {"scroll", CSS_VAL_SCROLL},
+      {"wait", CSS_VAL_WAIT},
+      {"small", CSS_VAL_SMALL},
+      {"solid", CSS_VAL_SOLID},
+      {"blink", CSS_VAL_BLINK},
+      {"red", CSS_VAL_RED},
+      {"fast", CSS_VAL_FAST},
+      {"square", CSS_VAL_SQUARE},
       {"initial", CSS_VAL_INITIAL},
-      {"smaller", CSS_VAL_SMALLER},
-      {"cross", CSS_VAL_CROSS},
-      {"normal", CSS_VAL_NORMAL},
-      {"text", CSS_VAL_TEXT},
-      {"graytext", CSS_VAL_GRAYTEXT},
-      {"slow", CSS_VAL_SLOW},
-      {"x-large", CSS_VAL_X_LARGE},
-      {"sub", CSS_VAL_SUB},
-      {"lime", CSS_VAL_LIME},
-      {"table", CSS_VAL_TABLE},
-      {"top", CSS_VAL_TOP},
-      {"up", CSS_VAL_UP},
-      {"inset", CSS_VAL_INSET},
-      {"disc", CSS_VAL_DISC},
-      {"left", CSS_VAL_LEFT},
-      {"single", CSS_VAL_SINGLE},
-      {"icon", CSS_VAL_ICON},
+      {"portrait", CSS_VAL_PORTRAIT},
       {"pre", CSS_VAL_PRE},
-      {"hand", CSS_VAL_HAND},
-      {"xx-large", CSS_VAL_XX_LARGE},
+      {"end", CSS_VAL_END},
+      {"bold", CSS_VAL_BOLD},
+      {"icon", CSS_VAL_ICON},
+      {"super", CSS_VAL_SUPER},
+      {"slow", CSS_VAL_SLOW},
+      {"unfurl", CSS_VAL_UNFURL},
+      {"purple", CSS_VAL_PURPLE},
       {"scrollbar", CSS_VAL_SCROLLBAR},
-      {"status-bar", CSS_VAL_STATUS_BAR},
-      {"crop", CSS_VAL_CROP},
+      {"block", CSS_VAL_BLOCK},
+      {"caption", CSS_VAL_CAPTION},
+      {"right", CSS_VAL_RIGHT},
+      {"slide", CSS_VAL_SLIDE},
+      {"transparent", CSS_VAL_TRANSPARENT},
+      {"inset", CSS_VAL_INSET},
+      {"down", CSS_VAL_DOWN},
+      {"small-caps", CSS_VAL_SMALL_CAPS},
+      {"ahead", CSS_VAL_AHEAD},
+      {"table", CSS_VAL_TABLE},
+      {"landscape", CSS_VAL_LANDSCAPE},
+      {"avoid", CSS_VAL_AVOID},
+      {"backwards", CSS_VAL_BACKWARDS},
+      {"hiragana", CSS_VAL_HIRAGANA},
+      {"blue", CSS_VAL_BLUE},
+      {"both", CSS_VAL_BOTH},
+      {"help", CSS_VAL_HELP},
+      {"nowrap", CSS_VAL_NOWRAP},
+      {"dashed", CSS_VAL_DASHED},
+      {"crosshair", CSS_VAL_CROSSHAIR},
       {"stretch", CSS_VAL_STRETCH},
-      {"black", CSS_VAL_BLACK},
+      {"large", CSS_VAL_LARGE},
       {"circle", CSS_VAL_CIRCLE},
-      {"armenian", CSS_VAL_ARMENIAN},
-      {"run-in", CSS_VAL_RUN_IN},
-      {"both", CSS_VAL_BOTH},
+      {"larger", CSS_VAL_LARGER},
+      {"outset", CSS_VAL_OUTSET},
       {"show", CSS_VAL_SHOW},
-      {"portrait", CSS_VAL_PORTRAIT},
-      {"lighter", CSS_VAL_LIGHTER},
-      {"transparent", CSS_VAL_TRANSPARENT},
-      {"compact", CSS_VAL_COMPACT},
-      {"auto", CSS_VAL_AUTO},
-      {"serif", CSS_VAL_SERIF},
-      {"justify", CSS_VAL_JUSTIFY},
+      {"normal", CSS_VAL_NORMAL},
+      {"dotted", CSS_VAL_DOTTED},
+      {"navy", CSS_VAL_NAVY},
+      {"katakana-iroha", CSS_VAL_KATAKANA_IROHA},
+      {"gray", CSS_VAL_GRAY},
+      {"hide", CSS_VAL_HIDE},
+      {"none", CSS_VAL_NONE},
+      {"always", CSS_VAL_ALWAYS},
+      {"silver", CSS_VAL_SILVER},
+      {"inside", CSS_VAL_INSIDE},
       {"inline", CSS_VAL_INLINE},
-      {"crosshair", CSS_VAL_CROSSHAIR},
-      {"list-item", CSS_VAL_LIST_ITEM},
-      {"blink", CSS_VAL_BLINK},
-      {"thick", CSS_VAL_THICK},
-      {"help", CSS_VAL_HELP},
-      {"square", CSS_VAL_SQUARE},
-      {"red", CSS_VAL_RED},
-      {"nowrap", CSS_VAL_NOWRAP},
-      {"highlight", CSS_VAL_HIGHLIGHT},
-      {"caption", CSS_VAL_CAPTION},
-      {"maroon", CSS_VAL_MAROON},
-      {"orange", CSS_VAL_ORANGE},
-      {"end", CSS_VAL_END},
+      {"collapse", CSS_VAL_COLLAPSE},
+      {"upper-latin", CSS_VAL_UPPER_LATIN},
+      {"invert", CSS_VAL_INVERT},
+      {"vertical", CSS_VAL_VERTICAL},
+      {"smaller", CSS_VAL_SMALLER},
+      {"hidden", CSS_VAL_HIDDEN},
+      {"compact", CSS_VAL_COMPACT},
+      {"ridge", CSS_VAL_RIDGE},
+      {"fuchsia", CSS_VAL_FUCHSIA},
+      {"left", CSS_VAL_LEFT},
+      {"upper-alpha", CSS_VAL_UPPER_ALPHA},
+      {"cursive", CSS_VAL_CURSIVE},
+      {"outside", CSS_VAL_OUTSIDE},
+      {"wider", CSS_VAL_WIDER},
+      {"single", CSS_VAL_SINGLE},
       {"alternate", CSS_VAL_ALTERNATE},
+      {"repeat", CSS_VAL_REPEAT},
       {"menu", CSS_VAL_MENU},
-      {"none", CSS_VAL_NONE},
-      {"green", CSS_VAL_GREEN},
-      {"white", CSS_VAL_WHITE},
-      {"katakana", CSS_VAL_KATAKANA},
-      {"sans-serif", CSS_VAL_SANS_SERIF},
+      {"separate", CSS_VAL_SEPARATE},
+      {"text", CSS_VAL_TEXT},
+      {"default", CSS_VAL_DEFAULT},
+      {"absolute", CSS_VAL_ABSOLUTE},
+      {"bolder", CSS_VAL_BOLDER},
+      {"pointer", CSS_VAL_POINTER},
       {"inherit", CSS_VAL_INHERIT},
-      {"higher", CSS_VAL_HIGHER},
-      {"solid", CSS_VAL_SOLID},
+      {"double", CSS_VAL_DOUBLE},
+      {"background", CSS_VAL_BACKGROUND},
       {"center", CSS_VAL_CENTER},
-      {"silver", CSS_VAL_SILVER},
-      {"small-caption", CSS_VAL_SMALL_CAPTION},
-      {"slide", CSS_VAL_SLIDE},
-      {"bold", CSS_VAL_BOLD},
       {"lower", CSS_VAL_LOWER},
-      {"yellow", CSS_VAL_YELLOW},
-      {"bottom", CSS_VAL_BOTTOM},
-      {"blue", CSS_VAL_BLUE},
-      {"ridge", CSS_VAL_RIDGE},
-      {"fuchsia", CSS_VAL_FUCHSIA},
-      {"invert", CSS_VAL_INVERT},
-      {"ahead", CSS_VAL_AHEAD},
-      {"vertical", CSS_VAL_VERTICAL},
-      {"down", CSS_VAL_DOWN},
-      {"georgian", CSS_VAL_GEORGIAN},
-      {"super", CSS_VAL_SUPER},
+      {"lime", CSS_VAL_LIME},
+      {"x-small", CSS_VAL_X_SMALL},
+      {"maroon", CSS_VAL_MAROON},
+      {"orange", CSS_VAL_ORANGE},
+      {"fantasy", CSS_VAL_FANTASY},
+      {"lighter", CSS_VAL_LIGHTER},
+      {"white", CSS_VAL_WHITE},
+      {"capitalize", CSS_VAL_CAPITALIZE},
+      {"serif", CSS_VAL_SERIF},
+      {"olive", CSS_VAL_OLIVE},
+      {"-khtml-auto", CSS_VAL__KHTML_AUTO},
       {"narrower", CSS_VAL_NARROWER},
-      {"repeat", CSS_VAL_REPEAT},
-      {"block", CSS_VAL_BLOCK},
-      {"unfurl", CSS_VAL_UNFURL},
-      {"separate", CSS_VAL_SEPARATE},
+      {"middle", CSS_VAL_MIDDLE},
+      {"window", CSS_VAL_WINDOW},
+      {"forwards", CSS_VAL_FORWARDS},
+      {"level", CSS_VAL_LEVEL},
+      {"multiple", CSS_VAL_MULTIPLE},
+      {"mix", CSS_VAL_MIX},
+      {"uppercase", CSS_VAL_UPPERCASE},
+      {"oblique", CSS_VAL_OBLIQUE},
+      {"small-caption", CSS_VAL_SMALL_CAPTION},
       {"decimal", CSS_VAL_DECIMAL},
-      {"inline-axis", CSS_VAL_INLINE_AXIS},
-      {"collapse", CSS_VAL_COLLAPSE},
-      {"-khtml-right", CSS_VAL__KHTML_RIGHT},
-      {"repeat-y", CSS_VAL_REPEAT_Y},
-      {"table-cell", CSS_VAL_TABLE_CELL},
-      {"hide", CSS_VAL_HIDE},
-      {"infinite", CSS_VAL_INFINITE},
-      {"text-top", CSS_VAL_TEXT_TOP},
-      {"wider", CSS_VAL_WIDER},
+      {"armenian", CSS_VAL_ARMENIAN},
+      {"horizontal", CSS_VAL_HORIZONTAL},
+      {"above", CSS_VAL_ABOVE},
+      {"justify", CSS_VAL_JUSTIFY},
+      {"visible", CSS_VAL_VISIBLE},
+      {"underline", CSS_VAL_UNDERLINE},
+      {"bottom", CSS_VAL_BOTTOM},
+      {"green", CSS_VAL_GREEN},
+      {"sans-serif", CSS_VAL_SANS_SERIF},
       {"below", CSS_VAL_BELOW},
-      {"inside", CSS_VAL_INSIDE},
-      {"hiragana-iroha", CSS_VAL_HIRAGANA_IROHA},
-      {"landscape", CSS_VAL_LANDSCAPE},
-      {"loud", CSS_VAL_LOUD},
-      {"repeat-x", CSS_VAL_REPEAT_X},
-      {"outset", CSS_VAL_OUTSET},
-      {"multiple", CSS_VAL_MULTIPLE},
-      {"baseline", CSS_VAL_BASELINE},
-      {"pointer", CSS_VAL_POINTER},
-      {"level", CSS_VAL_LEVEL},
-      {"forwards", CSS_VAL_FORWARDS},
-      {"move", CSS_VAL_MOVE},
-      {"capitalize", CSS_VAL_CAPITALIZE},
-      {"table-row", CSS_VAL_TABLE_ROW},
+      {"table-cell", CSS_VAL_TABLE_CELL},
+      {"grey", CSS_VAL_GREY},
+      {"list-item", CSS_VAL_LIST_ITEM},
+      {"higher", CSS_VAL_HIGHER},
+      {"relative", CSS_VAL_RELATIVE},
       {"lower-latin", CSS_VAL_LOWER_LATIN},
-      {"purple", CSS_VAL_PURPLE},
-      {"fixed", CSS_VAL_FIXED},
-      {"-khtml-text", CSS_VAL__KHTML_TEXT},
-      {"visible", CSS_VAL_VISIBLE},
-      {"infotext", CSS_VAL_INFOTEXT},
-      {"marquee", CSS_VAL_MARQUEE},
-      {"backwards", CSS_VAL_BACKWARDS},
+      {"table-row", CSS_VAL_TABLE_ROW},
+      {"appworkspace", CSS_VAL_APPWORKSPACE},
+      {"x-large", CSS_VAL_X_LARGE},
+      {"baseline", CSS_VAL_BASELINE},
+      {"lower-alpha", CSS_VAL_LOWER_ALPHA},
       {"s-resize", CSS_VAL_S_RESIZE},
-      {"olive", CSS_VAL_OLIVE},
-      {"avoid", CSS_VAL_AVOID},
-      {"highlighttext", CSS_VAL_HIGHLIGHTTEXT},
-      {"captiontext", CSS_VAL_CAPTIONTEXT},
+      {"table-caption", CSS_VAL_TABLE_CAPTION},
+      {"no-repeat", CSS_VAL_NO_REPEAT},
       {"block-axis", CSS_VAL_BLOCK_AXIS},
-      {"window", CSS_VAL_WINDOW},
+      {"marquee", CSS_VAL_MARQUEE},
+      {"text-top", CSS_VAL_TEXT_TOP},
+      {"hiragana-iroha", CSS_VAL_HIRAGANA_IROHA},
+      {"move", CSS_VAL_MOVE},
+      {"buttonshadow", CSS_VAL_BUTTONSHADOW},
       {"n-resize", CSS_VAL_N_RESIZE},
-      {"relative", CSS_VAL_RELATIVE},
-      {"above", CSS_VAL_ABOVE},
-      {"hebrew", CSS_VAL_HEBREW},
-      {"absolute", CSS_VAL_ABSOLUTE},
-      {"menutext", CSS_VAL_MENUTEXT},
-      {"horizontal", CSS_VAL_HORIZONTAL},
-      {"bolder", CSS_VAL_BOLDER},
-      {"-khtml-left", CSS_VAL__KHTML_LEFT},
-      {"cursive", CSS_VAL_CURSIVE},
-      {"-khtml-box", CSS_VAL__KHTML_BOX},
-      {"middle", CSS_VAL_MIDDLE},
-      {"dashed", CSS_VAL_DASHED},
-      {"default", CSS_VAL_DEFAULT},
+      {"read-only", CSS_VAL_READ_ONLY},
+      {"condensed", CSS_VAL_CONDENSED},
+      {"-khtml-right", CSS_VAL__KHTML_RIGHT},
+      {"highlight", CSS_VAL_HIGHLIGHT},
+      {"upper-roman", CSS_VAL_UPPER_ROMAN},
+      {"read-write", CSS_VAL_READ_WRITE},
+      {"infinite", CSS_VAL_INFINITE},
+      {"georgian", CSS_VAL_GEORGIAN},
+      {"activecaption", CSS_VAL_ACTIVECAPTION},
+      {"-khtml-nowrap", CSS_VAL__KHTML_NOWRAP},
+      {"groove", CSS_VAL_GROOVE},
+      {"ultra-condensed", CSS_VAL_ULTRA_CONDENSED},
+      {"inline-block", CSS_VAL_INLINE_BLOCK},
       {"medium", CSS_VAL_MEDIUM},
-      {"lower-alpha", CSS_VAL_LOWER_ALPHA},
-      {"inline-table", CSS_VAL_INLINE_TABLE},
-      {"embed", CSS_VAL_EMBED},
+      {"yellow", CSS_VAL_YELLOW},
       {"lowercase", CSS_VAL_LOWERCASE},
+      {"repeat-y", CSS_VAL_REPEAT_Y},
+      {"buttontext", CSS_VAL_BUTTONTEXT},
+      {"repeat-x", CSS_VAL_REPEAT_X},
+      {"buttonface", CSS_VAL_BUTTONFACE},
+      {"xx-small", CSS_VAL_XX_SMALL},
+      {"captiontext", CSS_VAL_CAPTIONTEXT},
+      {"reverse", CSS_VAL_REVERSE},
+      {"embed", CSS_VAL_EMBED},
+      {"inline-table", CSS_VAL_INLINE_TABLE},
+      {"overline", CSS_VAL_OVERLINE},
+      {"table-column", CSS_VAL_TABLE_COLUMN},
+      {"expanded", CSS_VAL_EXPANDED},
+      {"inline-axis", CSS_VAL_INLINE_AXIS},
+      {"close-quote", CSS_VAL_CLOSE_QUOTE},
+      {"hebrew", CSS_VAL_HEBREW},
+      {"monospace", CSS_VAL_MONOSPACE},
+      {"fixed", CSS_VAL_FIXED},
       {"w-resize", CSS_VAL_W_RESIZE},
       {"sw-resize", CSS_VAL_SW_RESIZE},
-      {"buttontext", CSS_VAL_BUTTONTEXT},
-      {"-khtml-xxx-large", CSS_VAL__KHTML_XXX_LARGE},
-      {"upper-latin", CSS_VAL_UPPER_LATIN},
-      {"table-caption", CSS_VAL_TABLE_CAPTION},
-      {"oblique", CSS_VAL_OBLIQUE},
-      {"lower-roman", CSS_VAL_LOWER_ROMAN},
+      {"open-quote", CSS_VAL_OPEN_QUOTE},
+      {"line-through", CSS_VAL_LINE_THROUGH},
       {"nw-resize", CSS_VAL_NW_RESIZE},
-      {"text-bottom", CSS_VAL_TEXT_BOTTOM},
-      {"-khtml-auto", CSS_VAL__KHTML_AUTO},
-      {"no-repeat", CSS_VAL_NO_REPEAT},
-      {"monospace", CSS_VAL_MONOSPACE},
-      {"table-column", CSS_VAL_TABLE_COLUMN},
-      {"groove", CSS_VAL_GROOVE},
-      {"message-box", CSS_VAL_MESSAGE_BOX},
-      {"hidden", CSS_VAL_HIDDEN},
-      {"-khtml-nowrap", CSS_VAL__KHTML_NOWRAP},
-      {"dotted", CSS_VAL_DOTTED},
-      {"reverse", CSS_VAL_REVERSE},
-      {"katakana-iroha", CSS_VAL_KATAKANA_IROHA},
-      {"buttonface", CSS_VAL_BUTTONFACE},
+      {"inactivecaption", CSS_VAL_INACTIVECAPTION},
+      {"ultra-expanded", CSS_VAL_ULTRA_EXPANDED},
+      {"-khtml-left", CSS_VAL__KHTML_LEFT},
+      {"-khtml-text", CSS_VAL__KHTML_TEXT},
       {"e-resize", CSS_VAL_E_RESIZE},
-      {"upper-alpha", CSS_VAL_UPPER_ALPHA},
+      {"graytext", CSS_VAL_GRAYTEXT},
       {"se-resize", CSS_VAL_SE_RESIZE},
       {"-khtml-center", CSS_VAL__KHTML_CENTER},
-      {"uppercase", CSS_VAL_UPPERCASE},
-      {"outside", CSS_VAL_OUTSIDE},
+      {"cjk-ideographic", CSS_VAL_CJK_IDEOGRAPHIC},
+      {"-khtml-box", CSS_VAL__KHTML_BOX},
       {"ne-resize", CSS_VAL_NE_RESIZE},
+      {"xx-large", CSS_VAL_XX_LARGE},
       {"-khtml-body", CSS_VAL__KHTML_BODY},
-      {"double", CSS_VAL_DOUBLE},
-      {"overline", CSS_VAL_OVERLINE},
-      {"upper-roman", CSS_VAL_UPPER_ROMAN},
-      {"line-through", CSS_VAL_LINE_THROUGH},
-      {"windowtext", CSS_VAL_WINDOWTEXT},
-      {"activecaption", CSS_VAL_ACTIVECAPTION},
-      {"buttonhighlight", CSS_VAL_BUTTONHIGHLIGHT},
-      {"underline", CSS_VAL_UNDERLINE},
-      {"inline-block", CSS_VAL_INLINE_BLOCK},
-      {"background", CSS_VAL_BACKGROUND},
-      {"expanded", CSS_VAL_EXPANDED},
-      {"windowframe", CSS_VAL_WINDOWFRAME},
-      {"inactivecaption", CSS_VAL_INACTIVECAPTION},
-      {"threedface", CSS_VAL_THREEDFACE},
-      {"close-quote", CSS_VAL_CLOSE_QUOTE},
-      {"appworkspace", CSS_VAL_APPWORKSPACE},
-      {"buttonshadow", CSS_VAL_BUTTONSHADOW},
-      {"condensed", CSS_VAL_CONDENSED},
-      {"-khtml-inline-box", CSS_VAL__KHTML_INLINE_BOX},
-      {"threedhighlight", CSS_VAL_THREEDHIGHLIGHT},
-      {"table-row-group", CSS_VAL_TABLE_ROW_GROUP},
-      {"open-quote", CSS_VAL_OPEN_QUOTE},
-      {"lower-greek", CSS_VAL_LOWER_GREEK},
+      {"lower-roman", CSS_VAL_LOWER_ROMAN},
       {"activeborder", CSS_VAL_ACTIVEBORDER},
-      {"ultra-expanded", CSS_VAL_ULTRA_EXPANDED},
-      {"inactivecaptiontext", CSS_VAL_INACTIVECAPTIONTEXT},
-      {"cjk-ideographic", CSS_VAL_CJK_IDEOGRAPHIC},
-      {"extra-expanded", CSS_VAL_EXTRA_EXPANDED},
+      {"infotext", CSS_VAL_INFOTEXT},
       {"threedshadow", CSS_VAL_THREEDSHADOW},
-      {"inactiveborder", CSS_VAL_INACTIVEBORDER},
+      {"menutext", CSS_VAL_MENUTEXT},
+      {"infobackground", CSS_VAL_INFOBACKGROUND},
+      {"threeddarkshadow", CSS_VAL_THREEDDARKSHADOW},
       {"no-close-quote", CSS_VAL_NO_CLOSE_QUOTE},
-      {"semi-expanded", CSS_VAL_SEMI_EXPANDED},
+      {"buttonhighlight", CSS_VAL_BUTTONHIGHLIGHT},
+      {"table-row-group", CSS_VAL_TABLE_ROW_GROUP},
+      {"no-open-quote", CSS_VAL_NO_OPEN_QUOTE},
+      {"windowtext", CSS_VAL_WINDOWTEXT},
+      {"inactiveborder", CSS_VAL_INACTIVEBORDER},
+      {"threedface", CSS_VAL_THREEDFACE},
+      {"bidi-override", CSS_VAL_BIDI_OVERRIDE},
+      {"text-bottom", CSS_VAL_TEXT_BOTTOM},
+      {"lower-greek", CSS_VAL_LOWER_GREEK},
       {"table-column-group", CSS_VAL_TABLE_COLUMN_GROUP},
-      {"ultra-condensed", CSS_VAL_ULTRA_CONDENSED},
-      {"infobackground", CSS_VAL_INFOBACKGROUND},
+      {"highlighttext", CSS_VAL_HIGHLIGHTTEXT},
       {"extra-condensed", CSS_VAL_EXTRA_CONDENSED},
-      {"no-open-quote", CSS_VAL_NO_OPEN_QUOTE},
+      {"windowframe", CSS_VAL_WINDOWFRAME},
       {"semi-condensed", CSS_VAL_SEMI_CONDENSED},
       {"threedlightshadow", CSS_VAL_THREEDLIGHTSHADOW},
-      {"bidi-override", CSS_VAL_BIDI_OVERRIDE},
-      {"table-footer-group", CSS_VAL_TABLE_FOOTER_GROUP},
+      {"threedhighlight", CSS_VAL_THREEDHIGHLIGHT},
       {"table-header-group", CSS_VAL_TABLE_HEADER_GROUP},
+      {"extra-expanded", CSS_VAL_EXTRA_EXPANDED},
+      {"inactivecaptiontext", CSS_VAL_INACTIVECAPTIONTEXT},
+      {"semi-expanded", CSS_VAL_SEMI_EXPANDED},
+      {"message-box", CSS_VAL_MESSAGE_BOX},
+      {"-khtml-inline-box", CSS_VAL__KHTML_INLINE_BOX},
+      {"table-footer-group", CSS_VAL_TABLE_FOOTER_GROUP},
       {"decimal-leading-zero", CSS_VAL_DECIMAL_LEADING_ZERO},
-      {"threeddarkshadow", CSS_VAL_THREEDDARKSHADOW},
+      {"-khtml-xxx-large", CSS_VAL__KHTML_XXX_LARGE},
       {"-khtml-baseline-middle", CSS_VAL__KHTML_BASELINE_MIDDLE}
     };
 
   static const short lookup[] =
     {
-         0,   -1,   -1,   -1, -259,    3, -251,   -2,
-        -1,    4,    5,   -1,   -1,   -1,   -1,    6,
-        -1,   -1,    7,   -1,    8,   -1,   -1,   -1,
-         9,   10,   -1,   -1,   -1,   -1,   11,   -1,
-        -1,   -1,   -1,   12,   -1,   -1,   -1,   -1,
+         0,   -1,   -1,   -1, -261,    3, -253,   -2,
+        -1,    4,    5,   -1,   -1,   -1,    6,    7,
+        -1,   -1,   -1,   -1,    8,   -1,   -1,   -1,
+        -1,    9,   -1,   -1,   -1,   -1,   10,   -1,
+        -1,   -1,   -1,   11,   -1,   12,   -1,   -1,
         13,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,   14,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   14,   -1,   -1,   -1,   -1,   -1,   15,
-        -1,   -1,   -1,   -1,   16,   -1,   -1,   -1,
-        -1,   -1,   -1,   17,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   18,
-        -1,   -1,   -1,   -1,   19,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   20,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   21,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        22,   -1,   -1,   23,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   24,
+        -1,   -1,   -1,   -1,   15,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   25,   -1,   26,   -1,
-        -1,   27,   -1,   28,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   16,   17,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,   18,   -1,   -1,
+        -1,   19,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        29,   -1,   -1,   -1,   30,   31,   32,   -1,
-        -1,   -1,   -1,   33,   34,   -1,   -1,   35,
-        36,   -1,   -1,   -1,   37,   -1,   38,   -1,
+        20,   -1,   21,   -1,   22,   -1,   -1,   -1,
+        -1,   -1,   -1,   23,   -1,   -1,   24,   25,
+        26,   -1,   -1,   -1,   27,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,   -1,   -1,   28,
+        -1,   -1,   -1,   -1,   -1,   -1,   29,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   30,   31,   32,   -1,   -1,   33,
+        -1,   -1,   -1,   -1,   -1,   34,   35,   -1,
+        -1,   -1,   -1,   -1,   -1,   -1,   36,   37,
+        -1,   -1,   38,   -1,   39,   40,   -1,   -1,
+        -1,   -1,   -1,   41,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   42,   -1,   43,   -1,   -1,
+        44,   45,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        39,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+        46,   47,   -1,   -1,   -1,   -1,   -1,   -1,
+        48,   49,   50,   -1,   51,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,   -1,   52,   -1,
+        53,   -1,   -1,   -1,   -1,   -1,   54,   -1,
+        -1,   -1,   55,   56,   57,   -1,   -1,   58,
+        -1,   59,   60,   -1,   61,   62,   -1,   63,
+        -1,   -1,   64,   65, -564, -188,   -2,   -1,
+        -1,   -1,   -1,   68,   -1,   -1,   69,   70,
+        -1,   -1,   -1,   71,   72,   -1,   -1,   73,
+        -1,   74,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,   75,   -1,   76,
+        -1,   77,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   78,   -1,   79,   80,   -1,
+        81,   -1,   -1,   -1,   -1,   82,   83,   -1,
+        -1,   84,   85,   -1,   -1,   -1,   -1,   86,
+        -1,   -1,   87,   -1,   -1,   -1,   -1,   -1,
+        88,   -1,   -1,   -1,   -1,   89,   -1,   -1,
+        -1,   -1,   90,   -1,   -1,   -1,   91,   -1,
+        92,   -1,   93,   94,   95,   96,   -1,   97,
+        98,   99,  100,   -1,   -1,   -1,  101,   -1,
+        -1,   -1,   -1,  102,   -1,   -1,  103,  104,
+        -1,   -1,   -1,  105,  106,  107,   -1,  108,
+        -1,   -1,   -1,   -1,  109,  110,   -1,  111,
+        -1,  112,   -1,  113,   -1,   -1,   -1,   -1,
+        -1,  114,  115,   -1,   -1,   -1,  116,   -1,
+        -1,   -1,   -1,   -1,   -1,   -1,  117,  118,
+        -1,   -1,   -1,   -1,  119,   -1,  120,   -1,
+        -1,  121,   -1,   -1,  122,   -1,  123,  124,
+       125,   -1,  126,  127,  128,   -1,   -1,  129,
+        -1,  130,  131,  132,  133,   -1,  134,   -1,
+       135,  136,   -1,  137,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,  138,   -1,   -1,   -1,
+        -1,   -1,  139,   -1,   -1,  140,   -1,  141,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   40,   -1,
-        -1,   41,   -1,   -1,   -1,   42,   -1,   43,
-        -1,   -1,   44,   -1,   45,   -1,   -1,   -1,
-        -1,   46,   47,   -1,   -1,   -1,   -1,   -1,
-        48,   49,   -1,   50,   51,   -1,   -1,   52,
-        -1,   -1,   53,   -1,   54,   -1,   55,   -1,
-        -1,   -1,   -1,   -1,   56,   -1,   57,   58,
-        59,   -1,   -1,   -1,   60,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   61,   62,   -1,
+        -1,   -1,   -1,   -1,  142,  143,   -1,   -1,
+       144,   -1,   -1,   -1,   -1,   -1,   -1,  145,
+       146,   -1,   -1,   -1,  147,   -1,   -1,   -1,
+       148,  149,  150,   -1,   -1,   -1,  151,  152,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,  153,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,   -1,  154,  155,
+        -1,   -1,  156,  157,   -1,   -1,   -1,   -1,
+        -1,  158,  159,  160,   -1,  161,   -1,  162,
+        -1,   -1,  163,   -1,   -1,   -1,  164,  165,
+        -1,  166,   -1,   -1,  167,   -1,  168,   -1,
+        -1,   -1,   -1,  169,   -1,   -1,   -1,   -1,
+        -1,  170,   -1,   -1,   -1,   -1,   -1,  171,
+        -1,  172,   -1,   -1,   -1,  173,   -1,  174,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        63,   -1,   -1,   64,   -1,   65,   66,   -1,
-        -1,   -1,   67,   68,   -1,   69,   -1,   -1,
-        -1,   -1,   -1,   70,   71,   -1,   -1,   72,
-        -1,   -1,   73,   74,   75,   -1,   -1,   76,
-        77,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   78,   79,   -1,   -1,   80,   -1,
-        -1,   -1,   -1,   81,   82,   -1,   -1,   -1,
-        83,   -1,   -1,   -1,   -1,   84,   -1,   -1,
-        85,   -1,   -1,   86,   -1,   -1,   -1,   -1,
-        87,   88,   -1,   -1,   89,   -1,   90,   91,
-        -1,   -1,   -1,   -1,   92,   -1,   -1,   93,
-        -1,   -1,   -1,   94,   -1,   -1,   95,   -1,
-        -1,   96,   -1,   -1,   -1,   97,   -1,   -1,
-        -1,   -1,   98,   -1,   -1,   99,   -1,  100,
-       101,  102,  103,  104,   -1,  105,   -1,   -1,
-       106,  107,   -1,   -1,  108,   -1,  109,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,  110,  111,
-        -1,   -1,   -1,   -1,   -1,  112,   -1,   -1,
-        -1,  113,  114,   -1,  115,  116,   -1,  117,
-        -1,  118,   -1,   -1,   -1,   -1,  119,   -1,
-        -1,   -1,  120,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,  175,   -1,   -1,   -1,   -1,   -1,
+        -1,  176,  177,   -1,   -1,  178,   -1,  179,
+        -1,   -1,   -1,   -1,  180,   -1,   -1,  181,
+       182,   -1,   -1,   -1,  183,   -1,   -1,   -1,
+       184,   -1,  185,   -1,  186,  187,   -1,   -1,
+        -1,   -1,   -1,  188,   -1,   -1,   -1,  189,
+       190,   -1,  191,   -1,   -1,  192,  193,   -1,
+       194,  195,  196,   -1,  197,  198,   -1,   -1,
+       199,   -1,   -1,   -1,   -1,  200,  201,   -1,
+       202,   -1,   -1,   -1,   -1,  203,   -1,  204,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,  121,   -1,   -1,  122,   -1,   -1,
-        -1,  123,   -1,   -1,   -1,  124,  125,   -1,
-       126,  127,   -1,  128,   -1,   -1,   -1,  129,
-       130,   -1,   -1,  131,   -1,   -1,   -1,   -1,
-        -1,  132,   -1,  133,   -1,  134,   -1,   -1,
-       135,   -1,   -1,   -1,  136,  137,  138,   -1,
-       139,   -1,  140,  141,   -1,  142,   -1,   -1,
-       143,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-       144,  145,   -1,   -1,   -1,  146,   -1,   -1,
-        -1,  147,  148,  149,   -1,   -1,   -1,   -1,
-        -1,   -1,  150,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,  151,   -1,   -1,   -1,   -1,
-       152,  153,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,  154,  155,  156,  157,   -1,   -1,  158,
-        -1,   -1,   -1,  159,   -1,   -1,  160,   -1,
-        -1,   -1,   -1,  161,  162,   -1,  163,   -1,
-        -1,   -1,   -1,  164,   -1,   -1,  165,   -1,
-       166,   -1,   -1,   -1,  167,  168,   -1,  169,
-        -1,   -1,   -1,   -1,   -1,  170,  171,  172,
-        -1,   -1,   -1,  173,   -1,   -1,   -1,  174,
-        -1,   -1,   -1,   -1,  175,   -1,  176,   -1,
-        -1,   -1,   -1,  177,   -1,   -1,   -1,   -1,
-       178,   -1,   -1,  179,   -1,   -1,  180,   -1,
-       181,   -1,   -1,   -1,  182,  183,   -1,   -1,
-        -1,   -1,  184,   -1,  185,   -1,  186,   -1,
-        -1,   -1,   -1,   -1,  187,  188,   -1,   -1,
-        -1,   -1,  189,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,  190,
-       191,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-       192,   -1,  193,   -1,   -1,  194,   -1,  195,
+        -1,   -1,   -1,   -1,   -1,   -1,  205,   -1,
+        -1,  206,   -1,   -1,  207,  208,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,   -1,  209,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,  196,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,  197,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,  198,   -1,   -1,   -1,
-        -1,  199,   -1,  200,   -1,   -1,  201,   -1,
-       202,   -1,   -1,   -1,   -1,   -1,  203,   -1,
-        -1,   -1,  204,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,  205,  206,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,  207,   -1,   -1,   -1,   -1,
-       208,   -1,  209,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,  210,
-        -1,   -1,  211,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,  212,   -1,
-       213,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,  214,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,  210,   -1,   -1,
+       211,   -1,  212,   -1,   -1,  213,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,  215,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,  216,
+        -1,   -1,  214,   -1,   -1,  215,   -1,   -1,
+       216,  217,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,  218,  219,   -1,   -1,  220,
+        -1,   -1,   -1,   -1,   -1,   -1,  221,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+       222,   -1,  223,  224,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,   -1,   -1,  225,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,  217,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,  218,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-       219,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,  226,  227,   -1,   -1,   -1,
+        -1,  228,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,  229,   -1,   -1,   -1,   -1,  230,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,  231,   -1,   -1,   -1,   -1,
+       232,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,  233,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,  220,   -1,   -1,  221,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,  222,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,  223,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,  224,
+        -1,   -1,   -1,   -1,   -1,   -1,   -1,  234,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,  235,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,  225,   -1,   -1,   -1,  226,   -1,
+        -1,   -1,   -1,   -1,  236,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,  237,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,  227,   -1,   -1,
-        -1,   -1,   -1,  228,  229,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,  238,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,  230,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,  231,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,  232,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,  233,   -1,
-        -1,   -1,  234,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,  235,   -1,   -1,   -1,  236,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-       237,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,  238,   -1,   -1,  239,
+        -1,   -1,   -1,   -1,   -1,   -1,   -1,  239,
         -1,   -1,  240,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,  241,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,  242,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,  241,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,  242,   -1,   -1,  243,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,  243,   -1,
+       244,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,  244,   -1,   -1,   -1,   -1,   -1,   -1,
+       245,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+       246,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,  245,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,  247,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,  248,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,  249,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
@@ -558,29 +538,27 @@ findValue (register const char *str, register unsigned int len)
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,  246,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,  250,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,  247,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,  248,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,  249,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,  251,   -1,   -1,
+        -1,   -1,   -1,   -1,   -1,  252,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-        -1,   -1,   -1,   -1,   -1,  250,   -1,   -1,
         -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-       251
+        -1,   -1,   -1,   -1,   -1,   -1,  253
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -871,6 +849,8 @@ static const char * const valueList[] = {
 "slide", 
 "alternate", 
 "unfurl", 
+"read-only", 
+"read-write", 
     0
 };
 DOMString getValueName(unsigned short id)
diff --git a/WebCore/khtml/css/cssvalues.h b/WebCore/khtml/css/cssvalues.h
index 44e311b..683f93e 100644
--- a/WebCore/khtml/css/cssvalues.h
+++ b/WebCore/khtml/css/cssvalues.h
@@ -261,7 +261,9 @@ DOM::DOMString getValueName(unsigned short id);
 #define CSS_VAL_SLIDE 250
 #define CSS_VAL_ALTERNATE 251
 #define CSS_VAL_UNFURL 252
+#define CSS_VAL_READ_ONLY 253
+#define CSS_VAL_READ_WRITE 254
 
-#define CSS_VAL_TOTAL 253
+#define CSS_VAL_TOTAL 255
 #endif
 
diff --git a/WebCore/khtml/css/cssvalues.in b/WebCore/khtml/css/cssvalues.in
index b95b8b6..2ff4a7e 100644
--- a/WebCore/khtml/css/cssvalues.in
+++ b/WebCore/khtml/css/cssvalues.in
@@ -368,3 +368,8 @@ slide
 alternate
 unfurl
 
+#
+# CSS_PROP__KHTML_USER_MODIFY
+#
+read-only
+read-write
diff --git a/WebCore/khtml/dom/dom_node.cpp b/WebCore/khtml/dom/dom_node.cpp
index 9451db4..c846148 100644
--- a/WebCore/khtml/dom/dom_node.cpp
+++ b/WebCore/khtml/dom/dom_node.cpp
@@ -407,12 +407,6 @@ void Node::applyChanges()
     impl->recalcStyle( NodeImpl::Inherit );
 }
 
-void Node::getCursor(int offset, int &_x, int &_y, int &height)
-{
-    if (!impl) throw DOMException(DOMException::NOT_FOUND_ERR);
-    impl->getCursor(offset, _x, _y, height);
-}
-
 QRect Node::getRect()
 {
     if (!impl) throw DOMException(DOMException::NOT_FOUND_ERR);
diff --git a/WebCore/khtml/dom/dom_node.h b/WebCore/khtml/dom/dom_node.h
index 95d77e0..51aa4eb 100644
--- a/WebCore/khtml/dom/dom_node.h
+++ b/WebCore/khtml/dom/dom_node.h
@@ -868,7 +868,6 @@ public:
     unsigned long index() const;
     QString toHTML();
     void applyChanges();
-    void getCursor(int offset, int &_x, int &_y, int &height);
     /**
      * not part of the DOM.
      * @returns the exact coordinates and size of this element.
diff --git a/WebCore/khtml/dom/dom_position.cpp b/WebCore/khtml/dom/dom_position.cpp
new file mode 100644
index 0000000..b6b5e32
--- /dev/null
+++ b/WebCore/khtml/dom/dom_position.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "dom_position.h"
+#include "xml/dom_nodeimpl.h"
+
+using DOM::DOMPosition;
+
+DOMPosition::DOMPosition(NodeImpl *node, long offset) 
+    : m_node(0), m_offset(offset) 
+{ 
+    if (node) {
+        m_node = node;
+        m_node->ref();
+    }
+};
+
+DOMPosition::DOMPosition(const DOMPosition &o)
+    : m_node(0), m_offset(o.offset()) 
+{
+    if (o.node()) {
+        m_node = o.node();
+        m_node->ref();
+    }
+}
+
+DOMPosition::~DOMPosition() {
+    if (m_node) {
+        m_node->deref();
+    }
+}
+
+DOMPosition &DOMPosition::operator=(const DOMPosition &o)
+{
+    if (m_node) {
+        m_node->deref();
+    }
+    m_node = o.node();
+    if (m_node) {
+        m_node->ref();
+    }
+
+    m_offset = o.offset();
+    
+    return *this;
+}
diff --git a/WebCore/khtml/dom/dom_position.h b/WebCore/khtml/dom/dom_position.h
new file mode 100644
index 0000000..6fb6028
--- /dev/null
+++ b/WebCore/khtml/dom/dom_position.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+namespace DOM {
+
+class NodeImpl;
+
+class DOMPosition
+{
+public:
+    DOMPosition() : m_node(0), m_offset(0) {};
+    DOMPosition(NodeImpl *node, long offset);
+    DOMPosition(const DOMPosition &);
+    ~DOMPosition();
+
+    NodeImpl *node() const { return m_node; }
+    long offset() const { return m_offset; }
+
+    bool isEmpty() const { return m_node == 0; }
+
+    DOMPosition &operator=(const DOMPosition &o);
+    
+    friend bool operator==(const DOMPosition &a, const DOMPosition &b);
+    friend bool operator!=(const DOMPosition &a, const DOMPosition &b);
+    
+private:
+    NodeImpl *m_node;
+    long m_offset;
+};
+
+inline bool operator==(const DOMPosition &a, const DOMPosition &b)
+{
+    return a.node() == b.node() && a.offset() == b.offset();
+}
+
+inline bool operator!=(const DOMPosition &a, const DOMPosition &b)
+{
+    return !(a == b);
+}
+
+}; // namespace DOM
\ No newline at end of file
diff --git a/WebCore/khtml/editing/SelectionController.cpp b/WebCore/khtml/editing/SelectionController.cpp
new file mode 100644
index 0000000..e4e9cfa
--- /dev/null
+++ b/WebCore/khtml/editing/SelectionController.cpp
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+  
+#include "khtml_selection.h"
+
+#include "khtml_part.h"
+#include "khtmlview.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qrect.h"
+#include "dom/dom2_range.h"
+#include "dom/dom_node.h"
+#include "dom/dom_position.h"
+#include "dom/dom_string.h"
+#include "rendering/render_object.h"
+#include "rendering/render_style.h"
+#include "rendering/render_text.h"
+#include "xml/dom_docimpl.h"
+#include "xml/dom_nodeimpl.h"
+#include "xml/dom_textimpl.h"
+
+#if APPLE_CHANGES
+#include <KWQAssertions.h>
+#include <CoreServices/CoreServices.h>
+#endif
+
+using DOM::DocumentImpl;
+using DOM::DOMPosition;
+using DOM::DOMString;
+using DOM::Node;
+using DOM::NodeImpl;
+using DOM::Range;
+using DOM::TextImpl;
+using khtml::InlineTextBox;
+using khtml::InlineTextBoxArray;
+using khtml::RenderObject;
+using khtml::RenderText;
+
+enum { CARET_BLINK_FREQUENCY = 500 };
+
+#if APPLE_CHANGES
+static void findWordBoundary(QChar *chars, int len, int position, int *start, int *end);
+static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset);
+static bool lastRunAt(RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset);
+static bool startAndEndLineNodesIncludingNode(DOM::NodeImpl *node, int offset, KHTMLSelection &selection);
+#endif
+
+
+KHTMLSelection::KHTMLSelection() 
+	: QObject(),
+	  m_part(0),
+	  m_baseNode(0), m_baseOffset(0), m_extentNode(0), m_extentOffset(0),
+	  m_startNode(0), m_startOffset(0), m_endNode(0), m_endOffset(0),
+	  m_state(NONE), m_caretBlinkTimer(0),
+      m_baseIsStart(true), m_caretBlinks(true), m_caretPaint(false), 
+      m_visible(false), m_startEndValid(false)
+{
+}
+
+KHTMLSelection::KHTMLSelection(const KHTMLSelection &o)
+	: QObject(),
+	  m_part(o.m_part),
+	  m_baseNode(0), m_baseOffset(0), m_extentNode(0), m_extentOffset(0),
+	  m_startNode(0), m_startOffset(0), m_endNode(0), m_endOffset(0)
+{
+    setBase(o.baseNode(), o.baseOffset());
+    setExtent(o.extentNode(), o.extentOffset());
+    setStart(o.startNode(), o.startOffset());
+    setEnd(o.endNode(), o.endOffset());
+
+	m_state = o.m_state;
+	m_caretBlinkTimer = o.m_caretBlinkTimer;
+	m_baseIsStart = o.m_baseIsStart;
+	m_caretBlinks = o.m_caretBlinks;
+	m_caretPaint = true;
+	m_visible = o.m_visible;
+    m_startEndValid = true;
+}
+
+KHTMLSelection::~KHTMLSelection()
+{
+    if (m_baseNode)
+        m_baseNode->deref();
+    if (m_extentNode)
+        m_extentNode->deref();
+}
+
+KHTMLSelection &KHTMLSelection::operator=(const KHTMLSelection &o)
+{
+    m_part = o.m_part;
+    
+    setBase(o.baseNode(), o.baseOffset());
+    setExtent(o.extentNode(), o.extentOffset());
+    setStart(o.startNode(), o.startOffset());
+    setEnd(o.endNode(), o.endOffset());
+
+	m_state = o.m_state;
+	m_caretBlinkTimer = o.m_caretBlinkTimer;
+	m_baseIsStart = o.m_baseIsStart;
+	m_caretBlinks = o.m_caretBlinks;
+	m_caretPaint = true;
+	m_visible = o.m_visible;
+    m_startEndValid = true;
+    return *this;
+}
+
+void KHTMLSelection::setSelection(DOM::NodeImpl *node, long offset)
+{
+	setBaseNode(node);
+	setExtentNode(node);
+	setBaseOffset(offset);
+	setExtentOffset(offset);
+	update();
+}
+
+void KHTMLSelection::setSelection(const DOM::Range &r)
+{
+	setSelection(r.startContainer().handle(), r.startOffset(), 
+		r.endContainer().handle(), r.endOffset());
+}
+
+void KHTMLSelection::setSelection(const DOM::DOMPosition &pos)
+{
+	setSelection(pos.node(), pos.offset());
+}
+
+void KHTMLSelection::setSelection(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset)
+{
+	setBaseNode(baseNode);
+	setExtentNode(extentNode);
+	setBaseOffset(baseOffset);
+	setExtentOffset(extentOffset);
+	update();
+}
+
+void KHTMLSelection::setBase(DOM::NodeImpl *node, long offset)
+{
+	setBaseNode(node);
+	setBaseOffset(offset);
+	update();
+}
+
+void KHTMLSelection::setExtent(DOM::NodeImpl *node, long offset)
+{
+	setExtentNode(node);
+	setExtentOffset(offset);
+	update();
+}
+
+bool KHTMLSelection::alterSelection(EAlter alter, EDirection dir, ETextElement elem)
+{
+    DOMPosition pos;
+    
+    switch (dir) {
+        case FORWARD:
+            switch (elem) {
+                case CHARACTER:
+                    pos = nextCharacterPosition();
+                    break;
+                case WORD:
+                    break;
+                case LINE:
+                    break;
+            }
+            break;
+        case BACKWARD:
+            switch (elem) {
+                case CHARACTER:
+                    break;
+                case WORD:
+                    break;
+                case LINE:
+                    break;
+            }
+            break;
+    }
+    
+    if (pos.isEmpty())
+        return false;
+    
+    if (alter == MOVE)
+        setSelection(pos.node(), pos.offset());
+    else // alter == EXTEND
+        setExtent(pos.node(), pos.offset());
+    
+    return true;
+}
+
+void KHTMLSelection::clearSelection()
+{
+	setBaseNode(0);
+	setExtentNode(0);
+	setBaseOffset(0);
+	setExtentOffset(0);
+	update();
+}
+
+NodeImpl *KHTMLSelection::startNode() const
+{ 
+    return m_startNode;
+}
+
+long KHTMLSelection::startOffset() const
+{ 
+    return m_startOffset;
+}
+
+NodeImpl *KHTMLSelection::endNode() const 
+{
+    return m_endNode;
+}
+
+long KHTMLSelection::endOffset() const 
+{ 
+    return m_endOffset;
+}
+
+void KHTMLSelection::setVisible(bool flag)
+{
+    m_visible = flag;
+    update();
+}
+
+void KHTMLSelection::invalidate()
+{
+    update();
+}
+
+void KHTMLSelection::update()
+{
+    // make sure we do not have a dangling start or end
+	if (!m_baseNode && !m_extentNode) {
+        setBaseOffset(0);
+        setExtentOffset(0);
+        m_baseIsStart = true;
+    }
+	else if (!m_baseNode) {
+		setBaseNode(m_extentNode);
+		setBaseOffset(m_extentOffset);
+        m_baseIsStart = true;
+	}
+	else if (!m_extentNode) {
+		setExtentNode(m_baseNode);
+		setExtentOffset(m_baseOffset);
+        m_baseIsStart = true;
+	}
+    else {
+        // adjust m_baseIsStart as needed
+        if (m_baseNode == m_extentNode) {
+            if (m_baseOffset > m_extentOffset)
+                m_baseIsStart = false;
+            else 
+                m_baseIsStart = true;
+        }
+        else if (nodeIsBeforeNode(m_baseNode, m_extentNode))
+            m_baseIsStart = true;
+        else
+            m_baseIsStart = false;
+    }
+
+    // update start and end
+    m_startEndValid = false;
+    calculateStartAndEnd();
+    
+    // update the blink timer
+    if (m_caretBlinkTimer >= 0)
+        killTimer(m_caretBlinkTimer);
+    if (m_visible && m_state == CARET && m_caretBlinks)
+        m_caretBlinkTimer = startTimer(CARET_BLINK_FREQUENCY);
+    else
+        m_caretBlinkTimer = -1;
+
+    // short-circuit if not visible
+    if (!m_visible) {
+        if (m_caretPaint) {
+            m_caretPaint = false;
+            repaint();
+        }
+        return;
+    }
+
+    // short-circuit if not CARET state
+	if (m_state != CARET)
+		return;
+
+    // calculate the new caret rendering position
+    int oldX = m_caretX;   
+    int oldY = m_caretY;   
+    int oldSize = m_caretSize;
+    
+    int newX = 0;
+    int newY = 0;
+    int newSize = 0;
+    
+    NodeImpl *node = startNode();
+    if (node && node->renderer()) {
+        int w;
+        node->renderer()->caretPos(startOffset(), true, newX, newY, w, newSize);
+    }
+
+    // repaint the old position if necessary
+    // prevents two carets from ever being drawn
+    if (m_caretPaint && (oldX != newX || oldY != newY || oldSize != newSize)) {
+        repaint();
+    }
+
+    // update caret rendering position
+    m_caretX = newX;
+    m_caretY = newY;
+    m_caretSize = newSize;
+
+    // paint the caret if it is visible
+    if (m_visible && m_caretSize != 0) {
+        m_caretPaint = true;
+        repaint();
+    }
+}
+
+bool KHTMLSelection::isEmpty() const
+{
+    return m_baseNode == 0 && m_extentNode == 0;
+}
+
+#ifdef APPLE_CHANGES
+void KHTMLSelection::paint(QPainter *p, const QRect &rect) const
+{
+    if (!m_caretPaint || m_state != CARET)
+        return;
+
+    QRect pos(m_caretX, m_caretY, 1, m_caretSize);
+    if (pos.intersects(rect)) {
+        QPen pen = p->pen();
+        pen.setStyle(SolidLine);
+        pen.setColor(Qt::black);
+        pen.setWidth(1);
+        p->setPen(pen);
+        p->drawLine(pos.left(), pos.top(), pos.left(), pos.bottom());
+    }
+}
+#endif
+
+void KHTMLSelection::setPart(KHTMLPart *part)
+{
+    m_part = part;
+}
+
+void KHTMLSelection::timerEvent(QTimerEvent *e)
+{
+    if (e->timerId() == m_caretBlinkTimer && m_visible) {
+        m_caretPaint = !m_caretPaint;
+        repaint();
+    }
+}
+
+void KHTMLSelection::repaint(bool immediate) const
+{
+    KHTMLView *v = m_part->view();
+    if (!v)
+        return;
+    // EDIT FIXME: fudge a bit to make sure we don't leave behind artifacts
+    v->updateContents(m_caretX - 1, m_caretY - 1, 3, m_caretSize + 2, immediate);
+}
+
+void KHTMLSelection::setBaseNode(DOM::NodeImpl *node)
+{
+	if (m_baseNode == node)
+		return;
+
+	if (m_baseNode)
+		m_baseNode->deref();
+	
+	m_baseNode = node;
+	
+	if (m_baseNode)
+		m_baseNode->ref();
+}
+
+void KHTMLSelection::setBaseOffset(long offset)
+{
+	m_baseOffset = offset;
+}
+
+void KHTMLSelection::setExtentNode(DOM::NodeImpl *node)
+{
+	if (m_extentNode == node)
+		return;
+
+	if (m_extentNode)
+		m_extentNode->deref();
+	
+	m_extentNode = node;
+	
+	if (m_extentNode)
+		m_extentNode->ref();
+}
+	
+void KHTMLSelection::setExtentOffset(long offset)
+{
+	m_extentOffset = offset;
+}
+
+void KHTMLSelection::setStart(DOM::NodeImpl *node, long offset)
+{
+    setStartNode(node);
+    setStartOffset(offset);
+}
+
+void KHTMLSelection::setStartNode(DOM::NodeImpl *node)
+{
+	if (m_startNode == node)
+		return;
+
+	if (m_startNode)
+		m_startNode->deref();
+	
+	m_startNode = node;
+	
+	if (m_startNode)
+		m_startNode->ref();
+}
+
+void KHTMLSelection::setStartOffset(long offset)
+{
+	m_startOffset = offset;
+}
+
+void KHTMLSelection::setEnd(DOM::NodeImpl *node, long offset)
+{
+    setEndNode(node);
+    setEndOffset(offset);
+}
+
+void KHTMLSelection::setEndNode(DOM::NodeImpl *node)
+{
+	if (m_endNode == node)
+		return;
+
+	if (m_endNode)
+		m_endNode->deref();
+	
+	m_endNode = node;
+	
+	if (m_endNode)
+		m_endNode->ref();
+}
+	
+void KHTMLSelection::setEndOffset(long offset)
+{
+	m_endOffset = offset;
+}
+
+void KHTMLSelection::expandSelection(ETextElement select)
+{
+    m_startEndValid = false;
+    calculateStartAndEnd(select);
+}
+
+void KHTMLSelection::calculateStartAndEnd(ETextElement select)
+{
+    if (m_startEndValid)
+        return;
+
+#if !APPLE_CHANGES
+    if (m_baseIsStart) {
+        setStartNode(m_baseNode);
+        setStartOffset(m_baseOffset);
+        setEndNode(m_extentNode);
+        setEndOffset(m_extentOffset);
+    }
+    else {
+        setStartNode(m_extentNode);
+        setStartOffset(m_extentOffset);
+        setEndNode(m_baseNode);
+        setEndOffset(m_baseOffset);
+    }
+#else
+    if (select == CHARACTER) {
+        if (m_baseIsStart) {
+            setStartNode(m_baseNode);
+            setStartOffset(m_baseOffset);
+            setEndNode(m_extentNode);
+            setEndOffset(m_extentOffset);
+        }
+        else {
+            setStartNode(m_extentNode);
+            setStartOffset(m_extentOffset);
+            setEndNode(m_baseNode);
+            setEndOffset(m_baseOffset);
+        }
+    }
+    else if (select == WORD) {
+        int baseStartOffset = m_baseOffset;
+        int baseEndOffset = m_baseOffset;
+        int extentStartOffset = m_extentOffset;
+        int extentEndOffset = m_extentOffset;
+        if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            DOMString t = m_baseNode->nodeValue();
+            QChar *chars = t.unicode();
+            uint len = t.length();
+            findWordBoundary(chars, len, m_baseOffset, &baseStartOffset, &baseEndOffset);
+        }
+        if (m_extentNode && (m_extentNode->nodeType() == Node::TEXT_NODE || m_extentNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            DOMString t = m_extentNode->nodeValue();
+            QChar *chars = t.unicode();
+            uint len = t.length();
+            findWordBoundary(chars, len, m_extentOffset, &extentStartOffset, &extentEndOffset);
+        }
+        if (m_baseIsStart) {
+            setStartNode(m_baseNode);
+            setStartOffset(baseStartOffset);
+            setEndNode(m_extentNode);
+            setEndOffset(extentEndOffset);
+        }
+        else {
+            setStartNode(m_extentNode);
+            setStartOffset(extentStartOffset);
+            setEndNode(m_baseNode);
+            setEndOffset(baseEndOffset);
+        }
+    }
+    else {  // select == LINE
+        KHTMLSelection baseSelection = *this;
+        KHTMLSelection extentSelection = *this;
+        if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            if (startAndEndLineNodesIncludingNode(m_baseNode, m_baseOffset, baseSelection)) {
+                setStartNode(baseSelection.baseNode());
+                setStartOffset(baseSelection.baseOffset());
+                setEndNode(baseSelection.extentNode());
+                setEndOffset(baseSelection.extentOffset());
+            }
+        }
+        if (m_extentNode && (m_extentNode->nodeType() == Node::TEXT_NODE || m_extentNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            if (startAndEndLineNodesIncludingNode(m_extentNode, m_extentOffset, extentSelection)) {
+                setStartNode(extentSelection.baseNode());
+                setStartOffset(extentSelection.baseOffset());
+                setEndNode(extentSelection.extentNode());
+                setEndOffset(extentSelection.extentOffset());
+            }
+        }
+        if (m_baseIsStart) {
+            setStartNode(baseSelection.startNode());
+            setStartOffset(baseSelection.startOffset());
+            setEndNode(extentSelection.endNode());
+            setEndOffset(extentSelection.endOffset());
+        }
+        else {
+            setStartNode(extentSelection.startNode());
+            setStartOffset(extentSelection.startOffset());
+            setEndNode(baseSelection.endNode());
+            setEndOffset(baseSelection.endOffset());
+        }
+    }
+#endif  // APPLE_CHANGES
+
+	// update the state
+	if (!m_startNode && !m_endNode)
+		m_state = NONE;
+	if (m_startNode == m_endNode && m_startOffset == m_endOffset)
+		m_state = CARET;
+	else
+		m_state = RANGE;
+    
+    m_startEndValid = true;
+}
+
+DOMPosition KHTMLSelection::nextCharacterPosition()
+{
+    DOMPosition result;
+	NodeImpl *node = endNode();
+	long offset = endOffset();
+    long desiredOffset = offset + 1;
+
+    if (!node)
+        return result;
+    
+    //
+    // Look in this renderer
+    //
+    RenderObject *renderer = node->renderer();
+    if (renderer->isText()) {
+        RenderText *textRenderer = static_cast<khtml::RenderText *>(renderer);
+        InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+        unsigned i = 0;
+        for (i = 0; i < runs.count(); i++) {
+            long start = runs[i]->m_start;
+            long end = runs[i]->m_start + runs[i]->m_len;
+            if (desiredOffset > end) {
+                // Skip this node.
+                // It is too early in the text runs to be involved.
+                continue;
+            }
+            else if (desiredOffset >= start && 
+                (desiredOffset < end || (desiredOffset == end && i + 1 == runs.count() && !renderer->nextEditable())) ||
+                (desiredOffset == end && textRenderer->precedesLineBreak() && !textRenderer->followsLineBreak())) {
+                // Desired offset is in this node.
+                // Either it is:
+                // 1. at or after the start and before, but not at the end
+                // 2. at the end of a text run and is immediately followed by a line break
+                //    but does not precede a line break
+                // 3. at the end of the editable content of the document
+                return DOMPosition(renderer->element(), desiredOffset);
+            }
+            else if (desiredOffset <= start) {
+                // The offset we're looking for is before this node
+                // this means the offset must be in text that is
+                // not rendered. Just return the start of the node.
+                return DOMPosition(renderer->element(), start);
+            }
+        }
+    }
+    else if (desiredOffset < renderer->caretMaxOffset() || (desiredOffset == renderer->caretMaxOffset() && !renderer->nextEditable())) {
+        return DOMPosition(node, desiredOffset);
+    }
+
+    //
+    // Look in next renderer(s)
+    //
+    renderer = renderer->nextEditable();
+    while (renderer) {
+        if (renderer->isText()) {
+            RenderText *textRenderer = static_cast<khtml::RenderText *>(renderer);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            if (runs.count())
+                return DOMPosition(renderer->element(), runs[0]->m_start);
+        }
+        else {
+            return DOMPosition(renderer->element(), renderer->caretMinOffset());
+        }
+        renderer = renderer->nextEditable();
+    }
+
+    result = DOMPosition(node, offset);
+    return result;
+}
+
+bool KHTMLSelection::nodeIsBeforeNode(NodeImpl *n1, NodeImpl *n2) 
+{
+	if (!n1 || !n2) 
+		return true;
+ 
+ 	if (n1 == n2)
+ 		return true;
+ 
+ 	bool result = false;
+    int n1Depth = 0;
+    int n2Depth = 0;
+
+    // First we find the depths of the two nodes in the tree (n1Depth, n2Depth)
+    DOM::NodeImpl *n = n1;
+    while (n->parentNode()) {
+        n = n->parentNode();
+        n1Depth++;
+    }
+    n = n2;
+    while (n->parentNode()) {
+        n = n->parentNode();
+        n2Depth++;
+    }
+    // Climb up the tree with the deeper node, until both nodes have equal depth
+    while (n2Depth > n1Depth) {
+        n2 = n2->parentNode();
+        n2Depth--;
+    }
+    while (n1Depth > n2Depth) {
+        n1 = n1->parentNode();
+        n1Depth--;
+    }
+    // Climb the tree with both n1 and n2 until they have the same parent
+    while (n1->parentNode() != n2->parentNode()) {
+        n1 = n1->parentNode();
+        n2 = n2->parentNode();
+    }
+    // Iterate through the parent's children until n1 or n2 is found
+    n = n1->parentNode()->firstChild();
+    while (n) {
+        if (n == n1) {
+            result = true;
+            break;
+        }
+        else if (n == n2) {
+            result = false;
+            break;
+        }
+        n = n->nextSibling();
+    }
+	return result;
+}
+
+#if APPLE_CHANGES
+
+static void findWordBoundary(QChar *chars, int len, int position, int *start, int *end)
+{
+    TextBreakLocatorRef breakLocator;
+    OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakWordMask, &breakLocator);
+    if (status == noErr) {
+        UniCharArrayOffset startOffset, endOffset;
+        status = UCFindTextBreak(breakLocator, kUCTextBreakWordMask, 0, (const UniChar *)chars, len, position, &endOffset);
+        if (status == noErr) {
+            status = UCFindTextBreak(breakLocator, kUCTextBreakWordMask, kUCTextBreakGoBackwardsMask, (const UniChar *)chars, len, position, &startOffset);
+        }
+        UCDisposeTextBreakLocator(&breakLocator);
+        if (status == noErr) {
+            *start = startOffset;
+            *end = endOffset;
+            return;
+        }
+    }
+    
+    // If Carbon fails (why would it?), do a simple space/punctuation boundary check.
+    if (chars[position].isSpace()) {
+        int pos = position;
+        while (chars[pos].isSpace() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (chars[pos].isSpace() && pos < (int)len)
+            pos++;
+        *end = pos;
+    } else if (chars[position].isPunct()) {
+        int pos = position;
+        while (chars[pos].isPunct() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (chars[pos].isPunct() && pos < (int)len)
+            pos++;
+        *end = pos;
+    } else {
+        int pos = position;
+        while (!chars[pos].isSpace() && !chars[pos].isPunct() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (!chars[pos].isSpace() && !chars[pos].isPunct() && pos < (int)len)
+            pos++;
+        *end = pos;
+    }
+}
+
+static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
+{
+    for (RenderObject *n = renderNode; n; n = n->nextSibling()) {
+        if (n->isText()) {
+            RenderText *textRenderer = static_cast<khtml::RenderText *>(n);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            for (unsigned i = 0; i != runs.count(); i++) {
+                if (runs[i]->m_y == y) {
+                    startNode = textRenderer->element();
+                    startOffset = runs[i]->m_start;
+                    return true;
+                }
+            }
+        }
+        
+        if (firstRunAt(n->firstChild(), y, startNode, startOffset)) {
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+static bool lastRunAt(RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset)
+{
+    RenderObject *n = renderNode;
+    if (!n) {
+        return false;
+    }
+    RenderObject *next;
+    while ((next = n->nextSibling())) {
+        n = next;
+    }
+    
+    while (1) {
+        if (lastRunAt(n->firstChild(), y, endNode, endOffset)) {
+            return true;
+        }
+    
+        if (n->isText()) {
+            RenderText *textRenderer =  static_cast<khtml::RenderText *>(n);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            for (int i = (int)runs.count()-1; i >= 0; i--) {
+                if (runs[i]->m_y == y) {
+                    endNode = textRenderer->element();
+                    endOffset = runs[i]->m_start + runs[i]->m_len;
+                    return true;
+                }
+            }
+        }
+        
+        if (n == renderNode) {
+            return false;
+        }
+        
+        n = n->previousSibling();
+    }
+}
+
+static bool startAndEndLineNodesIncludingNode(DOM::NodeImpl *node, int offset, KHTMLSelection &selection)
+{
+    if (node && (node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE)) {
+        int pos;
+        int selectionPointY;
+        RenderText *renderer = static_cast<RenderText *>(node->renderer());
+        InlineTextBox * run = renderer->findNextInlineTextBox( offset, pos );
+        DOMString t = node->nodeValue();
+        
+        if (!run)
+            return false;
+            
+        selectionPointY = run->m_y;
+        
+        // Go up to first non-inline element.
+        khtml::RenderObject *renderNode = renderer;
+        while (renderNode && renderNode->isInline())
+            renderNode = renderNode->parent();
+        
+        renderNode = renderNode->firstChild();
+        
+        DOM::NodeImpl *startNode = 0;
+        DOM::NodeImpl *endNode = 0;
+        long startOffset;
+        long endOffset;
+        
+        // Look for all the first child in the block that is on the same line
+        // as the selection point.
+        if (!firstRunAt (renderNode, selectionPointY, startNode, startOffset))
+            return false;
+    
+        // Look for all the last child in the block that is on the same line
+        // as the selection point.
+        if (!lastRunAt (renderNode, selectionPointY, endNode, endOffset))
+            return false;
+        
+        selection.setSelection(startNode, startOffset, endNode, endOffset);
+        
+        return true;
+    }
+    return false;
+}
+
+#endif
diff --git a/WebCore/khtml/editing/SelectionController.h b/WebCore/khtml/editing/SelectionController.h
new file mode 100644
index 0000000..e073149
--- /dev/null
+++ b/WebCore/khtml/editing/SelectionController.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef __khtml_selection_h__
+#define __khtml_selection_h__
+
+#include <qobject.h>
+
+class KHTMLPart;
+class KHTMLPartPrivate;
+class KHTMLView;
+class QPainter;
+class QRect;
+class QTimerEvent;
+
+namespace DOM {
+    class DOMPosition;
+    class NodeImpl;
+    class Range;
+};
+
+class KHTMLSelection : public QObject
+{
+  Q_OBJECT
+
+public:
+    KHTMLSelection();
+    KHTMLSelection(const KHTMLSelection &);
+    ~KHTMLSelection();
+
+	enum EState { NONE, CARET, RANGE };
+	enum ETextElement { CHARACTER, WORD, LINE };
+	enum EDirection { FORWARD, BACKWARD };
+	enum EAlter { MOVE, EXTEND };
+
+	EState state() const { return m_state; }
+
+    void setSelection(DOM::NodeImpl *node, long offset);
+    void setSelection(const DOM::Range &);
+    void setSelection(const DOM::DOMPosition &);
+    void setSelection(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset);
+    void setBase(DOM::NodeImpl *node, long offset);
+    void setExtent(DOM::NodeImpl *node, long offset);
+    void expandSelection(ETextElement);
+    bool alterSelection(EAlter, EDirection, ETextElement);
+    void clearSelection();
+    
+    DOM::NodeImpl *baseNode() const { return m_baseNode; }
+    long baseOffset() const { return m_baseOffset; }
+
+    DOM::NodeImpl *extentNode() const { return m_extentNode; }
+    long extentOffset() const { return m_extentOffset; }
+
+    DOM::NodeImpl *startNode() const;
+    long startOffset() const;
+
+    DOM::NodeImpl *endNode() const;
+    long endOffset() const;
+
+    void setVisible(bool flag=true);
+    bool visible() const { return m_visible; }
+    
+    void invalidate();
+    
+    bool isEmpty() const;
+    
+#ifdef APPLE_CHANGES
+    void paint(QPainter *p, const QRect &rect) const;
+#endif
+
+    KHTMLSelection &operator=(const KHTMLSelection &o);
+    
+    friend bool operator==(const KHTMLSelection &a, const KHTMLSelection &b);
+    friend bool operator!=(const KHTMLSelection &a, const KHTMLSelection &b);
+    
+    friend class KHTMLPart;
+
+    void dump() {
+        fprintf(stderr, "selection: %p:%d ; %p:%d (%p:%d ; %p:%d)\n", 
+            m_baseNode, m_baseOffset, m_extentNode, m_extentOffset,
+            startNode(), startOffset(), endNode(), endOffset());
+    }
+    
+private:
+    void setPart(KHTMLPart *part);
+
+    void update();
+
+    void timerEvent(QTimerEvent *e);
+    void repaint(bool immediate=false) const;
+
+	void setBaseNode(DOM::NodeImpl *);
+	void setBaseOffset(long);
+	void setExtentNode(DOM::NodeImpl *);
+	void setExtentOffset(long);
+
+	void setStart(DOM::NodeImpl *, long);
+	void setStartNode(DOM::NodeImpl *);
+	void setStartOffset(long);
+	void setEnd(DOM::NodeImpl *, long);
+	void setEndNode(DOM::NodeImpl *);
+	void setEndOffset(long);
+
+    bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
+
+    void calculateStartAndEnd(ETextElement select=CHARACTER);
+    
+    DOM::DOMPosition nextCharacterPosition();
+    
+    KHTMLPart *m_part;            // part for this selection
+
+    DOM::NodeImpl *m_baseNode;    // base node for the selection
+    long m_baseOffset;            // offset into base node where selection is
+    DOM::NodeImpl *m_extentNode;  // extent node for the selection
+    long m_extentOffset;          // offset into extent node where selection is
+
+    DOM::NodeImpl *m_startNode;   // start node for the selection (read-only)
+    long m_startOffset;           // offset into start node where selection is (read-only)
+    DOM::NodeImpl *m_endNode;     // end node for the selection (read-only)
+    long m_endOffset;             // offset into end node where selection is (read-only)
+
+	EState m_state;               // the state of the selection
+
+    int m_caretBlinkTimer;        // caret blink frequency timer id
+	
+	int m_caretX;
+	int m_caretY;
+	int m_caretSize;
+
+	bool m_baseIsStart : 1;     // true if base node is before the extent node
+    bool m_caretBlinks : 1;     // true if caret blinks
+    bool m_caretPaint : 1;      // flag used to deal with blinking the caret
+    bool m_visible : 1;         // true if selection is to be displayed at all
+	bool m_startEndValid : 1;   // true if the start and end are valid
+};
+
+
+inline bool operator==(const KHTMLSelection &a, const KHTMLSelection &b)
+{
+    return a.baseNode() == b.baseNode() && a.baseOffset() == b.baseOffset() &&
+        a.extentNode() == b.extentNode() && a.extentOffset() == b.extentOffset();
+}
+
+inline bool operator!=(const KHTMLSelection &a, const KHTMLSelection &b)
+{
+    return !(a == b);
+}
+
+#endif
\ No newline at end of file
diff --git a/WebCore/khtml/editing/htmlediting.cpp b/WebCore/khtml/editing/htmlediting.cpp
new file mode 100644
index 0000000..c9dda8d
--- /dev/null
+++ b/WebCore/khtml/editing/htmlediting.cpp
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "htmlediting.h"
+
+#if APPLE_CHANGES
+#include "KWQAssertions.h"
+#endif
+
+#include "khtmlview.h"
+#include "khtml_part.h"
+#include "khtml_selection.h"
+#include "rendering/render_object.h"
+#include "xml/dom_elementimpl.h"
+#include "xml/dom_nodeimpl.h"
+#include "xml/dom2_rangeimpl.h"
+#include "xml/dom_textimpl.h"
+
+using DOM::DocumentImpl;
+using DOM::DOMString;
+using DOM::ElementImpl;
+using DOM::Node;
+using DOM::NodeImpl;
+using DOM::Range;
+using DOM::RangeImpl;
+using DOM::TextImpl;
+
+using khtml::DeleteTextCommand;
+using khtml::EditCommand;
+using khtml::EditCommandID;
+using khtml::InputTextCommand;
+
+//------------------------------------------------------------------------------------------
+// EditCommand
+
+EditCommand::EditCommand(DOM::DocumentImpl *document) : m_document(0)
+{
+    m_document = document;
+    if (m_document) {
+        m_document->ref();
+    }
+}
+
+EditCommand::~EditCommand()
+{
+    if (m_document)
+        m_document->deref();
+}
+
+void EditCommand::deleteSelection()
+{
+    if (!m_document || !m_document->view() || !m_document->view()->part())
+        return;
+    
+    KHTMLSelection &selection = m_document->view()->part()->getKHTMLSelection();
+    Range range(selection.startNode(), selection.startOffset(), selection.endNode(), selection.endOffset());
+    range.deleteContents();
+    selection.setSelection(selection.startNode(), selection.startOffset());
+    m_document->clearSelection();
+}
+
+void EditCommand::pruneEmptyNodes() const
+{
+    return;
+
+#if 0
+    KHTMLView *view = document()->view();
+    if (!view)
+        return;
+
+    KHTMLPart *part = view->part();
+    if (!part)
+        return;
+
+    KHTMLSelection &selection = part->getKHTMLSelection();
+    
+    bool prunedNodes = false;
+    NodeImpl *node = selection.startNode();
+    while (1) {
+        if (node->isTextNode()) {
+            TextImpl *textNode = static_cast<TextImpl *>(node);
+            if (textNode->length() == 0) {
+                node = textNode->traversePreviousNode();
+                removeNode(textNode);
+                prunedNodes = true;
+            }
+            else {
+                break;
+            }
+        }
+        else if (!node->hasChildNodes()) {
+            NodeImpl *n = node;
+            node = node->traversePreviousNode();
+            removeNode(n);
+            prunedNodes = true;
+        }
+        else {
+            break;
+        }
+    }
+    
+    if (prunedNodes) {
+        selection.setSelection(node, node->caretMaxOffset());
+    }
+#endif
+}
+
+void EditCommand::removeNode(DOM::NodeImpl *node) const
+{
+    if (!node)
+        return;
+    
+    int exceptionCode;
+    node->remove(exceptionCode);
+}
+
+//------------------------------------------------------------------------------------------
+// InputTextCommand
+
+EditCommandID InputTextCommand::commandID() const { return InputTextCommandID; }
+
+InputTextCommand::InputTextCommand(DocumentImpl *document, const DOMString &text) 
+    : EditCommand(document)
+{
+    if (text.isEmpty()) {
+#if APPLE_CHANGES
+        ERROR("InputTextCommand constructed with zero-length string");
+#endif
+        m_text = "";
+    }
+    else {
+        m_text = text; 
+    }
+}
+
+bool InputTextCommand::isLineBreak() const
+{
+    return m_text.length() == 1 && (m_text[0] == '\n' || m_text[0] == '\r');
+}
+
+bool InputTextCommand::isSpace() const
+{
+    return m_text.length() == 1 && (m_text[0] == ' ');
+}
+
+bool InputTextCommand::apply()
+{
+    KHTMLView *view = document()->view();
+    if (!view)
+        return false;
+
+    KHTMLPart *part = view->part();
+    if (!part)
+        return false;
+
+    KHTMLSelection &selection = part->getKHTMLSelection();
+    if (!selection.startNode()->isTextNode())
+        return false;
+
+    // Delete the current selection
+    if (selection.state() == KHTMLSelection::RANGE) {
+        deleteSelection();
+        // EDIT FIXME: adjust selection position
+    }
+    
+    TextImpl *textNode = static_cast<TextImpl *>(selection.startNode());
+    int exceptionCode;
+    
+    if (isLineBreak()) {
+        TextImpl *textBeforeNode = document()->createTextNode(textNode->substringData(0, selection.startOffset(), exceptionCode));
+        textNode->deleteData(0, selection.startOffset(), exceptionCode);
+        ElementImpl *breakNode = document()->createHTMLElement("BR", exceptionCode);
+        textNode->parentNode()->insertBefore(textBeforeNode, textNode, exceptionCode);
+        textNode->parentNode()->insertBefore(breakNode, textNode, exceptionCode);
+        textBeforeNode->deref();
+        breakNode->deref();
+        
+        // Set the cursor at the beginning of the node after the split.
+        selection.setSelection(textNode, 0);
+    }
+    else {
+        textNode->insertData(selection.startOffset(), text(), exceptionCode);
+        // EDIT FIXME: this is a hack for now
+        // advance the cursor
+        int textLength = text().length();
+        selection.setSelection(selection.startNode(), selection.startOffset() + textLength);
+    }
+
+    return true;
+}
+
+bool InputTextCommand::canUndo() const
+{
+    return true;
+}
+
+//------------------------------------------------------------------------------------------
+// DeleteTextCommand
+
+EditCommandID DeleteTextCommand::commandID() const { return DeleteTextCommandID; }
+
+DeleteTextCommand::DeleteTextCommand(DocumentImpl *document) 
+    : EditCommand(document)
+{
+}
+
+bool DeleteTextCommand::apply()
+{
+    KHTMLView *view = document()->view();
+    if (!view)
+        return false;
+
+    KHTMLPart *part = view->part();
+    if (!part)
+        return false;
+
+    KHTMLSelection &selection = part->getKHTMLSelection();
+
+    // Delete the current selection
+    if (selection.state() == KHTMLSelection::RANGE) {
+        deleteSelection();
+        // EDIT FIXME: adjust selection position
+        return true;
+    }
+
+    if (!selection.startNode())
+        return false;
+
+    NodeImpl *caretNode = selection.startNode();
+
+    if (caretNode->isTextNode()) {
+        int exceptionCode;
+
+        // Check if we can delete character at cursor
+        int offset = selection.startOffset() - 1;
+        if (offset >= 0) {
+            TextImpl *textNode = static_cast<TextImpl *>(caretNode);
+            textNode->deleteData(offset, 1, exceptionCode);
+            selection.setSelection(textNode, offset);
+            pruneEmptyNodes();
+            return true;
+        }
+        
+        // Check if previous sibling is a BR element
+        NodeImpl *previousSibling = caretNode->previousSibling();
+        if (previousSibling->renderer() && previousSibling->renderer()->isBR()) {
+            caretNode->parentNode()->removeChild(previousSibling, exceptionCode);
+            // EDIT FIXME: adjust selection position
+            return true;
+        }
+        
+        // Check if previous leaf node is a text node
+        NodeImpl *previousLeafNode = caretNode->previousLeafNode();
+        if (previousLeafNode->isTextNode()) {
+            TextImpl *textNode = static_cast<TextImpl *>(previousLeafNode);
+            offset = previousLeafNode->caretMaxOffset() - 1;
+            textNode->deleteData(offset, 1, exceptionCode);
+            selection.setSelection(textNode, offset);
+            pruneEmptyNodes();
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool DeleteTextCommand::canUndo() const
+{
+    return true;
+}
+
diff --git a/WebCore/khtml/editing/htmlediting.h b/WebCore/khtml/editing/htmlediting.h
new file mode 100644
index 0000000..95fd2bf
--- /dev/null
+++ b/WebCore/khtml/editing/htmlediting.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef __htmlediting_h__
+#define __htmlediting_h__
+
+#include <khtml_selection.h>
+#include <dom_docimpl.h>
+#include <dom_string.h>
+#include <dom_node.h>
+#include <dom_nodeimpl.h>
+#include <dom2_range.h>
+
+class KHTMLSelection;
+
+namespace khtml {
+
+enum EditCommandID { InputTextCommandID, DeleteTextCommandID, };
+
+class EditCommand
+{
+public:    
+    EditCommand(DOM::DocumentImpl *document);
+    virtual ~EditCommand();
+
+    virtual EditCommandID commandID() const = 0;
+
+    DOM::DocumentImpl *document() const { return m_document; }
+
+    virtual bool apply() = 0;
+    virtual bool canUndo() const = 0;
+    
+protected:
+    void deleteSelection();
+    void pruneEmptyNodes() const;
+    void removeNode(DOM::NodeImpl *) const;
+    
+private:
+    DOM::DocumentImpl *m_document;
+};
+
+
+class InputTextCommand : public EditCommand
+{
+public:
+    InputTextCommand(DOM::DocumentImpl *document, const DOM::DOMString &text);
+    virtual ~InputTextCommand() {};
+    
+    virtual EditCommandID commandID() const;
+    
+    virtual bool apply();
+    virtual bool canUndo() const;
+
+    DOM::DOMString text() const { return m_text; }
+    bool isLineBreak() const;
+    bool isSpace() const;
+    
+private:
+    DOM::DOMString m_text;
+};
+
+class DeleteTextCommand : public EditCommand
+{
+public:
+    DeleteTextCommand(DOM::DocumentImpl *document);
+    virtual ~DeleteTextCommand() {};
+    
+    virtual EditCommandID commandID() const;
+    
+    virtual bool apply();
+    virtual bool canUndo() const;
+};
+
+}; // end namespace khtml
+
+#endif
diff --git a/WebCore/khtml/editing/selection.cpp b/WebCore/khtml/editing/selection.cpp
new file mode 100644
index 0000000..e4e9cfa
--- /dev/null
+++ b/WebCore/khtml/editing/selection.cpp
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+  
+#include "khtml_selection.h"
+
+#include "khtml_part.h"
+#include "khtmlview.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qrect.h"
+#include "dom/dom2_range.h"
+#include "dom/dom_node.h"
+#include "dom/dom_position.h"
+#include "dom/dom_string.h"
+#include "rendering/render_object.h"
+#include "rendering/render_style.h"
+#include "rendering/render_text.h"
+#include "xml/dom_docimpl.h"
+#include "xml/dom_nodeimpl.h"
+#include "xml/dom_textimpl.h"
+
+#if APPLE_CHANGES
+#include <KWQAssertions.h>
+#include <CoreServices/CoreServices.h>
+#endif
+
+using DOM::DocumentImpl;
+using DOM::DOMPosition;
+using DOM::DOMString;
+using DOM::Node;
+using DOM::NodeImpl;
+using DOM::Range;
+using DOM::TextImpl;
+using khtml::InlineTextBox;
+using khtml::InlineTextBoxArray;
+using khtml::RenderObject;
+using khtml::RenderText;
+
+enum { CARET_BLINK_FREQUENCY = 500 };
+
+#if APPLE_CHANGES
+static void findWordBoundary(QChar *chars, int len, int position, int *start, int *end);
+static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset);
+static bool lastRunAt(RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset);
+static bool startAndEndLineNodesIncludingNode(DOM::NodeImpl *node, int offset, KHTMLSelection &selection);
+#endif
+
+
+KHTMLSelection::KHTMLSelection() 
+	: QObject(),
+	  m_part(0),
+	  m_baseNode(0), m_baseOffset(0), m_extentNode(0), m_extentOffset(0),
+	  m_startNode(0), m_startOffset(0), m_endNode(0), m_endOffset(0),
+	  m_state(NONE), m_caretBlinkTimer(0),
+      m_baseIsStart(true), m_caretBlinks(true), m_caretPaint(false), 
+      m_visible(false), m_startEndValid(false)
+{
+}
+
+KHTMLSelection::KHTMLSelection(const KHTMLSelection &o)
+	: QObject(),
+	  m_part(o.m_part),
+	  m_baseNode(0), m_baseOffset(0), m_extentNode(0), m_extentOffset(0),
+	  m_startNode(0), m_startOffset(0), m_endNode(0), m_endOffset(0)
+{
+    setBase(o.baseNode(), o.baseOffset());
+    setExtent(o.extentNode(), o.extentOffset());
+    setStart(o.startNode(), o.startOffset());
+    setEnd(o.endNode(), o.endOffset());
+
+	m_state = o.m_state;
+	m_caretBlinkTimer = o.m_caretBlinkTimer;
+	m_baseIsStart = o.m_baseIsStart;
+	m_caretBlinks = o.m_caretBlinks;
+	m_caretPaint = true;
+	m_visible = o.m_visible;
+    m_startEndValid = true;
+}
+
+KHTMLSelection::~KHTMLSelection()
+{
+    if (m_baseNode)
+        m_baseNode->deref();
+    if (m_extentNode)
+        m_extentNode->deref();
+}
+
+KHTMLSelection &KHTMLSelection::operator=(const KHTMLSelection &o)
+{
+    m_part = o.m_part;
+    
+    setBase(o.baseNode(), o.baseOffset());
+    setExtent(o.extentNode(), o.extentOffset());
+    setStart(o.startNode(), o.startOffset());
+    setEnd(o.endNode(), o.endOffset());
+
+	m_state = o.m_state;
+	m_caretBlinkTimer = o.m_caretBlinkTimer;
+	m_baseIsStart = o.m_baseIsStart;
+	m_caretBlinks = o.m_caretBlinks;
+	m_caretPaint = true;
+	m_visible = o.m_visible;
+    m_startEndValid = true;
+    return *this;
+}
+
+void KHTMLSelection::setSelection(DOM::NodeImpl *node, long offset)
+{
+	setBaseNode(node);
+	setExtentNode(node);
+	setBaseOffset(offset);
+	setExtentOffset(offset);
+	update();
+}
+
+void KHTMLSelection::setSelection(const DOM::Range &r)
+{
+	setSelection(r.startContainer().handle(), r.startOffset(), 
+		r.endContainer().handle(), r.endOffset());
+}
+
+void KHTMLSelection::setSelection(const DOM::DOMPosition &pos)
+{
+	setSelection(pos.node(), pos.offset());
+}
+
+void KHTMLSelection::setSelection(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset)
+{
+	setBaseNode(baseNode);
+	setExtentNode(extentNode);
+	setBaseOffset(baseOffset);
+	setExtentOffset(extentOffset);
+	update();
+}
+
+void KHTMLSelection::setBase(DOM::NodeImpl *node, long offset)
+{
+	setBaseNode(node);
+	setBaseOffset(offset);
+	update();
+}
+
+void KHTMLSelection::setExtent(DOM::NodeImpl *node, long offset)
+{
+	setExtentNode(node);
+	setExtentOffset(offset);
+	update();
+}
+
+bool KHTMLSelection::alterSelection(EAlter alter, EDirection dir, ETextElement elem)
+{
+    DOMPosition pos;
+    
+    switch (dir) {
+        case FORWARD:
+            switch (elem) {
+                case CHARACTER:
+                    pos = nextCharacterPosition();
+                    break;
+                case WORD:
+                    break;
+                case LINE:
+                    break;
+            }
+            break;
+        case BACKWARD:
+            switch (elem) {
+                case CHARACTER:
+                    break;
+                case WORD:
+                    break;
+                case LINE:
+                    break;
+            }
+            break;
+    }
+    
+    if (pos.isEmpty())
+        return false;
+    
+    if (alter == MOVE)
+        setSelection(pos.node(), pos.offset());
+    else // alter == EXTEND
+        setExtent(pos.node(), pos.offset());
+    
+    return true;
+}
+
+void KHTMLSelection::clearSelection()
+{
+	setBaseNode(0);
+	setExtentNode(0);
+	setBaseOffset(0);
+	setExtentOffset(0);
+	update();
+}
+
+NodeImpl *KHTMLSelection::startNode() const
+{ 
+    return m_startNode;
+}
+
+long KHTMLSelection::startOffset() const
+{ 
+    return m_startOffset;
+}
+
+NodeImpl *KHTMLSelection::endNode() const 
+{
+    return m_endNode;
+}
+
+long KHTMLSelection::endOffset() const 
+{ 
+    return m_endOffset;
+}
+
+void KHTMLSelection::setVisible(bool flag)
+{
+    m_visible = flag;
+    update();
+}
+
+void KHTMLSelection::invalidate()
+{
+    update();
+}
+
+void KHTMLSelection::update()
+{
+    // make sure we do not have a dangling start or end
+	if (!m_baseNode && !m_extentNode) {
+        setBaseOffset(0);
+        setExtentOffset(0);
+        m_baseIsStart = true;
+    }
+	else if (!m_baseNode) {
+		setBaseNode(m_extentNode);
+		setBaseOffset(m_extentOffset);
+        m_baseIsStart = true;
+	}
+	else if (!m_extentNode) {
+		setExtentNode(m_baseNode);
+		setExtentOffset(m_baseOffset);
+        m_baseIsStart = true;
+	}
+    else {
+        // adjust m_baseIsStart as needed
+        if (m_baseNode == m_extentNode) {
+            if (m_baseOffset > m_extentOffset)
+                m_baseIsStart = false;
+            else 
+                m_baseIsStart = true;
+        }
+        else if (nodeIsBeforeNode(m_baseNode, m_extentNode))
+            m_baseIsStart = true;
+        else
+            m_baseIsStart = false;
+    }
+
+    // update start and end
+    m_startEndValid = false;
+    calculateStartAndEnd();
+    
+    // update the blink timer
+    if (m_caretBlinkTimer >= 0)
+        killTimer(m_caretBlinkTimer);
+    if (m_visible && m_state == CARET && m_caretBlinks)
+        m_caretBlinkTimer = startTimer(CARET_BLINK_FREQUENCY);
+    else
+        m_caretBlinkTimer = -1;
+
+    // short-circuit if not visible
+    if (!m_visible) {
+        if (m_caretPaint) {
+            m_caretPaint = false;
+            repaint();
+        }
+        return;
+    }
+
+    // short-circuit if not CARET state
+	if (m_state != CARET)
+		return;
+
+    // calculate the new caret rendering position
+    int oldX = m_caretX;   
+    int oldY = m_caretY;   
+    int oldSize = m_caretSize;
+    
+    int newX = 0;
+    int newY = 0;
+    int newSize = 0;
+    
+    NodeImpl *node = startNode();
+    if (node && node->renderer()) {
+        int w;
+        node->renderer()->caretPos(startOffset(), true, newX, newY, w, newSize);
+    }
+
+    // repaint the old position if necessary
+    // prevents two carets from ever being drawn
+    if (m_caretPaint && (oldX != newX || oldY != newY || oldSize != newSize)) {
+        repaint();
+    }
+
+    // update caret rendering position
+    m_caretX = newX;
+    m_caretY = newY;
+    m_caretSize = newSize;
+
+    // paint the caret if it is visible
+    if (m_visible && m_caretSize != 0) {
+        m_caretPaint = true;
+        repaint();
+    }
+}
+
+bool KHTMLSelection::isEmpty() const
+{
+    return m_baseNode == 0 && m_extentNode == 0;
+}
+
+#ifdef APPLE_CHANGES
+void KHTMLSelection::paint(QPainter *p, const QRect &rect) const
+{
+    if (!m_caretPaint || m_state != CARET)
+        return;
+
+    QRect pos(m_caretX, m_caretY, 1, m_caretSize);
+    if (pos.intersects(rect)) {
+        QPen pen = p->pen();
+        pen.setStyle(SolidLine);
+        pen.setColor(Qt::black);
+        pen.setWidth(1);
+        p->setPen(pen);
+        p->drawLine(pos.left(), pos.top(), pos.left(), pos.bottom());
+    }
+}
+#endif
+
+void KHTMLSelection::setPart(KHTMLPart *part)
+{
+    m_part = part;
+}
+
+void KHTMLSelection::timerEvent(QTimerEvent *e)
+{
+    if (e->timerId() == m_caretBlinkTimer && m_visible) {
+        m_caretPaint = !m_caretPaint;
+        repaint();
+    }
+}
+
+void KHTMLSelection::repaint(bool immediate) const
+{
+    KHTMLView *v = m_part->view();
+    if (!v)
+        return;
+    // EDIT FIXME: fudge a bit to make sure we don't leave behind artifacts
+    v->updateContents(m_caretX - 1, m_caretY - 1, 3, m_caretSize + 2, immediate);
+}
+
+void KHTMLSelection::setBaseNode(DOM::NodeImpl *node)
+{
+	if (m_baseNode == node)
+		return;
+
+	if (m_baseNode)
+		m_baseNode->deref();
+	
+	m_baseNode = node;
+	
+	if (m_baseNode)
+		m_baseNode->ref();
+}
+
+void KHTMLSelection::setBaseOffset(long offset)
+{
+	m_baseOffset = offset;
+}
+
+void KHTMLSelection::setExtentNode(DOM::NodeImpl *node)
+{
+	if (m_extentNode == node)
+		return;
+
+	if (m_extentNode)
+		m_extentNode->deref();
+	
+	m_extentNode = node;
+	
+	if (m_extentNode)
+		m_extentNode->ref();
+}
+	
+void KHTMLSelection::setExtentOffset(long offset)
+{
+	m_extentOffset = offset;
+}
+
+void KHTMLSelection::setStart(DOM::NodeImpl *node, long offset)
+{
+    setStartNode(node);
+    setStartOffset(offset);
+}
+
+void KHTMLSelection::setStartNode(DOM::NodeImpl *node)
+{
+	if (m_startNode == node)
+		return;
+
+	if (m_startNode)
+		m_startNode->deref();
+	
+	m_startNode = node;
+	
+	if (m_startNode)
+		m_startNode->ref();
+}
+
+void KHTMLSelection::setStartOffset(long offset)
+{
+	m_startOffset = offset;
+}
+
+void KHTMLSelection::setEnd(DOM::NodeImpl *node, long offset)
+{
+    setEndNode(node);
+    setEndOffset(offset);
+}
+
+void KHTMLSelection::setEndNode(DOM::NodeImpl *node)
+{
+	if (m_endNode == node)
+		return;
+
+	if (m_endNode)
+		m_endNode->deref();
+	
+	m_endNode = node;
+	
+	if (m_endNode)
+		m_endNode->ref();
+}
+	
+void KHTMLSelection::setEndOffset(long offset)
+{
+	m_endOffset = offset;
+}
+
+void KHTMLSelection::expandSelection(ETextElement select)
+{
+    m_startEndValid = false;
+    calculateStartAndEnd(select);
+}
+
+void KHTMLSelection::calculateStartAndEnd(ETextElement select)
+{
+    if (m_startEndValid)
+        return;
+
+#if !APPLE_CHANGES
+    if (m_baseIsStart) {
+        setStartNode(m_baseNode);
+        setStartOffset(m_baseOffset);
+        setEndNode(m_extentNode);
+        setEndOffset(m_extentOffset);
+    }
+    else {
+        setStartNode(m_extentNode);
+        setStartOffset(m_extentOffset);
+        setEndNode(m_baseNode);
+        setEndOffset(m_baseOffset);
+    }
+#else
+    if (select == CHARACTER) {
+        if (m_baseIsStart) {
+            setStartNode(m_baseNode);
+            setStartOffset(m_baseOffset);
+            setEndNode(m_extentNode);
+            setEndOffset(m_extentOffset);
+        }
+        else {
+            setStartNode(m_extentNode);
+            setStartOffset(m_extentOffset);
+            setEndNode(m_baseNode);
+            setEndOffset(m_baseOffset);
+        }
+    }
+    else if (select == WORD) {
+        int baseStartOffset = m_baseOffset;
+        int baseEndOffset = m_baseOffset;
+        int extentStartOffset = m_extentOffset;
+        int extentEndOffset = m_extentOffset;
+        if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            DOMString t = m_baseNode->nodeValue();
+            QChar *chars = t.unicode();
+            uint len = t.length();
+            findWordBoundary(chars, len, m_baseOffset, &baseStartOffset, &baseEndOffset);
+        }
+        if (m_extentNode && (m_extentNode->nodeType() == Node::TEXT_NODE || m_extentNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            DOMString t = m_extentNode->nodeValue();
+            QChar *chars = t.unicode();
+            uint len = t.length();
+            findWordBoundary(chars, len, m_extentOffset, &extentStartOffset, &extentEndOffset);
+        }
+        if (m_baseIsStart) {
+            setStartNode(m_baseNode);
+            setStartOffset(baseStartOffset);
+            setEndNode(m_extentNode);
+            setEndOffset(extentEndOffset);
+        }
+        else {
+            setStartNode(m_extentNode);
+            setStartOffset(extentStartOffset);
+            setEndNode(m_baseNode);
+            setEndOffset(baseEndOffset);
+        }
+    }
+    else {  // select == LINE
+        KHTMLSelection baseSelection = *this;
+        KHTMLSelection extentSelection = *this;
+        if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            if (startAndEndLineNodesIncludingNode(m_baseNode, m_baseOffset, baseSelection)) {
+                setStartNode(baseSelection.baseNode());
+                setStartOffset(baseSelection.baseOffset());
+                setEndNode(baseSelection.extentNode());
+                setEndOffset(baseSelection.extentOffset());
+            }
+        }
+        if (m_extentNode && (m_extentNode->nodeType() == Node::TEXT_NODE || m_extentNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            if (startAndEndLineNodesIncludingNode(m_extentNode, m_extentOffset, extentSelection)) {
+                setStartNode(extentSelection.baseNode());
+                setStartOffset(extentSelection.baseOffset());
+                setEndNode(extentSelection.extentNode());
+                setEndOffset(extentSelection.extentOffset());
+            }
+        }
+        if (m_baseIsStart) {
+            setStartNode(baseSelection.startNode());
+            setStartOffset(baseSelection.startOffset());
+            setEndNode(extentSelection.endNode());
+            setEndOffset(extentSelection.endOffset());
+        }
+        else {
+            setStartNode(extentSelection.startNode());
+            setStartOffset(extentSelection.startOffset());
+            setEndNode(baseSelection.endNode());
+            setEndOffset(baseSelection.endOffset());
+        }
+    }
+#endif  // APPLE_CHANGES
+
+	// update the state
+	if (!m_startNode && !m_endNode)
+		m_state = NONE;
+	if (m_startNode == m_endNode && m_startOffset == m_endOffset)
+		m_state = CARET;
+	else
+		m_state = RANGE;
+    
+    m_startEndValid = true;
+}
+
+DOMPosition KHTMLSelection::nextCharacterPosition()
+{
+    DOMPosition result;
+	NodeImpl *node = endNode();
+	long offset = endOffset();
+    long desiredOffset = offset + 1;
+
+    if (!node)
+        return result;
+    
+    //
+    // Look in this renderer
+    //
+    RenderObject *renderer = node->renderer();
+    if (renderer->isText()) {
+        RenderText *textRenderer = static_cast<khtml::RenderText *>(renderer);
+        InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+        unsigned i = 0;
+        for (i = 0; i < runs.count(); i++) {
+            long start = runs[i]->m_start;
+            long end = runs[i]->m_start + runs[i]->m_len;
+            if (desiredOffset > end) {
+                // Skip this node.
+                // It is too early in the text runs to be involved.
+                continue;
+            }
+            else if (desiredOffset >= start && 
+                (desiredOffset < end || (desiredOffset == end && i + 1 == runs.count() && !renderer->nextEditable())) ||
+                (desiredOffset == end && textRenderer->precedesLineBreak() && !textRenderer->followsLineBreak())) {
+                // Desired offset is in this node.
+                // Either it is:
+                // 1. at or after the start and before, but not at the end
+                // 2. at the end of a text run and is immediately followed by a line break
+                //    but does not precede a line break
+                // 3. at the end of the editable content of the document
+                return DOMPosition(renderer->element(), desiredOffset);
+            }
+            else if (desiredOffset <= start) {
+                // The offset we're looking for is before this node
+                // this means the offset must be in text that is
+                // not rendered. Just return the start of the node.
+                return DOMPosition(renderer->element(), start);
+            }
+        }
+    }
+    else if (desiredOffset < renderer->caretMaxOffset() || (desiredOffset == renderer->caretMaxOffset() && !renderer->nextEditable())) {
+        return DOMPosition(node, desiredOffset);
+    }
+
+    //
+    // Look in next renderer(s)
+    //
+    renderer = renderer->nextEditable();
+    while (renderer) {
+        if (renderer->isText()) {
+            RenderText *textRenderer = static_cast<khtml::RenderText *>(renderer);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            if (runs.count())
+                return DOMPosition(renderer->element(), runs[0]->m_start);
+        }
+        else {
+            return DOMPosition(renderer->element(), renderer->caretMinOffset());
+        }
+        renderer = renderer->nextEditable();
+    }
+
+    result = DOMPosition(node, offset);
+    return result;
+}
+
+bool KHTMLSelection::nodeIsBeforeNode(NodeImpl *n1, NodeImpl *n2) 
+{
+	if (!n1 || !n2) 
+		return true;
+ 
+ 	if (n1 == n2)
+ 		return true;
+ 
+ 	bool result = false;
+    int n1Depth = 0;
+    int n2Depth = 0;
+
+    // First we find the depths of the two nodes in the tree (n1Depth, n2Depth)
+    DOM::NodeImpl *n = n1;
+    while (n->parentNode()) {
+        n = n->parentNode();
+        n1Depth++;
+    }
+    n = n2;
+    while (n->parentNode()) {
+        n = n->parentNode();
+        n2Depth++;
+    }
+    // Climb up the tree with the deeper node, until both nodes have equal depth
+    while (n2Depth > n1Depth) {
+        n2 = n2->parentNode();
+        n2Depth--;
+    }
+    while (n1Depth > n2Depth) {
+        n1 = n1->parentNode();
+        n1Depth--;
+    }
+    // Climb the tree with both n1 and n2 until they have the same parent
+    while (n1->parentNode() != n2->parentNode()) {
+        n1 = n1->parentNode();
+        n2 = n2->parentNode();
+    }
+    // Iterate through the parent's children until n1 or n2 is found
+    n = n1->parentNode()->firstChild();
+    while (n) {
+        if (n == n1) {
+            result = true;
+            break;
+        }
+        else if (n == n2) {
+            result = false;
+            break;
+        }
+        n = n->nextSibling();
+    }
+	return result;
+}
+
+#if APPLE_CHANGES
+
+static void findWordBoundary(QChar *chars, int len, int position, int *start, int *end)
+{
+    TextBreakLocatorRef breakLocator;
+    OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakWordMask, &breakLocator);
+    if (status == noErr) {
+        UniCharArrayOffset startOffset, endOffset;
+        status = UCFindTextBreak(breakLocator, kUCTextBreakWordMask, 0, (const UniChar *)chars, len, position, &endOffset);
+        if (status == noErr) {
+            status = UCFindTextBreak(breakLocator, kUCTextBreakWordMask, kUCTextBreakGoBackwardsMask, (const UniChar *)chars, len, position, &startOffset);
+        }
+        UCDisposeTextBreakLocator(&breakLocator);
+        if (status == noErr) {
+            *start = startOffset;
+            *end = endOffset;
+            return;
+        }
+    }
+    
+    // If Carbon fails (why would it?), do a simple space/punctuation boundary check.
+    if (chars[position].isSpace()) {
+        int pos = position;
+        while (chars[pos].isSpace() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (chars[pos].isSpace() && pos < (int)len)
+            pos++;
+        *end = pos;
+    } else if (chars[position].isPunct()) {
+        int pos = position;
+        while (chars[pos].isPunct() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (chars[pos].isPunct() && pos < (int)len)
+            pos++;
+        *end = pos;
+    } else {
+        int pos = position;
+        while (!chars[pos].isSpace() && !chars[pos].isPunct() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (!chars[pos].isSpace() && !chars[pos].isPunct() && pos < (int)len)
+            pos++;
+        *end = pos;
+    }
+}
+
+static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
+{
+    for (RenderObject *n = renderNode; n; n = n->nextSibling()) {
+        if (n->isText()) {
+            RenderText *textRenderer = static_cast<khtml::RenderText *>(n);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            for (unsigned i = 0; i != runs.count(); i++) {
+                if (runs[i]->m_y == y) {
+                    startNode = textRenderer->element();
+                    startOffset = runs[i]->m_start;
+                    return true;
+                }
+            }
+        }
+        
+        if (firstRunAt(n->firstChild(), y, startNode, startOffset)) {
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+static bool lastRunAt(RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset)
+{
+    RenderObject *n = renderNode;
+    if (!n) {
+        return false;
+    }
+    RenderObject *next;
+    while ((next = n->nextSibling())) {
+        n = next;
+    }
+    
+    while (1) {
+        if (lastRunAt(n->firstChild(), y, endNode, endOffset)) {
+            return true;
+        }
+    
+        if (n->isText()) {
+            RenderText *textRenderer =  static_cast<khtml::RenderText *>(n);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            for (int i = (int)runs.count()-1; i >= 0; i--) {
+                if (runs[i]->m_y == y) {
+                    endNode = textRenderer->element();
+                    endOffset = runs[i]->m_start + runs[i]->m_len;
+                    return true;
+                }
+            }
+        }
+        
+        if (n == renderNode) {
+            return false;
+        }
+        
+        n = n->previousSibling();
+    }
+}
+
+static bool startAndEndLineNodesIncludingNode(DOM::NodeImpl *node, int offset, KHTMLSelection &selection)
+{
+    if (node && (node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE)) {
+        int pos;
+        int selectionPointY;
+        RenderText *renderer = static_cast<RenderText *>(node->renderer());
+        InlineTextBox * run = renderer->findNextInlineTextBox( offset, pos );
+        DOMString t = node->nodeValue();
+        
+        if (!run)
+            return false;
+            
+        selectionPointY = run->m_y;
+        
+        // Go up to first non-inline element.
+        khtml::RenderObject *renderNode = renderer;
+        while (renderNode && renderNode->isInline())
+            renderNode = renderNode->parent();
+        
+        renderNode = renderNode->firstChild();
+        
+        DOM::NodeImpl *startNode = 0;
+        DOM::NodeImpl *endNode = 0;
+        long startOffset;
+        long endOffset;
+        
+        // Look for all the first child in the block that is on the same line
+        // as the selection point.
+        if (!firstRunAt (renderNode, selectionPointY, startNode, startOffset))
+            return false;
+    
+        // Look for all the last child in the block that is on the same line
+        // as the selection point.
+        if (!lastRunAt (renderNode, selectionPointY, endNode, endOffset))
+            return false;
+        
+        selection.setSelection(startNode, startOffset, endNode, endOffset);
+        
+        return true;
+    }
+    return false;
+}
+
+#endif
diff --git a/WebCore/khtml/editing/selection.h b/WebCore/khtml/editing/selection.h
new file mode 100644
index 0000000..e073149
--- /dev/null
+++ b/WebCore/khtml/editing/selection.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef __khtml_selection_h__
+#define __khtml_selection_h__
+
+#include <qobject.h>
+
+class KHTMLPart;
+class KHTMLPartPrivate;
+class KHTMLView;
+class QPainter;
+class QRect;
+class QTimerEvent;
+
+namespace DOM {
+    class DOMPosition;
+    class NodeImpl;
+    class Range;
+};
+
+class KHTMLSelection : public QObject
+{
+  Q_OBJECT
+
+public:
+    KHTMLSelection();
+    KHTMLSelection(const KHTMLSelection &);
+    ~KHTMLSelection();
+
+	enum EState { NONE, CARET, RANGE };
+	enum ETextElement { CHARACTER, WORD, LINE };
+	enum EDirection { FORWARD, BACKWARD };
+	enum EAlter { MOVE, EXTEND };
+
+	EState state() const { return m_state; }
+
+    void setSelection(DOM::NodeImpl *node, long offset);
+    void setSelection(const DOM::Range &);
+    void setSelection(const DOM::DOMPosition &);
+    void setSelection(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset);
+    void setBase(DOM::NodeImpl *node, long offset);
+    void setExtent(DOM::NodeImpl *node, long offset);
+    void expandSelection(ETextElement);
+    bool alterSelection(EAlter, EDirection, ETextElement);
+    void clearSelection();
+    
+    DOM::NodeImpl *baseNode() const { return m_baseNode; }
+    long baseOffset() const { return m_baseOffset; }
+
+    DOM::NodeImpl *extentNode() const { return m_extentNode; }
+    long extentOffset() const { return m_extentOffset; }
+
+    DOM::NodeImpl *startNode() const;
+    long startOffset() const;
+
+    DOM::NodeImpl *endNode() const;
+    long endOffset() const;
+
+    void setVisible(bool flag=true);
+    bool visible() const { return m_visible; }
+    
+    void invalidate();
+    
+    bool isEmpty() const;
+    
+#ifdef APPLE_CHANGES
+    void paint(QPainter *p, const QRect &rect) const;
+#endif
+
+    KHTMLSelection &operator=(const KHTMLSelection &o);
+    
+    friend bool operator==(const KHTMLSelection &a, const KHTMLSelection &b);
+    friend bool operator!=(const KHTMLSelection &a, const KHTMLSelection &b);
+    
+    friend class KHTMLPart;
+
+    void dump() {
+        fprintf(stderr, "selection: %p:%d ; %p:%d (%p:%d ; %p:%d)\n", 
+            m_baseNode, m_baseOffset, m_extentNode, m_extentOffset,
+            startNode(), startOffset(), endNode(), endOffset());
+    }
+    
+private:
+    void setPart(KHTMLPart *part);
+
+    void update();
+
+    void timerEvent(QTimerEvent *e);
+    void repaint(bool immediate=false) const;
+
+	void setBaseNode(DOM::NodeImpl *);
+	void setBaseOffset(long);
+	void setExtentNode(DOM::NodeImpl *);
+	void setExtentOffset(long);
+
+	void setStart(DOM::NodeImpl *, long);
+	void setStartNode(DOM::NodeImpl *);
+	void setStartOffset(long);
+	void setEnd(DOM::NodeImpl *, long);
+	void setEndNode(DOM::NodeImpl *);
+	void setEndOffset(long);
+
+    bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
+
+    void calculateStartAndEnd(ETextElement select=CHARACTER);
+    
+    DOM::DOMPosition nextCharacterPosition();
+    
+    KHTMLPart *m_part;            // part for this selection
+
+    DOM::NodeImpl *m_baseNode;    // base node for the selection
+    long m_baseOffset;            // offset into base node where selection is
+    DOM::NodeImpl *m_extentNode;  // extent node for the selection
+    long m_extentOffset;          // offset into extent node where selection is
+
+    DOM::NodeImpl *m_startNode;   // start node for the selection (read-only)
+    long m_startOffset;           // offset into start node where selection is (read-only)
+    DOM::NodeImpl *m_endNode;     // end node for the selection (read-only)
+    long m_endOffset;             // offset into end node where selection is (read-only)
+
+	EState m_state;               // the state of the selection
+
+    int m_caretBlinkTimer;        // caret blink frequency timer id
+	
+	int m_caretX;
+	int m_caretY;
+	int m_caretSize;
+
+	bool m_baseIsStart : 1;     // true if base node is before the extent node
+    bool m_caretBlinks : 1;     // true if caret blinks
+    bool m_caretPaint : 1;      // flag used to deal with blinking the caret
+    bool m_visible : 1;         // true if selection is to be displayed at all
+	bool m_startEndValid : 1;   // true if the start and end are valid
+};
+
+
+inline bool operator==(const KHTMLSelection &a, const KHTMLSelection &b)
+{
+    return a.baseNode() == b.baseNode() && a.baseOffset() == b.baseOffset() &&
+        a.extentNode() == b.extentNode() && a.extentOffset() == b.extentOffset();
+}
+
+inline bool operator!=(const KHTMLSelection &a, const KHTMLSelection &b)
+{
+    return !(a == b);
+}
+
+#endif
\ No newline at end of file
diff --git a/WebCore/khtml/html/html_elementimpl.cpp b/WebCore/khtml/html/html_elementimpl.cpp
index 5de0a9d..19689e7 100644
--- a/WebCore/khtml/html/html_elementimpl.cpp
+++ b/WebCore/khtml/html/html_elementimpl.cpp
@@ -37,6 +37,7 @@
 
 #include "khtmlview.h"
 #include "khtml_part.h"
+#include "khtml_selection.h"
 
 #include "rendering/render_object.h"
 #include "rendering/render_replaced.h"
@@ -53,8 +54,7 @@ using namespace DOM;
 using namespace khtml;
 
 HTMLElementImpl::HTMLElementImpl(DocumentPtr *doc)
-    : ElementImpl(doc),
-      m_contentEditable(FlagNone)
+    : ElementImpl(doc)
 {
 }
 
@@ -131,11 +131,12 @@ void HTMLElementImpl::parseAttribute(AttributeImpl *attr)
         setChanged();
         break;
     case ATTR_CONTENTEDITABLE:
-    {
-        setContentEditable(attr->value());
-        setChanged();
+        if (attr->val()) {
+            setContentEditable(attr->value());
+        }
+        else
+            removeCSSProperty(CSS_PROP__KHTML_USER_MODIFY);
         break;
-    }
     case ATTR_STYLE:
         // ### we need to remove old style info in case there was any!
         // ### the inline sheet ay contain more than 1 property!
@@ -571,42 +572,40 @@ void HTMLElementImpl::addHTMLAlignment( DOMString alignment )
 	addCSSProperty( CSS_PROP_VERTICAL_ALIGN, propvalign );
 }
 
-bool HTMLElementImpl::isContentEditable() const {
-    if (m_contentEditable == FlagEnabled)
-        return true;
-    if (m_contentEditable == FlagDisabled)
-        return false;
+bool HTMLElementImpl::isFocusable() const
+{
+    return isContentEditable();
+}
 
-    NodeImpl *node = parentNode();
-    while (node && node->isHTMLElement()) {
-        HTMLElementImpl *element = static_cast<HTMLElementImpl *>(node);
-        if (element->m_contentEditable == FlagEnabled)
-            return true;
-        if (element->m_contentEditable == FlagDisabled)
-            return false;
-        node = node->parentNode();
-    }
-    return false;
+bool HTMLElementImpl::isContentEditable() const {
+    return contentEditable() == "true";
 }
 
 DOMString HTMLElementImpl::contentEditable() const {
-    if (m_contentEditable == FlagEnabled)
-        return "true";
-    if (m_contentEditable == FlagDisabled)
+    if (!renderer())
         return "false";
+    
+    switch (renderer()->style()->userModify()) {
+        case READ_WRITE:
+            return "true";
+        case READ_ONLY:
+            return "false";
+        default:
+            return "inherit";
+    }
     return "inherit";
 }
 
-void HTMLElementImpl::setContentEditable(const DOMString &enabled) {
-    if ( strcasecmp ( enabled, "true" ) == 0 )
-        m_contentEditable = FlagEnabled;
-    else if ( enabled.isEmpty() ) // we want the "true" attribute
-        setAttribute(ATTR_CONTENTEDITABLE, "true");
-    else if ( strcasecmp ( enabled, "false" ) == 0 )
-        m_contentEditable = FlagDisabled;
-    else if ( strcasecmp ( enabled, "inherit" ) == 0 ) {
-        m_contentEditable = FlagNone;
-    }
+void HTMLElementImpl::setContentEditable(const DOMString &enabled) 
+{
+    if (strcasecmp(enabled, "true") == 0 || enabled.isEmpty())
+        addCSSProperty(CSS_PROP__KHTML_USER_MODIFY, CSS_VAL_READ_WRITE);
+    else if (strcasecmp(enabled, "false") == 0)
+        addCSSProperty(CSS_PROP__KHTML_USER_MODIFY, CSS_VAL_READ_ONLY);
+    else if (strcasecmp(enabled, "inherit") == 0)
+        addCSSProperty(CSS_PROP__KHTML_USER_MODIFY, CSS_VAL_INHERIT);
+    else
+        removeCSSProperty(CSS_PROP__KHTML_USER_MODIFY);
 }
 
 void HTMLElementImpl::click()
@@ -641,8 +640,6 @@ DOMString HTMLElementImpl::toString() const
     return ElementImpl::toString();
 }
 
-
-
 // -------------------------------------------------------------------------
 HTMLGenericElementImpl::HTMLGenericElementImpl(DocumentPtr *doc, ushort i)
     : HTMLElementImpl(doc)
diff --git a/WebCore/khtml/html/html_elementimpl.h b/WebCore/khtml/html/html_elementimpl.h
index 831b556..702bb76 100644
--- a/WebCore/khtml/html/html_elementimpl.h
+++ b/WebCore/khtml/html/html_elementimpl.h
@@ -61,6 +61,7 @@ public:
 
     virtual DOMString namespaceURI() const;
     
+    virtual bool isFocusable() const;
     virtual bool isContentEditable() const;
     virtual DOMString contentEditable() const;
     virtual void setContentEditable(const DOMString &enabled);
@@ -76,11 +77,6 @@ public:
 protected:
     // for IMG, OBJECT and APPLET
     void addHTMLAlignment( DOMString alignment );
-
-private:
-    // FIXME: When the property for editing has been determined in CSS3, use that 
-    // instead of this member variable.
-    TristateFlag m_contentEditable;
 };
 
 class HTMLGenericElementImpl : public HTMLElementImpl
diff --git a/WebCore/khtml/khtml_part.cpp b/WebCore/khtml/khtml_part.cpp
index 57591cb..f1dfe64 100644
--- a/WebCore/khtml/khtml_part.cpp
+++ b/WebCore/khtml/khtml_part.cpp
@@ -53,6 +53,7 @@
 using namespace DOM;
 
 #include "khtmlview.h"
+#include "khtml_selection.h"
 #include <kparts/partmanager.h>
 #include "ecma/kjs_proxy.h"
 #include "khtml_settings.h"
@@ -182,6 +183,9 @@ void KHTMLPart::init( KHTMLView *view, GUIProfile prof )
 
   d->m_view = view;
   setWidget( d->m_view );
+  
+  d->m_selection.setPart(this);
+  d->m_selection.setVisible();
 
 #if !APPLE_CHANGES
   d->m_guiProfile = prof;
@@ -1038,10 +1042,6 @@ void KHTMLPart::clear()
 
   d->m_bMousePressed = false;
 
-  d->m_selectionStart = DOM::Node();
-  d->m_selectionEnd = DOM::Node();
-  d->m_startOffset = 0;
-  d->m_endOffset = 0;
 #ifndef QT_NO_CLIPBOARD
   connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
 #endif
@@ -2213,15 +2213,9 @@ bool KHTMLPart::findTextNext( const QString &str, bool forward, bool caseSensiti
                   ->posOfChar(d->m_findPos, x, y);
                 d->m_view->setContentsPos(x-50, y-50);
 #endif
-
-                d->m_selectionStart = d->m_findNode;
-                d->m_startOffset = d->m_findPos;
-                d->m_selectionEnd = d->m_findNode;
-                d->m_endOffset = d->m_findPos + matchLen;
-                d->m_startBeforeEnd = true;
-
-                d->m_doc->setSelection( d->m_selectionStart.handle(), d->m_startOffset,
-                                        d->m_selectionEnd.handle(), d->m_endOffset );
+                
+                d->m_selection.setSelection(d->m_findNode, d->m_findPos, d->m_findNode, d->m_findPos + matchLen);
+                d->m_doc->setSelection(d->m_selection);
                 emitSelectionChanged();
                 return true;
             }
@@ -2453,39 +2447,38 @@ QString KHTMLPart::selectedText() const
 
 bool KHTMLPart::hasSelection() const
 {
-  return ( !d->m_selectionStart.isNull() &&
-           !d->m_selectionEnd.isNull() );
+    return !d->m_selection.isEmpty();
 }
 
 DOM::Range KHTMLPart::selection() const
 {
     DOM::Range r = document().createRange();
     if (hasSelection()) {
-        r.setStart( d->m_selectionStart, d->m_startOffset );
-        r.setEnd( d->m_selectionEnd, d->m_endOffset );
+        r.setStart(d->m_selection.startNode(), d->m_selection.startOffset());
+        r.setEnd(d->m_selection.endNode(), d->m_selection.endOffset());
     }
     return r;
 }
 
-
-void KHTMLPart::setSelection( const DOM::Range &r )
+void KHTMLPart::setSelection(const DOM::Range &r)
 {
-    d->m_selectionStart = r.startContainer();
-    d->m_startOffset = r.startOffset();
-    d->m_selectionEnd = r.endContainer();
-    d->m_endOffset = r.endOffset();
-    d->m_doc->setSelection(d->m_selectionStart.handle(),d->m_startOffset,
-                           d->m_selectionEnd.handle(),d->m_endOffset);
+    d->m_selection.setSelection(r);
+    d->m_doc->setSelection(d->m_selection);
+    emitSelectionChanged();
 }
 
 void KHTMLPart::slotClearSelection()
 {
-    d->m_selectionStart = 0;
-    d->m_startOffset = 0;
-    d->m_selectionEnd = 0;
-    d->m_endOffset = 0;
-    if ( d->m_doc ) d->m_doc->clearSelection();
-    emitSelectionChanged();
+    bool hadSelection = hasSelection();
+    d->m_selection.clearSelection();
+    d->m_doc->clearSelection();
+    if (hadSelection)
+        emitSelectionChanged();
+}
+
+KHTMLSelection &KHTMLPart::getKHTMLSelection() const
+{
+    return d->m_selection;
 }
 
 #if !APPLE_CHANGES
@@ -4347,7 +4340,7 @@ void KHTMLPart::customEvent( QCustomEvent *event )
   KParts::ReadOnlyPart::customEvent( event );
 }
 
-#if APPLE_CHANGES
+#if 0
 
 static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
 {
@@ -4408,7 +4401,7 @@ static bool lastRunAt(RenderObject *renderNode, int y, NodeImpl *&endNode, long
     }
 }
 
-static bool startAndEndLineNodesIncludingNode (DOM::NodeImpl *node, int offset, DOM::Node &_startNode, long &startOffset, DOM::Node &_endNode, long &endOffset)
+static bool startAndEndLineNodesIncludingNode(DOM::NodeImpl *node, int offset, KHTMLSelection &selection)
 {
     if (node && (node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE)){
         int pos;
@@ -4416,8 +4409,6 @@ static bool startAndEndLineNodesIncludingNode (DOM::NodeImpl *node, int offset,
         khtml::RenderText *renderer = static_cast<khtml::RenderText *>(node->renderer());
         khtml::InlineTextBox * run = renderer->findNextInlineTextBox( offset, pos );
         DOMString t = node->nodeValue();
-        DOM::NodeImpl* startNode;
-        DOM::NodeImpl* endNode;
         
         if (!run)
             return false;
@@ -4431,6 +4422,11 @@ static bool startAndEndLineNodesIncludingNode (DOM::NodeImpl *node, int offset,
         
         renderNode = renderNode->firstChild();
         
+        DOM::NodeImpl *startNode = 0;
+        DOM::NodeImpl *endNode = 0;
+        long startOffset;
+        long endOffset;
+        
         // Look for all the first child in the block that is on the same line
         // as the selection point.
         if (!firstRunAt (renderNode, selectionPointY, startNode, startOffset))
@@ -4441,69 +4437,20 @@ static bool startAndEndLineNodesIncludingNode (DOM::NodeImpl *node, int offset,
         if (!lastRunAt (renderNode, selectionPointY, endNode, endOffset))
             return false;
         
-        _startNode = startNode;
-        _endNode = endNode;
+        selection.setSelection(startNode, startOffset, endNode, endOffset);
+        
         return true;
     }
     return false;
 }
 
-static void findWordBoundary(QChar *chars, int len, int position, int *start, int *end)
-{
-    TextBreakLocatorRef breakLocator;
-    OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakWordMask, &breakLocator);
-    if (status == noErr) {
-        UniCharArrayOffset startOffset, endOffset;
-        status = UCFindTextBreak(breakLocator, kUCTextBreakWordMask, 0, (const UniChar *)chars, len, position, &endOffset);
-        if (status == noErr) {
-            status = UCFindTextBreak(breakLocator, kUCTextBreakWordMask, kUCTextBreakGoBackwardsMask, (const UniChar *)chars, len, position, &startOffset);
-        }
-        UCDisposeTextBreakLocator(&breakLocator);
-        if (status == noErr) {
-            *start = startOffset;
-            *end = endOffset;
-            return;
-        }
-    }
-    
-    // If Carbon fails (why would it?), do a simple space/punctuation boundary check.
-    if (chars[position].isSpace()) {
-        int pos = position;
-        while (chars[pos].isSpace() && pos >= 0)
-            pos--;
-        *start = pos+1;
-        pos = position;
-        while (chars[pos].isSpace() && pos < (int)len)
-            pos++;
-        *end = pos;
-    } else if (chars[position].isPunct()) {
-        int pos = position;
-        while (chars[pos].isPunct() && pos >= 0)
-            pos--;
-        *start = pos+1;
-        pos = position;
-        while (chars[pos].isPunct() && pos < (int)len)
-            pos++;
-        *end = pos;
-    } else {
-        int pos = position;
-        while (!chars[pos].isSpace() && !chars[pos].isPunct() && pos >= 0)
-            pos--;
-        *start = pos+1;
-        pos = position;
-        while (!chars[pos].isSpace() && !chars[pos].isPunct() && pos < (int)len)
-            pos++;
-        *end = pos;
-    }
-}
 #endif
 
 bool KHTMLPart::isPointInsideSelection(int x, int y)
 {
     // Treat an empty selection like no selection.
-    if (d->m_selectionStart == d->m_selectionEnd && d->m_startOffset == d->m_endOffset) {
+    if (d->m_selection.state() == KHTMLSelection::CARET)
         return false;
-    }
     if (!xmlDocImpl()->renderer()) {
         return false;
     }
@@ -4528,572 +4475,447 @@ bool KHTMLPart::isPointInsideSelection(int x, int y)
         return false;
     }
 
-    DOM::Node n = d->m_selectionStart;
-    while(!n.isNull()) {
+    DOM::NodeImpl *n = d->m_selection.startNode();
+    while (n) {
         if (n == node) {
-            if ((n == d->m_selectionStart && offset < d->m_startOffset) ||
-                (n == d->m_selectionEnd && offset > d->m_endOffset)) {
+            if ((n == d->m_selection.startNode() && offset < d->m_selection.startOffset()) ||
+                (n == d->m_selection.endNode() && offset > d->m_selection.endOffset())) {
                 return false;
             }
             return true;
         }
-        if (n == d->m_selectionEnd) {
+        if (n == d->m_selection.endNode()) {
             break;
         }
-        DOM::Node next = n.firstChild();
-        if (next.isNull()) {
-            next = n.nextSibling();
+        DOM::NodeImpl *next = n->firstChild();
+        if (next) {
+            next = n->nextSibling();
         }
-        while (next.isNull() && !n.parentNode().isNull()) {
-            n = n.parentNode();
-            next = n.nextSibling();
+        while (!next && n->parentNode()) {
+            n = n->parentNode();
+            next = n->nextSibling();
         }
         n = next;
     }
     return false;
 }
 
-void KHTMLPart::khtmlMousePressEvent( khtml::MousePressEvent *event )
+#if APPLE_CHANGES
+
+void KHTMLPart::checkSelectionPoint(khtml::MouseEvent *event, DOM::NodeImpl *&node, int &offset)
 {
-  DOM::DOMString url = event->url();
-  QMouseEvent *_mouse = event->qmouseEvent();
-  DOM::Node innerNode = event->innerNode();
-  d->m_mousePressNode = innerNode;
-    
-   d->m_dragStartPos = _mouse->pos();
+    DOM::Node innerNode = event->innerNode();
 
-   if ( !event->url().isNull() ) {
-     d->m_strSelectedURL = event->url().string();
-     d->m_strSelectedURLTarget = event->target().string();
-   }
-   else
-     d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
+	// EDIT FIXME: Shouldn't be necessary to skip text nodes.
+	if (innerNode.nodeType() == Node::TEXT_NODE)
+		innerNode = innerNode.parentNode();
 
-  if ( _mouse->button() == LeftButton ||
-       _mouse->button() == MidButton )
-  {
-    d->m_bMousePressed = true;
+	innerNode.handle()->renderer()->checkSelectionPoint(event->x(), event->y(),
+							event->absX()-innerNode.handle()->renderer()->xPos(),
+							event->absY()-innerNode.handle()->renderer()->yPos(), 
+							node, offset);
+}
 
-#ifndef KHTML_NO_SELECTION
-#if APPLE_CHANGES
-    d->m_selectionInitiatedWithDoubleClick = false;
-    d->m_selectionInitiatedWithTripleClick = false;
-    d->m_mouseMovedSinceLastMousePress = false;
+void KHTMLPart::handleMousePressEventDoubleClick(khtml::MousePressEvent *event)
+{
+    QMouseEvent *mouse = event->qmouseEvent();
+    DOM::Node innerNode = event->innerNode();
 
-    if (event->qmouseEvent()->clickCount() == 2){
-        QMouseEvent *_mouse = event->qmouseEvent();
-        DOM::Node innerNode = event->innerNode();
-        
-        d->m_selectionStart = 0;
-        d->m_selectionEnd = 0;
-        d->m_startOffset = 0;
-        d->m_endOffset = 0;
-    
-        if ( _mouse->button() == LeftButton ){
-            if ( !innerNode.isNull()  && innerNode.handle()->renderer()) {
-                int startOffset = 0, endOffset = 0;
-                DOM::NodeImpl* node = 0;
-                
-                // FIXME: Shouldn't be necessary to skip text nodes.
-                if (innerNode.nodeType() == Node::TEXT_NODE)
-                    innerNode = innerNode.parentNode();
-                innerNode.handle()->renderer()->checkSelectionPoint( event->x(), event->y(),
-                                            event->absX()-innerNode.handle()->renderer()->xPos(),
-                                            event->absY()-innerNode.handle()->renderer()->yPos(), 
-                                            node, startOffset);
-                
-                if (node && (node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE)){
-                    DOMString t = node->nodeValue();
-                    QChar *chars = t.unicode();
-                    uint len = t.length();
-
-                    findWordBoundary (chars, len, startOffset, &startOffset, &endOffset);
-
-                    d->m_startBeforeEnd = true;
-                    d->m_selectionStart = node;
-                    d->m_startOffset = startOffset;
-                    d->m_selectionEnd = d->m_selectionStart;
-                    d->m_endOffset = endOffset;
-                }
-            }
-        }
-        if (d->m_selectionStart == 0 || d->m_selectionEnd == 0)
-            d->m_doc->clearSelection();
-        else{
-            d->m_initialSelectionStart = d->m_selectionStart;
-            d->m_initialSelectionStartOffset = d->m_startOffset;
-            d->m_initialSelectionEnd = d->m_selectionEnd;
-            d->m_initialSelectionEndOffset = d->m_endOffset;
-            d->m_selectionInitiatedWithDoubleClick = true;
-            d->m_doc->setSelection(d->m_selectionStart.handle(), d->m_startOffset,
-                    d->m_selectionEnd.handle(),d->m_endOffset);
+    d->m_selection.clearSelection();
+
+    if (mouse->button() == LeftButton && !innerNode.isNull() && innerNode.handle()->renderer()) {
+        NodeImpl *node = 0;
+        int offset = 0;
+        checkSelectionPoint(event, node, offset);
+        if (node && (node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE)) {
+            d->m_selection.setSelection(node, offset);
+            d->m_selection.expandSelection(KHTMLSelection::WORD);
         }
-        emitSelectionChanged();
-        startAutoScroll();
     }
-    else if (event->qmouseEvent()->clickCount() >= 3){
-        QMouseEvent *_mouse = event->qmouseEvent();
-        DOM::Node innerNode = event->innerNode();
-        
-        d->m_selectionStart = 0;
-        d->m_selectionEnd = 0;
-        d->m_startOffset = 0;
-        d->m_endOffset = 0;
     
-        if ( _mouse->button() == LeftButton ){
-            if ( !innerNode.isNull()  && innerNode.handle()->renderer()) {
-                int startOffset = 0;
-                DOM::NodeImpl* node = 0;
-                
-                // FIXME: Shouldn't be necessary to skip text nodes.
-                if (innerNode.nodeType() == Node::TEXT_NODE)
-                    innerNode = innerNode.parentNode();
-                innerNode.handle()->renderer()->checkSelectionPoint( event->x(), event->y(),
-                                            event->absX()-innerNode.handle()->renderer()->xPos(),
-                                            event->absY()-innerNode.handle()->renderer()->yPos(), 
-                                            node, startOffset);
-                
-                startAndEndLineNodesIncludingNode (node, startOffset, d->m_selectionStart, d->m_startOffset, d->m_selectionEnd, d->m_endOffset);
-            }
-        }
-        if (d->m_selectionStart == 0 || d->m_selectionEnd == 0)
-            d->m_doc->clearSelection();
-        else {
-            d->m_initialSelectionStart = d->m_selectionStart;
-            d->m_initialSelectionStartOffset = d->m_startOffset;
-            d->m_initialSelectionEnd = d->m_selectionEnd;
-            d->m_initialSelectionEndOffset = d->m_endOffset;
-            d->m_selectionInitiatedWithTripleClick = true;
-            d->m_doc->setSelection(d->m_selectionStart.handle(), d->m_startOffset,
-                    d->m_selectionEnd.handle(),d->m_endOffset);
+    if (d->m_selection.state() == KHTMLSelection::CARET) {
+        d->m_doc->clearSelection();
+    }
+    else {
+        d->m_textElement = KHTMLSelection::WORD;
+        d->m_doc->setSelection(d->m_selection);
+    }
+    
+    emitSelectionChanged();
+    startAutoScroll();
+}
+
+void KHTMLPart::handleMousePressEventTripleClick(khtml::MousePressEvent *event)
+{
+    QMouseEvent *mouse = event->qmouseEvent();
+    DOM::Node innerNode = event->innerNode();
+    
+    d->m_selection.clearSelection();
+    
+    if (mouse->button() == LeftButton && !innerNode.isNull() && innerNode.handle()->renderer()) {
+        DOM::NodeImpl* node = 0;
+        int offset = 0;
+        checkSelectionPoint(event, node, offset);
+        if (node && (node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE)) {
+            d->m_selection.setSelection(node, offset);
+            d->m_selection.expandSelection(KHTMLSelection::LINE);
         }
-                    
-        emitSelectionChanged();
-        startAutoScroll();
+    }
+    
+    if (d->m_selection.state() == KHTMLSelection::CARET) {
+        d->m_doc->clearSelection();
     }
     else {
-#endif
-        if ( _mouse->button() == LeftButton )
-        {
-            if ( !innerNode.isNull()  && innerNode.handle()->renderer()) {
+        d->m_textElement = KHTMLSelection::LINE;
+        d->m_doc->setSelection(d->m_selection);
+    }
+    
+    emitSelectionChanged();
+    startAutoScroll();
+}
+
+#endif // APPLE_CHANGES
+
+void KHTMLPart::handleMousePressEventSingleClick(khtml::MousePressEvent *event)
+{
+    QMouseEvent *mouse = event->qmouseEvent();
+    DOM::Node innerNode = event->innerNode();
+    
+	if (mouse->button() == LeftButton) {
+		if (innerNode.isNull() || !innerNode.handle()->renderer()) {
+			d->m_selection.clearSelection();
+		}
+		else {
 #if APPLE_CHANGES
-                // Don't restart the selection when the mouse is pressed on an
-                // existing selection so we can allow for text dragging.
-                if (isPointInsideSelection(event->x(), event->y())) {
-                    return;
-                }
+			// Don't restart the selection when the mouse is pressed on an
+			// existing selection so we can allow for text dragging.
+			if (isPointInsideSelection(event->x(), event->y())) {
+				return;
+			}
 #endif
-                int offset = 0;
-                DOM::NodeImpl* node = 0;
-
-                // FIXME: Shouldn't be necessary to skip text nodes.
-                if (innerNode.nodeType() == Node::TEXT_NODE)
-                    innerNode = innerNode.parentNode();
-                innerNode.handle()->renderer()->checkSelectionPoint( event->x(), event->y(),
-                                                                    event->absX()-innerNode.handle()->renderer()->xPos(),
-                                                                    event->absY()-innerNode.handle()->renderer()->yPos(), node, offset);
-                
-                d->m_selectionStart = node;
-                d->m_startOffset = offset;
-                //           kdDebug(6005) << "KHTMLPart::khtmlMousePressEvent selectionStart=" << d->m_selectionStart.handle()->renderer()
-                //                         << " offset=" << d->m_startOffset << endl;
-                d->m_selectionEnd = d->m_selectionStart;
-                d->m_endOffset = d->m_startOffset;
-                d->m_doc->clearSelection();
-            }
-            else
-            {
-                d->m_selectionStart = DOM::Node();
-                d->m_selectionEnd = DOM::Node();
-            }
-            emitSelectionChanged();
-            startAutoScroll();
-        }
-#if APPLE_CHANGES
+			DOM::NodeImpl* node = 0;
+			int offset = 0;
+        	checkSelectionPoint(event, node, offset);
+            d->m_selection.setSelection(node, offset);
+			d->m_doc->clearSelection();
+		}
+
+		emitSelectionChanged();
+		startAutoScroll();
+	}
+}
+
+void KHTMLPart::khtmlMousePressEvent(khtml::MousePressEvent *event)
+{
+    DOM::DOMString url = event->url();
+    QMouseEvent *mouse = event->qmouseEvent();
+    DOM::Node innerNode = event->innerNode();
+
+    d->m_mousePressNode = innerNode;
+    d->m_dragStartPos = mouse->pos();
+
+    if (!event->url().isNull()) {
+        d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
+    }
+    else {
+        d->m_strSelectedURL = event->url().string();
+        d->m_strSelectedURLTarget = event->target().string();
     }
-#endif
-#else
-    d->m_dragLastPos = _mouse->globalPos();
-#endif
-  }
 
 #if !APPLE_CHANGES
-  if ( _mouse->button() == RightButton )
-  {
-    popupMenu( d->m_strSelectedURL );
-    d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
-  }
+    if (mouse->button() == RightButton) {
+        popupMenu(d->m_strSelectedURL);
+        d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
+    }
 #endif
+
+    if (mouse->button() == LeftButton || mouse->button() == MidButton) {
+        d->m_bMousePressed = true;
+
+#ifdef KHTML_NO_SELECTION
+        d->m_dragLastPos = mouse->globalPos();
+#else
+#if APPLE_CHANGES
+        d->m_textElement = KHTMLSelection::CHARACTER;
+        d->m_mouseMovedSinceLastMousePress = false;
+
+		if (mouse->clickCount() == 2) {
+			handleMousePressEventDoubleClick(event);
+            return;
+		}
+        
+        if (mouse->clickCount() >= 3) {
+			handleMousePressEventTripleClick(event);
+            return;
+        }
+#endif // APPLE_CHANGES
+
+        handleMousePressEventSingleClick(event);
+
+#endif // KHTML_NO_SELECTION
+    }
 }
 
 void KHTMLPart::khtmlMouseDoubleClickEvent( khtml::MouseDoubleClickEvent *event)
 {
 }
 
-void KHTMLPart::khtmlMouseMoveEvent( khtml::MouseMoveEvent *event )
+bool KHTMLPart::handleMouseMoveEventDrag(khtml::MouseMoveEvent *event)
 {
-  QMouseEvent *_mouse = event->qmouseEvent();
-  DOM::Node innerNode = event->innerNode();
+#ifdef QT_NO_DRAGANDDROP
+	return false;
+#else
 
-#ifndef QT_NO_DRAGANDDROP
-  if( d->m_bMousePressed && (!d->m_strSelectedURL.isEmpty() || (!innerNode.isNull() && innerNode.elementId() == ID_IMG) ) &&
-      ( d->m_dragStartPos - _mouse->pos() ).manhattanLength() > KGlobalSettings::dndEventDelay() &&
-      d->m_bDnd && d->m_mousePressNode == innerNode ) {
+	QMouseEvent *mouse = event->qmouseEvent();
+	DOM::Node innerNode = event->innerNode();
+
+	if (d->m_bMousePressed && (!d->m_strSelectedURL.isEmpty() || (!innerNode.isNull() && innerNode.elementId() == ID_IMG)) &&
+	   (d->m_dragStartPos - mouse->pos()).manhattanLength() > KGlobalSettings::dndEventDelay() &&
+	    d->m_bDnd && d->m_mousePressNode == innerNode) {
+
+		QPixmap p;
+		QDragObject *drag = 0;
+		if (!d->m_strSelectedURL.isEmpty()) {
+			KURL u( completeURL( d->m_strSelectedURL) );
+			KURLDrag* urlDrag = KURLDrag::newDrag( u, d->m_view->viewport() );
+			if ( !d->m_referrer.isEmpty() )
+			urlDrag->metaData()["referrer"] = d->m_referrer;
+			drag = urlDrag;
+			p = KMimeType::pixmapForURL(u, 0, KIcon::Desktop, KIcon::SizeMedium);
+		} 
+		else {
+			HTMLImageElementImpl *i = static_cast<HTMLImageElementImpl *>(innerNode.handle());
+			if (i) {
+				KMultipleDrag *mdrag = new KMultipleDrag( d->m_view->viewport());
+				mdrag->addDragObject(new QImageDrag(i->currentImage(), 0L));
+				KURL u( completeURL( khtml::parseURL(i->getAttribute(ATTR_SRC)).string()));
+				KURLDrag* urlDrag = KURLDrag::newDrag(u, 0L);
+				if (!d->m_referrer.isEmpty())
+					urlDrag->metaData()["referrer"] = d->m_referrer;
+				mdrag->addDragObject( urlDrag );
+				drag = mdrag;
+				p = KMimeType::mimeType("image/png")->pixmap(KIcon::Desktop);
+			}
+		}
+		
+		if ( !p.isNull() )
+			drag->setPixmap(p);
+		
+		stopAutoScroll();
+		if(drag)
+			drag->drag();
+		
+		// when we finish our drag, we need to undo our mouse press
+		d->m_bMousePressed = false;
+		d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
+		return true;
+	}
+	
+	return false;
+#endif // QT_NO_DRAGANDDROP
+}
+
+bool KHTMLPart::handleMouseMoveEventOver(khtml::MouseMoveEvent *event)
+{
+#if APPLE_CHANGES
+	return false;
+#else
 
-      QPixmap p;
-      QDragObject *drag = 0;
-      if( !d->m_strSelectedURL.isEmpty() ) {
-          KURL u( completeURL( d->m_strSelectedURL) );
-          KURLDrag* urlDrag = KURLDrag::newDrag( u, d->m_view->viewport() );
-          if ( !d->m_referrer.isEmpty() )
-            urlDrag->metaData()["referrer"] = d->m_referrer;
-          drag = urlDrag;
-          p = KMimeType::pixmapForURL(u, 0, KIcon::Desktop, KIcon::SizeMedium);
-      } else {
-          HTMLImageElementImpl *i = static_cast<HTMLImageElementImpl *>(innerNode.handle());
-          if( i ) {
-            KMultipleDrag *mdrag = new KMultipleDrag( d->m_view->viewport() );
-            mdrag->addDragObject( new QImageDrag( i->currentImage(), 0L ) );
-            KURL u( completeURL( khtml::parseURL(i->getAttribute(ATTR_SRC)).string() ) );
-            KURLDrag* urlDrag = KURLDrag::newDrag( u, 0L );
-            if ( !d->m_referrer.isEmpty() )
-              urlDrag->metaData()["referrer"] = d->m_referrer;
-            mdrag->addDragObject( urlDrag );
-            drag = mdrag;
-            p = KMimeType::mimeType("image/png")->pixmap(KIcon::Desktop);
-          }
-      }
+	// Mouse clicked. Do nothing.
+	if (d->m_bMousePressed) {
+		return false;
+	}
+
+	// The mouse is over something
+	if (url.length()) {
+		bool shiftPressed = (mouse->state() & ShiftButton);
+
+		// Image map
+		if (!innerNode.isNull() && innerNode.elementId() == ID_IMG) {
+			HTMLImageElementImpl *i = static_cast<HTMLImageElementImpl *>(innerNode.handle());
+			if (i && i->isServerMap()) {
+				khtml::RenderObject *r = i->renderer();
+				if(r) {
+					int absx, absy, vx, vy;
+					r->absolutePosition(absx, absy);
+					view()->contentsToViewport( absx, absy, vx, vy );
+				
+					int x(mouse->x() - vx);
+					int y(mouse->y() - vy);
+				
+					d->m_overURL = url.string() + QString("?%1,%2").arg(x).arg(y);
+					d->m_overURLTarget = target.string();
+					overURL(d->m_overURL, target.string(), shiftPressed);
+					return true;
+				}
+			}
+		}
+		// normal link
+		if (d->m_overURL.isEmpty() || d->m_overURL != url || d->m_overURLTarget != target) {
+			d->m_overURL = url.string();
+			d->m_overURLTarget = target.string();
+			overURL(d->m_overURL, target.string(), shiftPressed);
+		}
+	}
+	else { // Not over a link...
+		if (!d->m_overURL.isEmpty()) { // and we were over a link  -> reset to "default statusbar text"
+			d->m_overURL = d->m_overURLTarget = QString::null;
+			emit onURL(QString::null);
+			// Default statusbar text can be set from javascript. Otherwise it's empty.
+			emit setStatusBarText(d->m_kjsDefaultStatusBarText);
+		}
+	}
+	
+	return true;
+#endif // APPLE_CHANGES
+}
 
-    if ( !p.isNull() )
-      drag->setPixmap(p);
+void KHTMLPart::handleMouseMoveEventSelection(khtml::MouseMoveEvent *event)
+{
+	// Mouse not pressed. Do nothing.
+	if (!d->m_bMousePressed)
+		return;
 
-    stopAutoScroll();
-    if(drag)
-        drag->drag();
+#ifdef KHTML_NO_SELECTION
+	if (d->m_doc && d->m_view) {
+		QPoint diff( mouse->globalPos() - d->m_dragLastPos );
+		
+		if (abs(diff.x()) > 64 || abs(diff.y()) > 64) {
+			d->m_view->scrollBy(-diff.x(), -diff.y());
+			d->m_dragLastPos = mouse->globalPos();
+		}
+	}
+	return;   
+#else
 
-    // when we finish our drag, we need to undo our mouse press
-    d->m_bMousePressed = false;
-    d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
-    return;
-  }
-#endif
+	QMouseEvent *mouse = event->qmouseEvent();
+	DOM::Node innerNode = event->innerNode();
 
-  DOM::DOMString url = event->url();
-  DOM::DOMString target = event->target();
+    if (mouse->state() != LeftButton || !innerNode.handle() || !innerNode.handle()->renderer())
+    	return;
 
-  // Not clicked -> mouse over stuff
-  if ( !d->m_bMousePressed )
-  {
-#if !APPLE_CHANGES
-    // The mouse is over something
-    if ( url.length() )
-    {
-      bool shiftPressed = ( _mouse->state() & ShiftButton );
+	// handle making selection
+	DOM::NodeImpl* node = 0;
+	int offset = 0;
 
-      // Image map
-      if ( !innerNode.isNull() && innerNode.elementId() == ID_IMG )
-      {
-        HTMLImageElementImpl *i = static_cast<HTMLImageElementImpl *>(innerNode.handle());
-        if ( i && i->isServerMap() )
-        {
-          khtml::RenderObject *r = i->renderer();
-          if(r)
-          {
-            int absx, absy, vx, vy;
-            r->absolutePosition(absx, absy);
-            view()->contentsToViewport( absx, absy, vx, vy );
+	checkSelectionPoint(event, node, offset);
 
-            int x(_mouse->x() - vx), y(_mouse->y() - vy);
+#if APPLE_CHANGES
+	// Don't modify the selection if we're not on a node.
+	if (node == 0)
+		return;
+
+	// Restart the selection if this is the first mouse move. This work is usually
+	// done in khtmlMousePressEvent, but not if the mouse press was on an existing selection.
+	if (!d->m_mouseMovedSinceLastMousePress) {
+		d->m_mouseMovedSinceLastMousePress = true;
+        d->m_selection.setSelection(node, offset);
+	}
+#endif        
 
-            d->m_overURL = url.string() + QString("?%1,%2").arg(x).arg(y);
-            d->m_overURLTarget = target.string();
-            overURL( d->m_overURL, target.string(), shiftPressed );
-            return;
-          }
-        }
-      }
+    d->m_selection.setExtent(node, offset);
 
-      // normal link
-      if ( d->m_overURL.isEmpty() || d->m_overURL != url || d->m_overURLTarget != target )
-      {
-        d->m_overURL = url.string();
-        d->m_overURLTarget = target.string();
-        overURL( d->m_overURL, target.string(), shiftPressed );
-      }
+#if APPLE_CHANGES
+    if (d->m_textElement != KHTMLSelection::CHARACTER) {
+        d->m_selection.expandSelection(d->m_textElement);
     }
-    else  // Not over a link...
-    {
-      if( !d->m_overURL.isEmpty() ) // and we were over a link  -> reset to "default statusbar text"
-      {
-        d->m_overURL = d->m_overURLTarget = QString::null;
-        emit onURL( QString::null );
-        // Default statusbar text can be set from javascript. Otherwise it's empty.
-        emit setStatusBarText( d->m_kjsDefaultStatusBarText );
-      }
+#endif    
+
+    if (!d->m_selection.isEmpty()) {
+        d->m_doc->setSelection(d->m_selection);
     }
-#endif // APPLE_CHANGES
-  }
-  else {
-#ifndef KHTML_NO_SELECTION
-    // selection stuff
-    if( d->m_bMousePressed && innerNode.handle() && innerNode.handle()->renderer() &&
-        ( _mouse->state() == LeftButton )) {
-        int offset = -1;
-        //kdDebug(6000) << "KHTMLPart::khtmlMouseMoveEvent x=" << event->x() << " y=" << event->y()
-        //              << " nodeAbsX=" << event->nodeAbsX() << " nodeAbsY=" << event->nodeAbsY()
-        //              << endl;
-        DOM::NodeImpl* node=0;
-        // FIXME: Shouldn't be necessary to skip text nodes.
-        if (innerNode.nodeType() == Node::TEXT_NODE)
-            innerNode = innerNode.parentNode();
-        innerNode.handle()->renderer()->checkSelectionPoint( event->x(), event->y(),
-                                                            event->absX()-innerNode.handle()->renderer()->xPos(),
-                                                            event->absY()-innerNode.handle()->renderer()->yPos(), node, offset);
-        //        if (d->m_selectionEnd.handle() && d->m_selectionEnd.handle()->renderer())
-        //          kdDebug( 6000 ) << "setting end of selection to " << d->m_selectionEnd.handle()->renderer() << "/"
-        //                          << d->m_endOffset << endl;
+        
+#endif // KHTML_NO_SELECTION
+}
 
-#if APPLE_CHANGES
-        // Don't modify the selection if we're not on a node.
-        if (node == 0)
-            return;
+void KHTMLPart::khtmlMouseMoveEvent(khtml::MouseMoveEvent *event)
+{
+	if (handleMouseMoveEventDrag(event))
+		return;
 
-        // Restart the selection if this is the first mouse move. This work is usually
-        // done in khtmlMousePressEvent, but not if the mouse press was on an existing selection.
-        if (!d->m_mouseMovedSinceLastMousePress) {
-            d->m_mouseMovedSinceLastMousePress = true;
-            d->m_selectionStart = node;
-            d->m_startOffset = offset;
-            d->m_selectionEnd = node;
-            d->m_endOffset = offset;
-            d->m_doc->clearSelection();
-        }
-#endif        
-        // we have to get to know if end is before start or not...
-        DOM::Node n = d->m_selectionStart;
-        d->m_startBeforeEnd = false;
-        while(!n.isNull()) {
-            if(n == node) {
-                d->m_startBeforeEnd = true;
-                break;
-            }
-            DOM::Node next = n.firstChild();
-            if(next.isNull()) next = n.nextSibling();
-            while( next.isNull() && !n.parentNode().isNull() ) {
-                n = n.parentNode();
-                next = n.nextSibling();
-            }
-            n = next;
-        }
-#if APPLE_CHANGES
-        if ( d->m_selectionInitiatedWithDoubleClick){
-            int wordStartOffset = offset, wordEndOffset = offset;
-            
-            if (node && (node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE)){
-                DOMString t = node->nodeValue();
-                QChar *chars = t.unicode();
-                uint len = t.length();
+	if (handleMouseMoveEventOver(event))
+		return;
 
-                findWordBoundary (chars, len, offset, &wordStartOffset, &wordEndOffset);
-            }
-            if (d->m_startBeforeEnd) {
-                if (node == d->m_initialSelectionStart.handle() && node == d->m_initialSelectionEnd.handle()){
-                    d->m_selectionStart = d->m_initialSelectionStart;
-                    d->m_startOffset = MIN(d->m_initialSelectionStartOffset, wordStartOffset);
-                    wordEndOffset = MAX(d->m_initialSelectionEndOffset, wordEndOffset);
-                    d->m_selectionEnd = node;
-                    d->m_endOffset = wordEndOffset;
-                }
-                else {
-                    d->m_selectionStart = d->m_initialSelectionStart;
-                    d->m_startOffset = d->m_initialSelectionStartOffset;
-                    d->m_selectionEnd = node;
-                    d->m_endOffset = wordEndOffset;
-                }
-            }
-            else {
-                d->m_selectionStart = d->m_initialSelectionEnd;
-                d->m_startOffset = d->m_initialSelectionEndOffset;
-                d->m_selectionEnd = node;
-                d->m_endOffset = wordStartOffset;
-            }
-        }
-        else if (d->m_selectionInitiatedWithTripleClick ){
-            DOM::Node lineStart, lineEnd;
-            long lineStartOffset, lineEndOffset;
-            
-            if (startAndEndLineNodesIncludingNode (node, offset, lineStart, lineStartOffset, lineEnd, lineEndOffset)){
-                if (d->m_startBeforeEnd) {
-                    if (node == d->m_initialSelectionStart.handle() && node == lineEnd.handle()){
-                        d->m_selectionStart = d->m_initialSelectionStart;
-                        d->m_startOffset = MIN(lineStartOffset, d->m_initialSelectionStartOffset);
-                        d->m_selectionEnd = lineEnd;
-                        d->m_endOffset = MAX(lineEndOffset, d->m_initialSelectionEndOffset);
-                    }
-                    else {
-                        d->m_selectionStart = d->m_initialSelectionStart;
-                        d->m_startOffset = d->m_initialSelectionStartOffset;
-                        d->m_selectionEnd = lineEnd;
-                        d->m_endOffset = lineEndOffset;
-                    }
-                }
-                else {
-                    d->m_selectionStart = d->m_initialSelectionEnd;
-                    d->m_startOffset = d->m_initialSelectionEndOffset;
-                    d->m_selectionEnd = lineStart;
-                    d->m_endOffset = lineStartOffset;
-                }
-            }
-        }
-        else {
-            d->m_selectionEnd = node;
-            d->m_endOffset = offset;
-        }
-#else
-        d->m_selectionEnd = node;
-        d->m_endOffset = offset;
-#endif        
-        if ( !d->m_selectionStart.isNull() && !d->m_selectionEnd.isNull() )
-        {
-            if (d->m_selectionEnd == d->m_selectionStart && d->m_endOffset < d->m_startOffset)
-                d->m_doc->setSelection(d->m_selectionStart.handle(),d->m_endOffset,
-                                d->m_selectionEnd.handle(),d->m_startOffset);
-            else if (d->m_startBeforeEnd)
-                d->m_doc->setSelection(d->m_selectionStart.handle(),d->m_startOffset,
-                                d->m_selectionEnd.handle(),d->m_endOffset);
-            else
-                d->m_doc->setSelection(d->m_selectionEnd.handle(),d->m_endOffset,
-                                d->m_selectionStart.handle(),d->m_startOffset);
-        }
-#else
-        if ( d->m_doc && d->m_view ) {
-            QPoint diff( _mouse->globalPos() - d->m_dragLastPos );
-            
-            if ( abs( diff.x() ) > 64 || abs( diff.y() ) > 64 ) {
-                d->m_view->scrollBy( -diff.x(), -diff.y() );
-                d->m_dragLastPos = _mouse->globalPos();
-            }
-        }   
-#endif
-        }
-    }
+	handleMouseMoveEventSelection(event);		
 }
 
 void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
 {
-  DOM::Node innerNode = event->innerNode();
-  d->m_mousePressNode = DOM::Node();
-
-  if ( d->m_bMousePressed )
-    stopAutoScroll();
-
-  // Used to prevent mouseMoveEvent from initiating a drag before
-  // the mouse is pressed again.
-  d->m_bMousePressed = false;
+	if (d->m_bMousePressed)
+		stopAutoScroll();
+	
+	// Used to prevent mouseMoveEvent from initiating a drag before
+	// the mouse is pressed again.
+	d->m_bMousePressed = false;
 
 #ifndef QT_NO_CLIPBOARD
-  QMouseEvent *_mouse = event->qmouseEvent();
-  if ((d->m_guiProfile == BrowserViewGUI) && (_mouse->button() == MidButton) && (event->url().isNull()))
-  {
-    QClipboard *cb = QApplication::clipboard();
-    cb->setSelectionMode( true );
-    QCString plain("plain");
-    QString url = cb->text(plain).stripWhiteSpace();
-    KURL u(url);
-    if ( u.isMalformed() ) {
-      // some half-baked guesses for incomplete urls
-      // (the same code is in libkonq/konq_dirpart.cc)
-      if ( url.startsWith( "ftp." ) )
-      {
-        url.prepend( "ftp://" );
-        u = url;
-      }
-      else
-      {
-        url.prepend( "http://" );
-        u = url;
-      }
-    }
-    if (u.isValid())
-    {
-      QString savedReferrer = d->m_referrer;
-      d->m_referrer = QString::null; // Disable referrer.
-      urlSelected(url, 0,0, "_top");
-      d->m_referrer = savedReferrer; // Restore original referrer.
-    }
-  }
+	QMouseEvent *_mouse = event->qmouseEvent();
+	if ((d->m_guiProfile == BrowserViewGUI) && (_mouse->button() == MidButton) && (event->url().isNull())) {
+		QClipboard *cb = QApplication::clipboard();
+		cb->setSelectionMode(true);
+		QCString plain("plain");
+		QString url = cb->text(plain).stripWhiteSpace();
+		KURL u(url);
+		if (u.isMalformed()) {
+			// some half-baked guesses for incomplete urls
+			// (the same code is in libkonq/konq_dirpart.cc)
+			if (url.startsWith("ftp.")) {
+				url.prepend("ftp://");
+				u = url;
+			}
+			else {
+				url.prepend("http://");
+				u = url;
+			}
+		}
+		if (u.isValid()) {
+			QString savedReferrer = d->m_referrer;
+			d->m_referrer = QString::null; // Disable referrer.
+			urlSelected(url, 0,0, "_top");
+			d->m_referrer = savedReferrer; // Restore original referrer.
+		}
+	}
 #endif
   
 #if APPLE_CHANGES
-  // Clear the selection if the mouse didn't move after the last mouse press.
-  // We do this so when clicking on the selection, the selection goes away.
-  if (d->m_dragStartPos.x() == event->qmouseEvent()->x() &&
-      d->m_dragStartPos.y() == event->qmouseEvent()->y() &&
-      !d->m_selectionInitiatedWithDoubleClick &&
-      !d->m_selectionInitiatedWithTripleClick) {
-      d->m_selectionStart = 0;
-      d->m_selectionEnd = 0;
-      d->m_startOffset = 0;
-      d->m_endOffset = 0;
-      d->m_doc->clearSelection();
-  }
+	// Clear the selection if the mouse didn't move after the last mouse press.
+	// We do this so when clicking on the selection, the selection goes away.
+    // However, if we are editing, place the caret.
+	if (d->m_dragStartPos.x() == event->qmouseEvent()->x() &&
+		d->m_dragStartPos.y() == event->qmouseEvent()->y() &&
+		d->m_selection.state() == KHTMLSelection::RANGE &&
+        d->m_textElement == KHTMLSelection::CHARACTER) {
+            if (isEditingAtCaret()) {
+                NodeImpl *node = 0;
+                int offset = 0;
+                checkSelectionPoint(event, node, offset);
+                d->m_selection.setSelection(node, offset);
+                d->m_doc->setSelection(d->m_selection);
+            }
+            else {
+                d->m_selection.clearSelection();
+                d->m_doc->clearSelection();
+            }
+	}
 #endif
+
 #ifndef KHTML_NO_SELECTION
-  // delete selection in case start and end position are at the same point
-  if(d->m_selectionStart == d->m_selectionEnd && d->m_startOffset == d->m_endOffset) {
-    d->m_selectionStart = 0;
-    d->m_selectionEnd = 0;
-    d->m_startOffset = 0;
-    d->m_endOffset = 0;
-    emitSelectionChanged();
-  } else {
-    // we have to get to know if end is before start or not...
-    DOM::Node n = d->m_selectionStart;
-    d->m_startBeforeEnd = false;
-    if( d->m_selectionStart == d->m_selectionEnd ) {
-      if( d->m_startOffset < d->m_endOffset )
-        d->m_startBeforeEnd = true;
-    } else {
-      while(!n.isNull()) {
-        if(n == d->m_selectionEnd) {
-          d->m_startBeforeEnd = true;
-          break;
-        }
-        DOM::Node next = n.firstChild();
-        if(next.isNull()) next = n.nextSibling();
-        while( next.isNull() && !n.parentNode().isNull() ) {
-          n = n.parentNode();
-          next = n.nextSibling();
-        }
-        n = next;
-      }
-    }
-    if(!d->m_startBeforeEnd)
-    {
-      DOM::Node tmpNode = d->m_selectionStart;
-      int tmpOffset = d->m_startOffset;
-      d->m_selectionStart = d->m_selectionEnd;
-      d->m_startOffset = d->m_endOffset;
-      d->m_selectionEnd = tmpNode;
-      d->m_endOffset = tmpOffset;
-      d->m_startBeforeEnd = true;
-    }
-    // get selected text and paste to the clipboard
+	
 #ifndef QT_NO_CLIPBOARD
+    // get selected text and paste to the clipboard
     QString text = selectedText();
     text.replace(QRegExp(QChar(0xa0)), " ");
     QClipboard *cb = QApplication::clipboard();
-    cb->setSelectionMode( true );
-    disconnect( kapp->clipboard(), SIGNAL( selectionChanged()), this, SLOT( slotClearSelection()));
+    cb->setSelectionMode(true);
+    disconnect(kapp->clipboard(), SIGNAL(selectionChanged()), this, SLOT(slotClearSelection()));
     cb->setText(text);
-    connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
-    cb->setSelectionMode( false );
-#endif
-    //kdDebug( 6000 ) << "selectedText = " << text << endl;
+    connect(kapp->clipboard(), SIGNAL(selectionChanged()), SLOT(slotClearSelection()));
+    cb->setSelectionMode(false);
+#endif // QT_NO_CLIPBOARD
+
     emitSelectionChanged();
-  }
-#endif
 
+#endif // KHTML_NO_SELECTION
 }
 
 void KHTMLPart::khtmlDrawContentsEvent( khtml::DrawContentsEvent * )
@@ -5281,18 +5103,22 @@ void KHTMLPart::selectAll()
     return;
   Q_ASSERT(first->renderer());
   Q_ASSERT(last->renderer());
-  d->m_selectionStart = first;
-  d->m_startOffset = 0;
-  d->m_selectionEnd = last;
-  d->m_endOffset = last->nodeValue().length();
-  d->m_startBeforeEnd = true;
-
-  d->m_doc->setSelection( d->m_selectionStart.handle(), d->m_startOffset,
-                          d->m_selectionEnd.handle(), d->m_endOffset );
-
+  d->m_selection.setSelection(first, 0, last, last->nodeValue().length());
+  d->m_doc->setSelection(d->m_selection);
   emitSelectionChanged();
 }
 
+bool KHTMLPart::isEditingAtCaret() const
+{
+    if (inEditMode())
+        return true;
+    
+    NodeImpl *node = d->m_selection.baseNode();
+    return node && node->isContentEditable();
+    
+    return false;
+}
+
 #if !APPLE_CHANGES
 
 bool KHTMLPart::checkLinkSecurity(const KURL &linkURL,const QString &message, const QString &button)
diff --git a/WebCore/khtml/khtml_part.h b/WebCore/khtml/khtml_part.h
index 145ab8f..37e4255 100644
--- a/WebCore/khtml/khtml_part.h
+++ b/WebCore/khtml/khtml_part.h
@@ -39,6 +39,7 @@
 class KHTMLPartPrivate;
 class KHTMLPartBrowserExtension;
 class KJSProxy;
+class KHTMLSelection;
 class KHTMLView;
 class KHTMLSettings;
 class KJavaAppletContext;
@@ -554,7 +555,7 @@ public:
    */
   int zoomFactor() const;
 
-  /**
+/**
    * Returns the text the user has marked.
    */
   virtual QString selectedText() const;
@@ -567,7 +568,7 @@ public:
   /**
    * Sets the current selection.
    */
-  void setSelection( const DOM::Range & );
+  void setSelection(const DOM::Range &);
 
   /**
    * Returns the text for a part of the document.
@@ -590,6 +591,17 @@ public:
   void selectAll();
 
   /**
+   * Returns the caret.
+   */
+  KHTMLSelection &getKHTMLSelection() const;
+
+  /**
+   * Returns whether editing is enabled at the current caret
+   * position.
+   */
+  bool isEditingAtCaret() const;
+
+  /**
    * Convenience method to show the document's view.
    *
    * Equivalent to widget()->show() or view()->show() .
@@ -1027,7 +1039,7 @@ private:
    * @internal
    */
   void emitSelectionChanged();
-
+  
   /**
    * @internal
    */
@@ -1108,6 +1120,18 @@ private:
 
   void replaceContentsWithScriptResult( const KURL &url );
 
+  void checkSelectionPoint(khtml::MouseEvent *event, DOM::NodeImpl *&node, int &offset);
+
+  bool handleMouseMoveEventDrag(khtml::MouseMoveEvent *event);
+  bool handleMouseMoveEventOver(khtml::MouseMoveEvent *event);
+  void handleMouseMoveEventSelection(khtml::MouseMoveEvent *event);
+
+#if APPLE_CHANGES
+  void handleMousePressEventSingleClick(khtml::MousePressEvent *event);
+  void handleMousePressEventDoubleClick(khtml::MousePressEvent *event);
+  void handleMousePressEventTripleClick(khtml::MousePressEvent *event);
+#endif
+
   KHTMLPartPrivate *d;
   friend class KHTMLPartPrivate;
 
diff --git a/WebCore/khtml/khtml_selection.cpp b/WebCore/khtml/khtml_selection.cpp
new file mode 100644
index 0000000..e4e9cfa
--- /dev/null
+++ b/WebCore/khtml/khtml_selection.cpp
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+  
+#include "khtml_selection.h"
+
+#include "khtml_part.h"
+#include "khtmlview.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qrect.h"
+#include "dom/dom2_range.h"
+#include "dom/dom_node.h"
+#include "dom/dom_position.h"
+#include "dom/dom_string.h"
+#include "rendering/render_object.h"
+#include "rendering/render_style.h"
+#include "rendering/render_text.h"
+#include "xml/dom_docimpl.h"
+#include "xml/dom_nodeimpl.h"
+#include "xml/dom_textimpl.h"
+
+#if APPLE_CHANGES
+#include <KWQAssertions.h>
+#include <CoreServices/CoreServices.h>
+#endif
+
+using DOM::DocumentImpl;
+using DOM::DOMPosition;
+using DOM::DOMString;
+using DOM::Node;
+using DOM::NodeImpl;
+using DOM::Range;
+using DOM::TextImpl;
+using khtml::InlineTextBox;
+using khtml::InlineTextBoxArray;
+using khtml::RenderObject;
+using khtml::RenderText;
+
+enum { CARET_BLINK_FREQUENCY = 500 };
+
+#if APPLE_CHANGES
+static void findWordBoundary(QChar *chars, int len, int position, int *start, int *end);
+static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset);
+static bool lastRunAt(RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset);
+static bool startAndEndLineNodesIncludingNode(DOM::NodeImpl *node, int offset, KHTMLSelection &selection);
+#endif
+
+
+KHTMLSelection::KHTMLSelection() 
+	: QObject(),
+	  m_part(0),
+	  m_baseNode(0), m_baseOffset(0), m_extentNode(0), m_extentOffset(0),
+	  m_startNode(0), m_startOffset(0), m_endNode(0), m_endOffset(0),
+	  m_state(NONE), m_caretBlinkTimer(0),
+      m_baseIsStart(true), m_caretBlinks(true), m_caretPaint(false), 
+      m_visible(false), m_startEndValid(false)
+{
+}
+
+KHTMLSelection::KHTMLSelection(const KHTMLSelection &o)
+	: QObject(),
+	  m_part(o.m_part),
+	  m_baseNode(0), m_baseOffset(0), m_extentNode(0), m_extentOffset(0),
+	  m_startNode(0), m_startOffset(0), m_endNode(0), m_endOffset(0)
+{
+    setBase(o.baseNode(), o.baseOffset());
+    setExtent(o.extentNode(), o.extentOffset());
+    setStart(o.startNode(), o.startOffset());
+    setEnd(o.endNode(), o.endOffset());
+
+	m_state = o.m_state;
+	m_caretBlinkTimer = o.m_caretBlinkTimer;
+	m_baseIsStart = o.m_baseIsStart;
+	m_caretBlinks = o.m_caretBlinks;
+	m_caretPaint = true;
+	m_visible = o.m_visible;
+    m_startEndValid = true;
+}
+
+KHTMLSelection::~KHTMLSelection()
+{
+    if (m_baseNode)
+        m_baseNode->deref();
+    if (m_extentNode)
+        m_extentNode->deref();
+}
+
+KHTMLSelection &KHTMLSelection::operator=(const KHTMLSelection &o)
+{
+    m_part = o.m_part;
+    
+    setBase(o.baseNode(), o.baseOffset());
+    setExtent(o.extentNode(), o.extentOffset());
+    setStart(o.startNode(), o.startOffset());
+    setEnd(o.endNode(), o.endOffset());
+
+	m_state = o.m_state;
+	m_caretBlinkTimer = o.m_caretBlinkTimer;
+	m_baseIsStart = o.m_baseIsStart;
+	m_caretBlinks = o.m_caretBlinks;
+	m_caretPaint = true;
+	m_visible = o.m_visible;
+    m_startEndValid = true;
+    return *this;
+}
+
+void KHTMLSelection::setSelection(DOM::NodeImpl *node, long offset)
+{
+	setBaseNode(node);
+	setExtentNode(node);
+	setBaseOffset(offset);
+	setExtentOffset(offset);
+	update();
+}
+
+void KHTMLSelection::setSelection(const DOM::Range &r)
+{
+	setSelection(r.startContainer().handle(), r.startOffset(), 
+		r.endContainer().handle(), r.endOffset());
+}
+
+void KHTMLSelection::setSelection(const DOM::DOMPosition &pos)
+{
+	setSelection(pos.node(), pos.offset());
+}
+
+void KHTMLSelection::setSelection(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset)
+{
+	setBaseNode(baseNode);
+	setExtentNode(extentNode);
+	setBaseOffset(baseOffset);
+	setExtentOffset(extentOffset);
+	update();
+}
+
+void KHTMLSelection::setBase(DOM::NodeImpl *node, long offset)
+{
+	setBaseNode(node);
+	setBaseOffset(offset);
+	update();
+}
+
+void KHTMLSelection::setExtent(DOM::NodeImpl *node, long offset)
+{
+	setExtentNode(node);
+	setExtentOffset(offset);
+	update();
+}
+
+bool KHTMLSelection::alterSelection(EAlter alter, EDirection dir, ETextElement elem)
+{
+    DOMPosition pos;
+    
+    switch (dir) {
+        case FORWARD:
+            switch (elem) {
+                case CHARACTER:
+                    pos = nextCharacterPosition();
+                    break;
+                case WORD:
+                    break;
+                case LINE:
+                    break;
+            }
+            break;
+        case BACKWARD:
+            switch (elem) {
+                case CHARACTER:
+                    break;
+                case WORD:
+                    break;
+                case LINE:
+                    break;
+            }
+            break;
+    }
+    
+    if (pos.isEmpty())
+        return false;
+    
+    if (alter == MOVE)
+        setSelection(pos.node(), pos.offset());
+    else // alter == EXTEND
+        setExtent(pos.node(), pos.offset());
+    
+    return true;
+}
+
+void KHTMLSelection::clearSelection()
+{
+	setBaseNode(0);
+	setExtentNode(0);
+	setBaseOffset(0);
+	setExtentOffset(0);
+	update();
+}
+
+NodeImpl *KHTMLSelection::startNode() const
+{ 
+    return m_startNode;
+}
+
+long KHTMLSelection::startOffset() const
+{ 
+    return m_startOffset;
+}
+
+NodeImpl *KHTMLSelection::endNode() const 
+{
+    return m_endNode;
+}
+
+long KHTMLSelection::endOffset() const 
+{ 
+    return m_endOffset;
+}
+
+void KHTMLSelection::setVisible(bool flag)
+{
+    m_visible = flag;
+    update();
+}
+
+void KHTMLSelection::invalidate()
+{
+    update();
+}
+
+void KHTMLSelection::update()
+{
+    // make sure we do not have a dangling start or end
+	if (!m_baseNode && !m_extentNode) {
+        setBaseOffset(0);
+        setExtentOffset(0);
+        m_baseIsStart = true;
+    }
+	else if (!m_baseNode) {
+		setBaseNode(m_extentNode);
+		setBaseOffset(m_extentOffset);
+        m_baseIsStart = true;
+	}
+	else if (!m_extentNode) {
+		setExtentNode(m_baseNode);
+		setExtentOffset(m_baseOffset);
+        m_baseIsStart = true;
+	}
+    else {
+        // adjust m_baseIsStart as needed
+        if (m_baseNode == m_extentNode) {
+            if (m_baseOffset > m_extentOffset)
+                m_baseIsStart = false;
+            else 
+                m_baseIsStart = true;
+        }
+        else if (nodeIsBeforeNode(m_baseNode, m_extentNode))
+            m_baseIsStart = true;
+        else
+            m_baseIsStart = false;
+    }
+
+    // update start and end
+    m_startEndValid = false;
+    calculateStartAndEnd();
+    
+    // update the blink timer
+    if (m_caretBlinkTimer >= 0)
+        killTimer(m_caretBlinkTimer);
+    if (m_visible && m_state == CARET && m_caretBlinks)
+        m_caretBlinkTimer = startTimer(CARET_BLINK_FREQUENCY);
+    else
+        m_caretBlinkTimer = -1;
+
+    // short-circuit if not visible
+    if (!m_visible) {
+        if (m_caretPaint) {
+            m_caretPaint = false;
+            repaint();
+        }
+        return;
+    }
+
+    // short-circuit if not CARET state
+	if (m_state != CARET)
+		return;
+
+    // calculate the new caret rendering position
+    int oldX = m_caretX;   
+    int oldY = m_caretY;   
+    int oldSize = m_caretSize;
+    
+    int newX = 0;
+    int newY = 0;
+    int newSize = 0;
+    
+    NodeImpl *node = startNode();
+    if (node && node->renderer()) {
+        int w;
+        node->renderer()->caretPos(startOffset(), true, newX, newY, w, newSize);
+    }
+
+    // repaint the old position if necessary
+    // prevents two carets from ever being drawn
+    if (m_caretPaint && (oldX != newX || oldY != newY || oldSize != newSize)) {
+        repaint();
+    }
+
+    // update caret rendering position
+    m_caretX = newX;
+    m_caretY = newY;
+    m_caretSize = newSize;
+
+    // paint the caret if it is visible
+    if (m_visible && m_caretSize != 0) {
+        m_caretPaint = true;
+        repaint();
+    }
+}
+
+bool KHTMLSelection::isEmpty() const
+{
+    return m_baseNode == 0 && m_extentNode == 0;
+}
+
+#ifdef APPLE_CHANGES
+void KHTMLSelection::paint(QPainter *p, const QRect &rect) const
+{
+    if (!m_caretPaint || m_state != CARET)
+        return;
+
+    QRect pos(m_caretX, m_caretY, 1, m_caretSize);
+    if (pos.intersects(rect)) {
+        QPen pen = p->pen();
+        pen.setStyle(SolidLine);
+        pen.setColor(Qt::black);
+        pen.setWidth(1);
+        p->setPen(pen);
+        p->drawLine(pos.left(), pos.top(), pos.left(), pos.bottom());
+    }
+}
+#endif
+
+void KHTMLSelection::setPart(KHTMLPart *part)
+{
+    m_part = part;
+}
+
+void KHTMLSelection::timerEvent(QTimerEvent *e)
+{
+    if (e->timerId() == m_caretBlinkTimer && m_visible) {
+        m_caretPaint = !m_caretPaint;
+        repaint();
+    }
+}
+
+void KHTMLSelection::repaint(bool immediate) const
+{
+    KHTMLView *v = m_part->view();
+    if (!v)
+        return;
+    // EDIT FIXME: fudge a bit to make sure we don't leave behind artifacts
+    v->updateContents(m_caretX - 1, m_caretY - 1, 3, m_caretSize + 2, immediate);
+}
+
+void KHTMLSelection::setBaseNode(DOM::NodeImpl *node)
+{
+	if (m_baseNode == node)
+		return;
+
+	if (m_baseNode)
+		m_baseNode->deref();
+	
+	m_baseNode = node;
+	
+	if (m_baseNode)
+		m_baseNode->ref();
+}
+
+void KHTMLSelection::setBaseOffset(long offset)
+{
+	m_baseOffset = offset;
+}
+
+void KHTMLSelection::setExtentNode(DOM::NodeImpl *node)
+{
+	if (m_extentNode == node)
+		return;
+
+	if (m_extentNode)
+		m_extentNode->deref();
+	
+	m_extentNode = node;
+	
+	if (m_extentNode)
+		m_extentNode->ref();
+}
+	
+void KHTMLSelection::setExtentOffset(long offset)
+{
+	m_extentOffset = offset;
+}
+
+void KHTMLSelection::setStart(DOM::NodeImpl *node, long offset)
+{
+    setStartNode(node);
+    setStartOffset(offset);
+}
+
+void KHTMLSelection::setStartNode(DOM::NodeImpl *node)
+{
+	if (m_startNode == node)
+		return;
+
+	if (m_startNode)
+		m_startNode->deref();
+	
+	m_startNode = node;
+	
+	if (m_startNode)
+		m_startNode->ref();
+}
+
+void KHTMLSelection::setStartOffset(long offset)
+{
+	m_startOffset = offset;
+}
+
+void KHTMLSelection::setEnd(DOM::NodeImpl *node, long offset)
+{
+    setEndNode(node);
+    setEndOffset(offset);
+}
+
+void KHTMLSelection::setEndNode(DOM::NodeImpl *node)
+{
+	if (m_endNode == node)
+		return;
+
+	if (m_endNode)
+		m_endNode->deref();
+	
+	m_endNode = node;
+	
+	if (m_endNode)
+		m_endNode->ref();
+}
+	
+void KHTMLSelection::setEndOffset(long offset)
+{
+	m_endOffset = offset;
+}
+
+void KHTMLSelection::expandSelection(ETextElement select)
+{
+    m_startEndValid = false;
+    calculateStartAndEnd(select);
+}
+
+void KHTMLSelection::calculateStartAndEnd(ETextElement select)
+{
+    if (m_startEndValid)
+        return;
+
+#if !APPLE_CHANGES
+    if (m_baseIsStart) {
+        setStartNode(m_baseNode);
+        setStartOffset(m_baseOffset);
+        setEndNode(m_extentNode);
+        setEndOffset(m_extentOffset);
+    }
+    else {
+        setStartNode(m_extentNode);
+        setStartOffset(m_extentOffset);
+        setEndNode(m_baseNode);
+        setEndOffset(m_baseOffset);
+    }
+#else
+    if (select == CHARACTER) {
+        if (m_baseIsStart) {
+            setStartNode(m_baseNode);
+            setStartOffset(m_baseOffset);
+            setEndNode(m_extentNode);
+            setEndOffset(m_extentOffset);
+        }
+        else {
+            setStartNode(m_extentNode);
+            setStartOffset(m_extentOffset);
+            setEndNode(m_baseNode);
+            setEndOffset(m_baseOffset);
+        }
+    }
+    else if (select == WORD) {
+        int baseStartOffset = m_baseOffset;
+        int baseEndOffset = m_baseOffset;
+        int extentStartOffset = m_extentOffset;
+        int extentEndOffset = m_extentOffset;
+        if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            DOMString t = m_baseNode->nodeValue();
+            QChar *chars = t.unicode();
+            uint len = t.length();
+            findWordBoundary(chars, len, m_baseOffset, &baseStartOffset, &baseEndOffset);
+        }
+        if (m_extentNode && (m_extentNode->nodeType() == Node::TEXT_NODE || m_extentNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            DOMString t = m_extentNode->nodeValue();
+            QChar *chars = t.unicode();
+            uint len = t.length();
+            findWordBoundary(chars, len, m_extentOffset, &extentStartOffset, &extentEndOffset);
+        }
+        if (m_baseIsStart) {
+            setStartNode(m_baseNode);
+            setStartOffset(baseStartOffset);
+            setEndNode(m_extentNode);
+            setEndOffset(extentEndOffset);
+        }
+        else {
+            setStartNode(m_extentNode);
+            setStartOffset(extentStartOffset);
+            setEndNode(m_baseNode);
+            setEndOffset(baseEndOffset);
+        }
+    }
+    else {  // select == LINE
+        KHTMLSelection baseSelection = *this;
+        KHTMLSelection extentSelection = *this;
+        if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            if (startAndEndLineNodesIncludingNode(m_baseNode, m_baseOffset, baseSelection)) {
+                setStartNode(baseSelection.baseNode());
+                setStartOffset(baseSelection.baseOffset());
+                setEndNode(baseSelection.extentNode());
+                setEndOffset(baseSelection.extentOffset());
+            }
+        }
+        if (m_extentNode && (m_extentNode->nodeType() == Node::TEXT_NODE || m_extentNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            if (startAndEndLineNodesIncludingNode(m_extentNode, m_extentOffset, extentSelection)) {
+                setStartNode(extentSelection.baseNode());
+                setStartOffset(extentSelection.baseOffset());
+                setEndNode(extentSelection.extentNode());
+                setEndOffset(extentSelection.extentOffset());
+            }
+        }
+        if (m_baseIsStart) {
+            setStartNode(baseSelection.startNode());
+            setStartOffset(baseSelection.startOffset());
+            setEndNode(extentSelection.endNode());
+            setEndOffset(extentSelection.endOffset());
+        }
+        else {
+            setStartNode(extentSelection.startNode());
+            setStartOffset(extentSelection.startOffset());
+            setEndNode(baseSelection.endNode());
+            setEndOffset(baseSelection.endOffset());
+        }
+    }
+#endif  // APPLE_CHANGES
+
+	// update the state
+	if (!m_startNode && !m_endNode)
+		m_state = NONE;
+	if (m_startNode == m_endNode && m_startOffset == m_endOffset)
+		m_state = CARET;
+	else
+		m_state = RANGE;
+    
+    m_startEndValid = true;
+}
+
+DOMPosition KHTMLSelection::nextCharacterPosition()
+{
+    DOMPosition result;
+	NodeImpl *node = endNode();
+	long offset = endOffset();
+    long desiredOffset = offset + 1;
+
+    if (!node)
+        return result;
+    
+    //
+    // Look in this renderer
+    //
+    RenderObject *renderer = node->renderer();
+    if (renderer->isText()) {
+        RenderText *textRenderer = static_cast<khtml::RenderText *>(renderer);
+        InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+        unsigned i = 0;
+        for (i = 0; i < runs.count(); i++) {
+            long start = runs[i]->m_start;
+            long end = runs[i]->m_start + runs[i]->m_len;
+            if (desiredOffset > end) {
+                // Skip this node.
+                // It is too early in the text runs to be involved.
+                continue;
+            }
+            else if (desiredOffset >= start && 
+                (desiredOffset < end || (desiredOffset == end && i + 1 == runs.count() && !renderer->nextEditable())) ||
+                (desiredOffset == end && textRenderer->precedesLineBreak() && !textRenderer->followsLineBreak())) {
+                // Desired offset is in this node.
+                // Either it is:
+                // 1. at or after the start and before, but not at the end
+                // 2. at the end of a text run and is immediately followed by a line break
+                //    but does not precede a line break
+                // 3. at the end of the editable content of the document
+                return DOMPosition(renderer->element(), desiredOffset);
+            }
+            else if (desiredOffset <= start) {
+                // The offset we're looking for is before this node
+                // this means the offset must be in text that is
+                // not rendered. Just return the start of the node.
+                return DOMPosition(renderer->element(), start);
+            }
+        }
+    }
+    else if (desiredOffset < renderer->caretMaxOffset() || (desiredOffset == renderer->caretMaxOffset() && !renderer->nextEditable())) {
+        return DOMPosition(node, desiredOffset);
+    }
+
+    //
+    // Look in next renderer(s)
+    //
+    renderer = renderer->nextEditable();
+    while (renderer) {
+        if (renderer->isText()) {
+            RenderText *textRenderer = static_cast<khtml::RenderText *>(renderer);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            if (runs.count())
+                return DOMPosition(renderer->element(), runs[0]->m_start);
+        }
+        else {
+            return DOMPosition(renderer->element(), renderer->caretMinOffset());
+        }
+        renderer = renderer->nextEditable();
+    }
+
+    result = DOMPosition(node, offset);
+    return result;
+}
+
+bool KHTMLSelection::nodeIsBeforeNode(NodeImpl *n1, NodeImpl *n2) 
+{
+	if (!n1 || !n2) 
+		return true;
+ 
+ 	if (n1 == n2)
+ 		return true;
+ 
+ 	bool result = false;
+    int n1Depth = 0;
+    int n2Depth = 0;
+
+    // First we find the depths of the two nodes in the tree (n1Depth, n2Depth)
+    DOM::NodeImpl *n = n1;
+    while (n->parentNode()) {
+        n = n->parentNode();
+        n1Depth++;
+    }
+    n = n2;
+    while (n->parentNode()) {
+        n = n->parentNode();
+        n2Depth++;
+    }
+    // Climb up the tree with the deeper node, until both nodes have equal depth
+    while (n2Depth > n1Depth) {
+        n2 = n2->parentNode();
+        n2Depth--;
+    }
+    while (n1Depth > n2Depth) {
+        n1 = n1->parentNode();
+        n1Depth--;
+    }
+    // Climb the tree with both n1 and n2 until they have the same parent
+    while (n1->parentNode() != n2->parentNode()) {
+        n1 = n1->parentNode();
+        n2 = n2->parentNode();
+    }
+    // Iterate through the parent's children until n1 or n2 is found
+    n = n1->parentNode()->firstChild();
+    while (n) {
+        if (n == n1) {
+            result = true;
+            break;
+        }
+        else if (n == n2) {
+            result = false;
+            break;
+        }
+        n = n->nextSibling();
+    }
+	return result;
+}
+
+#if APPLE_CHANGES
+
+static void findWordBoundary(QChar *chars, int len, int position, int *start, int *end)
+{
+    TextBreakLocatorRef breakLocator;
+    OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakWordMask, &breakLocator);
+    if (status == noErr) {
+        UniCharArrayOffset startOffset, endOffset;
+        status = UCFindTextBreak(breakLocator, kUCTextBreakWordMask, 0, (const UniChar *)chars, len, position, &endOffset);
+        if (status == noErr) {
+            status = UCFindTextBreak(breakLocator, kUCTextBreakWordMask, kUCTextBreakGoBackwardsMask, (const UniChar *)chars, len, position, &startOffset);
+        }
+        UCDisposeTextBreakLocator(&breakLocator);
+        if (status == noErr) {
+            *start = startOffset;
+            *end = endOffset;
+            return;
+        }
+    }
+    
+    // If Carbon fails (why would it?), do a simple space/punctuation boundary check.
+    if (chars[position].isSpace()) {
+        int pos = position;
+        while (chars[pos].isSpace() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (chars[pos].isSpace() && pos < (int)len)
+            pos++;
+        *end = pos;
+    } else if (chars[position].isPunct()) {
+        int pos = position;
+        while (chars[pos].isPunct() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (chars[pos].isPunct() && pos < (int)len)
+            pos++;
+        *end = pos;
+    } else {
+        int pos = position;
+        while (!chars[pos].isSpace() && !chars[pos].isPunct() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (!chars[pos].isSpace() && !chars[pos].isPunct() && pos < (int)len)
+            pos++;
+        *end = pos;
+    }
+}
+
+static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
+{
+    for (RenderObject *n = renderNode; n; n = n->nextSibling()) {
+        if (n->isText()) {
+            RenderText *textRenderer = static_cast<khtml::RenderText *>(n);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            for (unsigned i = 0; i != runs.count(); i++) {
+                if (runs[i]->m_y == y) {
+                    startNode = textRenderer->element();
+                    startOffset = runs[i]->m_start;
+                    return true;
+                }
+            }
+        }
+        
+        if (firstRunAt(n->firstChild(), y, startNode, startOffset)) {
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+static bool lastRunAt(RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset)
+{
+    RenderObject *n = renderNode;
+    if (!n) {
+        return false;
+    }
+    RenderObject *next;
+    while ((next = n->nextSibling())) {
+        n = next;
+    }
+    
+    while (1) {
+        if (lastRunAt(n->firstChild(), y, endNode, endOffset)) {
+            return true;
+        }
+    
+        if (n->isText()) {
+            RenderText *textRenderer =  static_cast<khtml::RenderText *>(n);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            for (int i = (int)runs.count()-1; i >= 0; i--) {
+                if (runs[i]->m_y == y) {
+                    endNode = textRenderer->element();
+                    endOffset = runs[i]->m_start + runs[i]->m_len;
+                    return true;
+                }
+            }
+        }
+        
+        if (n == renderNode) {
+            return false;
+        }
+        
+        n = n->previousSibling();
+    }
+}
+
+static bool startAndEndLineNodesIncludingNode(DOM::NodeImpl *node, int offset, KHTMLSelection &selection)
+{
+    if (node && (node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE)) {
+        int pos;
+        int selectionPointY;
+        RenderText *renderer = static_cast<RenderText *>(node->renderer());
+        InlineTextBox * run = renderer->findNextInlineTextBox( offset, pos );
+        DOMString t = node->nodeValue();
+        
+        if (!run)
+            return false;
+            
+        selectionPointY = run->m_y;
+        
+        // Go up to first non-inline element.
+        khtml::RenderObject *renderNode = renderer;
+        while (renderNode && renderNode->isInline())
+            renderNode = renderNode->parent();
+        
+        renderNode = renderNode->firstChild();
+        
+        DOM::NodeImpl *startNode = 0;
+        DOM::NodeImpl *endNode = 0;
+        long startOffset;
+        long endOffset;
+        
+        // Look for all the first child in the block that is on the same line
+        // as the selection point.
+        if (!firstRunAt (renderNode, selectionPointY, startNode, startOffset))
+            return false;
+    
+        // Look for all the last child in the block that is on the same line
+        // as the selection point.
+        if (!lastRunAt (renderNode, selectionPointY, endNode, endOffset))
+            return false;
+        
+        selection.setSelection(startNode, startOffset, endNode, endOffset);
+        
+        return true;
+    }
+    return false;
+}
+
+#endif
diff --git a/WebCore/khtml/khtml_selection.h b/WebCore/khtml/khtml_selection.h
new file mode 100644
index 0000000..e073149
--- /dev/null
+++ b/WebCore/khtml/khtml_selection.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef __khtml_selection_h__
+#define __khtml_selection_h__
+
+#include <qobject.h>
+
+class KHTMLPart;
+class KHTMLPartPrivate;
+class KHTMLView;
+class QPainter;
+class QRect;
+class QTimerEvent;
+
+namespace DOM {
+    class DOMPosition;
+    class NodeImpl;
+    class Range;
+};
+
+class KHTMLSelection : public QObject
+{
+  Q_OBJECT
+
+public:
+    KHTMLSelection();
+    KHTMLSelection(const KHTMLSelection &);
+    ~KHTMLSelection();
+
+	enum EState { NONE, CARET, RANGE };
+	enum ETextElement { CHARACTER, WORD, LINE };
+	enum EDirection { FORWARD, BACKWARD };
+	enum EAlter { MOVE, EXTEND };
+
+	EState state() const { return m_state; }
+
+    void setSelection(DOM::NodeImpl *node, long offset);
+    void setSelection(const DOM::Range &);
+    void setSelection(const DOM::DOMPosition &);
+    void setSelection(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset);
+    void setBase(DOM::NodeImpl *node, long offset);
+    void setExtent(DOM::NodeImpl *node, long offset);
+    void expandSelection(ETextElement);
+    bool alterSelection(EAlter, EDirection, ETextElement);
+    void clearSelection();
+    
+    DOM::NodeImpl *baseNode() const { return m_baseNode; }
+    long baseOffset() const { return m_baseOffset; }
+
+    DOM::NodeImpl *extentNode() const { return m_extentNode; }
+    long extentOffset() const { return m_extentOffset; }
+
+    DOM::NodeImpl *startNode() const;
+    long startOffset() const;
+
+    DOM::NodeImpl *endNode() const;
+    long endOffset() const;
+
+    void setVisible(bool flag=true);
+    bool visible() const { return m_visible; }
+    
+    void invalidate();
+    
+    bool isEmpty() const;
+    
+#ifdef APPLE_CHANGES
+    void paint(QPainter *p, const QRect &rect) const;
+#endif
+
+    KHTMLSelection &operator=(const KHTMLSelection &o);
+    
+    friend bool operator==(const KHTMLSelection &a, const KHTMLSelection &b);
+    friend bool operator!=(const KHTMLSelection &a, const KHTMLSelection &b);
+    
+    friend class KHTMLPart;
+
+    void dump() {
+        fprintf(stderr, "selection: %p:%d ; %p:%d (%p:%d ; %p:%d)\n", 
+            m_baseNode, m_baseOffset, m_extentNode, m_extentOffset,
+            startNode(), startOffset(), endNode(), endOffset());
+    }
+    
+private:
+    void setPart(KHTMLPart *part);
+
+    void update();
+
+    void timerEvent(QTimerEvent *e);
+    void repaint(bool immediate=false) const;
+
+	void setBaseNode(DOM::NodeImpl *);
+	void setBaseOffset(long);
+	void setExtentNode(DOM::NodeImpl *);
+	void setExtentOffset(long);
+
+	void setStart(DOM::NodeImpl *, long);
+	void setStartNode(DOM::NodeImpl *);
+	void setStartOffset(long);
+	void setEnd(DOM::NodeImpl *, long);
+	void setEndNode(DOM::NodeImpl *);
+	void setEndOffset(long);
+
+    bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
+
+    void calculateStartAndEnd(ETextElement select=CHARACTER);
+    
+    DOM::DOMPosition nextCharacterPosition();
+    
+    KHTMLPart *m_part;            // part for this selection
+
+    DOM::NodeImpl *m_baseNode;    // base node for the selection
+    long m_baseOffset;            // offset into base node where selection is
+    DOM::NodeImpl *m_extentNode;  // extent node for the selection
+    long m_extentOffset;          // offset into extent node where selection is
+
+    DOM::NodeImpl *m_startNode;   // start node for the selection (read-only)
+    long m_startOffset;           // offset into start node where selection is (read-only)
+    DOM::NodeImpl *m_endNode;     // end node for the selection (read-only)
+    long m_endOffset;             // offset into end node where selection is (read-only)
+
+	EState m_state;               // the state of the selection
+
+    int m_caretBlinkTimer;        // caret blink frequency timer id
+	
+	int m_caretX;
+	int m_caretY;
+	int m_caretSize;
+
+	bool m_baseIsStart : 1;     // true if base node is before the extent node
+    bool m_caretBlinks : 1;     // true if caret blinks
+    bool m_caretPaint : 1;      // flag used to deal with blinking the caret
+    bool m_visible : 1;         // true if selection is to be displayed at all
+	bool m_startEndValid : 1;   // true if the start and end are valid
+};
+
+
+inline bool operator==(const KHTMLSelection &a, const KHTMLSelection &b)
+{
+    return a.baseNode() == b.baseNode() && a.baseOffset() == b.baseOffset() &&
+        a.extentNode() == b.extentNode() && a.extentOffset() == b.extentOffset();
+}
+
+inline bool operator!=(const KHTMLSelection &a, const KHTMLSelection &b)
+{
+    return !(a == b);
+}
+
+#endif
\ No newline at end of file
diff --git a/WebCore/khtml/khtmlpart_p.h b/WebCore/khtml/khtmlpart_p.h
index 0e019a0..e5dac6b 100644
--- a/WebCore/khtml/khtmlpart_p.h
+++ b/WebCore/khtml/khtmlpart_p.h
@@ -38,6 +38,7 @@
 #include "khtml_events.h"
 #include "khtml_ext.h"
 #include "khtml_iface.h"
+#include "khtml_selection.h"
 #include "khtml_settings.h"
 #include "misc/decoder.h"
 #include "java/kjavaappletcontext.h"
@@ -119,8 +120,7 @@ public:
     m_bCleared = false;
     m_zoomFactor = 100;
     m_bDnd = true;
-    m_startOffset = m_endOffset = 0;
-    m_startBeforeEnd = true;
+    m_extendAtEnd = true;
 #if !APPLE_CHANGES
     m_linkCursor = KCursor::handCursor();
 #endif
@@ -341,22 +341,14 @@ public:
   DOM::Node m_mousePressNode; //node under the mouse when the mouse was pressed (set in the mouse handler)
 
 #if APPLE_CHANGES
-  DOM::Node m_initialSelectionStart;
-  long m_initialSelectionStartOffset;
-  DOM::Node m_initialSelectionEnd;
-  long m_initialSelectionEndOffset;
-  bool m_selectionInitiatedWithDoubleClick:1;
-  bool m_selectionInitiatedWithTripleClick:1;
+  KHTMLSelection::ETextElement m_textElement;
   bool m_mouseMovedSinceLastMousePress:1;
 #endif
-  DOM::Node m_selectionStart;
-  long m_startOffset;
-  DOM::Node m_selectionEnd;
-  long m_endOffset;
+  KHTMLSelection m_selection;
   QString m_overURL;
   QString m_overURLTarget;
 
-  bool m_startBeforeEnd:1;
+  bool m_extendAtEnd:1;
   bool m_bDnd:1;
   bool m_bFirstData:1;
   bool m_bClearing:1;
diff --git a/WebCore/khtml/khtmlview.cpp b/WebCore/khtml/khtmlview.cpp
index bf0ea78..c6ea3ab 100644
--- a/WebCore/khtml/khtmlview.cpp
+++ b/WebCore/khtml/khtmlview.cpp
@@ -26,21 +26,26 @@
 #include "khtmlview.h"
 
 #include "khtml_part.h"
+#include "khtml_selection.h"
 #include "khtml_events.h"
 
 #include "html/html_documentimpl.h"
 #include "html/html_inlineimpl.h"
 #include "html/html_formimpl.h"
+#include "rendering/render_arena.h"
 #include "rendering/render_object.h"
 #include "rendering/render_canvas.h"
 #include "rendering/render_style.h"
 #include "rendering/render_replaced.h"
+#include "rendering/render_line.h"
+#include "rendering/render_text.h"
 #include "xml/dom2_eventsimpl.h"
 #include "css/cssstyleselector.h"
 #include "misc/htmlhashes.h"
 #include "misc/helper.h"
 #include "khtml_settings.h"
 #include "khtml_printsettings.h"
+#include "khtmlpart_p.h"
 
 #include <kcursor.h>
 #include <ksimpleconfig.h>
@@ -79,6 +84,7 @@ protected:
     virtual void maybeTip(const QPoint &);
 
 private:
+
     KHTMLView *m_view;
     KHTMLViewPrivate* m_viewprivate;
 };
@@ -98,7 +104,7 @@ public:
         layoutTimerId = 0;
         complete = false;
         mousePressed = false;
-	tooltip = 0;
+        tooltip = 0;
 #ifdef INCREMENTAL_REPAINTING
         doFullRepaint = true;
 #endif
@@ -332,11 +338,10 @@ void KHTMLView::init()
 
 void KHTMLView::clear()
 {
-
-
 //    viewport()->erase();
 
     setStaticBackground(false);
+    m_part->getKHTMLSelection().clearSelection();
 
     d->reset();
     killTimers();
@@ -383,6 +388,7 @@ void KHTMLView::resizeEvent (QResizeEvent* e)
 #endif
     if ( m_part && m_part->xmlDocImpl() )
         m_part->xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT, false, false );
+
     KApplication::sendPostedEvents(viewport(), QEvent::Paint);
 }
 
@@ -433,6 +439,8 @@ void KHTMLView::drawContents( QPainter *p, int ex, int ey, int ew, int eh )
         py += PAINT_BUFFER_HEIGHT;
     }
 
+    // EDIT FIXME: KDE needs to draw the caret here.
+
     khtml::DrawContentsEvent event( p, ex, ey, ew, eh );
     QApplication::sendEvent( m_part, &event );
 
@@ -609,6 +617,8 @@ void KHTMLView::layout()
 
     root->layout();
 
+    m_part->getKHTMLSelection().invalidate();
+        
     //kdDebug( 6000 ) << "TIME: layout() dt=" << qt.elapsed() << endl;
    
     d->layoutSchedulingEnabled=true;
@@ -955,7 +965,6 @@ void KHTMLView::viewportMouseReleaseEvent( QMouseEvent * _mouse )
 
 void KHTMLView::keyPressEvent( QKeyEvent *_ke )
 {
-
     if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()) {
         if (m_part->xmlDocImpl()->focusNode()->dispatchKeyEvent(_ke))
         {
@@ -1267,19 +1276,24 @@ void KHTMLView::focusNextPrevNode(bool next)
         else
             scrollTo(QRect(contentsX()+visibleWidth()/2,0,0,0));
     }
-    else
-    // Scroll the view as necessary to ensure that the new focus node is visible
-    {
-      if (oldFocusNode)
-	{
-	  if (!scrollTo(newFocusNode->getRect()))
-	    return;
-	}
-      else
-	{
-	  ensureVisible(contentsX(), next?0:contentsHeight());
-	  //return;
-	}
+    else {
+        // EDIT FIXME: if it's an editable element, activate the caret
+        // otherwise, hide it
+        if (!m_part->inEditMode() && newFocusNode->renderer()->isEditable()) {
+            // make caret visible
+        } 
+        else {
+            // hide caret
+        }
+
+        // Scroll the view as necessary to ensure that the new focus node is visible
+        if (oldFocusNode) {
+            if (!scrollTo(newFocusNode->getRect()))
+                return;
+        }
+        else {
+            ensureVisible(contentsX(), next ? 0: contentsHeight());
+        }
     }
     // Set focus node on the document
     m_part->xmlDocImpl()->setFocusNode(newFocusNode);
@@ -1765,9 +1779,16 @@ void KHTMLView::dropEvent( QDropEvent *ev )
 }
 #endif // !APPLE_CHANGES
 
+void KHTMLView::focusInEvent( QFocusEvent *e )
+{
+    m_part->getKHTMLSelection().setVisible();
+    QScrollView::focusInEvent( e );
+}
+
 void KHTMLView::focusOutEvent( QFocusEvent *e )
 {
     m_part->stopAutoScroll();
+    m_part->getKHTMLSelection().setVisible(false);
     QScrollView::focusOutEvent( e );
 }
 
@@ -1789,7 +1810,6 @@ void KHTMLView::repaintRectangle(const QRect& r, bool immediate)
 
 void KHTMLView::timerEvent ( QTimerEvent *e )
 {
-//    kdDebug() << "timer event " << e->timerId() << endl;
     if (e->timerId()==d->layoutTimerId)
         layout();
 }
@@ -1851,3 +1871,4 @@ void KHTMLView::complete()
         d->layoutTimerId = startTimer( 0 );
     }
 }
+
diff --git a/WebCore/khtml/khtmlview.h b/WebCore/khtml/khtmlview.h
index f5f035f..27eb9ec 100644
--- a/WebCore/khtml/khtmlview.h
+++ b/WebCore/khtml/khtmlview.h
@@ -59,6 +59,7 @@ namespace khtml {
     class RenderPartObject;
     class RenderWidget;
     class CSSStyleSelector;
+    class InlineBox;
     void applyRule(DOM::CSSProperty *prop);
 };
 
@@ -167,14 +168,14 @@ public:
 #endif
 
 signals:
-    void cleared();
-
+        void cleared();
+    
 protected:
-    void clear();
-
+        void clear();
+    
 #if APPLE_CHANGES
 public:
-    void clearPart();
+        void clearPart();
 #endif
     virtual void resizeEvent ( QResizeEvent * event );
     virtual void showEvent ( QShowEvent * );
@@ -184,8 +185,9 @@ public:
     virtual void drawContents ( QPainter * p, int clipx, int clipy, int clipw, int cliph );
     virtual void drawContents( QPainter* );
 #endif
-
+    
     virtual void viewportMousePressEvent( QMouseEvent * );
+    virtual void focusInEvent( QFocusEvent * );
     virtual void focusOutEvent( QFocusEvent * );
     virtual void viewportMouseDoubleClickEvent( QMouseEvent * );
     virtual void viewportMouseMoveEvent(QMouseEvent *);
diff --git a/WebCore/khtml/rendering/render_block.cpp b/WebCore/khtml/rendering/render_block.cpp
index 1cbe61e..fbdfe0a 100644
--- a/WebCore/khtml/rendering/render_block.cpp
+++ b/WebCore/khtml/rendering/render_block.cpp
@@ -37,6 +37,8 @@
 #include "render_block.h"
 
 #include "khtmlview.h"
+#include "khtml_part.h"
+#include "khtml_selection.h"
 #include "htmltags.h"
 
 using namespace DOM;
@@ -1243,6 +1245,22 @@ void RenderBlock::paintObject(QPainter *p, int _x, int _y,
         style()->outlineWidth() && style()->visibility() == VISIBLE)
         paintOutline(p, _tx, _ty, width(), height(), style());
 
+    // 5. paint caret.
+    /*
+        If the caret's node's render object's containing block is this block,
+        and the paint action is PaintActionForeground,
+        then paint the caret.
+    */
+    if (paintAction == PaintActionForeground) {
+        const KHTMLSelection &s = document()->part()->getKHTMLSelection();
+        NodeImpl *baseNode = s.baseNode();
+        RenderObject *renderer = baseNode ? baseNode->renderer() : 0;
+        if (renderer && renderer->containingBlock() == this && baseNode->isContentEditable()) {
+            s.paint(p, QRect(_x, _y, _w, _h));
+        }
+    }
+    
+
 #ifdef BOX_DEBUG
     if ( style() && style()->visibility() == VISIBLE ) {
         if(isAnonymous())
diff --git a/WebCore/khtml/rendering/render_box.cpp b/WebCore/khtml/rendering/render_box.cpp
index 2ebe153..2f2687d 100644
--- a/WebCore/khtml/rendering/render_box.cpp
+++ b/WebCore/khtml/rendering/render_box.cpp
@@ -36,6 +36,7 @@
 #include "misc/htmlhashes.h"
 #include "xml/dom_nodeimpl.h"
 #include "xml/dom_docimpl.h"
+#include "render_line.h"
 
 #include <khtmlview.h>
 #include <kdebug.h>
@@ -1371,6 +1372,42 @@ void RenderBox::calcAbsoluteVertical()
 
 }
 
+void RenderBox::caretPos(int offset, bool override, int &_x, int &_y, int &width, int &height)
+{
+    _x = -1;
+    
+    // propagate it downwards to its children, someone will feel responsible
+    RenderObject *child = firstChild();
+    if (child) 
+        child->caretPos(offset, override, _x, _y, width, height);
+    
+    // if not, use the extents of this box 
+    // offset 0 means left, offset 1 means right
+    if (_x == -1) {
+        _x = xPos() + (offset == 0 ? 0 : m_width);
+        _y = yPos();
+        height = m_height;
+        width = override && offset == 0 ? m_width : 1;
+        // If height of box is smaller than font height, use the latter one,
+        // otherwise the caret might become invisible.
+        // FIXME: ignoring :first-line, missing good reason to take care of
+        int fontHeight = style()->fontMetrics().height();
+        if (fontHeight > height)
+            height = fontHeight;
+        
+        int absx, absy;
+        RenderObject *cb = containingBlock();
+        if (cb && cb != this && cb->absolutePosition(absx,absy)) {
+            _x += absx;
+            _y += absy;
+        } 
+        else {
+            // we don't know our absolute position, and there is no point returning
+            // just a relative one
+            _x = _y = -1;
+        }
+    }
+}
 
 int RenderBox::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
 {
diff --git a/WebCore/khtml/rendering/render_box.h b/WebCore/khtml/rendering/render_box.h
index 0edc97a..2725bb1 100644
--- a/WebCore/khtml/rendering/render_box.h
+++ b/WebCore/khtml/rendering/render_box.h
@@ -115,6 +115,8 @@ public:
     void relativePositionOffset(int &tx, int &ty);
 
     virtual RenderLayer* layer() const { return m_layer; }
+    
+    virtual void caretPos(int offset, bool override, int &_x, int &_y, int &width, int &height);
 
     virtual void paintBackgroundExtended(QPainter *p, const QColor &c, CachedImage *bg, int clipy, int cliph,
                                          int _tx, int _ty, int w, int height,
diff --git a/WebCore/khtml/rendering/render_br.cpp b/WebCore/khtml/rendering/render_br.cpp
index 901c921..f7c2e95 100644
--- a/WebCore/khtml/rendering/render_br.cpp
+++ b/WebCore/khtml/rendering/render_br.cpp
@@ -33,31 +33,6 @@ RenderBR::~RenderBR()
 {
 }
 
-void RenderBR::cursorPos(int /*offset*/, int &_x, int &_y, int &height)
-{
-    if (previousSibling() && !previousSibling()->isBR() && !previousSibling()->isFloating()) {
-        int offset = 0;
-        if (previousSibling()->isText())
-            offset = static_cast<RenderText*>(previousSibling())->length();
-
-        previousSibling()->cursorPos(offset,_x,_y,height);
-        return;
-    }
-
-    int absx, absy;
-    absolutePosition(absx,absy);
-    if (absx == -1) {
-        // we don't know our absolute position, and there is no point returning just a relative one
-        _x = _y = -1;
-    }
-    else {
-        _x += absx;
-        _y += absy;
-    }
-    height = RenderText::verticalPositionHint( false );
-
-}
-
 FindSelectionResult RenderBR::checkSelectionPointIgnoringContinuations(int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int &offset)
 {
     FindSelectionResult result = RenderText::checkSelectionPointIgnoringContinuations(_x, _y, _tx, _ty, node, offset);
@@ -73,3 +48,12 @@ FindSelectionResult RenderBR::checkSelectionPointIgnoringContinuations(int _x, i
     return result;
 }
 
+long RenderBR::caretMinOffset() const 
+{ 
+    return 0; 
+}
+
+long RenderBR::caretMaxOffset() const 
+{ 
+    return 0; 
+}
diff --git a/WebCore/khtml/rendering/render_br.h b/WebCore/khtml/rendering/render_br.h
index 2874229..43ea1c7 100644
--- a/WebCore/khtml/rendering/render_br.h
+++ b/WebCore/khtml/rendering/render_br.h
@@ -53,8 +53,10 @@ public:
     virtual short maxWidth() const { return 0; }
 
     virtual bool isBR() const { return true; }
-    virtual void cursorPos(int offset, int &_x, int &_y, int &height);
 
+    virtual long caretMinOffset() const;
+    virtual long caretMaxOffset() const;
+    
     virtual FindSelectionResult checkSelectionPointIgnoringContinuations(int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int &offset);
 };
 
diff --git a/WebCore/khtml/rendering/render_flow.cpp b/WebCore/khtml/rendering/render_flow.cpp
index 1e29520..f478f51 100644
--- a/WebCore/khtml/rendering/render_flow.cpp
+++ b/WebCore/khtml/rendering/render_flow.cpp
@@ -342,3 +342,50 @@ int RenderFlow::leftmostPosition(bool includeOverflowInterior, bool includeSelf)
     return left;
 }
 
+void RenderFlow::caretPos(int offset, bool override, int &_x, int &_y, int &width, int &height)
+{
+    if (firstChild() || style()->display() == INLINE) { 
+        // Do the normal calculation
+        RenderBox::caretPos(offset, override, _x, _y, width, height);
+        return;
+    }
+
+    // This is a special case:
+    // The element is not an inline element, and it's empty. So we have to
+    // calculate a fake position to indicate where objects are to be inserted.
+    
+    // EDIT FIXME: this does neither take into regard :first-line nor :first-letter
+    // However, as soon as some content is entered, the line boxes will be
+    // constructed properly and this kludge is not called any more. So only
+    // the caret size of an empty :first-line'd block is wrong, but I think we
+    // can live with that.
+    RenderStyle *currentStyle = style(true);
+    height = currentStyle->fontMetrics().height();
+    width = 1;
+
+    // EDIT FIXME: This needs to account for text direction
+    int w = this->width();
+    switch (currentStyle->textAlign()) {
+        case LEFT:
+        case KHTML_LEFT:
+        case TAAUTO:
+        case JUSTIFY:
+            _x = 0;
+            break;
+        case CENTER:
+        case KHTML_CENTER:
+            _x = w / 2;
+        break;
+        case RIGHT:
+        case KHTML_RIGHT:
+            _x = w;
+        break;
+    }
+    
+    _y = 0;
+    
+    int absx, absy;
+    absolutePosition(absx, absy, false);
+    _x += absx;
+    _y += absy;
+}
diff --git a/WebCore/khtml/rendering/render_flow.h b/WebCore/khtml/rendering/render_flow.h
index 31265be..e96c718 100644
--- a/WebCore/khtml/rendering/render_flow.h
+++ b/WebCore/khtml/rendering/render_flow.h
@@ -75,6 +75,8 @@ public:
     virtual int rightmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
     virtual int leftmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
     
+    virtual void caretPos(int offset, bool override, int &_x, int &_y, int &width, int &height);
+
 protected:
     // An inline can be split with blocks occurring in between the inline content.
     // When this occurs we need a pointer to our next object.  We can basically be
diff --git a/WebCore/khtml/rendering/render_line.cpp b/WebCore/khtml/rendering/render_line.cpp
index 35b70af..3fa5585 100644
--- a/WebCore/khtml/rendering/render_line.cpp
+++ b/WebCore/khtml/rendering/render_line.cpp
@@ -74,6 +74,16 @@ void InlineBox::operator delete(void* ptr, size_t sz)
     *(size_t *)ptr = sz;
 }
 
+long InlineBox::caretMinOffset() const 
+{ 
+    return 0; 
+}
+
+long InlineBox::caretMaxOffset() const 
+{ 
+    return 1; 
+}
+
 int InlineFlowBox::marginLeft()
 {
     if (!includeLeftEdge())
diff --git a/WebCore/khtml/rendering/render_line.h b/WebCore/khtml/rendering/render_line.h
index 73cc7b7..dedfc85 100644
--- a/WebCore/khtml/rendering/render_line.h
+++ b/WebCore/khtml/rendering/render_line.h
@@ -22,6 +22,8 @@
 #ifndef RENDER_LINE_H
 #define RENDER_LINE_H
 
+#include "rendering/render_object.h"
+
 namespace khtml {
 
 class InlineFlowBox;
@@ -96,6 +98,9 @@ public:
 
     virtual int topOverflow() { return yPos(); }
     virtual int bottomOverflow() { return yPos()+height(); }
+
+    virtual long caretMinOffset() const;
+    virtual long caretMaxOffset() const;
     
 public: // FIXME: Would like to make this protected, but methods are accessing these
         // members over in the part.
diff --git a/WebCore/khtml/rendering/render_object.cpp b/WebCore/khtml/rendering/render_object.cpp
index 130eee2..4fa076b 100644
--- a/WebCore/khtml/rendering/render_object.cpp
+++ b/WebCore/khtml/rendering/render_object.cpp
@@ -25,6 +25,7 @@
 
 #include "rendering/render_object.h"
 #include "rendering/render_table.h"
+#include "rendering/render_text.h"
 #include "rendering/render_list.h"
 #include "rendering/render_canvas.h"
 #include "xml/dom_elementimpl.h"
@@ -221,6 +222,144 @@ void RenderObject::insertChildNode(RenderObject*, RenderObject*)
     KHTMLAssert(0);
 }
 
+RenderObject *RenderObject::nextRenderer() const
+{
+    if (firstChild())
+        return firstChild();
+    else if (nextSibling())
+        return nextSibling();
+    else {
+        const RenderObject *r = this;
+        while (r && !r->nextSibling())
+            r = r->parent();
+        if (r)
+            return r->nextSibling();
+    }
+    return 0;
+}
+
+RenderObject *RenderObject::previousRenderer() const
+{
+    if (previousSibling()) {
+        RenderObject *r = previousSibling();
+        while (r->lastChild())
+            r = r->lastChild();
+        return r;
+    }
+    else if (parent()) {
+        return parent();
+    }
+    else {
+        return 0;
+    }
+}
+
+bool RenderObject::isEditable() const
+{
+    RenderText *textRenderer = 0;
+    if (isText()) {
+        textRenderer = static_cast<RenderText *>(const_cast<RenderObject *>(this));
+    }
+
+    return style()->visibility() == VISIBLE && 
+        element() && element()->isContentEditable() &&
+        (isReplaced() || (textRenderer && textRenderer->inlineTextBoxes().count() > 0));
+}
+
+RenderObject *RenderObject::nextEditable() const
+{
+    RenderObject *r = const_cast<RenderObject *>(this);
+    RenderObject *n = firstChild();
+    if (n) {
+        while (n) { 
+            r = n; 
+            n = n->firstChild(); 
+        }
+        if (r->isEditable())
+            return r;
+        else 
+            return r->nextEditable();
+    }
+    n = r->nextSibling();
+    if (n) {
+        r = n;
+        while (n) { 
+            r = n; 
+            n = n->firstChild(); 
+        }
+        if (r->isEditable())
+            return r;
+        else 
+            return r->nextEditable();
+    }
+    n = r->parent();
+    while (n) {
+        r = n;
+        n = r->nextSibling();
+        if (n) {
+            r = n;
+            n = r->firstChild();
+            while (n) { 
+                r = n; 
+                n = n->firstChild(); 
+            }
+            if (r->isEditable())
+                return r;
+            else 
+                return r->nextEditable();
+        }
+        n = r->parent();
+    }
+    return 0;
+}
+
+RenderObject *RenderObject::previousEditable() const
+{
+    RenderObject *r = const_cast<RenderObject *>(this);
+    RenderObject *n = firstChild();
+    if (n) {
+        while (n) { 
+            r = n; 
+            n = n->lastChild(); 
+        }
+        if (r->isEditable())
+            return r;
+        else 
+            return r->previousEditable();
+    }
+    n = r->previousSibling();
+    if (n) {
+        r = n;
+        while (n) { 
+            r = n; 
+            n = n->lastChild(); 
+        }
+        if (r->isEditable())
+            return r;
+        else 
+            return r->previousEditable();
+    }    
+    n = r->parent();
+    while (n) {
+        r = n;
+        n = r->previousSibling();
+        if (n) {
+            r = n;
+            n = r->lastChild();
+            while (n) { 
+                r = n; 
+                n = n->lastChild(); 
+            }
+            if (r->isEditable())
+                return r;
+            else 
+                return r->previousEditable();
+        }
+        n = r->parent();
+    }
+    return 0;
+} 
+
 static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*& newObject,
                       RenderLayer*& beforeChild)
 {
@@ -1384,9 +1523,11 @@ bool RenderObject::absolutePosition(int &xPos, int &yPos, bool f)
     }
 }
 
-void RenderObject::cursorPos(int /*offset*/, int &_x, int &_y, int &height)
+void RenderObject::caretPos(int /*offset*/, bool /*override*/, int &_x, int &_y, int &width, int &height)
 {
     _x = _y = height = -1;
+    width = 1;	// the caret has a default width of one pixel. If you want
+    		// to check for validity, only test the x-coordinate for >= 0.
 }
 
 int RenderObject::paddingTop() const
diff --git a/WebCore/khtml/rendering/render_object.h b/WebCore/khtml/rendering/render_object.h
index 021b11d..a9c05cf 100644
--- a/WebCore/khtml/rendering/render_object.h
+++ b/WebCore/khtml/rendering/render_object.h
@@ -123,6 +123,12 @@ public:
     virtual RenderObject *firstChild() const { return 0; }
     virtual RenderObject *lastChild() const { return 0; }
 
+    RenderObject *nextRenderer() const; 
+    RenderObject *previousRenderer() const; 
+
+    RenderObject *nextEditable() const; 
+    RenderObject *previousEditable() const; 
+    
     virtual RenderLayer* layer() const { return 0; }
     RenderLayer* enclosingLayer();
     void addLayers(RenderLayer* parentLayer, RenderObject* newObject);
@@ -236,6 +242,8 @@ public:
     virtual bool isTextArea() const { return false; }
     virtual bool isFrameSet() const { return false; }
     virtual bool isApplet() const { return false; }
+    
+    virtual bool isEditable() const;
 
     bool isHTMLMarquee() const;
     
@@ -655,7 +663,17 @@ public:
     virtual SelectionState selectionState() const { return SelectionNone;}
     virtual void setSelectionState(SelectionState) {}
 
-    virtual void cursorPos(int /*offset*/, int &/*_x*/, int &/*_y*/, int &/*height*/);
+    /**
+     * Returns the content coordinates of the caret within this render object.
+     * @param offset zero-based offset determining position within the render object.
+     * @param override @p true if input overrides existing characters,
+     * @p false if it inserts them. The width of the caret depends on this one.
+     * @param _x returns the left coordinate
+     * @param _y returns the top coordinate
+     * @param width returns the caret's width
+     * @param height returns the caret's height
+     */
+    virtual void caretPos(int offset, bool override, int &_x, int &_y, int &width, int &height);
 
     virtual int lowestPosition(bool includeOverflowInterior=true, bool includeSelf=true) const { return 0; }
     virtual int rightmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const { return 0; }
@@ -682,6 +700,9 @@ public:
     // Convenience, to avoid repeating the code to dig down to get this.
     QChar backslashAsCurrencySymbol() const;
 
+    virtual long caretMinOffset() const { return 0; }
+    virtual long caretMaxOffset() const { return 0; }
+
     virtual void setPixmap(const QPixmap&, const QRect&, CachedImage *);
 
 protected:
diff --git a/WebCore/khtml/rendering/render_replaced.cpp b/WebCore/khtml/rendering/render_replaced.cpp
index 0cb6935..deb63b8 100644
--- a/WebCore/khtml/rendering/render_replaced.cpp
+++ b/WebCore/khtml/rendering/render_replaced.cpp
@@ -113,6 +113,18 @@ bool RenderReplaced::canHaveChildren() const
     return false;
 }
 
+long RenderReplaced::caretMinOffset() const 
+{ 
+    return 0; 
+}
+
+// Returns 1 since a replaced element can have the caret positioned 
+// at its beginning (0), or at its end (1).
+long RenderReplaced::caretMaxOffset() const 
+{ 
+    return 1; 
+}
+
 // -----------------------------------------------------------------------------
 
 RenderWidget::RenderWidget(DOM::NodeImpl* node)
diff --git a/WebCore/khtml/rendering/render_replaced.h b/WebCore/khtml/rendering/render_replaced.h
index 1562c98..b2217ee 100644
--- a/WebCore/khtml/rendering/render_replaced.h
+++ b/WebCore/khtml/rendering/render_replaced.h
@@ -54,6 +54,9 @@ public:
 
     virtual bool canHaveChildren() const;
 
+    virtual long caretMinOffset() const;
+    virtual long caretMaxOffset() const;
+
 private:
     short m_intrinsicWidth;
     short m_intrinsicHeight;
diff --git a/WebCore/khtml/rendering/render_style.cpp b/WebCore/khtml/rendering/render_style.cpp
index fcd8bcb..80be39a 100644
--- a/WebCore/khtml/rendering/render_style.cpp
+++ b/WebCore/khtml/rendering/render_style.cpp
@@ -224,7 +224,7 @@ bool StyleCSS3NonInheritedData::operator==(const StyleCSS3NonInheritedData& o) c
 }
 
 StyleCSS3InheritedData::StyleCSS3InheritedData()
-:Shared<StyleCSS3InheritedData>(), textShadow(0)
+:Shared<StyleCSS3InheritedData>(), textShadow(0), userModify(READ_ONLY)
 {
 
 }
@@ -233,6 +233,7 @@ StyleCSS3InheritedData::StyleCSS3InheritedData(const StyleCSS3InheritedData& o)
 :Shared<StyleCSS3InheritedData>()
 {
     textShadow = o.textShadow ? new ShadowData(*o.textShadow) : 0;
+    userModify = o.userModify;
 }
 
 StyleCSS3InheritedData::~StyleCSS3InheritedData()
@@ -247,6 +248,8 @@ bool StyleCSS3InheritedData::operator==(const StyleCSS3InheritedData& o) const
 
 bool StyleCSS3InheritedData::shadowDataEquivalent(const StyleCSS3InheritedData& o) const
 {
+    if (userModify != o.userModify)
+        return false;
     if (!textShadow && o.textShadow || textShadow && !o.textShadow)
         return false;
     if (textShadow && o.textShadow && (*textShadow != *o.textShadow))
@@ -615,6 +618,7 @@ RenderStyle::Diff RenderStyle::diff( const RenderStyle *other ) const
         visual->textDecoration != other->visual->textDecoration ||
         css3NonInheritedData->opacity != other->css3NonInheritedData->opacity ||
         !css3InheritedData->shadowDataEquivalent(*other->css3InheritedData.get()) ||
+        css3InheritedData->userModify != other->css3InheritedData->userModify ||
         !(visual->palette == other->visual->palette)
 	)
         return Visible;
diff --git a/WebCore/khtml/rendering/render_style.h b/WebCore/khtml/rendering/render_style.h
index 415ce6a..9bc4c5a 100644
--- a/WebCore/khtml/rendering/render_style.h
+++ b/WebCore/khtml/rendering/render_style.h
@@ -517,6 +517,13 @@ struct BindingURI {
 };
 #endif
 
+//------------------------------------------------
+// CSS3 User Modify Properties
+
+enum EUserModify {
+    READ_ONLY, READ_WRITE
+};
+
 // This struct is for rarely used non-inherited CSS3 properties.  By grouping them together,
 // we save space, and only allocate this object when someone actually uses
 // a non-inherited CSS3 property.
@@ -546,7 +553,7 @@ public:
 
 // This struct is for rarely used inherited CSS3 properties.  By grouping them together,
 // we save space, and only allocate this object when someone actually uses
-// a non-inherited CSS3 property.
+// an inherited CSS3 property.
 class StyleCSS3InheritedData : public Shared<StyleCSS3InheritedData>
 {
 public:
@@ -561,6 +568,7 @@ public:
     bool shadowDataEquivalent(const StyleCSS3InheritedData& o) const;
 
     ShadowData* textShadow;  // Our text shadow information for shadowed text drawing.
+    EUserModify userModify : 2; // Flag used for editing state
 
 private:
     StyleCSS3InheritedData &operator=(const StyleCSS3InheritedData &);
@@ -1048,6 +1056,7 @@ public:
     int marqueeLoopCount() { return css3NonInheritedData->marquee->loops; }
     EMarqueeBehavior marqueeBehavior() { return css3NonInheritedData->marquee->behavior; }
     EMarqueeDirection marqueeDirection() { return css3NonInheritedData->marquee->direction; }
+    EUserModify userModify() const { return css3InheritedData->userModify; }
     // End CSS3 Getters
 
 // attribute setter methods
@@ -1219,6 +1228,7 @@ public:
     void setMarqueeDirection(EMarqueeDirection d) { SET_VAR(css3NonInheritedData.access()->marquee, direction, d); }
     void setMarqueeBehavior(EMarqueeBehavior b) { SET_VAR(css3NonInheritedData.access()->marquee, behavior, b); }
     void setMarqueeLoopCount(int i) { SET_VAR(css3NonInheritedData.access()->marquee, loops, i); }
+    void setUserModify(EUserModify u) { SET_VAR(css3InheritedData, userModify, u); }
     // End CSS3 Setters
     
     QPalette palette() const { return visual->palette; }
@@ -1306,6 +1316,7 @@ public:
     static Length initialMarqueeIncrement() { return Length(6, Fixed); }
     static EMarqueeBehavior initialMarqueeBehavior() { return MSCROLL; }
     static EMarqueeDirection initialMarqueeDirection() { return MAUTO; }
+    static EUserModify initialUserModify() { return READ_ONLY; }
 };
 
 
diff --git a/WebCore/khtml/rendering/render_text.cpp b/WebCore/khtml/rendering/render_text.cpp
index bd45704..101d72e 100644
--- a/WebCore/khtml/rendering/render_text.cpp
+++ b/WebCore/khtml/rendering/render_text.cpp
@@ -163,6 +163,16 @@ void InlineTextBox::paintDecoration( QPainter *pt, int _tx, int _ty, int decorat
 }
 #endif
 
+long InlineTextBox::caretMinOffset() const
+{
+    return m_start;
+}
+
+long InlineTextBox::caretMaxOffset() const
+{
+    return m_start + m_len;
+}
+
 #define LOCAL_WIDTH_BUF_SIZE	1024
 
 FindSelectionResult InlineTextBox::checkSelectionPoint(int _x, int _y, int _tx, int _ty, const Font *f, RenderText *text, int & offset, short lineHeight)
@@ -487,7 +497,7 @@ FindSelectionResult RenderText::checkSelectionPointIgnoringContinuations(int _x,
     return SelectionPointAfter;
 }
 
-void RenderText::cursorPos(int offset, int &_x, int &_y, int &height)
+void RenderText::caretPos(int offset, bool override, int &_x, int &_y, int &width, int &height)
 {
   if (!m_lines.count()) {
     _x = _y = height = -1;
@@ -502,9 +512,11 @@ void RenderText::cursorPos(int offset, int &_x, int &_y, int &height)
   const QFontMetrics &fm = metrics( s->m_firstLine );
   QString tekst(str->s + s->m_start, s->m_len);
   _x = s->m_x + (fm.boundingRect(tekst, pos)).right();
+#if 0
+  // EDIT FIXME
   if(pos)
       _x += fm.rightBearing( *(str->s + s->m_start + pos - 1 ) );
-
+#endif
   int absx, absy;
   absolutePosition(absx,absy);
   _x += absx;
@@ -1210,7 +1222,7 @@ void RenderText::setText(DOMStringImpl *text, bool force)
     KHTMLAssert(!isBR() || (str->l == 1 && (*str->s) == '\n'));
     KHTMLAssert(!str->l || str->s);
 
-    setNeedsLayout(true);
+    setNeedsLayoutAndMinMaxRecalc();
     
 #ifdef BIDI_DEBUG
     QConstString cstr(str->s, str->l);
@@ -1351,6 +1363,57 @@ const Font *RenderText::htmlFont(bool firstLine) const
     return &style(firstLine)->htmlFont();
 }
 
+long RenderText::caretMinOffset() const
+{
+    if (!m_lines.count()) 
+        return 0;
+    // EDIT FIXME: it is *not* guaranteed that the first run contains the lowest offset
+    // Either make this a linear search (slow),
+    // or maintain an index (needs much mem),
+    // or calculate and store it in bidi.cpp (needs calculation even if not needed)
+    return m_lines[0]->m_start;
+}
+
+long RenderText::caretMaxOffset() const
+{
+    int count = m_lines.count();
+    if (!count) 
+        return str->l;
+    // EDIT FIXME: it is *not* guaranteed that the last run contains the highest offset
+    // Either make this a linear search (slow),
+    // or maintain an index (needs much mem),
+    // or calculate and store it in bidi.cpp (needs calculation even if not needed)
+    return m_lines[count - 1]->m_start + m_lines[count - 1]->m_len;
+}
+
+bool RenderText::precedesLineBreak() const
+{
+    RenderObject *r = nextRenderer();
+    while (r) {
+        if (r->isBR() || r->isRenderBlock())
+            return true;
+        if (r->isText() || r->isReplaced())
+            return false;
+        r = r->nextRenderer();
+    }
+    
+    return false;
+}
+
+bool RenderText::followsLineBreak() const
+{
+    RenderObject *r = previousRenderer();
+    while (r) {
+        if (r->isBR() || r->isRenderBlock())
+            return true;
+        if (r->isText() || r->isReplaced())
+            return false;
+        r = r->previousRenderer();
+    }
+    
+    return false;
+}
+
 RenderTextFragment::RenderTextFragment(DOM::NodeImpl* _node, DOM::DOMStringImpl* _str,
                                        int startOffset, int endOffset)
 :RenderText(_node, _str->substring(startOffset, endOffset)), 
diff --git a/WebCore/khtml/rendering/render_text.h b/WebCore/khtml/rendering/render_text.h
index a670086..08c0286 100644
--- a/WebCore/khtml/rendering/render_text.h
+++ b/WebCore/khtml/rendering/render_text.h
@@ -75,6 +75,9 @@ public:
     void paintDecoration( QPainter *pt, int _tx, int _ty, int decoration);
     void paintSelection(const Font *f, RenderText *text, QPainter *p, RenderStyle* style, int tx, int ty, int startPos, int endPos);
 
+    virtual long caretMinOffset() const;
+    virtual long caretMaxOffset() const;
+    
     // Return before, after (offset set to max), or inside the text, at @p offset
     FindSelectionResult checkSelectionPoint(int _x, int _y, int _tx, int _ty, const Font *f, RenderText *text, int & offset, short lineheight);
 
@@ -195,7 +198,7 @@ public:
 
     virtual SelectionState selectionState() const {return m_selectionState;}
     virtual void setSelectionState(SelectionState s) {m_selectionState = s; }
-    virtual void cursorPos(int offset, int &_x, int &_y, int &height);
+    virtual void caretPos(int offset, bool override, int &_x, int &_y, int &width, int &height);
     void posOfChar(int ch, int &x, int &y);
 
     virtual short marginLeft() const { return style()->marginLeft().minWidth(0); }
@@ -219,6 +222,12 @@ public:
     bool allAscii() const;
 #endif
 
+    virtual long caretMinOffset() const;
+    virtual long caretMaxOffset() const;
+    
+    bool precedesLineBreak() const;
+    bool followsLineBreak() const;
+            
 #if APPLE_CHANGES
 public:
 #endif
diff --git a/WebCore/khtml/xml/dom_docimpl.cpp b/WebCore/khtml/xml/dom_docimpl.cpp
index 0c59213..35aa46d 100644
--- a/WebCore/khtml/xml/dom_docimpl.cpp
+++ b/WebCore/khtml/xml/dom_docimpl.cpp
@@ -51,6 +51,7 @@
 
 #include "khtmlview.h"
 #include "khtml_part.h"
+#include "khtml_selection.h"
 
 #include <kglobalsettings.h>
 #include <kstringhandler.h>
@@ -79,6 +80,7 @@ using XBL::XBLBindingManager;
 
 #if APPLE_CHANGES
 #include "KWQAccObjectCache.h"
+#include "KWQLogging.h"
 #endif
 
 using namespace DOM;
@@ -953,10 +955,9 @@ NodeIteratorImpl *DocumentImpl::createNodeIterator(NodeImpl *root, unsigned long
     return new NodeIteratorImpl(root,whatToShow,filter,entityReferenceExpansion);
 }
 
-TreeWalkerImpl *DocumentImpl::createTreeWalker(Node /*root*/, unsigned long /*whatToShow*/, NodeFilter &/*filter*/,
-                                bool /*entityReferenceExpansion*/)
+TreeWalkerImpl *DocumentImpl::createTreeWalker(const Node &root, unsigned long whatToShow, const NodeFilter &filter,
+                                bool entityReferenceExpansion)
 {
-    // ###
     return new TreeWalkerImpl;
 }
 
@@ -1190,6 +1191,15 @@ void DocumentImpl::setSelection(NodeImpl* s, int sp, NodeImpl* e, int ep)
         static_cast<RenderCanvas*>(m_render)->setSelection(s->renderer(),sp,e->renderer(),ep);
 }
 
+void DocumentImpl::setSelection(KHTMLSelection &s)
+{
+    if (m_render) {
+        RenderObject *startRenderer = s.startNode() ? s.startNode()->renderer() : 0;
+        RenderObject *endRenderer = s.endNode() ? s.endNode()->renderer() : 0;
+        static_cast<RenderCanvas*>(m_render)->setSelection(startRenderer, s.startOffset(), endRenderer, s.endOffset());
+    }
+}
+
 void DocumentImpl::clearSelection()
 {
     if ( m_render )
diff --git a/WebCore/khtml/xml/dom_docimpl.h b/WebCore/khtml/xml/dom_docimpl.h
index 3836a25..488b88d 100644
--- a/WebCore/khtml/xml/dom_docimpl.h
+++ b/WebCore/khtml/xml/dom_docimpl.h
@@ -43,10 +43,13 @@
 #include "decoder.h"
 #endif
 
+#include "htmlediting.h"
+
 class QPaintDevice;
 class QPaintDeviceMetrics;
 class KHTMLView;
 class KHTMLPart;
+class KHTMLSelection;
 class Tokenizer;
 class XMLHandler;
 class RenderArena;
@@ -60,6 +63,7 @@ namespace khtml {
     class DocLoader;
     class CSSStyleSelectorList;
     class RenderImage;
+    class EditCommand;
 }
 
 #ifndef KHTML_NO_XBL
@@ -237,7 +241,7 @@ public:
     NodeIteratorImpl *createNodeIterator(NodeImpl *root, unsigned long whatToShow,
                                     NodeFilter &filter, bool entityReferenceExpansion, int &exceptioncode);
 
-    TreeWalkerImpl *createTreeWalker(Node root, unsigned long whatToShow, NodeFilter &filter,
+    TreeWalkerImpl *createTreeWalker(const Node &root, unsigned long whatToShow, const NodeFilter &filter,
                             bool entityReferenceExpansion);
 
     virtual void recalcStyle( StyleChange = NoChange );
@@ -261,6 +265,7 @@ public:
     void setVisuallyOrdered();
 
     void setSelection(NodeImpl* s, int sp, NodeImpl* e, int ep);
+    void setSelection(KHTMLSelection &);
     void clearSelection();
 
     void open();
@@ -414,7 +419,7 @@ public:
     bool hasWindowEventListener(int id);
 
     EventListener *createHTMLEventListener(QString code);
-
+    
     /**
      * Searches through the document, starting from fromNode, for the next selectable element that comes after fromNode.
      * The order followed is as specified in section 17.11.1 of the HTML4 spec, which is elements with tab indexes
diff --git a/WebCore/khtml/xml/dom_elementimpl.cpp b/WebCore/khtml/xml/dom_elementimpl.cpp
index 563153e..22b3a9a 100644
--- a/WebCore/khtml/xml/dom_elementimpl.cpp
+++ b/WebCore/khtml/xml/dom_elementimpl.cpp
@@ -30,6 +30,9 @@
 #include "xml/dom2_eventsimpl.h"
 #include "xml/dom_elementimpl.h"
 
+#include "khtml_part.h"
+#include "khtml_selection.h"
+
 #include "html/dtd.h"
 #include "html/htmlparser.h"
 
@@ -354,6 +357,46 @@ void ElementImpl::createAttributeMap() const
     namedAttrMap->ref();
 }
 
+void ElementImpl::defaultEventHandler(EventImpl *evt)
+{
+    if (evt->id() == EventImpl::KEYPRESS_EVENT && isContentEditable()) {
+        KeyboardEventImpl *k = static_cast<KeyboardEventImpl *>(evt);
+        EditCommand *cmd = 0;
+        if (k->keyIdentifier() == "U+00007F" || 
+            k->keyIdentifier() == "U+000008" || 
+            k->keyIdentifier() == "ForwardDelete") {
+            cmd = new DeleteTextCommand(getDocument());
+        }
+        else if (k->keyIdentifier() == "Right") {
+            KHTMLPart *part = getDocument()->part();
+            if (part) {
+                part->getKHTMLSelection().alterSelection(KHTMLSelection::MOVE, KHTMLSelection::FORWARD, KHTMLSelection::CHARACTER);
+                evt->setDefaultHandled();
+            }
+        }
+        else if (k->keyIdentifier() == "Left") {
+            // EDIT FIXME: unimplemented
+        }
+        else if (k->keyIdentifier() == "Up") {
+            // EDIT FIXME: unimplemented
+        }
+        else if (k->keyIdentifier() == "Down") {
+            // EDIT FIXME: unimplemented
+        }
+        else {
+            QString text(k->qKeyEvent()->text());
+            cmd = new InputTextCommand(getDocument(), text);
+        }
+        if (cmd && cmd->apply()) {
+            evt->setDefaultHandled();
+            // EDIT FIXME: until undo is hooked up, the command has no place to go
+            // just delete
+            delete cmd;
+        }
+    }
+    NodeBaseImpl::defaultEventHandler(evt);
+}
+
 NamedAttrMapImpl* ElementImpl::defaultMap() const
 {
     return 0;
diff --git a/WebCore/khtml/xml/dom_elementimpl.h b/WebCore/khtml/xml/dom_elementimpl.h
index 9ef4c67..3d0d21e 100644
--- a/WebCore/khtml/xml/dom_elementimpl.h
+++ b/WebCore/khtml/xml/dom_elementimpl.h
@@ -220,6 +220,8 @@ public:
 
     virtual DOMString toString() const;
 
+    virtual void defaultEventHandler(EventImpl *evt);
+
 #ifndef NDEBUG
     virtual void dump(QTextStream *stream, QString ind = "") const;
 #endif
diff --git a/WebCore/khtml/xml/dom_nodeimpl.cpp b/WebCore/khtml/xml/dom_nodeimpl.cpp
index 764d408..7972eed 100644
--- a/WebCore/khtml/xml/dom_nodeimpl.cpp
+++ b/WebCore/khtml/xml/dom_nodeimpl.cpp
@@ -171,6 +171,17 @@ NodeImpl *NodeImpl::appendChild( NodeImpl *, int &exceptioncode )
   return 0;
 }
 
+void NodeImpl::remove(int &exceptioncode)
+{
+    exceptioncode = 0;
+    if (!parentNode()) {
+        exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
+        return;
+    }
+    
+    parentNode()->removeChild(this, exceptioncode);
+}
+
 bool NodeImpl::hasChildNodes(  ) const
 {
   return false;
@@ -451,10 +462,9 @@ QString NodeImpl::recursive_toHTML(bool start) const
     return me;
 }
 
-void NodeImpl::getCursor(int offset, int &_x, int &_y, int &height)
+bool NodeImpl::isContentEditable() const
 {
-    if(m_render) m_render->cursorPos(offset, _x, _y, height);
-    else _x = _y = height = -1;
+    return m_parent ? m_parent->isContentEditable() : false;
 }
 
 QRect NodeImpl::getRect() const
@@ -1231,6 +1241,82 @@ RenderObject * NodeImpl::nextRenderer()
     return 0;
 }
 
+NodeImpl *NodeImpl::previousLeafNode() const
+{
+    const NodeImpl *r = this;
+    const NodeImpl *n = lastChild();
+    if (n) {
+        while (n) { 
+            r = n; 
+            n = n->lastChild(); 
+        }
+        return const_cast<NodeImpl *>(r);
+    }
+    n = r->previousSibling();
+    if (n) {
+        r = n;
+        while (n) { 
+            r = n; 
+            n = n->lastChild(); 
+        }
+        return const_cast<NodeImpl *>(r);
+    }    
+    n = r->parentNode();
+    while (n) {
+        r = n;
+        n = r->previousSibling();
+        if (n) {
+            r = n;
+            n = r->lastChild();
+            while (n) { 
+                r = n; 
+                n = n->lastChild(); 
+            }
+            return const_cast<NodeImpl *>(r);
+        }
+        n = r->parentNode();
+    }
+    return 0;
+}
+
+NodeImpl *NodeImpl::nextLeafNode() const
+{
+    const NodeImpl *r = this;
+    const NodeImpl *n = firstChild();
+    if (n) {
+        while (n) { 
+            r = n; 
+            n = n->firstChild(); 
+        }
+        return const_cast<NodeImpl *>(r);
+    }
+    n = r->nextSibling();
+    if (n) {
+        r = n;
+        while (n) { 
+            r = n; 
+            n = n->firstChild(); 
+        }
+        return const_cast<NodeImpl *>(r);
+    }
+    n = r->parentNode();
+    while (n) {
+        r = n;
+        n = r->nextSibling();
+        if (n) {
+            r = n;
+            n = r->firstChild();
+            while (n) { 
+                r = n; 
+                n = n->firstChild(); 
+            }
+            return const_cast<NodeImpl *>(r);
+        }
+        n = r->parentNode();
+    }
+    return 0;
+}
+
 void NodeImpl::createRendererIfNeeded()
 {
 #if APPLE_CHANGES
@@ -1283,6 +1369,16 @@ RenderObject *NodeImpl::createRenderer(RenderArena *arena, RenderStyle *style)
     return 0;
 }
 
+long NodeImpl::caretMinOffset() const
+{
+    return renderer() ? renderer()->caretMinOffset() : 0;
+}
+
+long NodeImpl::caretMaxOffset() const
+{
+    return renderer() ? renderer()->caretMaxOffset() : 1;
+}
+
 //-------------------------------------------------------------------------
 
 NodeBaseImpl::NodeBaseImpl(DocumentPtr *doc)
diff --git a/WebCore/khtml/xml/dom_nodeimpl.h b/WebCore/khtml/xml/dom_nodeimpl.h
index a4475a2..06b1740 100644
--- a/WebCore/khtml/xml/dom_nodeimpl.h
+++ b/WebCore/khtml/xml/dom_nodeimpl.h
@@ -94,6 +94,7 @@ public:
     virtual NodeImpl *replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode );
     virtual NodeImpl *removeChild ( NodeImpl *oldChild, int &exceptioncode );
     virtual NodeImpl *appendChild ( NodeImpl *newChild, int &exceptioncode );
+    virtual void remove(int &exceptioncode);
     virtual bool hasChildNodes (  ) const;
     virtual NodeImpl *cloneNode ( bool deep ) = 0;
     virtual DOMString localName() const;
@@ -124,6 +125,24 @@ public:
     virtual void setFirstChild(NodeImpl *child);
     virtual void setLastChild(NodeImpl *child);
 
+    /** (Not part of the official DOM)
+     * Returns the next leaf node.
+     *
+     * Using this function delivers leaf nodes as if the whole DOM tree
+     * were a linear chain of its leaf nodes.
+     * @return next leaf node or 0 if there are no more.
+     */
+    NodeImpl *nextLeafNode() const;
+
+    /** (Not part of the official DOM)
+     * Returns the previous leaf node.
+     *
+     * Using this function delivers leaf nodes as if the whole DOM tree
+     * were a linear chain of its leaf nodes.
+     * @return previous leaf node or 0 if there are no more.
+     */
+    NodeImpl *previousLeafNode() const;
+
     // used by the parser. Doesn't do as many error checkings as
     // appendChild(), and returns the node into which will be parsed next.
     virtual NodeImpl *addChild(NodeImpl *newChild);
@@ -212,7 +231,7 @@ public:
     QString recursive_toHTML(bool start = false) const;
 	QString recursive_toHTMLWithRange(bool start, const DOM::Range &range) const;
 
-    virtual void getCursor(int offset, int &_x, int &_y, int &height);
+    virtual bool isContentEditable() const;
     virtual QRect getRect() const;
 
     enum StyleChange { NoChange, NoInherit, Inherit, Detach, Force };
@@ -290,6 +309,10 @@ public:
     void checkAddChild(NodeImpl *newChild, int &exceptioncode);
     bool isAncestor( NodeImpl *other );
     virtual bool childAllowed( NodeImpl *newChild );
+
+    virtual long caretMinOffset() const;
+    virtual long caretMaxOffset() const;
+
 #ifndef NDEBUG
     virtual void dump(QTextStream *stream, QString ind = "") const;
 #endif
diff --git a/WebCore/khtml/xml/dom_selection.cpp b/WebCore/khtml/xml/dom_selection.cpp
new file mode 100644
index 0000000..e4e9cfa
--- /dev/null
+++ b/WebCore/khtml/xml/dom_selection.cpp
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+  
+#include "khtml_selection.h"
+
+#include "khtml_part.h"
+#include "khtmlview.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qrect.h"
+#include "dom/dom2_range.h"
+#include "dom/dom_node.h"
+#include "dom/dom_position.h"
+#include "dom/dom_string.h"
+#include "rendering/render_object.h"
+#include "rendering/render_style.h"
+#include "rendering/render_text.h"
+#include "xml/dom_docimpl.h"
+#include "xml/dom_nodeimpl.h"
+#include "xml/dom_textimpl.h"
+
+#if APPLE_CHANGES
+#include <KWQAssertions.h>
+#include <CoreServices/CoreServices.h>
+#endif
+
+using DOM::DocumentImpl;
+using DOM::DOMPosition;
+using DOM::DOMString;
+using DOM::Node;
+using DOM::NodeImpl;
+using DOM::Range;
+using DOM::TextImpl;
+using khtml::InlineTextBox;
+using khtml::InlineTextBoxArray;
+using khtml::RenderObject;
+using khtml::RenderText;
+
+enum { CARET_BLINK_FREQUENCY = 500 };
+
+#if APPLE_CHANGES
+static void findWordBoundary(QChar *chars, int len, int position, int *start, int *end);
+static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset);
+static bool lastRunAt(RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset);
+static bool startAndEndLineNodesIncludingNode(DOM::NodeImpl *node, int offset, KHTMLSelection &selection);
+#endif
+
+
+KHTMLSelection::KHTMLSelection() 
+	: QObject(),
+	  m_part(0),
+	  m_baseNode(0), m_baseOffset(0), m_extentNode(0), m_extentOffset(0),
+	  m_startNode(0), m_startOffset(0), m_endNode(0), m_endOffset(0),
+	  m_state(NONE), m_caretBlinkTimer(0),
+      m_baseIsStart(true), m_caretBlinks(true), m_caretPaint(false), 
+      m_visible(false), m_startEndValid(false)
+{
+}
+
+KHTMLSelection::KHTMLSelection(const KHTMLSelection &o)
+	: QObject(),
+	  m_part(o.m_part),
+	  m_baseNode(0), m_baseOffset(0), m_extentNode(0), m_extentOffset(0),
+	  m_startNode(0), m_startOffset(0), m_endNode(0), m_endOffset(0)
+{
+    setBase(o.baseNode(), o.baseOffset());
+    setExtent(o.extentNode(), o.extentOffset());
+    setStart(o.startNode(), o.startOffset());
+    setEnd(o.endNode(), o.endOffset());
+
+	m_state = o.m_state;
+	m_caretBlinkTimer = o.m_caretBlinkTimer;
+	m_baseIsStart = o.m_baseIsStart;
+	m_caretBlinks = o.m_caretBlinks;
+	m_caretPaint = true;
+	m_visible = o.m_visible;
+    m_startEndValid = true;
+}
+
+KHTMLSelection::~KHTMLSelection()
+{
+    if (m_baseNode)
+        m_baseNode->deref();
+    if (m_extentNode)
+        m_extentNode->deref();
+}
+
+KHTMLSelection &KHTMLSelection::operator=(const KHTMLSelection &o)
+{
+    m_part = o.m_part;
+    
+    setBase(o.baseNode(), o.baseOffset());
+    setExtent(o.extentNode(), o.extentOffset());
+    setStart(o.startNode(), o.startOffset());
+    setEnd(o.endNode(), o.endOffset());
+
+	m_state = o.m_state;
+	m_caretBlinkTimer = o.m_caretBlinkTimer;
+	m_baseIsStart = o.m_baseIsStart;
+	m_caretBlinks = o.m_caretBlinks;
+	m_caretPaint = true;
+	m_visible = o.m_visible;
+    m_startEndValid = true;
+    return *this;
+}
+
+void KHTMLSelection::setSelection(DOM::NodeImpl *node, long offset)
+{
+	setBaseNode(node);
+	setExtentNode(node);
+	setBaseOffset(offset);
+	setExtentOffset(offset);
+	update();
+}
+
+void KHTMLSelection::setSelection(const DOM::Range &r)
+{
+	setSelection(r.startContainer().handle(), r.startOffset(), 
+		r.endContainer().handle(), r.endOffset());
+}
+
+void KHTMLSelection::setSelection(const DOM::DOMPosition &pos)
+{
+	setSelection(pos.node(), pos.offset());
+}
+
+void KHTMLSelection::setSelection(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset)
+{
+	setBaseNode(baseNode);
+	setExtentNode(extentNode);
+	setBaseOffset(baseOffset);
+	setExtentOffset(extentOffset);
+	update();
+}
+
+void KHTMLSelection::setBase(DOM::NodeImpl *node, long offset)
+{
+	setBaseNode(node);
+	setBaseOffset(offset);
+	update();
+}
+
+void KHTMLSelection::setExtent(DOM::NodeImpl *node, long offset)
+{
+	setExtentNode(node);
+	setExtentOffset(offset);
+	update();
+}
+
+bool KHTMLSelection::alterSelection(EAlter alter, EDirection dir, ETextElement elem)
+{
+    DOMPosition pos;
+    
+    switch (dir) {
+        case FORWARD:
+            switch (elem) {
+                case CHARACTER:
+                    pos = nextCharacterPosition();
+                    break;
+                case WORD:
+                    break;
+                case LINE:
+                    break;
+            }
+            break;
+        case BACKWARD:
+            switch (elem) {
+                case CHARACTER:
+                    break;
+                case WORD:
+                    break;
+                case LINE:
+                    break;
+            }
+            break;
+    }
+    
+    if (pos.isEmpty())
+        return false;
+    
+    if (alter == MOVE)
+        setSelection(pos.node(), pos.offset());
+    else // alter == EXTEND
+        setExtent(pos.node(), pos.offset());
+    
+    return true;
+}
+
+void KHTMLSelection::clearSelection()
+{
+	setBaseNode(0);
+	setExtentNode(0);
+	setBaseOffset(0);
+	setExtentOffset(0);
+	update();
+}
+
+NodeImpl *KHTMLSelection::startNode() const
+{ 
+    return m_startNode;
+}
+
+long KHTMLSelection::startOffset() const
+{ 
+    return m_startOffset;
+}
+
+NodeImpl *KHTMLSelection::endNode() const 
+{
+    return m_endNode;
+}
+
+long KHTMLSelection::endOffset() const 
+{ 
+    return m_endOffset;
+}
+
+void KHTMLSelection::setVisible(bool flag)
+{
+    m_visible = flag;
+    update();
+}
+
+void KHTMLSelection::invalidate()
+{
+    update();
+}
+
+void KHTMLSelection::update()
+{
+    // make sure we do not have a dangling start or end
+	if (!m_baseNode && !m_extentNode) {
+        setBaseOffset(0);
+        setExtentOffset(0);
+        m_baseIsStart = true;
+    }
+	else if (!m_baseNode) {
+		setBaseNode(m_extentNode);
+		setBaseOffset(m_extentOffset);
+        m_baseIsStart = true;
+	}
+	else if (!m_extentNode) {
+		setExtentNode(m_baseNode);
+		setExtentOffset(m_baseOffset);
+        m_baseIsStart = true;
+	}
+    else {
+        // adjust m_baseIsStart as needed
+        if (m_baseNode == m_extentNode) {
+            if (m_baseOffset > m_extentOffset)
+                m_baseIsStart = false;
+            else 
+                m_baseIsStart = true;
+        }
+        else if (nodeIsBeforeNode(m_baseNode, m_extentNode))
+            m_baseIsStart = true;
+        else
+            m_baseIsStart = false;
+    }
+
+    // update start and end
+    m_startEndValid = false;
+    calculateStartAndEnd();
+    
+    // update the blink timer
+    if (m_caretBlinkTimer >= 0)
+        killTimer(m_caretBlinkTimer);
+    if (m_visible && m_state == CARET && m_caretBlinks)
+        m_caretBlinkTimer = startTimer(CARET_BLINK_FREQUENCY);
+    else
+        m_caretBlinkTimer = -1;
+
+    // short-circuit if not visible
+    if (!m_visible) {
+        if (m_caretPaint) {
+            m_caretPaint = false;
+            repaint();
+        }
+        return;
+    }
+
+    // short-circuit if not CARET state
+	if (m_state != CARET)
+		return;
+
+    // calculate the new caret rendering position
+    int oldX = m_caretX;   
+    int oldY = m_caretY;   
+    int oldSize = m_caretSize;
+    
+    int newX = 0;
+    int newY = 0;
+    int newSize = 0;
+    
+    NodeImpl *node = startNode();
+    if (node && node->renderer()) {
+        int w;
+        node->renderer()->caretPos(startOffset(), true, newX, newY, w, newSize);
+    }
+
+    // repaint the old position if necessary
+    // prevents two carets from ever being drawn
+    if (m_caretPaint && (oldX != newX || oldY != newY || oldSize != newSize)) {
+        repaint();
+    }
+
+    // update caret rendering position
+    m_caretX = newX;
+    m_caretY = newY;
+    m_caretSize = newSize;
+
+    // paint the caret if it is visible
+    if (m_visible && m_caretSize != 0) {
+        m_caretPaint = true;
+        repaint();
+    }
+}
+
+bool KHTMLSelection::isEmpty() const
+{
+    return m_baseNode == 0 && m_extentNode == 0;
+}
+
+#ifdef APPLE_CHANGES
+void KHTMLSelection::paint(QPainter *p, const QRect &rect) const
+{
+    if (!m_caretPaint || m_state != CARET)
+        return;
+
+    QRect pos(m_caretX, m_caretY, 1, m_caretSize);
+    if (pos.intersects(rect)) {
+        QPen pen = p->pen();
+        pen.setStyle(SolidLine);
+        pen.setColor(Qt::black);
+        pen.setWidth(1);
+        p->setPen(pen);
+        p->drawLine(pos.left(), pos.top(), pos.left(), pos.bottom());
+    }
+}
+#endif
+
+void KHTMLSelection::setPart(KHTMLPart *part)
+{
+    m_part = part;
+}
+
+void KHTMLSelection::timerEvent(QTimerEvent *e)
+{
+    if (e->timerId() == m_caretBlinkTimer && m_visible) {
+        m_caretPaint = !m_caretPaint;
+        repaint();
+    }
+}
+
+void KHTMLSelection::repaint(bool immediate) const
+{
+    KHTMLView *v = m_part->view();
+    if (!v)
+        return;
+    // EDIT FIXME: fudge a bit to make sure we don't leave behind artifacts
+    v->updateContents(m_caretX - 1, m_caretY - 1, 3, m_caretSize + 2, immediate);
+}
+
+void KHTMLSelection::setBaseNode(DOM::NodeImpl *node)
+{
+	if (m_baseNode == node)
+		return;
+
+	if (m_baseNode)
+		m_baseNode->deref();
+	
+	m_baseNode = node;
+	
+	if (m_baseNode)
+		m_baseNode->ref();
+}
+
+void KHTMLSelection::setBaseOffset(long offset)
+{
+	m_baseOffset = offset;
+}
+
+void KHTMLSelection::setExtentNode(DOM::NodeImpl *node)
+{
+	if (m_extentNode == node)
+		return;
+
+	if (m_extentNode)
+		m_extentNode->deref();
+	
+	m_extentNode = node;
+	
+	if (m_extentNode)
+		m_extentNode->ref();
+}
+	
+void KHTMLSelection::setExtentOffset(long offset)
+{
+	m_extentOffset = offset;
+}
+
+void KHTMLSelection::setStart(DOM::NodeImpl *node, long offset)
+{
+    setStartNode(node);
+    setStartOffset(offset);
+}
+
+void KHTMLSelection::setStartNode(DOM::NodeImpl *node)
+{
+	if (m_startNode == node)
+		return;
+
+	if (m_startNode)
+		m_startNode->deref();
+	
+	m_startNode = node;
+	
+	if (m_startNode)
+		m_startNode->ref();
+}
+
+void KHTMLSelection::setStartOffset(long offset)
+{
+	m_startOffset = offset;
+}
+
+void KHTMLSelection::setEnd(DOM::NodeImpl *node, long offset)
+{
+    setEndNode(node);
+    setEndOffset(offset);
+}
+
+void KHTMLSelection::setEndNode(DOM::NodeImpl *node)
+{
+	if (m_endNode == node)
+		return;
+
+	if (m_endNode)
+		m_endNode->deref();
+	
+	m_endNode = node;
+	
+	if (m_endNode)
+		m_endNode->ref();
+}
+	
+void KHTMLSelection::setEndOffset(long offset)
+{
+	m_endOffset = offset;
+}
+
+void KHTMLSelection::expandSelection(ETextElement select)
+{
+    m_startEndValid = false;
+    calculateStartAndEnd(select);
+}
+
+void KHTMLSelection::calculateStartAndEnd(ETextElement select)
+{
+    if (m_startEndValid)
+        return;
+
+#if !APPLE_CHANGES
+    if (m_baseIsStart) {
+        setStartNode(m_baseNode);
+        setStartOffset(m_baseOffset);
+        setEndNode(m_extentNode);
+        setEndOffset(m_extentOffset);
+    }
+    else {
+        setStartNode(m_extentNode);
+        setStartOffset(m_extentOffset);
+        setEndNode(m_baseNode);
+        setEndOffset(m_baseOffset);
+    }
+#else
+    if (select == CHARACTER) {
+        if (m_baseIsStart) {
+            setStartNode(m_baseNode);
+            setStartOffset(m_baseOffset);
+            setEndNode(m_extentNode);
+            setEndOffset(m_extentOffset);
+        }
+        else {
+            setStartNode(m_extentNode);
+            setStartOffset(m_extentOffset);
+            setEndNode(m_baseNode);
+            setEndOffset(m_baseOffset);
+        }
+    }
+    else if (select == WORD) {
+        int baseStartOffset = m_baseOffset;
+        int baseEndOffset = m_baseOffset;
+        int extentStartOffset = m_extentOffset;
+        int extentEndOffset = m_extentOffset;
+        if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            DOMString t = m_baseNode->nodeValue();
+            QChar *chars = t.unicode();
+            uint len = t.length();
+            findWordBoundary(chars, len, m_baseOffset, &baseStartOffset, &baseEndOffset);
+        }
+        if (m_extentNode && (m_extentNode->nodeType() == Node::TEXT_NODE || m_extentNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            DOMString t = m_extentNode->nodeValue();
+            QChar *chars = t.unicode();
+            uint len = t.length();
+            findWordBoundary(chars, len, m_extentOffset, &extentStartOffset, &extentEndOffset);
+        }
+        if (m_baseIsStart) {
+            setStartNode(m_baseNode);
+            setStartOffset(baseStartOffset);
+            setEndNode(m_extentNode);
+            setEndOffset(extentEndOffset);
+        }
+        else {
+            setStartNode(m_extentNode);
+            setStartOffset(extentStartOffset);
+            setEndNode(m_baseNode);
+            setEndOffset(baseEndOffset);
+        }
+    }
+    else {  // select == LINE
+        KHTMLSelection baseSelection = *this;
+        KHTMLSelection extentSelection = *this;
+        if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            if (startAndEndLineNodesIncludingNode(m_baseNode, m_baseOffset, baseSelection)) {
+                setStartNode(baseSelection.baseNode());
+                setStartOffset(baseSelection.baseOffset());
+                setEndNode(baseSelection.extentNode());
+                setEndOffset(baseSelection.extentOffset());
+            }
+        }
+        if (m_extentNode && (m_extentNode->nodeType() == Node::TEXT_NODE || m_extentNode->nodeType() == Node::CDATA_SECTION_NODE)) {
+            if (startAndEndLineNodesIncludingNode(m_extentNode, m_extentOffset, extentSelection)) {
+                setStartNode(extentSelection.baseNode());
+                setStartOffset(extentSelection.baseOffset());
+                setEndNode(extentSelection.extentNode());
+                setEndOffset(extentSelection.extentOffset());
+            }
+        }
+        if (m_baseIsStart) {
+            setStartNode(baseSelection.startNode());
+            setStartOffset(baseSelection.startOffset());
+            setEndNode(extentSelection.endNode());
+            setEndOffset(extentSelection.endOffset());
+        }
+        else {
+            setStartNode(extentSelection.startNode());
+            setStartOffset(extentSelection.startOffset());
+            setEndNode(baseSelection.endNode());
+            setEndOffset(baseSelection.endOffset());
+        }
+    }
+#endif  // APPLE_CHANGES
+
+	// update the state
+	if (!m_startNode && !m_endNode)
+		m_state = NONE;
+	if (m_startNode == m_endNode && m_startOffset == m_endOffset)
+		m_state = CARET;
+	else
+		m_state = RANGE;
+    
+    m_startEndValid = true;
+}
+
+DOMPosition KHTMLSelection::nextCharacterPosition()
+{
+    DOMPosition result;
+	NodeImpl *node = endNode();
+	long offset = endOffset();
+    long desiredOffset = offset + 1;
+
+    if (!node)
+        return result;
+    
+    //
+    // Look in this renderer
+    //
+    RenderObject *renderer = node->renderer();
+    if (renderer->isText()) {
+        RenderText *textRenderer = static_cast<khtml::RenderText *>(renderer);
+        InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+        unsigned i = 0;
+        for (i = 0; i < runs.count(); i++) {
+            long start = runs[i]->m_start;
+            long end = runs[i]->m_start + runs[i]->m_len;
+            if (desiredOffset > end) {
+                // Skip this node.
+                // It is too early in the text runs to be involved.
+                continue;
+            }
+            else if (desiredOffset >= start && 
+                (desiredOffset < end || (desiredOffset == end && i + 1 == runs.count() && !renderer->nextEditable())) ||
+                (desiredOffset == end && textRenderer->precedesLineBreak() && !textRenderer->followsLineBreak())) {
+                // Desired offset is in this node.
+                // Either it is:
+                // 1. at or after the start and before, but not at the end
+                // 2. at the end of a text run and is immediately followed by a line break
+                //    but does not precede a line break
+                // 3. at the end of the editable content of the document
+                return DOMPosition(renderer->element(), desiredOffset);
+            }
+            else if (desiredOffset <= start) {
+                // The offset we're looking for is before this node
+                // this means the offset must be in text that is
+                // not rendered. Just return the start of the node.
+                return DOMPosition(renderer->element(), start);
+            }
+        }
+    }
+    else if (desiredOffset < renderer->caretMaxOffset() || (desiredOffset == renderer->caretMaxOffset() && !renderer->nextEditable())) {
+        return DOMPosition(node, desiredOffset);
+    }
+
+    //
+    // Look in next renderer(s)
+    //
+    renderer = renderer->nextEditable();
+    while (renderer) {
+        if (renderer->isText()) {
+            RenderText *textRenderer = static_cast<khtml::RenderText *>(renderer);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            if (runs.count())
+                return DOMPosition(renderer->element(), runs[0]->m_start);
+        }
+        else {
+            return DOMPosition(renderer->element(), renderer->caretMinOffset());
+        }
+        renderer = renderer->nextEditable();
+    }
+
+    result = DOMPosition(node, offset);
+    return result;
+}
+
+bool KHTMLSelection::nodeIsBeforeNode(NodeImpl *n1, NodeImpl *n2) 
+{
+	if (!n1 || !n2) 
+		return true;
+ 
+ 	if (n1 == n2)
+ 		return true;
+ 
+ 	bool result = false;
+    int n1Depth = 0;
+    int n2Depth = 0;
+
+    // First we find the depths of the two nodes in the tree (n1Depth, n2Depth)
+    DOM::NodeImpl *n = n1;
+    while (n->parentNode()) {
+        n = n->parentNode();
+        n1Depth++;
+    }
+    n = n2;
+    while (n->parentNode()) {
+        n = n->parentNode();
+        n2Depth++;
+    }
+    // Climb up the tree with the deeper node, until both nodes have equal depth
+    while (n2Depth > n1Depth) {
+        n2 = n2->parentNode();
+        n2Depth--;
+    }
+    while (n1Depth > n2Depth) {
+        n1 = n1->parentNode();
+        n1Depth--;
+    }
+    // Climb the tree with both n1 and n2 until they have the same parent
+    while (n1->parentNode() != n2->parentNode()) {
+        n1 = n1->parentNode();
+        n2 = n2->parentNode();
+    }
+    // Iterate through the parent's children until n1 or n2 is found
+    n = n1->parentNode()->firstChild();
+    while (n) {
+        if (n == n1) {
+            result = true;
+            break;
+        }
+        else if (n == n2) {
+            result = false;
+            break;
+        }
+        n = n->nextSibling();
+    }
+	return result;
+}
+
+#if APPLE_CHANGES
+
+static void findWordBoundary(QChar *chars, int len, int position, int *start, int *end)
+{
+    TextBreakLocatorRef breakLocator;
+    OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakWordMask, &breakLocator);
+    if (status == noErr) {
+        UniCharArrayOffset startOffset, endOffset;
+        status = UCFindTextBreak(breakLocator, kUCTextBreakWordMask, 0, (const UniChar *)chars, len, position, &endOffset);
+        if (status == noErr) {
+            status = UCFindTextBreak(breakLocator, kUCTextBreakWordMask, kUCTextBreakGoBackwardsMask, (const UniChar *)chars, len, position, &startOffset);
+        }
+        UCDisposeTextBreakLocator(&breakLocator);
+        if (status == noErr) {
+            *start = startOffset;
+            *end = endOffset;
+            return;
+        }
+    }
+    
+    // If Carbon fails (why would it?), do a simple space/punctuation boundary check.
+    if (chars[position].isSpace()) {
+        int pos = position;
+        while (chars[pos].isSpace() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (chars[pos].isSpace() && pos < (int)len)
+            pos++;
+        *end = pos;
+    } else if (chars[position].isPunct()) {
+        int pos = position;
+        while (chars[pos].isPunct() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (chars[pos].isPunct() && pos < (int)len)
+            pos++;
+        *end = pos;
+    } else {
+        int pos = position;
+        while (!chars[pos].isSpace() && !chars[pos].isPunct() && pos >= 0)
+            pos--;
+        *start = pos+1;
+        pos = position;
+        while (!chars[pos].isSpace() && !chars[pos].isPunct() && pos < (int)len)
+            pos++;
+        *end = pos;
+    }
+}
+
+static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
+{
+    for (RenderObject *n = renderNode; n; n = n->nextSibling()) {
+        if (n->isText()) {
+            RenderText *textRenderer = static_cast<khtml::RenderText *>(n);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            for (unsigned i = 0; i != runs.count(); i++) {
+                if (runs[i]->m_y == y) {
+                    startNode = textRenderer->element();
+                    startOffset = runs[i]->m_start;
+                    return true;
+                }
+            }
+        }
+        
+        if (firstRunAt(n->firstChild(), y, startNode, startOffset)) {
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+static bool lastRunAt(RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset)
+{
+    RenderObject *n = renderNode;
+    if (!n) {
+        return false;
+    }
+    RenderObject *next;
+    while ((next = n->nextSibling())) {
+        n = next;
+    }
+    
+    while (1) {
+        if (lastRunAt(n->firstChild(), y, endNode, endOffset)) {
+            return true;
+        }
+    
+        if (n->isText()) {
+            RenderText *textRenderer =  static_cast<khtml::RenderText *>(n);
+            InlineTextBoxArray runs = textRenderer->inlineTextBoxes();
+            for (int i = (int)runs.count()-1; i >= 0; i--) {
+                if (runs[i]->m_y == y) {
+                    endNode = textRenderer->element();
+                    endOffset = runs[i]->m_start + runs[i]->m_len;
+                    return true;
+                }
+            }
+        }
+        
+        if (n == renderNode) {
+            return false;
+        }
+        
+        n = n->previousSibling();
+    }
+}
+
+static bool startAndEndLineNodesIncludingNode(DOM::NodeImpl *node, int offset, KHTMLSelection &selection)
+{
+    if (node && (node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE)) {
+        int pos;
+        int selectionPointY;
+        RenderText *renderer = static_cast<RenderText *>(node->renderer());
+        InlineTextBox * run = renderer->findNextInlineTextBox( offset, pos );
+        DOMString t = node->nodeValue();
+        
+        if (!run)
+            return false;
+            
+        selectionPointY = run->m_y;
+        
+        // Go up to first non-inline element.
+        khtml::RenderObject *renderNode = renderer;
+        while (renderNode && renderNode->isInline())
+            renderNode = renderNode->parent();
+        
+        renderNode = renderNode->firstChild();
+        
+        DOM::NodeImpl *startNode = 0;
+        DOM::NodeImpl *endNode = 0;
+        long startOffset;
+        long endOffset;
+        
+        // Look for all the first child in the block that is on the same line
+        // as the selection point.
+        if (!firstRunAt (renderNode, selectionPointY, startNode, startOffset))
+            return false;
+    
+        // Look for all the last child in the block that is on the same line
+        // as the selection point.
+        if (!lastRunAt (renderNode, selectionPointY, endNode, endOffset))
+            return false;
+        
+        selection.setSelection(startNode, startOffset, endNode, endOffset);
+        
+        return true;
+    }
+    return false;
+}
+
+#endif
diff --git a/WebCore/khtml/xml/dom_selection.h b/WebCore/khtml/xml/dom_selection.h
new file mode 100644
index 0000000..e073149
--- /dev/null
+++ b/WebCore/khtml/xml/dom_selection.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef __khtml_selection_h__
+#define __khtml_selection_h__
+
+#include <qobject.h>
+
+class KHTMLPart;
+class KHTMLPartPrivate;
+class KHTMLView;
+class QPainter;
+class QRect;
+class QTimerEvent;
+
+namespace DOM {
+    class DOMPosition;
+    class NodeImpl;
+    class Range;
+};
+
+class KHTMLSelection : public QObject
+{
+  Q_OBJECT
+
+public:
+    KHTMLSelection();
+    KHTMLSelection(const KHTMLSelection &);
+    ~KHTMLSelection();
+
+	enum EState { NONE, CARET, RANGE };
+	enum ETextElement { CHARACTER, WORD, LINE };
+	enum EDirection { FORWARD, BACKWARD };
+	enum EAlter { MOVE, EXTEND };
+
+	EState state() const { return m_state; }
+
+    void setSelection(DOM::NodeImpl *node, long offset);
+    void setSelection(const DOM::Range &);
+    void setSelection(const DOM::DOMPosition &);
+    void setSelection(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset);
+    void setBase(DOM::NodeImpl *node, long offset);
+    void setExtent(DOM::NodeImpl *node, long offset);
+    void expandSelection(ETextElement);
+    bool alterSelection(EAlter, EDirection, ETextElement);
+    void clearSelection();
+    
+    DOM::NodeImpl *baseNode() const { return m_baseNode; }
+    long baseOffset() const { return m_baseOffset; }
+
+    DOM::NodeImpl *extentNode() const { return m_extentNode; }
+    long extentOffset() const { return m_extentOffset; }
+
+    DOM::NodeImpl *startNode() const;
+    long startOffset() const;
+
+    DOM::NodeImpl *endNode() const;
+    long endOffset() const;
+
+    void setVisible(bool flag=true);
+    bool visible() const { return m_visible; }
+    
+    void invalidate();
+    
+    bool isEmpty() const;
+    
+#ifdef APPLE_CHANGES
+    void paint(QPainter *p, const QRect &rect) const;
+#endif
+
+    KHTMLSelection &operator=(const KHTMLSelection &o);
+    
+    friend bool operator==(const KHTMLSelection &a, const KHTMLSelection &b);
+    friend bool operator!=(const KHTMLSelection &a, const KHTMLSelection &b);
+    
+    friend class KHTMLPart;
+
+    void dump() {
+        fprintf(stderr, "selection: %p:%d ; %p:%d (%p:%d ; %p:%d)\n", 
+            m_baseNode, m_baseOffset, m_extentNode, m_extentOffset,
+            startNode(), startOffset(), endNode(), endOffset());
+    }
+    
+private:
+    void setPart(KHTMLPart *part);
+
+    void update();
+
+    void timerEvent(QTimerEvent *e);
+    void repaint(bool immediate=false) const;
+
+	void setBaseNode(DOM::NodeImpl *);
+	void setBaseOffset(long);
+	void setExtentNode(DOM::NodeImpl *);
+	void setExtentOffset(long);
+
+	void setStart(DOM::NodeImpl *, long);
+	void setStartNode(DOM::NodeImpl *);
+	void setStartOffset(long);
+	void setEnd(DOM::NodeImpl *, long);
+	void setEndNode(DOM::NodeImpl *);
+	void setEndOffset(long);
+
+    bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
+
+    void calculateStartAndEnd(ETextElement select=CHARACTER);
+    
+    DOM::DOMPosition nextCharacterPosition();
+    
+    KHTMLPart *m_part;            // part for this selection
+
+    DOM::NodeImpl *m_baseNode;    // base node for the selection
+    long m_baseOffset;            // offset into base node where selection is
+    DOM::NodeImpl *m_extentNode;  // extent node for the selection
+    long m_extentOffset;          // offset into extent node where selection is
+
+    DOM::NodeImpl *m_startNode;   // start node for the selection (read-only)
+    long m_startOffset;           // offset into start node where selection is (read-only)
+    DOM::NodeImpl *m_endNode;     // end node for the selection (read-only)
+    long m_endOffset;             // offset into end node where selection is (read-only)
+
+	EState m_state;               // the state of the selection
+
+    int m_caretBlinkTimer;        // caret blink frequency timer id
+	
+	int m_caretX;
+	int m_caretY;
+	int m_caretSize;
+
+	bool m_baseIsStart : 1;     // true if base node is before the extent node
+    bool m_caretBlinks : 1;     // true if caret blinks
+    bool m_caretPaint : 1;      // flag used to deal with blinking the caret
+    bool m_visible : 1;         // true if selection is to be displayed at all
+	bool m_startEndValid : 1;   // true if the start and end are valid
+};
+
+
+inline bool operator==(const KHTMLSelection &a, const KHTMLSelection &b)
+{
+    return a.baseNode() == b.baseNode() && a.baseOffset() == b.baseOffset() &&
+        a.extentNode() == b.extentNode() && a.extentOffset() == b.extentOffset();
+}
+
+inline bool operator!=(const KHTMLSelection &a, const KHTMLSelection &b)
+{
+    return !(a == b);
+}
+
+#endif
\ No newline at end of file
diff --git a/WebCore/khtml/xml/dom_textimpl.cpp b/WebCore/khtml/xml/dom_textimpl.cpp
index 65134e4..aa9ff47 100644
--- a/WebCore/khtml/xml/dom_textimpl.cpp
+++ b/WebCore/khtml/xml/dom_textimpl.cpp
@@ -232,6 +232,18 @@ void CharacterDataImpl::checkCharDataOperation( const unsigned long offset, int
     }
 }
 
+long CharacterDataImpl::caretMinOffset() const 
+{
+    RenderText *r = static_cast<RenderText *>(renderer());
+    return r && r->isText() ? r->caretMinOffset() : 0;
+}
+
+long CharacterDataImpl::caretMaxOffset() const 
+{
+    RenderText *r = static_cast<RenderText *>(renderer());
+    return r && r->isText() ? r->caretMaxOffset() : (long)length();
+}
+
 #ifndef NDEBUG
 void CharacterDataImpl::dump(QTextStream *stream, QString ind) const
 {
diff --git a/WebCore/khtml/xml/dom_textimpl.h b/WebCore/khtml/xml/dom_textimpl.h
index 0b78098..6abbe30 100644
--- a/WebCore/khtml/xml/dom_textimpl.h
+++ b/WebCore/khtml/xml/dom_textimpl.h
@@ -64,6 +64,10 @@ public:
 
     DOMStringImpl *string() { return str; }
     virtual void checkCharDataOperation( const unsigned long offset, int &exceptioncode );
+
+    virtual long caretMinOffset() const;
+    virtual long caretMaxOffset() const;
+
 #ifndef NDEBUG
     virtual void dump(QTextStream *stream, QString ind = "") const;
 #endif
diff --git a/WebCore/kwq/KWQKDebug.h b/WebCore/kwq/KWQKDebug.h
index 77a1bee..138e76e 100644
--- a/WebCore/kwq/KWQKDebug.h
+++ b/WebCore/kwq/KWQKDebug.h
@@ -39,6 +39,7 @@ public:
     
     kdbgstream &operator<<(int) { return *this; }
     kdbgstream &operator<<(unsigned int) { return *this; }
+    kdbgstream &operator<<(long) { return *this; }
     kdbgstream &operator<<(double) { return *this; }
     kdbgstream &operator<<(const char *) { return *this; }
     kdbgstream &operator<<(const void *) { return *this; }
diff --git a/WebCore/kwq/KWQKHTMLPart.mm b/WebCore/kwq/KWQKHTMLPart.mm
index 11e211d..4d38608 100644
--- a/WebCore/kwq/KWQKHTMLPart.mm
+++ b/WebCore/kwq/KWQKHTMLPart.mm
@@ -42,6 +42,7 @@
 #import "htmltokenizer.h"
 #import "khtmlpart_p.h"
 #import "khtmlview.h"
+#import "khtml_selection.h"
 #import "kjs_binding.h"
 #import "kjs_window.h"
 #import "misc/htmlattrs.h"
@@ -800,11 +801,11 @@ void KWQKHTMLPart::jumpToSelection()
 {
     // Assumes that selection will only ever be text nodes. This is currently
     // true, but will it always be so?
-    if (!d->m_selectionStart.isNull()) {
-        RenderText *rt = dynamic_cast<RenderText *>(d->m_selectionStart.handle()->renderer());
+    if (d->m_selection.startNode()) {
+        RenderText *rt = dynamic_cast<RenderText *>(d->m_selection.startNode()->renderer());
         if (rt) {
             int x = 0, y = 0;
-            rt->posOfChar(d->m_startOffset, x, y);
+            rt->posOfChar(d->m_selection.startOffset(), x, y);
             // The -50 offset is copied from KHTMLPart::findTextNext, which sets the contents position
             // after finding a matched text string.
            d->m_view->setContentsPos(x - 50, y - 50);
@@ -1792,11 +1793,9 @@ void KWQKHTMLPart::khtmlMouseMoveEvent(MouseMoveEvent *event)
             return;
         }
 
-	if (_mouseDownMayStartDrag &&
-            !d->m_selectionInitiatedWithDoubleClick &&
-            !d->m_selectionInitiatedWithTripleClick &&
-            [_bridge mayStartDragWithMouseDragged:_currentEvent])
-        {
+	if (_mouseDownMayStartDrag && 
+        d->m_textElement == KHTMLSelection::CHARACTER &&
+        [_bridge mayStartDragWithMouseDragged:_currentEvent]) {
             // We are starting a text/image/url drag, so the cursor should be an arrow
             d->m_view->resetCursor();
             [_bridge handleMouseDragged:_currentEvent];
@@ -2672,22 +2671,22 @@ KWQWindowWidget *KWQKHTMLPart::topLevelWidget()
 
 int KWQKHTMLPart::selectionStartOffset() const
 {
-    return d->m_startOffset;
+    return d->m_selection.startOffset();
 }
 
 int KWQKHTMLPart::selectionEndOffset() const
 {
-    return d->m_endOffset;
+    return d->m_selection.endOffset();
 }
 
 NodeImpl *KWQKHTMLPart::selectionStart() const
 {
-    return d->m_selectionStart.handle();
+    return d->m_selection.startNode();
 }
 
 NodeImpl *KWQKHTMLPart::selectionEnd() const
 {
-    return d->m_selectionEnd.handle();
+    return d->m_selection.endNode();
 }
 
 void KWQKHTMLPart::setBridge(WebCoreBridge *p)
diff --git a/WebCore/kwq/KWQLogging.h b/WebCore/kwq/KWQLogging.h
index 0969edc..440115b 100644
--- a/WebCore/kwq/KWQLogging.h
+++ b/WebCore/kwq/KWQLogging.h
@@ -35,3 +35,4 @@ extern KWQLogChannel KWQLogFrames;
 extern KWQLogChannel KWQLogLoading;
 extern KWQLogChannel KWQLogPopupBlocking;
 extern KWQLogChannel KWQLogEvents;
+extern KWQLogChannel KWQLogEditing;
diff --git a/WebCore/kwq/KWQLogging.m b/WebCore/kwq/KWQLogging.m
index d512947..c4635ea 100644
--- a/WebCore/kwq/KWQLogging.m
+++ b/WebCore/kwq/KWQLogging.m
@@ -33,3 +33,4 @@ KWQLogChannel KWQLogLoading =           { 0x00000020, "WebCoreLogLevel", KWQLogC
 KWQLogChannel KWQLogPopupBlocking =     { 0x00000040, "WebCoreLogLevel", KWQLogChannelUninitialized };
 
 KWQLogChannel KWQLogEvents =            { 0x00000080, "WebCoreLogLevel", KWQLogChannelUninitialized };
+KWQLogChannel KWQLogEditing =           { 0x00000100, "WebCoreLogLevel", KWQLogChannelUninitialized };
diff --git a/WebCore/kwq/KWQWidget.h b/WebCore/kwq/KWQWidget.h
index 48c9cf2..7eff52a 100644
--- a/WebCore/kwq/KWQWidget.h
+++ b/WebCore/kwq/KWQWidget.h
@@ -134,6 +134,7 @@ public:
     void wheelEvent(QWheelEvent *) { }
     void keyPressEvent(QKeyEvent *) { }
     void keyReleaseEvent(QKeyEvent *) { }
+    void focusInEvent(QFocusEvent *) { }
     void focusOutEvent(QFocusEvent *) { }
 
     enum BackgroundMode { NoBackground };    

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list