LayoutTests:
authorjusting <justing@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Jul 2006 22:55:10 +0000 (22:55 +0000)
committerjusting <justing@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Jul 2006 22:55:10 +0000 (22:55 +0000)
        Reviewed by levi

        <rdar://problem/4631972>
        REGRESSION: Mail crashes when pasting entire contents of http://www.apple.com/support/ into a new mail message

        * editing/pasteboard/4631972-expected.checksum: Added.
        * editing/pasteboard/4631972-expected.png: Added.
        * editing/pasteboard/4631972-expected.txt: Added.
        * editing/pasteboard/4631972.html: Added.
        * editing/selection/drag-to-contenteditable-iframe-expected.txt:
        * editing/selection/replaced-boundaries-3-expected.checksum:
        * editing/selection/replaced-boundaries-3-expected.txt:
        * editing/selection/select-box-expected.txt:

WebCore:

        Reviewed by levi

        <rdar://problem/4631972>
        REGRESSION: Mail crashes when pasting entire contents of http://www.apple.com/support/ into a new mail message

        * dom/Position.cpp:
        (WebCore::Position::upstream): Deployed isBlock and enclosingBlock.
        (WebCore::Position::downstream): Ditto.
        * editing/CompositeEditCommand.cpp:
        (WebCore::CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary): Ditto.
        * editing/htmlediting.cpp:
        (WebCore::canHaveChildrenForEditing): Added !iframe.
        (WebCore::isBlock): Added, returns !node->renderer()->isInline()
        (WebCore::enclosingBlock): Added.
        * editing/htmlediting.h:

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/editing/pasteboard/4631972-expected.checksum [new file with mode: 0644]
LayoutTests/editing/pasteboard/4631972-expected.png [new file with mode: 0644]
LayoutTests/editing/pasteboard/4631972-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/4631972.html [new file with mode: 0644]
LayoutTests/editing/selection/drag-to-contenteditable-iframe-expected.txt
LayoutTests/editing/selection/replaced-boundaries-3-expected.checksum
LayoutTests/editing/selection/replaced-boundaries-3-expected.txt
LayoutTests/editing/selection/select-box-expected.txt
WebCore/ChangeLog
WebCore/dom/Position.cpp
WebCore/editing/CompositeEditCommand.cpp
WebCore/editing/htmlediting.cpp
WebCore/editing/htmlediting.h

index 87decc0..5f0a4d1 100644 (file)
@@ -1,3 +1,19 @@
+2006-07-19  Justin Garcia  <justin.garcia@apple.com>
+
+        Reviewed by levi
+        
+        <rdar://problem/4631972>
+        REGRESSION: Mail crashes when pasting entire contents of http://www.apple.com/support/ into a new mail message
+
+        * editing/pasteboard/4631972-expected.checksum: Added.
+        * editing/pasteboard/4631972-expected.png: Added.
+        * editing/pasteboard/4631972-expected.txt: Added.
+        * editing/pasteboard/4631972.html: Added.
+        * editing/selection/drag-to-contenteditable-iframe-expected.txt:
+        * editing/selection/replaced-boundaries-3-expected.checksum:
+        * editing/selection/replaced-boundaries-3-expected.txt:
+        * editing/selection/select-box-expected.txt:
+
 2006-07-19  Anders Carlsson  <acarlsson@apple.com>
 
         Reviewed by Adele.
diff --git a/LayoutTests/editing/pasteboard/4631972-expected.checksum b/LayoutTests/editing/pasteboard/4631972-expected.checksum
new file mode 100644 (file)
index 0000000..b1d252c
--- /dev/null
@@ -0,0 +1 @@
+eff80d03dc8d814c863e7f8d92b2c928
\ No newline at end of file
diff --git a/LayoutTests/editing/pasteboard/4631972-expected.png b/LayoutTests/editing/pasteboard/4631972-expected.png
new file mode 100644 (file)
index 0000000..b0b1160
Binary files /dev/null and b/LayoutTests/editing/pasteboard/4631972-expected.png differ
diff --git a/LayoutTests/editing/pasteboard/4631972-expected.txt b/LayoutTests/editing/pasteboard/4631972-expected.txt
new file mode 100644 (file)
index 0000000..1ed5f3c
--- /dev/null
@@ -0,0 +1,30 @@
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document toDOMRange:range from 1 of DIV > DIV > BODY > HTML > #document to 1 of DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {P} at (0,0) size 784x36
+        RenderText {#text} at (0,0) size 640x36
+          text run at (0,0) width 423: "This tests pasting a fragment containing an <iframe> after a <div>. "
+          text run at (423,0) width 215: "This used to fail on an assertion in"
+          text run at (0,18) width 325: "moveParagraphContentsToNewBlockIfNecessary. "
+          text run at (325,18) width 315: "You should see 'foo' and then an <iframe> below."
+      RenderBlock {DIV} at (0,52) size 784x70
+        RenderBlock (anonymous) at (0,0) size 784x18
+          RenderText {#text} at (0,0) size 21x18
+            text run at (0,0) width 21: "foo"
+        RenderBlock {DIV} at (0,18) size 784x52
+          RenderPartObject {IFRAME} at (0,0) size 102x52 [border: (1px solid #000000)]
+            layer at (0,0) size 100x50
+              RenderView at (0,0) size 100x50
+            layer at (0,0) size 100x8
+              RenderBlock {HTML} at (0,0) size 100x8
+                RenderBody {BODY} at (8,8) size 84x0
+          RenderBR {BR} at (102,52) size 0x0
+caret: position 1 of child 0 {IFRAME} of child 1 {DIV} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/editing/pasteboard/4631972.html b/LayoutTests/editing/pasteboard/4631972.html
new file mode 100644 (file)
index 0000000..1d754ea
--- /dev/null
@@ -0,0 +1,10 @@
+<p>This tests pasting a fragment containing an &lt;iframe&gt; after a &lt;div&gt;.  This used to fail on an assertion in moveParagraphContentsToNewBlockIfNecessary.  You should see 'foo' and then an &lt;iframe&gt; below.</p> 
+<div contenteditable="true" id="test"></div>
+
+<script>
+var s = window.getSelection();
+var e = document.getElementById("test");
+
+s.setPosition(e, 0);
+document.execCommand("InsertHTML", false, "<div>foo</div><iframe style='border:1px solid black; width:100; height:50;'></iframe>");
+</script>
\ No newline at end of file
index 976fdcd..cc0099f 100644 (file)
@@ -1,9 +1,8 @@
 EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 2 of BODY > HTML > #document to 2 of BODY > HTML > #document givenAction:WebViewInsertActionDropped
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of IFRAME > BODY > HTML > #document to 1 of IFRAME > BODY > HTML > #document toDOMRange:range from 1 of IFRAME > BODY > HTML > #document to 1 of IFRAME > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of BODY > HTML > #document to 2 of BODY > HTML > #document toDOMRange:range from 0 of #text > BODY > HTML > #document to 5 of #text > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of BODY > HTML > #document to 5 of BODY > HTML > #document
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of BODY > HTML > #document to 6 of BODY > HTML > #document
 EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of IFRAME > BODY > HTML > #document to 1 of IFRAME > BODY > HTML > #document toDOMRange:range from 1 of IFRAME > BODY > HTML > #document to 1 of IFRAME > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 0 of BODY > HTML > #document to 0 of BODY > HTML > #document givenAction:WebViewInsertActionDropped
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
index a018eea..078d2c8 100644 (file)
@@ -24,4 +24,4 @@ layer at (0,0) size 800x600
               text run at (0,0) width 195: "this select box shouldn't be selected"
         RenderText {#text} at (0,0) size 0x0
 selection start: position 1 of child 0 {#text} of child 3 {DIV} of child 1 {BODY} of child 0 {HTML} of document
-selection end:   position 0 of child 3 {SELECT} of child 3 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+selection end:   position 1 of child 1 {BR} of child 3 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index 26273b7..0ad8b58 100644 (file)
@@ -51,10 +51,6 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 layer at (0,0) size 800x600
   RenderView at (0,0) size 800x600
 layer at (0,0) size 800x600
index 141fa28..ddc2247 100644 (file)
@@ -1,3 +1,21 @@
+2006-07-19  Justin Garcia  <justin.garcia@apple.com>
+
+        Reviewed by levi
+        
+        <rdar://problem/4631972>
+        REGRESSION: Mail crashes when pasting entire contents of http://www.apple.com/support/ into a new mail message
+
+        * dom/Position.cpp:
+        (WebCore::Position::upstream): Deployed isBlock and enclosingBlock.
+        (WebCore::Position::downstream): Ditto.
+        * editing/CompositeEditCommand.cpp:
+        (WebCore::CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary): Ditto.
+        * editing/htmlediting.cpp:
+        (WebCore::canHaveChildrenForEditing): Added !iframe.
+        (WebCore::isBlock): Added, returns !node->renderer()->isInline()
+        (WebCore::enclosingBlock): Added.
+        * editing/htmlediting.h:
+
 2006-07-19  Anders Carlsson  <acarlsson@apple.com>
 
         Reviewed by Adele.
index db83a9a..8fd549e 100644 (file)
@@ -284,7 +284,7 @@ Position Position::upstream() const
         return Position();
     
     // iterate backward from there, looking for a qualified position
-    Node *block = startNode->enclosingBlockFlowOrTableElement();
+    Node *block = enclosingBlock(startNode);
     Position lastVisible = *this;
     Position currentPos = start;
     Node* originalRoot = node()->rootEditableElement();
@@ -297,7 +297,7 @@ Position Position::upstream() const
 
         // Don't enter a new enclosing block flow or table element.  There is code below that
         // terminates early if we're about to leave an enclosing block flow or table element.
-        if (block != currentNode->enclosingBlockFlowOrTableElement())
+        if (block != enclosingBlock(currentNode))
             return lastVisible;
 
         // skip position in unrendered or invisible node
@@ -313,7 +313,7 @@ Position Position::upstream() const
         // return lastVisible on the next iteration, but we terminate early to avoid calling previous()
         // beceause previous() for an offset 0 position calls nodeIndex(), which is O(n).
         // FIXME: Avoid calling previous on other offset 0 positions.
-        if (currentNode == currentNode->enclosingBlockFlowOrTableElement() && currentOffset == 0)
+        if (currentNode == enclosingBlock(currentNode) && currentOffset == 0)
             return lastVisible;
             
         // return position after replaced or BR elements
@@ -362,7 +362,7 @@ Position Position::downstream() const
         return Position();
 
     // iterate forward from there, looking for a qualified position
-    Node *block = startNode->enclosingBlockFlowOrTableElement();
+    Node *block = enclosingBlock(startNode);
     Position lastVisible = *this;
     Position currentPos = start;
     Node* originalRoot = node()->rootEditableElement();
@@ -379,7 +379,7 @@ Position Position::downstream() const
             break;
             
         // Do not enter a new enclosing block flow or table element, and don't leave the original one.
-        if (block != currentNode->enclosingBlockFlowOrTableElement())
+        if (block != enclosingBlock(currentNode))
             return lastVisible;
 
         // skip position in unrendered or invisible node
index 124262e..65f16f9 100644 (file)
@@ -553,24 +553,24 @@ void CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary(const Posi
     Position paragraphStart = visibleParagraphStart.deepEquivalent().upstream();
     Position end = visibleEnd.deepEquivalent().upstream();
 
-    // Perform some sanity checks. If there are no VisiblePositions in
-    // the same block as pos then paragraphStart will be outside the paragraph
+    // If there are no VisiblePositions in the same block as pos then 
+    // paragraphStart will be outside the paragraph
     if (Range::compareBoundaryPoints(pos, paragraphStart) < 0)
         return;
 
     // Perform some checks to see if we need to perform work in this function.
-    if (paragraphStart.node()->isBlockFlow()) {
-        if (end.node()->isBlockFlow()) {
+    if (isBlock(paragraphStart.node())) {
+        if (isBlock(end.node())) {
             if (!end.node()->isAncestor(paragraphStart.node())) {
                 // If the paragraph end is a descendant of paragraph start, then we need to run
                 // the rest of this function. If not, we can bail here.
                 return;
             }
         }
-        else if (end.node()->enclosingBlockFlowElement() != paragraphStart.node()) {
-            // The paragraph end is in another block that is an ancestor of the paragraph start.
+        else if (enclosingBlock(end.node()) != paragraphStart.node()) {
+            // The visibleEnd.  It must be an ancestor of the paragraph start.
             // We can bail as we have a full block to work with.
-            ASSERT(paragraphStart.node()->isAncestor(end.node()->enclosingBlockFlowElement()));
+            ASSERT(paragraphStart.node()->isAncestor(enclosingBlock(end.node())));
             return;
         }
         else if (isEndOfDocument(visibleEnd)) {
@@ -588,7 +588,7 @@ void CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary(const Posi
     
     insertNodeAt(newBlock.get(), paragraphStart.node(), paragraphStart.offset());
 
-    while (moveNode && !moveNode->isBlockFlow()) {
+    while (moveNode && !isBlock(moveNode)) {
         Node *next = moveNode->traverseNextSibling();
         removeNode(moveNode);
         appendNode(moveNode, newBlock.get());
index de6cf3c..b282672 100644 (file)
@@ -78,6 +78,7 @@ bool canHaveChildrenForEditing(const Node* node)
            !node->hasTagName(imgTag) &&
            !node->hasTagName(buttonTag) &&
            !node->hasTagName(objectTag) &&
+           !node->hasTagName(iframeTag) &&
            !node->isTextNode();
 }
 
@@ -258,6 +259,28 @@ VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& positio
     return VisiblePosition(p);
 }
 
+// Whether or not content before and after this node will collapse onto the same line as it.
+bool isBlock(Node* node)
+{
+    return node && node->renderer() && !node->renderer()->isInline();
+}
+
+// FIXME: Deploy this in all of the places where enclosingBlockFlow/enclosingBlockFlowOrTableElement are used.
+Node* enclosingBlock(Node* node)
+{
+    if (isBlock(node))
+        return node;
+        
+    while (1) {
+        node = node->parentNode();
+        if (!node)
+            break;
+        if (isBlock(node))
+            return node;
+    }
+    return 0;
+}
+
 Position rangeCompliantEquivalent(const Position& pos)
 {
     if (pos.isNull())
index 5764c6d..cb9eef4 100644 (file)
@@ -58,6 +58,8 @@ Position previousVisuallyDistinctCandidate(const Position&);
 bool isEditablePosition(const Position&);
 bool isRichlyEditablePosition(const Position&);
 Element* editableRootForPosition(const Position&);
+bool isBlock(Node*);
+Node* enclosingBlock(Node*);
 
 void rebalanceWhitespaceInTextNode(Node*, unsigned start, unsigned length);
 const String& nonBreakingSpaceString();