summaryrefslogtreecommitdiffstats
path: root/WebCore/html/HTMLInputElement.cpp
diff options
context:
space:
mode:
authorKristian Monsen <kristianm@google.com>2010-09-08 12:18:00 +0100
committerKristian Monsen <kristianm@google.com>2010-09-11 12:08:58 +0100
commit5ddde30071f639962dd557c453f2ad01f8f0fd00 (patch)
tree775803c4ab35af50aa5f5472cd1fb95fe9d5152d /WebCore/html/HTMLInputElement.cpp
parent3e63d9b33b753ca86d0765d1b3d711114ba9e34f (diff)
downloadexternal_webkit-5ddde30071f639962dd557c453f2ad01f8f0fd00.zip
external_webkit-5ddde30071f639962dd557c453f2ad01f8f0fd00.tar.gz
external_webkit-5ddde30071f639962dd557c453f2ad01f8f0fd00.tar.bz2
Merge WebKit at r66666 : Initial merge by git.
Change-Id: I57dedeb49859adc9c539e760f0e749768c66626f
Diffstat (limited to 'WebCore/html/HTMLInputElement.cpp')
-rw-r--r--WebCore/html/HTMLInputElement.cpp166
1 files changed, 136 insertions, 30 deletions
diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp
index f9c5162..c2e5416 100644
--- a/WebCore/html/HTMLInputElement.cpp
+++ b/WebCore/html/HTMLInputElement.cpp
@@ -111,12 +111,44 @@ static const double weekDefaultStepBase = -259200000.0; // The first day of 1970
static const double msecPerMinute = 60 * 1000;
static const double msecPerSecond = 1000;
+static const char emailPattern[] =
+ "[a-z0-9!#$%&'*+/=?^_`{|}~.-]+" // local part
+ "@"
+ "[a-z0-9-]+(\\.[a-z0-9-]+)+"; // domain part
+
static bool isNumberCharacter(UChar ch)
{
return ch == '+' || ch == '-' || ch == '.' || ch == 'e' || ch == 'E'
|| (ch >= '0' && ch <= '9');
}
+static bool isValidColorString(const String& value)
+{
+ if (value.isEmpty())
+ return false;
+ if (value[0] == '#') {
+ // We don't accept #rgb and #aarrggbb formats.
+ if (value.length() != 7)
+ return false;
+ }
+ Color color(value); // This accepts named colors such as "white".
+ return color.isValid() && !color.hasAlpha();
+}
+
+static bool isValidEmailAddress(const String& address)
+{
+ int addressLength = address.length();
+ if (!addressLength)
+ return false;
+
+ DEFINE_STATIC_LOCAL(const RegularExpression, regExp, (emailPattern, TextCaseInsensitive));
+
+ int matchLength;
+ int matchOffset = regExp.match(address, 0, &matchLength);
+
+ return !matchOffset && matchLength == addressLength;
+}
+
HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
: HTMLTextFormControlElement(tagName, document, form)
, m_xPos(0)
@@ -208,7 +240,71 @@ void HTMLInputElement::updateCheckedRadioButtons()
renderer()->theme()->stateChanged(renderer(), CheckedState);
}
-bool HTMLInputElement::valueMissing() const
+bool HTMLInputElement::isValidValue(const String& value) const
+{
+ // Should not call isValidValue() for the following types because
+ // we can't set string values for these types.
+ if (inputType() == CHECKBOX || inputType() == FILE || inputType() == RADIO) {
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+ return !typeMismatch(value)
+ && !stepMismatch(value)
+ && !rangeUnderflow(value)
+ && !rangeOverflow(value)
+ && !tooLong(value, IgnoreDirtyFlag)
+ && !patternMismatch(value)
+ && !valueMissing(value);
+}
+
+bool HTMLInputElement::typeMismatch(const String& value) const
+{
+ switch (inputType()) {
+ case COLOR:
+ return !isValidColorString(value);
+ case NUMBER:
+ return !parseToDoubleForNumberType(value, 0);
+ case URL:
+ return !KURL(KURL(), value).isValid();
+ case EMAIL: {
+ if (!multiple())
+ return !isValidEmailAddress(value);
+ Vector<String> addresses;
+ value.split(',', addresses);
+ for (unsigned i = 0; i < addresses.size(); ++i) {
+ if (!isValidEmailAddress(addresses[i]))
+ return true;
+ }
+ return false;
+ }
+ case DATE:
+ case DATETIME:
+ case DATETIMELOCAL:
+ case MONTH:
+ case TIME:
+ case WEEK:
+ return !parseToDateComponents(inputType(), value, 0);
+ case BUTTON:
+ case CHECKBOX:
+ case FILE:
+ case HIDDEN:
+ case IMAGE:
+ case ISINDEX:
+ case PASSWORD:
+ case RADIO:
+ case RANGE:
+ case RESET:
+ case SEARCH:
+ case SUBMIT:
+ case TELEPHONE:
+ case TEXT:
+ return false;
+ }
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+bool HTMLInputElement::valueMissing(const String& value) const
{
if (!isRequiredFormControl() || readOnly() || disabled())
return false;
@@ -228,7 +324,7 @@ bool HTMLInputElement::valueMissing() const
case TIME:
case URL:
case WEEK:
- return value().isEmpty();
+ return value.isEmpty();
case CHECKBOX:
return !checked();
case RADIO:
@@ -249,12 +345,11 @@ bool HTMLInputElement::valueMissing() const
return false;
}
-bool HTMLInputElement::patternMismatch() const
+bool HTMLInputElement::patternMismatch(const String& value) const
{
if (!isTextType())
return false;
const AtomicString& pattern = getAttribute(patternAttr);
- String value = this->value();
// Empty values can't be mismatched
if (pattern.isEmpty() || value.isEmpty())
return false;
@@ -265,7 +360,7 @@ bool HTMLInputElement::patternMismatch() const
return matchOffset || matchLength != valueLength;
}
-bool HTMLInputElement::tooLong() const
+bool HTMLInputElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) const
{
// We use isTextType() instead of supportsMaxLength() because of the
// 'virtual' overhead.
@@ -274,14 +369,16 @@ bool HTMLInputElement::tooLong() const
int max = maxLength();
if (max < 0)
return false;
- // Return false for the default value even if it is longer than maxLength.
- bool userEdited = !m_data.value().isNull();
- if (!userEdited)
- return false;
- return numGraphemeClusters(value()) > static_cast<unsigned>(max);
+ if (check == CheckDirtyFlag) {
+ // Return false for the default value even if it is longer than maxLength.
+ bool userEdited = !m_data.value().isNull();
+ if (!userEdited)
+ return false;
+ }
+ return numGraphemeClusters(value) > static_cast<unsigned>(max);
}
-bool HTMLInputElement::rangeUnderflow() const
+bool HTMLInputElement::rangeUnderflow(const String& value) const
{
const double nan = numeric_limits<double>::quiet_NaN();
switch (inputType()) {
@@ -292,11 +389,11 @@ bool HTMLInputElement::rangeUnderflow() const
case NUMBER:
case TIME:
case WEEK: {
- double doubleValue = parseToDouble(value(), nan);
+ double doubleValue = parseToDouble(value, nan);
return isfinite(doubleValue) && doubleValue < minimum();
}
case RANGE: // Guaranteed by sanitization.
- ASSERT(parseToDouble(value(), nan) >= minimum());
+ ASSERT(parseToDouble(value, nan) >= minimum());
case BUTTON:
case CHECKBOX:
case COLOR:
@@ -318,7 +415,7 @@ bool HTMLInputElement::rangeUnderflow() const
return false;
}
-bool HTMLInputElement::rangeOverflow() const
+bool HTMLInputElement::rangeOverflow(const String& value) const
{
const double nan = numeric_limits<double>::quiet_NaN();
switch (inputType()) {
@@ -329,11 +426,11 @@ bool HTMLInputElement::rangeOverflow() const
case NUMBER:
case TIME:
case WEEK: {
- double doubleValue = parseToDouble(value(), nan);
+ double doubleValue = parseToDouble(value, nan);
return isfinite(doubleValue) && doubleValue > maximum();
}
case RANGE: // Guaranteed by sanitization.
- ASSERT(parseToDouble(value(), nan) <= maximum());
+ ASSERT(parseToDouble(value, nan) <= maximum());
case BUTTON:
case CHECKBOX:
case COLOR:
@@ -478,7 +575,7 @@ double HTMLInputElement::stepBase() const
return 0.0;
}
-bool HTMLInputElement::stepMismatch() const
+bool HTMLInputElement::stepMismatch(const String& value) const
{
double step;
if (!getAllowedValueStep(&step))
@@ -491,7 +588,7 @@ bool HTMLInputElement::stepMismatch() const
return false;
case NUMBER: {
double doubleValue;
- if (!parseToDoubleForNumberType(value(), &doubleValue))
+ if (!parseToDoubleForNumberType(value, &doubleValue))
return false;
doubleValue = fabs(doubleValue - stepBase());
if (isinf(doubleValue))
@@ -513,7 +610,7 @@ bool HTMLInputElement::stepMismatch() const
case TIME:
case WEEK: {
const double nan = numeric_limits<double>::quiet_NaN();
- double doubleValue = parseToDouble(value(), nan);
+ double doubleValue = parseToDouble(value, nan);
doubleValue = fabs(doubleValue - stepBase());
if (!isfinite(doubleValue))
return false;
@@ -1175,8 +1272,11 @@ RenderObject* HTMLInputElement::createRenderer(RenderArena *arena, RenderStyle *
return new (arena) RenderFileUploadControl(this);
case HIDDEN:
break;
- case IMAGE:
- return new (arena) RenderImage(this);
+ case IMAGE: {
+ RenderImage* image = new (arena) RenderImage(this);
+ image->setImageResource(RenderImageResource::create());
+ return image;
+ }
case RANGE:
return new (arena) RenderSlider(this);
case COLOR:
@@ -1215,13 +1315,14 @@ void HTMLInputElement::attach()
m_imageLoader = adoptPtr(new HTMLImageLoader(this));
m_imageLoader->updateFromElement();
if (renderer() && m_imageLoader->haveFiredBeforeLoadEvent()) {
- RenderImage* imageObj = toRenderImage(renderer());
- imageObj->setCachedImage(m_imageLoader->image());
-
+ RenderImage* renderImage = toRenderImage(renderer());
+ RenderImageResource* renderImageResource = renderImage->imageResource();
+ renderImageResource->setCachedImage(m_imageLoader->image());
+
// If we have no image at all because we have no src attribute, set
// image height and width for the alt text instead.
- if (!m_imageLoader->image() && !imageObj->cachedImage())
- imageObj->setImageSizeForAltText();
+ if (!m_imageLoader->image() && !renderImageResource->cachedImage())
+ renderImage->setImageSizeForAltText();
}
}
@@ -1501,11 +1602,16 @@ void HTMLInputElement::copyNonAttributeProperties(const Element* source)
String HTMLInputElement::value() const
{
- // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control
- // but we don't want to break existing websites, who may be relying on being able to get the file name as a value.
if (inputType() == FILE) {
- if (!m_fileList->isEmpty())
- return m_fileList->item(0)->fileName();
+ if (!m_fileList->isEmpty()) {
+ // HTML5 tells us that we're supposed to use this goofy value for
+ // file input controls. Historically, browsers reveals the real
+ // file path, but that's a privacy problem. Code on the web
+ // decided to try to parse the value by looking for backslashes
+ // (because that's what Windows file paths use). To be compatible
+ // with that code, we make up a fake path for the file.
+ return "C:\\fakepath\\" + m_fileList->item(0)->fileName();
+ }
return String();
}