Have is<>(T*) function do a null check on the pointer argument
[WebKit-https.git] / Source / WebCore / html / HTMLTextFormControlElement.cpp
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, 2014 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 "Page.h"
42 #include "RenderBlockFlow.h"
43 #include "RenderTextControlSingleLine.h"
44 #include "RenderTheme.h"
45 #include "ShadowRoot.h"
46 #include "Text.h"
47 #include "TextControlInnerElements.h"
48 #include "htmlediting.h"
49 #include <wtf/text/StringBuilder.h>
50
51 namespace WebCore {
52
53 using namespace HTMLNames;
54
55 static Position positionForIndex(TextControlInnerTextElement*, unsigned);
56
57 HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
58     : HTMLFormControlElementWithState(tagName, document, form)
59     , m_cachedSelectionStart(-1)
60     , m_cachedSelectionEnd(-1)
61     , m_cachedSelectionDirection(SelectionHasNoDirection)
62     , m_lastChangeWasUserEdit(false)
63     , m_isPlaceholderVisible(false)
64 {
65 }
66
67 HTMLTextFormControlElement::~HTMLTextFormControlElement()
68 {
69 }
70
71 bool HTMLTextFormControlElement::childShouldCreateRenderer(const Node& child) const
72 {
73     // FIXME: We shouldn't force the pseudo elements down into the shadow, but
74     // this perserves the current behavior of WebKit.
75     if (child.isPseudoElement())
76         return HTMLFormControlElementWithState::childShouldCreateRenderer(child);
77     return hasShadowRootParent(child) && HTMLFormControlElementWithState::childShouldCreateRenderer(child);
78 }
79
80 Node::InsertionNotificationRequest HTMLTextFormControlElement::insertedInto(ContainerNode& insertionPoint)
81 {
82     HTMLFormControlElementWithState::insertedInto(insertionPoint);
83     if (!insertionPoint.inDocument())
84         return InsertionDone;
85     String initialValue = value();
86     setTextAsOfLastFormControlChangeEvent(initialValue.isNull() ? emptyString() : initialValue);
87     return InsertionDone;
88 }
89
90 void HTMLTextFormControlElement::dispatchFocusEvent(PassRefPtr<Element> oldFocusedElement, FocusDirection direction)
91 {
92     if (supportsPlaceholder())
93         updatePlaceholderVisibility();
94     handleFocusEvent(oldFocusedElement.get(), direction);
95     HTMLFormControlElementWithState::dispatchFocusEvent(oldFocusedElement, direction);
96 }
97
98 void HTMLTextFormControlElement::dispatchBlurEvent(PassRefPtr<Element> newFocusedElement)
99 {
100     if (supportsPlaceholder())
101         updatePlaceholderVisibility();
102     handleBlurEvent();
103     HTMLFormControlElementWithState::dispatchBlurEvent(newFocusedElement);
104 }
105
106 void HTMLTextFormControlElement::didEditInnerTextValue()
107 {
108     if (!isTextFormControl())
109         return;
110
111     m_lastChangeWasUserEdit = true;
112     subtreeHasChanged();
113 }
114
115 void HTMLTextFormControlElement::forwardEvent(Event* event)
116 {
117     if (event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)
118         return;
119     innerTextElement()->defaultEventHandler(event);
120 }
121
122 String HTMLTextFormControlElement::strippedPlaceholder() const
123 {
124     // According to the HTML5 specification, we need to remove CR and LF from
125     // the attribute value.
126     const AtomicString& attributeValue = fastGetAttribute(placeholderAttr);
127     if (!attributeValue.contains(newlineCharacter) && !attributeValue.contains(carriageReturn))
128         return attributeValue;
129
130     StringBuilder stripped;
131     unsigned length = attributeValue.length();
132     stripped.reserveCapacity(length);
133     for (unsigned i = 0; i < length; ++i) {
134         UChar character = attributeValue[i];
135         if (character == newlineCharacter || character == carriageReturn)
136             continue;
137         stripped.append(character);
138     }
139     return stripped.toString();
140 }
141
142 static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; }
143
144 bool HTMLTextFormControlElement::isPlaceholderEmpty() const
145 {
146     const AtomicString& attributeValue = fastGetAttribute(placeholderAttr);
147     return attributeValue.string().find(isNotLineBreak) == notFound;
148 }
149
150 bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
151 {
152     // This function is used by the style resolver to match the :placeholder-shown pseudo class.
153     // Since it is used for styling, it must not use any value depending on the style.
154     return supportsPlaceholder()
155         && isEmptyValue()
156         && !isPlaceholderEmpty()
157         && (document().focusedElement() != this || (document().page()->theme().shouldShowPlaceholderWhenFocused()));
158 }
159
160 void HTMLTextFormControlElement::updatePlaceholderVisibility()
161 {
162     bool placeHolderWasVisible = m_isPlaceholderVisible;
163     m_isPlaceholderVisible = placeholderShouldBeVisible();
164
165     if (placeHolderWasVisible == m_isPlaceholderVisible)
166         return;
167
168     setNeedsStyleRecalc();
169
170     if (HTMLElement* placeholder = placeholderElement())
171         placeholder->setInlineStyleProperty(CSSPropertyDisplay, m_isPlaceholderVisible ? CSSValueBlock : CSSValueNone, true);
172 }
173
174 void HTMLTextFormControlElement::setSelectionStart(int start)
175 {
176     setSelectionRange(start, std::max(start, selectionEnd()), selectionDirection());
177 }
178
179 void HTMLTextFormControlElement::setSelectionEnd(int end)
180 {
181     setSelectionRange(std::min(end, selectionStart()), end, selectionDirection());
182 }
183
184 void HTMLTextFormControlElement::setSelectionDirection(const String& direction)
185 {
186     setSelectionRange(selectionStart(), selectionEnd(), direction);
187 }
188
189 void HTMLTextFormControlElement::select()
190 {
191     // FIXME: We should abstract the selection behavior into an EditingBehavior function instead
192     // of hardcoding the behavior using a macro define.
193 #if PLATFORM(IOS)
194     // 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.
195     setSelectionRange(std::numeric_limits<int>::max(), std::numeric_limits<int>::max(), SelectionHasForwardDirection);
196 #else
197     setSelectionRange(0, std::numeric_limits<int>::max(), SelectionHasNoDirection);
198 #endif
199 }
200
201 String HTMLTextFormControlElement::selectedText() const
202 {
203     if (!isTextFormControl())
204         return String();
205     return value().substring(selectionStart(), selectionEnd() - selectionStart());
206 }
207
208 void HTMLTextFormControlElement::dispatchFormControlChangeEvent()
209 {
210     if (m_textAsOfLastFormControlChangeEvent != value()) {
211         dispatchChangeEvent();
212         setTextAsOfLastFormControlChangeEvent(value());
213     }
214     setChangedSinceLastFormControlChangeEvent(false);
215 }
216
217 void HTMLTextFormControlElement::setRangeText(const String& replacement, ExceptionCode& ec)
218 {
219     setRangeText(replacement, selectionStart(), selectionEnd(), String(), ec);
220 }
221
222 void HTMLTextFormControlElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionCode& ec)
223 {
224     if (start > end) {
225         ec = INDEX_SIZE_ERR;
226         return;
227     }
228
229     String text = innerTextValue();
230     unsigned textLength = text.length();
231     unsigned replacementLength = replacement.length();
232     unsigned newSelectionStart = selectionStart();
233     unsigned newSelectionEnd = selectionEnd();
234
235     start = std::min(start, textLength);
236     end = std::min(end, textLength);
237
238     if (start < end)
239         text.replace(start, end - start, replacement);
240     else
241         text.insert(replacement, start);
242
243     setInnerTextValue(text);
244
245     // FIXME: What should happen to the value (as in value()) if there's no renderer?
246     if (!renderer())
247         return;
248
249     subtreeHasChanged();
250
251     if (equalIgnoringCase(selectionMode, "select")) {
252         newSelectionStart = start;
253         newSelectionEnd = start + replacementLength;
254     } else if (equalIgnoringCase(selectionMode, "start"))
255         newSelectionStart = newSelectionEnd = start;
256     else if (equalIgnoringCase(selectionMode, "end"))
257         newSelectionStart = newSelectionEnd = start + replacementLength;
258     else {
259         // Default is "preserve".
260         long delta = replacementLength - (end - start);
261
262         if (newSelectionStart > end)
263             newSelectionStart += delta;
264         else if (newSelectionStart > start)
265             newSelectionStart = start;
266
267         if (newSelectionEnd > end)
268             newSelectionEnd += delta;
269         else if (newSelectionEnd > start)
270             newSelectionEnd = start + replacementLength;
271     }
272
273     setSelectionRange(newSelectionStart, newSelectionEnd, SelectionHasNoDirection);
274 }
275
276 void HTMLTextFormControlElement::setSelectionRange(int start, int end, const String& directionString)
277 {
278     TextFieldSelectionDirection direction = SelectionHasNoDirection;
279     if (directionString == "forward")
280         direction = SelectionHasForwardDirection;
281     else if (directionString == "backward")
282         direction = SelectionHasBackwardDirection;
283
284     return setSelectionRange(start, end, direction);
285 }
286
287 void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction)
288 {
289     if (!isTextFormControl())
290         return;
291
292     end = std::max(end, 0);
293     start = std::min(std::max(start, 0), end);
294
295     TextControlInnerTextElement* innerText = innerTextElement();
296     bool hasFocus = document().focusedElement() == this;
297     if (!hasFocus && innerText) {
298         // FIXME: Removing this synchronous layout requires fixing <https://webkit.org/b/128797>
299         document().updateLayoutIgnorePendingStylesheets();
300         if (RenderElement* rendererTextControl = renderer()) {
301             if (rendererTextControl->style().visibility() == HIDDEN || !innerText->renderBox()->height()) {
302                 cacheSelection(start, end, direction);
303                 return;
304             }
305         }
306     }
307
308     Position startPosition = positionForIndex(innerText, start);
309     Position endPosition;
310     if (start == end)
311         endPosition = startPosition;
312     else {
313         if (direction == SelectionHasBackwardDirection) {
314             endPosition = startPosition;
315             startPosition = positionForIndex(innerText, end);
316         } else
317             endPosition = positionForIndex(innerText, end);
318     }
319
320     if (Frame* frame = document().frame())
321         frame->selection().moveWithoutValidationTo(startPosition, endPosition, direction != SelectionHasNoDirection, !hasFocus);
322 }
323
324 int HTMLTextFormControlElement::indexForVisiblePosition(const VisiblePosition& position) const
325 {
326     TextControlInnerTextElement* innerText = innerTextElement();
327     if (!innerText || !innerText->contains(position.deepEquivalent().anchorNode()))
328         return 0;
329     unsigned index = indexForPosition(position.deepEquivalent());
330     ASSERT(VisiblePosition(positionForIndex(innerTextElement(), index)) == position);
331     return index;
332 }
333
334 VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) const
335 {
336     VisiblePosition position = positionForIndex(innerTextElement(), index);
337     ASSERT(indexForVisiblePosition(position) == index);
338     return position;
339 }
340
341 int HTMLTextFormControlElement::selectionStart() const
342 {
343     if (!isTextFormControl())
344         return 0;
345     if (document().focusedElement() != this && hasCachedSelection())
346         return m_cachedSelectionStart;
347
348     return computeSelectionStart();
349 }
350
351 int HTMLTextFormControlElement::computeSelectionStart() const
352 {
353     ASSERT(isTextFormControl());
354     Frame* frame = document().frame();
355     if (!frame)
356         return 0;
357
358     return indexForPosition(frame->selection().selection().start());
359 }
360
361 int HTMLTextFormControlElement::selectionEnd() const
362 {
363     if (!isTextFormControl())
364         return 0;
365     if (document().focusedElement() != this && hasCachedSelection())
366         return m_cachedSelectionEnd;
367     return computeSelectionEnd();
368 }
369
370 int HTMLTextFormControlElement::computeSelectionEnd() const
371 {
372     ASSERT(isTextFormControl());
373     Frame* frame = document().frame();
374     if (!frame)
375         return 0;
376
377     return indexForPosition(frame->selection().selection().end());
378 }
379
380 static const AtomicString& directionString(TextFieldSelectionDirection direction)
381 {
382     DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::ConstructFromLiteral));
383     DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, forward, ("forward", AtomicString::ConstructFromLiteral));
384     DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, backward, ("backward", AtomicString::ConstructFromLiteral));
385
386     switch (direction) {
387     case SelectionHasNoDirection:
388         return none;
389     case SelectionHasForwardDirection:
390         return forward;
391     case SelectionHasBackwardDirection:
392         return backward;
393     }
394
395     ASSERT_NOT_REACHED();
396     return none;
397 }
398
399 const AtomicString& HTMLTextFormControlElement::selectionDirection() const
400 {
401     if (!isTextFormControl())
402         return directionString(SelectionHasNoDirection);
403     if (document().focusedElement() != this && hasCachedSelection())
404         return directionString(cachedSelectionDirection());
405
406     return directionString(computeSelectionDirection());
407 }
408
409 TextFieldSelectionDirection HTMLTextFormControlElement::computeSelectionDirection() const
410 {
411     ASSERT(isTextFormControl());
412     Frame* frame = document().frame();
413     if (!frame)
414         return SelectionHasNoDirection;
415
416     const VisibleSelection& selection = frame->selection().selection();
417     return selection.isDirectional() ? (selection.isBaseFirst() ? SelectionHasForwardDirection : SelectionHasBackwardDirection) : SelectionHasNoDirection;
418 }
419
420 static inline void setContainerAndOffsetForRange(Node* node, int offset, Node*& containerNode, int& offsetInContainer)
421 {
422     if (node->isTextNode()) {
423         containerNode = node;
424         offsetInContainer = offset;
425     } else {
426         containerNode = node->parentNode();
427         offsetInContainer = node->computeNodeIndex() + offset;
428     }
429 }
430
431 PassRefPtr<Range> HTMLTextFormControlElement::selection() const
432 {
433     if (!renderer() || !isTextFormControl() || !hasCachedSelection())
434         return 0;
435
436     int start = m_cachedSelectionStart;
437     int end = m_cachedSelectionEnd;
438
439     ASSERT(start <= end);
440     TextControlInnerTextElement* innerText = innerTextElement();
441     if (!innerText)
442         return 0;
443
444     if (!innerText->firstChild())
445         return Range::create(document(), innerText, 0, innerText, 0);
446
447     int offset = 0;
448     Node* startNode = 0;
449     Node* endNode = 0;
450     for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(node, innerText)) {
451         ASSERT(!node->firstChild());
452         ASSERT(node->isTextNode() || node->hasTagName(brTag));
453         int length = node->isTextNode() ? lastOffsetInNode(node) : 1;
454
455         if (offset <= start && start <= offset + length)
456             setContainerAndOffsetForRange(node, start - offset, startNode, start);
457
458         if (offset <= end && end <= offset + length) {
459             setContainerAndOffsetForRange(node, end - offset, endNode, end);
460             break;
461         }
462
463         offset += length;
464     }
465
466     if (!startNode || !endNode)
467         return 0;
468
469     return Range::create(document(), startNode, start, endNode, end);
470 }
471
472 void HTMLTextFormControlElement::restoreCachedSelection()
473 {
474     setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, cachedSelectionDirection());
475 }
476
477 void HTMLTextFormControlElement::selectionChanged(bool shouldFireSelectEvent)
478 {
479     if (!isTextFormControl())
480         return;
481
482     // FIXME: Don't re-compute selection start and end if this function was called inside setSelectionRange.
483     // selectionStart() or selectionEnd() will return cached selection when this node doesn't have focus
484     cacheSelection(computeSelectionStart(), computeSelectionEnd(), computeSelectionDirection());
485     
486     if (shouldFireSelectEvent && m_cachedSelectionStart != m_cachedSelectionEnd)
487         dispatchEvent(Event::create(eventNames().selectEvent, true, false));
488 }
489
490 void HTMLTextFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
491 {
492     if (name == placeholderAttr) {
493         updatePlaceholderText();
494         updatePlaceholderVisibility();
495     } else
496         HTMLFormControlElementWithState::parseAttribute(name, value);
497 }
498
499 void HTMLTextFormControlElement::disabledStateChanged()
500 {
501     HTMLFormControlElementWithState::disabledStateChanged();
502     updateInnerTextElementEditability();
503 }
504
505 void HTMLTextFormControlElement::readOnlyAttributeChanged()
506 {
507     HTMLFormControlElementWithState::disabledAttributeChanged();
508     updateInnerTextElementEditability();
509 }
510
511 void HTMLTextFormControlElement::updateInnerTextElementEditability()
512 {
513     if (TextControlInnerTextElement* innerText = innerTextElement())
514         innerText->setAttribute(contenteditableAttr, isDisabledOrReadOnly() ? "false" : "plaintext-only");
515 }
516
517 bool HTMLTextFormControlElement::lastChangeWasUserEdit() const
518 {
519     if (!isTextFormControl())
520         return false;
521     return m_lastChangeWasUserEdit;
522 }
523
524 void HTMLTextFormControlElement::setInnerTextValue(const String& value)
525 {
526     if (!isTextFormControl())
527         return;
528
529     bool textIsChanged = value != innerTextValue();
530     if (textIsChanged || !innerTextElement()->hasChildNodes()) {
531         if (textIsChanged && renderer()) {
532             if (AXObjectCache* cache = document().existingAXObjectCache())
533                 cache->postNotification(this, AXObjectCache::AXValueChanged, TargetObservableParent);
534         }
535         innerTextElement()->setInnerText(value, ASSERT_NO_EXCEPTION);
536
537         if (value.endsWith('\n') || value.endsWith('\r'))
538             innerTextElement()->appendChild(HTMLBRElement::create(document()), ASSERT_NO_EXCEPTION);
539     }
540
541     setFormControlValueMatchesRenderer(true);
542 }
543
544 static String finishText(StringBuilder& result)
545 {
546     // Remove one trailing newline; there's always one that's collapsed out by rendering.
547     size_t size = result.length();
548     if (size && result[size - 1] == newlineCharacter)
549         result.resize(--size);
550     return result.toString();
551 }
552
553 String HTMLTextFormControlElement::innerTextValue() const
554 {
555     if (!isTextFormControl())
556         return emptyString();
557
558     TextControlInnerTextElement* innerText = innerTextElement();
559     if (!innerText)
560         return emptyString();
561
562     StringBuilder result;
563     for (Node* node = innerText; node; node = NodeTraversal::next(node, innerText)) {
564         if (is<HTMLBRElement>(*node))
565             result.append(newlineCharacter);
566         else if (is<Text>(*node))
567             result.append(downcast<Text>(*node).data());
568     }
569     return finishText(result);
570 }
571
572 static Position positionForIndex(TextControlInnerTextElement* innerText, unsigned index)
573 {
574     unsigned remainingCharactersToMoveForward = index;
575     Node* lastBrOrText = innerText;
576     for (Node* node = innerText; node; node = NodeTraversal::next(node, innerText)) {
577         if (node->hasTagName(brTag)) {
578             if (!remainingCharactersToMoveForward)
579                 return positionBeforeNode(node);
580             remainingCharactersToMoveForward--;
581             lastBrOrText = node;
582         } else if (is<Text>(*node)) {
583             Text& text = downcast<Text>(*node);
584             if (remainingCharactersToMoveForward < text.length())
585                 return Position(&text, remainingCharactersToMoveForward);
586             remainingCharactersToMoveForward -= text.length();
587             lastBrOrText = node;
588         }
589     }
590     return lastPositionInOrAfterNode(lastBrOrText);
591 }
592
593 unsigned HTMLTextFormControlElement::indexForPosition(const Position& passedPosition) const
594 {
595     TextControlInnerTextElement* innerText = innerTextElement();
596     if (!innerText || !innerText->contains(passedPosition.anchorNode()) || passedPosition.isNull())
597         return 0;
598
599     if (positionBeforeNode(innerText) == passedPosition)
600         return 0;
601
602     unsigned index = 0;
603     Node* startNode = passedPosition.computeNodeBeforePosition();
604     if (!startNode)
605         startNode = passedPosition.containerNode();
606     ASSERT(startNode);
607     ASSERT(innerText->contains(startNode));
608
609     for (Node* node = startNode; node; node = NodeTraversal::previous(node, innerText)) {
610         if (is<Text>(*node)) {
611             unsigned length = downcast<Text>(*node).length();
612             if (node == passedPosition.containerNode())
613                 index += std::min<unsigned>(length, passedPosition.offsetInContainerNode());
614             else
615                 index += length;
616         } else if (is<HTMLBRElement>(*node))
617             ++index;
618     }
619
620     unsigned length = innerTextValue().length();
621     index = std::min(index, length); // FIXME: We shouldn't have to call innerTextValue() just to ignore the last LF. See finishText.
622 #ifndef ASSERT_DISABLED
623     VisiblePosition visiblePosition = passedPosition;
624     unsigned indexComputedByVisiblePosition = 0;
625     if (visiblePosition.isNotNull())
626         indexComputedByVisiblePosition = WebCore::indexForVisiblePosition(innerText, visiblePosition, false /* forSelectionPreservation */);
627     ASSERT(index == indexComputedByVisiblePosition);
628 #endif
629     return index;
630 }
631
632 #if PLATFORM(IOS)
633 void HTMLTextFormControlElement::hidePlaceholder()
634 {
635     if (HTMLElement* placeholder = placeholderElement())
636         placeholder->setInlineStyleProperty(CSSPropertyVisibility, CSSValueHidden, true);
637 }
638
639 void HTMLTextFormControlElement::showPlaceholderIfNecessary()
640 {
641     if (HTMLElement* placeholder = placeholderElement())
642         placeholder->setInlineStyleProperty(CSSPropertyVisibility, CSSValueVisible, true);
643 }
644 #endif
645
646 static 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
663 String 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 (is<HTMLBRElement>(*node))
689             result.append(newlineCharacter);
690         else if (is<Text>(*node)) {
691             String data = downcast<Text>(*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
710 HTMLTextFormControlElement* 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 && is<HTMLTextFormControlElement>(*ancestor) ? downcast<HTMLTextFormControlElement>(ancestor) : nullptr;
721 }
722
723 static 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
733 String 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