2008-08-08 Beth Dakin <bdakin@apple.com>
authorbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 9 Aug 2008 01:05:01 +0000 (01:05 +0000)
committerbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 9 Aug 2008 01:05:01 +0000 (01:05 +0000)
        Reviewed by Darin.

        This patch makes the findString and markAllMatchesForText functions
        work with disconnected frames that are contained within
        overflow:hidden blocks.

        * editing/Editor.cpp:
        (WebCore::Editor::rangeVisibility):
        (WebCore::Editor::firstVisibleRange):
        (WebCore::Editor::lastVisibleRange):
        * editing/Editor.h:
        (WebCore::Editor::):
        * page/Frame.cpp:
        (WebCore::Frame::findString):
        (WebCore::Frame::markAllMatchesForText):

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

WebCore/ChangeLog
WebCore/editing/Editor.cpp
WebCore/editing/Editor.h
WebCore/page/Frame.cpp

index 0b8aec1ad4f7bc55a218cbb3f4874b575d525f54..3caaf29cad985f3c0b9b8c7b4d34d40819f238df 100644 (file)
@@ -1,3 +1,21 @@
+2008-08-08  Beth Dakin  <bdakin@apple.com>
+
+        Reviewed by Darin.
+
+        This patch makes the findString and markAllMatchesForText functions 
+        work with disconnected frames that are contained within 
+        overflow:hidden blocks.
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::rangeVisibility):
+        (WebCore::Editor::firstVisibleRange):
+        (WebCore::Editor::lastVisibleRange):
+        * editing/Editor.h:
+        (WebCore::Editor::):
+        * page/Frame.cpp:
+        (WebCore::Frame::findString):
+        (WebCore::Frame::markAllMatchesForText):
+
 2008-08-08  Maxime Britto  <britto@apple.com>
 
         Reviewed by Adele.
index 526ed115e5a5ef21b568efd6ffd0a4ca13eae6b5..0651830e0e6cd2a3a9b08b7c2633b8827a5a898d 100644 (file)
@@ -53,6 +53,8 @@
 #include "Page.h"
 #include "Pasteboard.h"
 #include "RemoveFormatCommand.h"
+#include "RenderBlock.h"
+#include "RenderPart.h"
 #include "ReplaceSelectionCommand.h"
 #include "Sound.h"
 #include "Text.h"
@@ -1930,4 +1932,72 @@ void Editor::setKillRingToYankedState()
 
 #endif
 
+Editor::Visibility Editor::rangeVisibility(Range* range) const
+{
+    // Right now, we only check the visibility of a range for disconnected frames. For all other
+    // frames, we assume visibility.
+    if (!m_frame->isDisconnected() || !range)
+        return InsideVisibleArea;
+    
+    RenderPart* renderer = m_frame->ownerRenderer();
+    RenderBlock* container = renderer->containingBlock();
+    if (!(container->style()->overflowX() == OHIDDEN || container->style()->overflowY() == OHIDDEN))
+        return InsideVisibleArea;
+
+    IntRect rectInPageCoords = container->getOverflowClipRect(0, 0);
+    IntRect rectInFrameCoords = IntRect(renderer->xPos() * -1, renderer->yPos() * -1,
+                                    rectInPageCoords.width(), rectInPageCoords.height());
+    IntRect resultRect = range->boundingBox();
+    
+    if (rectInFrameCoords.contains(resultRect))
+        return InsideVisibleArea;
+    if (resultRect.y() < rectInFrameCoords.y())
+        return BeforeVisibleArea;
+    if (resultRect.y() > rectInFrameCoords.y())
+        return AfterVisibleArea;
+
+    ASSERT(resultRect.y() == rectInFrameCoords.y());
+    if (resultRect.x() < rectInFrameCoords.x())
+        return BeforeVisibleArea;
+    return AfterVisibleArea;
+}
+
+PassRefPtr<Range> Editor::firstVisibleRange(Range* startRange, const String& target, bool forward, bool caseFlag)
+{
+    if (!forward)
+        return startRange;
+
+    RefPtr<Range> resultRange = startRange;
+    RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
+    ExceptionCode ec = 0;
+
+    while (rangeVisibility(resultRange.get()) == BeforeVisibleArea) {
+        searchRange->setStartAfter(resultRange->endContainer(), ec);
+        if (searchRange->startContainer() == searchRange->endContainer())
+            return startRange;
+        resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
+    }
+    
+    return resultRange;
+}
+
+PassRefPtr<Range> Editor::lastVisibleRange(Range* startRange, const String& target, bool forward, bool caseFlag)
+{
+    if (forward)
+        return startRange;
+
+    RefPtr<Range> resultRange = startRange;
+    RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
+    ExceptionCode ec = 0;
+
+    while (rangeVisibility(resultRange.get()) == AfterVisibleArea) {
+        searchRange->setEndBefore(resultRange->startContainer(), ec);
+        if (searchRange->startContainer() == searchRange->endContainer())
+            return startRange;
+        resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
+    }
+    
+    return resultRange;
+}
+
 } // namespace WebCore
index 14de1e340b4b6ebee152a457f1d08426afe41f6a..28ef6b7269967f71fa765ff46b4758b983257efc 100644 (file)
@@ -253,6 +253,12 @@ public:
     void setKillRingToYankedState();
 
     PassRefPtr<Range> selectedRange();
+    
+    // We should make these functions private when their callers in Frame are moved over here to Editor
+    enum Visibility { BeforeVisibleArea, InsideVisibleArea, AfterVisibleArea };
+    Visibility rangeVisibility(Range*) const;
+    PassRefPtr<Range> firstVisibleRange(Range*, const String&, bool forward, bool caseFlag);
+    PassRefPtr<Range> lastVisibleRange(Range*, const String&, bool forward, bool caseFlag);
 
 private:
     Frame* m_frame;
index a51f980b41b8852f0836d34a6cf9e13f35e75324..e2b3b4874b4d87b339c8e1cdab909ae527805b9d 100644 (file)
@@ -1538,15 +1538,27 @@ bool Frame::findString(const String& target, bool forward, bool caseFlag, bool w
 
         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
     }
+    
+    Editor::Visibility rangeLocation = editor()->rangeVisibility(resultRange.get());
+    if (rangeLocation == Editor::BeforeVisibleArea && forward)
+        resultRange = editor()->firstVisibleRange(resultRange.get(), target, forward, caseFlag);
 
     // If we didn't find anything and we're wrapping, search again in the entire document (this will
     // redundantly re-search the area already searched in some cases).
-    if (resultRange->collapsed(exception) && wrapFlag) {
+    bool disconnectedFrameShouldWrap = rangeLocation == Editor::AfterVisibleArea
+        || (rangeLocation == Editor::BeforeVisibleArea && !forward);
+    if (resultRange->collapsed(exception) && wrapFlag || disconnectedFrameShouldWrap) {
         searchRange = rangeOfContents(document());
         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
         // We used to return false here if we ended up with the same range that we started with
         // (e.g., the selection was already the only instance of this text). But we decided that
         // this should be a success case instead, so we'll just fall through in that case.
+        
+        rangeLocation = editor()->rangeVisibility(resultRange.get());
+        if (rangeLocation == Editor::BeforeVisibleArea)
+            resultRange = editor()->firstVisibleRange(resultRange.get(), target, forward, caseFlag);
+        else if (rangeLocation == Editor::AfterVisibleArea)
+            resultRange = editor()->lastVisibleRange(resultRange.get(), target, forward, caseFlag);
     }
 
     if (resultRange->collapsed(exception))
@@ -1582,6 +1594,15 @@ unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsig
         VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
         if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
             break;
+        
+        Editor::Visibility rangeLocation = editor()->rangeVisibility(resultRange.get());
+        if (rangeLocation == Editor::BeforeVisibleArea) {
+            searchRange = rangeOfContents(document());
+            searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), exception);
+            continue;
+        }
+        if (rangeLocation == Editor::AfterVisibleArea)
+            break;
 
         ++matchCount;