LayoutTests:
authorjusting <justing@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 May 2007 21:37:04 +0000 (21:37 +0000)
committerjusting <justing@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 May 2007 21:37:04 +0000 (21:37 +0000)
        Reviewed by darin

        <rdar://problem/5136696> Selection is removed when focusing a node in another frame

        Demonstrates bug:
        * editing/selection/5136696-expected.checksum: Added.
        * editing/selection/5136696-expected.png: Added.
        * editing/selection/5136696-expected.txt: Added.
        * editing/selection/5136696.html: Added.

WebCore:

        Reviewed by darin

        <rdar://problem/5136696> Selection is removed when focusing a node in another frame
        <rdar://problem/5192388> WordPress: Can't insert links/images

        Don't clear a selection when changing focus if the new
        focus node is in a different frame than the old selection.

        * dom/Document.cpp:
        (WebCore::Document::setFocusedNode): Moved code to clear
        selections to the FocusController, since it is Page level
        and will know about the frame/document that contained the
        old selection. Moved code to call shouldEndEditing to the
        FocusController because selections are now cleared before
        calling Document::setFocusedNode and shouldEndEditing must
        be called before selections are cleared.
        * dom/Element.cpp:
        (WebCore::Element::blur): Call FocusController::setFocusNode
        instead of Document::setFocusNode, if possible.
        * page/EventHandler.cpp:
        (WebCore::EventHandler::dispatchMouseEvent): Ditto.
        * page/FocusController.cpp:
        (WebCore::relinquishesEditingFocus): Moved from Document.cpp.
        (WebCore::clearSelectionIfNeeded): Ditto.  Don't clear if
        the old selection is in a frame that's different than the
        one that contains the new focus node.
        (WebCore::FocusController::setFocusedNode): Moved code
        here from Document::setFocusedNode.
        * page/Frame.cpp:
        (WebCore::Frame::setFocusedNodeIfNeeded): Call
        FocusController::setFocusNode.

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

LayoutTests/ChangeLog
LayoutTests/editing/selection/5136696-expected.checksum [new file with mode: 0644]
LayoutTests/editing/selection/5136696-expected.png [new file with mode: 0644]
LayoutTests/editing/selection/5136696-expected.txt [new file with mode: 0644]
LayoutTests/editing/selection/5136696.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/dom/Document.cpp
WebCore/dom/Element.cpp
WebCore/page/EventHandler.cpp
WebCore/page/FocusController.cpp
WebCore/page/Frame.cpp

index 6469d1f376fc373d176452ed2fc809d9436f7dd6..445d4e05bd4e18562a144ed8c9a60a9c12f968e3 100644 (file)
@@ -1,3 +1,15 @@
+2007-05-14  Justin Garcia  <justin.garcia@apple.com>
+
+        Reviewed by darin
+        
+        <rdar://problem/5136696> Selection is removed when focusing a node in another frame
+
+        Demonstrates bug:
+        * editing/selection/5136696-expected.checksum: Added.
+        * editing/selection/5136696-expected.png: Added.
+        * editing/selection/5136696-expected.txt: Added.
+        * editing/selection/5136696.html: Added.
+
 2007-05-14  Kimmo Kinnunen  <kimmok@iki.fi>
 
         Tests for http://bugs.webkit.org/show_bug.cgi?id=10878
diff --git a/LayoutTests/editing/selection/5136696-expected.checksum b/LayoutTests/editing/selection/5136696-expected.checksum
new file mode 100644 (file)
index 0000000..222c02d
--- /dev/null
@@ -0,0 +1 @@
+2ee0d0aa57cf21885a4971be6ec16706
\ No newline at end of file
diff --git a/LayoutTests/editing/selection/5136696-expected.png b/LayoutTests/editing/selection/5136696-expected.png
new file mode 100644 (file)
index 0000000..c6d94e5
Binary files /dev/null and b/LayoutTests/editing/selection/5136696-expected.png differ
diff --git a/LayoutTests/editing/selection/5136696-expected.txt b/LayoutTests/editing/selection/5136696-expected.txt
new file mode 100644 (file)
index 0000000..6fb37cb
--- /dev/null
@@ -0,0 +1,28 @@
+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 784x18
+        RenderText {#text} at (0,0) size 666x18
+          text run at (0,0) width 666: "This tests to make sure that a selection in one from isn't cleared when focusing a node in a different frame."
+      RenderBlock (anonymous) at (0,34) size 784x177
+        RenderPartObject {IFRAME} at (0,0) size 304x154 [border: (2px inset #000000)]
+          layer at (0,0) size 300x150
+            RenderView at (0,0) size 300x150
+          layer at (0,0) size 300x150
+            RenderBlock {HTML} at (0,0) size 300x150
+              RenderBody {BODY} at (8,8) size 284x134 [bgcolor=#FFFFE0]
+                RenderText {#text} at (0,0) size 270x36
+                  text run at (0,0) width 270: "This test should be selected, but this frame "
+                  text run at (0,18) width 133: "shouldn't be focused."
+        RenderBR {BR} at (304,154) size 0x0
+        RenderTextControl {INPUT} at (2,156) size 217x19 [bgcolor=#FFFFFF] [border: (2px inset #000000)]
+        RenderText {#text} at (0,0) size 0x0
+        RenderText {#text} at (0,0) size 0x0
+layer at (13,201) size 211x13
+  RenderBlock {DIV} at (3,3) size 211x13
+    RenderText {#text} at (1,0) size 181x13
+      text run at (1,0) width 181: "This text field should be focused."
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of child 5 {INPUT} of child 0 {BODY} of child 0 {HTML} of document
+selection end:   position 34 of child 0 {#text} of child 0 {DIV} of child 5 {INPUT} of child 0 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/editing/selection/5136696.html b/LayoutTests/editing/selection/5136696.html
new file mode 100644 (file)
index 0000000..86c493b
--- /dev/null
@@ -0,0 +1,20 @@
+<p>This tests to make sure that a selection in one from isn't cleared when focusing a node in a different frame.</p>
+<iframe border="1" src="../resources/contenteditable-iframe-src.html"></iframe><br>
+<input type="text" id="input" value="This text field should be focused." size="30">
+
+<script>
+function runTest() {
+    frame = frames[0];
+    frame.focus();
+    s = frame.getSelection();
+    s.setPosition(frame.document.body, 0);
+    frame.document.execCommand("InsertText", false, "This test should be selected, but this frame shouldn't be focused.");
+    frame.document.execCommand("SelectAll");
+    document.getElementById("input").focus();
+    if (window.layoutTestController)
+        window.layoutTestController.notifyDone();
+}
+if (window.layoutTestController)
+    window.layoutTestController.waitUntilDone();
+window.setTimeout(runTest, 200);
+</script>
index 39edaf362a7b3f9397ba2e57ad01f44a94aaea48..b42535c259ff1bbf42c1205bc55ab9f95c01958d 100644 (file)
@@ -1,3 +1,37 @@
+2007-05-14  Justin Garcia  <justin.garcia@apple.com>
+
+        Reviewed by darin
+        
+        <rdar://problem/5136696> Selection is removed when focusing a node in another frame
+        <rdar://problem/5192388> WordPress: Can't insert links/images
+        
+        Don't clear a selection when changing focus if the new
+        focus node is in a different frame than the old selection.
+
+        * dom/Document.cpp:
+        (WebCore::Document::setFocusedNode): Moved code to clear 
+        selections to the FocusController, since it is Page level 
+        and will know about the frame/document that contained the 
+        old selection. Moved code to call shouldEndEditing to the 
+        FocusController because selections are now cleared before
+        calling Document::setFocusedNode and shouldEndEditing must
+        be called before selections are cleared.
+        * dom/Element.cpp:
+        (WebCore::Element::blur): Call FocusController::setFocusNode
+        instead of Document::setFocusNode, if possible.
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::dispatchMouseEvent): Ditto.
+        * page/FocusController.cpp:
+        (WebCore::relinquishesEditingFocus): Moved from Document.cpp.
+        (WebCore::clearSelectionIfNeeded): Ditto.  Don't clear if
+        the old selection is in a frame that's different than the 
+        one that contains the new focus node.
+        (WebCore::FocusController::setFocusedNode): Moved code
+        here from Document::setFocusedNode.
+        * page/Frame.cpp:
+        (WebCore::Frame::setFocusedNodeIfNeeded): Call
+        FocusController::setFocusNode.
+
 2007-05-14  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by Darin Adler.
index e4b27aef47eb79ce25a2b4ce612288f300fc7f80..d292bffdcf4c234e93e38362f69f004e163b0953 100644 (file)
@@ -228,19 +228,6 @@ static Widget* widgetForNode(Node* focusedNode)
     return static_cast<RenderWidget*>(renderer)->widget();
 }
 
-static bool relinquishesEditingFocus(Node *node)
-{
-    ASSERT(node);
-    ASSERT(node->isContentEditable());
-
-    Node *root = node->rootEditableElement();
-    Frame* frame = node->document()->frame();
-    if (!frame || !root)
-        return false;
-
-    return frame->editor()->shouldEndEditing(rangeOfContents(root).get());
-}
-
 static bool acceptsEditingFocus(Node *node)
 {
     ASSERT(node);
@@ -254,18 +241,6 @@ static bool acceptsEditingFocus(Node *node)
     return frame->editor()->shouldBeginEditing(rangeOfContents(root).get());
 }
 
-static void clearSelectionIfNeeded(Frame* frame, Node* newFocusedNode)
-{
-    if (!frame)
-        return;
-
-    // Clear the selection when changing the focus node to null or to a node that is not 
-    // contained by the current selection.
-    Node* startContainer = frame->selectionController()->start().node();
-    if (!newFocusedNode || (startContainer && startContainer != newFocusedNode && !(startContainer->isDescendantOf(newFocusedNode)) && startContainer->shadowAncestorNode() != newFocusedNode))
-        frame->selectionController()->clear();
-}
-
 DeprecatedPtrList<Document>*  Document::changedDocuments = 0;
 
 // FrameView might be 0
@@ -2151,14 +2126,10 @@ bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode)
 
     if (m_focusedNode == newFocusedNode)
         return true;
-
-    if (m_focusedNode && m_focusedNode.get() == m_focusedNode->rootEditableElement() && !relinquishesEditingFocus(m_focusedNode.get()))
-          return false;
         
     bool focusChangeBlocked = false;
     RefPtr<Node> oldFocusedNode = m_focusedNode;
     m_focusedNode = 0;
-    clearSelectionIfNeeded(frame(), newFocusedNode.get());
 
     // Remove focus from the existing focus node (if any)
     if (oldFocusedNode && !oldFocusedNode->m_inDetach) { 
@@ -2183,14 +2154,12 @@ bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode)
             focusChangeBlocked = true;
             newFocusedNode = 0;
         }
-        clearSelectionIfNeeded(frame(), newFocusedNode.get());
         EventTargetNodeCast(oldFocusedNode.get())->dispatchUIEvent(DOMFocusOutEvent);
         if (m_focusedNode) {
             // handler shifted focus
             focusChangeBlocked = true;
             newFocusedNode = 0;
         }
-        clearSelectionIfNeeded(frame(), newFocusedNode.get());
         if ((oldFocusedNode.get() == this) && oldFocusedNode->hasOneRef())
             return true;
             
index 68d36c11a51bd65950a3b03e90ff5443b3f16007..685fdcb5bf44ab2dc76dd4c1915726b390d0a795 100644 (file)
@@ -1012,8 +1012,12 @@ void Element::blur()
 {
     stopUpdateFocusAppearanceTimer();
     Document* doc = document();
-    if (doc->focusedNode() == this)
-        doc->setFocusedNode(0);
+    if (doc->focusedNode() == this) {
+        if (doc->frame())
+            doc->frame()->page()->focusController()->setFocusedNode(0);
+        else
+            doc->setFocusedNode(0);
+    }
 }
 
 void Element::stopUpdateFocusAppearanceTimer()
index 83b53d0a77f7923c234ec76bd95696e8b5747386..3b4e3634fb8536d86ccb32a22c4111d042258e26 100644 (file)
@@ -1187,7 +1187,7 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe
         // If focus shift is blocked, we eat the event.  Note we should never clear swallowEvent
         // if the page already set it (e.g., by canceling default behavior).
         if (node && node->isMouseFocusable()) {
-            if (!m_frame->document()->setFocusedNode(node))
+            if (!m_frame->page()->focusController()->setFocusedNode(node))
                 swallowEvent = true;
         } else if (!node || !node->focused()) {
             if (!m_frame->document()->setFocusedNode(0))
index 4924ae35dbe7f061d329f4286d5b12b7700f2624..894fc76d412e134ee51eb49680a751c19aa76ac7 100644 (file)
@@ -207,11 +207,52 @@ bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* even
     return true;
 }
 
+static bool relinquishesEditingFocus(Node *node)
+{
+    ASSERT(node);
+    ASSERT(node->isContentEditable());
+
+    Node* root = node->rootEditableElement();
+    Frame* frame = node->document()->frame();
+    if (!frame || !root)
+        return false;
+
+    return frame->editor()->shouldEndEditing(rangeOfContents(root).get());
+}
+
+static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Node* newFocusedNode)
+{
+    if (!oldFocusedFrame)
+        return;
+        
+    if (newFocusedNode && oldFocusedFrame->document() != newFocusedNode->document())
+        return;
+    
+    SelectionController* s = oldFocusedFrame->selectionController();
+    if (s->isNone())
+        return;
+    
+    Node* selectionStartNode = s->selection().start().node();
+    if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->shadowAncestorNode() == newFocusedNode)
+        return;
+    
+    s->clear();
+}
+
 bool FocusController::setFocusedNode(Node* node)
 {
     RefPtr<Frame> oldFocusedFrame = focusedFrame();
     RefPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : 0;
     
+    Node* oldFocusedNode = oldDocument ? oldDocument->focusedNode() : 0;
+    if (oldFocusedNode == node)
+        return true;
+        
+    if (oldFocusedNode && oldFocusedNode->rootEditableElement() == oldFocusedNode && !relinquishesEditingFocus(oldFocusedNode))
+        return false;
+        
+    clearSelectionIfNeeded(oldFocusedFrame.get(), node);
+    
     if (!node) {
         if (oldDocument)
             oldDocument->setFocusedNode(0);
index b05fa24c67bb18c1192bf59d86daf3a98c171bfa..7fb7a45e6f0d219d56e87b6e01cd27d9d3c3798d 100644 (file)
@@ -613,7 +613,7 @@ void Frame::setFocusedNodeIfNeeded()
             // so add the !isFrameElement check here. There's probably a better way to make this
             // work in the long term, but this is the safest fix at this time.
             if (target && target->isMouseFocusable() && !isFrameElement(target)) {
-                document()->setFocusedNode(target);
+                page()->focusController()->setFocusedNode(target);
                 return;
             }
             renderer = renderer->parent();