[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:35:07 UTC 2009


The following commit has been merged in the debian/unstable branch:
commit 7784bef2ce7664523ae2dfbd9c431576804ba157
Author: kocienda <kocienda at 268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Apr 20 21:20:23 2004 +0000

    WebCore:
    
            Reviewed by Hyatt
    
            * WebCore.pbproj/project.pbxproj:
            * khtml/khtml_part.cpp:
            (KHTMLPart::handleMousePressEventDoubleClick): Improved name of expandToElement. Now is expandUsingGranularity.
            (KHTMLPart::handleMousePressEventTripleClick): Ditto.
            (KHTMLPart::handleMouseMoveEventSelection): Ditto.
            * khtml/khtml_selection.cpp:
            (KHTMLSelection::modify): Added support for modifying and extending selection right and left by word.
            Also added support for extending selection up and down.
            (KHTMLSelection::expandUsingGranularity): New name for expandToElement.
            (KHTMLSelection::xPosForVerticalArrowNavigation): Made this function handle cases where we know we
            want to use a particular position for calculating the right x position. We need this to handle
            extending selection up and down, and for setting the caret to the right place when moving up
            and down when a range is already selected.
            (KHTMLSelection::validate): Name tweak. expandTo variable now granularity.
            * khtml/khtml_selection.h: Make declaration changes for changes to cpp file.
            * khtml/misc/helper.cpp:
            (khtml::findWordBoundary): Added this hook for KDE to do their version of KWQFindWordBoundary
            * khtml/misc/helper.h:
            * khtml/rendering/render_block.cpp:
            (khtml::RenderBlock::positionForCoordinates): Factor out closest box finder code to its own function
            * khtml/rendering/render_line.cpp:
            (InlineFlowBox::closestChildForXPos): New function. This is the factored code that was taken out of
            render_block.cpp.
            (InlineBox::closestLeafChildForXPos): Ditto.
            * khtml/rendering/render_line.h: Ditto.
            * khtml/rendering/render_replaced.cpp:
            (RenderReplaced::positionForCoordinates): I think I am starting to get how the coordinate transforms work.
            Made some fixups based on this greater sense of enlightenment.
            * khtml/rendering/render_text.cpp:
            (RenderText::positionForCoordinates): Ditto. Fix lastTextBox/firstTextBox code mistake.
            * khtml/xml/dom_position.cpp:
            (DOMPosition::previousWordPosition): Added.
            (DOMPosition::nextWordPosition): Added.
            (DOMPosition::previousLinePosition): No longer use nodeAtPoint. Use new closestLeafChildForXPos instead.
            (DOMPosition::nextLinePosition): Ditto.
            (DOMPosition::inLastEditableInContainingEditableBlock):
            * khtml/xml/dom_position.h:
            * kwq/KWQTextUtilities.cpp: Added.
            (KWQFindWordBoundary): Factored out code that was in a static function in khtml_selection.cpp so
            that DOMPosition can use it too.
            * kwq/KWQTextUtilities.h: Added.
    
    WebKit:
    
            Reviewed by Hyatt
    
             Added implementations for these methods.
    
            * WebView.subproj/WebView.m:
            (-[WebView moveUpAndModifySelection:]):
            (-[WebView moveWordLeft:]):
            (-[WebView moveWordLeftAndModifySelection:]):
            (-[WebView moveWordRight:]):
            (-[WebView moveWordRightAndModifySelection:]):
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@6431 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog-2005-08-23 b/WebCore/ChangeLog-2005-08-23
index 3731d22..5f22656 100644
--- a/WebCore/ChangeLog-2005-08-23
+++ b/WebCore/ChangeLog-2005-08-23
@@ -1,3 +1,49 @@
+2004-04-20  Ken Kocienda  <kocienda at apple.com>
+
+        Reviewed by Hyatt
+
+        * WebCore.pbproj/project.pbxproj:
+        * khtml/khtml_part.cpp:
+        (KHTMLPart::handleMousePressEventDoubleClick): Improved name of expandToElement. Now is expandUsingGranularity.
+        (KHTMLPart::handleMousePressEventTripleClick): Ditto.
+        (KHTMLPart::handleMouseMoveEventSelection): Ditto.
+        * khtml/khtml_selection.cpp:
+        (KHTMLSelection::modify): Added support for modifying and extending selection right and left by word.
+        Also added support for extending selection up and down.
+        (KHTMLSelection::expandUsingGranularity): New name for expandToElement.
+        (KHTMLSelection::xPosForVerticalArrowNavigation): Made this function handle cases where we know we
+        want to use a particular position for calculating the right x position. We need this to handle
+        extending selection up and down, and for setting the caret to the right place when moving up
+        and down when a range is already selected.
+        (KHTMLSelection::validate): Name tweak. expandTo variable now granularity.
+        * khtml/khtml_selection.h: Make declaration changes for changes to cpp file.
+        * khtml/misc/helper.cpp:
+        (khtml::findWordBoundary): Added this hook for KDE to do their version of KWQFindWordBoundary
+        * khtml/misc/helper.h:
+        * khtml/rendering/render_block.cpp:
+        (khtml::RenderBlock::positionForCoordinates): Factor out closest box finder code to its own function
+        * khtml/rendering/render_line.cpp:
+        (InlineFlowBox::closestChildForXPos): New function. This is the factored code that was taken out of 
+        render_block.cpp.
+        (InlineBox::closestLeafChildForXPos): Ditto.
+        * khtml/rendering/render_line.h: Ditto.
+        * khtml/rendering/render_replaced.cpp:
+        (RenderReplaced::positionForCoordinates): I think I am starting to get how the coordinate transforms work.
+        Made some fixups based on this greater sense of enlightenment.
+        * khtml/rendering/render_text.cpp:
+        (RenderText::positionForCoordinates): Ditto. Fix lastTextBox/firstTextBox code mistake.
+        * khtml/xml/dom_position.cpp:
+        (DOMPosition::previousWordPosition): Added.
+        (DOMPosition::nextWordPosition): Added.
+        (DOMPosition::previousLinePosition): No longer use nodeAtPoint. Use new closestLeafChildForXPos instead.
+        (DOMPosition::nextLinePosition): Ditto.
+        (DOMPosition::inLastEditableInContainingEditableBlock):
+        * khtml/xml/dom_position.h:
+        * kwq/KWQTextUtilities.cpp: Added.
+        (KWQFindWordBoundary): Factored out code that was in a static function in khtml_selection.cpp so 
+        that DOMPosition can use it too.
+        * kwq/KWQTextUtilities.h: Added.
+
 2004-04-19  Ken Kocienda  <kocienda at apple.com>
 
         Reviewed by Hyatt
diff --git a/WebCore/WebCore.pbproj/project.pbxproj b/WebCore/WebCore.pbproj/project.pbxproj
index d9f4f15..cdde0e8 100644
--- a/WebCore/WebCore.pbproj/project.pbxproj
+++ b/WebCore/WebCore.pbproj/project.pbxproj
@@ -532,6 +532,7 @@
 				BE91FC9206133697005E3790,
 				832556E5061DF155007B8054,
 				BC86FB8F061F5C23006BB822,
+				BE8BD8F506359F6000D3F20B,
 			);
 			isa = PBXHeadersBuildPhase;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -813,6 +814,7 @@
 				BE91FC9106133697005E3790,
 				832556E7061DF161007B8054,
 				BC86FB90061F5C23006BB822,
+				BE8BD8F406359F6000D3F20B,
 			);
 			isa = PBXSourcesBuildPhase;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -860,7 +862,7 @@
 			isa = PBXShellScriptBuildPhase;
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "if [ -f ../Tools/Scripts/embed-into-alex ]; then sh ../Tools/Scripts/embed-into-alex; fi";
+			shellScript = "#if [ -f ../Tools/Scripts/embed-into-alex ]; then sh ../Tools/Scripts/embed-into-alex; fi";
 		};
 //250
 //251
@@ -2716,6 +2718,34 @@
 			settings = {
 			};
 		};
+		BE8BD8F206359F6000D3F20B = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.cpp.cpp;
+			path = KWQTextUtilities.cpp;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		BE8BD8F306359F6000D3F20B = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.c.h;
+			path = KWQTextUtilities.h;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		BE8BD8F406359F6000D3F20B = {
+			fileRef = BE8BD8F206359F6000D3F20B;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		BE8BD8F506359F6000D3F20B = {
+			fileRef = BE8BD8F306359F6000D3F20B;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
 		BE9185DD05EE59B80081354D = {
 			fileEncoding = 30;
 			isa = PBXFileReference;
@@ -3129,6 +3159,8 @@
 				93386B90037045B3008635CE,
 				93386B91037045B3008635CE,
 				F587852F02DE375901EA4122,
+				BE8BD8F206359F6000D3F20B,
+				BE8BD8F306359F6000D3F20B,
 				F587853502DE375901EA4122,
 				F587853602DE375901EA4122,
 				F587851B02DE375901EA4122,
diff --git a/WebCore/khtml/editing/SelectionController.cpp b/WebCore/khtml/editing/SelectionController.cpp
index 96d50e2..82dc803 100644
--- a/WebCore/khtml/editing/SelectionController.cpp
+++ b/WebCore/khtml/editing/SelectionController.cpp
@@ -46,6 +46,7 @@
 
 #if APPLE_CHANGES
 #include <KWQAssertions.h>
+#include <KWQTextUtilities.h>
 #include <CoreServices/CoreServices.h>
 
 #define EDIT_DEBUG 0
@@ -65,7 +66,6 @@ using khtml::RenderObject;
 using khtml::RenderText;
 
 #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);
@@ -250,7 +250,7 @@ void KHTMLSelection::moveTo(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeI
 	validate();
 }
 
-bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
+bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity granularity)
 {
     DOMPosition pos;
     
@@ -258,76 +258,98 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
         // EDIT FIXME: This needs to handle bidi
         case RIGHT:
         case FORWARD:
-            switch (elem) {
-                case CHARACTER:
-                    if (alter == EXTEND) {
-                        if (!m_modifyBiasSet) {
-                            m_modifyBiasSet = true;
-                            setBaseNode(startNode());
-                            setBaseOffset(startOffset());
-                            setExtentNode(endNode());
-                            setExtentOffset(endOffset());
-                        }
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(startNode());
+                    setBaseOffset(startOffset());
+                    setExtentNode(endNode());
+                    setExtentOffset(endOffset());
+                }
+                if (granularity == CHARACTER)
+                    pos = extentPosition().nextCharacterPosition();
+                else if (granularity == WORD)
+                    pos = extentPosition().nextWordPosition();
+            }
+            else {
+                m_modifyBiasSet = false;
+                if (state() == RANGE) {
+                    if (granularity == CHARACTER)
+                        pos = endPosition();
+                    else if (granularity == WORD)
+                        pos = extentPosition().nextWordPosition();
+                }
+                else {
+                    if (granularity == CHARACTER)
                         pos = extentPosition().nextCharacterPosition();
-                    }
-                    else {
-                        m_modifyBiasSet = false;
-                        if (state() == RANGE)
-                            pos = endPosition();
-                        else
-                            pos = endPosition().nextCharacterPosition();
-                    }
-                    break;
-                case WORD:
-                    // EDIT FIXME: implement
-                    break;
-                case LINE:
-                    // EDIT FIXME: implement
-                    break;
+                    else if (granularity == WORD)
+                        pos = extentPosition().nextWordPosition();
+                }
             }
             break;
         // EDIT FIXME: This needs to handle bidi
         case LEFT:
         case BACKWARD:
-            switch (elem) {
-                case CHARACTER:
-                    if (alter == EXTEND) {
-                        if (!m_modifyBiasSet) {
-                            m_modifyBiasSet = true;
-                            setBaseNode(endNode());
-                            setBaseOffset(endOffset());
-                            setExtentNode(startNode());
-                            setExtentOffset(startOffset());
-                        }
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(endNode());
+                    setBaseOffset(endOffset());
+                    setExtentNode(startNode());
+                    setExtentOffset(startOffset());
+                }
+                if (granularity == CHARACTER)
+                    pos = extentPosition().previousCharacterPosition();
+                else if (granularity == WORD)
+                    pos = extentPosition().previousWordPosition();
+            }
+            else {
+                m_modifyBiasSet = false;
+                if (state() == RANGE) {
+                    if (granularity == CHARACTER)
+                        pos = startPosition();
+                    else if (granularity == WORD)
+                        pos = extentPosition().previousWordPosition();
+                }
+                else {
+                    if (granularity == CHARACTER)
                         pos = extentPosition().previousCharacterPosition();
-                    }
-                    else {
-                        m_modifyBiasSet = false;
-                        if (state() == RANGE)
-                            pos = startPosition();
-                        else
-                            pos = startPosition().previousCharacterPosition();
-                    }
-                    break;
-                case WORD:
-                    // EDIT FIXME: implement
-                    break;
-                case LINE:
-                    // EDIT FIXME: implement
-                    break;
+                    else if (granularity == WORD)
+                        pos = extentPosition().previousWordPosition();
+                }
             }
             break;
         case UP:
-            if (alter == EXTEND)
-                ERROR("unimplemented");
-            else
-                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation());
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(endNode());
+                    setBaseOffset(endOffset());
+                    setExtentNode(startNode());
+                    setExtentOffset(startOffset());
+                }
+                pos = extentPosition().previousLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+            }
+            else {
+                m_modifyBiasSet = false;
+                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation(START, state()==RANGE));
+            }
             break;
         case DOWN:
-            if (alter == EXTEND)
-                ERROR("unimplemented");
-            else
-                pos = startPosition().nextLinePosition(xPosForVerticalArrowNavigation());
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(startNode());
+                    setBaseOffset(startOffset());
+                    setExtentNode(endNode());
+                    setExtentOffset(endOffset());
+                }
+                pos = extentPosition().nextLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+            }
+            else {
+                m_modifyBiasSet = false;
+                pos = endPosition().nextLinePosition(xPosForVerticalArrowNavigation(END, state()==RANGE));
+            }
             break;
     }
     
@@ -342,25 +364,45 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
     return true;
 }
 
-void KHTMLSelection::expandToElement(ETextGranularity select)
+bool KHTMLSelection::expandUsingGranularity(ETextGranularity granularity)
 {
-    validate(select);
+    if (state() == NONE)
+        return false;
+        
+    validate(granularity);
+    return true;
 }
 
-int KHTMLSelection::xPosForVerticalArrowNavigation() const
+int KHTMLSelection::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) const
 {
     int x = 0;
 
     if (state() == NONE)
         return x;
 
-    KHTMLPart *part = startPosition().node()->getDocument()->part();
+    DOMPosition pos;
+    switch (type) {
+        case START:
+            pos = startPosition();
+            break;
+        case END:
+            pos = endPosition();
+            break;
+        case BASE:
+            pos = basePosition();
+            break;
+        case EXTENT:
+            pos = extentPosition();
+            break;
+    }
+
+    KHTMLPart *part = pos.node()->getDocument()->part();
     if (!part)
         return x;
         
-    if (part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
+    if (recalc || part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
         int y, w, h;
-        startPosition().node()->renderer()->caretPos(startPosition().offset(), true, x, y, w, h);
+        pos.node()->renderer()->caretPos(pos.offset(), true, x, y, w, h);
         part->setXPosForVerticalArrowNavigation(x);
     }
     else {
@@ -561,7 +603,7 @@ void KHTMLSelection::setEndOffset(long offset)
 	m_endOffset = offset;
 }
 
-void KHTMLSelection::validate(ETextGranularity expandTo)
+void KHTMLSelection::validate(ETextGranularity granularity)
 {
     // move the base and extent nodes to their equivalent leaf positions
     bool baseAndExtentEqual = m_baseNode == m_extentNode && m_baseOffset == m_extentOffset;
@@ -625,7 +667,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
         setEndOffset(m_baseOffset);
     }
 #else
-    if (expandTo == CHARACTER) {
+    if (granularity == CHARACTER) {
         if (m_baseIsStart) {
             setStartNode(m_baseNode);
             setStartOffset(m_baseOffset);
@@ -639,7 +681,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             setEndOffset(m_baseOffset);
         }
     }
-    else if (expandTo == WORD) {
+    else if (granularity == WORD) {
         int baseStartOffset = m_baseOffset;
         int baseEndOffset = m_baseOffset;
         int extentStartOffset = m_extentOffset;
@@ -648,13 +690,13 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             DOMString t = m_baseNode->nodeValue();
             QChar *chars = t.unicode();
             uint len = t.length();
-            findWordBoundary(chars, len, m_baseOffset, &baseStartOffset, &baseEndOffset);
+            KWQFindWordBoundary(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);
+            KWQFindWordBoundary(chars, len, m_extentOffset, &extentStartOffset, &extentEndOffset);
         }
         if (m_baseIsStart) {
             setStartNode(m_baseNode);
@@ -669,7 +711,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             setEndOffset(baseEndOffset);
         }
     }
-    else {  // expandTo == LINE
+    else {  // granularity == LINE
         KHTMLSelection baseSelection = *this;
         KHTMLSelection extentSelection = *this;
         if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
@@ -822,55 +864,6 @@ bool KHTMLSelection::nodeIsBeforeNode(NodeImpl *n1, NodeImpl *n2)
 
 #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()) {
diff --git a/WebCore/khtml/editing/SelectionController.h b/WebCore/khtml/editing/SelectionController.h
index f96e49a..326a0ea 100644
--- a/WebCore/khtml/editing/SelectionController.h
+++ b/WebCore/khtml/editing/SelectionController.h
@@ -64,7 +64,7 @@ public:
     void moveTo(const KHTMLSelection &);
     void moveTo(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset);
     bool modify(EAlter, EDirection, ETextGranularity);
-    void expandToElement(ETextGranularity);
+    bool expandUsingGranularity(ETextGranularity);
     void clear();
 
     bool moveToRenderedContent();
@@ -108,8 +108,10 @@ public:
     friend class KHTMLPart;
 
 private:
+	enum EPositionType { START, END, BASE, EXTENT };
+
     void init();
-    void validate(ETextGranularity expandTo=CHARACTER);
+    void validate(ETextGranularity granularity=CHARACTER);
 
     void layoutCaret();
     void needsCaretRepaint();
@@ -129,7 +131,7 @@ private:
     bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
 
     void calculateStartAndEnd(ETextGranularity select=CHARACTER);
-    int xPosForVerticalArrowNavigation() const;
+    int xPosForVerticalArrowNavigation(EPositionType, bool recalc=false) const;
     
     DOM::NodeImpl *m_baseNode;    // base node for the selection
     long m_baseOffset;            // offset into base node where selection is
diff --git a/WebCore/khtml/editing/selection.cpp b/WebCore/khtml/editing/selection.cpp
index 96d50e2..82dc803 100644
--- a/WebCore/khtml/editing/selection.cpp
+++ b/WebCore/khtml/editing/selection.cpp
@@ -46,6 +46,7 @@
 
 #if APPLE_CHANGES
 #include <KWQAssertions.h>
+#include <KWQTextUtilities.h>
 #include <CoreServices/CoreServices.h>
 
 #define EDIT_DEBUG 0
@@ -65,7 +66,6 @@ using khtml::RenderObject;
 using khtml::RenderText;
 
 #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);
@@ -250,7 +250,7 @@ void KHTMLSelection::moveTo(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeI
 	validate();
 }
 
-bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
+bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity granularity)
 {
     DOMPosition pos;
     
@@ -258,76 +258,98 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
         // EDIT FIXME: This needs to handle bidi
         case RIGHT:
         case FORWARD:
-            switch (elem) {
-                case CHARACTER:
-                    if (alter == EXTEND) {
-                        if (!m_modifyBiasSet) {
-                            m_modifyBiasSet = true;
-                            setBaseNode(startNode());
-                            setBaseOffset(startOffset());
-                            setExtentNode(endNode());
-                            setExtentOffset(endOffset());
-                        }
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(startNode());
+                    setBaseOffset(startOffset());
+                    setExtentNode(endNode());
+                    setExtentOffset(endOffset());
+                }
+                if (granularity == CHARACTER)
+                    pos = extentPosition().nextCharacterPosition();
+                else if (granularity == WORD)
+                    pos = extentPosition().nextWordPosition();
+            }
+            else {
+                m_modifyBiasSet = false;
+                if (state() == RANGE) {
+                    if (granularity == CHARACTER)
+                        pos = endPosition();
+                    else if (granularity == WORD)
+                        pos = extentPosition().nextWordPosition();
+                }
+                else {
+                    if (granularity == CHARACTER)
                         pos = extentPosition().nextCharacterPosition();
-                    }
-                    else {
-                        m_modifyBiasSet = false;
-                        if (state() == RANGE)
-                            pos = endPosition();
-                        else
-                            pos = endPosition().nextCharacterPosition();
-                    }
-                    break;
-                case WORD:
-                    // EDIT FIXME: implement
-                    break;
-                case LINE:
-                    // EDIT FIXME: implement
-                    break;
+                    else if (granularity == WORD)
+                        pos = extentPosition().nextWordPosition();
+                }
             }
             break;
         // EDIT FIXME: This needs to handle bidi
         case LEFT:
         case BACKWARD:
-            switch (elem) {
-                case CHARACTER:
-                    if (alter == EXTEND) {
-                        if (!m_modifyBiasSet) {
-                            m_modifyBiasSet = true;
-                            setBaseNode(endNode());
-                            setBaseOffset(endOffset());
-                            setExtentNode(startNode());
-                            setExtentOffset(startOffset());
-                        }
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(endNode());
+                    setBaseOffset(endOffset());
+                    setExtentNode(startNode());
+                    setExtentOffset(startOffset());
+                }
+                if (granularity == CHARACTER)
+                    pos = extentPosition().previousCharacterPosition();
+                else if (granularity == WORD)
+                    pos = extentPosition().previousWordPosition();
+            }
+            else {
+                m_modifyBiasSet = false;
+                if (state() == RANGE) {
+                    if (granularity == CHARACTER)
+                        pos = startPosition();
+                    else if (granularity == WORD)
+                        pos = extentPosition().previousWordPosition();
+                }
+                else {
+                    if (granularity == CHARACTER)
                         pos = extentPosition().previousCharacterPosition();
-                    }
-                    else {
-                        m_modifyBiasSet = false;
-                        if (state() == RANGE)
-                            pos = startPosition();
-                        else
-                            pos = startPosition().previousCharacterPosition();
-                    }
-                    break;
-                case WORD:
-                    // EDIT FIXME: implement
-                    break;
-                case LINE:
-                    // EDIT FIXME: implement
-                    break;
+                    else if (granularity == WORD)
+                        pos = extentPosition().previousWordPosition();
+                }
             }
             break;
         case UP:
-            if (alter == EXTEND)
-                ERROR("unimplemented");
-            else
-                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation());
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(endNode());
+                    setBaseOffset(endOffset());
+                    setExtentNode(startNode());
+                    setExtentOffset(startOffset());
+                }
+                pos = extentPosition().previousLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+            }
+            else {
+                m_modifyBiasSet = false;
+                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation(START, state()==RANGE));
+            }
             break;
         case DOWN:
-            if (alter == EXTEND)
-                ERROR("unimplemented");
-            else
-                pos = startPosition().nextLinePosition(xPosForVerticalArrowNavigation());
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(startNode());
+                    setBaseOffset(startOffset());
+                    setExtentNode(endNode());
+                    setExtentOffset(endOffset());
+                }
+                pos = extentPosition().nextLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+            }
+            else {
+                m_modifyBiasSet = false;
+                pos = endPosition().nextLinePosition(xPosForVerticalArrowNavigation(END, state()==RANGE));
+            }
             break;
     }
     
@@ -342,25 +364,45 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
     return true;
 }
 
-void KHTMLSelection::expandToElement(ETextGranularity select)
+bool KHTMLSelection::expandUsingGranularity(ETextGranularity granularity)
 {
-    validate(select);
+    if (state() == NONE)
+        return false;
+        
+    validate(granularity);
+    return true;
 }
 
-int KHTMLSelection::xPosForVerticalArrowNavigation() const
+int KHTMLSelection::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) const
 {
     int x = 0;
 
     if (state() == NONE)
         return x;
 
-    KHTMLPart *part = startPosition().node()->getDocument()->part();
+    DOMPosition pos;
+    switch (type) {
+        case START:
+            pos = startPosition();
+            break;
+        case END:
+            pos = endPosition();
+            break;
+        case BASE:
+            pos = basePosition();
+            break;
+        case EXTENT:
+            pos = extentPosition();
+            break;
+    }
+
+    KHTMLPart *part = pos.node()->getDocument()->part();
     if (!part)
         return x;
         
-    if (part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
+    if (recalc || part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
         int y, w, h;
-        startPosition().node()->renderer()->caretPos(startPosition().offset(), true, x, y, w, h);
+        pos.node()->renderer()->caretPos(pos.offset(), true, x, y, w, h);
         part->setXPosForVerticalArrowNavigation(x);
     }
     else {
@@ -561,7 +603,7 @@ void KHTMLSelection::setEndOffset(long offset)
 	m_endOffset = offset;
 }
 
-void KHTMLSelection::validate(ETextGranularity expandTo)
+void KHTMLSelection::validate(ETextGranularity granularity)
 {
     // move the base and extent nodes to their equivalent leaf positions
     bool baseAndExtentEqual = m_baseNode == m_extentNode && m_baseOffset == m_extentOffset;
@@ -625,7 +667,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
         setEndOffset(m_baseOffset);
     }
 #else
-    if (expandTo == CHARACTER) {
+    if (granularity == CHARACTER) {
         if (m_baseIsStart) {
             setStartNode(m_baseNode);
             setStartOffset(m_baseOffset);
@@ -639,7 +681,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             setEndOffset(m_baseOffset);
         }
     }
-    else if (expandTo == WORD) {
+    else if (granularity == WORD) {
         int baseStartOffset = m_baseOffset;
         int baseEndOffset = m_baseOffset;
         int extentStartOffset = m_extentOffset;
@@ -648,13 +690,13 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             DOMString t = m_baseNode->nodeValue();
             QChar *chars = t.unicode();
             uint len = t.length();
-            findWordBoundary(chars, len, m_baseOffset, &baseStartOffset, &baseEndOffset);
+            KWQFindWordBoundary(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);
+            KWQFindWordBoundary(chars, len, m_extentOffset, &extentStartOffset, &extentEndOffset);
         }
         if (m_baseIsStart) {
             setStartNode(m_baseNode);
@@ -669,7 +711,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             setEndOffset(baseEndOffset);
         }
     }
-    else {  // expandTo == LINE
+    else {  // granularity == LINE
         KHTMLSelection baseSelection = *this;
         KHTMLSelection extentSelection = *this;
         if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
@@ -822,55 +864,6 @@ bool KHTMLSelection::nodeIsBeforeNode(NodeImpl *n1, NodeImpl *n2)
 
 #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()) {
diff --git a/WebCore/khtml/editing/selection.h b/WebCore/khtml/editing/selection.h
index f96e49a..326a0ea 100644
--- a/WebCore/khtml/editing/selection.h
+++ b/WebCore/khtml/editing/selection.h
@@ -64,7 +64,7 @@ public:
     void moveTo(const KHTMLSelection &);
     void moveTo(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset);
     bool modify(EAlter, EDirection, ETextGranularity);
-    void expandToElement(ETextGranularity);
+    bool expandUsingGranularity(ETextGranularity);
     void clear();
 
     bool moveToRenderedContent();
@@ -108,8 +108,10 @@ public:
     friend class KHTMLPart;
 
 private:
+	enum EPositionType { START, END, BASE, EXTENT };
+
     void init();
-    void validate(ETextGranularity expandTo=CHARACTER);
+    void validate(ETextGranularity granularity=CHARACTER);
 
     void layoutCaret();
     void needsCaretRepaint();
@@ -129,7 +131,7 @@ private:
     bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
 
     void calculateStartAndEnd(ETextGranularity select=CHARACTER);
-    int xPosForVerticalArrowNavigation() const;
+    int xPosForVerticalArrowNavigation(EPositionType, bool recalc=false) const;
     
     DOM::NodeImpl *m_baseNode;    // base node for the selection
     long m_baseOffset;            // offset into base node where selection is
diff --git a/WebCore/khtml/khtml_part.cpp b/WebCore/khtml/khtml_part.cpp
index cb13fca..1ae0d19 100644
--- a/WebCore/khtml/khtml_part.cpp
+++ b/WebCore/khtml/khtml_part.cpp
@@ -4544,7 +4544,7 @@ void KHTMLPart::handleMousePressEventDoubleClick(khtml::MousePressEvent *event)
         DOMPosition pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()));
         if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) {
             selection.moveTo(pos);
-            selection.expandToElement(KHTMLSelection::WORD);
+            selection.expandUsingGranularity(KHTMLSelection::WORD);
         }
     }
     
@@ -4567,7 +4567,7 @@ void KHTMLPart::handleMousePressEventTripleClick(khtml::MousePressEvent *event)
         DOMPosition pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()));
         if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) {
             selection.moveTo(pos);
-            selection.expandToElement(KHTMLSelection::LINE);
+            selection.expandUsingGranularity(KHTMLSelection::LINE);
         }
     }
     
@@ -4818,7 +4818,7 @@ void KHTMLPart::handleMouseMoveEventSelection(khtml::MouseMoveEvent *event)
 
 #if APPLE_CHANGES
     if (d->m_textElement != KHTMLSelection::CHARACTER) {
-        sel.expandToElement(d->m_textElement);
+        sel.expandUsingGranularity(d->m_textElement);
     }
 #endif    
 
diff --git a/WebCore/khtml/khtml_selection.cpp b/WebCore/khtml/khtml_selection.cpp
index 96d50e2..82dc803 100644
--- a/WebCore/khtml/khtml_selection.cpp
+++ b/WebCore/khtml/khtml_selection.cpp
@@ -46,6 +46,7 @@
 
 #if APPLE_CHANGES
 #include <KWQAssertions.h>
+#include <KWQTextUtilities.h>
 #include <CoreServices/CoreServices.h>
 
 #define EDIT_DEBUG 0
@@ -65,7 +66,6 @@ using khtml::RenderObject;
 using khtml::RenderText;
 
 #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);
@@ -250,7 +250,7 @@ void KHTMLSelection::moveTo(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeI
 	validate();
 }
 
-bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
+bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity granularity)
 {
     DOMPosition pos;
     
@@ -258,76 +258,98 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
         // EDIT FIXME: This needs to handle bidi
         case RIGHT:
         case FORWARD:
-            switch (elem) {
-                case CHARACTER:
-                    if (alter == EXTEND) {
-                        if (!m_modifyBiasSet) {
-                            m_modifyBiasSet = true;
-                            setBaseNode(startNode());
-                            setBaseOffset(startOffset());
-                            setExtentNode(endNode());
-                            setExtentOffset(endOffset());
-                        }
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(startNode());
+                    setBaseOffset(startOffset());
+                    setExtentNode(endNode());
+                    setExtentOffset(endOffset());
+                }
+                if (granularity == CHARACTER)
+                    pos = extentPosition().nextCharacterPosition();
+                else if (granularity == WORD)
+                    pos = extentPosition().nextWordPosition();
+            }
+            else {
+                m_modifyBiasSet = false;
+                if (state() == RANGE) {
+                    if (granularity == CHARACTER)
+                        pos = endPosition();
+                    else if (granularity == WORD)
+                        pos = extentPosition().nextWordPosition();
+                }
+                else {
+                    if (granularity == CHARACTER)
                         pos = extentPosition().nextCharacterPosition();
-                    }
-                    else {
-                        m_modifyBiasSet = false;
-                        if (state() == RANGE)
-                            pos = endPosition();
-                        else
-                            pos = endPosition().nextCharacterPosition();
-                    }
-                    break;
-                case WORD:
-                    // EDIT FIXME: implement
-                    break;
-                case LINE:
-                    // EDIT FIXME: implement
-                    break;
+                    else if (granularity == WORD)
+                        pos = extentPosition().nextWordPosition();
+                }
             }
             break;
         // EDIT FIXME: This needs to handle bidi
         case LEFT:
         case BACKWARD:
-            switch (elem) {
-                case CHARACTER:
-                    if (alter == EXTEND) {
-                        if (!m_modifyBiasSet) {
-                            m_modifyBiasSet = true;
-                            setBaseNode(endNode());
-                            setBaseOffset(endOffset());
-                            setExtentNode(startNode());
-                            setExtentOffset(startOffset());
-                        }
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(endNode());
+                    setBaseOffset(endOffset());
+                    setExtentNode(startNode());
+                    setExtentOffset(startOffset());
+                }
+                if (granularity == CHARACTER)
+                    pos = extentPosition().previousCharacterPosition();
+                else if (granularity == WORD)
+                    pos = extentPosition().previousWordPosition();
+            }
+            else {
+                m_modifyBiasSet = false;
+                if (state() == RANGE) {
+                    if (granularity == CHARACTER)
+                        pos = startPosition();
+                    else if (granularity == WORD)
+                        pos = extentPosition().previousWordPosition();
+                }
+                else {
+                    if (granularity == CHARACTER)
                         pos = extentPosition().previousCharacterPosition();
-                    }
-                    else {
-                        m_modifyBiasSet = false;
-                        if (state() == RANGE)
-                            pos = startPosition();
-                        else
-                            pos = startPosition().previousCharacterPosition();
-                    }
-                    break;
-                case WORD:
-                    // EDIT FIXME: implement
-                    break;
-                case LINE:
-                    // EDIT FIXME: implement
-                    break;
+                    else if (granularity == WORD)
+                        pos = extentPosition().previousWordPosition();
+                }
             }
             break;
         case UP:
-            if (alter == EXTEND)
-                ERROR("unimplemented");
-            else
-                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation());
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(endNode());
+                    setBaseOffset(endOffset());
+                    setExtentNode(startNode());
+                    setExtentOffset(startOffset());
+                }
+                pos = extentPosition().previousLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+            }
+            else {
+                m_modifyBiasSet = false;
+                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation(START, state()==RANGE));
+            }
             break;
         case DOWN:
-            if (alter == EXTEND)
-                ERROR("unimplemented");
-            else
-                pos = startPosition().nextLinePosition(xPosForVerticalArrowNavigation());
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(startNode());
+                    setBaseOffset(startOffset());
+                    setExtentNode(endNode());
+                    setExtentOffset(endOffset());
+                }
+                pos = extentPosition().nextLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+            }
+            else {
+                m_modifyBiasSet = false;
+                pos = endPosition().nextLinePosition(xPosForVerticalArrowNavigation(END, state()==RANGE));
+            }
             break;
     }
     
@@ -342,25 +364,45 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
     return true;
 }
 
-void KHTMLSelection::expandToElement(ETextGranularity select)
+bool KHTMLSelection::expandUsingGranularity(ETextGranularity granularity)
 {
-    validate(select);
+    if (state() == NONE)
+        return false;
+        
+    validate(granularity);
+    return true;
 }
 
-int KHTMLSelection::xPosForVerticalArrowNavigation() const
+int KHTMLSelection::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) const
 {
     int x = 0;
 
     if (state() == NONE)
         return x;
 
-    KHTMLPart *part = startPosition().node()->getDocument()->part();
+    DOMPosition pos;
+    switch (type) {
+        case START:
+            pos = startPosition();
+            break;
+        case END:
+            pos = endPosition();
+            break;
+        case BASE:
+            pos = basePosition();
+            break;
+        case EXTENT:
+            pos = extentPosition();
+            break;
+    }
+
+    KHTMLPart *part = pos.node()->getDocument()->part();
     if (!part)
         return x;
         
-    if (part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
+    if (recalc || part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
         int y, w, h;
-        startPosition().node()->renderer()->caretPos(startPosition().offset(), true, x, y, w, h);
+        pos.node()->renderer()->caretPos(pos.offset(), true, x, y, w, h);
         part->setXPosForVerticalArrowNavigation(x);
     }
     else {
@@ -561,7 +603,7 @@ void KHTMLSelection::setEndOffset(long offset)
 	m_endOffset = offset;
 }
 
-void KHTMLSelection::validate(ETextGranularity expandTo)
+void KHTMLSelection::validate(ETextGranularity granularity)
 {
     // move the base and extent nodes to their equivalent leaf positions
     bool baseAndExtentEqual = m_baseNode == m_extentNode && m_baseOffset == m_extentOffset;
@@ -625,7 +667,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
         setEndOffset(m_baseOffset);
     }
 #else
-    if (expandTo == CHARACTER) {
+    if (granularity == CHARACTER) {
         if (m_baseIsStart) {
             setStartNode(m_baseNode);
             setStartOffset(m_baseOffset);
@@ -639,7 +681,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             setEndOffset(m_baseOffset);
         }
     }
-    else if (expandTo == WORD) {
+    else if (granularity == WORD) {
         int baseStartOffset = m_baseOffset;
         int baseEndOffset = m_baseOffset;
         int extentStartOffset = m_extentOffset;
@@ -648,13 +690,13 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             DOMString t = m_baseNode->nodeValue();
             QChar *chars = t.unicode();
             uint len = t.length();
-            findWordBoundary(chars, len, m_baseOffset, &baseStartOffset, &baseEndOffset);
+            KWQFindWordBoundary(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);
+            KWQFindWordBoundary(chars, len, m_extentOffset, &extentStartOffset, &extentEndOffset);
         }
         if (m_baseIsStart) {
             setStartNode(m_baseNode);
@@ -669,7 +711,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             setEndOffset(baseEndOffset);
         }
     }
-    else {  // expandTo == LINE
+    else {  // granularity == LINE
         KHTMLSelection baseSelection = *this;
         KHTMLSelection extentSelection = *this;
         if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
@@ -822,55 +864,6 @@ bool KHTMLSelection::nodeIsBeforeNode(NodeImpl *n1, NodeImpl *n2)
 
 #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()) {
diff --git a/WebCore/khtml/khtml_selection.h b/WebCore/khtml/khtml_selection.h
index f96e49a..326a0ea 100644
--- a/WebCore/khtml/khtml_selection.h
+++ b/WebCore/khtml/khtml_selection.h
@@ -64,7 +64,7 @@ public:
     void moveTo(const KHTMLSelection &);
     void moveTo(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset);
     bool modify(EAlter, EDirection, ETextGranularity);
-    void expandToElement(ETextGranularity);
+    bool expandUsingGranularity(ETextGranularity);
     void clear();
 
     bool moveToRenderedContent();
@@ -108,8 +108,10 @@ public:
     friend class KHTMLPart;
 
 private:
+	enum EPositionType { START, END, BASE, EXTENT };
+
     void init();
-    void validate(ETextGranularity expandTo=CHARACTER);
+    void validate(ETextGranularity granularity=CHARACTER);
 
     void layoutCaret();
     void needsCaretRepaint();
@@ -129,7 +131,7 @@ private:
     bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
 
     void calculateStartAndEnd(ETextGranularity select=CHARACTER);
-    int xPosForVerticalArrowNavigation() const;
+    int xPosForVerticalArrowNavigation(EPositionType, bool recalc=false) const;
     
     DOM::NodeImpl *m_baseNode;    // base node for the selection
     long m_baseOffset;            // offset into base node where selection is
diff --git a/WebCore/khtml/misc/helper.cpp b/WebCore/khtml/misc/helper.cpp
index 7bae657..607b703 100644
--- a/WebCore/khtml/misc/helper.cpp
+++ b/WebCore/khtml/misc/helper.cpp
@@ -23,9 +23,22 @@
 
 #include "helper.h"
 
+#if APPLE_CHANGES
+#include "KWQTextUtilities.h"
+#endif
+
 QPainter *khtml::printpainter = 0;
 
 void khtml::setPrintPainter( QPainter *printer )
 {
     printpainter = printer;
 }
+
+void khtml::findWordBoundary(QChar *chars, int len, int position, int *start, int *end)
+{
+#if APPLE_CHANGES
+    KWQFindWordBoundary(chars, len, position, start, end);
+#else
+    // KDE implementation
+#endif
+}
\ No newline at end of file
diff --git a/WebCore/khtml/misc/helper.h b/WebCore/khtml/misc/helper.h
index 537032e..a4622cd 100644
--- a/WebCore/khtml/misc/helper.h
+++ b/WebCore/khtml/misc/helper.h
@@ -22,8 +22,10 @@
 #ifndef html_helper_h
 #define html_helper_h
 
-#include <qcolor.h>
 class QPainter;
+class QChar;
+
+#include <qcolor.h>
 #include <qfontmetrics.h>
 #include <qfont.h>
 
@@ -44,6 +46,10 @@ namespace khtml
 			       // to get BiDi contexts right.
 			       SelectionPointBeforeInLine,
 			       SelectionPointAfterInLine };
+
+
+ 
+    void findWordBoundary(QChar *chars, int len, int position, int *start, int *end);
 };
 
 #endif
diff --git a/WebCore/khtml/rendering/render_block.cpp b/WebCore/khtml/rendering/render_block.cpp
index 33dde28..f04a45b 100644
--- a/WebCore/khtml/rendering/render_block.cpp
+++ b/WebCore/khtml/rendering/render_block.cpp
@@ -2085,36 +2085,9 @@ DOMPosition RenderBlock::positionForCoordinates(int _x, int _y)
                 bottom = absy + root->bottomOverflow();
             // check if this root line box is located at this y coordinate
             if (_y >= top && _y < bottom && root->firstChild()) {
-                InlineBox *closestBox = 0;
-                bool useClosestBoxLeftEdge = true;
-
-                if (_x <= absx + root->firstChild()->m_x) {
-                    // if the x coordinate is to the left of the root box's first child, 
-                    // make the first child closest
-                    closestBox = root->firstChild(); 
-                }
-                else if (_x >= absx + root->lastChild()->m_x + root->lastChild()->m_width) {
-                    // if the x coordinate is to the right of the root box's last child, 
-                    // make the last child closest
-                    closestBox = root->lastChild(); 
-                    useClosestBoxLeftEdge = false;
-                }
-                else {
-                    // look for the closest child for this root;
-                    // check only the right edges, since the left edge of the first
-                    // box has already been checked
-                    for (InlineBox *box = root->firstChild(); box; box = box->nextOnLine()) {
-                        if (_x < absx + box->m_x + box->m_width) { 
-                            closestBox = box; 
-                            useClosestBoxLeftEdge = false;
-                            break;
-                        }
-                    }
-                }
-                if (closestBox) {
-                    RenderObject *renderer = useClosestBoxLeftEdge ? closestBox->firstLeafChild()->object() : closestBox->lastLeafChild()->object();
-                    return renderer->positionForCoordinates(_x, _y);
-                }
+                InlineBox *closestBox = root->closestLeafChildForXPos(_x, absx);
+                if (closestBox)
+                    return closestBox->object()->positionForCoordinates(_x, _y);
             }
         }
         return DOMPosition(element(), 0);
diff --git a/WebCore/khtml/rendering/render_line.cpp b/WebCore/khtml/rendering/render_line.cpp
index 4859d66..a5f52aa 100644
--- a/WebCore/khtml/rendering/render_line.cpp
+++ b/WebCore/khtml/rendering/render_line.cpp
@@ -759,6 +759,41 @@ InlineBox* InlineFlowBox::lastLeafChild()
     return box;
 }
 
+InlineBox* InlineFlowBox::closestChildForXPos(int _x, int _tx)
+{
+    if (_x < _tx + firstChild()->m_x)
+        // if the x coordinate is to the left of the first child
+        return firstChild(); 
+    else if (_x >= _tx + lastChild()->m_x + lastChild()->m_width)
+        // if the x coordinate is to the right of the last child
+        return lastChild(); 
+    else
+        // look for the closest child;
+        // check only the right edges, since the left edge of the first
+        // box has already been checked
+        for (InlineBox *box = firstChild(); box; box = box->nextOnLine())
+            if (_x < _tx + box->m_x + box->m_width)
+                return box;
+
+    return 0;
+}
+
+InlineBox* InlineBox::closestLeafChildForXPos(int _x, int _tx)
+{
+    if (!isInlineFlowBox())
+        return this;
+    
+    InlineFlowBox *flowBox = static_cast<InlineFlowBox*>(this);
+    if (!flowBox->firstChild())
+        return this;
+
+    InlineBox *box = flowBox->closestChildForXPos(_x, _tx);
+    if (!box)
+        return this;
+    
+    return box->closestLeafChildForXPos(_x, _tx);
+}
+
 void RootInlineBox::adjustVerticalPosition(int delta)
 {
     InlineFlowBox::adjustVerticalPosition(delta);
@@ -778,4 +813,3 @@ void RootInlineBox::childRemoved(InlineBox* box)
         prev->markDirty();
     }
 }
-
diff --git a/WebCore/khtml/rendering/render_line.h b/WebCore/khtml/rendering/render_line.h
index 7052ceb..970393b 100644
--- a/WebCore/khtml/rendering/render_line.h
+++ b/WebCore/khtml/rendering/render_line.h
@@ -92,6 +92,7 @@ public:
 
     virtual InlineBox* firstLeafChild();
     virtual InlineBox* lastLeafChild();
+    InlineBox* closestLeafChildForXPos(int _x, int _tx);
         
     RenderObject* object() const { return m_object; }
 
@@ -195,6 +196,7 @@ public:
 
     virtual InlineBox* firstLeafChild();
     virtual InlineBox* lastLeafChild();
+    InlineBox* closestChildForXPos(int _x, int _tx);
         
     virtual void setConstructed() {
         InlineBox::setConstructed();
diff --git a/WebCore/khtml/rendering/render_replaced.cpp b/WebCore/khtml/rendering/render_replaced.cpp
index 6ec4711..b993a7e 100644
--- a/WebCore/khtml/rendering/render_replaced.cpp
+++ b/WebCore/khtml/rendering/render_replaced.cpp
@@ -137,10 +137,10 @@ DOMPosition RenderReplaced::positionForCoordinates(int _x, int _y)
     RootInlineBox *root = box->root();
 
     int absx, absy;
-    absolutePosition(absx, absy);
+    containingBlock()->absolutePosition(absx, absy);
 
     int top = absy + root->topOverflow();
-    int bottom = absy + root->bottomOverflow();
+    int bottom = root->nextRootBox() ? absy + root->nextRootBox()->topOverflow() : absy + root->bottomOverflow();
 
     if (_y < top)
         return DOMPosition(element(), caretMinOffset()); // coordinates are above
@@ -149,7 +149,7 @@ DOMPosition RenderReplaced::positionForCoordinates(int _x, int _y)
         return DOMPosition(element(), caretMaxOffset()); // coordinates are below
     
     if (element()) {
-        if (_x <= absx + (width() / 2))
+        if (_x <= absx + xPos() + (width() / 2))
             return DOMPosition(element(), 0);
         return DOMPosition(element(), 1);
     }
diff --git a/WebCore/khtml/rendering/render_text.cpp b/WebCore/khtml/rendering/render_text.cpp
index 7db9f66..68a73c4 100644
--- a/WebCore/khtml/rendering/render_text.cpp
+++ b/WebCore/khtml/rendering/render_text.cpp
@@ -445,12 +445,12 @@ DOMPosition RenderText::positionForCoordinates(int _x, int _y)
         return DOMPosition(element(), 0);
 
     int absx, absy;
-    absolutePosition(absx, absy);
+    containingBlock()->absolutePosition(absx, absy);
 
     if (firstTextBox() && _y < absy + firstTextBox()->root()->bottomOverflow() && _x < absx + firstTextBox()->m_x) {
         // at the y coordinate of the first line or above
         // and the x coordinate is to the left than the first text box left edge
-        return DOMPosition(element(), lastTextBox()->m_start);
+        return DOMPosition(element(), firstTextBox()->m_start);
     }
 
     if (lastTextBox() && _y >= absy + lastTextBox()->root()->topOverflow() && _x >= absx + lastTextBox()->m_x + lastTextBox()->m_width) {
diff --git a/WebCore/khtml/xml/dom_position.cpp b/WebCore/khtml/xml/dom_position.cpp
index f5aef10..f25cfa3 100644
--- a/WebCore/khtml/xml/dom_position.cpp
+++ b/WebCore/khtml/xml/dom_position.cpp
@@ -25,7 +25,9 @@
 
 #include "dom_position.h"
 
+#include "helper.h"
 #include "htmltags.h"
+#include "qstring.h"
 #include "rendering/render_block.h"
 #include "rendering/render_line.h"
 #include "rendering/render_object.h"
@@ -45,6 +47,7 @@ using DOM::NodeImpl;
 using khtml::InlineBox;
 using khtml::InlineFlowBox;
 using khtml::InlineTextBox;
+using khtml::RenderBlock;
 using khtml::RenderObject;
 using khtml::RenderText;
 using khtml::RootInlineBox;
@@ -298,6 +301,58 @@ DOMPosition DOMPosition::nextCharacterPosition() const
     return *this;
 }
 
+DOMPosition DOMPosition::previousWordPosition() const
+{
+    if (isEmpty())
+        return DOMPosition();
+
+    DOMPosition pos = *this;
+    for (EditIterator it(*this); !it.atStart(); it.previous()) {
+        if (it.current().node()->nodeType() == Node::TEXT_NODE || it.current().node()->nodeType() == Node::CDATA_SECTION_NODE) {
+            DOMString t = it.current().node()->nodeValue();
+            QChar *chars = t.unicode();
+            uint len = t.length();
+            int start, end;
+            khtml::findWordBoundary(chars, len, it.current().offset(), &start, &end);
+            pos = DOMPosition(it.current().node(), start);
+        }
+        else {
+            pos = DOMPosition(it.current().node(), it.current().node()->caretMinOffset());
+        }
+        if (pos != *this)
+            return pos;
+        it.setPosition(pos);
+    }
+    
+    return *this;
+}
+
+DOMPosition DOMPosition::nextWordPosition() const
+{
+    if (isEmpty())
+        return DOMPosition();
+
+    DOMPosition pos = *this;
+    for (EditIterator it(*this); !it.atEnd(); it.next()) {
+        if (it.current().node()->nodeType() == Node::TEXT_NODE || it.current().node()->nodeType() == Node::CDATA_SECTION_NODE) {
+            DOMString t = it.current().node()->nodeValue();
+            QChar *chars = t.unicode();
+            uint len = t.length();
+            int start, end;
+            khtml::findWordBoundary(chars, len, it.current().offset(), &start, &end);
+            pos = DOMPosition(it.current().node(), end);
+        }
+        else {
+            pos = DOMPosition(it.current().node(), it.current().node()->caretMaxOffset());
+        }
+        if (pos != *this)
+            return pos;
+        it.setPosition(pos);
+    }
+    
+    return *this;
+}
+
 DOMPosition DOMPosition::previousLinePosition(int x) const
 {
     if (!node())
@@ -310,10 +365,10 @@ DOMPosition DOMPosition::previousLinePosition(int x) const
     if (!box)
         return *this;
 
-    NodeImpl *previousLineNode = 0;
+    RenderBlock *containingBlock = 0;
     RootInlineBox *root = box->root()->prevRootBox();
     if (root) {
-        previousLineNode = node();
+        containingBlock = node()->renderer()->containingBlock();
     }
     else {
         // This containing editable block does not have a previous line.
@@ -331,26 +386,19 @@ DOMPosition DOMPosition::previousLinePosition(int x) const
                 ASSERT(box);
                 // previous root line box found
                 root = box->root();
-                previousLineNode = n;
+                containingBlock = n->renderer()->containingBlock();
             }
         }
     }
     
-    if (!root)
-        return *this;
-    ASSERT(previousLineNode);
-    
-    int absx, absy;
-    previousLineNode->renderer()->containingBlock()->absolutePosition(absx, absy);
-    int y = absy + root->topOverflow() + ((root->bottomOverflow() - root->topOverflow()) / 2);
-
-    RenderObject::NodeInfo nodeInfo(true, true);
-    previousLineNode->getDocument()->renderer()->layer()->nodeAtPoint(nodeInfo, x, y);
-
-    if (!nodeInfo.innerNode() || !nodeInfo.innerNode()->renderer())
-        return *this;
+    if (root) {
+        int absx, absy;
+        containingBlock->absolutePosition(absx, absy);
+        RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
+        return renderer->positionForCoordinates(x, absy + root->topOverflow());
+    }
     
-    return nodeInfo.innerNode()->renderer()->positionForCoordinates(x, y);
+    return *this;
 }
 
 DOMPosition DOMPosition::nextLinePosition(int x) const
@@ -365,10 +413,10 @@ DOMPosition DOMPosition::nextLinePosition(int x) const
     if (!box)
         return *this;
 
-    NodeImpl *nextLineNode = 0;
+    RenderBlock *containingBlock = 0;
     RootInlineBox *root = box->root()->nextRootBox();
     if (root) {
-        nextLineNode = node();
+        containingBlock = node()->renderer()->containingBlock();
     }
     else {
         // This containing editable block does not have a next line.
@@ -386,25 +434,19 @@ DOMPosition DOMPosition::nextLinePosition(int x) const
                 ASSERT(box);
                 // previous root line box found
                 root = box->root();
-                nextLineNode = n;
+                containingBlock = n->renderer()->containingBlock();
             }
         }
     }
     
-    if (!root)
-        return *this;
-    ASSERT(nextLineNode);
-    
-    int absx, absy;
-    nextLineNode->renderer()->containingBlock()->absolutePosition(absx, absy);
-    int y = absy + root->topOverflow() + ((root->bottomOverflow() - root->topOverflow()) / 2);
-    
-    RenderObject::NodeInfo nodeInfo(true, true);
-    nextLineNode->getDocument()->renderer()->layer()->nodeAtPoint(nodeInfo, x, y);
-    if (!nodeInfo.innerNode() || !nodeInfo.innerNode()->renderer())
-        return *this;
-    
-    return nodeInfo.innerNode()->renderer()->positionForCoordinates(x, y);
+    if (root) {
+        int absx, absy;
+        containingBlock->absolutePosition(absx, absy);
+        RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
+        return renderer->positionForCoordinates(x, absy + root->topOverflow());
+    }
+
+    return *this;
 }
 
 DOMPosition DOMPosition::equivalentUpstreamPosition() const
@@ -825,5 +867,3 @@ bool DOMPosition::inLastEditableInContainingEditableBlock() const
 
     return true;
 }
-
-
diff --git a/WebCore/khtml/xml/dom_position.h b/WebCore/khtml/xml/dom_position.h
index b94c867..13310cf 100644
--- a/WebCore/khtml/xml/dom_position.h
+++ b/WebCore/khtml/xml/dom_position.h
@@ -51,6 +51,8 @@ public:
     DOMPosition nextRenderedEditablePosition() const;
     DOMPosition previousCharacterPosition() const;
     DOMPosition nextCharacterPosition() const;
+    DOMPosition previousWordPosition() const;
+    DOMPosition nextWordPosition() const;
     DOMPosition previousLinePosition(int x) const;
     DOMPosition nextLinePosition(int x) const;
     DOMPosition equivalentUpstreamPosition() const;
diff --git a/WebCore/khtml/xml/dom_selection.cpp b/WebCore/khtml/xml/dom_selection.cpp
index 96d50e2..82dc803 100644
--- a/WebCore/khtml/xml/dom_selection.cpp
+++ b/WebCore/khtml/xml/dom_selection.cpp
@@ -46,6 +46,7 @@
 
 #if APPLE_CHANGES
 #include <KWQAssertions.h>
+#include <KWQTextUtilities.h>
 #include <CoreServices/CoreServices.h>
 
 #define EDIT_DEBUG 0
@@ -65,7 +66,6 @@ using khtml::RenderObject;
 using khtml::RenderText;
 
 #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);
@@ -250,7 +250,7 @@ void KHTMLSelection::moveTo(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeI
 	validate();
 }
 
-bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
+bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity granularity)
 {
     DOMPosition pos;
     
@@ -258,76 +258,98 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
         // EDIT FIXME: This needs to handle bidi
         case RIGHT:
         case FORWARD:
-            switch (elem) {
-                case CHARACTER:
-                    if (alter == EXTEND) {
-                        if (!m_modifyBiasSet) {
-                            m_modifyBiasSet = true;
-                            setBaseNode(startNode());
-                            setBaseOffset(startOffset());
-                            setExtentNode(endNode());
-                            setExtentOffset(endOffset());
-                        }
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(startNode());
+                    setBaseOffset(startOffset());
+                    setExtentNode(endNode());
+                    setExtentOffset(endOffset());
+                }
+                if (granularity == CHARACTER)
+                    pos = extentPosition().nextCharacterPosition();
+                else if (granularity == WORD)
+                    pos = extentPosition().nextWordPosition();
+            }
+            else {
+                m_modifyBiasSet = false;
+                if (state() == RANGE) {
+                    if (granularity == CHARACTER)
+                        pos = endPosition();
+                    else if (granularity == WORD)
+                        pos = extentPosition().nextWordPosition();
+                }
+                else {
+                    if (granularity == CHARACTER)
                         pos = extentPosition().nextCharacterPosition();
-                    }
-                    else {
-                        m_modifyBiasSet = false;
-                        if (state() == RANGE)
-                            pos = endPosition();
-                        else
-                            pos = endPosition().nextCharacterPosition();
-                    }
-                    break;
-                case WORD:
-                    // EDIT FIXME: implement
-                    break;
-                case LINE:
-                    // EDIT FIXME: implement
-                    break;
+                    else if (granularity == WORD)
+                        pos = extentPosition().nextWordPosition();
+                }
             }
             break;
         // EDIT FIXME: This needs to handle bidi
         case LEFT:
         case BACKWARD:
-            switch (elem) {
-                case CHARACTER:
-                    if (alter == EXTEND) {
-                        if (!m_modifyBiasSet) {
-                            m_modifyBiasSet = true;
-                            setBaseNode(endNode());
-                            setBaseOffset(endOffset());
-                            setExtentNode(startNode());
-                            setExtentOffset(startOffset());
-                        }
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(endNode());
+                    setBaseOffset(endOffset());
+                    setExtentNode(startNode());
+                    setExtentOffset(startOffset());
+                }
+                if (granularity == CHARACTER)
+                    pos = extentPosition().previousCharacterPosition();
+                else if (granularity == WORD)
+                    pos = extentPosition().previousWordPosition();
+            }
+            else {
+                m_modifyBiasSet = false;
+                if (state() == RANGE) {
+                    if (granularity == CHARACTER)
+                        pos = startPosition();
+                    else if (granularity == WORD)
+                        pos = extentPosition().previousWordPosition();
+                }
+                else {
+                    if (granularity == CHARACTER)
                         pos = extentPosition().previousCharacterPosition();
-                    }
-                    else {
-                        m_modifyBiasSet = false;
-                        if (state() == RANGE)
-                            pos = startPosition();
-                        else
-                            pos = startPosition().previousCharacterPosition();
-                    }
-                    break;
-                case WORD:
-                    // EDIT FIXME: implement
-                    break;
-                case LINE:
-                    // EDIT FIXME: implement
-                    break;
+                    else if (granularity == WORD)
+                        pos = extentPosition().previousWordPosition();
+                }
             }
             break;
         case UP:
-            if (alter == EXTEND)
-                ERROR("unimplemented");
-            else
-                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation());
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(endNode());
+                    setBaseOffset(endOffset());
+                    setExtentNode(startNode());
+                    setExtentOffset(startOffset());
+                }
+                pos = extentPosition().previousLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+            }
+            else {
+                m_modifyBiasSet = false;
+                pos = startPosition().previousLinePosition(xPosForVerticalArrowNavigation(START, state()==RANGE));
+            }
             break;
         case DOWN:
-            if (alter == EXTEND)
-                ERROR("unimplemented");
-            else
-                pos = startPosition().nextLinePosition(xPosForVerticalArrowNavigation());
+            if (alter == EXTEND) {
+                if (!m_modifyBiasSet) {
+                    m_modifyBiasSet = true;
+                    setBaseNode(startNode());
+                    setBaseOffset(startOffset());
+                    setExtentNode(endNode());
+                    setExtentOffset(endOffset());
+                }
+                pos = extentPosition().nextLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+            }
+            else {
+                m_modifyBiasSet = false;
+                pos = endPosition().nextLinePosition(xPosForVerticalArrowNavigation(END, state()==RANGE));
+            }
             break;
     }
     
@@ -342,25 +364,45 @@ bool KHTMLSelection::modify(EAlter alter, EDirection dir, ETextGranularity elem)
     return true;
 }
 
-void KHTMLSelection::expandToElement(ETextGranularity select)
+bool KHTMLSelection::expandUsingGranularity(ETextGranularity granularity)
 {
-    validate(select);
+    if (state() == NONE)
+        return false;
+        
+    validate(granularity);
+    return true;
 }
 
-int KHTMLSelection::xPosForVerticalArrowNavigation() const
+int KHTMLSelection::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) const
 {
     int x = 0;
 
     if (state() == NONE)
         return x;
 
-    KHTMLPart *part = startPosition().node()->getDocument()->part();
+    DOMPosition pos;
+    switch (type) {
+        case START:
+            pos = startPosition();
+            break;
+        case END:
+            pos = endPosition();
+            break;
+        case BASE:
+            pos = basePosition();
+            break;
+        case EXTENT:
+            pos = extentPosition();
+            break;
+    }
+
+    KHTMLPart *part = pos.node()->getDocument()->part();
     if (!part)
         return x;
         
-    if (part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
+    if (recalc || part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
         int y, w, h;
-        startPosition().node()->renderer()->caretPos(startPosition().offset(), true, x, y, w, h);
+        pos.node()->renderer()->caretPos(pos.offset(), true, x, y, w, h);
         part->setXPosForVerticalArrowNavigation(x);
     }
     else {
@@ -561,7 +603,7 @@ void KHTMLSelection::setEndOffset(long offset)
 	m_endOffset = offset;
 }
 
-void KHTMLSelection::validate(ETextGranularity expandTo)
+void KHTMLSelection::validate(ETextGranularity granularity)
 {
     // move the base and extent nodes to their equivalent leaf positions
     bool baseAndExtentEqual = m_baseNode == m_extentNode && m_baseOffset == m_extentOffset;
@@ -625,7 +667,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
         setEndOffset(m_baseOffset);
     }
 #else
-    if (expandTo == CHARACTER) {
+    if (granularity == CHARACTER) {
         if (m_baseIsStart) {
             setStartNode(m_baseNode);
             setStartOffset(m_baseOffset);
@@ -639,7 +681,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             setEndOffset(m_baseOffset);
         }
     }
-    else if (expandTo == WORD) {
+    else if (granularity == WORD) {
         int baseStartOffset = m_baseOffset;
         int baseEndOffset = m_baseOffset;
         int extentStartOffset = m_extentOffset;
@@ -648,13 +690,13 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             DOMString t = m_baseNode->nodeValue();
             QChar *chars = t.unicode();
             uint len = t.length();
-            findWordBoundary(chars, len, m_baseOffset, &baseStartOffset, &baseEndOffset);
+            KWQFindWordBoundary(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);
+            KWQFindWordBoundary(chars, len, m_extentOffset, &extentStartOffset, &extentEndOffset);
         }
         if (m_baseIsStart) {
             setStartNode(m_baseNode);
@@ -669,7 +711,7 @@ void KHTMLSelection::validate(ETextGranularity expandTo)
             setEndOffset(baseEndOffset);
         }
     }
-    else {  // expandTo == LINE
+    else {  // granularity == LINE
         KHTMLSelection baseSelection = *this;
         KHTMLSelection extentSelection = *this;
         if (m_baseNode && (m_baseNode->nodeType() == Node::TEXT_NODE || m_baseNode->nodeType() == Node::CDATA_SECTION_NODE)) {
@@ -822,55 +864,6 @@ bool KHTMLSelection::nodeIsBeforeNode(NodeImpl *n1, NodeImpl *n2)
 
 #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()) {
diff --git a/WebCore/khtml/xml/dom_selection.h b/WebCore/khtml/xml/dom_selection.h
index f96e49a..326a0ea 100644
--- a/WebCore/khtml/xml/dom_selection.h
+++ b/WebCore/khtml/xml/dom_selection.h
@@ -64,7 +64,7 @@ public:
     void moveTo(const KHTMLSelection &);
     void moveTo(DOM::NodeImpl *baseNode, long baseOffset, DOM::NodeImpl *extentNode, long extentOffset);
     bool modify(EAlter, EDirection, ETextGranularity);
-    void expandToElement(ETextGranularity);
+    bool expandUsingGranularity(ETextGranularity);
     void clear();
 
     bool moveToRenderedContent();
@@ -108,8 +108,10 @@ public:
     friend class KHTMLPart;
 
 private:
+	enum EPositionType { START, END, BASE, EXTENT };
+
     void init();
-    void validate(ETextGranularity expandTo=CHARACTER);
+    void validate(ETextGranularity granularity=CHARACTER);
 
     void layoutCaret();
     void needsCaretRepaint();
@@ -129,7 +131,7 @@ private:
     bool nodeIsBeforeNode(DOM::NodeImpl *n1, DOM::NodeImpl *n2);
 
     void calculateStartAndEnd(ETextGranularity select=CHARACTER);
-    int xPosForVerticalArrowNavigation() const;
+    int xPosForVerticalArrowNavigation(EPositionType, bool recalc=false) const;
     
     DOM::NodeImpl *m_baseNode;    // base node for the selection
     long m_baseOffset;            // offset into base node where selection is
diff --git a/WebCore/kwq/KWQTextUtilities.cpp b/WebCore/kwq/KWQTextUtilities.cpp
new file mode 100644
index 0000000..9260bf1
--- /dev/null
+++ b/WebCore/kwq/KWQTextUtilities.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2004 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. 
+ */
+
+#import "KWQTextUtilities.h"
+
+#import <qstring.h>
+
+#import <CoreServices/CoreServices.h>
+
+void KWQFindWordBoundary(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;
+    }
+}
diff --git a/WebCore/kwq/KWQView.h b/WebCore/kwq/KWQTextUtilities.h
similarity index 89%
copy from WebCore/kwq/KWQView.h
copy to WebCore/kwq/KWQTextUtilities.h
index bac6d18..bedeb32 100644
--- a/WebCore/kwq/KWQView.h
+++ b/WebCore/kwq/KWQTextUtilities.h
@@ -22,12 +22,12 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
- 
-#import <Cocoa/Cocoa.h>
 
-class QWidget;
+#ifndef _KWQTextUtilities_h_
+#define _KWQTextUtilities_h_
+
+class QChar;
+ 
+void KWQFindWordBoundary(QChar *chars, int len, int position, int *start, int *end);
 
-// all AK View subclasses in KWQ should implement this protocol
- at protocol KWQWidgetHolder
-- (QWidget *)widget;
- at end
+#endif
\ No newline at end of file
diff --git a/WebKit/ChangeLog b/WebKit/ChangeLog
index 65bfacd..f98ea94 100644
--- a/WebKit/ChangeLog
+++ b/WebKit/ChangeLog
@@ -1,3 +1,16 @@
+2004-04-20  Ken Kocienda  <kocienda at apple.com>
+
+        Reviewed by Hyatt
+
+         Added implementations for these methods.
+
+        * WebView.subproj/WebView.m:
+        (-[WebView moveUpAndModifySelection:]):
+        (-[WebView moveWordLeft:]):
+        (-[WebView moveWordLeftAndModifySelection:]):
+        (-[WebView moveWordRight:]):
+        (-[WebView moveWordRightAndModifySelection:]):
+
 2004-04-20  John Sullivan  <sullivan at apple.com>
 
         - fixed <rdar://problem/3622393>: When in stealth mode, visited webpage 
diff --git a/WebKit/WebView.subproj/WebView.m b/WebKit/WebView.subproj/WebView.m
index 1722273..a333b0a 100644
--- a/WebKit/WebView.subproj/WebView.m
+++ b/WebKit/WebView.subproj/WebView.m
@@ -2399,7 +2399,7 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
 - (void)moveUpAndModifySelection:(id)sender
 {
     if ([self _currentSelectionIsEditable]) {
-        ERROR("unimplemented");
+        [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectUp granularity:WebSelectByCharacter];
         return;
     }
     [[self nextResponder] tryToPerform:@selector(moveUpAndModifySelection:) with:sender];
@@ -2444,7 +2444,7 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
 - (void)moveWordLeft:(id)sender
 {
     if ([self _currentSelectionIsEditable]) {
-        ERROR("unimplemented");
+        [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectLeft granularity:WebSelectByWord];
         return;
     }
     [[self nextResponder] tryToPerform:@selector(moveWordLeft:) with:sender];
@@ -2453,7 +2453,7 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
 - (void)moveWordLeftAndModifySelection:(id)sender
 {
     if ([self _currentSelectionIsEditable]) {
-        ERROR("unimplemented");
+        [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectLeft granularity:WebSelectByWord];
         return;
     }
     [[self nextResponder] tryToPerform:@selector(moveWordLeftAndModifySelection:) with:sender];
@@ -2462,7 +2462,7 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
 - (void)moveWordRight:(id)sender
 {
     if ([self _currentSelectionIsEditable]) {
-        ERROR("unimplemented");
+        [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectRight granularity:WebSelectByWord];
         return;
     }
     [[self nextResponder] tryToPerform:@selector(moveWordRight:) with:sender];
@@ -2471,7 +2471,7 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
 - (void)moveWordRightAndModifySelection:(id)sender
 {
     if ([self _currentSelectionIsEditable]) {
-        ERROR("unimplemented");
+        [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectRight granularity:WebSelectByWord];
         return;
     }
     [[self nextResponder] tryToPerform:@selector(moveWordRightAndModifySelection:) with:sender];

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list