Ejemplo n.º 1
0
static Position previousIfPositionIsAfterLineBreak(const Position& position, HTMLElement* innerEditor)
{
    if (position.isNull())
        return Position();

    // Move back if position is just after line break.
    if (isHTMLBRElement(*position.anchorNode())) {
        if (position.isAfterAnchor())
            return Position(position.anchorNode(), PositionAnchorType::BeforeAnchor);
        if (position.isBeforeAnchor())
            return previousIfPositionIsAfterLineBreak(endOfPrevious(*position.anchorNode(), innerEditor), innerEditor);
        // We don't place caret into BR element, since well-formed BR element
        // doesn't have child nodes.
        ASSERT_NOT_REACHED();
        return position;
    }

    if (!position.anchorNode()->isTextNode())
        return position;

    Text* textNode = toText(position.anchorNode());
    unsigned offset = position.offsetInContainerNode();
    if (textNode->length() == 0 || offset == 0)
        return previousIfPositionIsAfterLineBreak(endOfPrevious(*position.anchorNode(), innerEditor), innerEditor);

    if (offset <= textNode->length() && textNode->data()[offset - 1] == '\n')
        return Position(textNode, offset - 1);

    return position;
}
Ejemplo n.º 2
0
void HTMLTextAreaElement::subtreeHasChanged() {
#if DCHECK_IS_ON()
  // The innerEditor should have either Text nodes or a placeholder break
  // element. If we see other nodes, it's a bug in editing code and we should
  // fix it.
  Element* innerEditor = innerEditorElement();
  for (Node& node : NodeTraversal::descendantsOf(*innerEditor)) {
    if (node.isTextNode())
      continue;
    DCHECK(isHTMLBRElement(node));
    DCHECK_EQ(&node, innerEditor->lastChild());
  }
#endif
  addPlaceholderBreakElementIfNecessary();
  setChangedSinceLastFormControlChangeEvent(true);
  m_valueIsUpToDate = false;
  setNeedsValidityCheck();
  setAutofilled(false);
  updatePlaceholderVisibility();

  if (!isFocused())
    return;

  // When typing in a textarea, childrenChanged is not called, so we need to
  // force the directionality check.
  calculateAndAdjustDirectionality();

  DCHECK(document().isActive());
  document().frameHost()->chromeClient().didChangeValueInTextField(*this);
}
Ejemplo n.º 3
0
Position HTMLTextFormControlElement::startOfSentence(const Position& position)
{
    HTMLTextFormControlElement* textFormControl = enclosingTextFormControl(position);
    ASSERT(textFormControl);

    HTMLElement* innerEditor = textFormControl->innerEditorElement();
    if (!innerEditor->childNodes()->length())
        return startOfInnerText(textFormControl);

    const Position innerPosition = position.anchorNode() == innerEditor ? innerNodePosition(position) : position;
    const Position pivotPosition = previousIfPositionIsAfterLineBreak(innerPosition, innerEditor);
    if (pivotPosition.isNull())
        return startOfInnerText(textFormControl);

    for (Node* node = pivotPosition.anchorNode(); node; node = NodeTraversal::previous(*node, innerEditor)) {
        bool isPivotNode = (node == pivotPosition.anchorNode());

        if (isHTMLBRElement(node) && (!isPivotNode || pivotPosition.isAfterAnchor()))
            return Position(node, PositionAnchorType::AfterAnchor);

        if (node->isTextNode()) {
            Text* textNode = toText(node);
            size_t lastLineBreak = textNode->data().substring(0, isPivotNode ? pivotPosition.offsetInContainerNode() : textNode->length()).reverseFind('\n');
            if (lastLineBreak != kNotFound)
                return Position(textNode, lastLineBreak + 1);
        }
    }
    return startOfInnerText(textFormControl);
}
Ejemplo n.º 4
0
void HTMLTextFormControlElement::setInnerEditorValue(const String& value)
{
    ASSERT(!openShadowRoot());
    if (!isTextFormControl() || openShadowRoot())
        return;

    bool textIsChanged = value != innerEditorValue();
    HTMLElement* innerEditor = innerEditorElement();
    if (!textIsChanged && innerEditor->hasChildren())
        return;

    // If the last child is a trailing <br> that's appended below, remove it
    // first so as to enable setInnerText() fast path of updating a text node.
    if (isHTMLBRElement(innerEditor->lastChild()))
        innerEditor->removeChild(innerEditor->lastChild(), ASSERT_NO_EXCEPTION);

    // We don't use setTextContent.  It triggers unnecessary paint.
    if (value.isEmpty())
        innerEditor->removeChildren();
    else
        replaceChildrenWithText(innerEditor, value, ASSERT_NO_EXCEPTION);

    // Add <br> so that we can put the caret at the next line of the last
    // newline.
    addPlaceholderBreakElementIfNecessary();

    if (textIsChanged && layoutObject()) {
        if (AXObjectCache* cache = document().existingAXObjectCache())
            cache->handleTextFormControlChanged(this);
    }
}
Ejemplo n.º 5
0
Position HTMLTextFormControlElement::endOfSentence(const Position& position)
{
    HTMLTextFormControlElement* textFormControl = enclosingTextFormControl(position);
    ASSERT(textFormControl);

    HTMLElement* innerEditor = textFormControl->innerEditorElement();
    if (innerEditor->childNodes()->length() == 0)
        return startOfInnerText(textFormControl);

    const Position pivotPosition = position.anchorNode() == innerEditor ? innerNodePosition(position) : position;
    if (pivotPosition.isNull())
        return startOfInnerText(textFormControl);

    for (Node* node = pivotPosition.anchorNode(); node; node = NodeTraversal::next(*node, innerEditor)) {
        bool isPivotNode = node == pivotPosition.anchorNode();

        if (isHTMLBRElement(node))
            return Position(node, PositionAnchorType::AfterAnchor);

        if (node->isTextNode()) {
            Text* textNode = toText(node);
            size_t firstLineBreak = textNode->data().find('\n', isPivotNode ? pivotPosition.offsetInContainerNode() : 0);
            if (firstLineBreak != kNotFound)
                return Position(textNode, firstLineBreak + 1);
        }
    }
    return endOfInnerText(textFormControl);
}
static Position previousIfPositionIsAfterLineBreak(const Position& position, HTMLElement* innerEditor)
{
    if (position.isNull())
        return Position();

    // Move back if position is just after line break.
    if (isHTMLBRElement(*position.anchorNode())) {
        switch (position.anchorType()) {
        case Position::PositionIsAfterAnchor:
            return Position(position.anchorNode(), Position::PositionIsBeforeAnchor);
        case Position::PositionIsBeforeAnchor:
            return previousIfPositionIsAfterLineBreak(endOfPrevious(*position.anchorNode(), innerEditor), innerEditor);
        default:
            ASSERT_NOT_REACHED();
        }
    } else if (position.anchorNode()->isTextNode()) {
        Text* textNode = toText(position.anchorNode());
        unsigned offset = position.offsetInContainerNode();
        if (textNode->length() == 0 || offset == 0) {
            return previousIfPositionIsAfterLineBreak(endOfPrevious(*position.anchorNode(), innerEditor), innerEditor);
        }

        if (offset <= textNode->length() && textNode->data()[offset - 1] == '\n') {
            return Position(textNode, offset - 1);
        }
    }

    return position;
}
Ejemplo n.º 7
0
static Position endOfPrevious(const Node& node, HTMLElement* innerEditor)
{
    Node* previousNode = NodeTraversal::previous(node, innerEditor);
    if (!previousNode)
        return Position();

    if (isHTMLBRElement(previousNode))
        return Position(previousNode, PositionAnchorType::AfterAnchor);

    if (previousNode->isTextNode())
        return Position(toText(previousNode), toText(previousNode)->length());

    return Position();
}
String HTMLTextFormControlElement::innerEditorValue() const
{
    ASSERT(!hasAuthorShadowRoot());
    HTMLElement* innerEditor = innerEditorElement();
    if (!innerEditor || !isTextFormControl())
        return emptyString();

    StringBuilder result;
    for (Node* node = innerEditor; node; node = NodeTraversal::next(*node, innerEditor)) {
        if (isHTMLBRElement(*node))
            result.append(newlineCharacter);
        else if (node->isTextNode())
            result.append(toText(node)->data());
    }
    return finishText(result);
}
String HTMLTextFormControlElement::innerEditorValue() const
{
    ASSERT(!hasOpenShadowRoot());
    HTMLElement* innerEditor = innerEditorElement();
    if (!innerEditor || !isTextFormControl())
        return emptyString();

    StringBuilder result;
    for (Node& node : NodeTraversal::inclusiveDescendantsOf(*innerEditor)) {
        if (isHTMLBRElement(node))
            result.append(newlineCharacter);
        else if (node.isTextNode())
            result.append(toText(node).data());
    }
    return finishText(result);
}
Ejemplo n.º 10
0
String HTMLTextFormControlElement::valueWithHardLineBreaks() const
{
    // FIXME: It's not acceptable to ignore the HardWrap setting when there is no layoutObject.
    // While we have no evidence this has ever been a practical problem, it would be best to fix it some day.
    HTMLElement* innerText = innerEditorElement();
    if (!innerText || !isTextFormControl())
        return value();

    LayoutBlockFlow* layoutObject = toLayoutBlockFlow(innerText->layoutObject());
    if (!layoutObject)
        return value();

    Node* breakNode;
    unsigned breakOffset;
    RootInlineBox* line = layoutObject->firstRootBox();
    if (!line)
        return value();

    getNextSoftBreak(line, breakNode, breakOffset);

    StringBuilder result;
    for (Node& node : NodeTraversal::descendantsOf(*innerText)) {
        if (isHTMLBRElement(node)) {
            ASSERT(&node == innerText->lastChild());
            if (&node != innerText->lastChild())
                result.append(newlineCharacter);
        } else if (node.isTextNode()) {
            String data = toText(node).data();
            unsigned length = data.length();
            unsigned position = 0;
            while (breakNode == node && breakOffset <= length) {
                if (breakOffset > position) {
                    result.append(data, position, breakOffset - position);
                    position = breakOffset;
                    result.append(newlineCharacter);
                }
                getNextSoftBreak(line, breakNode, breakOffset);
            }
            result.append(data, position, length - position);
        }
        while (breakNode == node)
            getNextSoftBreak(line, breakNode, breakOffset);
    }
    return result.toString();
}
String HTMLTextFormControlElement::valueWithHardLineBreaks() const
{
    // FIXME: It's not acceptable to ignore the HardWrap setting when there is no renderer.
    // While we have no evidence this has ever been a practical problem, it would be best to fix it some day.
    HTMLElement* innerText = innerEditorElement();
    if (!innerText || !isTextFormControl())
        return value();

    RenderBlock* renderer = toRenderBlock(innerText->renderer());
    if (!renderer)
        return value();

    Node* breakNode;
    unsigned breakOffset;
    RootInlineBox* line = renderer->firstRootBox();
    if (!line)
        return value();

    getNextSoftBreak(line, breakNode, breakOffset);

    StringBuilder result;
    for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(*node, innerText)) {
        if (isHTMLBRElement(*node))
            result.append(newlineCharacter);
        else if (node->isTextNode()) {
            String data = toText(node)->data();
            unsigned length = data.length();
            unsigned position = 0;
            while (breakNode == node && breakOffset <= length) {
                if (breakOffset > position) {
                    result.append(data, position, breakOffset - position);
                    position = breakOffset;
                    result.append(newlineCharacter);
                }
                getNextSoftBreak(line, breakNode, breakOffset);
            }
            result.append(data, position, length - position);
        }
        while (breakNode == node)
            getNextSoftBreak(line, breakNode, breakOffset);
    }
    return finishText(result);
}
PassRefPtrWillBeRawPtr<Range> HTMLTextFormControlElement::selection() const
{
    if (!renderer() || !isTextFormControl())
        return nullptr;

    int start = m_cachedSelectionStart;
    int end = m_cachedSelectionEnd;

    ASSERT(start <= end);
    HTMLElement* innerText = innerEditorElement();
    if (!innerText)
        return nullptr;

    if (!innerText->firstChild())
        return Range::create(document(), innerText, 0, innerText, 0);

    int offset = 0;
    Node* startNode = 0;
    Node* endNode = 0;
    for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(*node, innerText)) {
        ASSERT(!node->firstChild());
        ASSERT(node->isTextNode() || isHTMLBRElement(*node));
        int length = node->isTextNode() ? lastOffsetInNode(node) : 1;

        if (offset <= start && start <= offset + length)
            setContainerAndOffsetForRange(node, start - offset, startNode, start);

        if (offset <= end && end <= offset + length) {
            setContainerAndOffsetForRange(node, end - offset, endNode, end);
            break;
        }

        offset += length;
    }

    if (!startNode || !endNode)
        return nullptr;

    return Range::create(document(), startNode, start, endNode, end);
}
Ejemplo n.º 13
0
Range* HTMLTextFormControlElement::selection() const
{
    if (!layoutObject() || !isTextFormControl())
        return nullptr;

    int start = m_cachedSelectionStart;
    int end = m_cachedSelectionEnd;

    ASSERT(start <= end);
    HTMLElement* innerText = innerEditorElement();
    if (!innerText)
        return nullptr;

    if (!innerText->hasChildren())
        return Range::create(document(), innerText, 0, innerText, 0);

    int offset = 0;
    Node* startNode = 0;
    Node* endNode = 0;
    for (Node& node : NodeTraversal::descendantsOf(*innerText)) {
        ASSERT(!node.hasChildren());
        ASSERT(node.isTextNode() || isHTMLBRElement(node));
        int length = node.isTextNode() ? lastOffsetInNode(&node) : 1;

        if (offset <= start && start <= offset + length)
            setContainerAndOffsetForRange(&node, start - offset, startNode, start);

        if (offset <= end && end <= offset + length) {
            setContainerAndOffsetForRange(&node, end - offset, endNode, end);
            break;
        }

        offset += length;
    }

    if (!startNode || !endNode)
        return nullptr;

    return Range::create(document(), startNode, start, endNode, end);
}