Reviewed by Darin.
authorap@webkit.org <ap@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2007 06:21:57 +0000 (06:21 +0000)
committerap@webkit.org <ap@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2007 06:21:57 +0000 (06:21 +0000)
        http://bugs.webkit.org/show_bug.cgi?id=15954
        Move DOM Selection operations out of SelectionController

        No change in functionality.

WebCore:
        * editing/SelectionController.cpp:
        (WebCore::SelectionController::setSelectedRange):
        * editing/SelectionController.h:
        * page/DOMSelection.cpp:
        (WebCore::DOMSelection::anchorNode):
        (WebCore::DOMSelection::baseNode):
        (WebCore::DOMSelection::anchorOffset):
        (WebCore::DOMSelection::baseOffset):
        (WebCore::DOMSelection::focusNode):
        (WebCore::DOMSelection::extentNode):
        (WebCore::DOMSelection::focusOffset):
        (WebCore::DOMSelection::extentOffset):
        (WebCore::DOMSelection::isCollapsed):
        (WebCore::DOMSelection::type):
        (WebCore::DOMSelection::rangeCount):
        (WebCore::DOMSelection::collapse):
        (WebCore::DOMSelection::collapseToEnd):
        (WebCore::DOMSelection::collapseToStart):
        (WebCore::DOMSelection::empty):
        (WebCore::DOMSelection::setBaseAndExtent):
        (WebCore::DOMSelection::setPosition):
        (WebCore::DOMSelection::modify):
        (WebCore::DOMSelection::extend):
        (WebCore::DOMSelection::getRangeAt):
        (WebCore::DOMSelection::removeAllRanges):
        (WebCore::DOMSelection::addRange):
        (WebCore::DOMSelection::deleteFromDocument):
        (WebCore::DOMSelection::containsNode):
        (WebCore::DOMSelection::selectAllChildren):
        (WebCore::DOMSelection::toString):
        * page/DOMSelection.h:
        Moved all DOM API methods to DOMSelection; changed SelectionController::setSelectedRange()
        to return its result directly instead of via an ExceptionCode that no caller wanted.

        * editing/Editor.cpp:
        (WebCore::Editor::deleteRange):
        (WebCore::Editor::removeFormattingAndStyle):
        (WebCore::Editor::selectComposition):
        (WebCore::Editor::setComposition):
        * html/HTMLInputElement.cpp: (WebCore::HTMLInputElement::defaultEventHandler):
        Adapted for SelectionController::setSelectedRange() now returning a bool.
        SelectionController::toString() is no longer avasilable, use plainText() explicitly.

        * WebCore.base.exp: Changed SelectionController::setSelectedRange() signature.

WebKit:
        * WebView/WebHTMLView.mm:
        (-[WebHTMLView _expandSelectionToGranularity:]):
        (-[WebHTMLView selectToMark:]):
        (-[WebHTMLView swapWithMark:]):
        * WebView/WebView.mm:
        (-[WebView setSelectedDOMRange:affinity:]):
        Adapted for SelectionController::setSelectedRange() now returning a bool.

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

WebCore/ChangeLog
WebCore/WebCore.base.exp
WebCore/editing/Editor.cpp
WebCore/editing/SelectionController.cpp
WebCore/editing/SelectionController.h
WebCore/html/HTMLInputElement.cpp
WebCore/page/DOMSelection.cpp
WebCore/page/DOMSelection.h
WebKit/mac/ChangeLog
WebKit/mac/WebView/WebHTMLView.mm
WebKit/mac/WebView/WebView.mm

index 00187c9c7dfa3398f5a73db5490e5c3fc16c7f95..e0ab48739a737a02f9ad904824a59fb2b54d6d58 100644 (file)
@@ -1,3 +1,57 @@
+2007-11-12  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin.
+
+        http://bugs.webkit.org/show_bug.cgi?id=15954
+        Move DOM Selection operations out of SelectionController
+
+        No change in functionality.
+
+        * editing/SelectionController.cpp:
+        (WebCore::SelectionController::setSelectedRange):
+        * editing/SelectionController.h:
+        * page/DOMSelection.cpp:
+        (WebCore::DOMSelection::anchorNode):
+        (WebCore::DOMSelection::baseNode):
+        (WebCore::DOMSelection::anchorOffset):
+        (WebCore::DOMSelection::baseOffset):
+        (WebCore::DOMSelection::focusNode):
+        (WebCore::DOMSelection::extentNode):
+        (WebCore::DOMSelection::focusOffset):
+        (WebCore::DOMSelection::extentOffset):
+        (WebCore::DOMSelection::isCollapsed):
+        (WebCore::DOMSelection::type):
+        (WebCore::DOMSelection::rangeCount):
+        (WebCore::DOMSelection::collapse):
+        (WebCore::DOMSelection::collapseToEnd):
+        (WebCore::DOMSelection::collapseToStart):
+        (WebCore::DOMSelection::empty):
+        (WebCore::DOMSelection::setBaseAndExtent):
+        (WebCore::DOMSelection::setPosition):
+        (WebCore::DOMSelection::modify):
+        (WebCore::DOMSelection::extend):
+        (WebCore::DOMSelection::getRangeAt):
+        (WebCore::DOMSelection::removeAllRanges):
+        (WebCore::DOMSelection::addRange):
+        (WebCore::DOMSelection::deleteFromDocument):
+        (WebCore::DOMSelection::containsNode):
+        (WebCore::DOMSelection::selectAllChildren):
+        (WebCore::DOMSelection::toString):
+        * page/DOMSelection.h:
+        Moved all DOM API methods to DOMSelection; changed SelectionController::setSelectedRange()
+        to return its result directly instead of via an ExceptionCode that no caller wanted.
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::deleteRange):
+        (WebCore::Editor::removeFormattingAndStyle):
+        (WebCore::Editor::selectComposition):
+        (WebCore::Editor::setComposition):
+        * html/HTMLInputElement.cpp: (WebCore::HTMLInputElement::defaultEventHandler):
+        Adapted for SelectionController::setSelectedRange() now returning a bool.
+        SelectionController::toString() is no longer avasilable, use plainText() explicitly.
+
+        * WebCore.base.exp: Changed SelectionController::setSelectedRange() signature.
+
 2007-11-12  Dan Bernstein  <mitz@apple.com>
 
         Reviewed by Darin Adler.
index 3fcf5c4828984720ae5b9659e058fe4e5f6ab165..16bef8f3d7388f411e9fc63d707820f7d0925ad3 100644 (file)
@@ -331,7 +331,7 @@ __ZN7WebCore19InspectorController16setWindowVisibleEb
 __ZN7WebCore19InspectorController4showEv
 __ZN7WebCore19InspectorController5closeEv
 __ZN7WebCore19InspectorController7inspectEPNS_4NodeE
-__ZN7WebCore19SelectionController16setSelectedRangeEPNS_5RangeENS_9EAffinityEbRi
+__ZN7WebCore19SelectionController16setSelectedRangeEPNS_5RangeENS_9EAffinityEb
 __ZN7WebCore19SelectionController5clearEv
 __ZN7WebCore19SelectionController9selectAllEv
 __ZN7WebCore19TextResourceDecoder5flushEv
index e37bce7438b112d851bf4f483c7c892567a142bc..2906b8d640b861d2d41e984da18789b33e555f2c 100644 (file)
@@ -237,20 +237,16 @@ void Editor::deleteRange(Range* range, bool killRing, bool prepend, bool smartDe
     if (killRing)
         addToKillRing(range, prepend);
 
-    ExceptionCode ec = 0;
-
     SelectionController* selectionController = m_frame->selectionController();
     bool smartDelete = smartDeleteOK && canSmartCopyOrDelete();
     switch (deletionAction) {
         case deleteSelectionAction:
-            selectionController->setSelectedRange(range, DOWNSTREAM, true, ec);
-            if (ec)
+            if (!selectionController->setSelectedRange(range, DOWNSTREAM, true))
                 return;
             deleteSelectionWithSmartDelete(smartDelete);
             break;
         case deleteKeyAction:
-            selectionController->setSelectedRange(range, DOWNSTREAM, (granularity != CharacterGranularity), ec);
-            if (ec)
+            if (!selectionController->setSelectedRange(range, DOWNSTREAM, (granularity != CharacterGranularity)))
                 return;
             if (m_frame->document()) {
                 TypingCommand::deleteKeyPressed(m_frame->document(), smartDelete, granularity);
@@ -258,8 +254,7 @@ void Editor::deleteRange(Range* range, bool killRing, bool prepend, bool smartDe
             }
             break;
         case forwardDeleteKeyAction:
-            selectionController->setSelectedRange(range, DOWNSTREAM, (granularity != CharacterGranularity), ec);
-            if (ec)
+            if (!selectionController->setSelectedRange(range, DOWNSTREAM, (granularity != CharacterGranularity)))
                 return;
             if (m_frame->document()) {
                 TypingCommand::forwardDeleteKeyPressed(m_frame->document(), smartDelete, granularity);
@@ -617,8 +612,8 @@ void Editor::removeFormattingAndStyle()
     Document* document = m_frame->document();
     
     // Make a plain text string from the selection to remove formatting like tables and lists.
-    String string = m_frame->selectionController()->toString();
-    
+    String string = plainText(m_frame->selectionController()->selection().toRange().get());
+
     // Get the default style for this editable root, it's the style that we'll give the
     // content that we're operating on.
     Node* root = m_frame->selectionController()->rootEditableElement();
@@ -1670,8 +1665,7 @@ void Editor::selectComposition()
     RefPtr<Range> range = compositionRange();
     if (!range)
         return;
-    ExceptionCode ec = 0;
-    m_frame->selectionController()->setSelectedRange(range.get(), DOWNSTREAM, false, ec);
+    m_frame->selectionController()->setSelectedRange(range.get(), DOWNSTREAM, false);
 }
 
 void Editor::confirmComposition()
@@ -1742,9 +1736,9 @@ void Editor::setComposition(const String& text, const Vector<CompositionUnderlin
     if (!text.isEmpty()) {
         TypingCommand::insertText(m_frame->document(), text, true, true);
 
-        Node* baseNode = m_frame->selectionController()->baseNode();
+        Node* baseNode = m_frame->selectionController()->base().node();
         unsigned baseOffset = m_frame->selectionController()->base().offset();
-        Node* extentNode = m_frame->selectionController()->extentNode();
+        Node* extentNode = m_frame->selectionController()->extent().node();
         unsigned extentOffset = m_frame->selectionController()->extent().offset();
 
         if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
@@ -1763,8 +1757,7 @@ void Editor::setComposition(const String& text, const Vector<CompositionUnderlin
             unsigned start = min(baseOffset + selectionStart, extentOffset);
             unsigned end = min(max(start, baseOffset + selectionEnd), extentOffset);
             RefPtr<Range> selectedRange = new Range(baseNode->document(), baseNode, start, baseNode, end);                
-            ExceptionCode ec = 0;
-            m_frame->selectionController()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false, ec);
+            m_frame->selectionController()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false);
         }
     }
 
index b71b91173ec90cb742f089e2c411c51f9f2c4d39..889a2f28148b8e35b2f1400428641dd2683e660a 100644 (file)
@@ -407,56 +407,6 @@ VisiblePosition SelectionController::modifyMovingLeftBackward(TextGranularity gr
     return pos;
 }
 
-bool SelectionController::modify(const String &alterString, const String &directionString, const String &granularityString, bool userTriggered)
-{
-    String alterStringLower = alterString.lower();
-    EAlteration alter;
-    if (alterStringLower == "extend")
-        alter = EXTEND;
-    else if (alterStringLower == "move")
-        alter = MOVE;
-    else 
-        return false;
-    
-    String directionStringLower = directionString.lower();
-    EDirection direction;
-    if (directionStringLower == "forward")
-        direction = FORWARD;
-    else if (directionStringLower == "backward")
-        direction = BACKWARD;
-    else if (directionStringLower == "left")
-        direction = LEFT;
-    else if (directionStringLower == "right")
-        direction = RIGHT;
-    else
-        return false;
-        
-    String granularityStringLower = granularityString.lower();
-    TextGranularity granularity;
-    if (granularityStringLower == "character")
-        granularity = CharacterGranularity;
-    else if (granularityStringLower == "word")
-        granularity = WordGranularity;
-    else if (granularityStringLower == "sentence")
-        granularity = SentenceGranularity;
-    else if (granularityStringLower == "line")
-        granularity = LineGranularity;
-    else if (granularityStringLower == "paragraph")
-        granularity = ParagraphGranularity;
-    else if (granularityStringLower == "lineboundary")
-        granularity = LineBoundary;
-    else if (granularityStringLower == "sentenceboundary")
-        granularity = SentenceBoundary;
-    else if (granularityStringLower == "paragraphboundary")
-        granularity = ParagraphBoundary;
-    else if (granularityStringLower == "documentboundary")
-        granularity = DocumentBoundary;
-    else
-        return false;
-                
-    return modify(alter, direction, granularity, userTriggered);
-}
-
 bool SelectionController::modify(EAlteration alter, EDirection dir, TextGranularity granularity, bool userTriggered)
 {
     if (userTriggered) {
@@ -706,240 +656,6 @@ void SelectionController::setNeedsLayout(bool flag)
     m_needsLayout = flag;
 }
 
-String SelectionController::type() const
-{
-    if (isNone())
-        return "None";
-    else if (isCaret())
-        return "Caret";
-    else
-        return "Range";
-}
-
-// These methods are accessible via JS (and are not used internally), so they must return valid DOM positions.
-Node* SelectionController::baseNode() const
-{
-    Position base = rangeCompliantEquivalent(m_sel.base());
-    return base.node();
-}
-
-int SelectionController::baseOffset() const
-{
-    Position base = rangeCompliantEquivalent(m_sel.base());
-    return base.offset();
-}
-
-Node* SelectionController::extentNode() const
-{
-    Position extent = rangeCompliantEquivalent(m_sel.extent());
-    return extent.node();
-}
-
-int SelectionController::extentOffset() const
-{
-    Position extent = rangeCompliantEquivalent(m_sel.extent());
-    return extent.offset();
-}
-
-Node* SelectionController::anchorNode() const
-{
-    Position anchor = m_sel.isBaseFirst() ? m_sel.start() : m_sel.end();
-    anchor = rangeCompliantEquivalent(anchor);
-    return anchor.node();
-}
-
-int SelectionController::anchorOffset() const
-{
-    Position anchor = m_sel.isBaseFirst() ? m_sel.start() : m_sel.end();
-    anchor = rangeCompliantEquivalent(anchor);
-    return anchor.offset();
-}
-
-Node* SelectionController::focusNode() const
-{
-    Position focus = m_sel.isBaseFirst() ? m_sel.end() : m_sel.start();
-    focus = rangeCompliantEquivalent(focus);
-    return focus.node();
-}
-
-int SelectionController::focusOffset() const
-{
-    Position focus = m_sel.isBaseFirst() ? m_sel.end() : m_sel.start();
-    focus = rangeCompliantEquivalent(focus);
-    return focus.offset();
-}
-
-String SelectionController::toString() const
-{
-    return plainText(m_sel.toRange().get());
-}
-
-PassRefPtr<Range> SelectionController::getRangeAt(int index, ExceptionCode& ec) const
-{
-    if (index < 0 || index >= rangeCount()) {
-        ec = INDEX_SIZE_ERR;
-        return 0;
-    }   
-    return m_sel.toRange();
-}
-
-void SelectionController::removeAllRanges()
-{
-    clear();
-}
-
-// Adds r to the currently selected range.
-void SelectionController::addRange(const Range* r)
-{
-    if (!r)
-        return;
-    
-    if (isNone()) {
-        setSelection(Selection(r));
-        return;
-    }
-
-    RefPtr<Range> range = m_sel.toRange();
-    ExceptionCode ec = 0;
-    if (r->compareBoundaryPoints(Range::START_TO_START, range.get(), ec) == -1) {
-        // We don't support discontiguous selection. We don't do anything if r and range don't intersect.
-        if (r->compareBoundaryPoints(Range::END_TO_START, range.get(), ec) > -1) {
-            if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1)
-                // The original range and r intersect.
-                setSelection(Selection(r->startPosition(), range->endPosition(), DOWNSTREAM));
-            else
-                // r contains the original range.
-                setSelection(Selection(r));
-        }
-    } else {
-        // We don't support discontiguous selection. We don't do anything if r and range don't intersect.
-        if (r->compareBoundaryPoints(Range::START_TO_END, range.get(), ec) < 1) {
-            if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1)
-                // The original range contains r.
-                setSelection(Selection(range.get()));
-            else
-                // The original range and r intersect.
-                setSelection(Selection(range->startPosition(), r->endPosition(), DOWNSTREAM));
-        }
-    }
-}
-
-void SelectionController::deleteFromDocument()
-{
-    if (isNone())
-        return;
-
-    if (isCollapsed())
-        modify(EXTEND, BACKWARD, CharacterGranularity);
-
-    RefPtr<Range> selectedRange = m_sel.toRange();
-
-    ExceptionCode ec = 0;
-    selectedRange->deleteContents(ec);
-    ASSERT(!ec);
-    
-    setBaseAndExtent(selectedRange->startContainer(ec), selectedRange->startOffset(ec), selectedRange->startContainer(ec), selectedRange->startOffset(ec), ec);
-    ASSERT(!ec);
-}
-
-bool SelectionController::containsNode(const Node* n, bool allowPartial) const
-{
-    if (!n || isNone())
-        return false;
-
-    Node* parentNode = n->parentNode();
-    unsigned nodeIndex = n->nodeIndex();
-    RefPtr<Range> selectedRange = m_sel.toRange();
-
-    if (!parentNode)
-        return false;
-
-    ExceptionCode ec = 0;
-    bool nodeFullySelected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->startContainer(ec), selectedRange->startOffset(ec)) >= 0
-        && Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->endContainer(ec), selectedRange->endOffset(ec)) <= 0;
-    ASSERT(!ec);
-    if (nodeFullySelected)
-        return true;
-
-    bool nodeFullyUnselected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->endContainer(ec), selectedRange->endOffset(ec)) > 0
-        || Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->startContainer(ec), selectedRange->startOffset(ec)) < 0;
-    ASSERT(!ec);
-    if (nodeFullyUnselected)
-        return false;
-
-    return allowPartial || n->isTextNode();
-}
-
-void SelectionController::selectAllChildren(Node* n, ExceptionCode& ec)
-{
-    if (!n)
-        return;
-
-    // This doesn't (and shouldn't) select text node characters.
-    setBaseAndExtent(n, 0, n, n->childNodeCount(), ec);
-}
-
-void SelectionController::setBaseAndExtent(Node *baseNode, int baseOffset, Node *extentNode, int extentOffset, ExceptionCode& ec)
-{
-    if (baseOffset < 0 || extentOffset < 0) {
-        ec = INDEX_SIZE_ERR;
-        return;
-    }
-    VisiblePosition visibleBase = VisiblePosition(baseNode, baseOffset, DOWNSTREAM);
-    VisiblePosition visibleExtent = VisiblePosition(extentNode, extentOffset, DOWNSTREAM);
-    
-    moveTo(visibleBase, visibleExtent);
-}
-
-void SelectionController::setPosition(Node *node, int offset, ExceptionCode& ec)
-{
-    if (offset < 0) {
-        ec = INDEX_SIZE_ERR;
-        return;
-    }
-    moveTo(VisiblePosition(node, offset, DOWNSTREAM));
-}
-
-void SelectionController::collapse(Node *node, int offset, ExceptionCode& ec)
-{
-    if (offset < 0) {
-        ec = INDEX_SIZE_ERR;
-        return;
-    }
-    moveTo(VisiblePosition(node, offset, DOWNSTREAM));
-}
-
-void SelectionController::collapseToEnd()
-{
-    moveTo(VisiblePosition(m_sel.end(), DOWNSTREAM));
-}
-
-void SelectionController::collapseToStart()
-{
-    moveTo(VisiblePosition(m_sel.start(), DOWNSTREAM));
-}
-
-void SelectionController::empty()
-{
-    moveTo(VisiblePosition());
-}
-
-void SelectionController::extend(Node* node, int offset, ExceptionCode& ec)
-{
-    if (!node) {
-        ec = TYPE_MISMATCH_ERR;
-        return;
-    }
-    if (offset < 0
-        || node->offsetInCharacters() && offset > caretMaxOffset(node)
-        || !node->offsetInCharacters() && offset > (int)node->childNodeCount()) {
-        ec = INDEX_SIZE_ERR;
-        return;
-    }
-    m_sel.expandUsingGranularity(CharacterGranularity);
-    setExtent(VisiblePosition(node, offset, DOWNSTREAM));
-}
-
 void SelectionController::layout()
 {
     if (isNone() || !m_sel.start().node()->inDocument() || !m_sel.end().node()->inDocument()) {
@@ -1244,22 +960,19 @@ void SelectionController::selectAll()
     m_frame->notifyRendererOfSelectionChange(true);
 }
 
-void SelectionController::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping, ExceptionCode& ec)
+bool SelectionController::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping)
 {
-    ec = 0;
-    
-    if (!range) {
-        ec = INVALID_STATE_ERR;
-        return;
-    }
-    
+    if (!range)
+        return false;
+
+    ExceptionCode ec = 0;
     Node* startContainer = range->startContainer(ec);
     if (ec)
-        return;
+        return false;
 
     Node* endContainer = range->endContainer(ec);
     if (ec)
-        return;
+        return false;
     
     ASSERT(startContainer);
     ASSERT(endContainer);
@@ -1271,20 +984,21 @@ void SelectionController::setSelectedRange(Range* range, EAffinity affinity, boo
     // they start at the beginning of the next line instead
     bool collapsed = range->collapsed(ec);
     if (ec)
-        return;
+        return false;
     
     int startOffset = range->startOffset(ec);
     if (ec)
-        return;
+        return false;
 
     int endOffset = range->endOffset(ec);
     if (ec)
-        return;
+        return false;
     
     // FIXME: Can we provide extentAffinity?
     VisiblePosition visibleStart(startContainer, startOffset, collapsed ? affinity : DOWNSTREAM);
     VisiblePosition visibleEnd(endContainer, endOffset, SEL_DEFAULT_AFFINITY);
     setSelection(Selection(visibleStart, visibleEnd), closeTyping);
+    return true;
 }
 
 bool SelectionController::isInPasswordField() const
index b6fa3fecf59d57ecac770ddfd323cf04ff679b50..7c8c0188c91c833edcee031a882dea8823685c77 100644 (file)
@@ -57,7 +57,7 @@ public:
 
     const Selection& selection() const { return m_sel; }
     void setSelection(const Selection&, bool closeTyping = true, bool clearTypingStyle = true, bool userTriggered = false);
-    void setSelectedRange(Range*, EAffinity, bool closeTyping, ExceptionCode&);
+    bool setSelectedRange(Range*, EAffinity, bool closeTyping);
     void selectAll();
     void clear();
     
@@ -103,46 +103,6 @@ public:
     
     void nodeWillBeRemoved(Node*);
 
-    // Safari Selection Object API
-    // These methods return the valid equivalents of internal editing positions.
-    Node* baseNode() const;
-    Node* extentNode() const;
-    int baseOffset() const;
-    int extentOffset() const;
-    String type() const;
-    void setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionCode&);
-    void setPosition(Node*, int offset, ExceptionCode&);
-    bool modify(const String& alterString, const String& directionString, const String& granularityString, bool userTriggered = false);
-    
-    // Mozilla Selection Object API
-    // In Firefox, anchor/focus are the equal to the start/end of the selection,
-    // but reflect the direction in which the selection was made by the user.  That does
-    // not mean that they are base/extent, since the base/extent don't reflect
-    // expansion.
-    // These methods return the valid equivalents of internal editing positions.
-    Node* anchorNode() const;
-    int anchorOffset() const;
-    Node* focusNode() const;
-    int focusOffset() const;
-    bool isCollapsed() const { return !isRange(); }
-    String toString() const;
-    void collapse(Node*, int offset, ExceptionCode&);
-    void collapseToEnd();
-    void collapseToStart();
-    void extend(Node*, int offset, ExceptionCode&);
-    PassRefPtr<Range> getRangeAt(int index, ExceptionCode&) const;
-    int rangeCount() const { return !isNone() ? 1 : 0; }
-    void removeAllRanges();
-    void addRange(const Range*);
-    void deleteFromDocument();
-    bool containsNode(const Node*, bool allowPartial) const;
-    void selectAllChildren(Node*, ExceptionCode&);
-    
-    // Microsoft Selection Object API
-    void empty();
-    //void clear();
-    //TextRange *createRange();
-    
     bool recomputeCaretRect(); // returns true if caret rect moved
     void invalidateCaretRect();
     void paintCaret(GraphicsContext*, const IntRect&);
index d906e7802c6c04c9643f775e498702856721fb7c..454248ed9d990f3c79f246031bdf1598efc83c9c 100644 (file)
@@ -53,6 +53,7 @@
 #include "SelectionController.h"
 #include "TextBreakIterator.h"
 #include "TextEvent.h"
+#include "TextIterator.h"
 
 using namespace std;
 
@@ -1292,7 +1293,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
         // Make sure that the text to be inserted will not violate the maxLength.
         int oldLen = numGraphemeClusters(value().impl());
         ASSERT(oldLen <= maxLength());
-        int selectionLen = numGraphemeClusters(document()->frame()->selectionController()->toString().impl());
+        int selectionLen = numGraphemeClusters(plainText(document()->frame()->selectionController()->selection().toRange().get()).impl());
         ASSERT(oldLen >= selectionLen);
         int maxNewLen = maxLength() - (oldLen - selectionLen);
 
index c0e47b39dbdd41810259fc0c587f6b5317faf43e..908848402c9d0cf8cd3d150ba3cdd6b778399d07 100644 (file)
 #include "config.h"
 #include "DOMSelection.h"
 
+#include "ExceptionCode.h"
 #include "Frame.h"
+#include "htmlediting.h"
 #include "Node.h"
 #include "PlatformString.h"
 #include "Range.h"
 #include "SelectionController.h"
+#include "TextIterator.h"
 
 namespace WebCore {
 
@@ -57,189 +60,375 @@ Node* DOMSelection::anchorNode() const
 {
     if (!m_frame)
         return 0;
-    return m_frame->selectionController()->anchorNode();
+
+    const Selection& selection = m_frame->selectionController()->selection();
+    Position anchor = selection.isBaseFirst() ? selection.start() : selection.end();
+    anchor = rangeCompliantEquivalent(anchor);
+    return anchor.node();
 }
 
 Node* DOMSelection::baseNode() const
 {
     if (!m_frame)
         return 0;
-    return m_frame->selectionController()->baseNode();
+    return rangeCompliantEquivalent(m_frame->selectionController()->selection().base()).node();
 }
 
 int DOMSelection::anchorOffset() const
 {
     if (!m_frame)
         return 0;
-    return m_frame->selectionController()->anchorOffset();
+
+    const Selection& selection = m_frame->selectionController()->selection();
+    Position anchor = selection.isBaseFirst() ? selection.start() : selection.end();
+    anchor = rangeCompliantEquivalent(anchor);
+    return anchor.offset();
 }
 
 int DOMSelection::baseOffset() const
 {
     if (!m_frame)
         return 0;
-    return m_frame->selectionController()->baseOffset();
+    return rangeCompliantEquivalent(m_frame->selectionController()->selection().base()).offset();
 }
 
 Node* DOMSelection::focusNode() const
 {
     if (!m_frame)
         return 0;
-    return m_frame->selectionController()->focusNode();
+
+    const Selection& selection = m_frame->selectionController()->selection();
+    Position focus = selection.isBaseFirst() ? selection.end() : selection.start();
+    focus = rangeCompliantEquivalent(focus);
+    return focus.node();
 }
 
 Node* DOMSelection::extentNode() const
 {
     if (!m_frame)
         return 0;
-    return m_frame->selectionController()->extentNode();
+    return rangeCompliantEquivalent(m_frame->selectionController()->selection().extent()).node();
 }
 
 int DOMSelection::focusOffset() const
 {
     if (!m_frame)
         return 0;
-    return m_frame->selectionController()->focusOffset();
+
+    const Selection& selection = m_frame->selectionController()->selection();
+    Position focus = selection.isBaseFirst() ? selection.end() : selection.start();
+    focus = rangeCompliantEquivalent(focus);
+    return focus.offset();
 }
 
 int DOMSelection::extentOffset() const
 {
     if (!m_frame)
         return 0;
-    return m_frame->selectionController()->extentOffset();
+    return rangeCompliantEquivalent(m_frame->selectionController()->selection().extent()).offset();
 }
 
 bool DOMSelection::isCollapsed() const
 {
     if (!m_frame)
         return false;
-    return m_frame->selectionController()->isCollapsed();
+    return !m_frame->selectionController()->isRange();
 }
 
 String DOMSelection::type() const
 {
     if (!m_frame)
         return String();
-    return m_frame->selectionController()->type();
+
+    SelectionController* selectionController = m_frame->selectionController();
+
+    if (selectionController->isNone())
+        return "None";
+    if (selectionController->isCaret())
+        return "Caret";
+    return "Range";
 }
 
 int DOMSelection::rangeCount() const
 {
     if (!m_frame)
         return 0;
-    return m_frame->selectionController()->rangeCount();
+    return m_frame->selectionController()->isNone() ? 0 : 1;
 }
 
 void DOMSelection::collapse(Node* node, int offset, ExceptionCode& ec)
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->collapse(node, offset, ec);
+
+    if (offset < 0) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+    m_frame->selectionController()->moveTo(VisiblePosition(node, offset, DOWNSTREAM));
 }
 
 void DOMSelection::collapseToEnd()
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->collapseToEnd();
+
+    const Selection& selection = m_frame->selectionController()->selection();
+    m_frame->selectionController()->moveTo(VisiblePosition(selection.end(), DOWNSTREAM));
 }
 
 void DOMSelection::collapseToStart()
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->collapseToStart();
+
+    const Selection& selection = m_frame->selectionController()->selection();
+    m_frame->selectionController()->moveTo(VisiblePosition(selection.start(), DOWNSTREAM));
 }
 
 void DOMSelection::empty()
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->empty();
+    m_frame->selectionController()->moveTo(VisiblePosition());
 }
 
 void DOMSelection::setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionCode& ec)
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->setBaseAndExtent(baseNode, baseOffset, extentNode, extentOffset, ec);
+
+    if (baseOffset < 0 || extentOffset < 0) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+    VisiblePosition visibleBase = VisiblePosition(baseNode, baseOffset, DOWNSTREAM);
+    VisiblePosition visibleExtent = VisiblePosition(extentNode, extentOffset, DOWNSTREAM);
+    
+    m_frame->selectionController()->moveTo(visibleBase, visibleExtent);
 }
 
 void DOMSelection::setPosition(Node* node, int offset, ExceptionCode& ec)
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->setPosition(node, offset, ec);
+    if (offset < 0) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+    m_frame->selectionController()->moveTo(VisiblePosition(node, offset, DOWNSTREAM));
 }
 
 void DOMSelection::setPosition(Node* node, ExceptionCode& ec)
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->setPosition(node, 0, ec);
+    m_frame->selectionController()->moveTo(VisiblePosition(node, 0, DOWNSTREAM));
 }
 
-void DOMSelection::modify(const String& alter, const String& direction, const String& granularity)
+void DOMSelection::modify(const String& alterString, const String& directionString, const String& granularityString)
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->modify(alter, direction, granularity);
+
+    String alterStringLower = alterString.lower();
+    SelectionController::EAlteration alter;
+    if (alterStringLower == "extend")
+        alter = SelectionController::EXTEND;
+    else if (alterStringLower == "move")
+        alter = SelectionController::MOVE;
+    else 
+        return;
+    
+    String directionStringLower = directionString.lower();
+    SelectionController::EDirection direction;
+    if (directionStringLower == "forward")
+        direction = SelectionController::FORWARD;
+    else if (directionStringLower == "backward")
+        direction = SelectionController::BACKWARD;
+    else if (directionStringLower == "left")
+        direction = SelectionController::LEFT;
+    else if (directionStringLower == "right")
+        direction = SelectionController::RIGHT;
+    else
+        return;
+        
+    String granularityStringLower = granularityString.lower();
+    TextGranularity granularity;
+    if (granularityStringLower == "character")
+        granularity = CharacterGranularity;
+    else if (granularityStringLower == "word")
+        granularity = WordGranularity;
+    else if (granularityStringLower == "sentence")
+        granularity = SentenceGranularity;
+    else if (granularityStringLower == "line")
+        granularity = LineGranularity;
+    else if (granularityStringLower == "paragraph")
+        granularity = ParagraphGranularity;
+    else if (granularityStringLower == "lineboundary")
+        granularity = LineBoundary;
+    else if (granularityStringLower == "sentenceboundary")
+        granularity = SentenceBoundary;
+    else if (granularityStringLower == "paragraphboundary")
+        granularity = ParagraphBoundary;
+    else if (granularityStringLower == "documentboundary")
+        granularity = DocumentBoundary;
+    else
+        return;
+
+    m_frame->selectionController()->modify(alter, direction, granularity, false);
 }
 
-void DOMSelection::extend(Node* n, int offset, ExceptionCode& ec)
+void DOMSelection::extend(Node* node, int offset, ExceptionCode& ec)
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->extend(n, offset, ec);
+
+    if (!node) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+    if (offset < 0 || offset > (node->offsetInCharacters() ? caretMaxOffset(node) : (int)node->childNodeCount())) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    SelectionController* selectionController = m_frame->selectionController();
+    selectionController->expandUsingGranularity(CharacterGranularity);
+    selectionController->setExtent(VisiblePosition(node, offset, DOWNSTREAM));
 }
 
 PassRefPtr<Range> DOMSelection::getRangeAt(int index, ExceptionCode& ec)
 {
     if (!m_frame)
         return 0;
-    return m_frame->selectionController()->getRangeAt(index, ec);
+
+    if (index < 0 || index >= rangeCount()) {
+        ec = INDEX_SIZE_ERR;
+        return 0;
+    }
+
+    const Selection& selection = m_frame->selectionController()->selection();
+    return selection.toRange();
 }
 
 void DOMSelection::removeAllRanges()
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->removeAllRanges();
+    m_frame->selectionController()->clear();
 }
 
-void DOMSelection::addRange(Range* range)
+void DOMSelection::addRange(Range* r)
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->addRange(range);
+    if (!r)
+        return;
+
+    SelectionController* selectionController = m_frame->selectionController();
+    
+    if (selectionController->isNone()) {
+        selectionController->setSelection(Selection(r));
+        return;
+    }
+
+    RefPtr<Range> range = selectionController->selection().toRange();
+    ExceptionCode ec = 0;
+    if (r->compareBoundaryPoints(Range::START_TO_START, range.get(), ec) == -1) {
+        // We don't support discontiguous selection. We don't do anything if r and range don't intersect.
+        if (r->compareBoundaryPoints(Range::END_TO_START, range.get(), ec) > -1) {
+            if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1)
+                // The original range and r intersect.
+                selectionController->setSelection(Selection(r->startPosition(), range->endPosition(), DOWNSTREAM));
+            else
+                // r contains the original range.
+                selectionController->setSelection(Selection(r));
+        }
+    } else {
+        // We don't support discontiguous selection. We don't do anything if r and range don't intersect.
+        if (r->compareBoundaryPoints(Range::START_TO_END, range.get(), ec) < 1) {
+            if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1)
+                // The original range contains r.
+                selectionController->setSelection(Selection(range.get()));
+            else
+                // The original range and r intersect.
+                selectionController->setSelection(Selection(range->startPosition(), r->endPosition(), DOWNSTREAM));
+        }
+    }
 }
 
 void DOMSelection::deleteFromDocument()
 {
     if (!m_frame)
         return;
-    m_frame->selectionController()->deleteFromDocument();
+
+    SelectionController* selectionController = m_frame->selectionController();
+
+    if (selectionController->isNone())
+        return;
+
+    if (isCollapsed())
+        selectionController->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity);
+
+    RefPtr<Range> selectedRange = selectionController->selection().toRange();
+
+    ExceptionCode ec = 0;
+    selectedRange->deleteContents(ec);
+    ASSERT(!ec);
+    
+    setBaseAndExtent(selectedRange->startContainer(ec), selectedRange->startOffset(ec), selectedRange->startContainer(ec), selectedRange->startOffset(ec), ec);
+    ASSERT(!ec);
 }
 
 bool DOMSelection::containsNode(const Node* n, bool allowPartial) const
 {
     if (!m_frame)
         return false;
-    return m_frame->selectionController()->containsNode(n, allowPartial);
+
+    SelectionController* selectionController = m_frame->selectionController();
+
+    if (!n || selectionController->isNone())
+        return false;
+
+    Node* parentNode = n->parentNode();
+    unsigned nodeIndex = n->nodeIndex();
+    RefPtr<Range> selectedRange = selectionController->selection().toRange();
+
+    if (!parentNode)
+        return false;
+
+    ExceptionCode ec = 0;
+    bool nodeFullySelected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->startContainer(ec), selectedRange->startOffset(ec)) >= 0
+        && Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->endContainer(ec), selectedRange->endOffset(ec)) <= 0;
+    ASSERT(!ec);
+    if (nodeFullySelected)
+        return true;
+
+    bool nodeFullyUnselected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->endContainer(ec), selectedRange->endOffset(ec)) > 0
+        || Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->startContainer(ec), selectedRange->startOffset(ec)) < 0;
+    ASSERT(!ec);
+    if (nodeFullyUnselected)
+        return false;
+
+    return allowPartial || n->isTextNode();
 }
 
 void DOMSelection::selectAllChildren(Node* n, ExceptionCode& ec)
 {
-    if (!m_frame)
+    if (!n)
         return;
-    m_frame->selectionController()->selectAllChildren(n, ec);
+
+    // This doesn't (and shouldn't) select text node characters.
+    setBaseAndExtent(n, 0, n, n->childNodeCount(), ec);
 }
 
 String DOMSelection::toString()
 {
     if (!m_frame)
         return String();
-    return m_frame->selectionController()->toString();
+
+    return plainText(m_frame->selectionController()->selection().toRange().get());
 }
 
 } // namespace WebCore
index 466da54e96480886c510c22c5af8d5faea92c6b3..489849ba3d516abe1af831693ae10296bd5d22be 100644 (file)
@@ -50,26 +50,33 @@ namespace WebCore {
         Frame* frame() const;
         void disconnectFrame();
 
-        Node* anchorNode() const;
+        // Safari Selection Object API
+        // These methods return the valid equivalents of internal editing positions.
         Node* baseNode() const;
-        int anchorOffset() const;
+        Node* extentNode() const;
         int baseOffset() const;
+        int extentOffset() const;
+        String type() const;
+        void setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionCode&);
+        void setPosition(Node*, int offset, ExceptionCode&);
+        void setPosition(Node*, ExceptionCode&);
+        void modify(const String& alter, const String& direction, const String& granularity);
+
+        // Mozilla Selection Object API
+        // In Firefox, anchor/focus are the equal to the start/end of the selection,
+        // but reflect the direction in which the selection was made by the user.  That does
+        // not mean that they are base/extent, since the base/extent don't reflect
+        // expansion.
+        // These methods return the valid equivalents of internal editing positions.
+        Node* anchorNode() const;
+        int anchorOffset() const;
         Node* focusNode() const;
-        Node* extentNode() const;
         int focusOffset() const;
-        int extentOffset() const;
         bool isCollapsed() const;
-        String type() const;
         int rangeCount() const;
-
         void collapse(Node*, int offset, ExceptionCode&);
         void collapseToEnd();
         void collapseToStart();
-        void empty();
-        void setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionCode&);
-        void setPosition(Node*, int offset, ExceptionCode&);
-        void setPosition(Node*, ExceptionCode&);
-        void modify(const String& alter, const String& direction, const String& granularity);
         void extend(Node*, int offset, ExceptionCode&);
         PassRefPtr<Range> getRangeAt(int, ExceptionCode&);
         void removeAllRanges();
@@ -80,6 +87,11 @@ namespace WebCore {
 
         String toString();
 
+        // Microsoft Selection Object API
+        void empty();
+        //void clear();
+        //TextRange *createRange();
+
     private:
         Frame* m_frame;
     };
index 418d3f54c4c0aa924fdfaad7ea245aa14d5e5cd9..1b40105e400d63f2600b1891aa6c04ba251aa103 100644 (file)
@@ -1,3 +1,18 @@
+2007-11-12  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin.
+
+        http://bugs.webkit.org/show_bug.cgi?id=15954
+        Move DOM Selection operations out of SelectionController
+
+        * WebView/WebHTMLView.mm:
+        (-[WebHTMLView _expandSelectionToGranularity:]):
+        (-[WebHTMLView selectToMark:]):
+        (-[WebHTMLView swapWithMark:]):
+        * WebView/WebView.mm:
+        (-[WebView setSelectedDOMRange:affinity:]):
+        Adapted for SelectionController::setSelectedRange() now returning a bool.
+
 2007-11-12  Oliver Hunt  <oliver@apple.com>
 
         Reviewed by Darin and Geoff.
index 86c8e0f31995079679e9cdd186155cc1828752c0..21f59733ee6667787b431e32968811a3a715cc4b 100644 (file)
@@ -3717,8 +3717,7 @@ noPromisedData:
     EAffinity affinity = coreFrame->selectionController()->affinity();
     WebView *webView = [self _webView];
     if ([[webView _editingDelegateForwarder] webView:webView shouldChangeSelectedDOMRange:[self _selectedRange] toDOMRange:domRange affinity:kit(affinity) stillSelecting:NO]) {
-        ExceptionCode ec = 0;
-        coreFrame->selectionController()->setSelectedRange(range.get(), affinity, true, ec);
+        coreFrame->selectionController()->setSelectedRange(range.get(), affinity, true);
     }
 }
 
@@ -4676,8 +4675,7 @@ static DOMRange *unionDOMRanges(DOMRange *a, DOMRange *b)
         NSBeep();
         return;
     }
-    ExceptionCode ec = 0;
-    coreFrame->selectionController()->setSelectedRange(core(unionDOMRanges(mark, [self _selectedRange])), DOWNSTREAM, true, ec);
+    coreFrame->selectionController()->setSelectedRange(core(unionDOMRanges(mark, [self _selectedRange])), DOWNSTREAM, true);
 }
 
 - (void)swapWithMark:(id)sender
@@ -4693,9 +4691,7 @@ static DOMRange *unionDOMRanges(DOMRange *a, DOMRange *b)
         return;
     }
 
-    ExceptionCode ec = 0;
-    coreFrame->selectionController()->setSelectedRange(core(mark), DOWNSTREAM, true, ec);
-    if (ec == 0)
+    if (coreFrame->selectionController()->setSelectedRange(core(mark), DOWNSTREAM, true))
         [bridge setMarkDOMRange:selection];
 }
 
index c35139650ce44391ad19b2cb07bda1f48bb3edc1..513e2d7d43bf9b2424108316faef1de2368ad951 100644 (file)
@@ -3233,8 +3233,7 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
         if (!coreFrame)
             return;
 
-        ExceptionCode ec = 0;
-        coreFrame->selectionController()->setSelectedRange([range _range], core(selectionAffinity), true, ec);
+        coreFrame->selectionController()->setSelectedRange([range _range], core(selectionAffinity), true);
     }
 }