LayoutTests:
authorantti <antti@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 May 2007 22:25:01 +0000 (22:25 +0000)
committerantti <antti@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 May 2007 22:25:01 +0000 (22:25 +0000)
        Reviewed by Darin.

        Test for http://bugs.webkit.org/show_bug.cgi?id=13727
        REGRESSION: Reproducible hang setting the selection's extent offset to -1
        <rdar://problem/5206890>

        * LayoutTests/editing/selection/selection-invalid-offset-expected.txt: Added.
        * LayoutTests/editing/selection/selection-invalid-offset.html: Added.

WebCore:

        Reviewed by Darin.

        Fix for http://bugs.webkit.org/show_bug.cgi?id=13727
        REGRESSION: Reproducible hang setting the selection's extent offset to -1
        <rdar://problem/5206890>

        Rise INDEX_SIZE_ERR if used selection index is negative. This matches HTML5 for
        getRangeAt() and collapse() which are part of the spec (FF throws NS_ERROR_FAILURE).

        Not throwing exceptions yet for too high offsets (except getRangeAt()) as it is
        unclear if WebCore's definition of offsets is the same as other browsers.

        * bindings/js/kjs_window.cpp:
        * WebCore/editing/SelectionController.cpp:
        * WebCore/editing/SelectionController.h:
        * WebCore/editing/VisiblePosition.cpp:

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

LayoutTests/ChangeLog
LayoutTests/editing/selection/selection-invalid-offset-expected.txt [new file with mode: 0644]
LayoutTests/editing/selection/selection-invalid-offset.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/bindings/js/kjs_window.cpp
WebCore/editing/SelectionController.cpp
WebCore/editing/SelectionController.h
WebCore/editing/VisiblePosition.cpp

index 6b8704265a9445a5c0a27733ee54e63266c2be59..cfd70b119395220f76ee002f026bfad97a53a2e8 100644 (file)
@@ -1,3 +1,14 @@
+2007-05-17  Antti Koivisto  <antti@apple.com>
+
+        Reviewed by Darin.
+        
+        Test for http://bugs.webkit.org/show_bug.cgi?id=13727
+        REGRESSION: Reproducible hang setting the selection's extent offset to -1
+        <rdar://problem/5206890>
+
+        * LayoutTests/editing/selection/selection-invalid-offset-expected.txt: Added.
+        * LayoutTests/editing/selection/selection-invalid-offset.html: Added.
+
 2007-05-17  Adele Peterson  <adele@apple.com>
 
         Reviewed by Mitz.
diff --git a/LayoutTests/editing/selection/selection-invalid-offset-expected.txt b/LayoutTests/editing/selection/selection-invalid-offset-expected.txt
new file mode 100644 (file)
index 0000000..7719c27
--- /dev/null
@@ -0,0 +1,8 @@
+You should see six OKs below (and not hang): 
+OK
+OK
+OK
+OK
+OK
+OK
+
diff --git a/LayoutTests/editing/selection/selection-invalid-offset.html b/LayoutTests/editing/selection/selection-invalid-offset.html
new file mode 100644 (file)
index 0000000..30d9867
--- /dev/null
@@ -0,0 +1,37 @@
+<body>
+You should see six OKs below (and not hang): <br>
+<script>
+if (window.layoutTestController)
+    layoutTestController.dumpAsText();
+var body = document.body;
+var selection = window.getSelection();
+try {
+selection.collapse(body, -1);
+} catch (e) {document.write(((e.code==DOMException.INDEX_SIZE_ERR) ? "OK" : "FAIL")+"<br>"); }
+
+try {
+selection.setBaseAndExtent(body, -1, body, 0);
+} catch (e) {document.write(((e.code==DOMException.INDEX_SIZE_ERR) ? "OK" : "FAIL")+"<br>"); }
+
+try {
+selection.setBaseAndExtent(body, 0, body, -1);
+} catch (e) {document.write(((e.code==DOMException.INDEX_SIZE_ERR) ? "OK" : "FAIL")+"<br>"); }
+
+try {
+selection.setPosition(body, -1);
+} catch (e) {document.write(((e.code==DOMException.INDEX_SIZE_ERR) ? "OK" : "FAIL")+"<br>"); }
+
+try {
+selection.getRangeAt(-1);
+} catch (e) {document.write(((e.code==DOMException.INDEX_SIZE_ERR) ? "OK" : "FAIL")+"<br>"); }
+
+try {
+selection.getRangeAt(10000);
+} catch (e) {document.write(((e.code==DOMException.INDEX_SIZE_ERR) ? "OK" : "FAIL")+"<br>"); }
+
+// these should throw as well but don't at the moment. Just checking they don't crash. 
+selection.collapse(body, 10000);
+selection.setBaseAndExtent(body, 1000, body, 0);
+selection.setBaseAndExtent(body, 0, body, 10000);
+selection.setPosition(body, 10000);
+</script>
index 76e9bd1d6a4213178ed6fdd3214fdbc98dbdade6..bb30e9781c5e8208eb77db78354e03b93fa69137 100644 (file)
@@ -1,3 +1,22 @@
+2007-05-17  Antti Koivisto  <antti@apple.com>
+
+        Reviewed by Darin.
+
+        Fix for http://bugs.webkit.org/show_bug.cgi?id=13727
+        REGRESSION: Reproducible hang setting the selection's extent offset to -1
+        <rdar://problem/5206890>
+        
+        Rise INDEX_SIZE_ERR if used selection index is negative. This matches HTML5 for
+        getRangeAt() and collapse() which are part of the spec (FF throws NS_ERROR_FAILURE). 
+        
+        Not throwing exceptions yet for too high offsets (except getRangeAt()) as it is
+        unclear if WebCore's definition of offsets is the same as other browsers.
+
+        * bindings/js/kjs_window.cpp:
+        * WebCore/editing/SelectionController.cpp:
+        * WebCore/editing/SelectionController.h:
+        * WebCore/editing/VisiblePosition.cpp:
+        
 2007-05-17  Adele Peterson  <adele@apple.com>
 
         Reviewed by Mitz.
index 834be1bf10521555cc7879cce8c6f5d27c1f1857..85aa45493ac7220571e72a70c21698ca70ebee9e 100644 (file)
@@ -2483,10 +2483,10 @@ JSValue *SelectionFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const
     Frame *frame = selection->frame();
     if (frame) {
         SelectionController* s = frame->selectionController();
-        
+        ExceptionCode ec = 0;
         switch (id) {
             case Selection::Collapse:
-                s->collapse(toNode(args[0]), args[1]->toInt32(exec));
+                s->collapse(toNode(args[0]), args[1]->toInt32(exec), ec);
                 break;
             case Selection::CollapseToEnd:
                 s->collapseToEnd();
@@ -2498,16 +2498,18 @@ JSValue *SelectionFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const
                 s->empty();
                 break;
             case Selection::SetBaseAndExtent:
-                s->setBaseAndExtent(toNode(args[0]), args[1]->toInt32(exec), toNode(args[2]), args[3]->toInt32(exec));
+                s->setBaseAndExtent(toNode(args[0]), args[1]->toInt32(exec), toNode(args[2]), args[3]->toInt32(exec), ec);
                 break;
             case Selection::SetPosition:
-                s->setPosition(toNode(args[0]), args[1]->toInt32(exec));
+                s->setPosition(toNode(args[0]), args[1]->toInt32(exec), ec);
                 break;
             case Selection::Modify:
                 s->modify(args[0]->toString(exec), args[1]->toString(exec), args[2]->toString(exec));
                 break;
             case Selection::GetRangeAt:
-                return toJS(exec, s->getRangeAt(args[0]->toInt32(exec)).get());
+                JSValue* val = toJS(exec, s->getRangeAt(args[0]->toInt32(exec), ec).get());
+                setDOMException(exec, ec);
+                return val;
             case Selection::RemoveAllRanges:
                 s->removeAllRanges();
                 break;
@@ -2517,6 +2519,7 @@ JSValue *SelectionFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const
             case Selection::ToString:
                 return jsString(s->toString());
         }
+        setDOMException(exec, ec);
     }
 
     return jsUndefined();
index 3ce3424baf9edd39b68dff60b60e7e42bc69bfc5..0acc4e345b44a920a11a3274757ca840871f2aec 100644 (file)
@@ -31,6 +31,7 @@
 #include "Editor.h"
 #include "Element.h"
 #include "EventNames.h"
+#include "ExceptionCode.h"
 #include "FocusController.h"
 #include "Frame.h"
 #include "FrameTree.h"
@@ -719,9 +720,13 @@ String SelectionController::toString() const
     return String(plainText(m_sel.toRange().get()));
 }
 
-PassRefPtr<Range> SelectionController::getRangeAt(int index) const
+PassRefPtr<Range> SelectionController::getRangeAt(int index, ExceptionCode& ec) const
 {
-    return index == 0 ? m_sel.toRange() : 0;
+    if (index < 0 || index >= rangeCount()) {
+        ec = INDEX_SIZE_ERR;
+        return 0;
+    }   
+    return m_sel.toRange();
 }
 
 void SelectionController::removeAllRanges()
@@ -762,21 +767,33 @@ void SelectionController::addRange(const Range* r)
     }
 }
 
-void SelectionController::setBaseAndExtent(Node *baseNode, int baseOffset, Node *extentNode, int extentOffset)
+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)
+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)
+void SelectionController::collapse(Node *node, int offset, ExceptionCode& ec)
 {
+    if (offset < 0) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
     moveTo(VisiblePosition(node, offset, DOWNSTREAM));
 }
 
@@ -795,8 +812,12 @@ void SelectionController::empty()
     moveTo(VisiblePosition());
 }
 
-void SelectionController::extend(Node *node, int offset)
+void SelectionController::extend(Node *node, int offset, ExceptionCode& ec)
 {
+    if (offset < 0) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
     moveTo(VisiblePosition(node, offset, DOWNSTREAM));
 }
 
index 8357d99dc9a58b7535f4279cfaa24b416387ddfe..05b9deac2f5a777de3a899f194a3c43e924a5c6c 100644 (file)
@@ -109,8 +109,8 @@ public:
     int baseOffset() const { return m_sel.base().offset(); }
     int extentOffset() const { return m_sel.extent().offset(); }
     String type() const;
-    void setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset);
-    void setPosition(Node*, int offset);
+    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
@@ -124,11 +124,11 @@ public:
     int focusOffset() const { return m_sel.isBaseFirst() ? m_sel.end().offset() : m_sel.start().offset(); }
     bool isCollapsed() const { return !isRange(); }
     String toString() const;
-    void collapse(Node*, int offset);
+    void collapse(Node*, int offset, ExceptionCode&);
     void collapseToEnd();
     void collapseToStart();
-    void extend(Node*, int offset);
-    PassRefPtr<Range> getRangeAt(int index) const;
+    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*);
index 82fb7d79806be38d07b9b8243ccfdd4ad3304c47..66a236a5c1c547aea6de266a773cb97c0915f770 100644 (file)
@@ -47,6 +47,7 @@ VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
 
 VisiblePosition::VisiblePosition(Node *node, int offset, EAffinity affinity)
 {
+    ASSERT(offset >= 0);
     init(Position(node, offset), affinity);
 }