void InsertTextCommand::setEndingSelectionWithoutValidation(const Position& startPosition, const Position& endPosition)
{
    // We could have inserted a part of composed character sequence,
    // so we are basically treating ending selection as a range to avoid validation.
    // <http://bugs.webkit.org/show_bug.cgi?id=15781>
    VisibleSelection forcedEndingSelection;
    forcedEndingSelection.setWithoutValidation(startPosition, endPosition);
    forcedEndingSelection.setIsDirectional(endingSelection().isDirectional());
    setEndingSelection(forcedEndingSelection);
}
Exemple #2
0
void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction, NeedToDispatchSelectEvent eventBehaviour, SelectionOption selectionOption)
{
    if (openShadowRoot() || !isTextFormControl())
        return;
    const int editorValueLength = static_cast<int>(innerEditorValue().length());
    ASSERT(editorValueLength >= 0);
    end = std::max(std::min(end, editorValueLength), 0);
    start = std::min(std::max(start, 0), end);
    cacheSelection(start, end, direction);

    if (selectionOption == NotChangeSelection || (selectionOption == ChangeSelectionIfFocused && document().focusedElement() != this) || !inShadowIncludingDocument()) {
        if (eventBehaviour == DispatchSelectEvent)
            scheduleSelectEvent();
        return;
    }

    LocalFrame* frame = document().frame();
    HTMLElement* innerEditor = innerEditorElement();
    if (!frame || !innerEditor)
        return;

    Position startPosition = positionForIndex(innerEditor, start);
    Position endPosition = start == end ? startPosition : positionForIndex(innerEditor, end);

    ASSERT(start == indexForPosition(innerEditor, startPosition));
    ASSERT(end == indexForPosition(innerEditor, endPosition));

#if ENABLE(ASSERT)
    // startPosition and endPosition can be null position for example when
    // "-webkit-user-select: none" style attribute is specified.
    if (startPosition.isNotNull() && endPosition.isNotNull()) {
        ASSERT(startPosition.anchorNode()->shadowHost() == this
            && endPosition.anchorNode()->shadowHost() == this);
    }
#endif // ENABLE(ASSERT)
    VisibleSelection newSelection;
    if (direction == SelectionHasBackwardDirection)
        newSelection.setWithoutValidation(endPosition, startPosition);
    else
        newSelection.setWithoutValidation(startPosition, endPosition);
    newSelection.setIsDirectional(direction != SelectionHasNoDirection);

    frame->selection().setSelection(newSelection, FrameSelection::DoNotAdjustInFlatTree | FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | (selectionOption == ChangeSelectionAndFocus ? 0 : FrameSelection::DoNotSetFocus));
    if (eventBehaviour == DispatchSelectEvent)
        scheduleSelectEvent();
}
void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction)
{
    document().updateLayoutIgnorePendingStylesheets();

    if (!renderer() || !renderer()->isTextControl())
        return;

    end = std::max(end, 0);
    start = std::min(std::max(start, 0), end);

    if (!hasVisibleTextArea(*renderer(), innerTextElement())) {
        cacheSelection(start, end, direction);
        return;
    }
    VisiblePosition startPosition = visiblePositionForIndex(start);
    VisiblePosition endPosition;
    if (start == end)
        endPosition = startPosition;
    else
        endPosition = visiblePositionForIndex(end);

#if !PLATFORM(IOS)
    // startPosition and endPosition can be null position for example when
    // "-webkit-user-select: none" style attribute is specified.
    if (startPosition.isNotNull() && endPosition.isNotNull()) {
        ASSERT(startPosition.deepEquivalent().deprecatedNode()->shadowHost() == this
            && endPosition.deepEquivalent().deprecatedNode()->shadowHost() == this);
    }
#endif
    VisibleSelection newSelection;
    if (direction == SelectionHasBackwardDirection)
        newSelection = VisibleSelection(endPosition, startPosition);
    else
        newSelection = VisibleSelection(startPosition, endPosition);
    newSelection.setIsDirectional(direction != SelectionHasNoDirection);

    if (Frame* frame = document().frame())
        frame->selection().setSelection(newSelection);
}
Exemple #4
0
void InsertTextCommand::doApply()
{
    ASSERT(m_text.find('\n') == notFound);

    if (!endingSelection().isNonOrphanedCaretOrRange())
        return;

    // Delete the current selection.
    // FIXME: This delete operation blows away the typing style.
    if (endingSelection().isRange()) {
        if (performTrivialReplace(m_text, m_selectInsertedText))
            return;
        deleteSelection(false, true, true, false, false);
        // deleteSelection eventually makes a new endingSelection out of a Position. If that Position doesn't have
        // a renderer (e.g. it is on a <frameset> in the DOM), the VisibleSelection cannot be canonicalized to 
        // anything other than NoSelection. The rest of this function requires a real endingSelection, so bail out.
        if (endingSelection().isNone())
            return;
    }

    Position startPosition(endingSelection().start());
    
    Position placeholder;
    // We want to remove preserved newlines and brs that will collapse (and thus become unnecessary) when content 
    // is inserted just before them.
    // FIXME: We shouldn't really have to do this, but removing placeholders is a workaround for 9661.
    // If the caret is just before a placeholder, downstream will normalize the caret to it.
    Position downstream(startPosition.downstream());
    if (lineBreakExistsAtPosition(downstream)) {
        // FIXME: This doesn't handle placeholders at the end of anonymous blocks.
        VisiblePosition caret(startPosition);
        if (isEndOfBlock(caret) && isStartOfParagraph(caret))
            placeholder = downstream;
        // Don't remove the placeholder yet, otherwise the block we're inserting into would collapse before
        // we get a chance to insert into it.  We check for a placeholder now, though, because doing so requires
        // the creation of a VisiblePosition, and if we did that post-insertion it would force a layout.
    }
    
    // Insert the character at the leftmost candidate.
    startPosition = startPosition.upstream();
    
    // It is possible for the node that contains startPosition to contain only unrendered whitespace,
    // and so deleteInsignificantText could remove it.  Save the position before the node in case that happens.
    Position positionBeforeStartNode(positionInParentBeforeNode(startPosition.containerNode()));
    deleteInsignificantText(startPosition.upstream(), startPosition.downstream());
    if (!startPosition.anchorNode()->inDocument())
        startPosition = positionBeforeStartNode;
    if (!startPosition.isCandidate())
        startPosition = startPosition.downstream();
    
    startPosition = positionAvoidingSpecialElementBoundary(startPosition);
    
    Position endPosition;
    
    if (m_text == "\t") {
        endPosition = insertTab(startPosition);
        startPosition = endPosition.previous();
        if (placeholder.isNotNull())
            removePlaceholderAt(placeholder);
    } else {
        // Make sure the document is set up to receive m_text
        startPosition = positionInsideTextNode(startPosition);
        ASSERT(startPosition.anchorType() == Position::PositionIsOffsetInAnchor);
        ASSERT(startPosition.containerNode());
        ASSERT(startPosition.containerNode()->isTextNode());
        if (placeholder.isNotNull())
            removePlaceholderAt(placeholder);
        RefPtr<Text> textNode = startPosition.containerText();
        const unsigned offset = startPosition.offsetInContainerNode();

        insertTextIntoNode(textNode, offset, m_text);
        endPosition = Position(textNode, offset + m_text.length());
        if (m_markerSupplier)
            m_markerSupplier->addMarkersToTextNode(textNode.get(), offset, m_text);

        if (m_rebalanceType == RebalanceLeadingAndTrailingWhitespaces) {
            // The insertion may require adjusting adjacent whitespace, if it is present.
            rebalanceWhitespaceAt(endPosition);
            // Rebalancing on both sides isn't necessary if we've inserted only spaces.
            if (!shouldRebalanceLeadingWhitespaceFor(m_text))
                rebalanceWhitespaceAt(startPosition);
        } else {
            ASSERT(m_rebalanceType == RebalanceAllWhitespaces);
            if (canRebalance(startPosition) && canRebalance(endPosition))
                rebalanceWhitespaceOnTextSubstring(textNode, startPosition.offsetInContainerNode(), endPosition.offsetInContainerNode());
        }
    }

    // We could have inserted a part of composed character sequence,
    // so we are basically treating ending selection as a range to avoid validation.
    // <http://bugs.webkit.org/show_bug.cgi?id=15781>
    VisibleSelection forcedEndingSelection;
    forcedEndingSelection.setWithoutValidation(startPosition, endPosition);
    forcedEndingSelection.setIsDirectional(endingSelection().isDirectional());
    setEndingSelection(forcedEndingSelection);

    // Handle the case where there is a typing style.
    if (RefPtr<EditingStyle> typingStyle = document()->frame()->selection()->typingStyle()) {
        typingStyle->prepareToApplyAt(endPosition, EditingStyle::PreserveWritingDirection);
        if (!typingStyle->isEmpty())
            applyStyle(typingStyle.get());
    }

    if (!m_selectInsertedText)
        setEndingSelection(VisibleSelection(endingSelection().end(), endingSelection().affinity(), endingSelection().isDirectional()));
}