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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 | 52 |
53 using namespace HTMLNames; | 53 using namespace HTMLNames; |
54 | 54 |
55 static const int defaultRows = 2; | 55 static const int defaultRows = 2; |
56 static const int defaultCols = 20; | 56 static const int defaultCols = 20; |
57 | 57 |
58 // On submission, LF characters are converted into CRLF. | 58 // On submission, LF characters are converted into CRLF. |
59 // This function returns number of characters considering this. | 59 // This function returns number of characters considering this. |
60 static inline unsigned computeLengthForSubmission(const String& text, unsigned n
umberOfLineBreaks) | 60 static inline unsigned computeLengthForSubmission(const String& text, unsigned n
umberOfLineBreaks) |
61 { | 61 { |
62 return numGraphemeClusters(text) + numberOfLineBreaks; | 62 return text.length() + numberOfLineBreaks; |
63 } | 63 } |
64 | 64 |
65 static unsigned numberOfLineBreaks(const String& text) | 65 static unsigned numberOfLineBreaks(const String& text) |
66 { | 66 { |
67 unsigned length = text.length(); | 67 unsigned length = text.length(); |
68 unsigned count = 0; | 68 unsigned count = 0; |
69 for (unsigned i = 0; i < length; i++) { | 69 for (unsigned i = 0; i < length; i++) { |
70 if (text[i] == '\n') | 70 if (text[i] == '\n') |
71 count++; | 71 count++; |
72 } | 72 } |
73 return count; | 73 return count; |
74 } | 74 } |
75 | 75 |
76 static inline unsigned computeLengthForSubmission(const String& text) | 76 static inline unsigned computeLengthForSubmission(const String& text) |
77 { | 77 { |
78 return numGraphemeClusters(text) + numberOfLineBreaks(text); | 78 return text.length() + numberOfLineBreaks(text); |
79 } | |
80 | |
81 static inline unsigned upperBoundForLengthForSubmission(const String& text, unsi
gned numberOfLineBreaks) | |
82 { | |
83 return text.length() + numberOfLineBreaks; | |
84 } | 79 } |
85 | 80 |
86 HTMLTextAreaElement::HTMLTextAreaElement(const QualifiedName& tagName, Document*
document, HTMLFormElement* form) | 81 HTMLTextAreaElement::HTMLTextAreaElement(const QualifiedName& tagName, Document*
document, HTMLFormElement* form) |
87 : HTMLTextFormControlElement(tagName, document, form) | 82 : HTMLTextFormControlElement(tagName, document, form) |
88 , m_rows(defaultRows) | 83 , m_rows(defaultRows) |
89 , m_cols(defaultCols) | 84 , m_cols(defaultCols) |
90 , m_wrap(SoftWrap) | 85 , m_wrap(SoftWrap) |
91 , m_placeholder(0) | 86 , m_placeholder(0) |
92 , m_isDirty(false) | 87 , m_isDirty(false) |
93 , m_wasModifiedByUser(false) | 88 , m_wasModifiedByUser(false) |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*
event) const | 282 void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*
event) const |
288 { | 283 { |
289 ASSERT(event); | 284 ASSERT(event); |
290 ASSERT(renderer()); | 285 ASSERT(renderer()); |
291 int signedMaxLength = maxLength(); | 286 int signedMaxLength = maxLength(); |
292 if (signedMaxLength < 0) | 287 if (signedMaxLength < 0) |
293 return; | 288 return; |
294 unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength); | 289 unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength); |
295 | 290 |
296 const String& currentValue = innerTextValue(); | 291 const String& currentValue = innerTextValue(); |
297 unsigned numberOfLineBreaksInCurrentValue = numberOfLineBreaks(currentValue)
; | 292 unsigned currentLength = computeLengthForSubmission(currentValue); |
298 if (upperBoundForLengthForSubmission(currentValue, numberOfLineBreaksInCurre
ntValue) | 293 if (currentLength + computeLengthForSubmission(event->text()) < unsignedMaxL
ength) |
299 + upperBoundForLengthForSubmission(event->text(), numberOfLineBreaks(eve
nt->text())) < unsignedMaxLength) | |
300 return; | 294 return; |
301 | 295 |
302 unsigned currentLength = computeLengthForSubmission(currentValue, numberOfLi
neBreaksInCurrentValue); | |
303 // selectionLength represents the selection length of this text field to be | 296 // selectionLength represents the selection length of this text field to be |
304 // removed by this insertion. | 297 // removed by this insertion. |
305 // If the text field has no focus, we don't need to take account of the | 298 // If the text field has no focus, we don't need to take account of the |
306 // selection length. The selection is the source of text drag-and-drop in | 299 // selection length. The selection is the source of text drag-and-drop in |
307 // that case, and nothing in the text field will be removed. | 300 // that case, and nothing in the text field will be removed. |
308 unsigned selectionLength = focused() ? computeLengthForSubmission(plainText(
document()->frame()->selection()->selection().toNormalizedRange().get())) : 0; | 301 unsigned selectionLength = focused() ? computeLengthForSubmission(plainText(
document()->frame()->selection()->selection().toNormalizedRange().get())) : 0; |
309 ASSERT(currentLength >= selectionLength); | 302 ASSERT(currentLength >= selectionLength); |
310 unsigned baseLength = currentLength - selectionLength; | 303 unsigned baseLength = currentLength - selectionLength; |
311 unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLeng
th - baseLength : 0; | 304 unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLeng
th - baseLength : 0; |
312 event->setText(sanitizeUserInputValue(event->text(), appendableLength)); | 305 event->setText(sanitizeUserInputValue(event->text(), appendableLength)); |
313 } | 306 } |
314 | 307 |
315 String HTMLTextAreaElement::sanitizeUserInputValue(const String& proposedValue,
unsigned maxLength) | 308 String HTMLTextAreaElement::sanitizeUserInputValue(const String& proposedValue,
unsigned maxLength) |
316 { | 309 { |
317 return proposedValue.left(numCharactersInGraphemeClusters(proposedValue, max
Length)); | 310 if (maxLength > 0 && U16_IS_LEAD(proposedValue[maxLength - 1])) |
| 311 --maxLength; |
| 312 return proposedValue.left(maxLength); |
318 } | 313 } |
319 | 314 |
320 HTMLElement* HTMLTextAreaElement::innerTextElement() const | 315 HTMLElement* HTMLTextAreaElement::innerTextElement() const |
321 { | 316 { |
322 Node* node = userAgentShadowRoot()->firstChild(); | 317 Node* node = userAgentShadowRoot()->firstChild(); |
323 ASSERT(!node || node->hasTagName(divTag)); | 318 ASSERT(!node || node->hasTagName(divTag)); |
324 return toHTMLElement(node); | 319 return toHTMLElement(node); |
325 } | 320 } |
326 | 321 |
327 void HTMLTextAreaElement::rendererWillBeDestroyed() | 322 void HTMLTextAreaElement::rendererWillBeDestroyed() |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
477 bool HTMLTextAreaElement::tooLong(const String& value, NeedsToCheckDirtyFlag che
ck) const | 472 bool HTMLTextAreaElement::tooLong(const String& value, NeedsToCheckDirtyFlag che
ck) const |
478 { | 473 { |
479 // Return false for the default value or value set by script even if it is | 474 // Return false for the default value or value set by script even if it is |
480 // longer than maxLength. | 475 // longer than maxLength. |
481 if (check == CheckDirtyFlag && !m_wasModifiedByUser) | 476 if (check == CheckDirtyFlag && !m_wasModifiedByUser) |
482 return false; | 477 return false; |
483 | 478 |
484 int max = maxLength(); | 479 int max = maxLength(); |
485 if (max < 0) | 480 if (max < 0) |
486 return false; | 481 return false; |
487 unsigned unsignedMax = static_cast<unsigned>(max); | 482 return computeLengthForSubmission(value) > static_cast<unsigned>(max); |
488 unsigned numberOfLineBreaksInValue = numberOfLineBreaks(value); | |
489 return upperBoundForLengthForSubmission(value, numberOfLineBreaksInValue) >
unsignedMax | |
490 && computeLengthForSubmission(value, numberOfLineBreaksInValue) > unsign
edMax; | |
491 } | 483 } |
492 | 484 |
493 bool HTMLTextAreaElement::isValidValue(const String& candidate) const | 485 bool HTMLTextAreaElement::isValidValue(const String& candidate) const |
494 { | 486 { |
495 return !valueMissing(candidate) && !tooLong(candidate, IgnoreDirtyFlag); | 487 return !valueMissing(candidate) && !tooLong(candidate, IgnoreDirtyFlag); |
496 } | 488 } |
497 | 489 |
498 void HTMLTextAreaElement::accessKeyAction(bool) | 490 void HTMLTextAreaElement::accessKeyAction(bool) |
499 { | 491 { |
500 focus(); | 492 focus(); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
550 RefPtr<HTMLDivElement> placeholder = HTMLDivElement::create(document()); | 542 RefPtr<HTMLDivElement> placeholder = HTMLDivElement::create(document()); |
551 m_placeholder = placeholder.get(); | 543 m_placeholder = placeholder.get(); |
552 m_placeholder->setPseudo(AtomicString("-webkit-input-placeholder", Atomi
cString::ConstructFromLiteral)); | 544 m_placeholder->setPseudo(AtomicString("-webkit-input-placeholder", Atomi
cString::ConstructFromLiteral)); |
553 userAgentShadowRoot()->insertBefore(m_placeholder, innerTextElement()->n
extSibling(), ASSERT_NO_EXCEPTION); | 545 userAgentShadowRoot()->insertBefore(m_placeholder, innerTextElement()->n
extSibling(), ASSERT_NO_EXCEPTION); |
554 } | 546 } |
555 m_placeholder->setInnerText(placeholderText, ASSERT_NO_EXCEPTION); | 547 m_placeholder->setInnerText(placeholderText, ASSERT_NO_EXCEPTION); |
556 fixPlaceholderRenderer(m_placeholder, innerTextElement()); | 548 fixPlaceholderRenderer(m_placeholder, innerTextElement()); |
557 } | 549 } |
558 | 550 |
559 } | 551 } |
OLD | NEW |