Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(347)

Side by Side Diff: third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp

Issue 2380473002: Change the linebreak behavior of minlength and maxlength attributes of TEXTAREA. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698