diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/html/HTMLTextAreaElement.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/html/HTMLTextAreaElement.cpp')
-rw-r--r-- | Source/WebCore/html/HTMLTextAreaElement.cpp | 247 |
1 files changed, 144 insertions, 103 deletions
diff --git a/Source/WebCore/html/HTMLTextAreaElement.cpp b/Source/WebCore/html/HTMLTextAreaElement.cpp index d40d4e810..44e0330c5 100644 --- a/Source/WebCore/html/HTMLTextAreaElement.cpp +++ b/Source/WebCore/html/HTMLTextAreaElement.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2004-2008, 2010, 2014, 2016 Apple Inc. All rights reserved. * (C) 2006 Alexey Proskuryakov (ap@nypop.com) * Copyright (C) 2007 Samuel Weinig (sam@webkit.org) * @@ -26,32 +26,28 @@ #include "config.h" #include "HTMLTextAreaElement.h" -#include "Attribute.h" #include "BeforeTextInsertedEvent.h" #include "CSSValueKeywords.h" #include "Document.h" #include "Editor.h" +#include "ElementChildIterator.h" #include "Event.h" -#include "EventHandler.h" #include "EventNames.h" -#include "ExceptionCode.h" -#include "ExceptionCodePlaceholder.h" #include "FormController.h" #include "FormDataList.h" #include "Frame.h" #include "FrameSelection.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" #include "LocalizedStrings.h" #include "RenderTextControlMultiLine.h" #include "ShadowRoot.h" #include "Text.h" -#include "TextBreakIterator.h" #include "TextControlInnerElements.h" #include "TextIterator.h" #include "TextNodeTraversal.h" #include <wtf/Ref.h> #include <wtf/StdLibExtras.h> -#include <wtf/text/StringBuilder.h> namespace WebCore { @@ -62,12 +58,12 @@ static const int defaultCols = 20; // On submission, LF characters are converted into CRLF. // This function returns number of characters considering this. -static inline unsigned computeLengthForSubmission(const String& text, unsigned numberOfLineBreaks) +static inline unsigned computeLengthForSubmission(StringView text, unsigned numberOfLineBreaks) { return numGraphemeClusters(text) + numberOfLineBreaks; } -static unsigned numberOfLineBreaks(const String& text) +static unsigned numberOfLineBreaks(StringView text) { unsigned length = text.length(); unsigned count = 0; @@ -78,12 +74,12 @@ static unsigned numberOfLineBreaks(const String& text) return count; } -static inline unsigned computeLengthForSubmission(const String& text) +static inline unsigned computeLengthForSubmission(StringView text) { return numGraphemeClusters(text) + numberOfLineBreaks(text); } -static inline unsigned upperBoundForLengthForSubmission(const String& text, unsigned numberOfLineBreaks) +static inline unsigned upperBoundForLengthForSubmission(StringView text, unsigned numberOfLineBreaks) { return text.length() + numberOfLineBreaks; } @@ -92,30 +88,27 @@ HTMLTextAreaElement::HTMLTextAreaElement(const QualifiedName& tagName, Document& : HTMLTextFormControlElement(tagName, document, form) , m_rows(defaultRows) , m_cols(defaultCols) - , m_wrap(SoftWrap) - , m_placeholder(0) - , m_isDirty(false) - , m_wasModifiedByUser(false) { ASSERT(hasTagName(textareaTag)); setFormControlValueMatchesRenderer(true); } -PassRefPtr<HTMLTextAreaElement> HTMLTextAreaElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form) +Ref<HTMLTextAreaElement> HTMLTextAreaElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form) { - RefPtr<HTMLTextAreaElement> textArea = adoptRef(new HTMLTextAreaElement(tagName, document, form)); + Ref<HTMLTextAreaElement> textArea = adoptRef(*new HTMLTextAreaElement(tagName, document, form)); textArea->ensureUserAgentShadowRoot(); - return textArea.release(); + return textArea; } void HTMLTextAreaElement::didAddUserAgentShadowRoot(ShadowRoot* root) { - root->appendChild(TextControlInnerTextElement::create(document()), ASSERT_NO_EXCEPTION); + root->appendChild(TextControlInnerTextElement::create(document())); + updateInnerTextElementEditability(); } const AtomicString& HTMLTextAreaElement::formControlType() const { - DEFINE_STATIC_LOCAL(const AtomicString, textarea, ("textarea", AtomicString::ConstructFromLiteral)); + static NeverDestroyed<const AtomicString> textarea("textarea", AtomicString::ConstructFromLiteral); return textarea; } @@ -169,18 +162,14 @@ void HTMLTextAreaElement::collectStyleForPresentationAttribute(const QualifiedNa void HTMLTextAreaElement::parseAttribute(const QualifiedName& name, const AtomicString& value) { if (name == rowsAttr) { - int rows = value.toInt(); - if (rows <= 0) - rows = defaultRows; + unsigned rows = limitToOnlyHTMLNonNegativeNumbersGreaterThanZero(value, defaultRows); if (m_rows != rows) { m_rows = rows; if (renderer()) renderer()->setNeedsLayoutAndPrefWidthsRecalc(); } } else if (name == colsAttr) { - int cols = value.toInt(); - if (cols <= 0) - cols = defaultCols; + unsigned cols = limitToOnlyHTMLNonNegativeNumbersGreaterThanZero(value, defaultCols); if (m_cols != cols) { m_cols = cols; if (renderer()) @@ -190,9 +179,9 @@ void HTMLTextAreaElement::parseAttribute(const QualifiedName& name, const Atomic // The virtual/physical values were a Netscape extension of HTML 3.0, now deprecated. // The soft/hard /off values are a recommendation for HTML 4 extension by IE and NS 4. WrapMethod wrap; - if (equalIgnoringCase(value, "physical") || equalIgnoringCase(value, "hard") || equalIgnoringCase(value, "on")) + if (equalLettersIgnoringASCIICase(value, "physical") || equalLettersIgnoringASCIICase(value, "hard") || equalLettersIgnoringASCIICase(value, "on")) wrap = HardWrap; - else if (equalIgnoringCase(value, "off")) + else if (equalLettersIgnoringASCIICase(value, "off")) wrap = NoWrap; else wrap = SoftWrap; @@ -204,14 +193,28 @@ void HTMLTextAreaElement::parseAttribute(const QualifiedName& name, const Atomic } else if (name == accesskeyAttr) { // ignore for the moment } else if (name == maxlengthAttr) - setNeedsValidityCheck(); + maxLengthAttributeChanged(value); + else if (name == minlengthAttr) + minLengthAttributeChanged(value); else HTMLTextFormControlElement::parseAttribute(name, value); } -RenderPtr<RenderElement> HTMLTextAreaElement::createElementRenderer(PassRef<RenderStyle> style) +void HTMLTextAreaElement::maxLengthAttributeChanged(const AtomicString& newValue) { - return createRenderer<RenderTextControlMultiLine>(*this, std::move(style)); + internalSetMaxLength(parseHTMLNonNegativeInteger(newValue).value_or(-1)); + updateValidity(); +} + +void HTMLTextAreaElement::minLengthAttributeChanged(const AtomicString& newValue) +{ + internalSetMinLength(parseHTMLNonNegativeInteger(newValue).value_or(-1)); + updateValidity(); +} + +RenderPtr<RenderElement> HTMLTextAreaElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&) +{ + return createRenderer<RenderTextControlMultiLine>(*this, WTFMove(style)); } bool HTMLTextAreaElement::appendFormData(FormDataList& encoding, bool) @@ -224,7 +227,7 @@ bool HTMLTextAreaElement::appendFormData(FormDataList& encoding, bool) const String& text = (m_wrap == HardWrap) ? valueWithHardLineBreaks() : value(); encoding.appendData(name(), text); - const AtomicString& dirnameAttrValue = fastGetAttribute(dirnameAttr); + const AtomicString& dirnameAttrValue = attributeWithoutSynchronization(dirnameAttr); if (!dirnameAttrValue.isNull()) encoding.appendData(dirnameAttrValue, directionForFormData()); return true; @@ -240,7 +243,7 @@ bool HTMLTextAreaElement::hasCustomFocusLogic() const return true; } -bool HTMLTextAreaElement::isKeyboardFocusable(KeyboardEvent*) const +bool HTMLTextAreaElement::isKeyboardFocusable(KeyboardEvent&) const { // If a given text area can be focused at all, then it will always be keyboard focusable. return isFocusable(); @@ -251,26 +254,26 @@ bool HTMLTextAreaElement::isMouseFocusable() const return isFocusable(); } -void HTMLTextAreaElement::updateFocusAppearance(bool restorePreviousSelection) +void HTMLTextAreaElement::updateFocusAppearance(SelectionRestorationMode restorationMode, SelectionRevealMode revealMode) { - if (!restorePreviousSelection || !hasCachedSelection()) { + if (restorationMode == SelectionRestorationMode::SetDefault || !hasCachedSelection()) { // If this is the first focus, set a caret at the beginning of the text. // This matches some browsers' behavior; see bug 11746 Comment #15. // http://bugs.webkit.org/show_bug.cgi?id=11746#c15 - setSelectionRange(0, 0); + setSelectionRange(0, 0, SelectionHasNoDirection, Element::defaultFocusTextStateChangeIntent()); } else - restoreCachedSelection(); + restoreCachedSelection(Element::defaultFocusTextStateChangeIntent()); if (document().frame()) - document().frame()->selection().revealSelection(); + document().frame()->selection().revealSelection(revealMode); } -void HTMLTextAreaElement::defaultEventHandler(Event* event) +void HTMLTextAreaElement::defaultEventHandler(Event& event) { - if (renderer() && (event->isMouseEvent() || event->isDragEvent() || event->eventInterface() == WheelEventInterfaceType || event->type() == eventNames().blurEvent)) + if (renderer() && (event.isMouseEvent() || event.type() == eventNames().blurEvent)) forwardEvent(event); - else if (renderer() && event->isBeforeTextInsertedEvent()) - handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(event)); + else if (renderer() && is<BeforeTextInsertedEvent>(event)) + handleBeforeTextInsertedEvent(downcast<BeforeTextInsertedEvent>(event)); HTMLTextFormControlElement::defaultEventHandler(event); } @@ -279,7 +282,7 @@ void HTMLTextAreaElement::subtreeHasChanged() { setChangedSinceLastFormControlChangeEvent(true); setFormControlValueMatchesRenderer(false); - setNeedsValidityCheck(); + updateValidity(); if (!focused()) return; @@ -290,11 +293,10 @@ void HTMLTextAreaElement::subtreeHasChanged() calculateAndAdjustDirectionality(); } -void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event) const +void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent& event) const { - ASSERT(event); ASSERT(renderer()); - int signedMaxLength = maxLength(); + int signedMaxLength = effectiveMaxLength(); if (signedMaxLength < 0) return; unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength); @@ -302,7 +304,7 @@ void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* const String& currentValue = innerTextValue(); unsigned numberOfLineBreaksInCurrentValue = numberOfLineBreaks(currentValue); if (upperBoundForLengthForSubmission(currentValue, numberOfLineBreaksInCurrentValue) - + upperBoundForLengthForSubmission(event->text(), numberOfLineBreaks(event->text())) < unsignedMaxLength) + + upperBoundForLengthForSubmission(event.text(), numberOfLineBreaks(event.text())) < unsignedMaxLength) return; unsigned currentLength = computeLengthForSubmission(currentValue, numberOfLineBreaksInCurrentValue); @@ -315,7 +317,7 @@ void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* ASSERT(currentLength >= selectionLength); unsigned baseLength = currentLength - selectionLength; unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLength - baseLength : 0; - event->setText(sanitizeUserInputValue(event->text(), appendableLength)); + event.setText(sanitizeUserInputValue(event.text(), appendableLength)); } String HTMLTextAreaElement::sanitizeUserInputValue(const String& proposedValue, unsigned maxLength) @@ -325,8 +327,11 @@ String HTMLTextAreaElement::sanitizeUserInputValue(const String& proposedValue, TextControlInnerTextElement* HTMLTextAreaElement::innerTextElement() const { - Node* node = userAgentShadowRoot()->firstChild(); - return toTextControlInnerTextElement(node); + ShadowRoot* root = userAgentShadowRoot(); + if (!root) + return nullptr; + + return childrenOfType<TextControlInnerTextElement>(*root).first(); } void HTMLTextAreaElement::rendererWillBeDestroyed() @@ -342,10 +347,9 @@ void HTMLTextAreaElement::updateValue() const ASSERT(renderer()); m_value = innerTextValue(); const_cast<HTMLTextAreaElement*>(this)->setFormControlValueMatchesRenderer(true); - const_cast<HTMLTextAreaElement*>(this)->notifyFormStateChanged(); m_isDirty = true; m_wasModifiedByUser = true; - const_cast<HTMLTextAreaElement*>(this)->updatePlaceholderVisibility(false); + const_cast<HTMLTextAreaElement*>(this)->updatePlaceholderVisibility(); } String HTMLTextAreaElement::value() const @@ -358,14 +362,14 @@ void HTMLTextAreaElement::setValue(const String& value) { setValueCommon(value); m_isDirty = true; - setNeedsValidityCheck(); + updateValidity(); } void HTMLTextAreaElement::setNonDirtyValue(const String& value) { setValueCommon(value); m_isDirty = false; - setNeedsValidityCheck(); + updateValidity(); } void HTMLTextAreaElement::setValueCommon(const String& newValue) @@ -373,7 +377,7 @@ void HTMLTextAreaElement::setValueCommon(const String& newValue) m_wasModifiedByUser = false; // Code elsewhere normalizes line endings added by the user via the keyboard or pasting. // We normalize line endings coming from JavaScript here. - String normalizedValue = newValue.isNull() ? "" : newValue; + String normalizedValue = newValue.isNull() ? emptyString() : newValue; normalizedValue.replace("\r\n", "\n"); normalizedValue.replace('\r', '\n'); @@ -385,8 +389,8 @@ void HTMLTextAreaElement::setValueCommon(const String& newValue) m_value = normalizedValue; setInnerTextValue(m_value); setLastChangeWasNotUserEdit(); - updatePlaceholderVisibility(false); - setNeedsStyleRecalc(); + updatePlaceholderVisibility(); + invalidateStyleForSubtree(); setFormControlValueMatchesRenderer(true); // Set the caret to the end of the text value. @@ -395,54 +399,37 @@ void HTMLTextAreaElement::setValueCommon(const String& newValue) setSelectionRange(endOfString, endOfString); } - notifyFormStateChanged(); setTextAsOfLastFormControlChangeEvent(normalizedValue); } String HTMLTextAreaElement::defaultValue() const { - return TextNodeTraversal::contentsAsString(this); + return TextNodeTraversal::contentsAsString(*this); } void HTMLTextAreaElement::setDefaultValue(const String& defaultValue) { - Ref<HTMLTextAreaElement> protectFromMutationEvents(*this); + Ref<HTMLTextAreaElement> protectedThis(*this); // To preserve comments, remove only the text nodes, then add a single text node. - Vector<RefPtr<Text>> textNodes; - for (Text* textNode = TextNodeTraversal::firstChild(this); textNode; textNode = TextNodeTraversal::nextSibling(textNode)) - textNodes.append(textNode); + Vector<Ref<Text>> textNodes; + for (Text* textNode = TextNodeTraversal::firstChild(*this); textNode; textNode = TextNodeTraversal::nextSibling(*textNode)) + textNodes.append(*textNode); - size_t size = textNodes.size(); - for (size_t i = 0; i < size; ++i) - removeChild(textNodes[i].get(), IGNORE_EXCEPTION); + for (auto& textNode : textNodes) + removeChild(textNode.get()); // Normalize line endings. String value = defaultValue; value.replace("\r\n", "\n"); value.replace('\r', '\n'); - insertBefore(document().createTextNode(value), firstChild(), IGNORE_EXCEPTION); + insertBefore(document().createTextNode(value), firstChild()); if (!m_isDirty) setNonDirtyValue(value); } -int HTMLTextAreaElement::maxLength() const -{ - bool ok; - int value = getAttribute(maxlengthAttr).string().toInt(&ok); - return ok && value >= 0 ? value : -1; -} - -void HTMLTextAreaElement::setMaxLength(int newValue, ExceptionCode& ec) -{ - if (newValue < 0) - ec = INDEX_SIZE_ERR; - else - setIntegralAttribute(maxlengthAttr, newValue); -} - String HTMLTextAreaElement::validationMessage() const { if (!willValidate()) @@ -454,8 +441,11 @@ String HTMLTextAreaElement::validationMessage() const if (valueMissing()) return validationMessageValueMissingText(); + if (tooShort()) + return validationMessageTooShortText(computeLengthForSubmission(value()), minLength()); + if (tooLong()) - return validationMessageTooLongText(computeLengthForSubmission(value()), maxLength()); + return validationMessageTooLongText(computeLengthForSubmission(value()), effectiveMaxLength()); return String(); } @@ -465,21 +455,52 @@ bool HTMLTextAreaElement::valueMissing() const return willValidate() && valueMissing(value()); } +bool HTMLTextAreaElement::tooShort() const +{ + return willValidate() && tooShort(value(), CheckDirtyFlag); +} + +bool HTMLTextAreaElement::tooShort(StringView value, NeedsToCheckDirtyFlag check) const +{ + // Return false for the default value or value set by script even if it is + // shorter than minLength. + if (check == CheckDirtyFlag && !m_wasModifiedByUser) + return false; + + int min = minLength(); + if (min <= 0) + return false; + + // The empty string is excluded from tooShort validation. + if (value.isEmpty()) + return false; + + // FIXME: The HTML specification says that the "number of characters" is measured using code-unit length and, + // in the case of textarea elements, with all line breaks normalized to a single character (as opposed to CRLF pairs). + unsigned unsignedMin = static_cast<unsigned>(min); + unsigned numberOfLineBreaksInValue = numberOfLineBreaks(value); + return upperBoundForLengthForSubmission(value, numberOfLineBreaksInValue) < unsignedMin + && computeLengthForSubmission(value, numberOfLineBreaksInValue) < unsignedMin; +} + bool HTMLTextAreaElement::tooLong() const { return willValidate() && tooLong(value(), CheckDirtyFlag); } -bool HTMLTextAreaElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) const +bool HTMLTextAreaElement::tooLong(StringView value, NeedsToCheckDirtyFlag check) const { // Return false for the default value or value set by script even if it is // longer than maxLength. if (check == CheckDirtyFlag && !m_wasModifiedByUser) return false; - int max = maxLength(); + int max = effectiveMaxLength(); if (max < 0) return false; + + // FIXME: The HTML specification says that the "number of characters" is measured using code-unit length and, + // in the case of textarea elements, with all line breaks normalized to a single character (as opposed to CRLF pairs). unsigned unsignedMax = static_cast<unsigned>(max); unsigned numberOfLineBreaksInValue = numberOfLineBreaks(value); return upperBoundForLengthForSubmission(value, numberOfLineBreaksInValue) > unsignedMax @@ -488,7 +509,7 @@ bool HTMLTextAreaElement::tooLong(const String& value, NeedsToCheckDirtyFlag che bool HTMLTextAreaElement::isValidValue(const String& candidate) const { - return !valueMissing(candidate) && !tooLong(candidate, IgnoreDirtyFlag); + return !valueMissing(candidate) && !tooShort(candidate, IgnoreDirtyFlag) && !tooLong(candidate, IgnoreDirtyFlag); } void HTMLTextAreaElement::accessKeyAction(bool) @@ -496,14 +517,14 @@ void HTMLTextAreaElement::accessKeyAction(bool) focus(); } -void HTMLTextAreaElement::setCols(int cols) +void HTMLTextAreaElement::setCols(unsigned cols) { - setIntegralAttribute(colsAttr, cols); + setUnsignedIntegralAttribute(colsAttr, limitToOnlyHTMLNonNegativeNumbersGreaterThanZero(cols, defaultCols)); } -void HTMLTextAreaElement::setRows(int rows) +void HTMLTextAreaElement::setRows(unsigned rows) { - setIntegralAttribute(rowsAttr, rows); + setUnsignedIntegralAttribute(rowsAttr, limitToOnlyHTMLNonNegativeNumbersGreaterThanZero(rows, defaultRows)); } bool HTMLTextAreaElement::shouldUseInputMethod() @@ -513,12 +534,7 @@ bool HTMLTextAreaElement::shouldUseInputMethod() HTMLElement* HTMLTextAreaElement::placeholderElement() const { - return m_placeholder; -} - -bool HTMLTextAreaElement::matchesReadOnlyPseudoClass() const -{ - return isReadOnly(); + return m_placeholder.get(); } bool HTMLTextAreaElement::matchesReadWritePseudoClass() const @@ -531,18 +547,16 @@ void HTMLTextAreaElement::updatePlaceholderText() String placeholderText = strippedPlaceholder(); if (placeholderText.isEmpty()) { if (m_placeholder) { - userAgentShadowRoot()->removeChild(m_placeholder, ASSERT_NO_EXCEPTION); - m_placeholder = 0; + userAgentShadowRoot()->removeChild(*m_placeholder); + m_placeholder = nullptr; } return; } if (!m_placeholder) { - RefPtr<HTMLDivElement> placeholder = HTMLDivElement::create(document()); - m_placeholder = placeholder.get(); - m_placeholder->setPseudo(AtomicString("-webkit-input-placeholder", AtomicString::ConstructFromLiteral)); - userAgentShadowRoot()->insertBefore(m_placeholder, innerTextElement()->nextSibling()); + m_placeholder = TextControlPlaceholderElement::create(document()); + userAgentShadowRoot()->insertBefore(*m_placeholder, innerTextElement()->nextSibling()); } - m_placeholder->setInnerText(placeholderText, ASSERT_NO_EXCEPTION); + m_placeholder->setInnerText(placeholderText); } bool HTMLTextAreaElement::willRespondToMouseClickEvents() @@ -550,4 +564,31 @@ bool HTMLTextAreaElement::willRespondToMouseClickEvents() return !isDisabledFormControl(); } +RenderStyle HTMLTextAreaElement::createInnerTextStyle(const RenderStyle& style) const +{ + auto textBlockStyle = RenderStyle::create(); + textBlockStyle.inheritFrom(style); + adjustInnerTextStyle(style, textBlockStyle); + textBlockStyle.setDisplay(BLOCK); + +#if PLATFORM(IOS) + // We're adding three extra pixels of padding to line textareas up with text fields. + textBlockStyle.setPaddingLeft(Length(3, Fixed)); + textBlockStyle.setPaddingRight(Length(3, Fixed)); +#endif + + return textBlockStyle; +} + +void HTMLTextAreaElement::copyNonAttributePropertiesFromElement(const Element& source) +{ + auto& sourceElement = downcast<HTMLTextAreaElement>(source); + + setValueCommon(sourceElement.value()); + m_isDirty = sourceElement.m_isDirty; + HTMLTextFormControlElement::copyNonAttributePropertiesFromElement(source); + + updateValidity(); +} + } // namespace WebCore |