[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.15.1-1414-gc69ee75

eric at webkit.org eric at webkit.org
Thu Oct 29 20:32:49 UTC 2009


The following commit has been merged in the webkit-1.1 branch:
commit fa588e6768ec03b9a40c92f557a0d955e94d3bc3
Author: eric at webkit.org <eric at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Sep 24 02:55:39 2009 +0000

    2009-09-23  Kent Tamura  <tkent at chromium.org>
    
            Reviewed by Darin Adler.
    
            Tests for maxLength of <textarea>
            https://bugs.webkit.org/show_bug.cgi?id=29292
    
            * fast/forms/script-tests/textarea-maxlength.js: Added.
            * fast/forms/textarea-maxlength-expected.txt: Added.
            * fast/forms/textarea-maxlength.html: Added.
    2009-09-23  Kent Tamura  <tkent at chromium.org>
    
            Reviewed by Darin Adler.
    
            - Support for maxLength of <textarea>
            - Move numGraphemeClusters() and numCharactersInGraphemeClusters() from InputElement to String.
            https://bugs.webkit.org/show_bug.cgi?id=29292
    
            Test: fast/forms/textarea-maxlength.html
    
            * dom/InputElement.cpp:
            (WebCore::InputElement::sanitizeUserInputValue):
            (WebCore::InputElement::handleBeforeTextInsertedEvent):
            * html/HTMLTextAreaElement.cpp:
            (WebCore::HTMLTextAreaElement::defaultEventHandler):
            (WebCore::HTMLTextAreaElement::handleBeforeTextInsertedEvent):
            (WebCore::HTMLTextAreaElement::sanitizeUserInputValue):
            (WebCore::HTMLTextAreaElement::maxLength):
            (WebCore::HTMLTextAreaElement::setMaxLength):
            * html/HTMLTextAreaElement.h:
            * html/HTMLTextAreaElement.idl:
            * platform/text/PlatformString.h:
            * platform/text/String.cpp:
            (WebCore::String::numGraphemeClusters):
            (WebCore::String::numCharactersInGraphemeClusters):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@48698 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index cc66725..2469b83 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,14 @@
+2009-09-23  Kent Tamura  <tkent at chromium.org>
+
+        Reviewed by Darin Adler.
+
+        Tests for maxLength of <textarea>
+        https://bugs.webkit.org/show_bug.cgi?id=29292
+
+        * fast/forms/script-tests/textarea-maxlength.js: Added.
+        * fast/forms/textarea-maxlength-expected.txt: Added.
+        * fast/forms/textarea-maxlength.html: Added.
+
 2009-09-23  Martin Robinson  <martin.james.robinson at gmail.com>
 
         Reviewed by Xan Lopez.
diff --git a/LayoutTests/fast/forms/script-tests/textarea-maxlength.js b/LayoutTests/fast/forms/script-tests/textarea-maxlength.js
new file mode 100644
index 0000000..7cf0f5d
--- /dev/null
+++ b/LayoutTests/fast/forms/script-tests/textarea-maxlength.js
@@ -0,0 +1,120 @@
+description('Tests for HTMLTextAreaElement.maxLength behaviors.');
+
+var textArea = document.createElement('textarea');
+document.body.appendChild(textArea);
+
+// No maxlength attribute
+shouldBe('textArea.maxLength', '0');
+
+// Invalid maxlength attributes
+textArea.setAttribute('maxlength', '-3');
+shouldBe('textArea.maxLength', '0');
+textArea.setAttribute('maxlength', 'xyz');
+shouldBe('textArea.maxLength', '0');
+
+// Valid maxlength attributes
+textArea.setAttribute('maxlength', '1');
+shouldBe('textArea.maxLength', '1');
+textArea.setAttribute('maxlength', '256');
+shouldBe('textArea.maxLength', '256');
+
+// Set values to .maxLength
+textArea.maxLength = 13;
+shouldBe('textArea.getAttribute("maxlength")', '"13"');
+
+textArea.maxLength = -1;
+shouldBe('textArea.maxLength', '4294967295');
+shouldBe('textArea.getAttribute("maxlength")', '"4294967295"');
+
+// maxLength doesn't truncate the default value.
+textArea = document.createElement('textarea');
+textArea.setAttribute('maxlength', '3');
+textArea.innerHTML = 'abcd';
+document.body.appendChild(textArea);
+shouldBe('textArea.value', '"abcd"');
+
+// maxLength doesn't truncate .value
+textArea.maxLength = 3;
+textArea.value = 'abcde';
+shouldBe('textArea.value', '"abcde"');
+
+// Set up for user-input tests
+function createFocusedTextAreaWithMaxLength3() {
+    if (textArea)
+        document.body.removeChild(textArea);
+    textArea = document.createElement('textarea');
+    textArea.setAttribute('maxlength', '3');
+    document.body.appendChild(textArea);
+    textArea.focus();
+}
+
+// Insert text of which length is maxLength.
+createFocusedTextAreaWithMaxLength3();
+document.execCommand('insertText', false, 'abc');
+shouldBe('textArea.value', '"abc"');
+
+// Try to add characters to maxLength characters.
+createFocusedTextAreaWithMaxLength3();
+textArea.value = 'abc';
+document.execCommand('insertText', false, 'def');
+shouldBe('textArea.value', '"abc"');
+
+// Replace text
+createFocusedTextAreaWithMaxLength3();
+textArea.value = 'abc';
+document.execCommand('selectAll');
+document.execCommand('insertText', false, 'def');
+shouldBe('textArea.value', '"def"');
+
+// Existing value is longer than maxLength.  We can't add text.
+createFocusedTextAreaWithMaxLength3();
+textArea.value = 'abcdef';
+document.execCommand('insertText', false, 'ghi');
+shouldBe('textArea.value', '"abcdef"');
+
+// We can delete a character in the longer value.
+createFocusedTextAreaWithMaxLength3();
+textArea.value = 'abcdef';
+document.execCommand('delete');
+shouldBe('textArea.value', '"abcde"');
+
+// A linebreak is 1 character.
+createFocusedTextAreaWithMaxLength3();
+document.execCommand('insertText', false, 'A');
+document.execCommand('insertLineBreak');
+document.execCommand('insertText', false, 'B');
+shouldBe('textArea.value', '"A\\nB"');
+
+// According to the HTML5 specification, maxLength is code-point length.
+// However WebKit handles it as grapheme length.
+
+// fancyX should be treated as 1 grapheme.
+var fancyX = "x\u0305\u0332";// + String.fromCharCode(0x305) + String.fromCharCode(0x332);
+// u10000 is one character consisted of a surrogate pair.
+var u10000 = "\ud800\udc00";
+
+// Inserts 5 code-points in UTF-16
+createFocusedTextAreaWithMaxLength3();
+document.execCommand('insertText', false, 'AB' + fancyX);
+shouldBe('textArea.value', '"AB" + fancyX');
+shouldBe('textArea.value.length', '5');
+
+createFocusedTextAreaWithMaxLength3();
+textArea.value = 'AB' + fancyX;
+textArea.setSelectionRange(2, 5);  // Select fancyX
+document.execCommand('insertText', false, 'CDE');
+shouldBe('textArea.value', '"ABC"');
+
+// Inserts 4 code-points in UTF-16
+createFocusedTextAreaWithMaxLength3();
+document.execCommand('insertText', false, 'AB' + u10000);
+shouldBe('textArea.value', '"AB" + u10000');
+shouldBe('textArea.value.length', '4');
+
+createFocusedTextAreaWithMaxLength3();
+textArea.value = 'AB' + u10000;
+textArea.setSelectionRange(2, 4);  // Select u10000
+document.execCommand('insertText', false, 'CDE');
+shouldBe('textArea.value', '"ABC"');
+
+var successfullyParsed = true;
diff --git a/LayoutTests/fast/forms/textarea-maxlength-expected.txt b/LayoutTests/fast/forms/textarea-maxlength-expected.txt
new file mode 100644
index 0000000..bd1aa17
--- /dev/null
+++ b/LayoutTests/fast/forms/textarea-maxlength-expected.txt
@@ -0,0 +1,31 @@
+Tests for HTMLTextAreaElement.maxLength behaviors.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS textArea.maxLength is 0
+PASS textArea.maxLength is 0
+PASS textArea.maxLength is 0
+PASS textArea.maxLength is 1
+PASS textArea.maxLength is 256
+PASS textArea.getAttribute("maxlength") is "13"
+PASS textArea.maxLength is 4294967295
+PASS textArea.getAttribute("maxlength") is "4294967295"
+PASS textArea.value is "abcd"
+PASS textArea.value is "abcde"
+PASS textArea.value is "abc"
+PASS textArea.value is "abc"
+PASS textArea.value is "def"
+PASS textArea.value is "abcdef"
+PASS textArea.value is "abcde"
+PASS textArea.value is "A\nB"
+PASS textArea.value is "AB" + fancyX
+PASS textArea.value.length is 5
+PASS textArea.value is "ABC"
+PASS textArea.value is "AB" + u10000
+PASS textArea.value.length is 4
+PASS textArea.value is "ABC"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/forms/textarea-maxlength.html b/LayoutTests/fast/forms/textarea-maxlength.html
new file mode 100644
index 0000000..ac5ecdb
--- /dev/null
+++ b/LayoutTests/fast/forms/textarea-maxlength.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/textarea-maxlength.js"></script>
+<script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 479db41..28b3d4c 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,29 @@
+2009-09-23  Kent Tamura  <tkent at chromium.org>
+
+        Reviewed by Darin Adler.
+
+        - Support for maxLength of <textarea>
+        - Move numGraphemeClusters() and numCharactersInGraphemeClusters() from InputElement to String.
+        https://bugs.webkit.org/show_bug.cgi?id=29292
+
+        Test: fast/forms/textarea-maxlength.html
+
+        * dom/InputElement.cpp:
+        (WebCore::InputElement::sanitizeUserInputValue):
+        (WebCore::InputElement::handleBeforeTextInsertedEvent):
+        * html/HTMLTextAreaElement.cpp:
+        (WebCore::HTMLTextAreaElement::defaultEventHandler):
+        (WebCore::HTMLTextAreaElement::handleBeforeTextInsertedEvent):
+        (WebCore::HTMLTextAreaElement::sanitizeUserInputValue):
+        (WebCore::HTMLTextAreaElement::maxLength):
+        (WebCore::HTMLTextAreaElement::setMaxLength):
+        * html/HTMLTextAreaElement.h:
+        * html/HTMLTextAreaElement.idl:
+        * platform/text/PlatformString.h:
+        * platform/text/String.cpp:
+        (WebCore::String::numGraphemeClusters):
+        (WebCore::String::numCharactersInGraphemeClusters):
+
 2009-09-23  Martin Robinson  <martin.james.robinson at gmail.com>
 
         Reviewed by Xan Lopez.
diff --git a/WebCore/dom/InputElement.cpp b/WebCore/dom/InputElement.cpp
index 97793e2..875d9f2 100644
--- a/WebCore/dom/InputElement.cpp
+++ b/WebCore/dom/InputElement.cpp
@@ -34,7 +34,6 @@
 #include "RenderTextControlSingleLine.h"
 #include "SelectionController.h"
 #include "TextIterator.h"
-#include "TextBreakIterator.h"
 
 #if ENABLE(WML)
 #include "WMLInputElement.h"
@@ -159,23 +158,6 @@ void InputElement::setValueFromRenderer(InputElementData& data, InputElement* in
     notifyFormStateChanged(element);
 }
 
-static int numCharactersInGraphemeClusters(StringImpl* s, int numGraphemeClusters)
-{
-    if (!s)
-        return 0;
-
-    TextBreakIterator* it = characterBreakIterator(s->characters(), s->length());
-    if (!it)
-        return 0;
-
-    for (int i = 0; i < numGraphemeClusters; ++i) {
-        if (textBreakNext(it) == TextBreakDone)
-            return s->length();
-    }
-
-    return textBreakCurrent(it);
-}
-
 String InputElement::sanitizeValue(const InputElement* inputElement, const String& proposedValue)
 {
     return InputElement::sanitizeUserInputValue(inputElement, proposedValue, s_maximumLength);
@@ -191,36 +173,15 @@ String InputElement::sanitizeUserInputValue(const InputElement* inputElement, co
     string.replace('\r', ' ');
     string.replace('\n', ' ');
 
-    StringImpl* s = string.impl();
-    int newLength = numCharactersInGraphemeClusters(s, maxLength);
-    for (int i = 0; i < newLength; ++i) {
-        const UChar& current = (*s)[i];
+    unsigned newLength = string.numCharactersInGraphemeClusters(maxLength);
+    for (unsigned i = 0; i < newLength; ++i) {
+        const UChar current = string[i];
         if (current < ' ' && current != '\t') {
             newLength = i;
             break;
         }
     }
-
-    if (newLength < static_cast<int>(string.length()))
-        return string.left(newLength);
-
-    return string;
-}
-
-static int numGraphemeClusters(StringImpl* s)
-{
-    if (!s)
-        return 0;
-
-    TextBreakIterator* it = characterBreakIterator(s->characters(), s->length());
-    if (!it)
-        return 0;
-
-    int num = 0;
-    while (textBreakNext(it) != TextBreakDone)
-        ++num;
-
-    return num;
+    return string.left(newLength);
 }
 
 void InputElement::handleBeforeTextInsertedEvent(InputElementData& data, InputElement* inputElement, Element* element, Event* event)
@@ -231,15 +192,16 @@ void InputElement::handleBeforeTextInsertedEvent(InputElementData& data, InputEl
     // We use RenderTextControlSingleLine::text() instead of InputElement::value()
     // because they can be mismatched by sanitizeValue() in
     // RenderTextControlSingleLine::subtreeHasChanged() in some cases.
-    int oldLength = numGraphemeClusters(toRenderTextControlSingleLine(element->renderer())->text().impl());
+    unsigned oldLength = toRenderTextControlSingleLine(element->renderer())->text().numGraphemeClusters();
 
     // selection() may be a pre-edit text.
-    int selectionLength = numGraphemeClusters(plainText(element->document()->frame()->selection()->selection().toNormalizedRange().get()).impl());
+    unsigned selectionLength = plainText(element->document()->frame()->selection()->selection().toNormalizedRange().get()).numGraphemeClusters();
     ASSERT(oldLength >= selectionLength);
 
     // Selected characters will be removed by the next text event.
-    int baseLength = oldLength - selectionLength;
-    int appendableLength = data.maxLength() - baseLength;
+    unsigned baseLength = oldLength - selectionLength;
+    unsigned maxLength = static_cast<unsigned>(data.maxLength()); // maxLength() can never be negative.
+    unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
 
     // Truncate the inserted text to avoid violating the maxLength and other constraints.
     BeforeTextInsertedEvent* textEvent = static_cast<BeforeTextInsertedEvent*>(event);
diff --git a/WebCore/html/HTMLTextAreaElement.cpp b/WebCore/html/HTMLTextAreaElement.cpp
index d3fc897..3cf4852 100644
--- a/WebCore/html/HTMLTextAreaElement.cpp
+++ b/WebCore/html/HTMLTextAreaElement.cpp
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "HTMLTextAreaElement.h"
 
+#include "BeforeTextInsertedEvent.h"
 #include "ChromeClient.h"
 #include "CSSValueKeywords.h"
 #include "Document.h"
@@ -35,12 +36,14 @@
 #include "FormDataList.h"
 #include "Frame.h"
 #include "HTMLNames.h"
+#include "InputElement.h"
 #include "MappedAttribute.h"
 #include "Page.h"
 #include "RenderStyle.h"
 #include "RenderTextControlMultiLine.h"
 #include "ScriptEventListener.h"
 #include "Text.h"
+#include "TextIterator.h"
 #include "VisibleSelection.h"
 #include <wtf/StdLibExtras.h>
 
@@ -270,10 +273,34 @@ void HTMLTextAreaElement::defaultEventHandler(Event* event)
 {
     if (renderer() && (event->isMouseEvent() || event->isDragEvent() || event->isWheelEvent() || event->type() == eventNames().blurEvent))
         toRenderTextControlMultiLine(renderer())->forwardEvent(event);
+    else if (renderer() && event->isBeforeTextInsertedEvent())
+        handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(event));
 
     HTMLFormControlElementWithState::defaultEventHandler(event);
 }
 
+void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event) const
+{
+    ASSERT(event);
+    ASSERT(renderer());
+    bool ok;
+    unsigned maxLength = getAttribute(maxlengthAttr).string().toUInt(&ok);
+    if (!ok)
+        return;
+
+    unsigned currentLength = toRenderTextControl(renderer())->text().numGraphemeClusters();
+    unsigned selectionLength = plainText(document()->frame()->selection()->selection().toNormalizedRange().get()).numGraphemeClusters();
+    ASSERT(currentLength >= selectionLength);
+    unsigned baseLength = currentLength - selectionLength;
+    unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
+    event->setText(sanitizeUserInputValue(event->text(), appendableLength));
+}
+
+String HTMLTextAreaElement::sanitizeUserInputValue(const String& proposedValue, unsigned maxLength)
+{
+    return proposedValue.left(proposedValue.numCharactersInGraphemeClusters(maxLength));
+}
+
 void HTMLTextAreaElement::rendererWillBeDestroyed()
 {
     updateValue();
@@ -374,6 +401,16 @@ void HTMLTextAreaElement::setDefaultValue(const String& defaultValue)
     setValue(value);
 }
 
+unsigned HTMLTextAreaElement::maxLength() const
+{
+    return getAttribute(maxlengthAttr).string().toUInt();
+}
+
+void HTMLTextAreaElement::setMaxLength(unsigned newValue)
+{
+    setAttribute(maxlengthAttr, String::number(newValue));
+}
+
 void HTMLTextAreaElement::accessKeyAction(bool)
 {
     focus();
diff --git a/WebCore/html/HTMLTextAreaElement.h b/WebCore/html/HTMLTextAreaElement.h
index 1f5cb91..fbf519d 100644
--- a/WebCore/html/HTMLTextAreaElement.h
+++ b/WebCore/html/HTMLTextAreaElement.h
@@ -28,6 +28,7 @@
 
 namespace WebCore {
 
+class BeforeTextInsertedEvent;
 class VisibleSelection;
 
 class HTMLTextAreaElement : public HTMLFormControlElementWithState {
@@ -78,6 +79,8 @@ public:
     String defaultValue() const;
     void setDefaultValue(const String&);
     int textLength() const { return value().length(); }
+    unsigned maxLength() const;
+    void setMaxLength(unsigned);
     
     void rendererWillBeDestroyed();
     
@@ -99,6 +102,8 @@ public:
 private:
     enum WrapMethod { NoWrap, SoftWrap, HardWrap };
 
+    void handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*) const;
+    static String sanitizeUserInputValue(const String&, unsigned maxLength);
     void updateValue() const;
     void updatePlaceholderVisibility(bool placeholderValueChanged);
     virtual void dispatchFocusEvent();
diff --git a/WebCore/html/HTMLTextAreaElement.idl b/WebCore/html/HTMLTextAreaElement.idl
index 6d27f54..84583f5 100644
--- a/WebCore/html/HTMLTextAreaElement.idl
+++ b/WebCore/html/HTMLTextAreaElement.idl
@@ -34,6 +34,7 @@ module html {
                  attribute  long                 cols;
                  attribute  boolean              disabled;
                  attribute  boolean              autofocus;
+                 attribute  unsigned long        maxLength;
                  attribute  [ConvertNullToNullString] DOMString            name;
                  attribute  [ConvertNullToNullString, Reflect] DOMString   placeholder;
                  attribute  boolean              readOnly;
diff --git a/WebCore/platform/text/PlatformString.h b/WebCore/platform/text/PlatformString.h
index 258b28d..b9b4078 100644
--- a/WebCore/platform/text/PlatformString.h
+++ b/WebCore/platform/text/PlatformString.h
@@ -254,6 +254,14 @@ public:
     // Determines the writing direction using the Unicode Bidi Algorithm rules P2 and P3.
     WTF::Unicode::Direction defaultWritingDirection() const { return m_impl ? m_impl->defaultWritingDirection() : WTF::Unicode::LeftToRight; }
 
+    // Counts the number of grapheme clusters. A surrogate pair or a sequence
+    // of a non-combining character and following combining characters is
+    // counted as 1 grapheme cluster.
+    unsigned numGraphemeClusters() const;
+    // Returns the number of characters which will be less than or equal to
+    // the specified grapheme cluster length.
+    unsigned numCharactersInGraphemeClusters(unsigned) const;
+
 private:
     RefPtr<StringImpl> m_impl;
 };
diff --git a/WebCore/platform/text/String.cpp b/WebCore/platform/text/String.cpp
index 2730939..e892ef6 100644
--- a/WebCore/platform/text/String.cpp
+++ b/WebCore/platform/text/String.cpp
@@ -25,6 +25,7 @@
 #include "CString.h"
 #include "FloatConversion.h"
 #include "StringBuffer.h"
+#include "TextBreakIterator.h"
 #include "TextEncoding.h"
 #include <wtf/dtoa.h>
 #include <limits>
@@ -921,6 +922,31 @@ PassRefPtr<SharedBuffer> utf8Buffer(const String& string)
     return SharedBuffer::adoptVector(buffer);
 }
 
+unsigned String::numGraphemeClusters() const
+{
+    TextBreakIterator* it = characterBreakIterator(characters(), length());
+    if (!it)
+        return length();
+
+    unsigned num = 0;
+    while (textBreakNext(it) != TextBreakDone)
+        ++num;
+    return num;
+}
+
+unsigned String::numCharactersInGraphemeClusters(unsigned numGraphemeClusters) const
+{
+    TextBreakIterator* it = characterBreakIterator(characters(), length());
+    if (!it)
+        return min(length(), numGraphemeClusters);
+
+    for (unsigned i = 0; i < numGraphemeClusters; ++i) {
+        if (textBreakNext(it) == TextBreakDone)
+            return length();
+    }
+    return textBreakCurrent(it);
+}
+
 } // namespace WebCore
 
 #ifndef NDEBUG

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list