• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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 
HTMLTextFormControlElement(const QualifiedName & tagName,Document & doc,HTMLFormElement * form)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 
~HTMLTextFormControlElement()62 HTMLTextFormControlElement::~HTMLTextFormControlElement()
63 {
64 }
65 
insertedInto(ContainerNode * insertionPoint)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 
dispatchFocusEvent(Element * oldFocusedElement,FocusDirection direction)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 
dispatchBlurEvent(Element * newFocusedElement)84 void HTMLTextFormControlElement::dispatchBlurEvent(Element* newFocusedElement)
85 {
86     if (supportsPlaceholder())
87         updatePlaceholderVisibility(false);
88     handleBlurEvent();
89     HTMLFormControlElementWithState::dispatchBlurEvent(newFocusedElement);
90 }
91 
defaultEventHandler(Event * event)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 
forwardEvent(Event * event)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 
strippedPlaceholder() const110 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 
isNotLineBreak(UChar ch)130 static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; }
131 
isPlaceholderEmpty() const132 bool HTMLTextFormControlElement::isPlaceholderEmpty() const
133 {
134     const AtomicString& attributeValue = fastGetAttribute(placeholderAttr);
135     return attributeValue.string().find(isNotLineBreak) == kNotFound;
136 }
137 
placeholderShouldBeVisible() const138 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 
placeholderElement() const148 HTMLElement* HTMLTextFormControlElement::placeholderElement() const
149 {
150     return toHTMLElement(userAgentShadowRoot()->getElementById(ShadowElementNames::placeholder()));
151 }
152 
updatePlaceholderVisibility(bool placeholderValueChanged)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 
setSelectionStart(int start)165 void HTMLTextFormControlElement::setSelectionStart(int start)
166 {
167     setSelectionRange(start, max(start, selectionEnd()), selectionDirection());
168 }
169 
setSelectionEnd(int end)170 void HTMLTextFormControlElement::setSelectionEnd(int end)
171 {
172     setSelectionRange(min(end, selectionStart()), end, selectionDirection());
173 }
174 
setSelectionDirection(const String & direction)175 void HTMLTextFormControlElement::setSelectionDirection(const String& direction)
176 {
177     setSelectionRange(selectionStart(), selectionEnd(), direction);
178 }
179 
select()180 void HTMLTextFormControlElement::select()
181 {
182     setSelectionRange(0, numeric_limits<int>::max(), SelectionHasNoDirection);
183 }
184 
selectedText() const185 String HTMLTextFormControlElement::selectedText() const
186 {
187     if (!isTextFormControl())
188         return String();
189     return value().substring(selectionStart(), selectionEnd() - selectionStart());
190 }
191 
dispatchFormControlChangeEvent()192 void HTMLTextFormControlElement::dispatchFormControlChangeEvent()
193 {
194     if (m_textAsOfLastFormControlChangeEvent != value()) {
195         HTMLElement::dispatchChangeEvent();
196         setTextAsOfLastFormControlChangeEvent(value());
197     }
198     setChangedSinceLastFormControlChangeEvent(false);
199 }
200 
hasVisibleTextArea(RenderObject * renderer,HTMLElement * innerText)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 
setRangeText(const String & replacement,ExceptionState & exceptionState)208 void HTMLTextFormControlElement::setRangeText(const String& replacement, ExceptionState& exceptionState)
209 {
210     setRangeText(replacement, selectionStart(), selectionEnd(), String(), exceptionState);
211 }
212 
setRangeText(const String & replacement,unsigned start,unsigned end,const String & selectionMode,ExceptionState & exceptionState)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 
setSelectionRange(int start,int end,const String & directionString)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 
setSelectionRange(int start,int end,TextFieldSelectionDirection direction)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 
visiblePositionForIndex(int index) const316 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 
indexForVisiblePosition(const VisiblePosition & pos) const327 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 
selectionStart() const339 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 
computeSelectionStart() const349 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 
selectionEnd() const359 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 
computeSelectionEnd() const368 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 
directionString(TextFieldSelectionDirection direction)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 
selectionDirection() const397 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 
computeSelectionDirection() const407 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 
setContainerAndOffsetForRange(Node * node,int offset,Node * & containerNode,int & offsetInContainer)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 
selection() const429 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 
restoreCachedSelection()470 void HTMLTextFormControlElement::restoreCachedSelection()
471 {
472     setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, m_cachedSelectionDirection);
473 }
474 
selectionChanged(bool userTriggered)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 
parseAttribute(const QualifiedName & name,const AtomicString & value)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 
lastChangeWasUserEdit() const498 bool HTMLTextFormControlElement::lastChangeWasUserEdit() const
499 {
500     if (!isTextFormControl())
501         return false;
502     return m_lastChangeWasUserEdit;
503 }
504 
setInnerTextValue(const String & value)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 
finishText(StringBuilder & result)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 
innerTextValue() const534 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 
getNextSoftBreak(RootInlineBox * & line,Node * & breakNode,unsigned & breakOffset)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 
valueWithHardLineBreaks() const567 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 
enclosingTextFormControl(const Position & position)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 
parentHTMLElement(const Element * element)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 
directionForFormData() const634 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 
innerTextElement() const654 HTMLElement* HTMLTextFormControlElement::innerTextElement() const
655 {
656     return toHTMLElement(userAgentShadowRoot()->getElementById(ShadowElementNames::innerEditor()));
657 }
658 
659 } // namespace Webcore
660