| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2001 Dirk Mueller (mueller@kde.org) | 4 * (C) 2001 Dirk Mueller (mueller@kde.org) |
| 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserv
ed. | 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserv
ed. |
| 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) | 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) |
| 7 * Copyright (C) 2007 Samuel Weinig (sam@webkit.org) | 7 * Copyright (C) 2007 Samuel Weinig (sam@webkit.org) |
| 8 * | 8 * |
| 9 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
| 10 * modify it under the terms of the GNU Library General Public | 10 * modify it under the terms of the GNU Library General Public |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 #include "wtf/StdLibExtras.h" | 53 #include "wtf/StdLibExtras.h" |
| 54 #include "wtf/text/StringBuilder.h" | 54 #include "wtf/text/StringBuilder.h" |
| 55 | 55 |
| 56 namespace blink { | 56 namespace blink { |
| 57 | 57 |
| 58 using namespace HTMLNames; | 58 using namespace HTMLNames; |
| 59 | 59 |
| 60 static const unsigned defaultRows = 2; | 60 static const unsigned defaultRows = 2; |
| 61 static const unsigned defaultCols = 20; | 61 static const unsigned defaultCols = 20; |
| 62 | 62 |
| 63 // On submission, LF characters are converted into CRLF. | 63 static inline unsigned computeLengthForAPIValue(const String& text) |
| 64 // This function returns number of characters considering this. | |
| 65 static unsigned numberOfLineBreaks(const String& text) | |
| 66 { | 64 { |
| 67 unsigned length = text.length(); | 65 unsigned length = text.length(); |
| 68 unsigned count = 0; | 66 unsigned crlfCount = 0; |
| 69 for (unsigned i = 0; i < length; i++) { | 67 for (unsigned i = 0; i < length; ++i) { |
| 70 if (text[i] == '\n') | 68 if (text[i] == '\r' && i + 1 < length && text[i + 1] == '\n') |
| 71 count++; | 69 crlfCount++; |
| 72 } | 70 } |
| 73 return count; | 71 return text.length() - crlfCount; |
| 74 } | |
| 75 | |
| 76 static inline unsigned computeLengthForSubmission(const String& text) | |
| 77 { | |
| 78 return text.length() + numberOfLineBreaks(text); | |
| 79 } | 72 } |
| 80 | 73 |
| 81 HTMLTextAreaElement::HTMLTextAreaElement(Document& document, HTMLFormElement* fo
rm) | 74 HTMLTextAreaElement::HTMLTextAreaElement(Document& document, HTMLFormElement* fo
rm) |
| 82 : HTMLTextFormControlElement(textareaTag, document, form) | 75 : HTMLTextFormControlElement(textareaTag, document, form) |
| 83 , m_rows(defaultRows) | 76 , m_rows(defaultRows) |
| 84 , m_cols(defaultCols) | 77 , m_cols(defaultCols) |
| 85 , m_wrap(SoftWrap) | 78 , m_wrap(SoftWrap) |
| 86 , m_isDirty(false) | 79 , m_isDirty(false) |
| 87 , m_valueIsUpToDate(true) | 80 , m_valueIsUpToDate(true) |
| 88 , m_isPlaceholderVisible(false) | 81 , m_isPlaceholderVisible(false) |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*
event) const | 306 void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*
event) const |
| 314 { | 307 { |
| 315 DCHECK(event); | 308 DCHECK(event); |
| 316 DCHECK(layoutObject()); | 309 DCHECK(layoutObject()); |
| 317 int signedMaxLength = maxLength(); | 310 int signedMaxLength = maxLength(); |
| 318 if (signedMaxLength < 0) | 311 if (signedMaxLength < 0) |
| 319 return; | 312 return; |
| 320 unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength); | 313 unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength); |
| 321 | 314 |
| 322 const String& currentValue = innerEditorValue(); | 315 const String& currentValue = innerEditorValue(); |
| 323 unsigned currentLength = computeLengthForSubmission(currentValue); | 316 unsigned currentLength = computeLengthForAPIValue(currentValue); |
| 324 if (currentLength + computeLengthForSubmission(event->text()) < unsignedMaxL
ength) | 317 if (currentLength + computeLengthForAPIValue(event->text()) < unsignedMaxLen
gth) |
| 325 return; | 318 return; |
| 326 | 319 |
| 327 // selectionLength represents the selection length of this text field to be | 320 // selectionLength represents the selection length of this text field to be |
| 328 // removed by this insertion. | 321 // removed by this insertion. |
| 329 // If the text field has no focus, we don't need to take account of the | 322 // If the text field has no focus, we don't need to take account of the |
| 330 // selection length. The selection is the source of text drag-and-drop in | 323 // selection length. The selection is the source of text drag-and-drop in |
| 331 // that case, and nothing in the text field will be removed. | 324 // that case, and nothing in the text field will be removed. |
| 332 unsigned selectionLength = 0; | 325 unsigned selectionLength = 0; |
| 333 if (focused()) { | 326 if (focused()) { |
| 334 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesh
eets | 327 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesh
eets |
| 335 // needs to be audited. See http://crbug.com/590369 for more details. | 328 // needs to be audited. See http://crbug.com/590369 for more details. |
| 336 document().updateStyleAndLayoutIgnorePendingStylesheets(); | 329 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 337 | 330 |
| 338 selectionLength = computeLengthForSubmission(document().frame()->selecti
on().selectedText()); | 331 selectionLength = computeLengthForAPIValue(document().frame()->selection
().selectedText()); |
| 339 } | 332 } |
| 340 DCHECK_GE(currentLength, selectionLength); | 333 DCHECK_GE(currentLength, selectionLength); |
| 341 unsigned baseLength = currentLength - selectionLength; | 334 unsigned baseLength = currentLength - selectionLength; |
| 342 unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLeng
th - baseLength : 0; | 335 unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLeng
th - baseLength : 0; |
| 343 event->setText(sanitizeUserInputValue(event->text(), appendableLength)); | 336 event->setText(sanitizeUserInputValue(event->text(), appendableLength)); |
| 344 } | 337 } |
| 345 | 338 |
| 346 String HTMLTextAreaElement::sanitizeUserInputValue(const String& proposedValue,
unsigned maxLength) | 339 String HTMLTextAreaElement::sanitizeUserInputValue(const String& proposedValue,
unsigned maxLength) |
| 347 { | 340 { |
| 348 unsigned submissionLength = 0; | 341 unsigned submissionLength = 0; |
| 349 unsigned i = 0; | 342 unsigned i = 0; |
| 350 for (; i < proposedValue.length(); ++i) { | 343 for (; i < proposedValue.length(); ++i) { |
| 351 submissionLength += proposedValue[i] == '\n' ? 2 : 1; | 344 if (proposedValue[i] == '\r' && i + 1 < proposedValue.length() && propos
edValue[i + 1] == '\n') |
| 345 continue; |
| 346 ++submissionLength; |
| 352 if (submissionLength == maxLength) { | 347 if (submissionLength == maxLength) { |
| 353 ++i; | 348 ++i; |
| 354 break; | 349 break; |
| 355 } | 350 } |
| 356 if (submissionLength > maxLength) | 351 if (submissionLength > maxLength) |
| 357 break; | 352 break; |
| 358 } | 353 } |
| 359 if (i > 0 && U16_IS_LEAD(proposedValue[i - 1])) | 354 if (i > 0 && U16_IS_LEAD(proposedValue[i - 1])) |
| 360 --i; | 355 --i; |
| 361 return proposedValue.left(i); | 356 return proposedValue.left(i); |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 if (!willValidate()) | 538 if (!willValidate()) |
| 544 return String(); | 539 return String(); |
| 545 | 540 |
| 546 if (customError()) | 541 if (customError()) |
| 547 return customValidationMessage(); | 542 return customValidationMessage(); |
| 548 | 543 |
| 549 if (valueMissing()) | 544 if (valueMissing()) |
| 550 return locale().queryString(WebLocalizedString::ValidationValueMissing); | 545 return locale().queryString(WebLocalizedString::ValidationValueMissing); |
| 551 | 546 |
| 552 if (tooLong()) | 547 if (tooLong()) |
| 553 return locale().validationMessageTooLongText(computeLengthForSubmission(
value()), maxLength()); | 548 return locale().validationMessageTooLongText(value().length(), maxLength
()); |
| 554 | 549 |
| 555 if (tooShort()) | 550 if (tooShort()) |
| 556 return locale().validationMessageTooShortText(computeLengthForSubmission
(value()), minLength()); | 551 return locale().validationMessageTooShortText(value().length(), minLengt
h()); |
| 557 | 552 |
| 558 return String(); | 553 return String(); |
| 559 } | 554 } |
| 560 | 555 |
| 561 bool HTMLTextAreaElement::valueMissing() const | 556 bool HTMLTextAreaElement::valueMissing() const |
| 562 { | 557 { |
| 563 // We should not call value() for performance. | 558 // We should not call value() for performance. |
| 564 return willValidate() && valueMissing(nullptr); | 559 return willValidate() && valueMissing(nullptr); |
| 565 } | 560 } |
| 566 | 561 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 584 bool HTMLTextAreaElement::tooLong(const String* value, NeedsToCheckDirtyFlag che
ck) const | 579 bool HTMLTextAreaElement::tooLong(const String* value, NeedsToCheckDirtyFlag che
ck) const |
| 585 { | 580 { |
| 586 // Return false for the default value or value set by script even if it is | 581 // Return false for the default value or value set by script even if it is |
| 587 // longer than maxLength. | 582 // longer than maxLength. |
| 588 if (check == CheckDirtyFlag && !lastChangeWasUserEdit()) | 583 if (check == CheckDirtyFlag && !lastChangeWasUserEdit()) |
| 589 return false; | 584 return false; |
| 590 | 585 |
| 591 int max = maxLength(); | 586 int max = maxLength(); |
| 592 if (max < 0) | 587 if (max < 0) |
| 593 return false; | 588 return false; |
| 594 return computeLengthForSubmission(value ? *value : this->value()) > static_c
ast<unsigned>(max); | 589 unsigned len = value ? computeLengthForAPIValue(*value) : this->value().leng
th(); |
| 590 return len > static_cast<unsigned>(max); |
| 595 } | 591 } |
| 596 | 592 |
| 597 bool HTMLTextAreaElement::tooShort(const String* value, NeedsToCheckDirtyFlag ch
eck) const | 593 bool HTMLTextAreaElement::tooShort(const String* value, NeedsToCheckDirtyFlag ch
eck) const |
| 598 { | 594 { |
| 599 // Return false for the default value or value set by script even if it is | 595 // Return false for the default value or value set by script even if it is |
| 600 // shorter than minLength. | 596 // shorter than minLength. |
| 601 if (check == CheckDirtyFlag && !lastChangeWasUserEdit()) | 597 if (check == CheckDirtyFlag && !lastChangeWasUserEdit()) |
| 602 return false; | 598 return false; |
| 603 | 599 |
| 604 int min = minLength(); | 600 int min = minLength(); |
| 605 if (min <= 0) | 601 if (min <= 0) |
| 606 return false; | 602 return false; |
| 607 // An empty string is excluded from minlength check. | 603 // An empty string is excluded from minlength check. |
| 608 unsigned len = computeLengthForSubmission(value ? *value : this->value()); | 604 unsigned len = value ? computeLengthForAPIValue(*value) : this->value().leng
th(); |
| 609 return len > 0 && len < static_cast<unsigned>(min); | 605 return len > 0 && len < static_cast<unsigned>(min); |
| 610 } | 606 } |
| 611 | 607 |
| 612 bool HTMLTextAreaElement::isValidValue(const String& candidate) const | 608 bool HTMLTextAreaElement::isValidValue(const String& candidate) const |
| 613 { | 609 { |
| 614 return !valueMissing(&candidate) && !tooLong(&candidate, IgnoreDirtyFlag) &&
!tooShort(&candidate, IgnoreDirtyFlag); | 610 return !valueMissing(&candidate) && !tooLong(&candidate, IgnoreDirtyFlag) &&
!tooShort(&candidate, IgnoreDirtyFlag); |
| 615 } | 611 } |
| 616 | 612 |
| 617 void HTMLTextAreaElement::accessKeyAction(bool) | 613 void HTMLTextAreaElement::accessKeyAction(bool) |
| 618 { | 614 { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 682 | 678 |
| 683 void HTMLTextAreaElement::copyNonAttributePropertiesFromElement(const Element& s
ource) | 679 void HTMLTextAreaElement::copyNonAttributePropertiesFromElement(const Element& s
ource) |
| 684 { | 680 { |
| 685 const HTMLTextAreaElement& sourceElement = static_cast<const HTMLTextAreaEle
ment&>(source); | 681 const HTMLTextAreaElement& sourceElement = static_cast<const HTMLTextAreaEle
ment&>(source); |
| 686 setValueCommon(sourceElement.value(), DispatchNoEvent, SetSeletion); | 682 setValueCommon(sourceElement.value(), DispatchNoEvent, SetSeletion); |
| 687 m_isDirty = sourceElement.m_isDirty; | 683 m_isDirty = sourceElement.m_isDirty; |
| 688 HTMLTextFormControlElement::copyNonAttributePropertiesFromElement(source); | 684 HTMLTextFormControlElement::copyNonAttributePropertiesFromElement(source); |
| 689 } | 685 } |
| 690 | 686 |
| 691 } // namespace blink | 687 } // namespace blink |
| OLD | NEW |