Chromium Code Reviews

Unified Diff: third_party/WebKit/WebCore/dom/InputElement.cpp

Issue 21184: WebKit merge 40722:40785 (part 1) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
« no previous file with comments | « third_party/WebKit/WebCore/dom/Element.cpp ('k') | third_party/WebKit/WebCore/dom/Node.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/WebCore/dom/InputElement.cpp
===================================================================
--- third_party/WebKit/WebCore/dom/InputElement.cpp (revision 9391)
+++ third_party/WebKit/WebCore/dom/InputElement.cpp (working copy)
@@ -1,307 +1,307 @@
-/*
- * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "InputElement.h"
-
-#include "BeforeTextInsertedEvent.h"
-#include "ChromeClient.h"
-#include "Document.h"
-#include "Event.h"
-#include "EventNames.h"
-#include "FormControlElement.h"
-#include "Frame.h"
-#include "HTMLInputElement.h"
-#include "HTMLNames.h"
-#include "Page.h"
-#include "RenderTextControlSingleLine.h"
-#include "SelectionController.h"
-#include "TextIterator.h"
-#include "TextBreakIterator.h"
-
-#if ENABLE(WML)
-#include "WMLInputElement.h"
-#include "WMLNames.h"
-#endif
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-// FIXME: According to HTML4, the length attribute's value can be arbitrarily
-// large. However, due to http://bugs.webkit.org/show_bugs.cgi?id=14536 things
-// get rather sluggish when a text field has a larger number of characters than
-// this, even when just clicking in the text field.
-const int InputElement::s_maximumLength = 524288;
-const int InputElement::s_defaultSize = 20;
-
-void InputElement::dispatchFocusEvent(InputElementData& data, Document* document)
-{
- if (!data.inputElement()->isTextField())
- return;
-
- updatePlaceholderVisibility(data, document);
-
- if (data.inputElement()->isPasswordField() && document->frame())
- document->setUseSecureKeyboardEntryWhenActive(true);
-}
-
-void InputElement::dispatchBlurEvent(InputElementData& data, Document* document)
-{
- if (!data.inputElement()->isTextField())
- return;
-
- Frame* frame = document->frame();
- if (!frame)
- return;
-
- updatePlaceholderVisibility(data, document);
-
- if (data.inputElement()->isPasswordField())
- document->setUseSecureKeyboardEntryWhenActive(false);
-
- frame->textFieldDidEndEditing(data.element());
-}
-
-void InputElement::updatePlaceholderVisibility(InputElementData& data, Document* document, bool placeholderValueChanged)
-{
- ASSERT(data.inputElement()->isTextField());
-
- bool oldPlaceholderShouldBeVisible = data.placeholderShouldBeVisible();
- Element* element = data.element();
-
- data.setPlaceholderShouldBeVisible(data.inputElement()->value().isEmpty()
- && document->focusedNode() != element
- && !data.inputElement()->placeholderValue().isEmpty());
-
- if ((oldPlaceholderShouldBeVisible != data.placeholderShouldBeVisible() || placeholderValueChanged) && element->renderer())
- static_cast<RenderTextControlSingleLine*>(element->renderer())->updatePlaceholderVisibility();
-}
-
-void InputElement::updateFocusAppearance(InputElementData& data, Document* document, bool restorePreviousSelection)
-{
- ASSERT(data.inputElement()->isTextField());
-
- if (!restorePreviousSelection || data.cachedSelectionStart() == -1)
- data.inputElement()->select();
- else
- // Restore the cached selection.
- updateSelectionRange(data, data.cachedSelectionStart(), data.cachedSelectionEnd());
-
- if (document && document->frame())
- document->frame()->revealSelection();
-}
-
-void InputElement::updateSelectionRange(InputElementData& data, int start, int end)
-{
- if (!data.inputElement()->isTextField())
- return;
-
- if (RenderTextControl* renderer = static_cast<RenderTextControl*>(data.element()->renderer()))
- renderer->setSelectionRange(start, end);
-}
-
-void InputElement::aboutToUnload(InputElementData& data, Document* document)
-{
- if (!data.inputElement()->isTextField() || !data.element()->focused() || !document->frame())
- return;
-
- document->frame()->textFieldDidEndEditing(data.element());
-}
-
-void InputElement::setValueFromRenderer(InputElementData& data, Document* document, const String& value)
-{
- // Renderer and our event handler are responsible for constraining values.
- ASSERT(value == data.inputElement()->constrainValue(value) || data.inputElement()->constrainValue(value).isEmpty());
-
- if (data.inputElement()->isTextField())
- updatePlaceholderVisibility(data, document);
-
- // Workaround for bug where trailing \n is included in the result of textContent.
- // The assert macro above may also be simplified to: value == constrainValue(value)
- // http://bugs.webkit.org/show_bug.cgi?id=9661
- if (value == "\n")
- data.setValue("");
- else
- data.setValue(value);
-
- Element* element = data.element();
- FormControlElement* formControlElement = toFormControlElement(element);
- ASSERT(formControlElement);
- formControlElement->setValueMatchesRenderer();
-
- // Fire the "input" DOM event
- element->dispatchEventForType(eventNames().inputEvent, true, false);
- notifyFormStateChanged(data, document);
-}
-
-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::constrainValue(const InputElementData& data, const String& proposedValue, int maxLength)
-{
- String string = proposedValue;
- if (!data.inputElement()->isTextField())
- return string;
-
- string.replace("\r\n", " ");
- 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];
- 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;
-}
-
-void InputElement::handleBeforeTextInsertedEvent(InputElementData& data, Document* document, Event* event)
-{
- ASSERT(event->isBeforeTextInsertedEvent());
-
- // Make sure that the text to be inserted will not violate the maxLength.
- int oldLength = numGraphemeClusters(data.inputElement()->value().impl());
- ASSERT(oldLength <= data.maxLength());
- int selectionLength = numGraphemeClusters(plainText(document->frame()->selection()->selection().toRange().get()).impl());
- ASSERT(oldLength >= selectionLength);
- int maxNewLength = data.maxLength() - (oldLength - selectionLength);
-
- // Truncate the inserted text to avoid violating the maxLength and other constraints.
- BeforeTextInsertedEvent* textEvent = static_cast<BeforeTextInsertedEvent*>(event);
- textEvent->setText(constrainValue(data, textEvent->text(), maxNewLength));
-}
-
-void InputElement::parseSizeAttribute(InputElementData& data, MappedAttribute* attribute)
-{
- data.setSize(attribute->isNull() ? InputElement::s_defaultSize : attribute->value().toInt());
-
- if (RenderObject* renderer = data.element()->renderer())
- renderer->setNeedsLayoutAndPrefWidthsRecalc();
-}
-
-void InputElement::parseMaxLengthAttribute(InputElementData& data, MappedAttribute* attribute)
-{
- int maxLength = attribute->isNull() ? InputElement::s_maximumLength : attribute->value().toInt();
- if (maxLength <= 0 || maxLength > InputElement::s_maximumLength)
- maxLength = InputElement::s_maximumLength;
-
- int oldMaxLength = data.maxLength();
- data.setMaxLength(maxLength);
-
- if (oldMaxLength != maxLength)
- updateValueIfNeeded(data);
-
- data.element()->setChanged();
-}
-
-void InputElement::updateValueIfNeeded(InputElementData& data)
-{
- String oldValue = data.value();
- String newValue = data.inputElement()->constrainValue(oldValue);
- if (newValue != oldValue)
- data.inputElement()->setValue(newValue);
-}
-
-void InputElement::notifyFormStateChanged(InputElementData& data, Document* document)
-{
- Frame* frame = document->frame();
- if (!frame)
- return;
-
- if (Page* page = frame->page())
- page->chrome()->client()->formStateDidChange(data.element());
-}
-
-// InputElementData
-InputElementData::InputElementData(InputElement* inputElement, Element* element)
- : m_inputElement(inputElement)
- , m_element(element)
- , m_placeholderShouldBeVisible(false)
- , m_size(InputElement::s_defaultSize)
- , m_maxLength(InputElement::s_maximumLength)
- , m_cachedSelectionStart(-1)
- , m_cachedSelectionEnd(-1)
-{
- ASSERT(m_inputElement);
- ASSERT(m_element);
-}
-
-InputElementData::~InputElementData()
-{
-}
-
-const AtomicString& InputElementData::name() const
-{
- return m_name.isNull() ? emptyAtom : m_name;
-}
-
-InputElement* toInputElement(Element* element)
-{
- if (element->isHTMLElement() && (element->hasTagName(inputTag) || element->hasTagName(isindexTag)))
- return static_cast<HTMLInputElement*>(element);
-
-#if ENABLE(WML)
- if (element->isWMLElement() && element->hasTagName(WMLNames::inputTag))
- return static_cast<WMLInputElement*>(element);
-#endif
-
- return 0;
-}
-
-}
+/*
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "InputElement.h"
+
+#include "BeforeTextInsertedEvent.h"
+#include "ChromeClient.h"
+#include "Document.h"
+#include "Event.h"
+#include "EventNames.h"
+#include "FormControlElement.h"
+#include "Frame.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "Page.h"
+#include "RenderTextControlSingleLine.h"
+#include "SelectionController.h"
+#include "TextIterator.h"
+#include "TextBreakIterator.h"
+
+#if ENABLE(WML)
+#include "WMLInputElement.h"
+#include "WMLNames.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// FIXME: According to HTML4, the length attribute's value can be arbitrarily
+// large. However, due to http://bugs.webkit.org/show_bugs.cgi?id=14536 things
+// get rather sluggish when a text field has a larger number of characters than
+// this, even when just clicking in the text field.
+const int InputElement::s_maximumLength = 524288;
+const int InputElement::s_defaultSize = 20;
+
+void InputElement::dispatchFocusEvent(InputElementData& data, Document* document)
+{
+ if (!data.inputElement()->isTextField())
+ return;
+
+ updatePlaceholderVisibility(data, document);
+
+ if (data.inputElement()->isPasswordField() && document->frame())
+ document->setUseSecureKeyboardEntryWhenActive(true);
+}
+
+void InputElement::dispatchBlurEvent(InputElementData& data, Document* document)
+{
+ if (!data.inputElement()->isTextField())
+ return;
+
+ Frame* frame = document->frame();
+ if (!frame)
+ return;
+
+ updatePlaceholderVisibility(data, document);
+
+ if (data.inputElement()->isPasswordField())
+ document->setUseSecureKeyboardEntryWhenActive(false);
+
+ frame->textFieldDidEndEditing(data.element());
+}
+
+void InputElement::updatePlaceholderVisibility(InputElementData& data, Document* document, bool placeholderValueChanged)
+{
+ ASSERT(data.inputElement()->isTextField());
+
+ bool oldPlaceholderShouldBeVisible = data.placeholderShouldBeVisible();
+ Element* element = data.element();
+
+ data.setPlaceholderShouldBeVisible(data.inputElement()->value().isEmpty()
+ && document->focusedNode() != element
+ && !data.inputElement()->placeholderValue().isEmpty());
+
+ if ((oldPlaceholderShouldBeVisible != data.placeholderShouldBeVisible() || placeholderValueChanged) && element->renderer())
+ static_cast<RenderTextControlSingleLine*>(element->renderer())->updatePlaceholderVisibility();
+}
+
+void InputElement::updateFocusAppearance(InputElementData& data, Document* document, bool restorePreviousSelection)
+{
+ ASSERT(data.inputElement()->isTextField());
+
+ if (!restorePreviousSelection || data.cachedSelectionStart() == -1)
+ data.inputElement()->select();
+ else
+ // Restore the cached selection.
+ updateSelectionRange(data, data.cachedSelectionStart(), data.cachedSelectionEnd());
+
+ if (document && document->frame())
+ document->frame()->revealSelection();
+}
+
+void InputElement::updateSelectionRange(InputElementData& data, int start, int end)
+{
+ if (!data.inputElement()->isTextField())
+ return;
+
+ if (RenderTextControl* renderer = static_cast<RenderTextControl*>(data.element()->renderer()))
+ renderer->setSelectionRange(start, end);
+}
+
+void InputElement::aboutToUnload(InputElementData& data, Document* document)
+{
+ if (!data.inputElement()->isTextField() || !data.element()->focused() || !document->frame())
+ return;
+
+ document->frame()->textFieldDidEndEditing(data.element());
+}
+
+void InputElement::setValueFromRenderer(InputElementData& data, Document* document, const String& value)
+{
+ // Renderer and our event handler are responsible for constraining values.
+ ASSERT(value == data.inputElement()->constrainValue(value) || data.inputElement()->constrainValue(value).isEmpty());
+
+ if (data.inputElement()->isTextField())
+ updatePlaceholderVisibility(data, document);
+
+ // Workaround for bug where trailing \n is included in the result of textContent.
+ // The assert macro above may also be simplified to: value == constrainValue(value)
+ // http://bugs.webkit.org/show_bug.cgi?id=9661
+ if (value == "\n")
+ data.setValue("");
+ else
+ data.setValue(value);
+
+ Element* element = data.element();
+ FormControlElement* formControlElement = toFormControlElement(element);
+ ASSERT(formControlElement);
+ formControlElement->setValueMatchesRenderer();
+
+ // Fire the "input" DOM event
+ element->dispatchEventForType(eventNames().inputEvent, true, false);
+ notifyFormStateChanged(data, document);
+}
+
+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::constrainValue(const InputElementData& data, const String& proposedValue, int maxLength)
+{
+ String string = proposedValue;
+ if (!data.inputElement()->isTextField())
+ return string;
+
+ string.replace("\r\n", " ");
+ 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];
+ 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;
+}
+
+void InputElement::handleBeforeTextInsertedEvent(InputElementData& data, Document* document, Event* event)
+{
+ ASSERT(event->isBeforeTextInsertedEvent());
+
+ // Make sure that the text to be inserted will not violate the maxLength.
+ int oldLength = numGraphemeClusters(data.inputElement()->value().impl());
+ ASSERT(oldLength <= data.maxLength());
+ int selectionLength = numGraphemeClusters(plainText(document->frame()->selection()->selection().toNormalizedRange().get()).impl());
+ ASSERT(oldLength >= selectionLength);
+ int maxNewLength = data.maxLength() - (oldLength - selectionLength);
+
+ // Truncate the inserted text to avoid violating the maxLength and other constraints.
+ BeforeTextInsertedEvent* textEvent = static_cast<BeforeTextInsertedEvent*>(event);
+ textEvent->setText(constrainValue(data, textEvent->text(), maxNewLength));
+}
+
+void InputElement::parseSizeAttribute(InputElementData& data, MappedAttribute* attribute)
+{
+ data.setSize(attribute->isNull() ? InputElement::s_defaultSize : attribute->value().toInt());
+
+ if (RenderObject* renderer = data.element()->renderer())
+ renderer->setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+void InputElement::parseMaxLengthAttribute(InputElementData& data, MappedAttribute* attribute)
+{
+ int maxLength = attribute->isNull() ? InputElement::s_maximumLength : attribute->value().toInt();
+ if (maxLength <= 0 || maxLength > InputElement::s_maximumLength)
+ maxLength = InputElement::s_maximumLength;
+
+ int oldMaxLength = data.maxLength();
+ data.setMaxLength(maxLength);
+
+ if (oldMaxLength != maxLength)
+ updateValueIfNeeded(data);
+
+ data.element()->setChanged();
+}
+
+void InputElement::updateValueIfNeeded(InputElementData& data)
+{
+ String oldValue = data.value();
+ String newValue = data.inputElement()->constrainValue(oldValue);
+ if (newValue != oldValue)
+ data.inputElement()->setValue(newValue);
+}
+
+void InputElement::notifyFormStateChanged(InputElementData& data, Document* document)
+{
+ Frame* frame = document->frame();
+ if (!frame)
+ return;
+
+ if (Page* page = frame->page())
+ page->chrome()->client()->formStateDidChange(data.element());
+}
+
+// InputElementData
+InputElementData::InputElementData(InputElement* inputElement, Element* element)
+ : m_inputElement(inputElement)
+ , m_element(element)
+ , m_placeholderShouldBeVisible(false)
+ , m_size(InputElement::s_defaultSize)
+ , m_maxLength(InputElement::s_maximumLength)
+ , m_cachedSelectionStart(-1)
+ , m_cachedSelectionEnd(-1)
+{
+ ASSERT(m_inputElement);
+ ASSERT(m_element);
+}
+
+InputElementData::~InputElementData()
+{
+}
+
+const AtomicString& InputElementData::name() const
+{
+ return m_name.isNull() ? emptyAtom : m_name;
+}
+
+InputElement* toInputElement(Element* element)
+{
+ if (element->isHTMLElement() && (element->hasTagName(inputTag) || element->hasTagName(isindexTag)))
+ return static_cast<HTMLInputElement*>(element);
+
+#if ENABLE(WML)
+ if (element->isWMLElement() && element->hasTagName(WMLNames::inputTag))
+ return static_cast<WMLInputElement*>(element);
+#endif
+
+ return 0;
+}
+
+}
« no previous file with comments | « third_party/WebKit/WebCore/dom/Element.cpp ('k') | third_party/WebKit/WebCore/dom/Node.h » ('j') | no next file with comments »

Powered by Google App Engine