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;
}
Пример #2
0
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());
}
Пример #3
0
// 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;
}