Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2001 Dirk Mueller (mueller (at) kde.org)
      5  * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
      6  *           (C) 2006 Alexey Proskuryakov (ap (at) 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 "core/html/HTMLTextFormControlElement.h"
     27 
     28 #include "HTMLNames.h"
     29 #include "bindings/v8/ExceptionState.h"
     30 #include "bindings/v8/ExceptionStatePlaceholder.h"
     31 #include "core/accessibility/AXObjectCache.h"
     32 #include "core/dom/Document.h"
     33 #include "core/dom/Event.h"
     34 #include "core/dom/EventNames.h"
     35 #include "core/dom/NodeRenderingContext.h"
     36 #include "core/dom/NodeTraversal.h"
     37 #include "core/dom/Text.h"
     38 #include "core/editing/FrameSelection.h"
     39 #include "core/editing/TextIterator.h"
     40 #include "core/html/HTMLBRElement.h"
     41 #include "core/page/Frame.h"
     42 #include "core/page/UseCounter.h"
     43 #include "core/rendering/RenderBox.h"
     44 #include "core/rendering/RenderTextControl.h"
     45 #include "core/rendering/RenderTheme.h"
     46 #include "wtf/text/StringBuilder.h"
     47 
     48 namespace WebCore {
     49 
     50 using namespace HTMLNames;
     51 using namespace std;
     52 
     53 HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* form)
     54     : HTMLFormControlElementWithState(tagName, doc, form)
     55     , m_lastChangeWasUserEdit(false)
     56     , m_cachedSelectionStart(-1)
     57     , m_cachedSelectionEnd(-1)
     58     , m_cachedSelectionDirection(SelectionHasNoDirection)
     59 {
     60 }
     61 
     62 HTMLTextFormControlElement::~HTMLTextFormControlElement()
     63 {
     64 }
     65 
     66 Node::InsertionNotificationRequest HTMLTextFormControlElement::insertedInto(ContainerNode* insertionPoint)
     67 {
     68     HTMLFormControlElementWithState::insertedInto(insertionPoint);
     69     if (!insertionPoint->inDocument())
     70         return InsertionDone;
     71     String initialValue = value();
     72     setTextAsOfLastFormControlChangeEvent(initialValue.isNull() ? emptyString() : initialValue);
     73     return InsertionDone;
     74 }
     75 
     76 void HTMLTextFormControlElement::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection direction)
     77 {
     78     if (supportsPlaceholder())
     79         updatePlaceholderVisibility(false);
     80     handleFocusEvent(oldFocusedElement, direction);
     81     HTMLFormControlElementWithState::dispatchFocusEvent(oldFocusedElement, direction);
     82 }
     83 
     84 void HTMLTextFormControlElement::dispatchBlurEvent(Element* newFocusedElement)
     85 {
     86     if (supportsPlaceholder())
     87         updatePlaceholderVisibility(false);
     88     handleBlurEvent();
     89     HTMLFormControlElementWithState::dispatchBlurEvent(newFocusedElement);
     90 }
     91 
     92 void HTMLTextFormControlElement::defaultEventHandler(Event* event)
     93 {
     94     if (event->type() == eventNames().webkitEditableContentChangedEvent && renderer() && renderer()->isTextControl()) {
     95         m_lastChangeWasUserEdit = true;
     96         subtreeHasChanged();
     97         return;
     98     }
     99 
    100     HTMLFormControlElementWithState::defaultEventHandler(event);
    101 }
    102 
    103 void HTMLTextFormControlElement::forwardEvent(Event* event)
    104 {
    105     if (event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)
    106         return;
    107     innerTextElement()->defaultEventHandler(event);
    108 }
    109 
    110 String HTMLTextFormControlElement::strippedPlaceholder() const
    111 {
    112     // According to the HTML5 specification, we need to remove CR and LF from
    113     // the attribute value.
    114     const AtomicString& attributeValue = fastGetAttribute(placeholderAttr);
    115     if (!attributeValue.contains(newlineCharacter) && !attributeValue.contains(carriageReturn))
    116         return attributeValue;
    117 
    118     StringBuilder stripped;
    119     unsigned length = attributeValue.length();
    120     stripped.reserveCapacity(length);
    121     for (unsigned i = 0; i < length; ++i) {
    122         UChar character = attributeValue[i];
    123         if (character == newlineCharacter || character == carriageReturn)
    124             continue;
    125         stripped.append(character);
    126     }
    127     return stripped.toString();
    128 }
    129 
    130 static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; }
    131 
    132 bool HTMLTextFormControlElement::isPlaceholderEmpty() const
    133 {
    134     const AtomicString& attributeValue = fastGetAttribute(placeholderAttr);
    135     return attributeValue.string().find(isNotLineBreak) == notFound;
    136 }
    137 
    138 bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
    139 {
    140     return supportsPlaceholder()
    141         && isEmptyValue()
    142         && isEmptySuggestedValue()
    143         && !isPlaceholderEmpty()
    144         && (document()->focusedElement() != this || (renderer() && renderer()->theme()->shouldShowPlaceholderWhenFocused()))
    145         && (!renderer() || renderer()->style()->visibility() == VISIBLE);
    146 }
    147 
    148 void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged)
    149 {
    150     if (!supportsPlaceholder())
    151         return;
    152     if (!placeholderElement() || placeholderValueChanged)
    153         updatePlaceholderText();
    154     HTMLElement* placeholder = placeholderElement();
    155     if (!placeholder)
    156         return;
    157     placeholder->setInlineStyleProperty(CSSPropertyVisibility, placeholderShouldBeVisible() ? CSSValueVisible : CSSValueHidden);
    158 }
    159 
    160 void HTMLTextFormControlElement::fixPlaceholderRenderer(HTMLElement* placeholder, HTMLElement* siblingElement)
    161 {
    162     // FIXME: We should change the order of DOM nodes. But it makes an assertion
    163     // failure in editing code.
    164     if (!placeholder || !placeholder->renderer())
    165         return;
    166     RenderObject* placeholderRenderer = placeholder->renderer();
    167     RenderObject* siblingRenderer = siblingElement->renderer();
    168     if (!siblingRenderer)
    169         return;
    170     if (placeholderRenderer->nextSibling() == siblingRenderer)
    171         return;
    172     RenderObject* parentRenderer = placeholderRenderer->parent();
    173     ASSERT(siblingRenderer->parent() == parentRenderer);
    174     parentRenderer->removeChild(placeholderRenderer);
    175     parentRenderer->addChild(placeholderRenderer, siblingRenderer);
    176 }
    177 
    178 void HTMLTextFormControlElement::setSelectionStart(int start)
    179 {
    180     setSelectionRange(start, max(start, selectionEnd()), selectionDirection());
    181 }
    182 
    183 void HTMLTextFormControlElement::setSelectionEnd(int end)
    184 {
    185     setSelectionRange(min(end, selectionStart()), end, selectionDirection());
    186 }
    187 
    188 void HTMLTextFormControlElement::setSelectionDirection(const String& direction)
    189 {
    190     setSelectionRange(selectionStart(), selectionEnd(), direction);
    191 }
    192 
    193 void HTMLTextFormControlElement::select()
    194 {
    195     setSelectionRange(0, numeric_limits<int>::max(), SelectionHasNoDirection);
    196 }
    197 
    198 String HTMLTextFormControlElement::selectedText() const
    199 {
    200     if (!isTextFormControl())
    201         return String();
    202     return value().substring(selectionStart(), selectionEnd() - selectionStart());
    203 }
    204 
    205 void HTMLTextFormControlElement::dispatchFormControlChangeEvent()
    206 {
    207     if (m_textAsOfLastFormControlChangeEvent != value()) {
    208         HTMLElement::dispatchChangeEvent();
    209         setTextAsOfLastFormControlChangeEvent(value());
    210     }
    211     setChangedSinceLastFormControlChangeEvent(false);
    212 }
    213 
    214 static inline bool hasVisibleTextArea(RenderTextControl* textControl, HTMLElement* innerText)
    215 {
    216     ASSERT(textControl);
    217     return textControl->style()->visibility() != HIDDEN && innerText && innerText->renderer() && innerText->renderBox()->height();
    218 }
    219 
    220 
    221 void HTMLTextFormControlElement::setRangeText(const String& replacement, ExceptionState& es)
    222 {
    223     setRangeText(replacement, selectionStart(), selectionEnd(), String(), es);
    224 }
    225 
    226 void HTMLTextFormControlElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionState& es)
    227 {
    228     if (start > end) {
    229         es.throwDOMException(IndexSizeError);
    230         return;
    231     }
    232 
    233     String text = innerTextValue();
    234     unsigned textLength = text.length();
    235     unsigned replacementLength = replacement.length();
    236     unsigned newSelectionStart = selectionStart();
    237     unsigned newSelectionEnd = selectionEnd();
    238 
    239     start = std::min(start, textLength);
    240     end = std::min(end, textLength);
    241 
    242     if (start < end)
    243         text.replace(start, end - start, replacement);
    244     else
    245         text.insert(replacement, start);
    246 
    247     setInnerTextValue(text);
    248 
    249     // FIXME: What should happen to the value (as in value()) if there's no renderer?
    250     if (!renderer())
    251         return;
    252 
    253     subtreeHasChanged();
    254 
    255     if (equalIgnoringCase(selectionMode, "select")) {
    256         newSelectionStart = start;
    257         newSelectionEnd = start + replacementLength;
    258     } else if (equalIgnoringCase(selectionMode, "start"))
    259         newSelectionStart = newSelectionEnd = start;
    260     else if (equalIgnoringCase(selectionMode, "end"))
    261         newSelectionStart = newSelectionEnd = start + replacementLength;
    262     else {
    263         // Default is "preserve".
    264         long delta = replacementLength - (end - start);
    265 
    266         if (newSelectionStart > end)
    267             newSelectionStart += delta;
    268         else if (newSelectionStart > start)
    269             newSelectionStart = start;
    270 
    271         if (newSelectionEnd > end)
    272             newSelectionEnd += delta;
    273         else if (newSelectionEnd > start)
    274             newSelectionEnd = start + replacementLength;
    275     }
    276 
    277     setSelectionRange(newSelectionStart, newSelectionEnd, SelectionHasNoDirection);
    278 }
    279 
    280 void HTMLTextFormControlElement::setSelectionRange(int start, int end, const String& directionString)
    281 {
    282     TextFieldSelectionDirection direction = SelectionHasNoDirection;
    283     if (directionString == "forward")
    284         direction = SelectionHasForwardDirection;
    285     else if (directionString == "backward")
    286         direction = SelectionHasBackwardDirection;
    287 
    288     return setSelectionRange(start, end, direction);
    289 }
    290 
    291 void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction)
    292 {
    293     document()->updateLayoutIgnorePendingStylesheets();
    294 
    295     if (!renderer() || !renderer()->isTextControl())
    296         return;
    297 
    298     end = max(end, 0);
    299     start = min(max(start, 0), end);
    300 
    301     if (!hasVisibleTextArea(toRenderTextControl(renderer()), innerTextElement())) {
    302         cacheSelection(start, end, direction);
    303         return;
    304     }
    305     VisiblePosition startPosition = visiblePositionForIndex(start);
    306     VisiblePosition endPosition;
    307     if (start == end)
    308         endPosition = startPosition;
    309     else
    310         endPosition = visiblePositionForIndex(end);
    311 
    312     // startPosition and endPosition can be null position for example when
    313     // "-webkit-user-select: none" style attribute is specified.
    314     if (startPosition.isNotNull() && endPosition.isNotNull()) {
    315         ASSERT(startPosition.deepEquivalent().deprecatedNode()->shadowHost() == this
    316             && endPosition.deepEquivalent().deprecatedNode()->shadowHost() == this);
    317     }
    318     VisibleSelection newSelection;
    319     if (direction == SelectionHasBackwardDirection)
    320         newSelection = VisibleSelection(endPosition, startPosition);
    321     else
    322         newSelection = VisibleSelection(startPosition, endPosition);
    323     newSelection.setIsDirectional(direction != SelectionHasNoDirection);
    324 
    325     if (Frame* frame = document()->frame())
    326         frame->selection()->setSelection(newSelection);
    327 }
    328 
    329 VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) const
    330 {
    331     if (index <= 0)
    332         return VisiblePosition(firstPositionInNode(innerTextElement()), DOWNSTREAM);
    333     RefPtr<Range> range = Range::create(document());
    334     range->selectNodeContents(innerTextElement(), ASSERT_NO_EXCEPTION);
    335     CharacterIterator it(range.get());
    336     it.advance(index - 1);
    337     return VisiblePosition(it.range()->endPosition(), UPSTREAM);
    338 }
    339 
    340 int HTMLTextFormControlElement::indexForVisiblePosition(const VisiblePosition& pos) const
    341 {
    342     Position indexPosition = pos.deepEquivalent().parentAnchoredEquivalent();
    343     if (enclosingTextFormControl(indexPosition) != this)
    344         return 0;
    345     RefPtr<Range> range = Range::create(indexPosition.document());
    346     range->setStart(innerTextElement(), 0, ASSERT_NO_EXCEPTION);
    347     range->setEnd(indexPosition.containerNode(), indexPosition.offsetInContainerNode(), ASSERT_NO_EXCEPTION);
    348     return TextIterator::rangeLength(range.get());
    349 }
    350 
    351 int HTMLTextFormControlElement::selectionStart() const
    352 {
    353     if (!isTextFormControl())
    354         return 0;
    355     if (document()->focusedElement() != this && hasCachedSelection())
    356         return m_cachedSelectionStart;
    357 
    358     return computeSelectionStart();
    359 }
    360 
    361 int HTMLTextFormControlElement::computeSelectionStart() const
    362 {
    363     ASSERT(isTextFormControl());
    364     Frame* frame = document()->frame();
    365     if (!frame)
    366         return 0;
    367 
    368     return indexForVisiblePosition(frame->selection()->start());
    369 }
    370 
    371 int HTMLTextFormControlElement::selectionEnd() const
    372 {
    373     if (!isTextFormControl())
    374         return 0;
    375     if (document()->focusedElement() != this && hasCachedSelection())
    376         return m_cachedSelectionEnd;
    377     return computeSelectionEnd();
    378 }
    379 
    380 int HTMLTextFormControlElement::computeSelectionEnd() const
    381 {
    382     ASSERT(isTextFormControl());
    383     Frame* frame = document()->frame();
    384     if (!frame)
    385         return 0;
    386 
    387     return indexForVisiblePosition(frame->selection()->end());
    388 }
    389 
    390 static const AtomicString& directionString(TextFieldSelectionDirection direction)
    391 {
    392     DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::ConstructFromLiteral));
    393     DEFINE_STATIC_LOCAL(const AtomicString, forward, ("forward", AtomicString::ConstructFromLiteral));
    394     DEFINE_STATIC_LOCAL(const AtomicString, backward, ("backward", AtomicString::ConstructFromLiteral));
    395 
    396     switch (direction) {
    397     case SelectionHasNoDirection:
    398         return none;
    399     case SelectionHasForwardDirection:
    400         return forward;
    401     case SelectionHasBackwardDirection:
    402         return backward;
    403     }
    404 
    405     ASSERT_NOT_REACHED();
    406     return none;
    407 }
    408 
    409 const AtomicString& HTMLTextFormControlElement::selectionDirection() const
    410 {
    411     if (!isTextFormControl())
    412         return directionString(SelectionHasNoDirection);
    413     if (document()->focusedElement() != this && hasCachedSelection())
    414         return directionString(m_cachedSelectionDirection);
    415 
    416     return directionString(computeSelectionDirection());
    417 }
    418 
    419 TextFieldSelectionDirection HTMLTextFormControlElement::computeSelectionDirection() const
    420 {
    421     ASSERT(isTextFormControl());
    422     Frame* frame = document()->frame();
    423     if (!frame)
    424         return SelectionHasNoDirection;
    425 
    426     const VisibleSelection& selection = frame->selection()->selection();
    427     return selection.isDirectional() ? (selection.isBaseFirst() ? SelectionHasForwardDirection : SelectionHasBackwardDirection) : SelectionHasNoDirection;
    428 }
    429 
    430 static inline void setContainerAndOffsetForRange(Node* node, int offset, Node*& containerNode, int& offsetInContainer)
    431 {
    432     if (node->isTextNode()) {
    433         containerNode = node;
    434         offsetInContainer = offset;
    435     } else {
    436         containerNode = node->parentNode();
    437         offsetInContainer = node->nodeIndex() + offset;
    438     }
    439 }
    440 
    441 PassRefPtr<Range> HTMLTextFormControlElement::selection() const
    442 {
    443     if (!renderer() || !isTextFormControl() || !hasCachedSelection())
    444         return 0;
    445 
    446     int start = m_cachedSelectionStart;
    447     int end = m_cachedSelectionEnd;
    448 
    449     ASSERT(start <= end);
    450     HTMLElement* innerText = innerTextElement();
    451     if (!innerText)
    452         return 0;
    453 
    454     if (!innerText->firstChild())
    455         return Range::create(document(), innerText, 0, innerText, 0);
    456 
    457     int offset = 0;
    458     Node* startNode = 0;
    459     Node* endNode = 0;
    460     for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(node, innerText)) {
    461         ASSERT(!node->firstChild());
    462         ASSERT(node->isTextNode() || node->hasTagName(brTag));
    463         int length = node->isTextNode() ? lastOffsetInNode(node) : 1;
    464 
    465         if (offset <= start && start <= offset + length)
    466             setContainerAndOffsetForRange(node, start - offset, startNode, start);
    467 
    468         if (offset <= end && end <= offset + length) {
    469             setContainerAndOffsetForRange(node, end - offset, endNode, end);
    470             break;
    471         }
    472 
    473         offset += length;
    474     }
    475 
    476     if (!startNode || !endNode)
    477         return 0;
    478 
    479     return Range::create(document(), startNode, start, endNode, end);
    480 }
    481 
    482 void HTMLTextFormControlElement::restoreCachedSelection()
    483 {
    484     setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, m_cachedSelectionDirection);
    485 }
    486 
    487 void HTMLTextFormControlElement::selectionChanged(bool userTriggered)
    488 {
    489     if (!renderer() || !isTextFormControl())
    490         return;
    491 
    492     // selectionStart() or selectionEnd() will return cached selection when this node doesn't have focus
    493     cacheSelection(computeSelectionStart(), computeSelectionEnd(), computeSelectionDirection());
    494 
    495     if (Frame* frame = document()->frame()) {
    496         if (frame->selection()->isRange() && userTriggered)
    497             dispatchEvent(Event::create(eventNames().selectEvent, true, false));
    498     }
    499 }
    500 
    501 void HTMLTextFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    502 {
    503     if (name == placeholderAttr) {
    504         updatePlaceholderVisibility(true);
    505         UseCounter::count(document(), UseCounter::PlaceholderAttribute);
    506     } else
    507         HTMLFormControlElementWithState::parseAttribute(name, value);
    508 }
    509 
    510 bool HTMLTextFormControlElement::lastChangeWasUserEdit() const
    511 {
    512     if (!isTextFormControl())
    513         return false;
    514     return m_lastChangeWasUserEdit;
    515 }
    516 
    517 void HTMLTextFormControlElement::setInnerTextValue(const String& value)
    518 {
    519     if (!isTextFormControl())
    520         return;
    521 
    522     bool textIsChanged = value != innerTextValue();
    523     if (textIsChanged || !innerTextElement()->hasChildNodes()) {
    524         if (textIsChanged && document() && renderer()) {
    525             if (AXObjectCache* cache = document()->existingAXObjectCache())
    526                 cache->postNotification(this, AXObjectCache::AXValueChanged, false);
    527         }
    528         innerTextElement()->setInnerText(value, ASSERT_NO_EXCEPTION);
    529 
    530         if (value.endsWith('\n') || value.endsWith('\r'))
    531             innerTextElement()->appendChild(HTMLBRElement::create(document()), ASSERT_NO_EXCEPTION, AttachLazily);
    532     }
    533 
    534     setFormControlValueMatchesRenderer(true);
    535 }
    536 
    537 static String finishText(StringBuilder& result)
    538 {
    539     // Remove one trailing newline; there's always one that's collapsed out by rendering.
    540     size_t size = result.length();
    541     if (size && result[size - 1] == '\n')
    542         result.resize(--size);
    543     return result.toString();
    544 }
    545 
    546 String HTMLTextFormControlElement::innerTextValue() const
    547 {
    548     HTMLElement* innerText = innerTextElement();
    549     if (!innerText || !isTextFormControl())
    550         return emptyString();
    551 
    552     StringBuilder result;
    553     for (Node* node = innerText; node; node = NodeTraversal::next(node, innerText)) {
    554         if (node->hasTagName(brTag))
    555             result.append(newlineCharacter);
    556         else if (node->isTextNode())
    557             result.append(toText(node)->data());
    558     }
    559     return finishText(result);
    560 }
    561 
    562 static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
    563 {
    564     RootInlineBox* next;
    565     for (; line; line = next) {
    566         next = line->nextRootBox();
    567         if (next && !line->endsWithBreak()) {
    568             ASSERT(line->lineBreakObj());
    569             breakNode = line->lineBreakObj()->node();
    570             breakOffset = line->lineBreakPos();
    571             line = next;
    572             return;
    573         }
    574     }
    575     breakNode = 0;
    576     breakOffset = 0;
    577 }
    578 
    579 String HTMLTextFormControlElement::valueWithHardLineBreaks() const
    580 {
    581     // FIXME: It's not acceptable to ignore the HardWrap setting when there is no renderer.
    582     // While we have no evidence this has ever been a practical problem, it would be best to fix it some day.
    583     HTMLElement* innerText = innerTextElement();
    584     if (!innerText || !isTextFormControl())
    585         return value();
    586 
    587     RenderBlock* renderer = toRenderBlock(innerText->renderer());
    588     if (!renderer)
    589         return value();
    590 
    591     Node* breakNode;
    592     unsigned breakOffset;
    593     RootInlineBox* line = renderer->firstRootBox();
    594     if (!line)
    595         return value();
    596 
    597     getNextSoftBreak(line, breakNode, breakOffset);
    598 
    599     StringBuilder result;
    600     for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(node, innerText)) {
    601         if (node->hasTagName(brTag))
    602             result.append(newlineCharacter);
    603         else if (node->isTextNode()) {
    604             String data = toText(node)->data();
    605             unsigned length = data.length();
    606             unsigned position = 0;
    607             while (breakNode == node && breakOffset <= length) {
    608                 if (breakOffset > position) {
    609                     result.append(data, position, breakOffset - position);
    610                     position = breakOffset;
    611                     result.append(newlineCharacter);
    612                 }
    613                 getNextSoftBreak(line, breakNode, breakOffset);
    614             }
    615             result.append(data, position, length - position);
    616         }
    617         while (breakNode == node)
    618             getNextSoftBreak(line, breakNode, breakOffset);
    619     }
    620     return finishText(result);
    621 }
    622 
    623 HTMLTextFormControlElement* enclosingTextFormControl(const Position& position)
    624 {
    625     ASSERT(position.isNull() || position.anchorType() == Position::PositionIsOffsetInAnchor
    626         || position.containerNode() || !position.anchorNode()->shadowHost()
    627         || (position.anchorNode()->parentNode() && position.anchorNode()->parentNode()->isShadowRoot()));
    628 
    629     Node* container = position.containerNode();
    630     if (!container)
    631         return 0;
    632     Element* ancestor = container->shadowHost();
    633     return ancestor && isHTMLTextFormControlElement(ancestor) ? toHTMLTextFormControlElement(ancestor) : 0;
    634 }
    635 
    636 static const Element* parentHTMLElement(const Element* element)
    637 {
    638     while (element) {
    639         element = element->parentElement();
    640         if (element && element->isHTMLElement())
    641             return element;
    642     }
    643     return 0;
    644 }
    645 
    646 String HTMLTextFormControlElement::directionForFormData() const
    647 {
    648     for (const Element* element = this; element; element = parentHTMLElement(element)) {
    649         const AtomicString& dirAttributeValue = element->fastGetAttribute(dirAttr);
    650         if (dirAttributeValue.isNull())
    651             continue;
    652 
    653         if (equalIgnoringCase(dirAttributeValue, "rtl") || equalIgnoringCase(dirAttributeValue, "ltr"))
    654             return dirAttributeValue;
    655 
    656         if (equalIgnoringCase(dirAttributeValue, "auto")) {
    657             bool isAuto;
    658             TextDirection textDirection = static_cast<const HTMLElement*>(element)->directionalityIfhasDirAutoAttribute(isAuto);
    659             return textDirection == RTL ? "rtl" : "ltr";
    660         }
    661     }
    662 
    663     return "ltr";
    664 }
    665 
    666 } // namespace Webcore
    667