+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.
#include "Page.h"
#include "Pasteboard.h"
#include "RemoveFormatCommand.h"
+#include "RenderBlock.h"
+#include "RenderPart.h"
#include "ReplaceSelectionCommand.h"
#include "Sound.h"
#include "Text.h"
#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
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;
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))
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;