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 "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 "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 50namespace WebCore { 51 52using namespace HTMLNames; 53 54static Position positionForIndex(TextControlInnerTextElement*, unsigned); 55 56HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form) 57 : HTMLFormControlElementWithState(tagName, document, form) 58 , m_lastChangeWasUserEdit(false) 59 , m_cachedSelectionStart(-1) 60 , m_cachedSelectionEnd(-1) 61 , m_cachedSelectionDirection(SelectionHasNoDirection) 62{ 63} 64 65HTMLTextFormControlElement::~HTMLTextFormControlElement() 66{ 67} 68 69bool HTMLTextFormControlElement::childShouldCreateRenderer(const Node& child) const 70{ 71 // FIXME: We shouldn't force the pseudo elements down into the shadow, but 72 // this perserves the current behavior of WebKit. 73 if (child.isPseudoElement()) 74 return HTMLFormControlElementWithState::childShouldCreateRenderer(child); 75 return hasShadowRootParent(child) && HTMLFormControlElementWithState::childShouldCreateRenderer(child); 76} 77 78Node::InsertionNotificationRequest HTMLTextFormControlElement::insertedInto(ContainerNode& insertionPoint) 79{ 80 HTMLFormControlElementWithState::insertedInto(insertionPoint); 81 if (!insertionPoint.inDocument()) 82 return InsertionDone; 83 String initialValue = value(); 84 setTextAsOfLastFormControlChangeEvent(initialValue.isNull() ? emptyString() : initialValue); 85 return InsertionDone; 86} 87 88void HTMLTextFormControlElement::dispatchFocusEvent(PassRefPtr<Element> oldFocusedElement, FocusDirection direction) 89{ 90 if (supportsPlaceholder()) 91 updatePlaceholderVisibility(false); 92 handleFocusEvent(oldFocusedElement.get(), direction); 93 HTMLFormControlElementWithState::dispatchFocusEvent(oldFocusedElement, direction); 94} 95 96void HTMLTextFormControlElement::dispatchBlurEvent(PassRefPtr<Element> newFocusedElement) 97{ 98 if (supportsPlaceholder()) 99 updatePlaceholderVisibility(false); 100 handleBlurEvent(); 101 HTMLFormControlElementWithState::dispatchBlurEvent(newFocusedElement); 102} 103 104void HTMLTextFormControlElement::didEditInnerTextValue() 105{ 106 if (!isTextFormControl()) 107 return; 108 109 m_lastChangeWasUserEdit = true; 110 subtreeHasChanged(); 111} 112 113void HTMLTextFormControlElement::forwardEvent(Event* event) 114{ 115 if (event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent) 116 return; 117 innerTextElement()->defaultEventHandler(event); 118} 119 120String HTMLTextFormControlElement::strippedPlaceholder() const 121{ 122 // According to the HTML5 specification, we need to remove CR and LF from 123 // the attribute value. 124 const AtomicString& attributeValue = fastGetAttribute(placeholderAttr); 125 if (!attributeValue.contains(newlineCharacter) && !attributeValue.contains(carriageReturn)) 126 return attributeValue; 127 128 StringBuilder stripped; 129 unsigned length = attributeValue.length(); 130 stripped.reserveCapacity(length); 131 for (unsigned i = 0; i < length; ++i) { 132 UChar character = attributeValue[i]; 133 if (character == newlineCharacter || character == carriageReturn) 134 continue; 135 stripped.append(character); 136 } 137 return stripped.toString(); 138} 139 140static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; } 141 142bool HTMLTextFormControlElement::isPlaceholderEmpty() const 143{ 144 const AtomicString& attributeValue = fastGetAttribute(placeholderAttr); 145 return attributeValue.string().find(isNotLineBreak) == notFound; 146} 147 148bool HTMLTextFormControlElement::placeholderShouldBeVisible() const 149{ 150 return supportsPlaceholder() 151 && isEmptyValue() 152 && isEmptySuggestedValue() 153 && !isPlaceholderEmpty() 154 && (document().focusedElement() != this || (renderer() && renderer()->theme().shouldShowPlaceholderWhenFocused())) 155 && (!renderer() || renderer()->style().visibility() == VISIBLE); 156} 157 158void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged) 159{ 160 if (!supportsPlaceholder()) 161 return; 162 if (!placeholderElement() || placeholderValueChanged) 163 updatePlaceholderText(); 164 HTMLElement* placeholder = placeholderElement(); 165 if (!placeholder) 166 return; 167 placeholder->setInlineStyleProperty(CSSPropertyVisibility, placeholderShouldBeVisible() ? CSSValueVisible : CSSValueHidden); 168} 169 170void HTMLTextFormControlElement::setSelectionStart(int start) 171{ 172 setSelectionRange(start, std::max(start, selectionEnd()), selectionDirection()); 173} 174 175void HTMLTextFormControlElement::setSelectionEnd(int end) 176{ 177 setSelectionRange(std::min(end, selectionStart()), end, selectionDirection()); 178} 179 180void HTMLTextFormControlElement::setSelectionDirection(const String& direction) 181{ 182 setSelectionRange(selectionStart(), selectionEnd(), direction); 183} 184 185void HTMLTextFormControlElement::select() 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); 192#else 193 setSelectionRange(0, std::numeric_limits<int>::max(), SelectionHasNoDirection); 194#endif 195} 196 197String HTMLTextFormControlElement::selectedText() const 198{ 199 if (!isTextFormControl()) 200 return String(); 201 return value().substring(selectionStart(), selectionEnd() - selectionStart()); 202} 203 204void HTMLTextFormControlElement::dispatchFormControlChangeEvent() 205{ 206 if (m_textAsOfLastFormControlChangeEvent != value()) { 207 dispatchChangeEvent(); 208 setTextAsOfLastFormControlChangeEvent(value()); 209 } 210 setChangedSinceLastFormControlChangeEvent(false); 211} 212 213void HTMLTextFormControlElement::setRangeText(const String& replacement, ExceptionCode& ec) 214{ 215 setRangeText(replacement, selectionStart(), selectionEnd(), String(), ec); 216} 217 218void 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 272void HTMLTextFormControlElement::setSelectionRange(int start, int end, const String& directionString) 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); 281} 282 283void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction) 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); 318} 319 320int 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 330VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) const 331{ 332 VisiblePosition position = positionForIndex(innerTextElement(), index); 333 ASSERT(indexForVisiblePosition(position) == index); 334 return position; 335} 336 337int 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 347int 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 357int 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 366int 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 376static 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 395const AtomicString& HTMLTextFormControlElement::selectionDirection() const 396{ 397 if (!isTextFormControl()) 398 return directionString(SelectionHasNoDirection); 399 if (document().focusedElement() != this && hasCachedSelection()) 400 return directionString(m_cachedSelectionDirection); 401 402 return directionString(computeSelectionDirection()); 403} 404 405TextFieldSelectionDirection 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 416static 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->nodeIndex() + offset; 424 } 425} 426 427PassRefPtr<Range> HTMLTextFormControlElement::selection() const 428{ 429 if (!renderer() || !isTextFormControl() || !hasCachedSelection()) 430 return 0; 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 0; 439 440 if (!innerText->firstChild()) 441 return Range::create(document(), innerText, 0, innerText, 0); 442 443 int offset = 0; 444 Node* startNode = 0; 445 Node* endNode = 0; 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 0; 464 465 return Range::create(document(), startNode, start, endNode, end); 466} 467 468void HTMLTextFormControlElement::restoreCachedSelection() 469{ 470 setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, m_cachedSelectionDirection); 471} 472 473void 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 486void HTMLTextFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 487{ 488 if (name == placeholderAttr) 489 updatePlaceholderVisibility(true); 490 else 491 HTMLFormControlElementWithState::parseAttribute(name, value); 492} 493 494void HTMLTextFormControlElement::disabledStateChanged() 495{ 496 HTMLFormControlElementWithState::disabledStateChanged(); 497 updateInnerTextElementEditability(); 498} 499 500void HTMLTextFormControlElement::readOnlyAttributeChanged() 501{ 502 HTMLFormControlElementWithState::disabledAttributeChanged(); 503 updateInnerTextElementEditability(); 504} 505 506void HTMLTextFormControlElement::updateInnerTextElementEditability() 507{ 508 if (TextControlInnerTextElement* innerText = innerTextElement()) 509 innerText->setAttribute(contenteditableAttr, isDisabledOrReadOnly() ? "false" : "plaintext-only"); 510} 511 512bool HTMLTextFormControlElement::lastChangeWasUserEdit() const 513{ 514 if (!isTextFormControl()) 515 return false; 516 return m_lastChangeWasUserEdit; 517} 518 519void HTMLTextFormControlElement::setInnerTextValue(const String& value) 520{ 521 if (!isTextFormControl()) 522 return; 523 524 bool textIsChanged = value != innerTextValue(); 525 if (textIsChanged || !innerTextElement()->hasChildNodes()) { 526 if (textIsChanged && renderer()) { 527 if (AXObjectCache* cache = document().existingAXObjectCache()) 528 cache->postNotification(this, AXObjectCache::AXValueChanged, TargetObservableParent); 529 } 530 innerTextElement()->setInnerText(value, ASSERT_NO_EXCEPTION); 531 532 if (value.endsWith('\n') || value.endsWith('\r')) 533 innerTextElement()->appendChild(HTMLBRElement::create(document()), ASSERT_NO_EXCEPTION); 534 } 535 536 setFormControlValueMatchesRenderer(true); 537} 538 539static String finishText(StringBuilder& result) 540{ 541 // Remove one trailing newline; there's always one that's collapsed out by rendering. 542 size_t size = result.length(); 543 if (size && result[size - 1] == newlineCharacter) 544 result.resize(--size); 545 return result.toString(); 546} 547 548String HTMLTextFormControlElement::innerTextValue() const 549{ 550 if (!isTextFormControl()) 551 return emptyString(); 552 553 TextControlInnerTextElement* innerText = innerTextElement(); 554 if (!innerText) 555 return emptyString(); 556 557 StringBuilder result; 558 for (Node* node = innerText; node; node = NodeTraversal::next(node, innerText)) { 559 if (node->hasTagName(brTag)) 560 result.append(newlineCharacter); 561 else if (node->isTextNode()) 562 result.append(toText(node)->data()); 563 } 564 return finishText(result); 565} 566 567static Position positionForIndex(TextControlInnerTextElement* innerText, unsigned index) 568{ 569 unsigned remainingCharactersToMoveForward = index; 570 Node* lastBrOrText = innerText; 571 for (Node* node = innerText; node; node = NodeTraversal::next(node, innerText)) { 572 if (node->hasTagName(brTag)) { 573 if (!remainingCharactersToMoveForward) 574 return positionBeforeNode(node); 575 remainingCharactersToMoveForward--; 576 lastBrOrText = node; 577 } else if (node->isTextNode()) { 578 Text& text = toText(*node); 579 if (remainingCharactersToMoveForward < text.length()) 580 return Position(&text, remainingCharactersToMoveForward); 581 remainingCharactersToMoveForward -= text.length(); 582 lastBrOrText = node; 583 } 584 } 585 return lastPositionInOrAfterNode(lastBrOrText); 586} 587 588unsigned HTMLTextFormControlElement::indexForPosition(const Position& passedPosition) const 589{ 590 TextControlInnerTextElement* innerText = innerTextElement(); 591 if (!innerText || !innerText->contains(passedPosition.anchorNode()) || passedPosition.isNull()) 592 return 0; 593 594 if (positionBeforeNode(innerText) == passedPosition) 595 return 0; 596 597 unsigned index = 0; 598 Node* startNode = passedPosition.computeNodeBeforePosition(); 599 if (!startNode) 600 startNode = passedPosition.containerNode(); 601 ASSERT(startNode); 602 ASSERT(innerText->contains(startNode)); 603 604 for (Node* node = startNode; node; node = NodeTraversal::previous(node, innerText)) { 605 if (node->isTextNode()) { 606 unsigned length = toText(*node).length(); 607 if (node == passedPosition.containerNode()) 608 index += std::min<unsigned>(length, passedPosition.offsetInContainerNode()); 609 else 610 index += length; 611 } else if (node->hasTagName(brTag)) 612 index++; 613 } 614 615 unsigned length = innerTextValue().length(); 616 index = std::min(index, length); // FIXME: We shouldn't have to call innerTextValue() just to ignore the last LF. See finishText. 617#ifndef ASSERT_DISABLED 618 VisiblePosition visiblePosition = passedPosition; 619 unsigned indexComputedByVisiblePosition = 0; 620 if (visiblePosition.isNotNull()) 621 indexComputedByVisiblePosition = WebCore::indexForVisiblePosition(innerText, visiblePosition, false /* forSelectionPreservation */); 622 ASSERT(index == indexComputedByVisiblePosition); 623#endif 624 return index; 625} 626 627#if PLATFORM(IOS) 628void HTMLTextFormControlElement::hidePlaceholder() 629{ 630 if (!supportsPlaceholder()) 631 return; 632 HTMLElement* placeholder = placeholderElement(); 633 if (!placeholder) { 634 updatePlaceholderText(); 635 return; 636 } 637 placeholder->setInlineStyleProperty(CSSPropertyVisibility, ASCIILiteral("hidden")); 638} 639 640void HTMLTextFormControlElement::showPlaceholderIfNecessary() 641{ 642 updatePlaceholderVisibility(false); 643} 644#endif 645 646static 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 663String 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 (node->hasTagName(brTag)) 689 result.append(newlineCharacter); 690 else if (node->isTextNode()) { 691 String data = toText(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 710HTMLTextFormControlElement* 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 && isHTMLTextFormControlElement(*ancestor) ? toHTMLTextFormControlElement(ancestor) : nullptr; 721} 722 723static 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 733String 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 754