summaryrefslogtreecommitdiffstats
path: root/WebCore/html/HTMLInputElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html/HTMLInputElement.cpp')
-rw-r--r--WebCore/html/HTMLInputElement.cpp445
1 files changed, 166 insertions, 279 deletions
diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp
index c5c55fd..c451680 100644
--- a/WebCore/html/HTMLInputElement.cpp
+++ b/WebCore/html/HTMLInputElement.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "HTMLInputElement.h"
-#include "BeforeTextInsertedEvent.h"
+#include "ChromeClient.h"
#include "CSSPropertyNames.h"
#include "Document.h"
#include "Editor.h"
@@ -50,10 +50,8 @@
#include "RenderImage.h"
#include "RenderSlider.h"
#include "RenderText.h"
-#include "RenderTextControl.h"
+#include "RenderTextControlSingleLine.h"
#include "RenderTheme.h"
-#include "SelectionController.h"
-#include "TextBreakIterator.h"
#include "TextEvent.h"
#if USE(LOW_BANDWIDTH_DISPLAY)
#include "FrameLoader.h"
@@ -61,7 +59,7 @@
#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
#include "WebViewCore.h"
#endif
-#include "TextIterator.h"
+#include <wtf/StdLibExtras.h>
using namespace std;
@@ -71,76 +69,24 @@ using namespace HTMLNames;
const int maxSavedResults = 256;
-// 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.
-static const int cMaxLen = 524288;
-
-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;
-}
-
-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);
-}
-
-HTMLInputElement::HTMLInputElement(Document* doc, HTMLFormElement* f)
- : HTMLFormControlElementWithState(inputTag, doc, f)
-{
- init();
-}
-
HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
: HTMLFormControlElementWithState(tagName, doc, f)
-{
- init();
-}
-
-void HTMLInputElement::init()
-{
- m_type = TEXT;
- m_maxLen = cMaxLen;
- m_size = 20;
- m_checked = false;
- m_defaultChecked = false;
- m_useDefaultChecked = true;
- m_indeterminate = false;
-
- m_haveType = false;
- m_activeSubmit = false;
- m_autocomplete = Uninitialized;
- m_inited = false;
- m_autofilled = false;
- m_placeholderShouldBeVisible = false;
-
- xPos = 0;
- yPos = 0;
-
- cachedSelStart = -1;
- cachedSelEnd = -1;
-
- m_maxResults = -1;
+ , m_data(this, this)
+ , m_xPos(0)
+ , m_yPos(0)
+ , m_maxResults(-1)
+ , m_type(TEXT)
+ , m_checked(false)
+ , m_defaultChecked(false)
+ , m_useDefaultChecked(true)
+ , m_indeterminate(false)
+ , m_haveType(false)
+ , m_activeSubmit(false)
+ , m_autocomplete(Uninitialized)
+ , m_autofilled(false)
+ , m_inited(false)
+{
+ ASSERT(hasTagName(inputTag) || hasTagName(isindexTag));
}
HTMLInputElement::~HTMLInputElement()
@@ -157,7 +103,7 @@ HTMLInputElement::~HTMLInputElement()
const AtomicString& HTMLInputElement::name() const
{
- return m_name.isNull() ? emptyAtom : m_name;
+ return m_data.name();
}
bool HTMLInputElement::autoComplete() const
@@ -193,9 +139,6 @@ bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
return false;
if (inputType() == RADIO) {
- // Unnamed radio buttons are never focusable (matches WinIE).
- if (name().isEmpty())
- return false;
// Never allow keyboard tabbing to leave you in the same radio group. Always
// skip any other elements in the group.
@@ -223,23 +166,15 @@ bool HTMLInputElement::isMouseFocusable() const
void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
{
- if (isTextField()) {
- if (!restorePreviousSelection || cachedSelStart == -1)
- select();
- else
- // Restore the cached selection.
- setSelectionRange(cachedSelStart, cachedSelEnd);
-
- if (document() && document()->frame())
- document()->frame()->revealSelection();
- } else
+ if (isTextField())
+ InputElement::updateFocusAppearance(m_data, document(), restorePreviousSelection);
+ else
HTMLFormControlElementWithState::updateFocusAppearance(restorePreviousSelection);
}
void HTMLInputElement::aboutToUnload()
{
- if (isTextField() && focused() && document()->frame())
- document()->frame()->textFieldDidEndEditing(this);
+ InputElement::aboutToUnload(m_data, document());
}
bool HTMLInputElement::shouldUseInputMethod() const
@@ -249,23 +184,17 @@ bool HTMLInputElement::shouldUseInputMethod() const
void HTMLInputElement::dispatchFocusEvent()
{
- if (isTextField()) {
- setAutofilled(false);
- updatePlaceholderVisibility();
- if (inputType() == PASSWORD && document()->frame())
- document()->setUseSecureKeyboardEntryWhenActive(true);
- }
+ InputElement::dispatchFocusEvent(m_data, document());
+
+ if (isTextField())
+ m_autofilled = false;
+
HTMLFormControlElementWithState::dispatchFocusEvent();
}
void HTMLInputElement::dispatchBlurEvent()
{
- if (isTextField() && document()->frame()) {
- updatePlaceholderVisibility();
- if (inputType() == PASSWORD)
- document()->setUseSecureKeyboardEntryWhenActive(false);
- document()->frame()->textFieldDidEndEditing(this);
- }
+ InputElement::dispatchBlurEvent(m_data, document());
HTMLFormControlElementWithState::dispatchBlurEvent();
}
@@ -345,14 +274,14 @@ void HTMLInputElement::setInputType(const String& t)
bool isPasswordField = inputType() == PASSWORD;
bool willRespectHeightAndWidth = respectHeightAndWidthAttrs();
- if (didStoreValue && !willStoreValue && !m_value.isNull()) {
- setAttribute(valueAttr, m_value);
- m_value = String();
+ if (didStoreValue && !willStoreValue && !m_data.value().isNull()) {
+ setAttribute(valueAttr, m_data.value());
+ m_data.setValue(String());
}
if (!didStoreValue && willStoreValue)
- m_value = constrainValue(getAttribute(valueAttr));
+ m_data.setValue(constrainValue(getAttribute(valueAttr)));
else
- recheckValue();
+ InputElement::updateValueIfNeeded(m_data);
if (wasPasswordField && !isPasswordField)
unregisterForActivationCallbackIfNeeded();
@@ -377,6 +306,8 @@ void HTMLInputElement::setInputType(const String& t)
checkedRadioButtons(this).addButton(this);
}
+
+ InputElement::notifyFormStateChanged(m_data, document());
}
m_haveType = true;
@@ -389,53 +320,53 @@ const AtomicString& HTMLInputElement::type() const
// needs to be lowercase according to DOM spec
switch (inputType()) {
case BUTTON: {
- static const AtomicString button("button");
+ DEFINE_STATIC_LOCAL(const AtomicString, button, ("button"));
return button;
}
case CHECKBOX: {
- static const AtomicString checkbox("checkbox");
+ DEFINE_STATIC_LOCAL(const AtomicString, checkbox, ("checkbox"));
return checkbox;
}
case FILE: {
- static const AtomicString file("file");
+ DEFINE_STATIC_LOCAL(const AtomicString, file, ("file"));
return file;
}
case HIDDEN: {
- static const AtomicString hidden("hidden");
+ DEFINE_STATIC_LOCAL(const AtomicString, hidden, ("hidden"));
return hidden;
}
case IMAGE: {
- static const AtomicString image("image");
+ DEFINE_STATIC_LOCAL(const AtomicString, image, ("image"));
return image;
}
case ISINDEX:
return emptyAtom;
case PASSWORD: {
- static const AtomicString password("password");
+ DEFINE_STATIC_LOCAL(const AtomicString, password, ("password"));
return password;
}
case RADIO: {
- static const AtomicString radio("radio");
+ DEFINE_STATIC_LOCAL(const AtomicString, radio, ("radio"));
return radio;
}
case RANGE: {
- static const AtomicString range("range");
+ DEFINE_STATIC_LOCAL(const AtomicString, range, ("range"));
return range;
}
case RESET: {
- static const AtomicString reset("reset");
+ DEFINE_STATIC_LOCAL(const AtomicString, reset, ("reset"));
return reset;
}
case SEARCH: {
- static const AtomicString search("search");
+ DEFINE_STATIC_LOCAL(const AtomicString, search, ("search"));
return search;
}
case SUBMIT: {
- static const AtomicString submit("submit");
+ DEFINE_STATIC_LOCAL(const AtomicString, submit, ("submit"));
return submit;
}
case TEXT: {
- static const AtomicString text("text");
+ DEFINE_STATIC_LOCAL(const AtomicString, text, ("text"));
return text;
}
}
@@ -512,8 +443,8 @@ int HTMLInputElement::selectionStart() const
{
if (!isTextField())
return 0;
- if (document()->focusedNode() != this && cachedSelStart != -1)
- return cachedSelStart;
+ if (document()->focusedNode() != this && m_data.cachedSelectionStart() != -1)
+ return m_data.cachedSelectionStart();
if (!renderer())
return 0;
return static_cast<RenderTextControl*>(renderer())->selectionStart();
@@ -523,8 +454,8 @@ int HTMLInputElement::selectionEnd() const
{
if (!isTextField())
return 0;
- if (document()->focusedNode() != this && cachedSelEnd != -1)
- return cachedSelEnd;
+ if (document()->focusedNode() != this && m_data.cachedSelectionEnd() != -1)
+ return m_data.cachedSelectionEnd();
if (!renderer())
return 0;
return static_cast<RenderTextControl*>(renderer())->selectionEnd();
@@ -559,11 +490,7 @@ void HTMLInputElement::select()
void HTMLInputElement::setSelectionRange(int start, int end)
{
- if (!isTextField())
- return;
- if (!renderer())
- return;
- static_cast<RenderTextControl*>(renderer())->setSelectionRange(start, end);
+ InputElement::updateSelectionRange(m_data, start, end);
}
void HTMLInputElement::accessKeyAction(bool sendToAnyElement)
@@ -618,7 +545,7 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr)
{
if (attr->name() == nameAttr) {
checkedRadioButtons(this).removeButton(this);
- m_name = attr->value();
+ m_data.setName(attr->value());
checkedRadioButtons(this).addButton(this);
} else if (attr->name() == autocompleteAttr) {
if (equalIgnoringCase(attr->value(), "off")) {
@@ -636,7 +563,7 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr)
setInputType(attr->value());
} else if (attr->name() == valueAttr) {
// We only need to setChanged if the form is looking at the default value right now.
- if (m_value.isNull())
+ if (m_data.value().isNull())
setChanged();
setValueMatchesRenderer(false);
} else if (attr->name() == checkedAttr) {
@@ -645,24 +572,18 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr)
setChecked(m_defaultChecked);
m_useDefaultChecked = true;
}
- } else if (attr->name() == maxlengthAttr) {
- int oldMaxLen = m_maxLen;
- m_maxLen = !attr->isNull() ? attr->value().toInt() : cMaxLen;
- if (m_maxLen <= 0 || m_maxLen > cMaxLen)
- m_maxLen = cMaxLen;
- if (oldMaxLen != m_maxLen)
- recheckValue();
- setChanged();
- } else if (attr->name() == sizeAttr) {
- m_size = !attr->isNull() ? attr->value().toInt() : 20;
- } else if (attr->name() == altAttr) {
+ } else if (attr->name() == maxlengthAttr)
+ InputElement::parseMaxLengthAttribute(m_data, attr);
+ else if (attr->name() == sizeAttr)
+ InputElement::parseSizeAttribute(m_data, attr);
+ else if (attr->name() == altAttr) {
if (renderer() && inputType() == IMAGE)
static_cast<RenderImage*>(renderer())->updateAltText();
} else if (attr->name() == srcAttr) {
if (renderer() && inputType() == IMAGE) {
if (!m_imageLoader)
m_imageLoader.set(new HTMLImageLoader(this));
- m_imageLoader->updateFromElement();
+ m_imageLoader->updateFromElementIgnoringPreviousError();
}
} else if (attr->name() == usemapAttr ||
attr->name() == accesskeyAttr) {
@@ -707,14 +628,15 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr)
attach();
}
setChanged();
- } else if (attr->name() == placeholderAttr)
- updatePlaceholderVisibility(true);
- else if (attr->name() == autosaveAttr ||
- attr->name() == incrementalAttr ||
- attr->name() == minAttr ||
- attr->name() == maxAttr ||
- attr->name() == multipleAttr ||
- attr->name() == precisionAttr)
+ } else if (attr->name() == placeholderAttr) {
+ if (isTextField())
+ InputElement::updatePlaceholderVisibility(m_data, document(), true);
+ } else if (attr->name() == autosaveAttr ||
+ attr->name() == incrementalAttr ||
+ attr->name() == minAttr ||
+ attr->name() == maxAttr ||
+ attr->name() == multipleAttr ||
+ attr->name() == precisionAttr)
setChanged();
else
HTMLFormControlElementWithState::parseMappedAttribute(attr);
@@ -772,7 +694,7 @@ RenderObject *HTMLInputElement::createRenderer(RenderArena *arena, RenderStyle *
case PASSWORD:
case SEARCH:
case TEXT:
- return new (arena) RenderTextControl(this, false);
+ return new (arena) RenderTextControlSingleLine(this);
}
ASSERT(false);
return 0;
@@ -875,8 +797,8 @@ bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart)
case IMAGE:
if (m_activeSubmit) {
- encoding.appendData(name().isEmpty() ? "x" : (name() + ".x"), xPos);
- encoding.appendData(name().isEmpty() ? "y" : (name() + ".y"), yPos);
+ encoding.appendData(name().isEmpty() ? "x" : (name() + ".x"), m_xPos);
+ encoding.appendData(name().isEmpty() ? "y" : (name() + ".y"), m_yPos);
if (!name().isEmpty() && !value().isEmpty())
encoding.appendData(name(), value());
return true;
@@ -960,14 +882,19 @@ void HTMLInputElement::setIndeterminate(bool _indeterminate)
theme()->stateChanged(renderer(), CheckedState);
}
-void HTMLInputElement::copyNonAttributeProperties(const Element *source)
+int HTMLInputElement::size() const
{
- const HTMLInputElement *sourceElem = static_cast<const HTMLInputElement *>(source);
+ return m_data.size();
+}
+
+void HTMLInputElement::copyNonAttributeProperties(const Element* source)
+{
+ const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source);
+
+ m_data.setValue(sourceElement->m_data.value());
+ m_checked = sourceElement->m_checked;
+ m_indeterminate = sourceElement->m_indeterminate;
- m_value = sourceElem->m_value;
- m_checked = sourceElem->m_checked;
- m_indeterminate = sourceElem->m_indeterminate;
-
HTMLFormControlElementWithState::copyNonAttributeProperties(source);
}
@@ -981,7 +908,7 @@ String HTMLInputElement::value() const
return String();
}
- String value = m_value;
+ String value = m_data.value();
if (value.isNull()) {
value = constrainValue(getAttribute(valueAttr));
@@ -1030,14 +957,14 @@ void HTMLInputElement::setValue(const String& value)
return;
if (isTextField())
- updatePlaceholderVisibility();
-
+ InputElement::updatePlaceholderVisibility(m_data, document());
+
setValueMatchesRenderer(false);
if (storesValueSeparateFromAttribute()) {
if (inputType() == FILE)
m_fileList->clear();
else {
- m_value = constrainValue(value);
+ m_data.setValue(constrainValue(value));
if (isTextField() && inDocument())
document()->updateRendering();
}
@@ -1048,47 +975,38 @@ void HTMLInputElement::setValue(const String& value)
setAttribute(valueAttr, constrainValue(value));
if (isTextField()) {
- unsigned max = m_value.length();
+ unsigned max = m_data.value().length();
if (document()->focusedNode() == this)
-#ifndef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
- setSelectionRange(max, max);
-#else
+#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
{
// Make sure our UI side textfield changes to match the RenderTextControl
android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, false, value);
- setSelectionRange(max, max);
- }
#endif
- else {
- cachedSelStart = max;
- cachedSelEnd = max;
+ InputElement::updateSelectionRange(m_data, max, max);
+#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
}
+#endif
+ else
+ cacheSelection(max, max);
}
+ InputElement::notifyFormStateChanged(m_data, document());
}
-void HTMLInputElement::setValueFromRenderer(const String& value)
+String HTMLInputElement::placeholderValue() const
{
- // Renderer and our event handler are responsible for constraining values.
- ASSERT(value == constrainValue(value) || constrainValue(value).isEmpty());
-
- // File upload controls will always use setFileListFromRenderer.
- ASSERT (inputType() != FILE);
-
- if (isTextField())
- updatePlaceholderVisibility();
-
- // 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")
- m_value = "";
- else
- m_value = value;
+ return getAttribute(placeholderAttr).string();
+}
- setValueMatchesRenderer();
+bool HTMLInputElement::searchEventsShouldBeDispatched() const
+{
+ return hasAttribute(incrementalAttr);
+}
- // Fire the "input" DOM event.
- dispatchEventForType(eventNames().inputEvent, true, false);
+void HTMLInputElement::setValueFromRenderer(const String& value)
+{
+ // File upload controls will always use setFileListFromRenderer.
+ ASSERT(inputType() != FILE);
+ InputElement::setValueFromRenderer(m_data, document(), value);
}
void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
@@ -1099,6 +1017,7 @@ void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
m_fileList->append(File::create(paths[i]));
setValueMatchesRenderer();
+ InputElement::notifyFormStateChanged(m_data, document());
}
bool HTMLInputElement::storesValueSeparateFromAttribute() const
@@ -1143,11 +1062,6 @@ void* HTMLInputElement::preDispatchEventHandler(Event *evt)
}
} else {
// For radio buttons, store the current selected radio object.
- if (name().isEmpty() || checked())
- return 0; // Match WinIE and don't allow unnamed radio buttons to be checked.
- // Checked buttons just stay checked.
- // FIXME: Need to learn to work without a form.
-
// We really want radio groups to end up in sane states, i.e., to have something checked.
// Therefore if nothing is currently selected, we won't allow this action to be "undone", since
// we want some object in the radio group to actually get selected.
@@ -1183,8 +1097,7 @@ void HTMLInputElement::postDispatchEventHandler(Event *evt, void* data)
// Make sure it is still a radio button and only do the restoration if it still
// belongs to our group.
- // Match WinIE and don't allow unnamed radio buttons to be checked.
- if (input->form() == form() && input->inputType() == RADIO && !name().isEmpty() && input->name() == name()) {
+ if (input->form() == form() && input->inputType() == RADIO && input->name() == name()) {
// Ok, the old radio button is still in our form and in our group and is still a
// radio button, so it's safe to restore selection to it.
input->setChecked(true);
@@ -1211,25 +1124,24 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
// FIXME: We could just call offsetX() and offsetY() on the event,
// but that's currently broken, so for now do the computation here.
if (me->isSimulated() || !renderer()) {
- xPos = 0;
- yPos = 0;
+ m_xPos = 0;
+ m_yPos = 0;
} else {
- int offsetX, offsetY;
- renderer()->absolutePosition(offsetX, offsetY);
- xPos = me->pageX() - offsetX;
- // FIXME: Why is yPos a short?
- yPos = me->pageY() - offsetY;
+ // FIXME: This doesn't work correctly with transforms.
+ IntPoint absOffset = roundedIntPoint(renderer()->localToAbsolute());
+ m_xPos = me->pageX() - absOffset.x();
+ m_yPos = me->pageY() - absOffset.y();
}
}
if (isTextField() && evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent() && focused() && document()->frame()
- && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) {
+ && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) {
evt->setDefaultHandled();
return;
}
if (inputType() == RADIO && evt->isMouseEvent()
- && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
+ && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
evt->setDefaultHandled();
return;
}
@@ -1253,13 +1165,13 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
form()->reset();
else {
m_activeSubmit = true;
- // FIXME: Would be cleaner to get xPos and yPos out of the underlying mouse
+ // FIXME: Would be cleaner to get m_xPos and m_yPos out of the underlying mouse
// event (if any) here instead of relying on the variables set above when
// processing the click event. Even better, appendFormData could pass the
- // event in, and then we could get rid of xPos and yPos altogether!
+ // event in, and then we could get rid of m_xPos and m_yPos altogether!
if (!form()->prepareSubmit(evt)) {
- xPos = 0;
- yPos = 0;
+ m_xPos = 0;
+ m_yPos = 0;
}
m_activeSubmit = false;
}
@@ -1363,9 +1275,8 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
if (elt->form() != form())
break;
if (n->hasTagName(inputTag)) {
- // Match WinIE and don't allow unnamed radio buttons to be checked.
HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n);
- if (inputElt->inputType() == RADIO && !name().isEmpty() && inputElt->name() == name() && inputElt->isFocusable()) {
+ if (inputElt->inputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) {
inputElt->setChecked(true);
document()->setFocusedNode(inputElt);
inputElt->dispatchSimulatedClick(evt, false, false);
@@ -1440,21 +1351,11 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
return;
}
- if (evt->isBeforeTextInsertedEvent()) {
- // Make sure that the text to be inserted will not violate the maxLength.
- int oldLen = numGraphemeClusters(value().impl());
- ASSERT(oldLen <= maxLength());
- int selectionLen = numGraphemeClusters(plainText(document()->frame()->selection()->selection().toRange().get()).impl());
- ASSERT(oldLen >= selectionLen);
- int maxNewLen = maxLength() - (oldLen - selectionLen);
-
- // Truncate the inserted text to avoid violating the maxLength and other constraints.
- BeforeTextInsertedEvent* textEvent = static_cast<BeforeTextInsertedEvent*>(evt);
- textEvent->setText(constrainValue(textEvent->text(), maxNewLen));
- }
+ if (evt->isBeforeTextInsertedEvent())
+ InputElement::handleBeforeTextInsertedEvent(m_data, document(), evt);
if (isTextField() && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent))
- static_cast<RenderTextControl*>(renderer())->forwardEvent(evt);
+ static_cast<RenderTextControlSingleLine*>(renderer())->forwardEvent(evt);
if (inputType() == RANGE && renderer()) {
RenderSlider* slider = static_cast<RenderSlider*>(renderer());
@@ -1462,11 +1363,8 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
MouseEvent* mEvt = static_cast<MouseEvent*>(evt);
if (!slider->mouseEventIsInThumb(mEvt)) {
IntPoint eventOffset(mEvt->offsetX(), mEvt->offsetY());
- if (mEvt->target() != this) {
- IntRect rect = renderer()->absoluteBoundingBoxRect();
- eventOffset.setX(mEvt->pageX() - rect.x());
- eventOffset.setY(mEvt->pageY() - rect.y());
- }
+ if (mEvt->target() != this) // Does this ever happen now? Was added for <video> controls
+ eventOffset = roundedIntPoint(renderer()->absoluteToLocal(FloatPoint(mEvt->pageX(), mEvt->pageY()), false, true));
slider->setValueForPosition(slider->positionForOffset(eventOffset));
}
}
@@ -1500,6 +1398,11 @@ void HTMLInputElement::setDefaultChecked(bool defaultChecked)
setAttribute(checkedAttr, defaultChecked ? "" : 0);
}
+void HTMLInputElement::setDefaultName(const AtomicString& name)
+{
+ m_data.setName(name);
+}
+
String HTMLInputElement::accept() const
{
return getAttribute(acceptAttr);
@@ -1540,6 +1443,11 @@ void HTMLInputElement::setAlt(const String &value)
setAttribute(altAttr, value);
}
+int HTMLInputElement::maxLength() const
+{
+ return m_data.maxLength();
+}
+
void HTMLInputElement::setMaxLength(int _maxLength)
{
setAttribute(maxlengthAttr, String::number(_maxLength));
@@ -1570,6 +1478,15 @@ void HTMLInputElement::setUseMap(const String &value)
setAttribute(usemapAttr, value);
}
+void HTMLInputElement::setAutofilled(bool b)
+{
+ if (b == m_autofilled)
+ return;
+
+ m_autofilled = b;
+ setChanged();
+}
+
FileList* HTMLInputElement::files()
{
if (inputType() != FILE)
@@ -1579,15 +1496,7 @@ FileList* HTMLInputElement::files()
String HTMLInputElement::constrainValue(const String& proposedValue) const
{
- return constrainValue(proposedValue, m_maxLen);
-}
-
-void HTMLInputElement::recheckValue()
-{
- String oldValue = value();
- String newValue = constrainValue(oldValue);
- if (newValue != oldValue)
- setValue(newValue);
+ return InputElement::constrainValue(m_data, proposedValue, m_data.maxLength());
}
bool HTMLInputElement::needsActivationCallback()
@@ -1607,62 +1516,32 @@ void HTMLInputElement::unregisterForActivationCallbackIfNeeded()
document()->unregisterForDocumentActivationCallbacks(this);
}
-void HTMLInputElement::updatePlaceholderVisibility(bool placeholderValueChanged)
-{
- ASSERT(isTextField());
-
- bool oldPlaceholderShouldBeVisible = m_placeholderShouldBeVisible;
-
- m_placeholderShouldBeVisible = value().isEmpty()
- && document()->focusedNode() != this
- && !getAttribute(placeholderAttr).isEmpty();
-
- if ((oldPlaceholderShouldBeVisible != m_placeholderShouldBeVisible || placeholderValueChanged) && renderer())
- static_cast<RenderTextControl*>(renderer())->updatePlaceholderVisibility();
-}
-
-String HTMLInputElement::constrainValue(const String& proposedValue, int maxLen) const
+void HTMLInputElement::cacheSelection(int start, int end)
{
- String string = proposedValue;
- if (isTextField()) {
- string.replace("\r\n", " ");
- string.replace('\r', ' ');
- string.replace('\n', ' ');
- StringImpl* s = string.impl();
- int newLen = numCharactersInGraphemeClusters(s, maxLen);
- for (int i = 0; i < newLen; ++i) {
- const UChar current = (*s)[i];
- if (current < ' ' && current != '\t') {
- newLen = i;
- break;
- }
- }
- if (newLen < static_cast<int>(string.length()))
- return string.substring(0, newLen);
- }
- return string;
+ m_data.setCachedSelectionStart(start);
+ m_data.setCachedSelectionEnd(end);
}
void HTMLInputElement::addSearchResult()
{
ASSERT(isSearchField());
if (renderer())
- static_cast<RenderTextControl*>(renderer())->addSearchResult();
+ static_cast<RenderTextControlSingleLine*>(renderer())->addSearchResult();
}
void HTMLInputElement::onSearch()
{
ASSERT(isSearchField());
if (renderer())
- static_cast<RenderTextControl*>(renderer())->stopSearchEventTimer();
+ static_cast<RenderTextControlSingleLine*>(renderer())->stopSearchEventTimer();
dispatchEventForType(eventNames().searchEvent, true, false);
}
Selection HTMLInputElement::selection() const
{
- if (!renderer() || !isTextField() || cachedSelStart == -1 || cachedSelEnd == -1)
+ if (!renderer() || !isTextField() || m_data.cachedSelectionStart() == -1 || m_data.cachedSelectionEnd() == -1)
return Selection();
- return static_cast<RenderTextControl*>(renderer())->selection(cachedSelStart, cachedSelEnd);
+ return static_cast<RenderTextControl*>(renderer())->selection(m_data.cachedSelectionStart(), m_data.cachedSelectionEnd());
}
void HTMLInputElement::documentDidBecomeActive()
@@ -1689,9 +1568,11 @@ void HTMLInputElement::didMoveToNewOwnerDocument()
HTMLFormControlElementWithState::didMoveToNewOwnerDocument();
}
-void HTMLInputElement::getSubresourceAttributeStrings(Vector<String>& urls) const
+void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
{
- urls.append(src().string());
+ HTMLFormControlElementWithState::addSubresourceAttributeURLs(urls);
+
+ addSubresourceURL(urls, src());
}
bool HTMLInputElement::willValidate() const
@@ -1700,4 +1581,10 @@ bool HTMLInputElement::willValidate() const
return HTMLFormControlElementWithState::willValidate() && inputType() != HIDDEN &&
inputType() != BUTTON && inputType() != RESET;
}
+
+bool HTMLInputElement::placeholderShouldBeVisible() const
+{
+ return m_data.placeholderShouldBeVisible();
+}
+
} // namespace