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/NodeTraversal.h"
     34 #include "core/dom/Text.h"
     35 #include "core/dom/shadow/ShadowRoot.h"
     36 #include "core/editing/FrameSelection.h"
     37 #include "core/editing/TextIterator.h"
     38 #include "core/events/Event.h"
     39 #include "core/events/ThreadLocalEventNames.h"
     40 #include "core/html/HTMLBRElement.h"
     41 #include "core/html/shadow/ShadowElementNames.h"
     42 #include "core/frame/Frame.h"
     43 #include "core/frame/UseCounter.h"
     44 #include "core/rendering/RenderBlock.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() == EventTypeNames::webkitEditableContentChanged && 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() == EventTypeNames::blur || event->type() == EventTypeNames::focus)
    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) == kNotFound;
    136 }
    137 
    138 bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
    139 {
    140     return supportsPlaceholder()
    141         && isEmptyValue()
    142         && isEmptySuggestedValue()
    143         && !isPlaceholderEmpty()
    144         && (document().focusedElement() != this || (RenderTheme::theme().shouldShowPlaceholderWhenFocused()))
    145         && (!renderer() || renderer()->style()->visibility() == VISIBLE);
    146 }
    147 
    148 HTMLElement* HTMLTextFormControlElement::placeholderElement() const
    149 {
    150     return toHTMLElement(userAgentShadowRoot()->getElementById(ShadowElementNames::placeholder()));
    151 }
    152 
    153 void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged)
    154 {
    155     if (!supportsPlaceholder())
    156         return;
    157     if (!placeholderElement() || placeholderValueChanged)
    158         updatePlaceholderText();
    159     HTMLElement* placeholder = placeholderElement();
    160     if (!placeholder)
    161         return;
    162     placeholder->setInlineStyleProperty(CSSPropertyVisibility, placeholderShouldBeVisible() ? CSSValueVisible : CSSValueHidden);
    163 }
    164 
    165 void HTMLTextFormControlElement::setSelectionStart(int start)
    166 {
    167     setSelectionRange(start, max(start, selectionEnd()), selectionDirection());
    168 }
    169 
    170 void HTMLTextFormControlElement::setSelectionEnd(int end)
    171 {
    172     setSelectionRange(min(end, selectionStart()), end, selectionDirection());
    173 }
    174 
    175 void HTMLTextFormControlElement::setSelectionDirection(const String& direction)
    176 {
    177     setSelectionRange(selectionStart(), selectionEnd(), direction);
    178 }
    179 
    180 void HTMLTextFormControlElement::select()
    181 {
    182     setSelectionRange(0, numeric_limits<int>::max(), SelectionHasNoDirection);
    183 }
    184 
    185 String HTMLTextFormControlElement::selectedText() const
    186 {
    187     if (!isTextFormControl())
    188         return String();
    189     return value().substring(selectionStart(), selectionEnd() - selectionStart());
    190 }
    191 
    192 void HTMLTextFormControlElement::dispatchFormControlChangeEvent()
    193 {
    194     if (m_textAsOfLastFormControlChangeEvent != value()) {
    195         HTMLElement::dispatchChangeEvent();
    196         setTextAsOfLastFormControlChangeEvent(value());
    197     }
    198     setChangedSinceLastFormControlChangeEvent(false);
    199 }
    200 
    201 static inline bool hasVisibleTextArea(RenderObject* renderer, HTMLElement* innerText)
    202 {
    203     ASSERT(renderer);
    204     return renderer->style()->visibility() != HIDDEN && innerText && innerText->renderer() && innerText->renderBox()->height();
    205 }
    206 
    207 
    208 void HTMLTextFormControlElement::setRangeText(const String& replacement, ExceptionState& exceptionState)
    209 {
    210     setRangeText(replacement, selectionStart(), selectionEnd(), String(), exceptionState);
    211 }
    212 
    213 void HTMLTextFormControlElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionState& exceptionState)
    214 {
    215     if (start > end) {
    216         exceptionState.throwDOMException(IndexSizeError, "The provided start value (" + String::number(start) + ") is larger than the provided end value (" + String::number(end) + ").");
    217         return;
    218     }
    219 
    220     String text = innerTextValue();
    221     unsigned textLength = text.length();
    222     unsigned replacementLength = replacement.length();
    223     unsigned newSelectionStart = selectionStart();
    224     unsigned newSelectionEnd = selectionEnd();
    225 
    226     start = std::min(start, textLength);
    227     end = std::min(end, textLength);
    228 
    229     if (start < end)
    230         text.replace(start, end - start, replacement);
    231     else
    232         text.insert(replacement, start);
    233 
    234     setInnerTextValue(text);
    235 
    236     // FIXME: What should happen to the value (as in value()) if there's no renderer?
    237     if (!renderer())
    238         return;
    239 
    240     subtreeHasChanged();
    241 
    242     if (equalIgnoringCase(selectionMode, "select")) {
    243         newSelectionStart = start;
    244         newSelectionEnd = start + replacementLength;
    245     } else if (equalIgnoringCase(selectionMode, "start"))
    246         newSelectionStart = newSelectionEnd = start;
    247     else if (equalIgnoringCase(selectionMode, "end"))
    248         newSelectionStart = newSelectionEnd = start + replacementLength;
    249     else {
    250         // Default is "preserve".
    251         long delta = replacementLength - (end - start);
    252 
    253         if (newSelectionStart > end)
    254             newSelectionStart += delta;
    255         else if (newSelectionStart > start)
    256             newSelectionStart = start;
    257 
    258         if (newSelectionEnd > end)
    259             newSelectionEnd += delta;
    260         else if (newSelectionEnd > start)
    261             newSelectionEnd = start + replacementLength;
    262     }
    263 
    264     setSelectionRange(newSelectionStart, newSelectionEnd, SelectionHasNoDirection);
    265 }
    266 
    267 void HTMLTextFormControlElement::setSelectionRange(int start, int end, const String& directionString)
    268 {
    269     TextFieldSelectionDirection direction = SelectionHasNoDirection;
    270     if (directionString == "forward")
    271         direction = SelectionHasForwardDirection;
    272     else if (directionString == "backward")
    273         direction = SelectionHasBackwardDirection;
    274 
    275     return setSelectionRange(start, end, direction);
    276 }
    277 
    278 void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction)
    279 {
    280     document().updateLayoutIgnorePendingStylesheets();
    281 
    282     if (!renderer() || !renderer()->isTextControl())
    283         return;
    284 
    285     end = max(end, 0);
    286     start = min(max(start, 0), end);
    287 
    288     if (!hasVisibleTextArea(renderer(), innerTextElement())) {
    289         cacheSelection(start, end, direction);
    290         return;
    291     }
    292     VisiblePosition startPosition = visiblePositionForIndex(start);
    293     VisiblePosition endPosition;
    294     if (start == end)
    295         endPosition = startPosition;
    296     else
    297         endPosition = visiblePositionForIndex(end);
    298 
    299     // startPosition and endPosition can be null position for example when
    300     // "-webkit-user-select: none" style attribute is specified.
    301     if (startPosition.isNotNull() && endPosition.isNotNull()) {
    302         ASSERT(startPosition.deepEquivalent().deprecatedNode()->shadowHost() == this
    303             && endPosition.deepEquivalent().deprecatedNode()->shadowHost() == this);
    304     }
    305     VisibleSelection newSelection;
    306     if (direction == SelectionHasBackwardDirection)
    307         newSelection = VisibleSelection(endPosition, startPosition);
    308     else
    309         newSelection = VisibleSelection(startPosition, endPosition);
    310     newSelection.setIsDirectional(direction != SelectionHasNoDirection);
    311 
    312     if (Frame* frame = document().frame())
    313         frame->selection().setSelection(newSelection);
    314 }
    315 
    316 VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) const
    317 {
    318     if (index <= 0)
    319         return VisiblePosition(firstPositionInNode(innerTextElement()), DOWNSTREAM);
    320     RefPtr<Range> range = Range::create(document());
    321     range->selectNodeContents(innerTextElement(), ASSERT_NO_EXCEPTION);
    322     CharacterIterator it(range.get());
    323     it.advance(index - 1);
    324     return VisiblePosition(it.range()->endPosition(), UPSTREAM);
    325 }
    326 
    327 int HTMLTextFormControlElement::indexForVisiblePosition(const VisiblePosition& pos) const
    328 {
    329     Position indexPosition = pos.deepEquivalent().parentAnchoredEquivalent();
    330     if (enclosingTextFormControl(indexPosition) != this)
    331         return 0;
    332     ASSERT(indexPosition.document());
    333     RefPtr<Range> range = Range::create(*indexPosition.document());
    334     range->setStart(innerTextElement(), 0, ASSERT_NO_EXCEPTION);
    335     range->setEnd(indexPosition.containerNode(), indexPosition.offsetInContainerNode(), ASSERT_NO_EXCEPTION);
    336     return TextIterator::rangeLength(range.get());
    337 }
    338 
    339 int HTMLTextFormControlElement::selectionStart() const
    340 {
    341     if (!isTextFormControl())
    342         return 0;
    343     if (document().focusedElement() != this && hasCachedSelection())
    344         return m_cachedSelectionStart;
    345 
    346     return computeSelectionStart();
    347 }
    348 
    349 int HTMLTextFormControlElement::computeSelectionStart() const
    350 {
    351     ASSERT(isTextFormControl());
    352     Frame* frame = document().frame();
    353     if (!frame)
    354         return 0;
    355 
    356     return indexForVisiblePosition(frame->selection().start());
    357 }
    358 
    359 int HTMLTextFormControlElement::selectionEnd() const
    360 {
    361     if (!isTextFormControl())
    362         return 0;
    363     if (document().focusedElement() != this && hasCachedSelection())
    364         return m_cachedSelectionEnd;
    365     return computeSelectionEnd();
    366 }
    367 
    368 int HTMLTextFormControlElement::computeSelectionEnd() const
    369 {
    370     ASSERT(isTextFormControl());
    371     Frame* frame = document().frame();
    372     if (!frame)
    373         return 0;
    374 
    375     return indexForVisiblePosition(frame->selection().end());
    376 }
    377 
    378 static const AtomicString& directionString(TextFieldSelectionDirection direction)
    379 {
    380     DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::ConstructFromLiteral));
    381     DEFINE_STATIC_LOCAL(const AtomicString, forward, ("forward", AtomicString::ConstructFromLiteral));
    382     DEFINE_STATIC_LOCAL(const AtomicString, backward, ("backward", AtomicString::ConstructFromLiteral));
    383 
    384     switch (direction) {
    385     case SelectionHasNoDirection:
    386         return none;
    387     case SelectionHasForwardDirection:
    388         return forward;
    389     case SelectionHasBackwardDirection:
    390         return backward;
    391     }
    392 
    393     ASSERT_NOT_REACHED();
    394     return none;
    395 }
    396 
    397 const AtomicString& HTMLTextFormControlElement::selectionDirection() const
    398 {
    399     if (!isTextFormControl())
    400         return directionString(SelectionHasNoDirection);
    401     if (document().focusedElement() != this && hasCachedSelection())
    402         return directionString(m_cachedSelectionDirection);
    403 
    404     return directionString(computeSelectionDirection());
    405 }
    406 
    407 TextFieldSelectionDirection HTMLTextFormControlElement::computeSelectionDirection() const
    408 {
    409     ASSERT(isTextFormControl());
    410     Frame* frame = document().frame();
    411     if (!frame)
    412         return SelectionHasNoDirection;
    413 
    414     const VisibleSelection& selection = frame->selection().selection();
    415     return selection.isDirectional() ? (selection.isBaseFirst() ? SelectionHasForwardDirection : SelectionHasBackwardDirection) : SelectionHasNoDirection;
    416 }
    417 
    418 static inline void setContainerAndOffsetForRange(Node* node, int offset, Node*& containerNode, int& offsetInContainer)
    419 {
    420     if (node->isTextNode()) {
    421         containerNode = node;
    422         offsetInContainer = offset;
    423     } else {
    424         containerNode = node->parentNode();
    425         offsetInContainer = node->nodeIndex() + offset;
    426     }
    427 }
    428 
    429 PassRefPtr<Range> HTMLTextFormControlElement::selection() const
    430 {
    431     if (!renderer() || !isTextFormControl() || !hasCachedSelection())
    432         return 0;
    433 
    434     int start = m_cachedSelectionStart;
    435     int end = m_cachedSelectionEnd;
    436 
    437     ASSERT(start <= end);
    438     HTMLElement* innerText = innerTextElement();
    439     if (!innerText)
    440         return 0;
    441 
    442     if (!innerText->firstChild())
    443         return Range::create(document(), innerText, 0, innerText, 0);
    444 
    445     int offset = 0;
    446     Node* startNode = 0;
    447     Node* endNode = 0;
    448     for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(*node, innerText)) {
    449         ASSERT(!node->firstChild());
    450         ASSERT(node->isTextNode() || node->hasTagName(brTag));
    451         int length = node->isTextNode() ? lastOffsetInNode(node) : 1;
    452 
    453         if (offset <= start && start <= offset + length)
    454             setContainerAndOffsetForRange(node, start - offset, startNode, start);
    455 
    456         if (offset <= end && end <= offset + length) {
    457             setContainerAndOffsetForRange(node, end - offset, endNode, end);
    458             break;
    459         }
    460 
    461         offset += length;
    462     }
    463 
    464     if (!startNode || !endNode)
    465         return 0;
    466 
    467     return Range::create(document(), startNode, start, endNode, end);
    468 }
    469 
    470 void HTMLTextFormControlElement::restoreCachedSelection()
    471 {
    472     setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, m_cachedSelectionDirection);
    473 }
    474 
    475 void HTMLTextFormControlElement::selectionChanged(bool userTriggered)
    476 {
    477     if (!renderer() || !isTextFormControl())
    478         return;
    479 
    480     // selectionStart() or selectionEnd() will return cached selection when this node doesn't have focus
    481     cacheSelection(computeSelectionStart(), computeSelectionEnd(), computeSelectionDirection());
    482 
    483     if (Frame* frame = document().frame()) {
    484         if (frame->selection().isRange() && userTriggered)
    485             dispatchEvent(Event::createBubble(EventTypeNames::select));
    486     }
    487 }
    488 
    489 void HTMLTextFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    490 {
    491     if (name == placeholderAttr) {
    492         updatePlaceholderVisibility(true);
    493         UseCounter::count(document(), UseCounter::PlaceholderAttribute);
    494     } else
    495         HTMLFormControlElementWithState::parseAttribute(name, value);
    496 }
    497 
    498 bool HTMLTextFormControlElement::lastChangeWasUserEdit() const
    499 {
    500     if (!isTextFormControl())
    501         return false;
    502     return m_lastChangeWasUserEdit;
    503 }
    504 
    505 void HTMLTextFormControlElement::setInnerTextValue(const String& value)
    506 {
    507     if (!isTextFormControl())
    508         return;
    509 
    510     bool textIsChanged = value != innerTextValue();
    511     if (textIsChanged || !innerTextElement()->hasChildNodes()) {
    512         if (textIsChanged && renderer()) {
    513             if (AXObjectCache* cache = document().existingAXObjectCache())
    514                 cache->postNotification(this, AXObjectCache::AXValueChanged, false);
    515         }
    516         innerTextElement()->setInnerText(value, ASSERT_NO_EXCEPTION);
    517 
    518         if (value.endsWith('\n') || value.endsWith('\r'))
    519             innerTextElement()->appendChild(HTMLBRElement::create(document()));
    520     }
    521 
    522     setFormControlValueMatchesRenderer(true);
    523 }
    524 
    525 static String finishText(StringBuilder& result)
    526 {
    527     // Remove one trailing newline; there's always one that's collapsed out by rendering.
    528     size_t size = result.length();
    529     if (size && result[size - 1] == '\n')
    530         result.resize(--size);
    531     return result.toString();
    532 }
    533 
    534 String HTMLTextFormControlElement::innerTextValue() const
    535 {
    536     HTMLElement* innerText = innerTextElement();
    537     if (!innerText || !isTextFormControl())
    538         return emptyString();
    539 
    540     StringBuilder result;
    541     for (Node* node = innerText; node; node = NodeTraversal::next(*node, innerText)) {
    542         if (node->hasTagName(brTag))
    543             result.append(newlineCharacter);
    544         else if (node->isTextNode())
    545             result.append(toText(node)->data());
    546     }
    547     return finishText(result);
    548 }
    549 
    550 static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
    551 {
    552     RootInlineBox* next;
    553     for (; line; line = next) {
    554         next = line->nextRootBox();
    555         if (next && !line->endsWithBreak()) {
    556             ASSERT(line->lineBreakObj());
    557             breakNode = line->lineBreakObj()->node();
    558             breakOffset = line->lineBreakPos();
    559             line = next;
    560             return;
    561         }
    562     }
    563     breakNode = 0;
    564     breakOffset = 0;
    565 }
    566 
    567 String HTMLTextFormControlElement::valueWithHardLineBreaks() const
    568 {
    569     // FIXME: It's not acceptable to ignore the HardWrap setting when there is no renderer.
    570     // While we have no evidence this has ever been a practical problem, it would be best to fix it some day.
    571     HTMLElement* innerText = innerTextElement();
    572     if (!innerText || !isTextFormControl())
    573         return value();
    574 
    575     RenderBlock* renderer = toRenderBlock(innerText->renderer());
    576     if (!renderer)
    577         return value();
    578 
    579     Node* breakNode;
    580     unsigned breakOffset;
    581     RootInlineBox* line = renderer->firstRootBox();
    582     if (!line)
    583         return value();
    584 
    585     getNextSoftBreak(line, breakNode, breakOffset);
    586 
    587     StringBuilder result;
    588     for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(*node, innerText)) {
    589         if (node->hasTagName(brTag))
    590             result.append(newlineCharacter);
    591         else if (node->isTextNode()) {
    592             String data = toText(node)->data();
    593             unsigned length = data.length();
    594             unsigned position = 0;
    595             while (breakNode == node && breakOffset <= length) {
    596                 if (breakOffset > position) {
    597                     result.append(data, position, breakOffset - position);
    598                     position = breakOffset;
    599                     result.append(newlineCharacter);
    600                 }
    601                 getNextSoftBreak(line, breakNode, breakOffset);
    602             }
    603             result.append(data, position, length - position);
    604         }
    605         while (breakNode == node)
    606             getNextSoftBreak(line, breakNode, breakOffset);
    607     }
    608     return finishText(result);
    609 }
    610 
    611 HTMLTextFormControlElement* enclosingTextFormControl(const Position& position)
    612 {
    613     ASSERT(position.isNull() || position.anchorType() == Position::PositionIsOffsetInAnchor
    614         || position.containerNode() || !position.anchorNode()->shadowHost()
    615         || (position.anchorNode()->parentNode() && position.anchorNode()->parentNode()->isShadowRoot()));
    616 
    617     Node* container = position.containerNode();
    618     if (!container)
    619         return 0;
    620     Element* ancestor = container->shadowHost();
    621     return ancestor && isHTMLTextFormControlElement(ancestor) ? toHTMLTextFormControlElement(ancestor) : 0;
    622 }
    623 
    624 static const HTMLElement* parentHTMLElement(const Element* element)
    625 {
    626     while (element) {
    627         element = element->parentElement();
    628         if (element && element->isHTMLElement())
    629             return toHTMLElement(element);
    630     }
    631     return 0;
    632 }
    633 
    634 String HTMLTextFormControlElement::directionForFormData() const
    635 {
    636     for (const HTMLElement* element = this; element; element = parentHTMLElement(element)) {
    637         const AtomicString& dirAttributeValue = element->fastGetAttribute(dirAttr);
    638         if (dirAttributeValue.isNull())
    639             continue;
    640 
    641         if (equalIgnoringCase(dirAttributeValue, "rtl") || equalIgnoringCase(dirAttributeValue, "ltr"))
    642             return dirAttributeValue;
    643 
    644         if (equalIgnoringCase(dirAttributeValue, "auto")) {
    645             bool isAuto;
    646             TextDirection textDirection = element->directionalityIfhasDirAutoAttribute(isAuto);
    647             return textDirection == RTL ? "rtl" : "ltr";
    648         }
    649     }
    650 
    651     return "ltr";
    652 }
    653 
    654 HTMLElement* HTMLTextFormControlElement::innerTextElement() const
    655 {
    656     return toHTMLElement(userAgentShadowRoot()->getElementById(ShadowElementNames::innerEditor()));
    657 }
    658 
    659 } // namespace Webcore
    660