HTMLInputElement.cpp [plain text]
#include "config.h"
#include "HTMLInputElement.h"
#include "AXObjectCache.h"
#include "BeforeTextInsertedEvent.h"
#include "CSSPropertyNames.h"
#include "CSSValueKeywords.h"
#include "Document.h"
#include "EventNames.h"
#include "ExceptionCode.h"
#include "FileList.h"
#include "Frame.h"
#include "HTMLCollection.h"
#include "HTMLDataListElement.h"
#include "HTMLFormElement.h"
#include "HTMLNames.h"
#include "HTMLOptionElement.h"
#include "HTMLParserIdioms.h"
#include "InputType.h"
#include "KeyboardEvent.h"
#include "LocalizedStrings.h"
#include "MouseEvent.h"
#include "NumberInputType.h"
#include "RenderTextControlSingleLine.h"
#include "RenderTheme.h"
#include "SearchInputType.h"
#include "ShadowRoot.h"
#include "ScriptEventListener.h"
#include "WheelEvent.h"
#include <wtf/MathExtras.h>
#include <wtf/StdLibExtras.h>
#if ENABLE(INPUT_TYPE_COLOR)
#include "ColorInputType.h"
#endif
#if ENABLE(INPUT_SPEECH)
#include "RuntimeEnabledFeatures.h"
#endif
#include "TouchEvent.h"
using namespace std;
namespace WebCore {
using namespace HTMLNames;
const int HTMLInputElement::maximumLength = 524288;
const int defaultSize = 20;
const int maxSavedResults = 256;
HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser)
: HTMLTextFormControlElement(tagName, document, form)
, m_size(defaultSize)
, m_maxLength(maximumLength)
, m_maxResults(-1)
, m_isChecked(false)
, m_reflectsCheckedAttribute(true)
, m_isIndeterminate(false)
, m_hasType(false)
, m_isActivatedSubmit(false)
, m_autocomplete(Uninitialized)
, m_isAutofilled(false)
, m_stateRestored(false)
, m_parsingInProgress(createdByParser)
, m_wasModifiedByUser(false)
, m_canReceiveDroppedFiles(false)
, m_inputType(InputType::createText(this))
{
ASSERT(hasTagName(inputTag) || hasTagName(isindexTag));
}
PassRefPtr<HTMLInputElement> HTMLInputElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser)
{
RefPtr<HTMLInputElement> inputElement = adoptRef(new HTMLInputElement(tagName, document, form, createdByParser));
inputElement->createShadowSubtree();
return inputElement.release();
}
void HTMLInputElement::createShadowSubtree()
{
ASSERT(!hasShadowRoot());
ShadowRoot::create(this, ShadowRoot::CreatingUserAgentShadowRoot, ASSERT_NO_EXCEPTION);
m_inputType->createShadowSubtree();
}
HTMLInputElement::~HTMLInputElement()
{
if (needsSuspensionCallback())
document()->unregisterForPageCacheSuspensionCallbacks(this);
setForm(0);
if (isRadioButton())
document()->checkedRadioButtons().removeButton(this);
}
const AtomicString& HTMLInputElement::formControlName() const
{
return m_name.isNull() ? emptyAtom : m_name;
}
HTMLElement* HTMLInputElement::containerElement() const
{
return m_inputType->containerElement();
}
HTMLElement* HTMLInputElement::innerTextElement() const
{
return m_inputType->innerTextElement();
}
HTMLElement* HTMLInputElement::innerBlockElement() const
{
return m_inputType->innerBlockElement();
}
HTMLElement* HTMLInputElement::innerSpinButtonElement() const
{
return m_inputType->innerSpinButtonElement();
}
HTMLElement* HTMLInputElement::resultsButtonElement() const
{
return m_inputType->resultsButtonElement();
}
HTMLElement* HTMLInputElement::cancelButtonElement() const
{
return m_inputType->cancelButtonElement();
}
#if ENABLE(INPUT_SPEECH)
HTMLElement* HTMLInputElement::speechButtonElement() const
{
return m_inputType->speechButtonElement();
}
#endif
HTMLElement* HTMLInputElement::placeholderElement() const
{
return m_inputType->placeholderElement();
}
bool HTMLInputElement::shouldAutocomplete() const
{
if (m_autocomplete != Uninitialized)
return m_autocomplete == On;
return HTMLTextFormControlElement::shouldAutocomplete();
}
bool HTMLInputElement::isValidValue(const String& value) const
{
if (!m_inputType->canSetStringValue()) {
ASSERT_NOT_REACHED();
return false;
}
return !m_inputType->typeMismatchFor(value)
&& !stepMismatch(value)
&& !rangeUnderflow(value)
&& !rangeOverflow(value)
&& !tooLong(value, IgnoreDirtyFlag)
&& !patternMismatch(value)
&& !valueMissing(value);
}
bool HTMLInputElement::typeMismatch() const
{
return m_inputType->typeMismatch();
}
bool HTMLInputElement::valueMissing(const String& value) const
{
return m_inputType->valueMissing(value);
}
bool HTMLInputElement::patternMismatch(const String& value) const
{
return m_inputType->patternMismatch(value);
}
bool HTMLInputElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) const
{
if (!isTextType())
return false;
int max = maxLength();
if (max < 0)
return false;
if (check == CheckDirtyFlag) {
if (!hasDirtyValue() || !m_wasModifiedByUser)
return false;
}
return numGraphemeClusters(value) > static_cast<unsigned>(max);
}
bool HTMLInputElement::rangeUnderflow(const String& value) const
{
return m_inputType->rangeUnderflow(value);
}
bool HTMLInputElement::rangeOverflow(const String& value) const
{
return m_inputType->rangeOverflow(value);
}
double HTMLInputElement::minimum() const
{
return m_inputType->minimum();
}
double HTMLInputElement::maximum() const
{
return m_inputType->maximum();
}
bool HTMLInputElement::stepMismatch(const String& value) const
{
double step;
if (!getAllowedValueStep(&step))
return false;
return m_inputType->stepMismatch(value, step);
}
String HTMLInputElement::minimumString() const
{
return m_inputType->serialize(minimum());
}
String HTMLInputElement::maximumString() const
{
return m_inputType->serialize(maximum());
}
String HTMLInputElement::stepBaseString() const
{
return m_inputType->serialize(m_inputType->stepBase());
}
String HTMLInputElement::stepString() const
{
double step;
if (!getAllowedValueStep(&step)) {
ASSERT_NOT_REACHED();
return String();
}
return serializeForNumberType(step / m_inputType->stepScaleFactor());
}
String HTMLInputElement::typeMismatchText() const
{
return m_inputType->typeMismatchText();
}
String HTMLInputElement::valueMissingText() const
{
return m_inputType->valueMissingText();
}
bool HTMLInputElement::getAllowedValueStep(double* step) const
{
return getAllowedValueStepWithDecimalPlaces(RejectAny, step, 0);
}
bool HTMLInputElement::getAllowedValueStepWithDecimalPlaces(AnyStepHandling anyStepHandling, double* step, unsigned* decimalPlaces) const
{
ASSERT(step);
double defaultStep = m_inputType->defaultStep();
double stepScaleFactor = m_inputType->stepScaleFactor();
if (!isfinite(defaultStep) || !isfinite(stepScaleFactor))
return false;
const AtomicString& stepString = fastGetAttribute(stepAttr);
if (stepString.isEmpty()) {
*step = defaultStep * stepScaleFactor;
if (decimalPlaces)
*decimalPlaces = 0;
return true;
}
if (equalIgnoringCase(stepString, "any")) {
switch (anyStepHandling) {
case RejectAny:
return false;
case AnyIsDefaultStep:
*step = defaultStep * stepScaleFactor;
if (decimalPlaces)
*decimalPlaces = 0;
return true;
default:
ASSERT_NOT_REACHED();
}
}
double parsed;
if (!decimalPlaces) {
if (!parseToDoubleForNumberType(stepString, &parsed) || parsed <= 0.0) {
*step = defaultStep * stepScaleFactor;
return true;
}
} else {
if (!parseToDoubleForNumberTypeWithDecimalPlaces(stepString, &parsed, decimalPlaces) || parsed <= 0.0) {
*step = defaultStep * stepScaleFactor;
*decimalPlaces = 0;
return true;
}
}
if (m_inputType->parsedStepValueShouldBeInteger())
parsed = max(round(parsed), 1.0);
double result = parsed * stepScaleFactor;
if (m_inputType->scaledStepValueShouldBeInteger())
result = max(round(result), 1.0);
ASSERT(result > 0);
*step = result;
return true;
}
void HTMLInputElement::applyStep(double count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionCode& ec)
{
double step;
unsigned stepDecimalPlaces, currentDecimalPlaces;
if (!getAllowedValueStepWithDecimalPlaces(anyStepHandling, &step, &stepDecimalPlaces)) {
ec = INVALID_STATE_ERR;
return;
}
const double nan = numeric_limits<double>::quiet_NaN();
double current = m_inputType->parseToDoubleWithDecimalPlaces(value(), nan, ¤tDecimalPlaces);
if (!isfinite(current)) {
ec = INVALID_STATE_ERR;
return;
}
double newValue = current + step * count;
if (isinf(newValue)) {
ec = INVALID_STATE_ERR;
return;
}
double acceptableError = m_inputType->acceptableError(step);
if (newValue - m_inputType->minimum() < -acceptableError) {
ec = INVALID_STATE_ERR;
return;
}
if (newValue < m_inputType->minimum())
newValue = m_inputType->minimum();
const AtomicString& stepString = fastGetAttribute(stepAttr);
if (!equalIgnoringCase(stepString, "any"))
newValue = alignValueForStep(newValue, step, currentDecimalPlaces, stepDecimalPlaces);
if (newValue - m_inputType->maximum() > acceptableError) {
ec = INVALID_STATE_ERR;
return;
}
if (newValue > m_inputType->maximum())
newValue = m_inputType->maximum();
setValueAsNumber(newValue, ec, eventBehavior);
if (AXObjectCache::accessibilityEnabled())
document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXValueChanged, true);
}
double HTMLInputElement::alignValueForStep(double newValue, double step, unsigned currentDecimalPlaces, unsigned stepDecimalPlaces)
{
if (newValue >= pow(10.0, 21.0))
return newValue;
unsigned baseDecimalPlaces;
double base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces);
baseDecimalPlaces = min(baseDecimalPlaces, 16u);
if (stepMismatch(value())) {
double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, currentDecimalPlaces)));
newValue = round(newValue * scale) / scale;
} else {
double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces)));
newValue = round((base + round((newValue - base) / step) * step) * scale) / scale;
}
return newValue;
}
void HTMLInputElement::stepUp(int n, ExceptionCode& ec)
{
applyStep(n, RejectAny, DispatchNoEvent, ec);
}
void HTMLInputElement::stepDown(int n, ExceptionCode& ec)
{
applyStep(-n, RejectAny, DispatchNoEvent, ec);
}
bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
{
if (readOnly())
return false;
if (isTextField())
return HTMLTextFormControlElement::isFocusable();
return HTMLTextFormControlElement::isKeyboardFocusable(event) && m_inputType->isKeyboardFocusable();
}
bool HTMLInputElement::isMouseFocusable() const
{
if (isTextField())
return HTMLTextFormControlElement::isFocusable();
return HTMLTextFormControlElement::isMouseFocusable();
}
void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
{
if (isTextField()) {
if (!restorePreviousSelection || !hasCachedSelection())
select();
else
restoreCachedSelection();
if (document()->frame())
document()->frame()->selection()->revealSelection();
} else
HTMLTextFormControlElement::updateFocusAppearance(restorePreviousSelection);
}
void HTMLInputElement::aboutToUnload()
{
if (!isTextField() || !focused())
return;
Frame* frame = document()->frame();
if (!frame)
return;
frame->editor()->textFieldDidEndEditing(this);
}
bool HTMLInputElement::shouldUseInputMethod()
{
return m_inputType->shouldUseInputMethod();
}
void HTMLInputElement::handleFocusEvent()
{
m_inputType->handleFocusEvent();
}
void HTMLInputElement::handleBlurEvent()
{
m_inputType->handleBlurEvent();
}
void HTMLInputElement::setType(const String& type)
{
if (type.isEmpty())
removeAttribute(typeAttr);
else
setAttribute(typeAttr, type);
}
void HTMLInputElement::updateType()
{
OwnPtr<InputType> newType = InputType::create(this, fastGetAttribute(typeAttr));
bool hadType = m_hasType;
m_hasType = true;
if (m_inputType->formControlType() == newType->formControlType())
return;
if (hadType && !newType->canChangeFromAnotherType()) {
setAttribute(typeAttr, type());
return;
}
removeFromRadioButtonGroup();
bool wasAttached = attached();
if (wasAttached)
detach();
bool didStoreValue = m_inputType->storesValueSeparateFromAttribute();
bool neededSuspensionCallback = needsSuspensionCallback();
bool didRespectHeightAndWidth = m_inputType->shouldRespectHeightAndWidthAttributes();
m_inputType->destroyShadowSubtree();
m_inputType = newType.release();
m_inputType->createShadowSubtree();
setNeedsWillValidateCheck();
bool willStoreValue = m_inputType->storesValueSeparateFromAttribute();
if (didStoreValue && !willStoreValue && hasDirtyValue()) {
setAttribute(valueAttr, m_valueIfDirty);
m_valueIfDirty = String();
}
if (!didStoreValue && willStoreValue) {
AtomicString valueString = fastGetAttribute(valueAttr);
m_valueIfDirty = sanitizeValue(valueString);
} else
updateValueIfNeeded();
setFormControlValueMatchesRenderer(false);
updateInnerTextValue();
m_wasModifiedByUser = false;
if (neededSuspensionCallback)
unregisterForSuspensionCallbackIfNeeded();
else
registerForSuspensionCallbackIfNeeded();
if (didRespectHeightAndWidth != m_inputType->shouldRespectHeightAndWidthAttributes()) {
ASSERT(attributeData());
if (Attribute* height = getAttributeItem(heightAttr))
attributeChanged(height);
if (Attribute* width = getAttributeItem(widthAttr))
attributeChanged(width);
if (Attribute* align = getAttributeItem(alignAttr))
attributeChanged(align);
}
if (wasAttached) {
attach();
if (document()->focusedNode() == this)
updateFocusAppearance(true);
}
setChangedSinceLastFormControlChangeEvent(false);
addToRadioButtonGroup();
setNeedsValidityCheck();
notifyFormStateChanged();
}
void HTMLInputElement::updateInnerTextValue()
{
if (!isTextField())
return;
if (!suggestedValue().isNull()) {
setInnerTextValue(suggestedValue());
updatePlaceholderVisibility(false);
} else if (!formControlValueMatchesRenderer()) {
setInnerTextValue(visibleValue());
updatePlaceholderVisibility(false);
}
}
void HTMLInputElement::subtreeHasChanged()
{
ASSERT(isTextField());
ASSERT(renderer());
RenderTextControlSingleLine* renderTextControl = toRenderTextControlSingleLine(renderer());
bool wasChanged = wasChangedSinceLastFormControlChangeEvent();
setChangedSinceLastFormControlChangeEvent(true);
String value = innerTextValue();
if (isAcceptableValue(value))
setValueFromRenderer(sanitizeValue(convertFromVisibleValue(value)));
updatePlaceholderVisibility(false);
setNeedsStyleRecalc();
if (cancelButtonElement())
renderTextControl->updateCancelButtonVisibility();
if (searchEventsShouldBeDispatched() && isSearchField() && m_inputType)
static_cast<SearchInputType*>(m_inputType.get())->startSearchEventTimer();
if (!wasChanged && focused()) {
if (Frame* frame = document()->frame())
frame->editor()->textFieldDidBeginEditing(this);
}
if (focused()) {
if (Frame* frame = document()->frame())
frame->editor()->textDidChangeInTextField(this);
}
if (isTextField())
calculateAndAdjustDirectionality();
}
const AtomicString& HTMLInputElement::formControlType() const
{
return m_inputType->formControlType();
}
bool HTMLInputElement::saveFormControlState(String& result) const
{
return m_inputType->saveFormControlState(result);
}
void HTMLInputElement::restoreFormControlState(const String& state)
{
m_inputType->restoreFormControlState(state);
m_stateRestored = true;
}
bool HTMLInputElement::canStartSelection() const
{
if (!isTextField())
return false;
return HTMLTextFormControlElement::canStartSelection();
}
bool HTMLInputElement::canHaveSelection() const
{
return isTextField();
}
void HTMLInputElement::accessKeyAction(bool sendMouseEvents)
{
m_inputType->accessKeyAction(sendMouseEvents);
}
bool HTMLInputElement::isPresentationAttribute(const QualifiedName& name) const
{
if (name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == widthAttr || name == heightAttr || (name == borderAttr && isImageButton()))
return true;
return HTMLTextFormControlElement::isPresentationAttribute(name);
}
void HTMLInputElement::collectStyleForAttribute(Attribute* attr, StylePropertySet* style)
{
if (attr->name() == vspaceAttr) {
addHTMLLengthToStyle(style, CSSPropertyMarginTop, attr->value());
addHTMLLengthToStyle(style, CSSPropertyMarginBottom, attr->value());
} else if (attr->name() == hspaceAttr) {
addHTMLLengthToStyle(style, CSSPropertyMarginLeft, attr->value());
addHTMLLengthToStyle(style, CSSPropertyMarginRight, attr->value());
} else if (attr->name() == alignAttr) {
if (m_inputType->shouldRespectAlignAttribute())
applyAlignmentAttributeToStyle(attr, style);
} else if (attr->name() == widthAttr) {
if (m_inputType->shouldRespectHeightAndWidthAttributes())
addHTMLLengthToStyle(style, CSSPropertyWidth, attr->value());
} else if (attr->name() == heightAttr) {
if (m_inputType->shouldRespectHeightAndWidthAttributes())
addHTMLLengthToStyle(style, CSSPropertyHeight, attr->value());
} else if (attr->name() == borderAttr && isImageButton())
applyBorderAttributeToStyle(attr, style);
else
return HTMLTextFormControlElement::collectStyleForAttribute(attr, style);
}
void HTMLInputElement::parseAttribute(Attribute* attr)
{
if (attr->name() == nameAttr) {
removeFromRadioButtonGroup();
m_name = attr->value();
addToRadioButtonGroup();
HTMLTextFormControlElement::parseAttribute(attr);
} else if (attr->name() == autocompleteAttr) {
if (equalIgnoringCase(attr->value(), "off")) {
m_autocomplete = Off;
registerForSuspensionCallbackIfNeeded();
} else {
bool needsToUnregister = m_autocomplete == Off;
if (attr->isEmpty())
m_autocomplete = Uninitialized;
else
m_autocomplete = On;
if (needsToUnregister)
unregisterForSuspensionCallbackIfNeeded();
}
} else if (attr->name() == typeAttr) {
updateType();
} else if (attr->name() == valueAttr) {
if (!hasDirtyValue()) {
updatePlaceholderVisibility(false);
setNeedsStyleRecalc();
}
setFormControlValueMatchesRenderer(false);
setNeedsValidityCheck();
} else if (attr->name() == checkedAttr) {
if (!m_parsingInProgress && m_reflectsCheckedAttribute) {
setChecked(!attr->isNull());
m_reflectsCheckedAttribute = true;
}
} else if (attr->name() == maxlengthAttr)
parseMaxLengthAttribute(attr);
else if (attr->name() == sizeAttr) {
int oldSize = m_size;
int value = attr->value().toInt();
m_size = value > 0 ? value : defaultSize;
if (m_size != oldSize && renderer())
renderer()->setNeedsLayoutAndPrefWidthsRecalc();
} else if (attr->name() == altAttr)
m_inputType->altAttributeChanged();
else if (attr->name() == srcAttr)
m_inputType->srcAttributeChanged();
else if (attr->name() == usemapAttr || attr->name() == accesskeyAttr) {
} else if (attr->name() == onsearchAttr) {
setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, attr));
} else if (attr->name() == resultsAttr) {
int oldResults = m_maxResults;
m_maxResults = !attr->isNull() ? std::min(attr->value().toInt(), maxSavedResults) : -1;
if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0))
reattachIfAttached();
setNeedsStyleRecalc();
} else if (attr->name() == autosaveAttr || attr->name() == incrementalAttr)
setNeedsStyleRecalc();
else if (attr->name() == minAttr || attr->name() == maxAttr) {
m_inputType->minOrMaxAttributeChanged();
setNeedsValidityCheck();
} else if (attr->name() == multipleAttr) {
m_inputType->multipleAttributeChanged();
setNeedsValidityCheck();
} else if (attr->name() == stepAttr) {
m_inputType->stepAttributeChanged();
setNeedsValidityCheck();
} else if (attr->name() == patternAttr || attr->name() == precisionAttr)
setNeedsValidityCheck();
else if (attr->name() == disabledAttr) {
HTMLTextFormControlElement::parseAttribute(attr);
m_inputType->disabledAttributeChanged();
} else if (attr->name() == readonlyAttr) {
HTMLTextFormControlElement::parseAttribute(attr);
m_inputType->readonlyAttributeChanged();
}
#if ENABLE(DATALIST)
else if (attr->name() == listAttr)
m_hasNonEmptyList = !attr->isEmpty();
#endif
#if ENABLE(INPUT_SPEECH)
else if (attr->name() == webkitspeechAttr) {
if (renderer()) {
detach();
m_inputType->destroyShadowSubtree();
m_inputType->createShadowSubtree();
attach();
} else {
m_inputType->destroyShadowSubtree();
m_inputType->createShadowSubtree();
}
setFormControlValueMatchesRenderer(false);
setNeedsStyleRecalc();
} else if (attr->name() == onwebkitspeechchangeAttr)
setAttributeEventListener(eventNames().webkitspeechchangeEvent, createAttributeEventListener(this, attr));
#endif
else
HTMLTextFormControlElement::parseAttribute(attr);
updateInnerTextValue();
}
void HTMLInputElement::finishParsingChildren()
{
m_parsingInProgress = false;
HTMLTextFormControlElement::finishParsingChildren();
if (!m_stateRestored) {
bool checked = hasAttribute(checkedAttr);
if (checked)
setChecked(checked);
m_reflectsCheckedAttribute = true;
}
}
bool HTMLInputElement::rendererIsNeeded(const NodeRenderingContext& context)
{
return m_inputType->rendererIsNeeded() && HTMLTextFormControlElement::rendererIsNeeded(context);
}
RenderObject* HTMLInputElement::createRenderer(RenderArena* arena, RenderStyle* style)
{
return m_inputType->createRenderer(arena, style);
}
void HTMLInputElement::attach()
{
if (!m_hasType)
updateType();
HTMLTextFormControlElement::attach();
m_inputType->attach();
if (document()->focusedNode() == this)
document()->updateFocusAppearanceSoon(true );
}
void HTMLInputElement::detach()
{
HTMLTextFormControlElement::detach();
setFormControlValueMatchesRenderer(false);
m_inputType->detach();
}
String HTMLInputElement::altText() const
{
String alt = fastGetAttribute(altAttr);
if (alt.isNull())
alt = getAttribute(titleAttr);
if (alt.isNull())
alt = getAttribute(valueAttr);
if (alt.isEmpty())
alt = inputElementAltText();
return alt;
}
bool HTMLInputElement::isSuccessfulSubmitButton() const
{
return !disabled() && m_inputType->canBeSuccessfulSubmitButton();
}
bool HTMLInputElement::isActivatedSubmit() const
{
return m_isActivatedSubmit;
}
void HTMLInputElement::setActivatedSubmit(bool flag)
{
m_isActivatedSubmit = flag;
}
bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart)
{
return m_inputType->isFormDataAppendable() && m_inputType->appendFormData(encoding, multipart);
}
void HTMLInputElement::reset()
{
if (m_inputType->storesValueSeparateFromAttribute())
setValue(String());
setAutofilled(false);
setChecked(hasAttribute(checkedAttr));
m_reflectsCheckedAttribute = true;
}
bool HTMLInputElement::isTextField() const
{
return m_inputType->isTextField();
}
bool HTMLInputElement::isTextType() const
{
return m_inputType->isTextType();
}
void HTMLInputElement::setChecked(bool nowChecked, TextFieldEventBehavior eventBehavior)
{
if (checked() == nowChecked)
return;
m_reflectsCheckedAttribute = false;
m_isChecked = nowChecked;
setNeedsStyleRecalc();
if (CheckedRadioButtons* buttons = checkedRadioButtons())
buttons->updateCheckedState(this);
if (renderer() && renderer()->style()->hasAppearance())
renderer()->theme()->stateChanged(renderer(), CheckedState);
setNeedsValidityCheck();
if (renderer() && AXObjectCache::accessibilityEnabled())
renderer()->document()->axObjectCache()->checkedStateChanged(renderer());
if (eventBehavior != DispatchNoEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) {
setTextAsOfLastFormControlChangeEvent(String());
dispatchFormControlChangeEvent();
}
}
void HTMLInputElement::setIndeterminate(bool newValue)
{
if (indeterminate() == newValue)
return;
m_isIndeterminate = newValue;
setNeedsStyleRecalc();
if (renderer() && renderer()->style()->hasAppearance())
renderer()->theme()->stateChanged(renderer(), CheckedState);
}
int HTMLInputElement::size() const
{
return m_size;
}
bool HTMLInputElement::sizeShouldIncludeDecoration(int& preferredSize) const
{
return m_inputType->sizeShouldIncludeDecoration(defaultSize, preferredSize);
}
void HTMLInputElement::copyNonAttributeProperties(const Element* source)
{
const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source);
m_valueIfDirty = sourceElement->m_valueIfDirty;
m_wasModifiedByUser = false;
setChecked(sourceElement->m_isChecked);
m_reflectsCheckedAttribute = sourceElement->m_reflectsCheckedAttribute;
m_isIndeterminate = sourceElement->m_isIndeterminate;
HTMLTextFormControlElement::copyNonAttributeProperties(source);
setFormControlValueMatchesRenderer(false);
updateInnerTextValue();
}
String HTMLInputElement::value() const
{
String value;
if (m_inputType->getTypeSpecificValue(value))
return value;
value = m_valueIfDirty;
if (!value.isNull())
return value;
AtomicString valueString = fastGetAttribute(valueAttr);
value = sanitizeValue(valueString);
if (!value.isNull())
return value;
return m_inputType->fallbackValue();
}
String HTMLInputElement::valueWithDefault() const
{
String value = this->value();
if (!value.isNull())
return value;
return m_inputType->defaultValue();
}
void HTMLInputElement::setValueForUser(const String& value)
{
setValue(value, DispatchChangeEvent);
}
const String& HTMLInputElement::suggestedValue() const
{
return m_suggestedValue;
}
void HTMLInputElement::setSuggestedValue(const String& value)
{
if (!m_inputType->canSetSuggestedValue())
return;
setFormControlValueMatchesRenderer(false);
m_suggestedValue = sanitizeValue(value);
setNeedsStyleRecalc();
updateInnerTextValue();
}
void HTMLInputElement::setValue(const String& value, TextFieldEventBehavior eventBehavior)
{
if (!m_inputType->canSetValue(value))
return;
RefPtr<HTMLInputElement> protector(this);
String sanitizedValue = sanitizeValue(value);
bool valueChanged = sanitizedValue != this->value();
setLastChangeWasNotUserEdit();
setFormControlValueMatchesRenderer(false);
m_suggestedValue = String(); m_inputType->setValue(sanitizedValue, valueChanged, eventBehavior);
if (!valueChanged)
return;
notifyFormStateChanged();
}
void HTMLInputElement::setValueInternal(const String& sanitizedValue, TextFieldEventBehavior eventBehavior)
{
m_valueIfDirty = sanitizedValue;
m_wasModifiedByUser = eventBehavior != DispatchNoEvent;
setNeedsValidityCheck();
}
double HTMLInputElement::valueAsDate() const
{
return m_inputType->valueAsDate();
}
void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec)
{
m_inputType->setValueAsDate(value, ec);
}
double HTMLInputElement::valueAsNumber() const
{
return m_inputType->valueAsNumber();
}
void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec, TextFieldEventBehavior eventBehavior)
{
if (!isfinite(newValue)) {
ec = NOT_SUPPORTED_ERR;
return;
}
m_inputType->setValueAsNumber(newValue, eventBehavior, ec);
}
String HTMLInputElement::placeholder() const
{
return fastGetAttribute(placeholderAttr).string();
}
void HTMLInputElement::setPlaceholder(const String& value)
{
setAttribute(placeholderAttr, value);
}
bool HTMLInputElement::searchEventsShouldBeDispatched() const
{
return hasAttribute(incrementalAttr);
}
void HTMLInputElement::setValueFromRenderer(const String& value)
{
ASSERT(!isFileUpload());
m_suggestedValue = String();
ASSERT(value == sanitizeValue(value) || sanitizeValue(value).isEmpty());
m_valueIfDirty = value == "\n" ? String("") : value;
setFormControlValueMatchesRenderer(true);
m_wasModifiedByUser = true;
if (!isTextField())
dispatchInputEvent();
notifyFormStateChanged();
setNeedsValidityCheck();
setAutofilled(false);
}
void* HTMLInputElement::preDispatchEventHandler(Event* event)
{
if (event->type() == eventNames().textInputEvent && m_inputType->shouldSubmitImplicitly(event)) {
event->stopPropagation();
return 0;
}
if (event->type() != eventNames().clickEvent)
return 0;
if (!event->isMouseEvent() || static_cast<MouseEvent*>(event)->button() != LeftButton)
return 0;
return m_inputType->willDispatchClick().leakPtr();
}
void HTMLInputElement::postDispatchEventHandler(Event* event, void* dataFromPreDispatch)
{
OwnPtr<ClickHandlingState> state = adoptPtr(static_cast<ClickHandlingState*>(dataFromPreDispatch));
if (!state)
return;
m_inputType->didDispatchClick(event, *state);
}
void HTMLInputElement::defaultEventHandler(Event* evt)
{
if (evt->isMouseEvent() && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
m_inputType->handleClickEvent(static_cast<MouseEvent*>(evt));
if (evt->defaultHandled())
return;
}
if (evt->isKeyboardEvent() && evt->type() == eventNames().keydownEvent) {
m_inputType->handleKeydownEvent(static_cast<KeyboardEvent*>(evt));
if (evt->defaultHandled())
return;
}
bool callBaseClassEarly = isTextField() && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
if (callBaseClassEarly) {
HTMLTextFormControlElement::defaultEventHandler(evt);
if (evt->defaultHandled())
return;
}
if (evt->type() == eventNames().DOMActivateEvent) {
m_inputType->handleDOMActivateEvent(evt);
if (evt->defaultHandled())
return;
}
if (evt->isKeyboardEvent() && evt->type() == eventNames().keypressEvent) {
m_inputType->handleKeypressEvent(static_cast<KeyboardEvent*>(evt));
if (evt->defaultHandled())
return;
}
if (evt->isKeyboardEvent() && evt->type() == eventNames().keyupEvent) {
m_inputType->handleKeyupEvent(static_cast<KeyboardEvent*>(evt));
if (evt->defaultHandled())
return;
}
if (m_inputType->shouldSubmitImplicitly(evt)) {
if (isSearchField()) {
addSearchResult();
onSearch();
}
if (wasChangedSinceLastFormControlChangeEvent())
dispatchFormControlChangeEvent();
RefPtr<HTMLFormElement> formForSubmission = m_inputType->formForSubmission();
if (formForSubmission)
formForSubmission->submitImplicitly(evt, canTriggerImplicitSubmission());
evt->setDefaultHandled();
return;
}
if (evt->isBeforeTextInsertedEvent())
m_inputType->handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(evt));
if (evt->hasInterface(eventNames().interfaceForWheelEvent)) {
m_inputType->handleWheelEvent(static_cast<WheelEvent*>(evt));
if (evt->defaultHandled())
return;
}
if (evt->isMouseEvent() && evt->type() == eventNames().mousedownEvent) {
m_inputType->handleMouseDownEvent(static_cast<MouseEvent*>(evt));
if (evt->defaultHandled())
return;
}
if (evt->interfaceName() == eventNames().interfaceForTouchEvent) {
m_inputType->handleTouchEvent(static_cast<TouchEvent*>(evt));
if (evt->defaultHandled())
return;
}
m_inputType->forwardEvent(evt);
if (!callBaseClassEarly && !evt->defaultHandled())
HTMLTextFormControlElement::defaultEventHandler(evt);
}
bool HTMLInputElement::isURLAttribute(Attribute *attr) const
{
return attr->name() == srcAttr || attr->name() == formactionAttr || HTMLTextFormControlElement::isURLAttribute(attr);
}
String HTMLInputElement::defaultValue() const
{
return fastGetAttribute(valueAttr);
}
void HTMLInputElement::setDefaultValue(const String &value)
{
setAttribute(valueAttr, value);
}
static inline bool isRFC2616TokenCharacter(UChar ch)
{
return isASCII(ch) && ch > ' ' && ch != '"' && ch != '(' && ch != ')' && ch != ',' && ch != '/' && (ch < ':' || ch > '@') && (ch < '[' || ch > ']') && ch != '{' && ch != '}' && ch != 0x7f;
}
static inline bool isValidMIMEType(const String& type)
{
size_t slashPosition = type.find('/');
if (slashPosition == notFound || !slashPosition || slashPosition == type.length() - 1)
return false;
for (size_t i = 0; i < type.length(); ++i) {
if (!isRFC2616TokenCharacter(type[i]) && i != slashPosition)
return false;
}
return true;
}
Vector<String> HTMLInputElement::acceptMIMETypes()
{
Vector<String> mimeTypes;
String acceptString = accept();
if (acceptString.isEmpty())
return mimeTypes;
Vector<String> splitTypes;
acceptString.split(',', false, splitTypes);
for (size_t i = 0; i < splitTypes.size(); ++i) {
String trimmedMimeType = stripLeadingAndTrailingHTMLSpaces(splitTypes[i]);
if (trimmedMimeType.isEmpty())
continue;
if (!isValidMIMEType(trimmedMimeType))
continue;
mimeTypes.append(trimmedMimeType.lower());
}
return mimeTypes;
}
String HTMLInputElement::accept() const
{
return fastGetAttribute(acceptAttr);
}
String HTMLInputElement::alt() const
{
return fastGetAttribute(altAttr);
}
int HTMLInputElement::maxLength() const
{
return m_maxLength;
}
void HTMLInputElement::setMaxLength(int maxLength, ExceptionCode& ec)
{
if (maxLength < 0)
ec = INDEX_SIZE_ERR;
else
setAttribute(maxlengthAttr, String::number(maxLength));
}
bool HTMLInputElement::multiple() const
{
return fastHasAttribute(multipleAttr);
}
void HTMLInputElement::setSize(unsigned size)
{
setAttribute(sizeAttr, String::number(size));
}
KURL HTMLInputElement::src() const
{
return document()->completeURL(fastGetAttribute(srcAttr));
}
void HTMLInputElement::setAutofilled(bool autofilled)
{
if (autofilled == m_isAutofilled)
return;
m_isAutofilled = autofilled;
setNeedsStyleRecalc();
}
FileList* HTMLInputElement::files()
{
return m_inputType->files();
}
void HTMLInputElement::receiveDroppedFiles(const Vector<String>& filenames)
{
m_inputType->receiveDroppedFiles(filenames);
}
Icon* HTMLInputElement::icon() const
{
return m_inputType->icon();
}
String HTMLInputElement::displayString() const
{
return m_inputType->displayString();
}
bool HTMLInputElement::canReceiveDroppedFiles() const
{
return m_canReceiveDroppedFiles;
}
void HTMLInputElement::setCanReceiveDroppedFiles(bool canReceiveDroppedFiles)
{
if (m_canReceiveDroppedFiles == canReceiveDroppedFiles)
return;
m_canReceiveDroppedFiles = canReceiveDroppedFiles;
if (renderer())
renderer()->updateFromElement();
}
String HTMLInputElement::visibleValue() const
{
return m_inputType->visibleValue();
}
String HTMLInputElement::convertFromVisibleValue(const String& visibleValue) const
{
return m_inputType->convertFromVisibleValue(visibleValue);
}
bool HTMLInputElement::isAcceptableValue(const String& proposedValue) const
{
return m_inputType->isAcceptableValue(proposedValue);
}
String HTMLInputElement::sanitizeValue(const String& proposedValue) const
{
if (proposedValue.isNull())
return proposedValue;
return m_inputType->sanitizeValue(proposedValue);
}
bool HTMLInputElement::hasUnacceptableValue() const
{
return m_inputType->hasUnacceptableValue();
}
bool HTMLInputElement::isInRange() const
{
return m_inputType->supportsRangeLimitation() && !rangeUnderflow(value()) && !rangeOverflow(value());
}
bool HTMLInputElement::isOutOfRange() const
{
return m_inputType->supportsRangeLimitation() && (rangeUnderflow(value()) || rangeOverflow(value()));
}
bool HTMLInputElement::needsSuspensionCallback()
{
return m_autocomplete == Off || m_inputType->shouldResetOnDocumentActivation();
}
void HTMLInputElement::registerForSuspensionCallbackIfNeeded()
{
if (needsSuspensionCallback())
document()->registerForPageCacheSuspensionCallbacks(this);
}
void HTMLInputElement::unregisterForSuspensionCallbackIfNeeded()
{
if (!needsSuspensionCallback())
document()->unregisterForPageCacheSuspensionCallbacks(this);
}
bool HTMLInputElement::isRequiredFormControl() const
{
return m_inputType->supportsRequired() && required();
}
void HTMLInputElement::addSearchResult()
{
}
void HTMLInputElement::onSearch()
{
ASSERT(isSearchField());
if (m_inputType)
static_cast<SearchInputType*>(m_inputType.get())->stopSearchEventTimer();
dispatchEvent(Event::create(eventNames().searchEvent, true, false));
}
void HTMLInputElement::documentDidResumeFromPageCache()
{
ASSERT(needsSuspensionCallback());
reset();
}
void HTMLInputElement::willChangeForm()
{
removeFromRadioButtonGroup();
HTMLTextFormControlElement::willChangeForm();
}
void HTMLInputElement::didChangeForm()
{
HTMLTextFormControlElement::didChangeForm();
addToRadioButtonGroup();
}
Node::InsertionNotificationRequest HTMLInputElement::insertedInto(Node* insertionPoint)
{
HTMLTextFormControlElement::insertedInto(insertionPoint);
if (!insertionPoint->inDocument())
return InsertionDone;
ASSERT(inDocument());
addToRadioButtonGroup();
return InsertionDone;
}
void HTMLInputElement::removedFrom(Node* insertionPoint)
{
if (insertionPoint->inDocument())
removeFromRadioButtonGroup();
HTMLTextFormControlElement::removedFrom(insertionPoint);
}
void HTMLInputElement::didMoveToNewDocument(Document* oldDocument)
{
m_inputType->willMoveToNewOwnerDocument();
bool needsSuspensionCallback = this->needsSuspensionCallback();
if (oldDocument) {
if (needsSuspensionCallback)
oldDocument->unregisterForPageCacheSuspensionCallbacks(this);
if (isRadioButton())
oldDocument->checkedRadioButtons().removeButton(this);
}
if (needsSuspensionCallback)
document()->registerForPageCacheSuspensionCallbacks(this);
HTMLTextFormControlElement::didMoveToNewDocument(oldDocument);
}
bool HTMLInputElement::willRespondToMouseClickEvents()
{
return !disabled();
}
void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
{
HTMLTextFormControlElement::addSubresourceAttributeURLs(urls);
addSubresourceURL(urls, src());
}
bool HTMLInputElement::recalcWillValidate() const
{
return m_inputType->supportsValidation() && HTMLTextFormControlElement::recalcWillValidate();
}
void HTMLInputElement::requiredAttributeChanged()
{
HTMLTextFormControlElement::requiredAttributeChanged();
if (CheckedRadioButtons* buttons = checkedRadioButtons())
buttons->requiredAttributeChanged(this);
}
#if ENABLE(INPUT_TYPE_COLOR)
void HTMLInputElement::selectColorInColorChooser(const Color& color)
{
if (!m_inputType->isColorControl())
return;
static_cast<ColorInputType*>(m_inputType.get())->didChooseColor(color);
}
#endif
#if ENABLE(DATALIST)
HTMLElement* HTMLInputElement::list() const
{
return dataList();
}
HTMLDataListElement* HTMLInputElement::dataList() const
{
if (!m_hasNonEmptyList)
return 0;
if (!m_inputType->shouldRespectListAttribute())
return 0;
Element* element = treeScope()->getElementById(fastGetAttribute(listAttr));
if (!element)
return 0;
if (!element->hasTagName(datalistTag))
return 0;
return static_cast<HTMLDataListElement*>(element);
}
#endif // ENABLE(DATALIST)
bool HTMLInputElement::isSteppable() const
{
return m_inputType->isSteppable();
}
void HTMLInputElement::stepUpFromRenderer(int n)
{
ASSERT(isSteppable());
if (!isSteppable())
return;
ASSERT(n);
if (!n)
return;
unsigned stepDecimalPlaces, baseDecimalPlaces;
double step, base;
if (!getAllowedValueStepWithDecimalPlaces(AnyIsDefaultStep, &step, &stepDecimalPlaces))
return;
base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces);
baseDecimalPlaces = min(baseDecimalPlaces, 16u);
int sign;
if (step > 0)
sign = n;
else if (step < 0)
sign = -n;
else
sign = 0;
const double nan = numeric_limits<double>::quiet_NaN();
String currentStringValue = value();
double current = m_inputType->parseToDouble(currentStringValue, nan);
if (!isfinite(current)) {
ExceptionCode ec;
current = m_inputType->defaultValueForStepUp();
double nextDiff = step * n;
if (current < m_inputType->minimum() - nextDiff)
current = m_inputType->minimum() - nextDiff;
if (current > m_inputType->maximum() - nextDiff)
current = m_inputType->maximum() - nextDiff;
setValueAsNumber(current, ec, DispatchInputAndChangeEvent);
}
if ((sign > 0 && current < m_inputType->minimum()) || (sign < 0 && current > m_inputType->maximum()))
setValue(m_inputType->serialize(sign > 0 ? m_inputType->minimum() : m_inputType->maximum()), DispatchInputAndChangeEvent);
else {
ExceptionCode ec;
if (stepMismatch(value())) {
ASSERT(step);
double newValue;
double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces)));
if (sign < 0)
newValue = round((base + floor((current - base) / step) * step) * scale) / scale;
else if (sign > 0)
newValue = round((base + ceil((current - base) / step) * step) * scale) / scale;
else
newValue = current;
if (newValue < m_inputType->minimum())
newValue = m_inputType->minimum();
if (newValue > m_inputType->maximum())
newValue = m_inputType->maximum();
setValueAsNumber(newValue, ec, n == 1 || n == -1 ? DispatchInputAndChangeEvent : DispatchNoEvent);
current = newValue;
if (n > 1)
applyStep(n - 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, ec);
else if (n < -1)
applyStep(n + 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, ec);
} else
applyStep(n, AnyIsDefaultStep, DispatchInputAndChangeEvent, ec);
}
}
#if ENABLE(INPUT_SPEECH)
bool HTMLInputElement::isSpeechEnabled() const
{
return m_inputType->shouldRespectSpeechAttribute() && RuntimeEnabledFeatures::speechInputEnabled() && hasAttribute(webkitspeechAttr);
}
#endif
DateComponents::Type HTMLInputElement::dateType() const
{
return m_inputType->dateType();
}
bool HTMLInputElement::isTextButton() const
{
return m_inputType->isTextButton();
}
bool HTMLInputElement::isRadioButton() const
{
return m_inputType->isRadioButton();
}
bool HTMLInputElement::isSearchField() const
{
return m_inputType->isSearchField();
}
bool HTMLInputElement::isInputTypeHidden() const
{
return m_inputType->isHiddenType();
}
bool HTMLInputElement::isPasswordField() const
{
return m_inputType->isPasswordField();
}
bool HTMLInputElement::isCheckbox() const
{
return m_inputType->isCheckbox();
}
bool HTMLInputElement::isRangeControl() const
{
return m_inputType->isRangeControl();
}
bool HTMLInputElement::isText() const
{
return m_inputType->isTextType();
}
bool HTMLInputElement::isEmailField() const
{
return m_inputType->isEmailField();
}
bool HTMLInputElement::isFileUpload() const
{
return m_inputType->isFileUpload();
}
bool HTMLInputElement::isImageButton() const
{
return m_inputType->isImageButton();
}
bool HTMLInputElement::isNumberField() const
{
return m_inputType->isNumberField();
}
bool HTMLInputElement::isSubmitButton() const
{
return m_inputType->isSubmitButton();
}
bool HTMLInputElement::isTelephoneField() const
{
return m_inputType->isTelephoneField();
}
bool HTMLInputElement::isURLField() const
{
return m_inputType->isURLField();
}
bool HTMLInputElement::isEnumeratable() const
{
return m_inputType->isEnumeratable();
}
bool HTMLInputElement::supportLabels() const
{
return m_inputType->supportLabels();
}
bool HTMLInputElement::shouldAppearChecked() const
{
return checked() && m_inputType->isCheckable();
}
bool HTMLInputElement::supportsPlaceholder() const
{
return m_inputType->supportsPlaceholder();
}
bool HTMLInputElement::isPlaceholderEmpty() const
{
if (m_inputType->usesFixedPlaceholder())
return m_inputType->fixedPlaceholder().isEmpty();
return HTMLTextFormControlElement::isPlaceholderEmpty();
}
void HTMLInputElement::updatePlaceholderText()
{
return m_inputType->updatePlaceholderText();
}
void HTMLInputElement::parseMaxLengthAttribute(Attribute* attribute)
{
int maxLength;
if (!parseHTMLInteger(attribute->value(), maxLength))
maxLength = maximumLength;
if (maxLength < 0 || maxLength > maximumLength)
maxLength = maximumLength;
int oldMaxLength = m_maxLength;
m_maxLength = maxLength;
if (oldMaxLength != maxLength)
updateValueIfNeeded();
setNeedsStyleRecalc();
setNeedsValidityCheck();
}
void HTMLInputElement::updateValueIfNeeded()
{
String newValue = sanitizeValue(m_valueIfDirty);
ASSERT(!m_valueIfDirty.isNull() || newValue.isNull());
if (newValue != m_valueIfDirty)
setValue(newValue);
}
String HTMLInputElement::defaultToolTip() const
{
return m_inputType->defaultToolTip();
}
bool HTMLInputElement::isIndeterminate() const
{
return m_inputType->supportsIndeterminateAppearance() && indeterminate();
}
bool HTMLInputElement::isInRequiredRadioButtonGroup() const
{
ASSERT(isRadioButton());
if (CheckedRadioButtons* buttons = checkedRadioButtons())
return buttons->isRequiredGroup(name());
return false;
}
HTMLInputElement* HTMLInputElement::checkedRadioButtonForGroup() const
{
if (CheckedRadioButtons* buttons = checkedRadioButtons())
return buttons->checkedButtonForGroup(name());
return 0;
}
CheckedRadioButtons* HTMLInputElement::checkedRadioButtons() const
{
if (!isRadioButton())
return 0;
if (HTMLFormElement* formElement = form())
return &formElement->checkedRadioButtons();
if (inDocument())
return &document()->checkedRadioButtons();
return 0;
}
inline void HTMLInputElement::addToRadioButtonGroup()
{
if (CheckedRadioButtons* buttons = checkedRadioButtons())
buttons->addButton(this);
}
inline void HTMLInputElement::removeFromRadioButtonGroup()
{
if (CheckedRadioButtons* buttons = checkedRadioButtons())
buttons->removeButton(this);
}
unsigned HTMLInputElement::height() const
{
return m_inputType->height();
}
unsigned HTMLInputElement::width() const
{
return m_inputType->width();
}
void HTMLInputElement::setHeight(unsigned height)
{
setAttribute(heightAttr, String::number(height));
}
void HTMLInputElement::setWidth(unsigned width)
{
setAttribute(widthAttr, String::number(width));
}
}