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