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;