int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int startOffset, int endOffset, bool markAll) const { // Found some bad grammar. Find the earliest detail range that starts in our search range (if any). // Optionally add a DocumentMarker for each detail in the range. int earliestDetailLocationSoFar = -1; int earliestDetailIndex = -1; for (unsigned i = 0; i < grammarDetails.size(); i++) { const GrammarDetail* detail = &grammarDetails[i]; ASSERT(detail->length > 0 && detail->location >= 0); int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location; // Skip this detail if it starts before the original search range if (detailStartOffsetInParagraph < startOffset) continue; // Skip this detail if it starts after the original search range if (detailStartOffsetInParagraph >= endOffset) continue; if (markAll) { const EphemeralRange badGrammarRange = calculateCharacterSubrange(EphemeralRange(m_start, m_end), badGrammarPhraseLocation - startOffset + detail->location, detail->length); badGrammarRange.document().markers().addMarker(badGrammarRange.startPosition(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail->userDescription); } // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order) if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->location) { earliestDetailIndex = i; earliestDetailLocationSoFar = detail->location; } } return earliestDetailIndex; }
void InputMethodController::setCompositionFromExistingText(const Vector<CompositionUnderline>& underlines, unsigned compositionStart, unsigned compositionEnd) { Element* editable = frame().selection().rootEditableElement(); if (!editable) return; const EphemeralRange range = PlainTextRange(compositionStart, compositionEnd).createRange(*editable); if (range.isNull()) return; const Position start = range.startPosition(); if (editableRootForPosition(start) != editable) return; const Position end = range.endPosition(); if (editableRootForPosition(end) != editable) return; clear(); for (const auto& underline : underlines) { unsigned underlineStart = compositionStart + underline.startOffset; unsigned underlineEnd = compositionStart + underline.endOffset; EphemeralRange ephemeralLineRange = PlainTextRange(underlineStart, underlineEnd).createRange(*editable); if (ephemeralLineRange.isNull()) continue; frame().document()->markers().addCompositionMarker(ephemeralLineRange.startPosition(), ephemeralLineRange.endPosition(), underline.color, underline.thick, underline.backgroundColor); } m_hasComposition = true; if (!m_compositionRange) m_compositionRange = Range::create(range.document()); m_compositionRange->setStart(range.startPosition()); m_compositionRange->setEnd(range.endPosition()); }
// static WebRange WebRange::fromDocumentRange(WebLocalFrame* frame, int start, int length) { LocalFrame* webFrame = toWebLocalFrameImpl(frame)->frame(); Element* selectionRoot = webFrame->selection().rootEditableElement(); ContainerNode* scope = selectionRoot ? selectionRoot : webFrame->document()->documentElement(); const EphemeralRange range = PlainTextRange(start, start + length).createRange(*scope); if (range.isNull()) return WebRange(); return Range::create(range.document(), range.startPosition(), range.endPosition()); }
String TextCheckingHelper::findFirstMisspelling(int& firstMisspellingOffset, bool markAll) { WordAwareIterator it(m_start, m_end); firstMisspellingOffset = 0; String firstMisspelling; int currentChunkOffset = 0; while (!it.atEnd()) { int length = it.length(); // Skip some work for one-space-char hunks if (!(length == 1 && it.characterAt(0) == ' ')) { int misspellingLocation = -1; int misspellingLength = 0; m_client->textChecker().checkSpellingOfString(it.substring(0, length), &misspellingLocation, &misspellingLength); // 5490627 shows that there was some code path here where the String constructor below crashes. // We don't know exactly what combination of bad input caused this, so we're making this much // more robust against bad input on release builds. ASSERT(misspellingLength >= 0); ASSERT(misspellingLocation >= -1); ASSERT(!misspellingLength || misspellingLocation >= 0); ASSERT(misspellingLocation < length); ASSERT(misspellingLength <= length); ASSERT(misspellingLocation + misspellingLength <= length); if (misspellingLocation >= 0 && misspellingLength > 0 && misspellingLocation < length && misspellingLength <= length && misspellingLocation + misspellingLength <= length) { // Compute range of misspelled word const EphemeralRange misspellingRange = calculateCharacterSubrange(EphemeralRange(m_start, m_end), currentChunkOffset + misspellingLocation, misspellingLength); // Remember first-encountered misspelling and its offset. if (!firstMisspelling) { firstMisspellingOffset = currentChunkOffset + misspellingLocation; firstMisspelling = it.substring(misspellingLocation, misspellingLength); } // Store marker for misspelled word. misspellingRange.document().markers().addMarker(misspellingRange.startPosition(), misspellingRange.endPosition(), DocumentMarker::Spelling); // Bail out if we're marking only the first misspelling, and not all instances. if (!markAll) break; } } currentChunkOffset += length; it.advance(); } return firstMisspelling; }