WebCore:
authordarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 May 2004 23:26:30 +0000 (23:26 +0000)
committerdarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 May 2004 23:26:30 +0000 (23:26 +0000)
        Reviewed by Ken.

        - various editing-related improvements

        * khtml/xml/dom_selection.h: Removed UP and DOWN directions, and added PARAGRAPH granularity.
        * khtml/xml/dom_selection.cpp:
        (DOM::Selection::modify): Got rid of the UP and DOWN directions, and made movement
        between lines happen when granularity is LINE. Added a new unimplemented granularity:
        PARAGRAPH.
        (DOM::Selection::validate): Remove some unneeded APPLE_CHANGES. The code need not be ifdef'd.
        (DOM::Selection::debugPosition): Ditto.

        * kwq/WebCoreBridge.h: Removed WebSelectUp and WebSelectDown, and added WebSelectByParagraph.
        Added stringForRange: and selectedDOMRangeWithGranularity:, and renamed replaceSelectionWithNewline
        to insertNewline because it has the insertText: semantic, not the replaceSelectionWithText: one.
        * kwq/WebCoreBridge.mm:
        (-[WebCoreBridge stringForRange:]): Added.
        (-[WebCoreBridge selectedDOMRangeWithGranularity:]): Added.
        (-[WebCoreBridge alterCurrentSelection:direction:granularity:]): Updated code to understand
        that vertical movement is based on granularity now, not direction.
        (-[WebCoreBridge replaceSelectionWithFragment:selectReplacement:]): Moved an ensureCaretVisible
        from the WebKit down here. I think perhaps this should go down even further in WebCore.
        (-[WebCoreBridge insertNewline]): Renamed, and moved ensureCaretVisible here.
        (-[WebCoreBridge insertText:]): Moved ensureCaretVisible here.
        (-[WebCoreBridge deleteKeyPressed]): Moved ensureCaretVisible here.

        * khtml/xml/dom_position.cpp: Some ifdef tweaks.

        * khtml/misc/helper.cpp: Namespace and formatting tweaks.
        * khtml/misc/helper.h: Removed some unused stuff.

        * khtml/dom/dom2_range.h: Make range constructor public so that anyone with
        a RangeImpl can easily make a Range.

WebKit:

        Reviewed by Ken.

        - various editing-related improvements
        - fixed <rdar://problem/3655366>: (Editing: -selectParagraph: method unimplemented (WebKit editing API))
        - fixed <rdar://problem/3655367>: (Editing: -selectLine: method unimplemented (WebKit editing API))
        - fixed <rdar://problem/3655369>: (Editing: -selectWord: method unimplemented (WebKit editing API))
        - fixed <rdar://problem/3655392>: (Editing: -uppercaseWord: method unimplemented (WebKit editing API))
        - fixed <rdar://problem/3655393>: (Editing: -lowercaseWord: method unimplemented (WebKit editing API))
        - fixed <rdar://problem/3655394>: (Editing: -capitalizeWord: method unimplemented (WebKit editing API))

        * WebView.subproj/WebHTMLView.m:
        (-[WebHTMLView _alterCurrentSelection:direction:granularity:]): Removed the call to
        ensureCaretVisible. This is now handled on the other side of the bridge.
        (-[WebHTMLView moveDown:]): Changed to use WebSelectByLine granularity instead of
        WebSelectDown direction.
        (-[WebHTMLView moveDownAndModifySelection:]): Ditto.
        (-[WebHTMLView moveUp:]): Ditto.
        (-[WebHTMLView moveUpAndModifySelection:]): Ditto.
        (-[WebHTMLView _expandSelectionToGranularity:]): Added.
        (-[WebHTMLView selectParagraph:]): Implemented by calling _expandSelectionToGranularity.
        (-[WebHTMLView selectLine:]): Ditto.
        (-[WebHTMLView selectWord:]): Ditto.
        (-[WebHTMLView _fontManagerOperationAsStyle]): Added. Placeholder for the job of figuring
        out what style change to make based on NSFontManager.
        (-[WebHTMLView changeFont:]): Implemented, but not really tested because guts are still
        missing due to lack of above method.
        (-[WebHTMLView insertTab:]): Removed the call to ensureCaretVisible.
        (-[WebHTMLView insertNewline:]): Removed the call to ensureCaretVisible.
        (-[WebHTMLView insertParagraphSeparator:]): Made this insert a newline for now.
        (-[WebHTMLView _changeWordCaseWithSelector:]): Added.
        (-[WebHTMLView uppercaseWord:]): Implemented by calling _changeWordCaseWithSelector.
        (-[WebHTMLView lowercaseWord:]): Ditto.
        (-[WebHTMLView capitalizeWord:]): Ditto.
        (-[WebHTMLView deleteBackward:]): Removed the call to ensureCaretVisible.
        (-[WebHTMLView checkSpelling:]): Put a pile of AppKit code in here as a placeholder.
        (-[WebHTMLView startSpeaking:]): Use the new stringForRange: method instead of outerText.
        That way we can handle cases where the entire document is selected.
        (-[WebHTMLView insertText:]): Removed the call to ensureCaretVisible.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@6731 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
WebCore/ChangeLog-2005-08-23
WebCore/khtml/dom/dom2_range.h
WebCore/khtml/editing/SelectionController.cpp
WebCore/khtml/editing/SelectionController.h
WebCore/khtml/editing/selection.cpp
WebCore/khtml/editing/selection.h
WebCore/khtml/misc/helper.cpp
WebCore/khtml/misc/helper.h
WebCore/khtml/xml/dom_position.cpp
WebCore/khtml/xml/dom_selection.cpp
WebCore/khtml/xml/dom_selection.h
WebCore/kwq/WebCoreBridge.h
WebCore/kwq/WebCoreBridge.mm
WebKit/ChangeLog
WebKit/Misc.subproj/WebNSURLExtras.m
WebKit/WebView.subproj/WebHTMLView.m

index 275ec84e5bd025b6e9430df5cf3fc88e71983f86..067e535d53e1e393f3590f7189dab823b9191c9b 100644 (file)
@@ -1,3 +1,39 @@
+2004-05-28  Darin Adler  <darin@apple.com>
+
+        Reviewed by Ken.
+
+        - various editing-related improvements
+
+        * khtml/xml/dom_selection.h: Removed UP and DOWN directions, and added PARAGRAPH granularity.
+        * khtml/xml/dom_selection.cpp:
+        (DOM::Selection::modify): Got rid of the UP and DOWN directions, and made movement
+        between lines happen when granularity is LINE. Added a new unimplemented granularity:
+        PARAGRAPH.
+        (DOM::Selection::validate): Remove some unneeded APPLE_CHANGES. The code need not be ifdef'd.
+        (DOM::Selection::debugPosition): Ditto.
+
+        * kwq/WebCoreBridge.h: Removed WebSelectUp and WebSelectDown, and added WebSelectByParagraph.
+        Added stringForRange: and selectedDOMRangeWithGranularity:, and renamed replaceSelectionWithNewline
+        to insertNewline because it has the insertText: semantic, not the replaceSelectionWithText: one.
+        * kwq/WebCoreBridge.mm:
+        (-[WebCoreBridge stringForRange:]): Added.
+        (-[WebCoreBridge selectedDOMRangeWithGranularity:]): Added.
+        (-[WebCoreBridge alterCurrentSelection:direction:granularity:]): Updated code to understand
+        that vertical movement is based on granularity now, not direction.
+        (-[WebCoreBridge replaceSelectionWithFragment:selectReplacement:]): Moved an ensureCaretVisible
+        from the WebKit down here. I think perhaps this should go down even further in WebCore.
+        (-[WebCoreBridge insertNewline]): Renamed, and moved ensureCaretVisible here.
+        (-[WebCoreBridge insertText:]): Moved ensureCaretVisible here.
+        (-[WebCoreBridge deleteKeyPressed]): Moved ensureCaretVisible here.
+
+        * khtml/xml/dom_position.cpp: Some ifdef tweaks.
+
+        * khtml/misc/helper.cpp: Namespace and formatting tweaks.
+        * khtml/misc/helper.h: Removed some unused stuff.
+
+        * khtml/dom/dom2_range.h: Make range constructor public so that anyone with
+        a RangeImpl can easily make a Range.
+
 2004-05-28  Richard Williamson   <rjw@apple.com>
 
        setStrokeColor and setFillColor now support
index a5ac6bda5cc97346b0cb949495d86bea3bc1b77a..49c74fe36377561f5b72e145a0d805182d2707a3 100644 (file)
@@ -463,12 +463,13 @@ public:
      * @internal
      * not part of the DOM
      */
+    Range(RangeImpl *i);
     RangeImpl *handle() const;
     bool isNull() const;
 
 protected:
     RangeImpl *impl;
-    Range(RangeImpl *i);
+
 private:
     void throwException(int exceptioncode) const;
 };
index 6b02454d3eb6a629ff7c5ada53645a44a3cf88ae..bef05584706f94489f2fb575b026474f4a25fecb 100644 (file)
 #include "xml/dom_textimpl.h"
 
 #if APPLE_CHANGES
-#include <KWQAssertions.h>
-#include <KWQTextUtilities.h>
-#include <CoreServices/CoreServices.h>
+#include "KWQAssertions.h"
+#else
+#define ASSERT(assertion) assert(assertion)
+#endif
 
 #define EDIT_DEBUG 0
-#endif
 
+using khtml::findWordBoundary;
 using khtml::InlineTextBox;
 using khtml::RenderObject;
 using khtml::RenderText;
 
 namespace DOM {
 
-#if APPLE_CHANGES
 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(NodeImpl *node, int offset, Selection &selection);
-#endif
 
 static inline Position &emptyPosition()
 {
@@ -208,24 +207,36 @@ bool Selection::modify(EAlter alter, EDirection dir, ETextGranularity granularit
                     m_modifyBiasSet = true;
                     assignBaseAndExtent(start(), end());
                 }
-                if (granularity == CHARACTER)
-                    pos = extent().nextCharacterPosition();
-                else if (granularity == WORD)
-                    pos = extent().nextWordPosition();
+                switch (granularity) {
+                    case CHARACTER:
+                        pos = extent().nextCharacterPosition();
+                        break;
+                    case WORD:
+                        pos = extent().nextWordPosition();
+                        break;
+                    case LINE:
+                        pos = extent().nextLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
+                }
             }
             else {
                 m_modifyBiasSet = false;
-                if (state() == RANGE) {
-                    if (granularity == CHARACTER)
-                        pos = end();
-                    else if (granularity == WORD)
-                        pos = extent().nextWordPosition();
-                }
-                else {
-                    if (granularity == CHARACTER)
-                        pos = extent().nextCharacterPosition();
-                    else if (granularity == WORD)
+                switch (granularity) {
+                    case CHARACTER:
+                        pos = (state() == RANGE) ? end() : extent().nextCharacterPosition();
+                        break;
+                    case WORD:
                         pos = extent().nextWordPosition();
+                        break;
+                    case LINE:
+                        pos = end().nextLinePosition(xPosForVerticalArrowNavigation(END, state() == RANGE));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
                 }
             }
             break;
@@ -237,51 +248,37 @@ bool Selection::modify(EAlter alter, EDirection dir, ETextGranularity granularit
                     m_modifyBiasSet = true;
                     assignBaseAndExtent(end(), start());
                 }
-                if (granularity == CHARACTER)
-                    pos = extent().previousCharacterPosition();
-                else if (granularity == WORD)
-                    pos = extent().previousWordPosition();
-            }
-            else {
-                m_modifyBiasSet = false;
-                if (state() == RANGE) {
-                    if (granularity == CHARACTER)
-                        pos = start();
-                    else if (granularity == WORD)
-                        pos = extent().previousWordPosition();
-                }
-                else {
-                    if (granularity == CHARACTER)
+                switch (granularity) {
+                    case CHARACTER:
                         pos = extent().previousCharacterPosition();
-                    else if (granularity == WORD)
+                        break;
+                    case WORD:
                         pos = extent().previousWordPosition();
+                        break;
+                    case LINE:
+                        pos = extent().previousLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
                 }
             }
-            break;
-        case UP:
-            if (alter == EXTEND) {
-                if (!m_modifyBiasSet) {
-                    m_modifyBiasSet = true;
-                    assignBaseAndExtent(end(), start());
-                }
-                pos = extent().previousLinePosition(xPosForVerticalArrowNavigation(EXTENT));
-            }
             else {
                 m_modifyBiasSet = false;
-                pos = start().previousLinePosition(xPosForVerticalArrowNavigation(START, state()==RANGE));
-            }
-            break;
-        case DOWN:
-            if (alter == EXTEND) {
-                if (!m_modifyBiasSet) {
-                    m_modifyBiasSet = true;
-                    assignBaseAndExtent(start(), end());
+                switch (granularity) {
+                    case CHARACTER:
+                        pos = (state() == RANGE) ? start() : extent().previousCharacterPosition();
+                        break;
+                    case WORD:
+                        pos = extent().previousWordPosition();
+                        break;
+                    case LINE:
+                        pos = start().previousLinePosition(xPosForVerticalArrowNavigation(START, state() == RANGE));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
                 }
-                pos = extent().nextLinePosition(xPosForVerticalArrowNavigation(EXTENT));
-            }
-            else {
-                m_modifyBiasSet = false;
-                pos = end().nextLinePosition(xPosForVerticalArrowNavigation(END, state()==RANGE));
             }
             break;
     }
@@ -558,12 +555,6 @@ void Selection::validate(ETextGranularity granularity)
     }
 
     // calculate the correct start and end positions
-#if !APPLE_CHANGES
-    if (m_baseIsStart)
-        assignStartAndEnd(base(), extent());
-    else
-        assignStartAndEnd(extent(), base());
-#else
     if (granularity == CHARACTER) {
         if (m_baseIsStart)
             assignStartAndEnd(base(), extent());
@@ -579,13 +570,13 @@ void Selection::validate(ETextGranularity granularity)
             DOMString t = base().node()->nodeValue();
             QChar *chars = t.unicode();
             uint len = t.length();
-            KWQFindWordBoundary(chars, len, base().offset(), &baseStartOffset, &baseEndOffset);
+            findWordBoundary(chars, len, base().offset(), &baseStartOffset, &baseEndOffset);
         }
         if (extent().notEmpty() && (extent().node()->nodeType() == Node::TEXT_NODE || extent().node()->nodeType() == Node::CDATA_SECTION_NODE)) {
             DOMString t = extent().node()->nodeValue();
             QChar *chars = t.unicode();
             uint len = t.length();
-            KWQFindWordBoundary(chars, len, extent().offset(), &extentStartOffset, &extentEndOffset);
+            findWordBoundary(chars, len, extent().offset(), &extentStartOffset, &extentEndOffset);
         }
         if (m_baseIsStart) {
             assignStart(Position(base().node(), baseStartOffset));
@@ -620,7 +611,6 @@ void Selection::validate(ETextGranularity granularity)
             assignEnd(baseSelection.end());
         }
     }
-#endif  // APPLE_CHANGES
 
     // adjust the state
     if (start().isEmpty() && end().isEmpty())
@@ -719,8 +709,6 @@ bool Selection::nodeIsBeforeNode(NodeImpl *n1, NodeImpl *n2) const
     return result;
 }
 
-#if APPLE_CHANGES
-
 static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
 {
     for (RenderObject *n = renderNode; n; n = n->nextSibling()) {
@@ -969,6 +957,4 @@ void Selection::debugPosition() const
     fprintf(stderr, "================================\n");
 }
 
-#endif
-
 } // namespace DOM
index 04f74990eb39e97ce38956bbe9d0ddfa5d038c57..e997df42842ea6cb475eb9b80fe42a20407d04e7 100644 (file)
@@ -47,8 +47,8 @@ class Selection
 public:
     enum EState { NONE, CARET, RANGE };
     enum EAlter { MOVE, EXTEND };
-    enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT, UP, DOWN };
-    enum ETextGranularity { CHARACTER, WORD, LINE };
+    enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
+    enum ETextGranularity { CHARACTER, WORD, LINE, PARAGRAPH };
 
     // These match the AppKit values for these concepts.
     // From NSTextView.h:
index 6b02454d3eb6a629ff7c5ada53645a44a3cf88ae..bef05584706f94489f2fb575b026474f4a25fecb 100644 (file)
 #include "xml/dom_textimpl.h"
 
 #if APPLE_CHANGES
-#include <KWQAssertions.h>
-#include <KWQTextUtilities.h>
-#include <CoreServices/CoreServices.h>
+#include "KWQAssertions.h"
+#else
+#define ASSERT(assertion) assert(assertion)
+#endif
 
 #define EDIT_DEBUG 0
-#endif
 
+using khtml::findWordBoundary;
 using khtml::InlineTextBox;
 using khtml::RenderObject;
 using khtml::RenderText;
 
 namespace DOM {
 
-#if APPLE_CHANGES
 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(NodeImpl *node, int offset, Selection &selection);
-#endif
 
 static inline Position &emptyPosition()
 {
@@ -208,24 +207,36 @@ bool Selection::modify(EAlter alter, EDirection dir, ETextGranularity granularit
                     m_modifyBiasSet = true;
                     assignBaseAndExtent(start(), end());
                 }
-                if (granularity == CHARACTER)
-                    pos = extent().nextCharacterPosition();
-                else if (granularity == WORD)
-                    pos = extent().nextWordPosition();
+                switch (granularity) {
+                    case CHARACTER:
+                        pos = extent().nextCharacterPosition();
+                        break;
+                    case WORD:
+                        pos = extent().nextWordPosition();
+                        break;
+                    case LINE:
+                        pos = extent().nextLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
+                }
             }
             else {
                 m_modifyBiasSet = false;
-                if (state() == RANGE) {
-                    if (granularity == CHARACTER)
-                        pos = end();
-                    else if (granularity == WORD)
-                        pos = extent().nextWordPosition();
-                }
-                else {
-                    if (granularity == CHARACTER)
-                        pos = extent().nextCharacterPosition();
-                    else if (granularity == WORD)
+                switch (granularity) {
+                    case CHARACTER:
+                        pos = (state() == RANGE) ? end() : extent().nextCharacterPosition();
+                        break;
+                    case WORD:
                         pos = extent().nextWordPosition();
+                        break;
+                    case LINE:
+                        pos = end().nextLinePosition(xPosForVerticalArrowNavigation(END, state() == RANGE));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
                 }
             }
             break;
@@ -237,51 +248,37 @@ bool Selection::modify(EAlter alter, EDirection dir, ETextGranularity granularit
                     m_modifyBiasSet = true;
                     assignBaseAndExtent(end(), start());
                 }
-                if (granularity == CHARACTER)
-                    pos = extent().previousCharacterPosition();
-                else if (granularity == WORD)
-                    pos = extent().previousWordPosition();
-            }
-            else {
-                m_modifyBiasSet = false;
-                if (state() == RANGE) {
-                    if (granularity == CHARACTER)
-                        pos = start();
-                    else if (granularity == WORD)
-                        pos = extent().previousWordPosition();
-                }
-                else {
-                    if (granularity == CHARACTER)
+                switch (granularity) {
+                    case CHARACTER:
                         pos = extent().previousCharacterPosition();
-                    else if (granularity == WORD)
+                        break;
+                    case WORD:
                         pos = extent().previousWordPosition();
+                        break;
+                    case LINE:
+                        pos = extent().previousLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
                 }
             }
-            break;
-        case UP:
-            if (alter == EXTEND) {
-                if (!m_modifyBiasSet) {
-                    m_modifyBiasSet = true;
-                    assignBaseAndExtent(end(), start());
-                }
-                pos = extent().previousLinePosition(xPosForVerticalArrowNavigation(EXTENT));
-            }
             else {
                 m_modifyBiasSet = false;
-                pos = start().previousLinePosition(xPosForVerticalArrowNavigation(START, state()==RANGE));
-            }
-            break;
-        case DOWN:
-            if (alter == EXTEND) {
-                if (!m_modifyBiasSet) {
-                    m_modifyBiasSet = true;
-                    assignBaseAndExtent(start(), end());
+                switch (granularity) {
+                    case CHARACTER:
+                        pos = (state() == RANGE) ? start() : extent().previousCharacterPosition();
+                        break;
+                    case WORD:
+                        pos = extent().previousWordPosition();
+                        break;
+                    case LINE:
+                        pos = start().previousLinePosition(xPosForVerticalArrowNavigation(START, state() == RANGE));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
                 }
-                pos = extent().nextLinePosition(xPosForVerticalArrowNavigation(EXTENT));
-            }
-            else {
-                m_modifyBiasSet = false;
-                pos = end().nextLinePosition(xPosForVerticalArrowNavigation(END, state()==RANGE));
             }
             break;
     }
@@ -558,12 +555,6 @@ void Selection::validate(ETextGranularity granularity)
     }
 
     // calculate the correct start and end positions
-#if !APPLE_CHANGES
-    if (m_baseIsStart)
-        assignStartAndEnd(base(), extent());
-    else
-        assignStartAndEnd(extent(), base());
-#else
     if (granularity == CHARACTER) {
         if (m_baseIsStart)
             assignStartAndEnd(base(), extent());
@@ -579,13 +570,13 @@ void Selection::validate(ETextGranularity granularity)
             DOMString t = base().node()->nodeValue();
             QChar *chars = t.unicode();
             uint len = t.length();
-            KWQFindWordBoundary(chars, len, base().offset(), &baseStartOffset, &baseEndOffset);
+            findWordBoundary(chars, len, base().offset(), &baseStartOffset, &baseEndOffset);
         }
         if (extent().notEmpty() && (extent().node()->nodeType() == Node::TEXT_NODE || extent().node()->nodeType() == Node::CDATA_SECTION_NODE)) {
             DOMString t = extent().node()->nodeValue();
             QChar *chars = t.unicode();
             uint len = t.length();
-            KWQFindWordBoundary(chars, len, extent().offset(), &extentStartOffset, &extentEndOffset);
+            findWordBoundary(chars, len, extent().offset(), &extentStartOffset, &extentEndOffset);
         }
         if (m_baseIsStart) {
             assignStart(Position(base().node(), baseStartOffset));
@@ -620,7 +611,6 @@ void Selection::validate(ETextGranularity granularity)
             assignEnd(baseSelection.end());
         }
     }
-#endif  // APPLE_CHANGES
 
     // adjust the state
     if (start().isEmpty() && end().isEmpty())
@@ -719,8 +709,6 @@ bool Selection::nodeIsBeforeNode(NodeImpl *n1, NodeImpl *n2) const
     return result;
 }
 
-#if APPLE_CHANGES
-
 static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
 {
     for (RenderObject *n = renderNode; n; n = n->nextSibling()) {
@@ -969,6 +957,4 @@ void Selection::debugPosition() const
     fprintf(stderr, "================================\n");
 }
 
-#endif
-
 } // namespace DOM
index 04f74990eb39e97ce38956bbe9d0ddfa5d038c57..e997df42842ea6cb475eb9b80fe42a20407d04e7 100644 (file)
@@ -47,8 +47,8 @@ class Selection
 public:
     enum EState { NONE, CARET, RANGE };
     enum EAlter { MOVE, EXTEND };
-    enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT, UP, DOWN };
-    enum ETextGranularity { CHARACTER, WORD, LINE };
+    enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
+    enum ETextGranularity { CHARACTER, WORD, LINE, PARAGRAPH };
 
     // These match the AppKit values for these concepts.
     // From NSTextView.h:
index 607b70300fdaefefac5ad469f02c7f7535119026..40bdda914751155f2e2253cb3b42f7b808f866ac 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the CSS implementation for KDE.
  *
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2003 Apple Computer, Inc.
+ * Copyright (C) 2004 Apple Computer, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #include "KWQTextUtilities.h"
 #endif
 
-QPainter *khtml::printpainter = 0;
+namespace khtml {
 
-void khtml::setPrintPainter( QPainter *printer )
+QPainter *printpainter = 0;
+
+void setPrintPainter( QPainter *printer )
 {
     printpainter = printer;
 }
 
-void khtml::findWordBoundary(QChar *chars, int len, int position, int *start, int *end)
+void 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
+}
+
+}
index a4622cd1d983ef706d20c839a87686e7955fe859..7875aaad15bb2046bb831a4ba0c09d71643c34dd 100644 (file)
@@ -2,6 +2,7 @@
  * This file is part of the CSS implementation for KDE.
  *
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2004 Apple Computer, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -38,17 +39,6 @@ namespace khtml
     extern QPainter *printpainter;
     void setPrintPainter( QPainter *printer );
 
-    //enumerator for findSelectionNode
-    enum FindSelectionResult { SelectionPointBefore,
-                              SelectionPointAfter,
-                              SelectionPointInside,
-                              // the next two are only used inside one line in RenderText
-                              // to get BiDi contexts right.
-                              SelectionPointBeforeInLine,
-                              SelectionPointAfterInLine };
-
-
     void findWordBoundary(QChar *chars, int len, int position, int *start, int *end);
 };
 
index 1d3b49bbbef986209f30d68ee114ab06c15f554b..4d1d083942c9cc2245c494fec73abe29d7b71d6d 100644 (file)
@@ -40,6 +40,9 @@
 #if APPLE_CHANGES
 #include "KWQAssertions.h"
 #include "KWQLogging.h"
+#else
+#define ASSERT(assertion) assert(assertion)
+#define LOG(channel, formatAndArgs...) ((void)0)
 #endif
 
 using khtml::InlineBox;
@@ -50,14 +53,6 @@ using khtml::RenderObject;
 using khtml::RenderText;
 using khtml::RootInlineBox;
 
-#if !APPLE_CHANGES
-#define ASSERT(assertion) ((void)0)
-#define ASSERT_WITH_MESSAGE(assertion, formatAndArgs...) ((void)0)
-#define ASSERT_NOT_REACHED() ((void)0)
-#define LOG(channel, formatAndArgs...) ((void)0)
-#define ERROR(formatAndArgs...) ((void)0)
-#endif
-
 namespace DOM {
 
 static bool renderersOnDifferentLine(RenderObject *r1, long o1, RenderObject *r2, long o2)
index 6b02454d3eb6a629ff7c5ada53645a44a3cf88ae..bef05584706f94489f2fb575b026474f4a25fecb 100644 (file)
 #include "xml/dom_textimpl.h"
 
 #if APPLE_CHANGES
-#include <KWQAssertions.h>
-#include <KWQTextUtilities.h>
-#include <CoreServices/CoreServices.h>
+#include "KWQAssertions.h"
+#else
+#define ASSERT(assertion) assert(assertion)
+#endif
 
 #define EDIT_DEBUG 0
-#endif
 
+using khtml::findWordBoundary;
 using khtml::InlineTextBox;
 using khtml::RenderObject;
 using khtml::RenderText;
 
 namespace DOM {
 
-#if APPLE_CHANGES
 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(NodeImpl *node, int offset, Selection &selection);
-#endif
 
 static inline Position &emptyPosition()
 {
@@ -208,24 +207,36 @@ bool Selection::modify(EAlter alter, EDirection dir, ETextGranularity granularit
                     m_modifyBiasSet = true;
                     assignBaseAndExtent(start(), end());
                 }
-                if (granularity == CHARACTER)
-                    pos = extent().nextCharacterPosition();
-                else if (granularity == WORD)
-                    pos = extent().nextWordPosition();
+                switch (granularity) {
+                    case CHARACTER:
+                        pos = extent().nextCharacterPosition();
+                        break;
+                    case WORD:
+                        pos = extent().nextWordPosition();
+                        break;
+                    case LINE:
+                        pos = extent().nextLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
+                }
             }
             else {
                 m_modifyBiasSet = false;
-                if (state() == RANGE) {
-                    if (granularity == CHARACTER)
-                        pos = end();
-                    else if (granularity == WORD)
-                        pos = extent().nextWordPosition();
-                }
-                else {
-                    if (granularity == CHARACTER)
-                        pos = extent().nextCharacterPosition();
-                    else if (granularity == WORD)
+                switch (granularity) {
+                    case CHARACTER:
+                        pos = (state() == RANGE) ? end() : extent().nextCharacterPosition();
+                        break;
+                    case WORD:
                         pos = extent().nextWordPosition();
+                        break;
+                    case LINE:
+                        pos = end().nextLinePosition(xPosForVerticalArrowNavigation(END, state() == RANGE));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
                 }
             }
             break;
@@ -237,51 +248,37 @@ bool Selection::modify(EAlter alter, EDirection dir, ETextGranularity granularit
                     m_modifyBiasSet = true;
                     assignBaseAndExtent(end(), start());
                 }
-                if (granularity == CHARACTER)
-                    pos = extent().previousCharacterPosition();
-                else if (granularity == WORD)
-                    pos = extent().previousWordPosition();
-            }
-            else {
-                m_modifyBiasSet = false;
-                if (state() == RANGE) {
-                    if (granularity == CHARACTER)
-                        pos = start();
-                    else if (granularity == WORD)
-                        pos = extent().previousWordPosition();
-                }
-                else {
-                    if (granularity == CHARACTER)
+                switch (granularity) {
+                    case CHARACTER:
                         pos = extent().previousCharacterPosition();
-                    else if (granularity == WORD)
+                        break;
+                    case WORD:
                         pos = extent().previousWordPosition();
+                        break;
+                    case LINE:
+                        pos = extent().previousLinePosition(xPosForVerticalArrowNavigation(EXTENT));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
                 }
             }
-            break;
-        case UP:
-            if (alter == EXTEND) {
-                if (!m_modifyBiasSet) {
-                    m_modifyBiasSet = true;
-                    assignBaseAndExtent(end(), start());
-                }
-                pos = extent().previousLinePosition(xPosForVerticalArrowNavigation(EXTENT));
-            }
             else {
                 m_modifyBiasSet = false;
-                pos = start().previousLinePosition(xPosForVerticalArrowNavigation(START, state()==RANGE));
-            }
-            break;
-        case DOWN:
-            if (alter == EXTEND) {
-                if (!m_modifyBiasSet) {
-                    m_modifyBiasSet = true;
-                    assignBaseAndExtent(start(), end());
+                switch (granularity) {
+                    case CHARACTER:
+                        pos = (state() == RANGE) ? start() : extent().previousCharacterPosition();
+                        break;
+                    case WORD:
+                        pos = extent().previousWordPosition();
+                        break;
+                    case LINE:
+                        pos = start().previousLinePosition(xPosForVerticalArrowNavigation(START, state() == RANGE));
+                        break;
+                    case PARAGRAPH:
+                        // not implemented
+                        break;
                 }
-                pos = extent().nextLinePosition(xPosForVerticalArrowNavigation(EXTENT));
-            }
-            else {
-                m_modifyBiasSet = false;
-                pos = end().nextLinePosition(xPosForVerticalArrowNavigation(END, state()==RANGE));
             }
             break;
     }
@@ -558,12 +555,6 @@ void Selection::validate(ETextGranularity granularity)
     }
 
     // calculate the correct start and end positions
-#if !APPLE_CHANGES
-    if (m_baseIsStart)
-        assignStartAndEnd(base(), extent());
-    else
-        assignStartAndEnd(extent(), base());
-#else
     if (granularity == CHARACTER) {
         if (m_baseIsStart)
             assignStartAndEnd(base(), extent());
@@ -579,13 +570,13 @@ void Selection::validate(ETextGranularity granularity)
             DOMString t = base().node()->nodeValue();
             QChar *chars = t.unicode();
             uint len = t.length();
-            KWQFindWordBoundary(chars, len, base().offset(), &baseStartOffset, &baseEndOffset);
+            findWordBoundary(chars, len, base().offset(), &baseStartOffset, &baseEndOffset);
         }
         if (extent().notEmpty() && (extent().node()->nodeType() == Node::TEXT_NODE || extent().node()->nodeType() == Node::CDATA_SECTION_NODE)) {
             DOMString t = extent().node()->nodeValue();
             QChar *chars = t.unicode();
             uint len = t.length();
-            KWQFindWordBoundary(chars, len, extent().offset(), &extentStartOffset, &extentEndOffset);
+            findWordBoundary(chars, len, extent().offset(), &extentStartOffset, &extentEndOffset);
         }
         if (m_baseIsStart) {
             assignStart(Position(base().node(), baseStartOffset));
@@ -620,7 +611,6 @@ void Selection::validate(ETextGranularity granularity)
             assignEnd(baseSelection.end());
         }
     }
-#endif  // APPLE_CHANGES
 
     // adjust the state
     if (start().isEmpty() && end().isEmpty())
@@ -719,8 +709,6 @@ bool Selection::nodeIsBeforeNode(NodeImpl *n1, NodeImpl *n2) const
     return result;
 }
 
-#if APPLE_CHANGES
-
 static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
 {
     for (RenderObject *n = renderNode; n; n = n->nextSibling()) {
@@ -969,6 +957,4 @@ void Selection::debugPosition() const
     fprintf(stderr, "================================\n");
 }
 
-#endif
-
 } // namespace DOM
index 04f74990eb39e97ce38956bbe9d0ddfa5d038c57..e997df42842ea6cb475eb9b80fe42a20407d04e7 100644 (file)
@@ -47,8 +47,8 @@ class Selection
 public:
     enum EState { NONE, CARET, RANGE };
     enum EAlter { MOVE, EXTEND };
-    enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT, UP, DOWN };
-    enum ETextGranularity { CHARACTER, WORD, LINE };
+    enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
+    enum ETextGranularity { CHARACTER, WORD, LINE, PARAGRAPH };
 
     // These match the AppKit values for these concepts.
     // From NSTextView.h:
index 20e4884bd90090e88f56e76e36cce08da0b77641..f7f34bbd5a99f04448331ba8a2b2354a30b53125 100644 (file)
@@ -89,24 +89,23 @@ typedef enum {
     WebCoreDevicePrinter
 } WebCoreDeviceType;
 
-typedef enum { 
-    WebSelectByMoving, 
-    WebSelectByExtending 
+typedef enum {
+    WebSelectByMoving,
+    WebSelectByExtending
 } WebSelectionAlteration;
 
-typedef enum { 
-    WebSelectForward, 
-    WebSelectBackward, 
-    WebSelectRight, 
-    WebSelectLeft, 
-    WebSelectUp, 
-    WebSelectDown,
+typedef enum {
+    WebSelectForward,
+    WebSelectBackward,
+    WebSelectRight,
+    WebSelectLeft
 } WebSelectionDirection;
 
-typedef enum { 
-    WebSelectByCharacter, 
-    WebSelectByWord, 
-    WebSelectByLine 
+typedef enum {
+    WebSelectByCharacter,
+    WebSelectByWord,
+    WebSelectByLine,
+    WebSelectByParagraph
 } WebSelectionGranularity;
 
 
@@ -241,6 +240,8 @@ typedef enum {
 - (NSAttributedString *)selectedAttributedString;
 - (NSString *)selectedString;
 
+- (NSString *)stringForRange:(DOMRange *)range;
+
 - (NSString *)markupStringFromNode:(DOMNode *)node nodes:(NSArray **)nodes;
 - (NSString *)markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes;
 
@@ -286,6 +287,8 @@ typedef enum {
 
 - (void)undoEditing:(id)arg;
 - (void)redoEditing:(id)arg;
+
+- (DOMRange *)selectedDOMRangeWithGranularity:(WebSelectionGranularity)granularity;
 - (DOMRange *)rangeByAlteringCurrentSelection:(WebSelectionAlteration)alteration direction:(WebSelectionDirection)direction granularity:(WebSelectionGranularity)granularity;
 - (void)alterCurrentSelection:(WebSelectionAlteration)alteration direction:(WebSelectionDirection)direction granularity:(WebSelectionGranularity)granularity;
 
@@ -296,9 +299,9 @@ typedef enum {
 - (void)replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement;
 - (void)replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement;
 - (void)replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement;
-- (void)replaceSelectionWithNewline;
 
 - (void)insertText:(NSString *)text;
+- (void)insertNewline;
 
 - (void)setSelectionToDragCaret;
 - (void)moveSelectionToDragCaret:(DOMDocumentFragment *)selectionFragment;
index 514de7bc4c9ae5313ccc8d3db0065cddc89bac31..6ea0c55f763bb2c89e7c2eb713961ebf9461655e 100644 (file)
@@ -501,6 +501,13 @@ static bool initializedKJS = FALSE;
     return [[text.getNSString() copy] autorelease];
 }
 
+- (NSString *)stringForRange:(DOMRange *)range
+{
+    QString text = _part->text([range _rangeImpl]);
+    text.replace('\\', _part->backslashAsCurrencySymbol());
+    return [[text.getNSString() copy] autorelease];
+}
+
 - (void)selectAll
 {
     _part->selectAll();
@@ -1334,6 +1341,17 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     cmd.reapply();
 }
 
+- (DOMRange *)selectedDOMRangeWithGranularity:(WebSelectionGranularity)granularity
+{
+    if (!_part)
+        return nil;
+        
+    // NOTE: The enums *must* match the very similar ones declared in ktml_selection.h
+    Selection selection(_part->selection());
+    selection.expandUsingGranularity(static_cast<Selection::ETextGranularity>(granularity));
+    return [DOMRange _rangeWithImpl:selection.toRange().handle()];
+}
+
 - (DOMRange *)rangeByAlteringCurrentSelection:(WebSelectionAlteration)alteration direction:(WebSelectionDirection)direction granularity:(WebSelectionGranularity)granularity
 {
     if (!_part)
@@ -1359,9 +1377,9 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
                      static_cast<Selection::ETextGranularity>(granularity));
 
     // save vertical navigation x position if necessary
-    int xPos = _part->xPosForVerticalArrowNavigation();
-    if (direction != WebSelectUp && direction != WebSelectDown)
-        xPos = KHTMLPart::NoXPosForVerticalArrowNavigation;
+    int xPos = KHTMLPart::NoXPosForVerticalArrowNavigation;
+    if (granularity == WebSelectByLine)
+        xPos = _part->xPosForVerticalArrowNavigation();
     
     // setting the selection always clears saved vertical navigation x position
     _part->setSelection(selection);
@@ -1369,6 +1387,8 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     // restore vertical navigation x position if necessary
     if (xPos != KHTMLPart::NoXPosForVerticalArrowNavigation)
         _part->setXPosForVerticalArrowNavigation(xPos);
+
+    [self ensureCaretVisible];
 }
 
 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity
@@ -1419,6 +1439,7 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     [fragment appendChild:[document createTextNode:text]];
     return fragment;
 }
+
 - (void)replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement
 {
     if (!_part || !_part->xmlDocImpl() || !fragment)
@@ -1426,6 +1447,7 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     
     ReplaceSelectionCommand cmd(_part->xmlDocImpl(), [fragment _fragmentImpl], selectReplacement);
     cmd.apply();
+    [self ensureCaretVisible];
 }
 
 - (void)replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement
@@ -1446,12 +1468,13 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     [self replaceSelectionWithFragment:[self documentFragmentWithText:text] selectReplacement:selectReplacement];
 }
 
-- (void)replaceSelectionWithNewline
+- (void)insertNewline
 {
     if (!_part || !_part->xmlDocImpl())
         return;
     
     TypingCommand::insertNewline(_part->xmlDocImpl());
+    [self ensureCaretVisible];
 }
 
 - (void)insertText:(NSString *)text
@@ -1460,6 +1483,7 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
         return;
     
     TypingCommand::insertText(_part->xmlDocImpl(), text);
+    [self ensureCaretVisible];
 }
 
 - (void)setSelectionToDragCaret
@@ -1513,6 +1537,7 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
         return;
     
     TypingCommand::deleteKeyPressed(_part->xmlDocImpl());
+    [self ensureCaretVisible];
 }
 
 - (void)applyStyle:(DOMCSSStyleDeclaration *)style
index 9d3abca72da68fbff23cd00d9012ad02a03045f5..204120d86857429c304dff0da4bc8d046c564ddd 100644 (file)
@@ -1,3 +1,44 @@
+2004-05-28  Darin Adler  <darin@apple.com>
+
+        Reviewed by Ken.
+
+        - various editing-related improvements
+        - fixed <rdar://problem/3655366>: (Editing: -selectParagraph: method unimplemented (WebKit editing API))
+        - fixed <rdar://problem/3655367>: (Editing: -selectLine: method unimplemented (WebKit editing API))
+        - fixed <rdar://problem/3655369>: (Editing: -selectWord: method unimplemented (WebKit editing API))
+        - fixed <rdar://problem/3655392>: (Editing: -uppercaseWord: method unimplemented (WebKit editing API))
+        - fixed <rdar://problem/3655393>: (Editing: -lowercaseWord: method unimplemented (WebKit editing API))
+        - fixed <rdar://problem/3655394>: (Editing: -capitalizeWord: method unimplemented (WebKit editing API))
+
+        * WebView.subproj/WebHTMLView.m:
+        (-[WebHTMLView _alterCurrentSelection:direction:granularity:]): Removed the call to
+        ensureCaretVisible. This is now handled on the other side of the bridge.
+        (-[WebHTMLView moveDown:]): Changed to use WebSelectByLine granularity instead of
+        WebSelectDown direction.
+        (-[WebHTMLView moveDownAndModifySelection:]): Ditto.
+        (-[WebHTMLView moveUp:]): Ditto.
+        (-[WebHTMLView moveUpAndModifySelection:]): Ditto.
+        (-[WebHTMLView _expandSelectionToGranularity:]): Added.
+        (-[WebHTMLView selectParagraph:]): Implemented by calling _expandSelectionToGranularity.
+        (-[WebHTMLView selectLine:]): Ditto.
+        (-[WebHTMLView selectWord:]): Ditto.
+        (-[WebHTMLView _fontManagerOperationAsStyle]): Added. Placeholder for the job of figuring
+        out what style change to make based on NSFontManager.
+        (-[WebHTMLView changeFont:]): Implemented, but not really tested because guts are still
+        missing due to lack of above method.
+        (-[WebHTMLView insertTab:]): Removed the call to ensureCaretVisible.
+        (-[WebHTMLView insertNewline:]): Removed the call to ensureCaretVisible.
+        (-[WebHTMLView insertParagraphSeparator:]): Made this insert a newline for now.
+        (-[WebHTMLView _changeWordCaseWithSelector:]): Added.
+        (-[WebHTMLView uppercaseWord:]): Implemented by calling _changeWordCaseWithSelector.
+        (-[WebHTMLView lowercaseWord:]): Ditto.
+        (-[WebHTMLView capitalizeWord:]): Ditto.
+        (-[WebHTMLView deleteBackward:]): Removed the call to ensureCaretVisible.
+        (-[WebHTMLView checkSpelling:]): Put a pile of AppKit code in here as a placeholder.
+        (-[WebHTMLView startSpeaking:]): Use the new stringForRange: method instead of outerText.
+        That way we can handle cases where the entire document is selected.
+        (-[WebHTMLView insertText:]): Removed the call to ensureCaretVisible.
+
 2004-05-28  Chris Blumenberg  <cblu@apple.com>
 
        Fixed: <rdar://problem/3672129>: (selection deselects when clicking editable WebView in background window)
index f874b7b7ecfb4430e1f70817506f51d0e8a70ee1..501586fed7f8372b5c47e0954d8df664a0aff73a 100644 (file)
@@ -735,7 +735,7 @@ static NSString *mapHostNames(NSString *string, BOOL encode)
         NSString *substring = [self substringWithRange:range];
         substring = (NSString *)CFURLCreateStringByReplacingPercentEscapes(NULL, (CFStringRef)substring, CFSTR(""));
         if (substring != nil) {
-            string = substring;
+            string = [substring autorelease];
             range = NSMakeRange(0, [string length]);
         }
     }
index e21952cb6c278b06336bf418450d556aecc4b181..28d2ae83cbad5888624426da3c636438ffe7b395 100644 (file)
@@ -2118,7 +2118,6 @@ static WebHTMLView *lastHitView = nil;
     WebView *webView = [self _webView];
     if ([[webView _editingDelegateForwarder] webView:webView shouldChangeSelectedDOMRange:[bridge selectedDOMRange] toDOMRange:proposedRange affinity:[bridge selectionAffinity] stillSelecting:NO]) {
         [bridge alterCurrentSelection:alteration direction:direction granularity:granularity];
-        [bridge ensureCaretVisible];
     }
 }
 
@@ -2134,12 +2133,12 @@ static WebHTMLView *lastHitView = nil;
 
 - (void)moveDown:(id)sender
 {
-    [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectDown granularity:WebSelectByCharacter];
+    [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectForward granularity:WebSelectByLine];
 }
 
 - (void)moveDownAndModifySelection:(id)sender
 {
-    [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectDown granularity:WebSelectByCharacter];
+    [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectForward granularity:WebSelectByLine];
 }
 
 - (void)moveForward:(id)sender
@@ -2204,12 +2203,12 @@ static WebHTMLView *lastHitView = nil;
 
 - (void)moveUp:(id)sender
 {
-    [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectUp granularity:WebSelectByCharacter];
+    [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectBackward granularity:WebSelectByLine];
 }
 
 - (void)moveUpAndModifySelection:(id)sender
 {
-    [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectUp granularity:WebSelectByCharacter];
+    [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectBackward granularity:WebSelectByLine];
 }
 
 - (void)moveWordBackward:(id)sender
@@ -2262,22 +2261,31 @@ static WebHTMLView *lastHitView = nil;
     ERROR("unimplemented");
 }
 
-
-    /* Selections */
+- (void)_expandSelectionToGranularity:(WebSelectionGranularity)granularity
+{
+    WebBridge *bridge = [self _bridge];
+    DOMRange *range = [bridge selectedDOMRangeWithGranularity:granularity];
+    if (range && ![range collapsed]) {
+        WebView *webView = [self _webView];
+        if ([[webView _editingDelegateForwarder] webView:webView shouldChangeSelectedDOMRange:[bridge selectedDOMRange] toDOMRange:range affinity:[bridge selectionAffinity] stillSelecting:NO]) {
+            [bridge setSelectedDOMRange:range affinity:[bridge selectionAffinity]];
+        }
+    }
+}
 
 - (void)selectParagraph:(id)sender
 {
-    ERROR("unimplemented");
+    [self _expandSelectionToGranularity:WebSelectByParagraph];
 }
 
 - (void)selectLine:(id)sender
 {
-    ERROR("unimplemented");
+    [self _expandSelectionToGranularity:WebSelectByLine];
 }
 
 - (void)selectWord:(id)sender
 {
-    ERROR("unimplemented");
+    [self _expandSelectionToGranularity:WebSelectByWord];
 }
 
 - (void)copy:(id)sender
@@ -2329,7 +2337,7 @@ static WebHTMLView *lastHitView = nil;
     WebView *webView = [self _webView];
     WebBridge *bridge = [self _bridge];
     if ([[webView _editingDelegateForwarder] webView:webView shouldInsertText:text replacingDOMRange:[bridge selectedDOMRange] givenAction:WebViewInsertActionPasted]) {
-        [[self _bridge] replaceSelectionWithText:text selectReplacement:NO];
+        [bridge replaceSelectionWithText:text selectReplacement:NO];
     }
 }
 
@@ -2338,9 +2346,24 @@ static WebHTMLView *lastHitView = nil;
     [self _replaceSelectionWithPasteboard:[NSPasteboard generalPasteboard] selectReplacement:NO allowPlainText:NO];
 }
 
+- (DOMCSSStyleDeclaration *)_fontManagerOperationAsStyle
+{
+    WebBridge *bridge = [self _bridge];
+    DOMCSSStyleDeclaration *style = [[bridge DOMDocument] createCSSStyleDeclaration];
+    //NSFontManager *fontManager = [NSFontManager sharedFontManager];
+    //NSFont *font = [fontManager convertFont:[NSFont]]
+    // FIXME: Figure out what style change to apply!
+    return style;
+}
+
 - (void)changeFont:(id)sender
 {
-    ERROR("unimplemented");
+    DOMCSSStyleDeclaration *style = [self _fontManagerOperationAsStyle];
+    WebView *webView = [self _webView];
+    WebBridge *bridge = [self _bridge];
+    if ([[webView _editingDelegateForwarder] webView:webView shouldApplyStyle:style toElementsInDOMRange:[bridge selectedDOMRange]]) {
+        [bridge applyStyle:style];
+    }
 }
 
 - (void)changeAttributes:(id)sender
@@ -2388,7 +2411,7 @@ static WebHTMLView *lastHitView = nil;
     WebView *webView = [self _webView];
     WebBridge *bridge = [self _bridge];
     if ([[webView _editingDelegateForwarder] webView:webView shouldInsertText:@"\t" replacingDOMRange:[bridge selectedDOMRange] givenAction:WebViewInsertActionPasted]) {
-        [[self _bridge] insertText:@"\t"];
+        [bridge insertText:@"\t"];
     }
 }
 
@@ -2404,14 +2427,14 @@ static WebHTMLView *lastHitView = nil;
     WebView *webView = [self _webView];
     WebBridge *bridge = [self _bridge];
     if ([[webView _editingDelegateForwarder] webView:webView shouldInsertText:@"\n" replacingDOMRange:[bridge selectedDOMRange] givenAction:WebViewInsertActionTyped]) {
-        [bridge replaceSelectionWithNewline];
-        [bridge ensureCaretVisible];
+        [bridge insertNewline];
     }
 }
 
 - (void)insertParagraphSeparator:(id)sender
 {
-    ERROR("unimplemented");
+    // FIXME: Should this do something different?
+    [self insertNewline:sender];
 }
 
 - (void)changeCaseOfLetter:(id)sender
@@ -2419,19 +2442,31 @@ static WebHTMLView *lastHitView = nil;
     ERROR("unimplemented");
 }
 
+- (void)_changeWordCaseWithSelector:(SEL)selector
+{
+    WebView *webView = [self _webView];
+    WebBridge *bridge = [self _bridge];
+    [self selectWord:nil];
+    NSString *word = [[bridge selectedString] performSelector:selector];
+    // FIXME: Does this need a different action context other than "typed"?
+    if ([[webView _editingDelegateForwarder] webView:webView shouldInsertText:word replacingDOMRange:[bridge selectedDOMRange] givenAction:WebViewInsertActionTyped]) {
+        [bridge replaceSelectionWithText:word selectReplacement:NO];
+    }
+}
+
 - (void)uppercaseWord:(id)sender
 {
-    ERROR("unimplemented");
+    [self _changeWordCaseWithSelector:@selector(uppercaseString)];
 }
 
 - (void)lowercaseWord:(id)sender
 {
-    ERROR("unimplemented");
+    [self _changeWordCaseWithSelector:@selector(lowercaseString)];
 }
 
 - (void)capitalizeWord:(id)sender
 {
-    ERROR("unimplemented");
+    [self _changeWordCaseWithSelector:@selector(capitalizedString)];
 }
 
 - (void)deleteForward:(id)sender
@@ -2446,7 +2481,6 @@ static WebHTMLView *lastHitView = nil;
         WebView *webView = [self _webView];
         if ([[webView _editingDelegateForwarder] webView:webView shouldDeleteDOMRange:[bridge selectedDOMRange]]) {
             [bridge deleteKeyPressed];
-            [bridge ensureCaretVisible];
         }
     }
 }
@@ -2499,14 +2533,175 @@ static WebHTMLView *lastHitView = nil;
 
 - (void)checkSpelling:(id)sender
 {
-    ERROR("unimplemented");
+#if 0
+    NSTextStorage *text = _getTextStorage(self);
+    NSTextViewSharedData *sharedData = _getSharedData(self);
+    if (text && ([text length] > 0) && [self isSelectable]) {
+        NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
+        NSRange selCharRange = [self selectedRange];
+        NSRange misspellCharRange = {0, 0}, grammarCharRange = {0, 0};
+        unsigned i, count;
+        NSArray *grammarRanges = nil, *grammarDescriptions = nil;
+
+        if (!checker || [checker windowIsSpellingPanel:[self window]]) return;
+
+        misspellCharRange = [checker checkSpellingOfString:[text string] startingAt:NSMaxRange(selCharRange) language:nil wrap:YES inSpellDocumentWithTag:[self spellCheckerDocumentTag] wordCount:NULL];
+#if GRAMMAR_CHECKING
+        grammarCharRange = [checker checkGrammarOfString:[text string] startingAt:NSMaxRange(selCharRange) language:nil wrap:YES inSpellDocumentWithTag:[self spellCheckerDocumentTag] ranges:&grammarRanges descriptions:&grammarDescriptions reconnectOnError:YES];
+#endif
+
+        if (misspellCharRange.length > 0 && (grammarCharRange.length == 0 || misspellCharRange.location <= grammarCharRange.location)) {
+            // select the text and drive the panel
+            [self setSelectedRange:misspellCharRange affinity:NSSelectionAffinityUpstream stillSelecting:NO];
+            if ([self isEditable]) {
+                [self _addSpellingAttributeForRange:misspellCharRange];
+                sharedData->_excludedSpellingCharRange = misspellCharRange;
+            }
+            [self scrollRangeToVisible:misspellCharRange];
+            [checker updateSpellingPanelWithMisspelledWord:[[text string] substringWithRange:misspellCharRange]];
+        } else if (grammarCharRange.length > 0) {
+            [self setSelectedRange:grammarCharRange affinity:NSSelectionAffinityUpstream stillSelecting:NO];
+            count = [grammarRanges count];
+            if ([self isEditable]) {
+                for (i = 0; i < count; i++) {
+                    NSRange range = [grammarRanges rangeAtIndex:i];
+                    range.location += grammarCharRange.location;
+                    [self _addSpellingAttributeForRange:range];
+                    [_getLayoutManager(self) addTemporaryAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[grammarDescriptions objectAtIndex:i], NSToolTipAttributeName, nil] forCharacterRange:range];
+                }
+            }
+            [self scrollRangeToVisible:grammarCharRange];
+        } else {
+            // Cause the beep to indicate there are no more misspellings.
+            [checker updateSpellingPanelWithMisspelledWord:@""];
+        }
+    }
+#endif
 }
 
 - (void)showGuessPanel:(id)sender
 {
-    ERROR("unimplemented");
+#if 0
+    NSTextStorage *text = _getTextStorage(self);
+    NSTextViewSharedData *sharedData = _getSharedData(self);
+    NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
+    if (text && ([text length] > 0) && [self isSelectable]) {
+        NSRange selCharRange = [self selectedRange];
+        NSRange misspellCharRange = {0, 0};
+        if (checker && ![checker windowIsSpellingPanel:[self window]]) {
+            misspellCharRange = [checker checkSpellingOfString:[text string] startingAt:((selCharRange.location > 0) ? (selCharRange.location - 1) : 0) language:nil wrap:YES inSpellDocumentWithTag:[self spellCheckerDocumentTag] wordCount:NULL];
+            if (misspellCharRange.length) {
+                // select the text and drive the panel
+                [self setSelectedRange:misspellCharRange affinity:NSSelectionAffinityUpstream stillSelecting:NO];
+                if ([self isEditable]) {
+                    [self _addSpellingAttributeForRange:misspellCharRange];
+                    sharedData->_excludedSpellingCharRange = misspellCharRange;
+                }
+                [self scrollRangeToVisible:misspellCharRange];
+                [checker updateSpellingPanelWithMisspelledWord:[[text string] substringWithRange:misspellCharRange]];
+            }
+        }
+    }
+    if (checker) {
+        [[checker spellingPanel] orderFront:sender];
+    }
+#endif
+}
+
+#if 0
+
+- (void)_changeSpellingToWord:(NSString *)newWord {
+    NSRange charRange = [self rangeForUserTextChange];
+    if ([self isEditable] && charRange.location != NSNotFound) {
+        NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
+        if (!checker || [checker windowIsSpellingPanel:[self window]]) return;
+
+        // Don't correct to empty string.
+        if ([newWord isEqualToString:@""]) return;
+
+        if ([self shouldChangeTextInRange:charRange replacementString:newWord]) {
+            [self replaceCharactersInRange:charRange withString:newWord];
+            charRange.length = [newWord length];
+            [self setSelectedRange:charRange affinity:NSSelectionAffinityUpstream stillSelecting:NO];
+            [self didChangeText];
+        }
+    }
+}
+
+- (void)_changeSpellingFromMenu:(id)sender {
+    [self _changeSpellingToWord:[sender title]];
+}
+
+- (void)changeSpelling:(id)sender {
+    [self _changeSpellingToWord:[[sender selectedCell] stringValue]];
+}
+
+- (void)ignoreSpelling:(id)sender {
+    NSRange charRange = [self rangeForUserTextChange];
+    if ([self isEditable]) {
+        NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
+        NSString *stringToIgnore;
+        unsigned int length;
+
+        if (!checker) return;
+
+        stringToIgnore = [sender stringValue];
+        length = [stringToIgnore length];
+        if (stringToIgnore && length > 0) {
+            [checker ignoreWord:stringToIgnore inSpellDocumentWithTag:[self spellCheckerDocumentTag]];
+            if (length == charRange.length && [stringToIgnore isEqualToString:[[_getTextStorage(self) string] substringWithRange:charRange]]) {
+                [self _removeSpellingAttributeForRange:charRange];
+            }
+        }
+    }
+}
+
+- (void)_ignoreSpellingFromMenu:(id)sender {
+    NSRange charRange = [self rangeForUserTextChange];
+    if ([self isEditable] && charRange.location != NSNotFound && charRange.length > 0) {
+        NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
+        if (!checker || [checker windowIsSpellingPanel:[self window]]) return;
+        [self _removeSpellingAttributeForRange:charRange];
+        [checker ignoreWord:[[_getTextStorage(self) string] substringWithRange:charRange] inSpellDocumentWithTag:[self spellCheckerDocumentTag]];
+    }
+}
+
+- (void)_learnSpellingFromMenu:(id)sender {
+    NSRange charRange = [self rangeForUserTextChange];
+    if ([self isEditable] && charRange.location != NSNotFound && charRange.length > 0) {
+        NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
+        if (!checker || [checker windowIsSpellingPanel:[self window]]) return;
+        [self _removeSpellingAttributeForRange:charRange];
+        [checker learnWord:[[_getTextStorage(self) string] substringWithRange:charRange]];
+    }
+}
+
+- (void)_forgetSpellingFromMenu:(id)sender {
+    NSRange charRange = [self rangeForUserTextChange];
+    if ([self isEditable] && charRange.location != NSNotFound && charRange.length > 0) {
+        NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
+        if (!checker || [checker windowIsSpellingPanel:[self window]]) return;
+        [checker forgetWord:[[_getTextStorage(self) string] substringWithRange:charRange]];
+    }
+}
+
+- (void)_openLinkFromMenu:(id)sender {
+    NSTextStorage *text = _getTextStorage(self);
+    NSRange charRange = [self selectedRange];
+    if (charRange.location != NSNotFound && charRange.length > 0) {
+        id link = [text attribute:NSLinkAttributeName atIndex:charRange.location effectiveRange:NULL];
+        if (link) {
+            [self clickedOnLink:link atIndex:charRange.location];
+        } else {
+            NSString *string = [[text string] substringWithRange:charRange];
+            link = [NSURL URLWithString:string];
+            if (link) [[NSWorkspace sharedWorkspace] openURL:link];
+        }
+    }
 }
 
+#endif
+
 - (void)performFindPanelAction:(id)sender
 {
     ERROR("unimplemented");
@@ -2514,14 +2709,14 @@ static WebHTMLView *lastHitView = nil;
 
 - (void)startSpeaking:(id)sender
 {
-    NSString *string = [self selectedString];
-    if ([string length] == 0) {
-        // FIXME: This cast must go away, because otherwise we have XML bugs.
-        // We agreed to do this by just adding another bridge method analogous to
-        // selectedString rather than trying to straighten this out in the DOM API for now.
-        string = [(DOMHTMLElement *)[[[self _bridge] DOMDocument] documentElement] outerText];
+    WebBridge *bridge = [self _bridge];
+    DOMRange *range = [bridge selectedDOMRange];
+    if (!range || [range collapsed]) {
+        DOMDocument *document = [bridge DOMDocument];
+        range = [document createRange];
+        [range selectNode:document];
     }
-    [NSApp speakString:string];
+    [NSApp speakString:[bridge stringForRange:range]];
 }
 
 - (void)stopSpeaking:(id)sender
@@ -2536,7 +2731,6 @@ static WebHTMLView *lastHitView = nil;
         WebView *webView = [self _webView];
         if ([[webView _editingDelegateForwarder] webView:webView shouldInsertText:text replacingDOMRange:[bridge selectedDOMRange] givenAction:WebViewInsertActionTyped]) {
             [bridge insertText:text];
-            [bridge ensureCaretVisible];
         }
     }
 }
@@ -2585,7 +2779,6 @@ static WebHTMLView *lastHitView = nil;
 
 @implementation WebHTMLView (WebInternal)
 
-// FIXME: Move to WebHTMLView.
 - (void)_updateFontPanel
 {
     // FIXME: NSTextView bails out if becoming or resigning first responder, for which it has ivar flags. Not