1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 *           (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
6 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB.  If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#include "config.h"
26#include "HTMLTextFormControlElement.h"
27
28#include "AXObjectCache.h"
29#include "Attribute.h"
30#include "ChromeClient.h"
31#include "Document.h"
32#include "Event.h"
33#include "EventNames.h"
34#include "Frame.h"
35#include "FrameSelection.h"
36#include "HTMLBRElement.h"
37#include "HTMLFormElement.h"
38#include "HTMLInputElement.h"
39#include "HTMLNames.h"
40#include "NodeTraversal.h"
41#include "RenderBlockFlow.h"
42#include "RenderTextControlSingleLine.h"
43#include "RenderTheme.h"
44#include "ShadowRoot.h"
45#include "Text.h"
46#include "TextControlInnerElements.h"
47#include "htmlediting.h"
48#include <wtf/text/StringBuilder.h>
49
50namespace WebCore {
51
52using namespace HTMLNames;
53
54static Position positionForIndex(TextControlInnerTextElement*, unsigned);
55
56HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
57    : HTMLFormControlElementWithState(tagName, document, form)
58    , m_lastChangeWasUserEdit(false)
59    , m_cachedSelectionStart(-1)
60    , m_cachedSelectionEnd(-1)
61    , m_cachedSelectionDirection(SelectionHasNoDirection)
62{
63}
64
65HTMLTextFormControlElement::~HTMLTextFormControlElement()
66{
67}
68
69bool HTMLTextFormControlElement::childShouldCreateRenderer(const Node& child) const
70{
71    // FIXME: We shouldn't force the pseudo elements down into the shadow, but
72    // this perserves the current behavior of WebKit.
73    if (child.isPseudoElement())
74        return HTMLFormControlElementWithState::childShouldCreateRenderer(child);
75    return hasShadowRootParent(child) && HTMLFormControlElementWithState::childShouldCreateRenderer(child);
76}
77
78Node::InsertionNotificationRequest HTMLTextFormControlElement::insertedInto(ContainerNode& insertionPoint)
79{
80    HTMLFormControlElementWithState::insertedInto(insertionPoint);
81    if (!insertionPoint.inDocument())
82        return InsertionDone;
83    String initialValue = value();
84    setTextAsOfLastFormControlChangeEvent(initialValue.isNull() ? emptyString() : initialValue);
85    return InsertionDone;
86}
87
88void HTMLTextFormControlElement::dispatchFocusEvent(PassRefPtr<Element> oldFocusedElement, FocusDirection direction)
89{
90    if (supportsPlaceholder())
91        updatePlaceholderVisibility(false);
92    handleFocusEvent(oldFocusedElement.get(), direction);
93    HTMLFormControlElementWithState::dispatchFocusEvent(oldFocusedElement, direction);
94}
95
96void HTMLTextFormControlElement::dispatchBlurEvent(PassRefPtr<Element> newFocusedElement)
97{
98    if (supportsPlaceholder())
99        updatePlaceholderVisibility(false);
100    handleBlurEvent();
101    HTMLFormControlElementWithState::dispatchBlurEvent(newFocusedElement);
102}
103
104void HTMLTextFormControlElement::didEditInnerTextValue()
105{
106    if (!isTextFormControl())
107        return;
108
109    m_lastChangeWasUserEdit = true;
110    subtreeHasChanged();
111}
112
113void HTMLTextFormControlElement::forwardEvent(Event* event)
114{
115    if (event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)
116        return;
117    innerTextElement()->defaultEventHandler(event);
118}
119
120String HTMLTextFormControlElement::strippedPlaceholder() const
121{
122    // According to the HTML5 specification, we need to remove CR and LF from
123    // the attribute value.
124    const AtomicString& attributeValue = fastGetAttribute(placeholderAttr);
125    if (!attributeValue.contains(newlineCharacter) && !attributeValue.contains(carriageReturn))
126        return attributeValue;
127
128    StringBuilder stripped;
129    unsigned length = attributeValue.length();
130    stripped.reserveCapacity(length);
131    for (unsigned i = 0; i < length; ++i) {
132        UChar character = attributeValue[i];
133        if (character == newlineCharacter || character == carriageReturn)
134            continue;
135        stripped.append(character);
136    }
137    return stripped.toString();
138}
139
140static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; }
141
142bool HTMLTextFormControlElement::isPlaceholderEmpty() const
143{
144    const AtomicString& attributeValue = fastGetAttribute(placeholderAttr);
145    return attributeValue.string().find(isNotLineBreak) == notFound;
146}
147
148bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
149{
150    return supportsPlaceholder()
151        && isEmptyValue()
152        && isEmptySuggestedValue()
153        && !isPlaceholderEmpty()
154        && (document().focusedElement() != this || (renderer() && renderer()->theme().shouldShowPlaceholderWhenFocused()))
155        && (!renderer() || renderer()->style().visibility() == VISIBLE);
156}
157
158void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged)
159{
160    if (!supportsPlaceholder())
161        return;
162    if (!placeholderElement() || placeholderValueChanged)
163        updatePlaceholderText();
164    HTMLElement* placeholder = placeholderElement();
165    if (!placeholder)
166        return;
167    placeholder->setInlineStyleProperty(CSSPropertyVisibility, placeholderShouldBeVisible() ? CSSValueVisible : CSSValueHidden);
168}
169
170void HTMLTextFormControlElement::setSelectionStart(int start)
171{
172    setSelectionRange(start, std::max(start, selectionEnd()), selectionDirection());
173}
174
175void HTMLTextFormControlElement::setSelectionEnd(int end)
176{
177    setSelectionRange(std::min(end, selectionStart()), end, selectionDirection());
178}
179
180void HTMLTextFormControlElement::setSelectionDirection(const String& direction)
181{
182    setSelectionRange(selectionStart(), selectionEnd(), direction);
183}
184
185void HTMLTextFormControlElement::select()
186{
187    // FIXME: We should abstract the selection behavior into an EditingBehavior function instead
188    // of hardcoding the behavior using a macro define.
189#if PLATFORM(IOS)
190    // We don't want to select all the text on iOS. Instead use the standard textfield behavior of going to the end of the line.
191    setSelectionRange(std::numeric_limits<int>::max(), std::numeric_limits<int>::max(), SelectionHasForwardDirection);
192#else
193    setSelectionRange(0, std::numeric_limits<int>::max(), SelectionHasNoDirection);
194#endif
195}
196
197String HTMLTextFormControlElement::selectedText() const
198{
199    if (!isTextFormControl())
200        return String();
201    return value().substring(selectionStart(), selectionEnd() - selectionStart());
202}
203
204void HTMLTextFormControlElement::dispatchFormControlChangeEvent()
205{
206    if (m_textAsOfLastFormControlChangeEvent != value()) {
207        dispatchChangeEvent();
208        setTextAsOfLastFormControlChangeEvent(value());
209    }
210    setChangedSinceLastFormControlChangeEvent(false);
211}
212
213void HTMLTextFormControlElement::setRangeText(const String& replacement, ExceptionCode& ec)
214{
215    setRangeText(replacement, selectionStart(), selectionEnd(), String(), ec);
216}
217
218void HTMLTextFormControlElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionCode& ec)
219{
220    if (start > end) {
221        ec = INDEX_SIZE_ERR;
222        return;
223    }
224
225    String text = innerTextValue();
226    unsigned textLength = text.length();
227    unsigned replacementLength = replacement.length();
228    unsigned newSelectionStart = selectionStart();
229    unsigned newSelectionEnd = selectionEnd();
230
231    start = std::min(start, textLength);
232    end = std::min(end, textLength);
233
234    if (start < end)
235        text.replace(start, end - start, replacement);
236    else
237        text.insert(replacement, start);
238
239    setInnerTextValue(text);
240
241    // FIXME: What should happen to the value (as in value()) if there's no renderer?
242    if (!renderer())
243        return;
244
245    subtreeHasChanged();
246
247    if (equalIgnoringCase(selectionMode, "select")) {
248        newSelectionStart = start;
249        newSelectionEnd = start + replacementLength;
250    } else if (equalIgnoringCase(selectionMode, "start"))
251        newSelectionStart = newSelectionEnd = start;
252    else if (equalIgnoringCase(selectionMode, "end"))
253        newSelectionStart = newSelectionEnd = start + replacementLength;
254    else {
255        // Default is "preserve".
256        long delta = replacementLength - (end - start);
257
258        if (newSelectionStart > end)
259            newSelectionStart += delta;
260        else if (newSelectionStart > start)
261            newSelectionStart = start;
262
263        if (newSelectionEnd > end)
264            newSelectionEnd += delta;
265        else if (newSelectionEnd > start)
266            newSelectionEnd = start + replacementLength;
267    }
268
269    setSelectionRange(newSelectionStart, newSelectionEnd, SelectionHasNoDirection);
270}
271
272void HTMLTextFormControlElement::setSelectionRange(int start, int end, const String& directionString)
273{
274    TextFieldSelectionDirection direction = SelectionHasNoDirection;
275    if (directionString == "forward")
276        direction = SelectionHasForwardDirection;
277    else if (directionString == "backward")
278        direction = SelectionHasBackwardDirection;
279
280    return setSelectionRange(start, end, direction);
281}
282
283void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction)
284{
285    if (!isTextFormControl())
286        return;
287
288    end = std::max(end, 0);
289    start = std::min(std::max(start, 0), end);
290
291    TextControlInnerTextElement* innerText = innerTextElement();
292    bool hasFocus = document().focusedElement() == this;
293    if (!hasFocus && innerText) {
294        // FIXME: Removing this synchronous layout requires fixing <https://webkit.org/b/128797>
295        document().updateLayoutIgnorePendingStylesheets();
296        if (RenderElement* rendererTextControl = renderer()) {
297            if (rendererTextControl->style().visibility() == HIDDEN || !innerText->renderBox()->height()) {
298                cacheSelection(start, end, direction);
299                return;
300            }
301        }
302    }
303
304    Position startPosition = positionForIndex(innerText, start);
305    Position endPosition;
306    if (start == end)
307        endPosition = startPosition;
308    else {
309        if (direction == SelectionHasBackwardDirection) {
310            endPosition = startPosition;
311            startPosition = positionForIndex(innerText, end);
312        } else
313            endPosition = positionForIndex(innerText, end);
314    }
315
316    if (Frame* frame = document().frame())
317        frame->selection().moveWithoutValidationTo(startPosition, endPosition, direction != SelectionHasNoDirection, !hasFocus);
318}
319
320int HTMLTextFormControlElement::indexForVisiblePosition(const VisiblePosition& position) const
321{
322    TextControlInnerTextElement* innerText = innerTextElement();
323    if (!innerText || !innerText->contains(position.deepEquivalent().anchorNode()))
324        return 0;
325    unsigned index = indexForPosition(position.deepEquivalent());
326    ASSERT(VisiblePosition(positionForIndex(innerTextElement(), index)) == position);
327    return index;
328}
329
330VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) const
331{
332    VisiblePosition position = positionForIndex(innerTextElement(), index);
333    ASSERT(indexForVisiblePosition(position) == index);
334    return position;
335}
336
337int HTMLTextFormControlElement::selectionStart() const
338{
339    if (!isTextFormControl())
340        return 0;
341    if (document().focusedElement() != this && hasCachedSelection())
342        return m_cachedSelectionStart;
343
344    return computeSelectionStart();
345}
346
347int HTMLTextFormControlElement::computeSelectionStart() const
348{
349    ASSERT(isTextFormControl());
350    Frame* frame = document().frame();
351    if (!frame)
352        return 0;
353
354    return indexForPosition(frame->selection().selection().start());
355}
356
357int HTMLTextFormControlElement::selectionEnd() const
358{
359    if (!isTextFormControl())
360        return 0;
361    if (document().focusedElement() != this && hasCachedSelection())
362        return m_cachedSelectionEnd;
363    return computeSelectionEnd();
364}
365
366int HTMLTextFormControlElement::computeSelectionEnd() const
367{
368    ASSERT(isTextFormControl());
369    Frame* frame = document().frame();
370    if (!frame)
371        return 0;
372
373    return indexForPosition(frame->selection().selection().end());
374}
375
376static const AtomicString& directionString(TextFieldSelectionDirection direction)
377{
378    DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::ConstructFromLiteral));
379    DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, forward, ("forward", AtomicString::ConstructFromLiteral));
380    DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, backward, ("backward", AtomicString::ConstructFromLiteral));
381
382    switch (direction) {
383    case SelectionHasNoDirection:
384        return none;
385    case SelectionHasForwardDirection:
386        return forward;
387    case SelectionHasBackwardDirection:
388        return backward;
389    }
390
391    ASSERT_NOT_REACHED();
392    return none;
393}
394
395const AtomicString& HTMLTextFormControlElement::selectionDirection() const
396{
397    if (!isTextFormControl())
398        return directionString(SelectionHasNoDirection);
399    if (document().focusedElement() != this && hasCachedSelection())
400        return directionString(m_cachedSelectionDirection);
401
402    return directionString(computeSelectionDirection());
403}
404
405TextFieldSelectionDirection HTMLTextFormControlElement::computeSelectionDirection() const
406{
407    ASSERT(isTextFormControl());
408    Frame* frame = document().frame();
409    if (!frame)
410        return SelectionHasNoDirection;
411
412    const VisibleSelection& selection = frame->selection().selection();
413    return selection.isDirectional() ? (selection.isBaseFirst() ? SelectionHasForwardDirection : SelectionHasBackwardDirection) : SelectionHasNoDirection;
414}
415
416static inline void setContainerAndOffsetForRange(Node* node, int offset, Node*& containerNode, int& offsetInContainer)
417{
418    if (node->isTextNode()) {
419        containerNode = node;
420        offsetInContainer = offset;
421    } else {
422        containerNode = node->parentNode();
423        offsetInContainer = node->nodeIndex() + offset;
424    }
425}
426
427PassRefPtr<Range> HTMLTextFormControlElement::selection() const
428{
429    if (!renderer() || !isTextFormControl() || !hasCachedSelection())
430        return 0;
431
432    int start = m_cachedSelectionStart;
433    int end = m_cachedSelectionEnd;
434
435    ASSERT(start <= end);
436    TextControlInnerTextElement* innerText = innerTextElement();
437    if (!innerText)
438        return 0;
439
440    if (!innerText->firstChild())
441        return Range::create(document(), innerText, 0, innerText, 0);
442
443    int offset = 0;
444    Node* startNode = 0;
445    Node* endNode = 0;
446    for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(node, innerText)) {
447        ASSERT(!node->firstChild());
448        ASSERT(node->isTextNode() || node->hasTagName(brTag));
449        int length = node->isTextNode() ? lastOffsetInNode(node) : 1;
450
451        if (offset <= start && start <= offset + length)
452            setContainerAndOffsetForRange(node, start - offset, startNode, start);
453
454        if (offset <= end && end <= offset + length) {
455            setContainerAndOffsetForRange(node, end - offset, endNode, end);
456            break;
457        }
458
459        offset += length;
460    }
461
462    if (!startNode || !endNode)
463        return 0;
464
465    return Range::create(document(), startNode, start, endNode, end);
466}
467
468void HTMLTextFormControlElement::restoreCachedSelection()
469{
470    setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, m_cachedSelectionDirection);
471}
472
473void HTMLTextFormControlElement::selectionChanged(bool shouldFireSelectEvent)
474{
475    if (!isTextFormControl())
476        return;
477
478    // FIXME: Don't re-compute selection start and end if this function was called inside setSelectionRange.
479    // selectionStart() or selectionEnd() will return cached selection when this node doesn't have focus
480    cacheSelection(computeSelectionStart(), computeSelectionEnd(), computeSelectionDirection());
481
482    if (shouldFireSelectEvent && m_cachedSelectionStart != m_cachedSelectionEnd)
483        dispatchEvent(Event::create(eventNames().selectEvent, true, false));
484}
485
486void HTMLTextFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
487{
488    if (name == placeholderAttr)
489        updatePlaceholderVisibility(true);
490    else
491        HTMLFormControlElementWithState::parseAttribute(name, value);
492}
493
494void HTMLTextFormControlElement::disabledStateChanged()
495{
496    HTMLFormControlElementWithState::disabledStateChanged();
497    updateInnerTextElementEditability();
498}
499
500void HTMLTextFormControlElement::readOnlyAttributeChanged()
501{
502    HTMLFormControlElementWithState::disabledAttributeChanged();
503    updateInnerTextElementEditability();
504}
505
506void HTMLTextFormControlElement::updateInnerTextElementEditability()
507{
508    if (TextControlInnerTextElement* innerText = innerTextElement())
509        innerText->setAttribute(contenteditableAttr, isDisabledOrReadOnly() ? "false" : "plaintext-only");
510}
511
512bool HTMLTextFormControlElement::lastChangeWasUserEdit() const
513{
514    if (!isTextFormControl())
515        return false;
516    return m_lastChangeWasUserEdit;
517}
518
519void HTMLTextFormControlElement::setInnerTextValue(const String& value)
520{
521    if (!isTextFormControl())
522        return;
523
524    bool textIsChanged = value != innerTextValue();
525    if (textIsChanged || !innerTextElement()->hasChildNodes()) {
526        if (textIsChanged && renderer()) {
527            if (AXObjectCache* cache = document().existingAXObjectCache())
528                cache->postNotification(this, AXObjectCache::AXValueChanged, TargetObservableParent);
529        }
530        innerTextElement()->setInnerText(value, ASSERT_NO_EXCEPTION);
531
532        if (value.endsWith('\n') || value.endsWith('\r'))
533            innerTextElement()->appendChild(HTMLBRElement::create(document()), ASSERT_NO_EXCEPTION);
534    }
535
536    setFormControlValueMatchesRenderer(true);
537}
538
539static String finishText(StringBuilder& result)
540{
541    // Remove one trailing newline; there's always one that's collapsed out by rendering.
542    size_t size = result.length();
543    if (size && result[size - 1] == newlineCharacter)
544        result.resize(--size);
545    return result.toString();
546}
547
548String HTMLTextFormControlElement::innerTextValue() const
549{
550    if (!isTextFormControl())
551        return emptyString();
552
553    TextControlInnerTextElement* innerText = innerTextElement();
554    if (!innerText)
555        return emptyString();
556
557    StringBuilder result;
558    for (Node* node = innerText; node; node = NodeTraversal::next(node, innerText)) {
559        if (node->hasTagName(brTag))
560            result.append(newlineCharacter);
561        else if (node->isTextNode())
562            result.append(toText(node)->data());
563    }
564    return finishText(result);
565}
566
567static Position positionForIndex(TextControlInnerTextElement* innerText, unsigned index)
568{
569    unsigned remainingCharactersToMoveForward = index;
570    Node* lastBrOrText = innerText;
571    for (Node* node = innerText; node; node = NodeTraversal::next(node, innerText)) {
572        if (node->hasTagName(brTag)) {
573            if (!remainingCharactersToMoveForward)
574                return positionBeforeNode(node);
575            remainingCharactersToMoveForward--;
576            lastBrOrText = node;
577        } else if (node->isTextNode()) {
578            Text& text = toText(*node);
579            if (remainingCharactersToMoveForward < text.length())
580                return Position(&text, remainingCharactersToMoveForward);
581            remainingCharactersToMoveForward -= text.length();
582            lastBrOrText = node;
583        }
584    }
585    return lastPositionInOrAfterNode(lastBrOrText);
586}
587
588unsigned HTMLTextFormControlElement::indexForPosition(const Position& passedPosition) const
589{
590    TextControlInnerTextElement* innerText = innerTextElement();
591    if (!innerText || !innerText->contains(passedPosition.anchorNode()) || passedPosition.isNull())
592        return 0;
593
594    if (positionBeforeNode(innerText) == passedPosition)
595        return 0;
596
597    unsigned index = 0;
598    Node* startNode = passedPosition.computeNodeBeforePosition();
599    if (!startNode)
600        startNode = passedPosition.containerNode();
601    ASSERT(startNode);
602    ASSERT(innerText->contains(startNode));
603
604    for (Node* node = startNode; node; node = NodeTraversal::previous(node, innerText)) {
605        if (node->isTextNode()) {
606            unsigned length = toText(*node).length();
607            if (node == passedPosition.containerNode())
608                index += std::min<unsigned>(length, passedPosition.offsetInContainerNode());
609            else
610                index += length;
611        } else if (node->hasTagName(brTag))
612            index++;
613    }
614
615    unsigned length = innerTextValue().length();
616    index = std::min(index, length); // FIXME: We shouldn't have to call innerTextValue() just to ignore the last LF. See finishText.
617#ifndef ASSERT_DISABLED
618    VisiblePosition visiblePosition = passedPosition;
619    unsigned indexComputedByVisiblePosition = 0;
620    if (visiblePosition.isNotNull())
621        indexComputedByVisiblePosition = WebCore::indexForVisiblePosition(innerText, visiblePosition, false /* forSelectionPreservation */);
622    ASSERT(index == indexComputedByVisiblePosition);
623#endif
624    return index;
625}
626
627#if PLATFORM(IOS)
628void HTMLTextFormControlElement::hidePlaceholder()
629{
630    if (!supportsPlaceholder())
631        return;
632    HTMLElement* placeholder = placeholderElement();
633    if (!placeholder) {
634        updatePlaceholderText();
635        return;
636    }
637    placeholder->setInlineStyleProperty(CSSPropertyVisibility, ASCIILiteral("hidden"));
638}
639
640void HTMLTextFormControlElement::showPlaceholderIfNecessary()
641{
642    updatePlaceholderVisibility(false);
643}
644#endif
645
646static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
647{
648    RootInlineBox* next;
649    for (; line; line = next) {
650        next = line->nextRootBox();
651        if (next && !line->endsWithBreak()) {
652            ASSERT(line->lineBreakObj());
653            breakNode = line->lineBreakObj()->node();
654            breakOffset = line->lineBreakPos();
655            line = next;
656            return;
657        }
658    }
659    breakNode = 0;
660    breakOffset = 0;
661}
662
663String HTMLTextFormControlElement::valueWithHardLineBreaks() const
664{
665    // FIXME: It's not acceptable to ignore the HardWrap setting when there is no renderer.
666    // While we have no evidence this has ever been a practical problem, it would be best to fix it some day.
667    if (!isTextFormControl())
668        return value();
669
670    TextControlInnerTextElement* innerText = innerTextElement();
671    if (!innerText)
672        return value();
673
674    RenderTextControlInnerBlock* renderer = innerText->renderer();
675    if (!renderer)
676        return value();
677
678    Node* breakNode;
679    unsigned breakOffset;
680    RootInlineBox* line = renderer->firstRootBox();
681    if (!line)
682        return value();
683
684    getNextSoftBreak(line, breakNode, breakOffset);
685
686    StringBuilder result;
687    for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(node, innerText)) {
688        if (node->hasTagName(brTag))
689            result.append(newlineCharacter);
690        else if (node->isTextNode()) {
691            String data = toText(node)->data();
692            unsigned length = data.length();
693            unsigned position = 0;
694            while (breakNode == node && breakOffset <= length) {
695                if (breakOffset > position) {
696                    result.append(data, position, breakOffset - position);
697                    position = breakOffset;
698                    result.append(newlineCharacter);
699                }
700                getNextSoftBreak(line, breakNode, breakOffset);
701            }
702            result.append(data, position, length - position);
703        }
704        while (breakNode == node)
705            getNextSoftBreak(line, breakNode, breakOffset);
706    }
707    return finishText(result);
708}
709
710HTMLTextFormControlElement* enclosingTextFormControl(const Position& position)
711{
712    ASSERT(position.isNull() || position.anchorType() == Position::PositionIsOffsetInAnchor
713        || position.containerNode() || !position.anchorNode()->shadowHost()
714        || hasShadowRootParent(*position.anchorNode()));
715
716    Node* container = position.containerNode();
717    if (!container)
718        return nullptr;
719    Element* ancestor = container->shadowHost();
720    return ancestor && isHTMLTextFormControlElement(*ancestor) ? toHTMLTextFormControlElement(ancestor) : nullptr;
721}
722
723static const Element* parentHTMLElement(const Element* element)
724{
725    while (element) {
726        element = element->parentElement();
727        if (element && element->isHTMLElement())
728            return element;
729    }
730    return 0;
731}
732
733String HTMLTextFormControlElement::directionForFormData() const
734{
735    for (const Element* element = this; element; element = parentHTMLElement(element)) {
736        const AtomicString& dirAttributeValue = element->fastGetAttribute(dirAttr);
737        if (dirAttributeValue.isNull())
738            continue;
739
740        if (equalIgnoringCase(dirAttributeValue, "rtl") || equalIgnoringCase(dirAttributeValue, "ltr"))
741            return dirAttributeValue;
742
743        if (equalIgnoringCase(dirAttributeValue, "auto")) {
744            bool isAuto;
745            TextDirection textDirection = static_cast<const HTMLElement*>(element)->directionalityIfhasDirAutoAttribute(isAuto);
746            return textDirection == RTL ? "rtl" : "ltr";
747        }
748    }
749
750    return "ltr";
751}
752
753} // namespace Webcore
754