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