- Revision
- 118725
- Author
- tk...@chromium.org
- Date
- 2012-05-28 22:37:57 -0700 (Mon, 28 May 2012)
Log Message
Fix a crash in HTMLFormControlElement::disabled().
https://bugs.webkit.org/show_bug.cgi?id=86534
Reviewed by Ryosuke Niwa.
Source/WebCore:
Stop to hold pointers of fildset and legend elements. We can avoid it by
holding ancestor's disabled state.
The ancesotr's disabled state should be invalidated when
- fieldset's disabled value is changed.
- fieldset's children is updated because a legend position might be changed.
- A form control is attached to or detached from a tree.
No new tests. It's almost impossible to make a reliable test.
* html/HTMLFieldSetElement.cpp:
(WebCore::HTMLFieldSetElement::invalidateDisabledStateUnder):
Added. Invalidate disabled state of form controls under the specified node.
(WebCore::HTMLFieldSetElement::disabledAttributeChanged):
Uses invalidateDisabledStateUnder().
(WebCore::HTMLFieldSetElement::childrenChanged):
Added new override function. We need invalidate disabled state of form
controls under legend elements.
* html/HTMLFieldSetElement.h:
(HTMLFieldSetElement): Add invalidateDisabledStateUnder() and childrenChanged().
* html/HTMLFormControlElement.cpp:
(WebCore::HTMLFormControlElement::HTMLFormControlElement):
Remove initialization of the removed data members.
Initialize m_ancestorDisabledState.
(WebCore::HTMLFormControlElement::updateAncestorDisabledState):
Update m_ancestorDisabledState. It should be
AncestorDisabledStateDisabled if the control is under a disabled
fieldset and not under the first legend child of the disabled filedset.
(WebCore::HTMLFormControlElement::ancestorDisabledStateWasChanged):
Invalidate m_ancestorDisabledState.
(WebCore::HTMLFormControlElement::insertedInto): ditto.
(WebCore::HTMLFormControlElement::removedFrom): ditto.
(WebCore::HTMLFormControlElement::disabled):
Calls updateAncestorDisabledState() if needed.
(WebCore::HTMLFormControlElement::recalcWillValidate):
Remove unnecessary check for m_legendAncestor.
* html/HTMLFormControlElement.h:
(HTMLFormControlElement):
- Rename updateFieldSetAndLegendAncestor() to updateAncestorDisabledState(), and make it private.
- Remove m_fieldSetAncestor, m_legendAncestor, and m_fieldSetAncestorValid.
- Add m_ancestorDisabledState.
LayoutTests:
Add a testcase to confirm <lagend> doesn't affect validation.
* fast/forms/datalist/datalist-child-validation-expected.txt:
* fast/forms/datalist/datalist-child-validation.html:
Modified Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (118724 => 118725)
--- trunk/LayoutTests/ChangeLog 2012-05-29 05:16:54 UTC (rev 118724)
+++ trunk/LayoutTests/ChangeLog 2012-05-29 05:37:57 UTC (rev 118725)
@@ -1,3 +1,15 @@
+2012-05-28 Kent Tamura <tk...@chromium.org>
+
+ Fix a crash in HTMLFormControlElement::disabled().
+ https://bugs.webkit.org/show_bug.cgi?id=86534
+
+ Reviewed by Ryosuke Niwa.
+
+ Add a testcase to confirm <lagend> doesn't affect validation.
+
+ * fast/forms/datalist/datalist-child-validation-expected.txt:
+ * fast/forms/datalist/datalist-child-validation.html:
+
2012-05-28 Marcus Bulach <bul...@chromium.org>
Removes pixel result requirements from fast/layers/clip-rects-assertion-expected.txt
Modified: trunk/LayoutTests/fast/forms/datalist/datalist-child-validation-expected.txt (118724 => 118725)
--- trunk/LayoutTests/fast/forms/datalist/datalist-child-validation-expected.txt 2012-05-29 05:16:54 UTC (rev 118724)
+++ trunk/LayoutTests/fast/forms/datalist/datalist-child-validation-expected.txt 2012-05-29 05:37:57 UTC (rev 118725)
@@ -9,6 +9,7 @@
PASS e.willValidate is true
PASS e.willValidate is true
PASS document.querySelector(":invalid") is e
+PASS document.getElementById("inLegend").willValidate is false
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/fast/forms/datalist/datalist-child-validation.html (118724 => 118725)
--- trunk/LayoutTests/fast/forms/datalist/datalist-child-validation.html 2012-05-29 05:16:54 UTC (rev 118724)
+++ trunk/LayoutTests/fast/forms/datalist/datalist-child-validation.html 2012-05-29 05:37:57 UTC (rev 118725)
@@ -11,8 +11,12 @@
<div id=w>
<input type=text id=e required>
</div>
+ <legend>
+ <input id="inLegend" required>
+ </legend>
</datalist>
+
<script>
description('Test for child elements of a datalist element.');
@@ -28,6 +32,8 @@
shouldBeTrue('e.willValidate');
shouldBe('document.querySelector(":invalid")', 'e');
+shouldBeFalse('document.getElementById("inLegend").willValidate');
+
</script>
<script src=""
</body>
Modified: trunk/Source/WebCore/ChangeLog (118724 => 118725)
--- trunk/Source/WebCore/ChangeLog 2012-05-29 05:16:54 UTC (rev 118724)
+++ trunk/Source/WebCore/ChangeLog 2012-05-29 05:37:57 UTC (rev 118725)
@@ -1,3 +1,55 @@
+2012-05-28 Kent Tamura <tk...@chromium.org>
+
+ Fix a crash in HTMLFormControlElement::disabled().
+ https://bugs.webkit.org/show_bug.cgi?id=86534
+
+ Reviewed by Ryosuke Niwa.
+
+ Stop to hold pointers of fildset and legend elements. We can avoid it by
+ holding ancestor's disabled state.
+
+ The ancesotr's disabled state should be invalidated when
+ - fieldset's disabled value is changed.
+ - fieldset's children is updated because a legend position might be changed.
+ - A form control is attached to or detached from a tree.
+
+ No new tests. It's almost impossible to make a reliable test.
+
+ * html/HTMLFieldSetElement.cpp:
+ (WebCore::HTMLFieldSetElement::invalidateDisabledStateUnder):
+ Added. Invalidate disabled state of form controls under the specified node.
+ (WebCore::HTMLFieldSetElement::disabledAttributeChanged):
+ Uses invalidateDisabledStateUnder().
+ (WebCore::HTMLFieldSetElement::childrenChanged):
+ Added new override function. We need invalidate disabled state of form
+ controls under legend elements.
+
+ * html/HTMLFieldSetElement.h:
+ (HTMLFieldSetElement): Add invalidateDisabledStateUnder() and childrenChanged().
+
+ * html/HTMLFormControlElement.cpp:
+ (WebCore::HTMLFormControlElement::HTMLFormControlElement):
+ Remove initialization of the removed data members.
+ Initialize m_ancestorDisabledState.
+ (WebCore::HTMLFormControlElement::updateAncestorDisabledState):
+ Update m_ancestorDisabledState. It should be
+ AncestorDisabledStateDisabled if the control is under a disabled
+ fieldset and not under the first legend child of the disabled filedset.
+ (WebCore::HTMLFormControlElement::ancestorDisabledStateWasChanged):
+ Invalidate m_ancestorDisabledState.
+ (WebCore::HTMLFormControlElement::insertedInto): ditto.
+ (WebCore::HTMLFormControlElement::removedFrom): ditto.
+ (WebCore::HTMLFormControlElement::disabled):
+ Calls updateAncestorDisabledState() if needed.
+ (WebCore::HTMLFormControlElement::recalcWillValidate):
+ Remove unnecessary check for m_legendAncestor.
+
+ * html/HTMLFormControlElement.h:
+ (HTMLFormControlElement):
+ - Rename updateFieldSetAndLegendAncestor() to updateAncestorDisabledState(), and make it private.
+ - Remove m_fieldSetAncestor, m_legendAncestor, and m_fieldSetAncestorValid.
+ - Add m_ancestorDisabledState.
+
2012-05-28 Takashi Toyoshima <toyos...@chromium.org>
[WebSocket] Receiving reserved close codes, 1005, 1006, and 1015 must appear as code=1006 and wasClean=false
Modified: trunk/Source/WebCore/html/HTMLFieldSetElement.cpp (118724 => 118725)
--- trunk/Source/WebCore/html/HTMLFieldSetElement.cpp 2012-05-29 05:16:54 UTC (rev 118724)
+++ trunk/Source/WebCore/html/HTMLFieldSetElement.cpp 2012-05-29 05:37:57 UTC (rev 118725)
@@ -47,14 +47,27 @@
return adoptRef(new HTMLFieldSetElement(tagName, document, form));
}
+void HTMLFieldSetElement::invalidateDisabledStateUnder(Element* base)
+{
+ for (Node* currentNode = base->traverseNextNode(base); currentNode; currentNode = currentNode->traverseNextNode(base)) {
+ if (currentNode && currentNode->isElementNode() && toElement(currentNode)->isFormControlElement())
+ static_cast<HTMLFormControlElement*>(currentNode)->ancestorDisabledStateWasChanged();
+ }
+}
+
void HTMLFieldSetElement::disabledAttributeChanged()
{
// This element must be updated before the style of nodes in its subtree gets recalculated.
HTMLFormControlElement::disabledAttributeChanged();
+ invalidateDisabledStateUnder(this);
+}
- for (Node* currentNode = this->traverseNextNode(this); currentNode; currentNode = currentNode->traverseNextNode(this)) {
- if (currentNode && currentNode->isElementNode() && toElement(currentNode)->isFormControlElement())
- static_cast<HTMLFormControlElement*>(currentNode)->ancestorDisabledStateWasChanged();
+void HTMLFieldSetElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+ HTMLFormControlElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+ for (Element* element = firstElementChild(); element; element = element->nextElementSibling()) {
+ if (element->hasTagName(legendTag))
+ invalidateDisabledStateUnder(element);
}
}
Modified: trunk/Source/WebCore/html/HTMLFieldSetElement.h (118724 => 118725)
--- trunk/Source/WebCore/html/HTMLFieldSetElement.h 2012-05-29 05:16:54 UTC (rev 118724)
+++ trunk/Source/WebCore/html/HTMLFieldSetElement.h 2012-05-29 05:37:57 UTC (rev 118725)
@@ -54,7 +54,9 @@
virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
virtual const AtomicString& formControlType() const;
virtual bool recalcWillValidate() const { return false; }
+ virtual void childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) OVERRIDE;
+ static void invalidateDisabledStateUnder(Element*);
void refreshElementsIfNeeded() const;
OwnPtr<HTMLFormCollection> m_elementsCollection;
Modified: trunk/Source/WebCore/html/HTMLFormControlElement.cpp (118724 => 118725)
--- trunk/Source/WebCore/html/HTMLFormControlElement.cpp 2012-05-29 05:16:54 UTC (rev 118724)
+++ trunk/Source/WebCore/html/HTMLFormControlElement.cpp 2012-05-29 05:37:57 UTC (rev 118725)
@@ -48,13 +48,11 @@
HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
: LabelableElement(tagName, document)
- , m_fieldSetAncestor(0)
- , m_legendAncestor(0)
- , m_fieldSetAncestorValid(false)
, m_disabled(false)
, m_readOnly(false)
, m_required(false)
, m_valueMatchesRenderer(false)
+ , m_ancestorDisabledState(AncestorDisabledStateUnknown)
, m_dataListAncestorState(Unknown)
, m_willValidateInitialized(false)
, m_willValidate(true)
@@ -95,23 +93,24 @@
return fastHasAttribute(formnovalidateAttr);
}
-void HTMLFormControlElement::updateFieldSetAndLegendAncestor() const
+void HTMLFormControlElement::updateAncestorDisabledState() const
{
- m_fieldSetAncestor = 0;
- m_legendAncestor = 0;
+ HTMLFieldSetElement* fieldSetAncestor = 0;
+ ContainerNode* legendAncestor = 0;
for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
- if (!m_legendAncestor && ancestor->hasTagName(legendTag))
- m_legendAncestor = static_cast<HTMLLegendElement*>(ancestor);
+ if (!legendAncestor && ancestor->hasTagName(legendTag))
+ legendAncestor = ancestor;
if (ancestor->hasTagName(fieldsetTag)) {
- m_fieldSetAncestor = static_cast<HTMLFieldSetElement*>(ancestor);
+ fieldSetAncestor = static_cast<HTMLFieldSetElement*>(ancestor);
break;
}
}
- m_fieldSetAncestorValid = true;
+ m_ancestorDisabledState = (fieldSetAncestor && fieldSetAncestor->disabled() && !(legendAncestor && legendAncestor == fieldSetAncestor->legend())) ? AncestorDisabledStateDisabled : AncestorDisabledStateEnabled;
}
void HTMLFormControlElement::ancestorDisabledStateWasChanged()
{
+ m_ancestorDisabledState = AncestorDisabledStateUnknown;
disabledAttributeChanged();
}
@@ -224,7 +223,7 @@
Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode* insertionPoint)
{
- m_fieldSetAncestorValid = false;
+ m_ancestorDisabledState = AncestorDisabledStateUnknown;
m_dataListAncestorState = Unknown;
setNeedsWillValidateCheck();
HTMLElement::insertedInto(insertionPoint);
@@ -235,7 +234,7 @@
void HTMLFormControlElement::removedFrom(ContainerNode* insertionPoint)
{
m_validationMessage = nullptr;
- m_fieldSetAncestorValid = false;
+ m_ancestorDisabledState = AncestorDisabledStateUnknown;
m_dataListAncestorState = Unknown;
HTMLElement::removedFrom(insertionPoint);
FormAssociatedElement::removedFrom(insertionPoint);
@@ -279,13 +278,9 @@
if (m_disabled)
return true;
- if (!m_fieldSetAncestorValid)
- updateFieldSetAndLegendAncestor();
-
- // Form controls in the first legend element inside a fieldset are not affected by fieldset.disabled.
- if (m_fieldSetAncestor && m_fieldSetAncestor->disabled())
- return !(m_legendAncestor && m_legendAncestor == m_fieldSetAncestor->legend());
- return false;
+ if (m_ancestorDisabledState == AncestorDisabledStateUnknown)
+ updateAncestorDisabledState();
+ return m_ancestorDisabledState == AncestorDisabledStateDisabled;
}
void HTMLFormControlElement::setDisabled(bool b)
@@ -361,7 +356,7 @@
{
if (m_dataListAncestorState == Unknown) {
for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
- if (!m_legendAncestor && ancestor->hasTagName(datalistTag)) {
+ if (ancestor->hasTagName(datalistTag)) {
m_dataListAncestorState = InsideDataList;
break;
}
Modified: trunk/Source/WebCore/html/HTMLFormControlElement.h (118724 => 118725)
--- trunk/Source/WebCore/html/HTMLFormControlElement.h 2012-05-29 05:16:54 UTC (rev 118724)
+++ trunk/Source/WebCore/html/HTMLFormControlElement.h 2012-05-29 05:37:57 UTC (rev 118725)
@@ -51,7 +51,6 @@
void setFormMethod(const String&);
bool formNoValidate() const;
- void updateFieldSetAndLegendAncestor() const;
void ancestorDisabledStateWasChanged();
virtual void reset() { }
@@ -148,16 +147,16 @@
virtual bool isDefaultButtonForForm() const;
virtual bool isValidFormControlElement();
String visibleValidationMessage() const;
+ void updateAncestorDisabledState() const;
- mutable HTMLFieldSetElement* m_fieldSetAncestor;
- mutable HTMLLegendElement* m_legendAncestor;
OwnPtr<ValidationMessage> m_validationMessage;
- mutable bool m_fieldSetAncestorValid : 1;
bool m_disabled : 1;
bool m_readOnly : 1;
bool m_required : 1;
bool m_valueMatchesRenderer : 1;
+ enum AncestorDisabledState { AncestorDisabledStateUnknown, AncestorDisabledStateEnabled, AncestorDisabledStateDisabled };
+ mutable AncestorDisabledState m_ancestorDisabledState;
enum DataListAncestorState { Unknown, InsideDataList, NotInsideDataList };
mutable enum DataListAncestorState m_dataListAncestorState;