int TextFinder::selectFindMatch(unsigned index, WebRect* selectionRect) { SECURITY_DCHECK(index < m_findMatchesCache.size()); Range* range = m_findMatchesCache[index].m_range; if (!range->boundaryPointsValid() || !range->startContainer()->isConnected()) return -1; // Check if the match is already selected. if (!m_currentActiveMatchFrame || !m_activeMatch || !areRangesEqual(m_activeMatch.get(), range)) { m_activeMatchIndex = m_findMatchesCache[index].m_ordinal - 1; // Set this frame as the active frame (the one with the active highlight). m_currentActiveMatchFrame = true; ownerFrame().viewImpl()->setFocusedFrame(&ownerFrame()); if (m_activeMatch) setMarkerActive(m_activeMatch.get(), false); m_activeMatch = range; setMarkerActive(m_activeMatch.get(), true); // Clear any user selection, to make sure Find Next continues on from the // match we just activated. ownerFrame().frame()->selection().clear(); // Make sure no node is focused. See http://crbug.com/38700. ownerFrame().frame()->document()->clearFocusedElement(); } IntRect activeMatchRect; IntRect activeMatchBoundingBox = enclosingIntRect( LayoutObject::absoluteBoundingBoxRectForRange(m_activeMatch.get())); if (!activeMatchBoundingBox.isEmpty()) { if (m_activeMatch->firstNode() && m_activeMatch->firstNode()->layoutObject()) { m_activeMatch->firstNode()->layoutObject()->scrollRectToVisible( LayoutRect(activeMatchBoundingBox), ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded, UserScroll); } // Zoom to the active match. activeMatchRect = ownerFrame().frameView()->contentsToRootFrame(activeMatchBoundingBox); ownerFrame().viewImpl()->zoomToFindInPageRect(activeMatchRect); } if (selectionRect) *selectionRect = activeMatchRect; return m_activeMatchIndex + 1; }
bool InPageSearchManager::findAndMarkText(const String& text, Range* range, Frame* frame, const FindOptions& options, bool isNewSearch) { m_activeMatch = frame->editor()->findStringAndScrollToVisible(text, range, options); if (m_activeMatch) { setMarkerActive(m_activeMatch.get(), true /* active */); if (isNewSearch) { scopeStringMatches(text, true /* reset */); // FIXME: If it is a not new search, we need to calculate activeMatchIndex and notify client. } return true; } return false; }
int TextFinder::selectFindMatch(unsigned index, WebRect* selectionRect) { ASSERT_WITH_SECURITY_IMPLICATION(index < m_findMatchesCache.size()); RefPtrWillBeRawPtr<Range> range = m_findMatchesCache[index].m_range; if (!range->boundaryPointsValid() || !range->startContainer()->inDocument()) return -1; // Check if the match is already selected. TextFinder& mainFrameTextFinder = m_ownerFrame.viewImpl()->mainFrameImpl()->ensureTextFinder(); WebLocalFrameImpl* activeMatchFrame = mainFrameTextFinder.m_currentActiveMatchFrame; if (&m_ownerFrame != activeMatchFrame || !m_activeMatch || !areRangesEqual(m_activeMatch.get(), range.get())) { if (isActiveMatchFrameValid()) activeMatchFrame->ensureTextFinder().setMatchMarkerActive(false); m_activeMatchIndexInCurrentFrame = m_findMatchesCache[index].m_ordinal - 1; // Set this frame as the active frame (the one with the active highlight). mainFrameTextFinder.m_currentActiveMatchFrame = &m_ownerFrame; m_ownerFrame.viewImpl()->setFocusedFrame(&m_ownerFrame); m_activeMatch = range.release(); setMarkerActive(m_activeMatch.get(), true); // Clear any user selection, to make sure Find Next continues on from the match we just activated. m_ownerFrame.frame()->selection().clear(); // Make sure no node is focused. See http://crbug.com/38700. m_ownerFrame.frame()->document()->setFocusedElement(nullptr); } IntRect activeMatchRect; IntRect activeMatchBoundingBox = enclosingIntRect(RenderObject::absoluteBoundingBoxRectForRange(m_activeMatch.get())); if (!activeMatchBoundingBox.isEmpty()) { if (m_activeMatch->firstNode() && m_activeMatch->firstNode()->renderer()) { m_activeMatch->firstNode()->renderer()->scrollRectToVisible( activeMatchBoundingBox, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded); } // Zoom to the active match. activeMatchRect = m_ownerFrame.frameView()->contentsToWindow(activeMatchBoundingBox); m_ownerFrame.viewImpl()->zoomToFindInPageRect(activeMatchRect); } if (selectionRect) *selectionRect = activeMatchRect; return ordinalOfFirstMatch() + m_activeMatchIndexInCurrentFrame + 1; }
void TextFinder::clearActiveFindMatch() { m_currentActiveMatchFrame = false; setMarkerActive(m_activeMatch.get(), false); resetActiveMatch(); }
bool TextFinder::find(int identifier, const WebString& searchText, const WebFindOptions& options, bool wrapWithinFrame, bool* activeNow) { if (!options.findNext) unmarkAllTextMatches(); else setMarkerActive(m_activeMatch.get(), false); if (m_activeMatch && &m_activeMatch->ownerDocument() != ownerFrame().frame()->document()) m_activeMatch = nullptr; // If the user has selected something since the last Find operation we want // to start from there. Otherwise, we start searching from where the last Find // operation left off (either a Find or a FindNext operation). VisibleSelection selection(ownerFrame().frame()->selection().selection()); bool activeSelection = !selection.isNone(); if (activeSelection) { m_activeMatch = firstRangeOf(selection); ownerFrame().frame()->selection().clear(); } DCHECK(ownerFrame().frame()); DCHECK(ownerFrame().frame()->view()); const FindOptions findOptions = (options.forward ? 0 : Backwards) | (options.matchCase ? 0 : CaseInsensitive) | (wrapWithinFrame ? WrapAround : 0) | (options.wordStart ? AtWordStarts : 0) | (options.medialCapitalAsWordStart ? TreatMedialCapitalAsWordStart : 0) | (options.findNext ? 0 : StartInSelection); m_activeMatch = ownerFrame().frame()->editor().findStringAndScrollToVisible( searchText, m_activeMatch.get(), findOptions); if (!m_activeMatch) { // If we're finding next the next active match might not be in the current // frame. In this case we don't want to clear the matches cache. if (!options.findNext) clearFindMatchesCache(); ownerFrame().frameView()->invalidatePaintForTickmarks(); return false; } // If the user is browsing a page with autosizing, adjust the zoom to the // column where the next hit has been found. Doing this when autosizing is // not set will result in a zoom reset on small devices. if (ownerFrame() .frame() ->document() ->textAutosizer() ->pageNeedsAutosizing()) { ownerFrame().viewImpl()->zoomToFindInPageRect( ownerFrame().frameView()->contentsToRootFrame( enclosingIntRect(LayoutObject::absoluteBoundingBoxRectForRange( m_activeMatch.get())))); } bool wasActiveFrame = m_currentActiveMatchFrame; m_currentActiveMatchFrame = true; bool isActive = setMarkerActive(m_activeMatch.get(), true); if (activeNow) *activeNow = isActive; // Make sure no node is focused. See http://crbug.com/38700. ownerFrame().frame()->document()->clearFocusedElement(); // Set this frame as focused. ownerFrame().viewImpl()->setFocusedFrame(&ownerFrame()); if (!options.findNext || activeSelection || !isActive) { // This is either an initial Find operation, a Find-next from a new // start point due to a selection, or new matches were found during // Find-next due to DOM alteration (that couldn't be set as active), so // we set the flag to ask the scoping effort to find the active rect for // us and report it back to the UI. m_locatingActiveRect = true; } else { if (!wasActiveFrame) { if (options.forward) m_activeMatchIndex = 0; else m_activeMatchIndex = m_lastMatchCount - 1; } else { if (options.forward) ++m_activeMatchIndex; else --m_activeMatchIndex; if (m_activeMatchIndex + 1 > m_lastMatchCount) m_activeMatchIndex = 0; else if (m_activeMatchIndex < 0) m_activeMatchIndex = m_lastMatchCount - 1; } WebRect selectionRect = ownerFrame().frameView()->contentsToRootFrame( m_activeMatch->boundingBox()); reportFindInPageSelection(selectionRect, m_activeMatchIndex + 1, identifier); } return true; }
bool TextFinder::find(int identifier, const WebString& searchText, const WebFindOptions& options, bool wrapWithinFrame, WebRect* selectionRect) { if (!m_ownerFrame.frame() || !m_ownerFrame.frame()->page()) return false; WebLocalFrameImpl* mainFrameImpl = m_ownerFrame.viewImpl()->mainFrameImpl(); if (!options.findNext) m_ownerFrame.frame()->page()->unmarkAllTextMatches(); else setMarkerActive(m_activeMatch.get(), false); if (m_activeMatch && &m_activeMatch->ownerDocument() != m_ownerFrame.frame()->document()) m_activeMatch = nullptr; // If the user has selected something since the last Find operation we want // to start from there. Otherwise, we start searching from where the last Find // operation left off (either a Find or a FindNext operation). VisibleSelection selection(m_ownerFrame.frame()->selection().selection()); bool activeSelection = !selection.isNone(); if (activeSelection) { m_activeMatch = selection.firstRange().get(); m_ownerFrame.frame()->selection().clear(); } ASSERT(m_ownerFrame.frame() && m_ownerFrame.frame()->view()); const FindOptions findOptions = (options.forward ? 0 : Backwards) | (options.matchCase ? 0 : CaseInsensitive) | (wrapWithinFrame ? WrapAround : 0) | (options.wordStart ? AtWordStarts : 0) | (options.medialCapitalAsWordStart ? TreatMedialCapitalAsWordStart : 0) | (options.findNext ? 0 : StartInSelection); m_activeMatch = m_ownerFrame.frame()->editor().findStringAndScrollToVisible(searchText, m_activeMatch.get(), findOptions); if (!m_activeMatch) { // If we're finding next the next active match might not be in the current frame. // In this case we don't want to clear the matches cache. if (!options.findNext) clearFindMatchesCache(); m_ownerFrame.invalidateAll(); return false; } #if OS(ANDROID) m_ownerFrame.viewImpl()->zoomToFindInPageRect(m_ownerFrame.frameView()->contentsToWindow(enclosingIntRect(RenderObject::absoluteBoundingBoxRectForRange(m_activeMatch.get())))); #endif setMarkerActive(m_activeMatch.get(), true); WebLocalFrameImpl* oldActiveFrame = mainFrameImpl->ensureTextFinder().m_currentActiveMatchFrame; mainFrameImpl->ensureTextFinder().m_currentActiveMatchFrame = &m_ownerFrame; // Make sure no node is focused. See http://crbug.com/38700. m_ownerFrame.frame()->document()->setFocusedElement(nullptr); if (!options.findNext || activeSelection) { // This is either a Find operation or a Find-next from a new start point // due to a selection, so we set the flag to ask the scoping effort // to find the active rect for us and report it back to the UI. m_locatingActiveRect = true; } else { if (oldActiveFrame != &m_ownerFrame) { if (options.forward) m_activeMatchIndexInCurrentFrame = 0; else m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1; } else { if (options.forward) ++m_activeMatchIndexInCurrentFrame; else --m_activeMatchIndexInCurrentFrame; if (m_activeMatchIndexInCurrentFrame + 1 > m_lastMatchCount) m_activeMatchIndexInCurrentFrame = 0; if (m_activeMatchIndexInCurrentFrame == -1) m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1; } if (selectionRect) { *selectionRect = m_ownerFrame.frameView()->contentsToWindow(m_activeMatch->boundingBox()); reportFindInPageSelection(*selectionRect, m_activeMatchIndexInCurrentFrame + 1, identifier); } } return true; }
void TextFinder::setMatchMarkerActive(bool active) { setMarkerActive(m_activeMatch.get(), active); }
bool InPageSearchManager::findNextString(const String& text, bool forward) { if (!text.length()) { clearTextMatches(); cancelPendingScopingEffort(); m_activeSearchString = String(); return false; } if (!shouldSearchForText(text)) { m_activeSearchString = text; return false; } // Validate the range in case any node has been removed since last search. if (m_activeMatch && !m_activeMatch->boundaryPointsValid()) m_activeMatch = 0; RefPtr<Range> searchStartingPoint(m_activeMatch); bool newSearch = m_activeSearchString != text; if (newSearch) { // Start a new search. m_activeSearchString = text; cancelPendingScopingEffort(); m_webPage->m_page->unmarkAllTextMatches(); } else { // Search same string for next occurrence. setMarkerActive(m_activeMatch.get(), false /* active */); // Searching for same string should start from the end of last match. if (m_activeMatch) { if (forward) searchStartingPoint->setStart(searchStartingPoint->endPosition()); else searchStartingPoint->setEnd(searchStartingPoint->startPosition()); } } // If there is any active selection, new search should start from the beginning of it. VisibleSelection selection = m_webPage->focusedOrMainFrame()->selection()->selection(); if (!selection.isNone()) { searchStartingPoint = selection.firstRange().get(); m_webPage->focusedOrMainFrame()->selection()->clear(); } Frame* currentActiveMatchFrame = selection.isNone() && m_activeMatch ? m_activeMatch->ownerDocument()->frame() : m_webPage->focusedOrMainFrame(); const FindOptions findOptions = (forward ? 0 : Backwards) | CaseInsensitive | StartInSelection; if (findAndMarkText(text, searchStartingPoint.get(), currentActiveMatchFrame, findOptions, newSearch)) return true; Frame* startFrame = currentActiveMatchFrame; do { currentActiveMatchFrame = DOMSupport::incrementFrame(currentActiveMatchFrame, forward, true /* wrapFlag */); if (findAndMarkText(text, 0, currentActiveMatchFrame, findOptions, newSearch)) return true; } while (currentActiveMatchFrame && startFrame != currentActiveMatchFrame); clearTextMatches(); // FIXME: We need to notify client here. return false; }