Title: [154761] trunk
Revision
154761
Author
[email protected]
Date
2013-08-28 11:28:55 -0700 (Wed, 28 Aug 2013)

Log Message

Don't keep unassociated elements in the past names map
https://bugs.webkit.org/show_bug.cgi?id=120328

Reviewed by Darin Adler.

Source/WebCore: 

Remove elements from the past names map of a form element when they are disassociated with the form to match
the behaviors of Firefox 24 and Internet Explorer 10. The specification feedback has been submitted to WHATWG
in http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2013-August/040586.html

Also fix a memory leak via the past names map when the elements in the map becomes an ancestor of the form
element by storing a raw pointer in the map. This is safe because the form associated elements are kept alive
by another mechanism.

Because ~FormAssociatedElement removes entries from the past names map, we could no longer store HTMLElement*
in HTMLFormElement::m_pastNamesMap as that requires casting FormAssociatedElement* to HTMLElement*, which is
not possible in ~FormAssociatedElement. We instead store pointers to FormNamedItem, new base class of
FormAssociatedElement and HTMLImageElement.

Test: fast/forms/past-names-map-should-not-contained-disassociated-elements.html

* Target.pri:
* WebCore.exp.in:
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.vcxproj/WebCore.vcxproj.filters:
* WebCore.xcodeproj/project.pbxproj:
* html/FormAssociatedElement.cpp:
* html/FormAssociatedElement.h:
(WebCore::toHTMLElement):

* html/FormNamedItem.h: Added.
(WebCore::FormNamedItem::~FormNamedItem):

* html/HTMLElement.h:
(WebCore::HTMLElement::asFormNamedItem): Added. This allows the conversion from a HTMLFormControlElement,
HTMLObjectElement, HTMLImageElement to FormNamedItem in getNamedElements to update the past names map.

* html/HTMLFormControlElement.h:
* html/HTMLFormElement.cpp:
(WebCore::HTMLFormElement::removeFormElement):
(WebCore::HTMLFormElement::removeImgElement):
(WebCore::HTMLFormElement::assertItemCanBeInPastNamesMap): Asserts that FormNamedItem added to or obtained
from the past names map is either a form associated element or an image element; the condition guarantees
that the item will be removed from the map before its element gets destructed.

(WebCore::HTMLFormElement::elementFromPastNamesMap):
(WebCore::HTMLFormElement::addToPastNamesMap):
(WebCore::HTMLFormElement::removeFromPastNamesMap): Finds and removes the obsolete item from the map in O(n).
Note that removeFromVector, which is called on m_associatedElements or m_imageElements before this function is called,
is already O(n).

(WebCore::HTMLFormElement::getNamedElements):

* html/HTMLFormElement.h:
* html/HTMLImageElement.h:
* html/HTMLObjectElement.h:

LayoutTests: 

Add a regression test. Also Updated the tests to expect the new behavior in which elements are not accessible via
their past names in a form element's name getter once they're disassociated with the form element.

* fast/forms/form-image-access-by-name-expected.txt:
* fast/forms/form-image-access-by-name.html:
* fast/forms/old-names-expected.txt:
* fast/forms/old-names.html:
* fast/forms/past-names-map-should-not-contained-disassociated-elements-expected.txt: Added.
* fast/forms/past-names-map-should-not-contained-disassociated-elements.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (154760 => 154761)


--- trunk/LayoutTests/ChangeLog	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/LayoutTests/ChangeLog	2013-08-28 18:28:55 UTC (rev 154761)
@@ -1,3 +1,20 @@
+2013-08-27  Ryosuke Niwa  <[email protected]>
+
+        Don't keep unassociated elements in the past names map
+        https://bugs.webkit.org/show_bug.cgi?id=120328
+
+        Reviewed by Darin Adler.
+
+        Add a regression test. Also Updated the tests to expect the new behavior in which elements are not accessible via
+        their past names in a form element's name getter once they're disassociated with the form element.
+
+        * fast/forms/form-image-access-by-name-expected.txt:
+        * fast/forms/form-image-access-by-name.html:
+        * fast/forms/old-names-expected.txt:
+        * fast/forms/old-names.html:
+        * fast/forms/past-names-map-should-not-contained-disassociated-elements-expected.txt: Added.
+        * fast/forms/past-names-map-should-not-contained-disassociated-elements.html: Added.
+
 2013-08-28  Brendan Long  <[email protected]>
 
         Duplicate in-band tracks when switching <source> elements

Modified: trunk/LayoutTests/fast/forms/form-image-access-by-name-expected.txt (154760 => 154761)


--- trunk/LayoutTests/fast/forms/form-image-access-by-name-expected.txt	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/LayoutTests/fast/forms/form-image-access-by-name-expected.txt	2013-08-28 18:28:55 UTC (rev 154761)
@@ -1,7 +1,9 @@
 
 PASS form.imageElement.id is '1'
 PASS form.imageElement.id is '2'
-PASS !!form.imageElement is true
+PASS form.imageElement.name = 'foo'; form.foo.id is '2'
+PASS form.imageElement is form.foo
+PASS !!form.imageElement is false
 PASS document.imageElement is undefined.
 PASS !!document.newImage is true
 PASS !!form.newImage is true

Modified: trunk/LayoutTests/fast/forms/form-image-access-by-name.html (154760 => 154761)


--- trunk/LayoutTests/fast/forms/form-image-access-by-name.html	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/LayoutTests/fast/forms/form-image-access-by-name.html	2013-08-28 18:28:55 UTC (rev 154761)
@@ -26,13 +26,12 @@
 
 span.innerHTML = "<img id='2' name='imageElement'>";
 shouldBe("form.imageElement.id", "'2'");
+shouldBe("form.imageElement.name = 'foo'; form.foo.id", "'2'");
+shouldBe("form.imageElement", "form.foo");
 
 span.innerHTML = "<img id='2' name='newImage'>";
+shouldBeFalse("!!form.imageElement");
 
-// imageElement has been removed from the DOM, but,
-// IE 6 has a quirk where once accessed, form images are always accessible by name
-shouldBeTrue("!!form.imageElement");
-
 // This quirk has no bearing on document. access
 shouldBeUndefined("document.imageElement");
 

Modified: trunk/LayoutTests/fast/forms/old-names-expected.txt (154760 => 154761)


--- trunk/LayoutTests/fast/forms/old-names-expected.txt	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/LayoutTests/fast/forms/old-names-expected.txt	2013-08-28 18:28:55 UTC (rev 154761)
@@ -90,10 +90,10 @@
 now remove element a
 
 PASS form.length is 1
-PASS form.original is a
+PASS form.original is undefined.
 PASS form.originalB is b
 PASS form.second is b
-PASS form.third is a
+PASS form.third is undefined.
 PASS form.fourth is b
 PASS form.elements.original is undefined
 PASS form.elements.originalB is undefined
@@ -101,12 +101,12 @@
 PASS form.elements.third is undefined
 PASS form.elements.fourth is b
 
-check we still remember names we should
+check that we no longer remember the past names of a
 
 PASS form.thisWillBeForgotten is undefined
 PASS form.thisWillBeForgottenToo is undefined
-PASS form.thisWillBeRemembered is a
-PASS form.thisWillBeRememberedToo is a
+PASS form.thisWillBeRemembered is undefined.
+PASS form.thisWillBeRememberedToo is undefined.
 
 PASS successfullyParsed is true
 

Modified: trunk/LayoutTests/fast/forms/old-names.html (154760 => 154761)


--- trunk/LayoutTests/fast/forms/old-names.html	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/LayoutTests/fast/forms/old-names.html	2013-08-28 18:28:55 UTC (rev 154761)
@@ -130,10 +130,10 @@
     form.removeChild(a);
 
     shouldBe('form.length', '1');
-    shouldBe('form.original', 'a');
+    shouldBeUndefined('form.original');
     shouldBe('form.originalB', 'b');
     shouldBe('form.second', 'b');
-    shouldBe('form.third', 'a');
+    shouldBeUndefined('form.third');
     shouldBe('form.fourth', 'b');
     shouldBe('form.elements.original', 'undefined');
     shouldBe('form.elements.originalB', 'undefined');
@@ -142,13 +142,13 @@
     shouldBe('form.elements.fourth', 'b');
  
     debug('');
-    debug("check we still remember names we should");
+    debug("check that we no longer remember the past names of a");
     debug('');
 
     shouldBe('form.thisWillBeForgotten', 'undefined');
     shouldBe('form.thisWillBeForgottenToo', 'undefined');
-    shouldBe('form.thisWillBeRemembered', 'a');
-    shouldBe('form.thisWillBeRememberedToo', 'a');
+    shouldBeUndefined('form.thisWillBeRemembered');
+    shouldBeUndefined('form.thisWillBeRememberedToo');
     debug('');
 }
 </script>

Added: trunk/LayoutTests/fast/forms/past-names-map-should-not-contained-disassociated-elements-expected.txt (0 => 154761)


--- trunk/LayoutTests/fast/forms/past-names-map-should-not-contained-disassociated-elements-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/past-names-map-should-not-contained-disassociated-elements-expected.txt	2013-08-28 18:28:55 UTC (rev 154761)
@@ -0,0 +1,16 @@
+This test ensures elements are removed from the past names map of a form element once they are no longer associated with the form element.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS form1['foo'] is input
+PASS form2.appendChild(form1.firstChild); form1['foo'] is undefined.
+PASS form2['foo'] is input
+PASS form2.removeChild(input);form2['foo'] is undefined.
+PASS form1.appendChild(input); form1['foo'] is input
+PASS input.setAttribute('form', 'form1'); form1.removeChild(input); input.appendChild(form1); form1['foo'] is undefined.
+PASS form1['foo'] is not input
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/forms/past-names-map-should-not-contained-disassociated-elements.html (0 => 154761)


--- trunk/LayoutTests/fast/forms/past-names-map-should-not-contained-disassociated-elements.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/past-names-map-should-not-contained-disassociated-elements.html	2013-08-28 18:28:55 UTC (rev 154761)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<body>
+<form id="form1"><input type="text" name="foo"></form>
+<form id="form2"></form>
+<script src=""
+<script>
+
+description('This test ensures elements are removed from the past names map of a form element once they are no longer associated with the form element.');
+
+var form1 = document.querySelector('#form1');
+var form2 = document.querySelector('#form2');
+var input = document.querySelector('input');
+
+shouldBe("form1['foo']", "input");
+shouldBeUndefined("form2.appendChild(form1.firstChild); form1['foo']");
+
+shouldBe("form2['foo']", "input");
+shouldBeUndefined("form2.removeChild(input);form2['foo']");
+
+shouldBe("form1.appendChild(input); form1['foo']", "input");
+shouldBeUndefined("input.setAttribute('form', 'form1'); form1.removeChild(input); input.appendChild(form1); form1['foo']");
+shouldNotBe("form1['foo']", "input");
+
+var successfullyParsed = true;
+
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (154760 => 154761)


--- trunk/Source/WebCore/ChangeLog	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/ChangeLog	2013-08-28 18:28:55 UTC (rev 154761)
@@ -1,3 +1,61 @@
+2013-08-27  Ryosuke Niwa  <[email protected]>
+
+        Don't keep unassociated elements in the past names map
+        https://bugs.webkit.org/show_bug.cgi?id=120328
+
+        Reviewed by Darin Adler.
+
+        Remove elements from the past names map of a form element when they are disassociated with the form to match
+        the behaviors of Firefox 24 and Internet Explorer 10. The specification feedback has been submitted to WHATWG
+        in http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2013-August/040586.html
+
+        Also fix a memory leak via the past names map when the elements in the map becomes an ancestor of the form
+        element by storing a raw pointer in the map. This is safe because the form associated elements are kept alive
+        by another mechanism.
+
+        Because ~FormAssociatedElement removes entries from the past names map, we could no longer store HTMLElement*
+        in HTMLFormElement::m_pastNamesMap as that requires casting FormAssociatedElement* to HTMLElement*, which is
+        not possible in ~FormAssociatedElement. We instead store pointers to FormNamedItem, new base class of
+        FormAssociatedElement and HTMLImageElement.
+
+        Test: fast/forms/past-names-map-should-not-contained-disassociated-elements.html
+
+        * Target.pri:
+        * WebCore.exp.in:
+        * WebCore.vcxproj/WebCore.vcxproj:
+        * WebCore.vcxproj/WebCore.vcxproj.filters:
+        * WebCore.xcodeproj/project.pbxproj:
+        * html/FormAssociatedElement.cpp:
+        * html/FormAssociatedElement.h:
+        (WebCore::toHTMLElement):
+
+        * html/FormNamedItem.h: Added.
+        (WebCore::FormNamedItem::~FormNamedItem):
+
+        * html/HTMLElement.h:
+        (WebCore::HTMLElement::asFormNamedItem): Added. This allows the conversion from a HTMLFormControlElement,
+        HTMLObjectElement, HTMLImageElement to FormNamedItem in getNamedElements to update the past names map.
+
+        * html/HTMLFormControlElement.h:
+        * html/HTMLFormElement.cpp:
+        (WebCore::HTMLFormElement::removeFormElement):
+        (WebCore::HTMLFormElement::removeImgElement):
+        (WebCore::HTMLFormElement::assertItemCanBeInPastNamesMap): Asserts that FormNamedItem added to or obtained
+        from the past names map is either a form associated element or an image element; the condition guarantees
+        that the item will be removed from the map before its element gets destructed.
+
+        (WebCore::HTMLFormElement::elementFromPastNamesMap):
+        (WebCore::HTMLFormElement::addToPastNamesMap):
+        (WebCore::HTMLFormElement::removeFromPastNamesMap): Finds and removes the obsolete item from the map in O(n).
+        Note that removeFromVector, which is called on m_associatedElements or m_imageElements before this function is called,
+        is already O(n).
+
+        (WebCore::HTMLFormElement::getNamedElements):
+
+        * html/HTMLFormElement.h:
+        * html/HTMLImageElement.h:
+        * html/HTMLObjectElement.h:
+
 2013-08-28  Brendan Long  <[email protected]>
 
         Duplicate in-band tracks when switching <source> elements

Modified: trunk/Source/WebCore/Target.pri (154760 => 154761)


--- trunk/Source/WebCore/Target.pri	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/Target.pri	2013-08-28 18:28:55 UTC (rev 154761)
@@ -1799,6 +1799,7 @@
     html/FormAssociatedElement.h \
     html/FormController.h \
     html/FormDataList.h \
+    html/FormNamedItem.h \
     html/FTPDirectoryDocument.h \
     html/HTMLAllCollection.h \
     html/HTMLAnchorElement.h \

Modified: trunk/Source/WebCore/WebCore.exp.in (154760 => 154761)


--- trunk/Source/WebCore/WebCore.exp.in	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/WebCore.exp.in	2013-08-28 18:28:55 UTC (rev 154761)
@@ -286,7 +286,6 @@
 __ZN7WebCore13directoryNameERKN3WTF6StringE
 __ZN7WebCore13listDirectoryERKN3WTF6StringES3_
 __ZN7WebCore13pointerCursorEv
-__ZN7WebCore13toHTMLElementEPNS_21FormAssociatedElementE
 __ZN7WebCore13toJSDOMWindowEN3JSC7JSValueE
 __ZN7WebCore14CachedResource12removeClientEPNS_20CachedResourceClientE
 __ZN7WebCore14CachedResource16unregisterHandleEPNS_24CachedResourceHandleBaseE

Modified: trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj (154760 => 154761)


--- trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj	2013-08-28 18:28:55 UTC (rev 154761)
@@ -20490,6 +20490,7 @@
     <ClInclude Include="..\html\FormAssociatedElement.h" />
     <ClInclude Include="..\html\FormController.h" />
     <ClInclude Include="..\html\FormDataList.h" />
+    <ClInclude Include="..\html\FormNamedItem.h" />
     <ClInclude Include="..\html\FTPDirectoryDocument.h" />
     <ClInclude Include="..\html\HiddenInputType.h" />
     <ClInclude Include="..\html\HTMLAllCollection.h" />

Modified: trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters (154760 => 154761)


--- trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters	2013-08-28 18:28:55 UTC (rev 154761)
@@ -10972,6 +10972,9 @@
     <ClInclude Include="..\html\FormDataList.h">
       <Filter>html</Filter>
     </ClInclude>
+    <ClInclude Include="..\html\FormNamedItem.h">
+      <Filter>html</Filter>
+    </ClInclude>
     <ClInclude Include="..\html\FTPDirectoryDocument.h">
       <Filter>html</Filter>
     </ClInclude>

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (154760 => 154761)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2013-08-28 18:28:55 UTC (rev 154761)
@@ -3255,6 +3255,7 @@
 		9B3A8872145632F9003AE8F5 /* DOMDOMSettableTokenList.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B3A8871145632F9003AE8F5 /* DOMDOMSettableTokenList.h */; };
 		9B417064125662B3006B28FC /* ApplyBlockElementCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B417062125662B3006B28FC /* ApplyBlockElementCommand.h */; };
 		9B417065125662B3006B28FC /* ApplyBlockElementCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9B417063125662B3006B28FC /* ApplyBlockElementCommand.cpp */; };
+		9B50B1DE17CD4C0F0087F63C /* FormNamedItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B50B1DC17CD4C0F0087F63C /* FormNamedItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9B6C41531344949000085B62 /* StringWithDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B6C41521344949000085B62 /* StringWithDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9B7E78BD16F16CC600126914 /* HTMLTreeBuilderSimulator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9B7E78BA16F16CAE00126914 /* HTMLTreeBuilderSimulator.cpp */; };
 		9B7E78BE16F16CC800126914 /* HTMLTreeBuilderSimulator.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B7E78BB16F16CAE00126914 /* HTMLTreeBuilderSimulator.h */; };
@@ -9681,6 +9682,7 @@
 		9B3A8871145632F9003AE8F5 /* DOMDOMSettableTokenList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMDOMSettableTokenList.h; sourceTree = "<group>"; };
 		9B417062125662B3006B28FC /* ApplyBlockElementCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplyBlockElementCommand.h; sourceTree = "<group>"; };
 		9B417063125662B3006B28FC /* ApplyBlockElementCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ApplyBlockElementCommand.cpp; sourceTree = "<group>"; };
+		9B50B1DC17CD4C0F0087F63C /* FormNamedItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormNamedItem.h; sourceTree = "<group>"; };
 		9B6C41521344949000085B62 /* StringWithDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringWithDirection.h; sourceTree = "<group>"; };
 		9B7E78BA16F16CAE00126914 /* HTMLTreeBuilderSimulator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLTreeBuilderSimulator.cpp; path = parser/HTMLTreeBuilderSimulator.cpp; sourceTree = "<group>"; };
 		9B7E78BB16F16CAE00126914 /* HTMLTreeBuilderSimulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTMLTreeBuilderSimulator.h; path = parser/HTMLTreeBuilderSimulator.h; sourceTree = "<group>"; };
@@ -15691,6 +15693,7 @@
 				F50664F6157F52DC00AC226F /* FormController.h */,
 				A8136D370973A8E700D74463 /* FormDataList.cpp */,
 				A8136D360973A8E700D74463 /* FormDataList.h */,
+				9B50B1DC17CD4C0F0087F63C /* FormNamedItem.h */,
 				97205AAD123928CA00B17380 /* FTPDirectoryDocument.cpp */,
 				97205AAE123928CA00B17380 /* FTPDirectoryDocument.h */,
 				F55B3D8B1251F12D003EF269 /* HiddenInputType.cpp */,
@@ -22881,6 +22884,7 @@
 				1A0D57370A5C77FE007EDD4C /* OverflowEvent.h in Headers */,
 				3774ABA50FA21EB400AD7DE9 /* OverlapTestRequestClient.h in Headers */,
 				65A21468097A329100B9050A /* Page.h in Headers */,
+				9B50B1DE17CD4C0F0087F63C /* FormNamedItem.h in Headers */,
 				1477E7770BF4134A00152872 /* PageCache.h in Headers */,
 				DAED203116F244480070EC0F /* PageConsole.h in Headers */,
 				F3820893147D35F90010BC06 /* PageConsoleAgent.h in Headers */,

Modified: trunk/Source/WebCore/html/FormAssociatedElement.cpp (154760 => 154761)


--- trunk/Source/WebCore/html/FormAssociatedElement.cpp	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/html/FormAssociatedElement.cpp	2013-08-28 18:28:55 UTC (rev 154761)
@@ -273,21 +273,6 @@
     return false;
 }
 
-const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
-{
-    if (associatedElement->isFormControlElement())
-        return static_cast<const HTMLFormControlElement*>(associatedElement);
-    // Assumes the element is an HTMLObjectElement
-    const HTMLElement* element = static_cast<const HTMLObjectElement*>(associatedElement);
-    ASSERT(element->hasTagName(objectTag));
-    return element;
-}
-
-HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
-{
-    return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
-}
-
 PassOwnPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element)
 {
     return adoptPtr(new FormAttributeTargetObserver(id, element));

Modified: trunk/Source/WebCore/html/FormAssociatedElement.h (154760 => 154761)


--- trunk/Source/WebCore/html/FormAssociatedElement.h	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/html/FormAssociatedElement.h	2013-08-28 18:28:55 UTC (rev 154761)
@@ -24,6 +24,7 @@
 #ifndef FormAssociatedElement_h
 #define FormAssociatedElement_h
 
+#include "FormNamedItem.h"
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -39,7 +40,7 @@
 class ValidityState;
 class VisibleSelection;
 
-class FormAssociatedElement {
+class FormAssociatedElement : public FormNamedItem {
 public:
     virtual ~FormAssociatedElement();
 
@@ -112,15 +113,24 @@
 
     void resetFormAttributeTargetObserver();
 
+    virtual bool isFormAssociatedElement() OVERRIDE FINAL { return true; }
+
     OwnPtr<FormAttributeTargetObserver> m_formAttributeTargetObserver;
     HTMLFormElement* m_form;
     OwnPtr<ValidityState> m_validityState;
     String m_customValidationMessage;
 };
 
-HTMLElement* toHTMLElement(FormAssociatedElement*);
-const HTMLElement* toHTMLElement(const FormAssociatedElement*);
+inline const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
+{
+    return const_cast<FormAssociatedElement*>(associatedElement)->asHTMLElement();
+}
 
+inline HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
+{
+    return associatedElement->asHTMLElement();
+}
+
 } // namespace
 
 #endif // FormAssociatedElement_h

Added: trunk/Source/WebCore/html/FormNamedItem.h (0 => 154761)


--- trunk/Source/WebCore/html/FormNamedItem.h	                        (rev 0)
+++ trunk/Source/WebCore/html/FormNamedItem.h	2013-08-28 18:28:55 UTC (rev 154761)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FormNamedItem_h
+#define FormNamedItem_h
+
+namespace WebCore {
+
+class HTMLElement;
+
+class FormNamedItem {
+public:
+    virtual ~FormNamedItem() { }
+    virtual HTMLElement* asHTMLElement() = 0;
+    virtual bool isFormAssociatedElement() = 0;
+};
+
+}
+
+#endif /* FormNamedItem_h */

Modified: trunk/Source/WebCore/html/HTMLElement.h (154760 => 154761)


--- trunk/Source/WebCore/html/HTMLElement.h	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/html/HTMLElement.h	2013-08-28 18:28:55 UTC (rev 154761)
@@ -28,6 +28,7 @@
 namespace WebCore {
 
 class DocumentFragment;
+class FormNamedItem;
 class HTMLCollection;
 class HTMLFormElement;
 
@@ -93,6 +94,7 @@
     virtual bool isHTMLUnknownElement() const { return false; }
 
     virtual bool isLabelable() const { return false; }
+    virtual FormNamedItem* asFormNamedItem() { return 0; }
 
 protected:
     HTMLElement(const QualifiedName& tagName, Document*, ConstructionType);

Modified: trunk/Source/WebCore/html/HTMLFormControlElement.h (154760 => 154761)


--- trunk/Source/WebCore/html/HTMLFormControlElement.h	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/html/HTMLFormControlElement.h	2013-08-28 18:28:55 UTC (rev 154761)
@@ -144,6 +144,9 @@
     virtual bool isValidFormControlElement();
     void updateAncestorDisabledState() const;
 
+    virtual HTMLElement* asHTMLElement() OVERRIDE FINAL { return this; }
+    virtual FormNamedItem* asFormNamedItem() OVERRIDE FINAL { return this; }
+
     OwnPtr<ValidationMessage> m_validationMessage;
     bool m_disabled : 1;
     bool m_isReadOnly : 1;

Modified: trunk/Source/WebCore/html/HTMLFormElement.cpp (154760 => 154761)


--- trunk/Source/WebCore/html/HTMLFormElement.cpp	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/html/HTMLFormElement.cpp	2013-08-28 18:28:55 UTC (rev 154761)
@@ -499,6 +499,7 @@
         --m_associatedElementsBeforeIndex;
     if (index < m_associatedElementsAfterIndex)
         --m_associatedElementsAfterIndex;
+    removeFromPastNamesMap(e);
     removeFromVector(m_associatedElements, e);
 }
 
@@ -516,6 +517,7 @@
 void HTMLFormElement::removeImgElement(HTMLImageElement* e)
 {
     ASSERT(m_imageElements.find(e) != notFound);
+    removeFromPastNamesMap(e);
     removeFromVector(m_imageElements, e);
 }
 
@@ -611,36 +613,75 @@
     return hasInvalidControls;
 }
 
-HTMLFormControlElement* HTMLFormElement::elementFromPastNamesMap(const AtomicString& pastName) const
+#ifndef NDEBUG
+void HTMLFormElement::assertItemCanBeInPastNamesMap(FormNamedItem* item) const
 {
+    HTMLElement* element = item->asHTMLElement();
+    ASSERT_WITH_SECURITY_IMPLICATION(element);
+    ASSERT_WITH_SECURITY_IMPLICATION(element->form() == this);
+    if (item->isFormAssociatedElement()) {
+        ASSERT_WITH_SECURITY_IMPLICATION(m_associatedElements.find(static_cast<FormAssociatedElement*>(item)) != notFound);
+        return;
+    }
+
+    ASSERT_WITH_SECURITY_IMPLICATION(element->hasTagName(imgTag));
+    ASSERT_WITH_SECURITY_IMPLICATION(m_imageElements.find(toHTMLImageElement(element)) != notFound);
+}
+#else
+inline void HTMLFormElement::assertItemCanBeInPastNamesMap(FormNamedItem*) const
+{
+}
+#endif
+
+HTMLElement* HTMLFormElement::elementFromPastNamesMap(const AtomicString& pastName) const
+{
     if (pastName.isEmpty() || !m_pastNamesMap)
         return 0;
-    return m_pastNamesMap->get(pastName.impl());
+    FormNamedItem* item = m_pastNamesMap->get(pastName.impl());
+    if (!item)
+        return 0;
+    assertItemCanBeInPastNamesMap(item);
+    return item->asHTMLElement();
 }
 
-void HTMLFormElement::addElementToPastNamesMap(HTMLFormControlElement* element, const AtomicString& pastName)
+void HTMLFormElement::addToPastNamesMap(FormNamedItem* item, const AtomicString& pastName)
 {
+    assertItemCanBeInPastNamesMap(item);
     if (pastName.isEmpty())
         return;
     if (!m_pastNamesMap)
         m_pastNamesMap = adoptPtr(new PastNamesMap);
-    m_pastNamesMap->set(pastName.impl(), element);
+    m_pastNamesMap->set(pastName.impl(), item);
 }
 
+void HTMLFormElement::removeFromPastNamesMap(FormNamedItem* item)
+{
+    ASSERT(item);
+    if (!m_pastNamesMap)
+        return;
+
+    PastNamesMap::iterator end = m_pastNamesMap->end();
+    for (PastNamesMap::iterator it = m_pastNamesMap->begin(); it != end; ++it) {
+        if (it->value == item)
+            it->value = 0; // Keep looping. Single element can have multiple names.
+    }
+}
+
 bool HTMLFormElement::hasNamedElement(const AtomicString& name)
 {
     return elements()->hasNamedItem(name) || elementFromPastNamesMap(name);
 }
 
+// FIXME: Use RefPtr<HTMLElement> for namedItems. elements()->namedItems never return non-HTMLElement nodes.
 void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
 {
     // http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#dom-form-nameditem
     elements()->namedItems(name, namedItems);
 
     // FIXME: The specification says we should not add the element from the past when names map when namedItems is not empty.
-    HTMLFormControlElement* elementFromPast = elementFromPastNamesMap(name);
+    HTMLElement* elementFromPast = elementFromPastNamesMap(name);
     if (namedItems.size() == 1 && namedItems.first() != elementFromPast)
-        addElementToPastNamesMap(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
+        addToPastNamesMap(toHTMLElement(namedItems.first().get())->asFormNamedItem(), name);
     else if (elementFromPast && namedItems.find(elementFromPast) == notFound)
         namedItems.append(elementFromPast);
 }

Modified: trunk/Source/WebCore/html/HTMLFormElement.h (154760 => 154761)


--- trunk/Source/WebCore/html/HTMLFormElement.h	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/html/HTMLFormElement.h	2013-08-28 18:28:55 UTC (rev 154761)
@@ -138,11 +138,12 @@
     // are any invalid controls in this form.
     bool checkInvalidControlsAndCollectUnhandled(Vector<RefPtr<FormAssociatedElement> >&);
 
-    HTMLFormControlElement* elementFromPastNamesMap(const AtomicString&) const;
-    void addElementToPastNamesMap(HTMLFormControlElement*, const AtomicString& pastName);
+    HTMLElement* elementFromPastNamesMap(const AtomicString&) const;
+    void addToPastNamesMap(FormNamedItem*, const AtomicString& pastName);
+    void assertItemCanBeInPastNamesMap(FormNamedItem*) const;
+    void removeFromPastNamesMap(FormNamedItem*);
 
-    // FIXME: This can leak HTMLFormControlElements.
-    typedef HashMap<RefPtr<AtomicStringImpl>, RefPtr<HTMLFormControlElement> > PastNamesMap;
+    typedef HashMap<RefPtr<AtomicStringImpl>, FormNamedItem*> PastNamesMap;
 
     FormSubmission::Attributes m_attributes;
     OwnPtr<PastNamesMap> m_pastNamesMap;

Modified: trunk/Source/WebCore/html/HTMLImageElement.h (154760 => 154761)


--- trunk/Source/WebCore/html/HTMLImageElement.h	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/html/HTMLImageElement.h	2013-08-28 18:28:55 UTC (rev 154761)
@@ -24,6 +24,7 @@
 #ifndef HTMLImageElement_h
 #define HTMLImageElement_h
 
+#include "FormNamedItem.h"
 #include "GraphicsTypes.h"
 #include "HTMLElement.h"
 #include "HTMLImageLoader.h"
@@ -32,7 +33,7 @@
 
 class HTMLFormElement;
 
-class HTMLImageElement : public HTMLElement {
+class HTMLImageElement : public HTMLElement, public FormNamedItem {
     friend class HTMLFormElement;
 public:
     static PassRefPtr<HTMLImageElement> create(Document*);
@@ -104,6 +105,10 @@
     virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
     virtual void removedFrom(ContainerNode*) OVERRIDE;
 
+    virtual bool isFormAssociatedElement() OVERRIDE FINAL { return false; }
+    virtual FormNamedItem* asFormNamedItem() OVERRIDE FINAL { return this; }
+    virtual HTMLElement* asHTMLElement() OVERRIDE FINAL { return this; }
+
     HTMLImageLoader m_imageLoader;
     HTMLFormElement* m_form;
     CompositeOperator m_compositeOperator;

Modified: trunk/Source/WebCore/html/HTMLObjectElement.h (154760 => 154761)


--- trunk/Source/WebCore/html/HTMLObjectElement.h	2013-08-28 18:27:03 UTC (rev 154760)
+++ trunk/Source/WebCore/html/HTMLObjectElement.h	2013-08-28 18:28:55 UTC (rev 154761)
@@ -101,6 +101,9 @@
     virtual void derefFormAssociatedElement() { deref(); }
     virtual HTMLFormElement* virtualForm() const;
 
+    virtual FormNamedItem* asFormNamedItem() OVERRIDE FINAL { return this; }
+    virtual HTMLElement* asHTMLElement() OVERRIDE FINAL { return this; }
+
     String m_classId;
     bool m_docNamedItem : 1;
     bool m_useFallbackContent : 1;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to