void SVGTextContentElement::selectSubString(unsigned charnum, unsigned nchars, ExceptionCode& ec) { unsigned numberOfChars = getNumberOfChars(); if (charnum >= numberOfChars) { ec = INDEX_SIZE_ERR; return; } if (nchars > numberOfChars - charnum) nchars = numberOfChars - charnum; ASSERT(document()); ASSERT(document()->frame()); FrameSelection* selection = document()->frame()->selection(); if (!selection) return; // Find selection start VisiblePosition start(firstPositionInNode(const_cast<SVGTextContentElement*>(this))); for (unsigned i = 0; i < charnum; ++i) start = start.next(); // Find selection end VisiblePosition end(start); for (unsigned i = 0; i < nchars; ++i) end = end.next(); selection->setSelection(VisibleSelection(start, end)); }
void SVGTextContentElement::selectSubString(unsigned charnum, unsigned nchars, ExceptionState& es) { unsigned numberOfChars = getNumberOfChars(); if (charnum >= numberOfChars) { es.throwUninformativeAndGenericDOMException(IndexSizeError); return; } if (nchars > numberOfChars - charnum) nchars = numberOfChars - charnum; ASSERT(document().frame()); // Find selection start VisiblePosition start(firstPositionInNode(const_cast<SVGTextContentElement*>(this))); for (unsigned i = 0; i < charnum; ++i) start = start.next(); // Find selection end VisiblePosition end(start); for (unsigned i = 0; i < nchars; ++i) end = end.next(); document().frame()->selection().setSelection(VisibleSelection(start, end)); }
void SurroundingText::initialize(const Position& startPosition, const Position& endPosition, unsigned maxLength) { ASSERT(startPosition.document() == endPosition.document()); const unsigned halfMaxLength = maxLength / 2; Document* document = startPosition.document(); // The position will have no document if it is null (as in no position). if (!document || !document->documentElement()) return; // The forward range starts at the selection end and ends at the document's // end. It will then be updated to only contain the text in the text in the // right range around the selection. CharacterIterator forwardIterator(endPosition, lastPositionInNode(document->documentElement()).parentAnchoredEquivalent(), TextIteratorStopsOnFormControls); // FIXME: why do we stop going trough the text if we were not able to select something on the right? if (!forwardIterator.atEnd()) forwardIterator.advance(maxLength - halfMaxLength); EphemeralRange forwardRange = forwardIterator.range(); if (forwardRange.isNull() || !Range::create(*document, endPosition, forwardRange.startPosition())->text().length()) return; // Same as with the forward range but with the backward range. The range // starts at the document's start and ends at the selection start and will // be updated. BackwardsCharacterIterator backwardsIterator(firstPositionInNode(document->documentElement()).parentAnchoredEquivalent(), startPosition, TextIteratorStopsOnFormControls); if (!backwardsIterator.atEnd()) backwardsIterator.advance(halfMaxLength); m_startOffsetInContent = Range::create(*document, backwardsIterator.endPosition(), startPosition)->text().length(); m_endOffsetInContent = Range::create(*document, backwardsIterator.endPosition(), endPosition)->text().length(); m_contentRange = Range::create(*document, backwardsIterator.endPosition(), forwardRange.startPosition()); ASSERT(m_contentRange); }
PassRefPtr<InjectedBundleRangeHandle> InjectedBundleNodeHandle::visibleRange() { VisiblePosition start = firstPositionInNode(m_node.ptr()); VisiblePosition end = lastPositionInNode(m_node.ptr()); RefPtr<Range> range = makeRange(start, end); return InjectedBundleRangeHandle::getOrCreate(range.get()); }
void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(Node* node) { if (!node) return; RefPtr<Range> rangeToCheck = Range::create(*m_frame.document(), firstPositionInNode(node), lastPositionInNode(node)); TextCheckingParagraph textToCheck(rangeToCheck, rangeToCheck); bool asynchronous = true; chunkAndMarkAllMisspellingsAndBadGrammar(resolveTextCheckingTypeMask(TextCheckingTypeSpelling | TextCheckingTypeGrammar), textToCheck, asynchronous); }
Position InsertTextCommand::positionInsideTextNode(const Position& p) { Position pos = p; if (isTabSpanTextNode(pos.anchorNode())) { RefPtrWillBeRawPtr<Node> textNode = document().createEditingTextNode(""); insertNodeAtTabSpanPosition(textNode.get(), pos); return firstPositionInNode(textNode.get()); } // Prepare for text input by looking at the specified position. // It may be necessary to insert a text node to receive characters. if (!pos.containerNode()->isTextNode()) { RefPtrWillBeRawPtr<Node> textNode = document().createEditingTextNode(""); insertNodeAt(textNode.get(), pos); return firstPositionInNode(textNode.get()); } return pos; }
VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) const { if (index <= 0) return VisiblePosition(firstPositionInNode(innerTextElement()), DOWNSTREAM); RefPtr<Range> range = Range::create(document()); range->selectNodeContents(innerTextElement(), ASSERT_NO_EXCEPTION); CharacterIterator it(range.get()); it.advance(index - 1); return VisiblePosition(it.range()->endPosition(), UPSTREAM); }
VisiblePosition RenderTextControl::visiblePositionForIndex(int index) const { if (index <= 0) return VisiblePosition(firstPositionInNode(innerTextElement()), DOWNSTREAM); ExceptionCode ec = 0; RefPtr<Range> range = Range::create(document()); range->selectNodeContents(innerTextElement(), ec); ASSERT(!ec); CharacterIterator it(range.get()); it.advance(index - 1); return VisiblePosition(it.range()->endPosition(), UPSTREAM); }
VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) const { if (index <= 0) return VisiblePosition(firstPositionInNode(innerEditorElement()), DOWNSTREAM); Position start, end; bool selected = Range::selectNodeContents(innerEditorElement(), start, end); if (!selected) return VisiblePosition(); CharacterIterator it(start, end); it.advance(index - 1); return VisiblePosition(it.endPosition(), UPSTREAM); }
PassRefPtr<Range> Editor::rangeOfString(const String& target, Range* referenceRange, FindOptions options) { if (target.isEmpty()) return nullptr; // Start from an edge of the reference range. Which edge is used depends on whether we're searching forward or // backward, and whether startInSelection is set. Position searchStart = firstPositionInNode(m_frame.document()); Position searchEnd = lastPositionInNode(m_frame.document()); bool forward = !(options & Backwards); bool startInReferenceRange = referenceRange && (options & StartInSelection); if (referenceRange) { if (forward) searchStart = startInReferenceRange ? referenceRange->startPosition() : referenceRange->endPosition(); else searchEnd = startInReferenceRange ? referenceRange->endPosition() : referenceRange->startPosition(); } RefPtr<Range> resultRange = findStringBetweenPositions(target, searchStart, searchEnd, options); // If we started in the reference range and the found range exactly matches the reference range, find again. // Build a selection with the found range to remove collapsed whitespace. // Compare ranges instead of selection objects to ignore the way that the current selection was made. if (resultRange && startInReferenceRange && areRangesEqual(VisibleSelection(resultRange.get()).toNormalizedRange().get(), referenceRange)) { if (forward) searchStart = resultRange->endPosition(); else searchEnd = resultRange->startPosition(); resultRange = findStringBetweenPositions(target, searchStart, searchEnd, options); } if (!resultRange && options & WrapAround) { searchStart = firstPositionInNode(m_frame.document()); searchEnd = lastPositionInNode(m_frame.document()); resultRange = findStringBetweenPositions(target, searchStart, searchEnd, options); } return resultRange.release(); }
SurroundingText::SurroundingText(const Position& position, unsigned maxLength) : m_positionOffsetInContent(0) { const unsigned halfMaxLength = maxLength / 2; Document* document = position.document(); // The |position| will have no document if it is null (as in no position). if (!document) return; // The forward range starts at the selection end and ends at the document's // end. It will then be updated to only contain the text in the text in the // right range around the selection. RefPtrWillBeRawPtr<Range> forwardRange = Range::create(*document, position, lastPositionInNode(document->documentElement()).parentAnchoredEquivalent()); CharacterIterator forwardIterator(forwardRange.get(), TextIteratorStopsOnFormControls); if (!forwardIterator.atEnd()) forwardIterator.advance(maxLength - halfMaxLength); forwardRange = forwardIterator.range(); if (!forwardRange || !Range::create(*document, position, forwardRange->startPosition())->text().length()) { ASSERT(forwardRange); return; } // Same as with the forward range but with the backward range. The range // starts at the document's start and ends at the selection start and will // be updated. RefPtrWillBeRawPtr<Range> backwardsRange = Range::create(*document, firstPositionInNode(document->documentElement()).parentAnchoredEquivalent(), position); BackwardsCharacterIterator backwardsIterator(backwardsRange.get(), TextIteratorStopsOnFormControls); if (!backwardsIterator.atEnd()) backwardsIterator.advance(halfMaxLength); backwardsRange = backwardsIterator.range(); if (!backwardsRange) { ASSERT(backwardsRange); return; } m_positionOffsetInContent = Range::create(*document, backwardsRange->endPosition(), position)->text().length(); m_contentRange = Range::create(*document, backwardsRange->endPosition(), forwardRange->startPosition()); ASSERT(m_contentRange); }
void VisibleSelection::adjustSelectionToAvoidCrossingShadowBoundaries() { if (m_base.isNull() || m_start.isNull() || m_end.isNull()) return; Node* startRootNode = m_start.anchorNode()->shadowTreeRootNode(); Node* endRootNode = m_end.anchorNode()->shadowTreeRootNode(); if (!startRootNode && !endRootNode) return; if (startRootNode == endRootNode) return; if (m_baseIsFirst) { m_extent = startRootNode ? lastPositionInNode(startRootNode) : positionBeforeNode(endRootNode->shadowHost()); m_end = m_extent; } else { m_extent = endRootNode ? firstPositionInNode(endRootNode) : positionAfterNode(startRootNode->shadowHost()); m_start = m_extent; } }
VisibleSelection VisibleSelection::selectionFromContentsOfNode(Node* node) { ASSERT(!editingIgnoresContent(node)); return VisibleSelection(firstPositionInNode(node), lastPositionInNode(node), DOWNSTREAM); }
void InsertParagraphSeparatorCommand::doApply() { if (!endingSelection().isNonOrphanedCaretOrRange()) return; Position insertionPosition = endingSelection().start(); EAffinity affinity = endingSelection().affinity(); // Delete the current selection. if (endingSelection().isRange()) { calculateStyleBeforeInsertion(insertionPosition); deleteSelection(false, true); insertionPosition = endingSelection().start(); affinity = endingSelection().affinity(); } // FIXME: The parentAnchoredEquivalent conversion needs to be moved into enclosingBlock. RefPtr<Element> startBlock = enclosingBlock(insertionPosition.parentAnchoredEquivalent().containerNode()); Position canonicalPos = VisiblePosition(insertionPosition).deepEquivalent(); if (!startBlock || !startBlock->nonShadowBoundaryParentNode() // FIXME: If the node is hidden, we don't have a canonical position so we will do the wrong thing for tables and <hr>. https://bugs.webkit.org/show_bug.cgi?id=40342 || (!canonicalPos.isNull() && isRenderedTableElement(canonicalPos.deprecatedNode()))) { applyCommandToComposite(InsertLineBreakCommand::create(document())); return; } // Use the leftmost candidate. insertionPosition = insertionPosition.upstream(); if (!insertionPosition.isCandidate()) insertionPosition = insertionPosition.downstream(); // Adjust the insertion position after the delete insertionPosition = positionAvoidingSpecialElementBoundary(insertionPosition); VisiblePosition visiblePos(insertionPosition, affinity); calculateStyleBeforeInsertion(insertionPosition); //--------------------------------------------------------------------- // Handle special case of typing return on an empty list item if (breakOutOfEmptyListItem()) return; //--------------------------------------------------------------------- // Prepare for more general cases. bool isFirstInBlock = isStartOfBlock(visiblePos); bool isLastInBlock = isEndOfBlock(visiblePos); bool nestNewBlock = false; // Create block to be inserted. RefPtr<Element> blockToInsert = nullptr; if (startBlock->isRootEditableElement()) { blockToInsert = createDefaultParagraphElement(document()); nestNewBlock = true; } else if (shouldUseDefaultParagraphElement(startBlock.get())) { blockToInsert = createDefaultParagraphElement(document()); } else { blockToInsert = startBlock->cloneElementWithoutChildren(); } //--------------------------------------------------------------------- // Handle case when position is in the last visible position in its block, // including when the block is empty. if (isLastInBlock) { if (nestNewBlock) { if (isFirstInBlock && !lineBreakExistsAtVisiblePosition(visiblePos)) { // The block is empty. Create an empty block to // represent the paragraph that we're leaving. RefPtr<HTMLElement> extraBlock = createDefaultParagraphElement(document()); appendNode(extraBlock, startBlock); } appendNode(blockToInsert, startBlock); } else { // Most of the time we want to stay at the nesting level of the startBlock (e.g., when nesting within lists). However, // for div nodes, this can result in nested div tags that are hard to break out of. Element* siblingElement = startBlock.get(); insertNodeAfter(blockToInsert, siblingElement); } // Recreate the same structure in the new paragraph. Vector<RefPtr<Element> > ancestors; getAncestorsInsideBlock(positionOutsideTabSpan(insertionPosition).deprecatedNode(), startBlock.get(), ancestors); RefPtr<Element> parent = cloneHierarchyUnderNewBlock(ancestors, blockToInsert); setEndingSelection(VisibleSelection(firstPositionInNode(parent.get()), DOWNSTREAM, endingSelection().isDirectional())); return; } //--------------------------------------------------------------------- // Handle case when position is in the first visible position in its block, and // similar case where previous position is in another, presumeably nested, block. if (isFirstInBlock || !inSameBlock(visiblePos, visiblePos.previous())) { Node* refNode = 0; insertionPosition = positionOutsideTabSpan(insertionPosition); if (isFirstInBlock && !nestNewBlock) { refNode = startBlock.get(); } else if (isFirstInBlock && nestNewBlock) { // startBlock should always have children, otherwise isLastInBlock would be true and it's handled above. ASSERT(startBlock->hasChildren()); refNode = startBlock->firstChild(); } else if (insertionPosition.deprecatedNode() == startBlock && nestNewBlock) { refNode = NodeTraversal::childAt(*startBlock, insertionPosition.deprecatedEditingOffset()); ASSERT(refNode); // must be true or we'd be in the end of block case } else refNode = insertionPosition.deprecatedNode(); // find ending selection position easily before inserting the paragraph insertionPosition = insertionPosition.downstream(); if (refNode) insertNodeBefore(blockToInsert, refNode); // Recreate the same structure in the new paragraph. Vector<RefPtr<Element> > ancestors; getAncestorsInsideBlock(positionAvoidingSpecialElementBoundary(positionOutsideTabSpan(insertionPosition)).deprecatedNode(), startBlock.get(), ancestors); // In this case, we need to set the new ending selection. setEndingSelection(VisibleSelection(insertionPosition, DOWNSTREAM, endingSelection().isDirectional())); return; } //--------------------------------------------------------------------- // Handle the (more complicated) general case, // Move downstream. Typing style code will take care of carrying along the // style of the upstream position. insertionPosition = insertionPosition.downstream(); // At this point, the insertionPosition's node could be a container, and we want to make sure we include // all of the correct nodes when building the ancestor list. So this needs to be the deepest representation of the position // before we walk the DOM tree. insertionPosition = positionOutsideTabSpan(VisiblePosition(insertionPosition).deepEquivalent()); // If the returned position lies either at the end or at the start of an element that is ignored by editing // we should move to its upstream or downstream position. if (editingIgnoresContent(insertionPosition.deprecatedNode())) { if (insertionPosition.atLastEditingPositionForNode()) insertionPosition = insertionPosition.downstream(); else if (insertionPosition.atFirstEditingPositionForNode()) insertionPosition = insertionPosition.upstream(); } // Make sure we do not cause a rendered space to become unrendered. // FIXME: We need the affinity for pos, but pos.downstream() does not give it Position leadingWhitespace = leadingWhitespacePosition(insertionPosition, VP_DEFAULT_AFFINITY); // FIXME: leadingWhitespacePosition is returning the position before preserved newlines for positions // after the preserved newline, causing the newline to be turned into a nbsp. if (leadingWhitespace.isNotNull() && leadingWhitespace.deprecatedNode()->isTextNode()) { Text* textNode = toText(leadingWhitespace.deprecatedNode()); ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace()); replaceTextInNodePreservingMarkers(textNode, leadingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString()); } // Split at pos if in the middle of a text node. Position positionAfterSplit; if (insertionPosition.anchorType() == Position::PositionIsOffsetInAnchor && insertionPosition.containerNode()->isTextNode()) { RefPtr<Text> textNode = toText(insertionPosition.containerNode()); bool atEnd = static_cast<unsigned>(insertionPosition.offsetInContainerNode()) >= textNode->length(); if (insertionPosition.deprecatedEditingOffset() > 0 && !atEnd) { splitTextNode(textNode, insertionPosition.offsetInContainerNode()); positionAfterSplit = firstPositionInNode(textNode.get()); insertionPosition.moveToPosition(textNode->previousSibling(), insertionPosition.offsetInContainerNode()); visiblePos = VisiblePosition(insertionPosition); } } // If we got detached due to mutation events, just bail out. if (!startBlock->parentNode()) return; // Put the added block in the tree. if (nestNewBlock) { appendNode(blockToInsert.get(), startBlock); } else { insertNodeAfter(blockToInsert.get(), startBlock); } document().updateLayoutIgnorePendingStylesheets(); // Move the start node and the siblings of the start node. if (VisiblePosition(insertionPosition) != VisiblePosition(positionBeforeNode(blockToInsert.get()))) { Node* n; if (insertionPosition.containerNode() == startBlock) n = insertionPosition.computeNodeAfterPosition(); else { Node* splitTo = insertionPosition.containerNode(); if (splitTo->isTextNode() && insertionPosition.offsetInContainerNode() >= caretMaxOffset(splitTo)) splitTo = NodeTraversal::next(*splitTo, startBlock.get()); ASSERT(splitTo); splitTreeToNode(splitTo, startBlock.get()); for (n = startBlock->firstChild(); n; n = n->nextSibling()) { VisiblePosition beforeNodePosition(positionBeforeNode(n)); if (!beforeNodePosition.isNull() && comparePositions(VisiblePosition(insertionPosition), beforeNodePosition) <= 0) break; } } moveRemainingSiblingsToNewParent(n, blockToInsert.get(), blockToInsert); } // Handle whitespace that occurs after the split if (positionAfterSplit.isNotNull()) { document().updateLayoutIgnorePendingStylesheets(); if (!positionAfterSplit.isRenderedCharacter()) { // Clear out all whitespace and insert one non-breaking space ASSERT(!positionAfterSplit.containerNode()->renderer() || positionAfterSplit.containerNode()->renderer()->style()->collapseWhiteSpace()); deleteInsignificantTextDownstream(positionAfterSplit); if (positionAfterSplit.deprecatedNode()->isTextNode()) insertTextIntoNode(toText(positionAfterSplit.containerNode()), 0, nonBreakingSpaceString()); } } setEndingSelection(VisibleSelection(firstPositionInNode(blockToInsert.get()), DOWNSTREAM, endingSelection().isDirectional())); }
void TextFinder::scopeStringMatches(int identifier, const WebString& searchText, const WebFindOptions& options, bool reset) { if (reset) { // This is a brand new search, so we need to reset everything. // Scoping is just about to begin. m_scopingInProgress = true; // Need to keep the current identifier locally in order to finish the // request in case the frame is detached during the process. m_findRequestIdentifier = identifier; // Clear highlighting for this frame. LocalFrame* frame = m_ownerFrame.frame(); if (frame && frame->page() && frame->editor().markedTextMatchesAreHighlighted()) frame->page()->unmarkAllTextMatches(); // Clear the tickmarks and results cache. clearFindMatchesCache(); // Clear the counters from last operation. m_lastMatchCount = 0; m_nextInvalidateAfter = 0; m_resumeScopingFromRange = nullptr; // The view might be null on detached frames. if (frame && frame->page()) m_ownerFrame.viewImpl()->mainFrameImpl()->ensureTextFinder().m_framesScopingCount++; // Now, defer scoping until later to allow find operation to finish quickly. scopeStringMatchesSoon(identifier, searchText, options, false); // false means just reset, so don't do it again. return; } if (!shouldScopeMatches(searchText)) { // Note that we want to defer the final update when resetting even if shouldScopeMatches returns false. // This is done in order to prevent sending a final message based only on the results of the first frame // since m_framesScopingCount would be 0 as other frames have yet to reset. finishCurrentScopingEffort(identifier); return; } WebLocalFrameImpl* mainFrameImpl = m_ownerFrame.viewImpl()->mainFrameImpl(); Position searchStart = firstPositionInNode(m_ownerFrame.frame()->document()); Position searchEnd = lastPositionInNode(m_ownerFrame.frame()->document()); ASSERT(searchStart.document() == searchEnd.document()); if (m_resumeScopingFromRange) { // This is a continuation of a scoping operation that timed out and didn't // complete last time around, so we should start from where we left off. ASSERT(m_resumeScopingFromRange->collapsed()); searchStart = m_resumeScopingFromRange->startPosition().next(); if (searchStart.document() != searchEnd.document()) return; } // This timeout controls how long we scope before releasing control. This // value does not prevent us from running for longer than this, but it is // periodically checked to see if we have exceeded our allocated time. const double maxScopingDuration = 0.1; // seconds int matchCount = 0; bool timedOut = false; double startTime = currentTime(); do { // Find next occurrence of the search string. // FIXME: (http://crbug.com/6818) This WebKit operation may run for longer // than the timeout value, and is not interruptible as it is currently // written. We may need to rewrite it with interruptibility in mind, or // find an alternative. Position resultStart; Position resultEnd; findPlainText(searchStart, searchEnd, searchText, options.matchCase ? 0 : CaseInsensitive, resultStart, resultEnd); if (resultStart == resultEnd) { // Not found. break; } RefPtrWillBeRawPtr<Range> resultRange = Range::create(*resultStart.document(), resultStart, resultEnd); if (resultRange->collapsed()) { // resultRange will be collapsed if the matched text spans over multiple TreeScopes. // FIXME: Show such matches to users. searchStart = resultStart.next(); continue; } ++matchCount; // Catch a special case where Find found something but doesn't know what // the bounding box for it is. In this case we set the first match we find // as the active rect. IntRect resultBounds = resultRange->boundingBox(); IntRect activeSelectionRect; if (m_locatingActiveRect) { activeSelectionRect = m_activeMatch.get() ? m_activeMatch->boundingBox() : resultBounds; } // If the Find function found a match it will have stored where the // match was found in m_activeSelectionRect on the current frame. If we // find this rect during scoping it means we have found the active // tickmark. bool foundActiveMatch = false; if (m_locatingActiveRect && (activeSelectionRect == resultBounds)) { // We have found the active tickmark frame. mainFrameImpl->ensureTextFinder().m_currentActiveMatchFrame = &m_ownerFrame; foundActiveMatch = true; // We also know which tickmark is active now. m_activeMatchIndexInCurrentFrame = matchCount - 1; // To stop looking for the active tickmark, we set this flag. m_locatingActiveRect = false; // Notify browser of new location for the selected rectangle. reportFindInPageSelection( m_ownerFrame.frameView()->contentsToWindow(resultBounds), m_activeMatchIndexInCurrentFrame + 1, identifier); } addMarker(resultRange.get(), foundActiveMatch); m_findMatchesCache.append(FindMatch(resultRange.get(), m_lastMatchCount + matchCount)); // Set the new start for the search range to be the end of the previous // result range. There is no need to use a VisiblePosition here, // since findPlainText will use a TextIterator to go over the visible // text nodes. searchStart = resultStart.next(); m_resumeScopingFromRange = Range::create(*resultStart.document(), resultStart, resultStart); timedOut = (currentTime() - startTime) >= maxScopingDuration; } while (!timedOut); // Remember what we search for last time, so we can skip searching if more // letters are added to the search string (and last outcome was 0). m_lastSearchString = searchText; if (matchCount > 0) { m_ownerFrame.frame()->editor().setMarkedTextMatchesAreHighlighted(true); m_lastMatchCount += matchCount; // Let the mainframe know how much we found during this pass. mainFrameImpl->increaseMatchCount(matchCount, identifier); } if (timedOut) { // If we found anything during this pass, we should redraw. However, we // don't want to spam too much if the page is extremely long, so if we // reach a certain point we start throttling the redraw requests. if (matchCount > 0) invalidateIfNecessary(); // Scoping effort ran out of time, lets ask for another time-slice. scopeStringMatchesSoon( identifier, searchText, options, false); // don't reset. return; // Done for now, resume work later. } finishCurrentScopingEffort(identifier); }
static HTMLElement* highestAncestorToWrapMarkup(const Range* range, EAnnotateForInterchange shouldAnnotate, Node* constrainingAncestor) { Node* commonAncestor = range->commonAncestorContainer(); ASSERT(commonAncestor); HTMLElement* specialCommonAncestor = 0; Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : commonAncestor; if (checkAncestor->renderer()) { HTMLElement* newSpecialCommonAncestor = toHTMLElement(highestEnclosingNodeOfType(firstPositionInNode(checkAncestor), &isPresentationalHTMLElement, CanCrossEditingBoundary, constrainingAncestor)); if (newSpecialCommonAncestor) specialCommonAncestor = newSpecialCommonAncestor; } if (HTMLAnchorElement* enclosingAnchor = toHTMLAnchorElement(enclosingElementWithTag(firstPositionInNode(specialCommonAncestor ? specialCommonAncestor : commonAncestor), HTMLNames::aTag))) specialCommonAncestor = enclosingAnchor; return specialCommonAncestor; }