212void InPageSearchManager::scopeStringMatches(const String& text, bool reset, Frame* scopingFrame)
213{
214 if (reset) {
215 m_activeMatchCount = 0;
216 m_resumeScopingFromRange = 0;
217 m_scopingComplete = false;
218 m_locatingActiveMatch = true;
219 // New search should always start from mainFrame.
220 scopeStringMatchesSoon(m_webPage->mainFrame(), text, false /* reset */);
221 return;
222 }
223
224 if (m_resumeScopingFromRange && scopingFrame != m_resumeScopingFromRange->ownerDocument()->frame())
225 m_resumeScopingFromRange = 0;
226
227 RefPtr<Range> searchRange(rangeOfContents(scopingFrame->document()));
228 Node* originalEndContainer = searchRange->endContainer();
229 int originalEndOffset = searchRange->endOffset();
230 ExceptionCode ec = 0, ec2 = 0;
231 if (m_resumeScopingFromRange) {
232 searchRange->setStart(m_resumeScopingFromRange->startContainer(), m_resumeScopingFromRange->startOffset(ec2) + 1, ec);
233 if (ec || ec2) {
234 m_scopingComplete = true; // We should stop scoping because of some stale data.
235 return;
236 }
237 }
238
239 int matchCount = 0;
240 bool timeout = false;
241 double startTime = currentTime();
242 do {
243 RefPtr<Range> resultRange(findPlainText(searchRange.get(), text, CaseInsensitive));
244 if (resultRange->collapsed(ec)) {
245 if (!resultRange->startContainer()->isInShadowTree())
246 break;
247 searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), ec);
248 searchRange->setEnd(originalEndContainer, originalEndOffset, ec);
249 continue;
250 }
251
252 if (scopingFrame->editor()->insideVisibleArea(resultRange.get())) {
253 ++matchCount;
254 bool foundActiveMatch = false;
255 if (m_locatingActiveMatch && areRangesEqual(resultRange.get(), m_activeMatch.get())) {
256 foundActiveMatch = true;
257 m_locatingActiveMatch = false;
258 m_activeMatchIndex = m_activeMatchCount + matchCount;
259 // FIXME: We need to notify client with m_activeMatchIndex.
260 }
261 resultRange->ownerDocument()->markers()->addTextMatchMarker(resultRange.get(), foundActiveMatch);
262 }
263 searchRange->setStart(resultRange->endContainer(ec), resultRange->endOffset(ec), ec);
264 Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
265 if (searchRange->collapsed(ec) && shadowTreeRoot)
266 searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
267 m_resumeScopingFromRange = resultRange;
268 timeout = (currentTime() - startTime) >= MaxScopingDuration;
269 } while (!timeout);
270
271 if (matchCount > 0) {
272 scopingFrame->editor()->setMarkedTextMatchesAreHighlighted(true /* highlight */);
273 m_activeMatchCount += matchCount;
274 }
275
276 if (timeout)
277 scopeStringMatchesSoon(scopingFrame, text, false /* reset */);
278 else {
279 // Scoping is done for this frame.
280 Frame* nextFrame = DOMSupport::incrementFrame(scopingFrame, true /* forward */, false /* wrapFlag */);
281 if (!nextFrame) {
282 m_scopingComplete = true;
283 return; // Scoping is done for all frames;
284 }
285 scopeStringMatchesSoon(nextFrame, text, false /* reset */);
286 }
287}
288
289void InPageSearchManager::scopeStringMatchesSoon(Frame* scopingFrame, const String& text, bool reset)
290{
291 m_deferredScopingWork.append(new DeferredScopeStringMatches(this, scopingFrame, text, reset));
292}
293
294void InPageSearchManager::callScopeStringMatches(DeferredScopeStringMatches* caller, Frame* scopingFrame, const String& text, bool reset)
295{
296 m_deferredScopingWork.remove(m_deferredScopingWork.find(caller));
297 scopeStringMatches(text, reset, scopingFrame);
298 delete caller;
299}
300
301void InPageSearchManager::cancelPendingScopingEffort()
302{
303 deleteAllValues(m_deferredScopingWork);
304 m_deferredScopingWork.clear();
305}
306