2011-03-04 Jia Pu <jpu@apple.com>
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 5 Mar 2011 06:12:36 +0000 (06:12 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 5 Mar 2011 06:12:36 +0000 (06:12 +0000)
        Reviewed by Darin Adler.

        On Mac, the bounding box sent to EditorClient::showCorrectionPanel() is incorrect when the correction occurs in an iframe.
        https://bugs.webkit.org/show_bug.cgi?id=55717
        <rdar://problem/9018127>

        manual-test: manual-tests/platforms/mac/autocorrection/autocorrection-in-iframe.html

        Previously, the bounding box passed into EditorClient::showCorrectionPanel() is in the frame's
        coordinate. This is incorrect when the correction occurs in an iframe. This patch added code
        to convert the bounding box to window coordinate using ScrollView::contentToWindow().

        * dom/Range.cpp:
        (WebCore::Range::getBoundingClientRect):
        (WebCore::Range::boundingRect):
        * dom/Range.h:
        * editing/Editor.cpp:
        (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges):
        (WebCore::Editor::correctionPanelTimerFired):
        (WebCore::Editor::windowRectForRange):
        * editing/Editor.h:
        * manual-tests/autocorrection/autocorrection-in-iframe.html: Added.
        * manual-tests/autocorrection/document-for-iframe-test.html: Added.
2011-03-04  Jia Pu  <jpu@apple.com>

        Reviewed by Darin Adler.

        On Mac, the bounding box sent to EditorClient::showCorrectionPanel() is incorrect when the correction occurs in an iframe.
        https://bugs.webkit.org/show_bug.cgi?id=55717
        <rdar://problem/9018127>

        With the change in WebCore, the bounding box passed into EditorClient::showCorrectionPanel()
        is already in window coordinate. We don't need to do further conversion anymore.

        * WebCoreSupport/WebEditorClient.mm:
        (WebEditorClient::showCorrectionPanel):

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

Source/WebCore/ChangeLog
Source/WebCore/dom/Range.cpp
Source/WebCore/dom/Range.h
Source/WebCore/editing/Editor.cpp
Source/WebCore/editing/Editor.h
Source/WebCore/manual-tests/autocorrection/autocorrection-in-iframe.html [new file with mode: 0644]
Source/WebCore/manual-tests/autocorrection/document-for-iframe-test.html [new file with mode: 0644]
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebCoreSupport/WebEditorClient.mm

index ce0d91b..521f281 100644 (file)
@@ -2,6 +2,32 @@
 
         Reviewed by Darin Adler.
 
+        On Mac, the bounding box sent to EditorClient::showCorrectionPanel() is incorrect when the correction occurs in an iframe.
+        https://bugs.webkit.org/show_bug.cgi?id=55717
+        <rdar://problem/9018127>
+
+        manual-test: manual-tests/platforms/mac/autocorrection/autocorrection-in-iframe.html
+
+        Previously, the bounding box passed into EditorClient::showCorrectionPanel() is in the frame's
+        coordinate. This is incorrect when the correction occurs in an iframe. This patch added code
+        to convert the bounding box to window coordinate using ScrollView::contentToWindow().
+
+        * dom/Range.cpp:
+        (WebCore::Range::getBoundingClientRect):
+        (WebCore::Range::boundingRect):
+        * dom/Range.h:
+        * editing/Editor.cpp:
+        (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges):
+        (WebCore::Editor::correctionPanelTimerFired):
+        (WebCore::Editor::windowRectForRange):
+        * editing/Editor.h:
+        * manual-tests/autocorrection/autocorrection-in-iframe.html: Added.
+        * manual-tests/autocorrection/document-for-iframe-test.html: Added.
+
+2011-03-04  Jia Pu  <jpu@apple.com>
+
+        Reviewed by Darin Adler.
+
         Those checking in Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited() should be done with VisiblePosition::isNull().
         https://bugs.webkit.org/show_bug.cgi?id=55731
 
index db07e1d..a0370fa 100644 (file)
@@ -1903,22 +1903,8 @@ PassRefPtr<ClientRectList> Range::getClientRects() const
 
 PassRefPtr<ClientRect> Range::getBoundingClientRect() const
 {
-    if (!m_start.container())
-        return 0;
-
-    m_ownerDocument->updateLayoutIgnorePendingStylesheets();
-
-    Vector<FloatQuad> quads;
-    getBorderAndTextQuads(quads);
-
-    if (quads.isEmpty())
-        return ClientRect::create();
-
-    FloatRect result;
-    for (size_t i = 0; i < quads.size(); ++i)
-        result.unite(quads[i].boundingBox());
-
-    return ClientRect::create(result);
+    FloatRect rect = boundingRect();
+    return rect.isEmpty() ? 0 : ClientRect::create(rect);
 }
 
 static void adjustFloatQuadsForScrollAndAbsoluteZoom(Vector<FloatQuad>& quads, Document* document, RenderObject* renderer)
@@ -1973,6 +1959,26 @@ void Range::getBorderAndTextQuads(Vector<FloatQuad>& quads) const
     }
 }
 
+    
+FloatRect Range::boundingRect() const
+{
+    if (!m_start.container())
+        return FloatRect();
+
+    m_ownerDocument->updateLayoutIgnorePendingStylesheets();
+
+    Vector<FloatQuad> quads;
+    getBorderAndTextQuads(quads);
+    if (quads.isEmpty())
+        return FloatRect();
+
+    FloatRect result;
+    for (size_t i = 0; i < quads.size(); ++i)
+        result.unite(quads[i].boundingBox());
+
+    return result;
+}
+
 } // namespace WebCore
 
 #ifndef NDEBUG
index 01c12e3..5637b77 100644 (file)
@@ -111,6 +111,7 @@ public:
     // Transform-friendly
     void textQuads(Vector<FloatQuad>&, bool useSelectionHeight = false);
     void getBorderAndTextQuads(Vector<FloatQuad>&) const;
+    FloatRect boundingRect() const;
 
     void nodeChildrenChanged(ContainerNode*);
     void nodeChildrenWillBeRemoved(ContainerNode*);
index dd93a27..6ba7043 100644 (file)
@@ -102,19 +102,6 @@ static inline bool isAmbiguousBoundaryCharacter(UChar character)
     return character == '\'' || character == rightSingleQuotationMark || character == hebrewPunctuationGershayim;
 }
 
-#if SUPPORT_AUTOCORRECTION_PANEL
-static FloatRect boundingBoxForRange(Range* range)
-{
-    Vector<FloatQuad> textQuads;
-    range->getBorderAndTextQuads(textQuads);
-    FloatRect totalBoundingBox;
-    size_t size = textQuads.size();
-    for (size_t i = 0; i< size; ++i)
-        totalBoundingBox.unite(textQuads[i].boundingBox());
-    return totalBoundingBox;
-}
-#endif // SUPPORT_AUTOCORRECTION_PANEL
-
 static const Vector<DocumentMarker::MarkerType>& markerTypesForAutocorrection()
 {
     DEFINE_STATIC_LOCAL(Vector<DocumentMarker::MarkerType>, markerTypesForAutoCorrection, ());
@@ -2414,17 +2401,14 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
             if (shouldShowCorrectionPanel) {
                 if (resultLocation + resultLength == spellingRangeEndOffset) {
                     // We only show the correction panel on the last word.
-                    Vector<FloatQuad> textQuads;
-                    rangeToReplace->getBorderAndTextQuads(textQuads);
-                    Vector<FloatQuad>::const_iterator end = textQuads.end();
-                    FloatRect totalBoundingBox;
-                    for (Vector<FloatQuad>::const_iterator it = textQuads.begin(); it < end; ++it)
-                        totalBoundingBox.unite(it->boundingBox());
+                    FloatRect boundingBox = windowRectForRange(rangeToReplace.get());
+                    if (boundingBox.isEmpty())
+                        break;
                     m_correctionPanelInfo.rangeToBeReplaced = rangeToReplace;
                     m_correctionPanelInfo.replacedString = plainText(rangeToReplace.get());
                     m_correctionPanelInfo.replacementString = result->replacement;
                     m_correctionPanelInfo.isActive = true;
-                    client()->showCorrectionPanel(m_correctionPanelInfo.panelType, totalBoundingBox, m_correctionPanelInfo.replacedString, result->replacement, Vector<String>(), this);
+                    client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, result->replacement, Vector<String>(), this);
                     break;
                 }
                 // If this function is called for showing correction panel, we ignore other correction or replacement.
@@ -2552,7 +2536,9 @@ void Editor::correctionPanelTimerFired(Timer<Editor>*)
     case CorrectionPanelInfo::PanelTypeReversion: {
         m_correctionPanelInfo.isActive = true;
         m_correctionPanelInfo.replacedString = plainText(m_correctionPanelInfo.rangeToBeReplaced.get());
-        client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBoxForRange(m_correctionPanelInfo.rangeToBeReplaced.get()), m_correctionPanelInfo.replacedString, m_correctionPanelInfo.replacementString, Vector<String>(), this);
+        FloatRect boundingBox = windowRectForRange(m_correctionPanelInfo.rangeToBeReplaced.get());
+        if (!boundingBox.isEmpty())
+            client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, m_correctionPanelInfo.replacementString, Vector<String>(), this);
     }
         break;
     case CorrectionPanelInfo::PanelTypeSpellingSuggestions: {
@@ -2568,7 +2554,9 @@ void Editor::correctionPanelTimerFired(Timer<Editor>*)
         String topSuggestion = suggestions.first();
         suggestions.remove(0);
         m_correctionPanelInfo.isActive = true;
-        client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBoxForRange(m_correctionPanelInfo.rangeToBeReplaced.get()), m_correctionPanelInfo.replacedString, topSuggestion, suggestions, this);
+        FloatRect boundingBox = windowRectForRange(m_correctionPanelInfo.rangeToBeReplaced.get());
+        if (!boundingBox.isEmpty())
+            client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, topSuggestion, suggestions, this);
     }
         break;
     }
@@ -3623,4 +3611,10 @@ bool Editor::selectionStartHasSpellingMarkerFor(int from, int length) const
     return false;
 }
 
+FloatRect Editor::windowRectForRange(const Range* range) const
+{
+    FrameView* view = frame()->view();
+    return view ? view->contentsToWindow(IntRect(range->boundingRect())) : FloatRect();
+}        
+
 } // namespace WebCore
index 595b77e..8f2ce45 100644 (file)
@@ -430,6 +430,7 @@ private:
     void applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>& markerTypesToAdd);
     // Return true if correction was applied, false otherwise.
     bool applyAutocorrectionBeforeTypingIfAppropriate();
+    FloatRect windowRectForRange(const Range*) const;
 };
 
 inline void Editor::setStartNewKillRingSequence(bool flag)
diff --git a/Source/WebCore/manual-tests/autocorrection/autocorrection-in-iframe.html b/Source/WebCore/manual-tests/autocorrection/autocorrection-in-iframe.html
new file mode 100644 (file)
index 0000000..c4ebbcf
--- /dev/null
@@ -0,0 +1,16 @@
+<html>
+<head>
+
+<title>Test autocorreciton UI positioning in iframe</title>
+</head>
+<body>
+<p>This test verifies that autocorrection UI is positioned correctly when the corrected word is in an iframe.</p>
+<p>After typing "the manag", you should see the autocorrection UI is shown below the bounding box of the corrected word "manag".</p>
+<br>
+<br>
+<br>
+<div style="-webkit-transform: translate(100px, 100px) rotate(20deg)">
+  <iframe src="document-for-iframe-test.html"></iframe>
+</div>
+</body>
+</html>
diff --git a/Source/WebCore/manual-tests/autocorrection/document-for-iframe-test.html b/Source/WebCore/manual-tests/autocorrection/document-for-iframe-test.html
new file mode 100644 (file)
index 0000000..629a830
--- /dev/null
@@ -0,0 +1,36 @@
+<html>
+<head>
+<style>
+.editing {
+    border: 2px solid red;
+    padding: 12px;
+    font-size: 24px;
+}
+</style>
+
+<script src=../../../../LayoutTests/editing/editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+function editingTest() {
+    typeCharacterCommand('t');
+    typeCharacterCommand('h');
+    typeCharacterCommand('e');
+    typeCharacterCommand(' ');
+    typeCharacterCommand('m');
+    typeCharacterCommand('a');
+    typeCharacterCommand('n');
+    typeCharacterCommand('a');
+    typeCharacterCommand('g');
+}
+</script>
+
+<div contenteditable id="root" class="editing">
+<span id="test"></span>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
index 17dc4d4..119b35b 100644 (file)
@@ -1,3 +1,17 @@
+2011-03-04  Jia Pu  <jpu@apple.com>
+
+        Reviewed by Darin Adler.
+
+        On Mac, the bounding box sent to EditorClient::showCorrectionPanel() is incorrect when the correction occurs in an iframe.
+        https://bugs.webkit.org/show_bug.cgi?id=55717
+        <rdar://problem/9018127>
+
+        With the change in WebCore, the bounding box passed into EditorClient::showCorrectionPanel()
+        is already in window coordinate. We don't need to do further conversion anymore.
+
+        * WebCoreSupport/WebEditorClient.mm:
+        (WebEditorClient::showCorrectionPanel):
+
 2011-03-04  Jessie Berlin  <jberlin@apple.com>
 
         Reviewed by Maciej Stachowiak.
index 3f7a53f..ad8e1be 100644 (file)
@@ -894,10 +894,6 @@ void WebEditorClient::updateSpellingUIWithGrammarString(const String& badGrammar
 void WebEditorClient::showCorrectionPanel(WebCore::CorrectionPanelInfo::PanelType panelType, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings, Editor* editor) {
     dismissCorrectionPanel(ReasonForDismissingCorrectionPanelIgnored);
 
-    NSRect boundingBoxAsNSRect = boundingBoxOfReplacedString;
-    NSRect webViewFrame = m_webView.frame;
-    boundingBoxAsNSRect.origin.y = webViewFrame.size.height-NSMaxY(boundingBoxAsNSRect);
-
     // Need to explicitly use these local NSString objects, because the C++ references may be invalidated by the time the block below is executed.
     NSString *replacedStringAsNSString = replacedString;
     NSString *replacementStringAsNSString = replacementString;
@@ -915,7 +911,7 @@ void WebEditorClient::showCorrectionPanel(WebCore::CorrectionPanelInfo::PanelTyp
             [alternativeStrings addObject:(NSString*)alternativeReplacementStrings[i]];
     }
     NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker];
-    [[NSSpellChecker sharedSpellChecker] showCorrectionBubbleOfType:bubbleType primaryString:replacementStringAsNSString alternativeStrings:alternativeStrings forStringInRect:boundingBoxAsNSRect view:m_webView completionHandler:^(NSString *acceptedString) {
+    [[NSSpellChecker sharedSpellChecker] showCorrectionBubbleOfType:bubbleType primaryString:replacementStringAsNSString alternativeStrings:alternativeStrings forStringInRect:boundingBoxOfReplacedString view:m_webView completionHandler:^(NSString *acceptedString) {
         switch (bubbleType) {
         case NSCorrectionBubbleTypeCorrection:
             if (acceptedString)