Title: [118725] trunk
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;
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to