author | Andrea Marchesini <amarchesini@mozilla.com> |
Wed, 19 Jun 2013 10:24:37 -0400 | |
changeset 135596 | 259e68f8843dd7c9af1766cb6092434f276c2db6 |
parent 135595 | 192cecc0111e5a7c30fe2a0c83aed53d444dce91 |
child 135597 | 5a3dc3d3189099e7d1b3c070ef6532c850213764 |
push id | 29734 |
push user | bzbarsky@mozilla.com |
push date | Wed, 19 Jun 2013 14:24:53 +0000 |
treeherder | mozilla-inbound@259e68f8843d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bz |
bugs | 841442 |
milestone | 24.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/base/src/nsFormData.cpp +++ b/content/base/src/nsFormData.cpp @@ -104,23 +104,23 @@ nsFormData::Append(const nsAString& aNam /* virtual */ JSObject* nsFormData::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) { return FormDataBinding::Wrap(aCx, aScope, this); } /* static */ already_AddRefed<nsFormData> nsFormData::Constructor(const GlobalObject& aGlobal, - const Optional<HTMLFormElement*>& aFormElement, + const Optional<NonNull<HTMLFormElement> >& aFormElement, ErrorResult& aRv) { nsRefPtr<nsFormData> formData = new nsFormData(aGlobal.Get()); if (aFormElement.WasPassed()) { - MOZ_ASSERT(aFormElement.Value()); - aRv = aFormElement.Value()->WalkFormElements(formData); + // TODO: this should ...Value().WalkFromElements(formData); - Bug 883827 + aRv = aFormElement.Value().get()->WalkFormElements(formData); } return formData.forget(); } // ------------------------------------------------------------------------- // nsIXHRSendable NS_IMETHODIMP
--- a/content/base/src/nsFormData.h +++ b/content/base/src/nsFormData.h @@ -47,17 +47,17 @@ public: // WebIDL nsISupports* GetParentObject() const { return mOwner; } static already_AddRefed<nsFormData> Constructor(const mozilla::dom::GlobalObject& aGlobal, - const mozilla::dom::Optional<mozilla::dom::HTMLFormElement*>& aFormElement, + const mozilla::dom::Optional<mozilla::dom::NonNull<mozilla::dom::HTMLFormElement> >& aFormElement, mozilla::ErrorResult& aRv); void Append(const nsAString& aName, const nsAString& aValue); void Append(const nsAString& aName, nsIDOMBlob* aBlob, const mozilla::dom::Optional<nsAString>& aFilename); // nsFormSubmission virtual nsresult GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream) MOZ_OVERRIDE;
--- a/content/html/content/src/HTMLFormElement.cpp +++ b/content/html/content/src/HTMLFormElement.cpp @@ -1,14 +1,15 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/HTMLFormElement.h" +#include "mozilla/dom/HTMLFormElementBinding.h" #include "nsIHTMLDocument.h" #include "nsEventStateManager.h" #include "nsEventStates.h" #include "nsGkAtoms.h" #include "nsStyleConsts.h" #include "nsPresContext.h" #include "nsIDocument.h" #include "nsIFormControlFrame.h" @@ -247,16 +248,18 @@ HTMLFormElement::HTMLFormElement(already mDefaultSubmitElement(nullptr), mFirstSubmitInElements(nullptr), mFirstSubmitNotInElements(nullptr), mInvalidElementsCount(0), mEverTriedInvalidSubmit(false) { mImageNameLookupTable.Init(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE); mPastNameLookupTable.Init(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE); + + SetIsDOMBinding(); } HTMLFormElement::~HTMLFormElement() { if (mControls) { mControls->DropFormReference(); } @@ -306,18 +309,27 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageNameLookupTable) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPastNameLookupTable) tmp->mSelectedRadioButtons.EnumerateRead(ElementTraverser, &cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLFormElement, nsGenericHTMLElement) tmp->Clear(); + ++tmp->mExpandoAndGeneration.generation; + tmp->mExpandoAndGeneration.expando = JS::UndefinedValue(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(HTMLFormElement, + nsGenericHTMLElement) + if (tmp->PreservingWrapper()) { + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mExpandoAndGeneration.expando); + } +NS_IMPL_CYCLE_COLLECTION_TRACE_END + NS_IMPL_ADDREF_INHERITED(HTMLFormElement, Element) NS_IMPL_RELEASE_INHERITED(HTMLFormElement, Element) // QueryInterface implementation for HTMLFormElement NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLFormElement) NS_HTML_CONTENT_INTERFACES(nsGenericHTMLElement) NS_INTERFACE_TABLE_INHERITED4(HTMLFormElement, @@ -329,20 +341,26 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLFormElement) NS_ELEMENT_INTERFACE_MAP_END // nsIDOMHTMLFormElement NS_IMPL_ELEMENT_CLONE_WITH_INIT(HTMLFormElement) +nsIHTMLCollection* +HTMLFormElement::Elements() +{ + return mControls; +} + NS_IMETHODIMP HTMLFormElement::GetElements(nsIDOMHTMLCollection** aElements) { - *aElements = mControls; + *aElements = Elements(); NS_ADDREF(*aElements); return NS_OK; } nsresult HTMLFormElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, const nsAString& aValue, bool aNotify) @@ -394,47 +412,53 @@ NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLForm NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLFormElement, Enctype, enctype, kFormDefaultEnctype->tag) NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLFormElement, Method, method, kFormDefaultMethod->tag) NS_IMPL_BOOL_ATTR(HTMLFormElement, NoValidate, novalidate) NS_IMPL_STRING_ATTR(HTMLFormElement, Name, name) NS_IMPL_STRING_ATTR(HTMLFormElement, Target, target) -NS_IMETHODIMP -HTMLFormElement::Submit() +void +HTMLFormElement::Submit(ErrorResult& aRv) { // Send the submit event - nsresult rv = NS_OK; nsRefPtr<nsPresContext> presContext = GetPresContext(); if (mPendingSubmission) { // aha, we have a pending submission that was not flushed // (this happens when form.submit() is called twice) // we have to delete it and build a new one since values // might have changed inbetween (we emulate IE here, that's all) mPendingSubmission = nullptr; } - rv = DoSubmitOrReset(nullptr, NS_FORM_SUBMIT); - return rv; + aRv = DoSubmitOrReset(nullptr, NS_FORM_SUBMIT); +} + +NS_IMETHODIMP +HTMLFormElement::Submit() +{ + ErrorResult rv; + Submit(rv); + return rv.ErrorCode(); } NS_IMETHODIMP HTMLFormElement::Reset() { nsFormEvent event(true, NS_FORM_RESET); nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this), nullptr, &event); return NS_OK; } NS_IMETHODIMP HTMLFormElement::CheckValidity(bool* retVal) { - *retVal = CheckFormValidity(nullptr); + *retVal = CheckValidity(); return NS_OK; } bool HTMLFormElement::ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute, const nsAString& aValue, nsAttrValue& aResult) @@ -1077,16 +1101,24 @@ HTMLFormElement::WalkFormElements(nsForm NS_IMETHODIMP_(uint32_t) HTMLFormElement::GetElementCount() const { uint32_t count = 0; mControls->GetLength(&count); return count; } +Element* +HTMLFormElement::IndexedGetter(uint32_t aIndex, bool &aFound) +{ + Element* element = mControls->mElements.SafeElementAt(aIndex, nullptr); + aFound = element != nullptr; + return element; +} + NS_IMETHODIMP_(nsIFormControl*) HTMLFormElement::GetElementAt(int32_t aIndex) const { return mControls->mElements.SafeElementAt(aIndex, nullptr); } /** * Compares the position of aControl1 and aControl2 in the document @@ -1429,30 +1461,31 @@ HTMLFormElement::HandleDefaultSubmitRemo "What happened here?"); // Notify about change if needed. if (mDefaultSubmitElement) { mDefaultSubmitElement->UpdateState(true); } } -static nsresult -RemoveElementFromTableInternal( +nsresult +HTMLFormElement::RemoveElementFromTableInternal( nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable, nsIContent* aChild, const nsAString& aName) { nsCOMPtr<nsISupports> supports; if (!aTable.Get(aName, getter_AddRefs(supports))) return NS_OK; // Single element in the hash, just remove it if it's the one // we're trying to remove... if (supports == aChild) { aTable.Remove(aName); + ++mExpandoAndGeneration.generation; return NS_OK; } nsCOMPtr<nsIContent> content(do_QueryInterface(supports)); if (content) { return NS_OK; } @@ -1466,16 +1499,17 @@ RemoveElementFromTableInternal( uint32_t length = 0; list->GetLength(&length); if (!length) { // If the list is empty we remove if from our hash, this shouldn't // happen tho aTable.Remove(aName); + ++mExpandoAndGeneration.generation; } else if (length == 1) { // Only one element left, replace the list in the hash with the // single element. nsIContent* node = list->Item(0); if (node) { aTable.Put(aName, node); } } @@ -1494,42 +1528,66 @@ RemovePastNames(const nsAString& aName, nsresult HTMLFormElement::RemoveElementFromTable(nsGenericHTMLFormElement* aElement, const nsAString& aName, RemoveElementReason aRemoveReason) { // If the element is being removed from the form, we have to remove it from // the past names map. if (aRemoveReason == ElementRemoved) { + uint32_t oldCount = mPastNameLookupTable.Count(); mPastNameLookupTable.Enumerate(RemovePastNames, aElement); + if (oldCount != mPastNameLookupTable.Count()) { + ++mExpandoAndGeneration.generation; + } } return mControls->RemoveElementFromTable(aElement, aName); } already_AddRefed<nsISupports> +HTMLFormElement::NamedGetter(const nsAString& aName, bool &aFound) +{ + aFound = true; + + nsCOMPtr<nsISupports> result = DoResolveName(aName, true); + if (result) { + AddToPastNamesMap(aName, result); + return result.forget(); + } + + result = mImageNameLookupTable.GetWeak(aName); + if (result) { + AddToPastNamesMap(aName, result); + return result.forget(); + } + + result = mPastNameLookupTable.GetWeak(aName); + if (result) { + return result.forget(); + } + + aFound = false; + return nullptr; +} + +void +HTMLFormElement::GetSupportedNames(nsTArray<nsString >& aRetval) +{ + // TODO https://www.w3.org/Bugs/Public/show_bug.cgi?id=22320 +} + +already_AddRefed<nsISupports> HTMLFormElement::FindNamedItem(const nsAString& aName, nsWrapperCache** aCache) { - nsCOMPtr<nsISupports> result = DoResolveName(aName, true); - if (result) { - // FIXME Get the wrapper cache from DoResolveName. - *aCache = nullptr; - AddToPastNamesMap(aName, result); - return result.forget(); - } - - result = mImageNameLookupTable.GetWeak(aName); - if (result) { - *aCache = nullptr; - AddToPastNamesMap(aName, result); - return result.forget(); - } - - result = mPastNameLookupTable.GetWeak(aName); + // FIXME Get the wrapper cache from DoResolveName. + + bool found; + nsCOMPtr<nsISupports> result = NamedGetter(aName, found); if (result) { *aCache = nullptr; return result.forget(); } return nullptr; } @@ -1760,23 +1818,27 @@ HTMLFormElement::GetEncoding(nsAString& } NS_IMETHODIMP HTMLFormElement::SetEncoding(const nsAString& aEncoding) { return SetEnctype(aEncoding); } +int32_t +HTMLFormElement::Length() +{ + return mControls->Length(); +} + NS_IMETHODIMP HTMLFormElement::GetLength(int32_t* aLength) { - uint32_t length; - nsresult rv = mControls->GetLength(&length); - *aLength = length; - return rv; + *aLength = Length(); + return NS_OK; } void HTMLFormElement::ForgetCurrentSubmission() { mNotifiedObservers = false; mIsSubmitting = false; mSubmittingRequest = nullptr; @@ -2451,43 +2513,44 @@ nsFormControlList::NamedItemInternal(con { if (aFlushContent) { FlushPendingNotifications(); } return mNameLookupTable.GetWeak(aName); } -static nsresult -AddElementToTableInternal( +nsresult +HTMLFormElement::AddElementToTableInternal( nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable, - nsIContent* aChild, const nsAString& aName, HTMLFormElement* aForm) + nsIContent* aChild, const nsAString& aName) { nsCOMPtr<nsISupports> supports; aTable.Get(aName, getter_AddRefs(supports)); if (!supports) { // No entry found, add the element aTable.Put(aName, aChild); + ++mExpandoAndGeneration.generation; } else { // Found something in the hash, check its type nsCOMPtr<nsIContent> content = do_QueryInterface(supports); if (content) { // Check if the new content is the same as the one we found in the // hash, if it is then we leave it in the hash as it is, this will // happen if a form control has both a name and an id with the same // value if (content == aChild) { return NS_OK; } // Found an element, create a list, add the element to the list and put // the list in the hash - nsSimpleContentList *list = new nsSimpleContentList(aForm); + nsSimpleContentList *list = new nsSimpleContentList(this); // If an element has a @form, we can assume it *might* be able to not have // a parent and still be in the form. NS_ASSERTION(content->HasAttr(kNameSpaceID_None, nsGkAtoms::form) || content->GetParent(), "Item in list without parent"); // Determine the ordering between the new and old element. bool newFirst = nsContentUtils::PositionIsBefore(aChild, content); @@ -2553,17 +2616,17 @@ AddElementToTableInternal( nsresult nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild, const nsAString& aName) { if (!ShouldBeInElements(aChild)) { return NS_OK; } - return AddElementToTableInternal(mNameLookupTable, aChild, aName, mForm); + return mForm->AddElementToTableInternal(mNameLookupTable, aChild, aName); } nsresult nsFormControlList::IndexOfControl(nsIFormControl* aControl, int32_t* aIndex) { // Note -- not a DOM method; callers should handle flushing themselves @@ -2577,17 +2640,17 @@ nsFormControlList::IndexOfControl(nsIFor nsresult nsFormControlList::RemoveElementFromTable(nsGenericHTMLFormElement* aChild, const nsAString& aName) { if (!ShouldBeInElements(aChild)) { return NS_OK; } - return RemoveElementFromTableInternal(mNameLookupTable, aChild, aName); + return mForm->RemoveElementFromTableInternal(mNameLookupTable, aChild, aName); } nsresult nsFormControlList::GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const { #ifdef DEBUG AssertDocumentOrder(mElements, mForm); AssertDocumentOrder(mNotInElements, mForm); @@ -2713,17 +2776,17 @@ HTMLFormElement::AddImageElement(HTMLIma AddElementToList(mImageElements, aChild, this); return NS_OK; } nsresult HTMLFormElement::AddImageElementToTable(HTMLImageElement* aChild, const nsAString& aName) { - return AddElementToTableInternal(mImageNameLookupTable, aChild, aName, this); + return AddElementToTableInternal(mImageNameLookupTable, aChild, aName); } nsresult HTMLFormElement::RemoveImageElement(HTMLImageElement* aChild) { uint32_t index = mImageElements.IndexOf(aChild); NS_ENSURE_STATE(index != mImageElements.NoIndex); @@ -2753,10 +2816,16 @@ HTMLFormElement::AddToPastNamesMap(const // node in candidates in the form element's past names map, replacing the // previous entry with the same name, if any. nsCOMPtr<nsIContent> node = do_QueryInterface(aChild); if (node) { mPastNameLookupTable.Put(aName, aChild); } } +JSObject* +HTMLFormElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope) +{ + return HTMLFormElementBinding::Wrap(aCx, aScope, this); +} + } // namespace dom } // namespace mozilla
--- a/content/html/content/src/HTMLFormElement.h +++ b/content/html/content/src/HTMLFormElement.h @@ -43,16 +43,18 @@ namespace dom { class nsFormControlList; class HTMLFormElement : public nsGenericHTMLElement, public nsIDOMHTMLFormElement, public nsIWebProgressListener, public nsIForm, public nsIRadioGroupContainer { + friend class nsFormControlList; + public: HTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo); virtual ~HTMLFormElement(); nsresult Init(); // nsISupports NS_DECL_ISUPPORTS_INHERITED @@ -126,18 +128,18 @@ public: /** * Forget all information about the current submission (and the fact that we * are currently submitting at all). */ void ForgetCurrentSubmission(); virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLFormElement, - nsGenericHTMLElement) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(HTMLFormElement, + nsGenericHTMLElement) /** * Remove an element from this form's list of elements * * @param aElement the element to remove * @param aUpdateValidity If true, updates the form validity. * @return NS_OK if the element was successfully removed. */ @@ -310,17 +312,117 @@ public: /** * Implements form[name]. Returns form controls in this form with the correct * value of the name attribute. */ already_AddRefed<nsISupports> FindNamedItem(const nsAString& aName, nsWrapperCache** aCache); + // WebIDL + + void GetAcceptCharset(DOMString& aValue) + { + GetHTMLAttr(nsGkAtoms::acceptcharset, aValue); + } + + void SetAcceptCharset(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::acceptcharset, aValue, aRv); + } + + // XPCOM GetAction() is OK + void SetAction(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::action, aValue, aRv); + } + + // XPCOM GetAutocomplete() is OK + void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv); + } + + // XPCOM GetEnctype() is OK + void SetEnctype(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::enctype, aValue, aRv); + } + + // XPCOM GetEncoding() is OK + void SetEncoding(const nsAString& aValue, ErrorResult& aRv) + { + SetEnctype(aValue, aRv); + } + + // XPCOM GetMethod() is OK + void SetMethod(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::method, aValue, aRv); + } + + void GetName(DOMString& aValue) + { + GetHTMLAttr(nsGkAtoms::name, aValue); + } + + void SetName(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::name, aValue, aRv); + } + + bool NoValidate() const + { + return GetBoolAttr(nsGkAtoms::novalidate); + } + + void SetNoValidate(bool aValue, ErrorResult& aRv) + { + SetHTMLBoolAttr(nsGkAtoms::novalidate, aValue, aRv); + } + + void GetTarget(DOMString& aValue) + { + GetHTMLAttr(nsGkAtoms::target, aValue); + } + + void SetTarget(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::target, aValue, aRv); + } + + // it's only out-of-line because the class definition is not available in the + // header + nsIHTMLCollection* Elements(); + + int32_t Length(); + + void Submit(ErrorResult& aRv); + + // XPCOM Reset() is OK + + bool CheckValidity() + { + return CheckFormValidity(nullptr); + } + + Element* + IndexedGetter(uint32_t aIndex, bool &aFound); + + already_AddRefed<nsISupports> + NamedGetter(const nsAString& aName, bool &aFound); + + void GetSupportedNames(nsTArray<nsString >& aRetval); + + js::ExpandoAndGeneration mExpandoAndGeneration; + protected: + virtual JSObject* WrapNode(JSContext* aCx, + JS::Handle<JSObject*> aScope) MOZ_OVERRIDE; + void PostPasswordEvent(); void EventHandled() { mFormPasswordEvent = nullptr; } class FormPasswordEvent : public nsAsyncDOMEvent { public: FormPasswordEvent(HTMLFormElement* aEventNode, const nsAString& aEventType) @@ -361,31 +463,31 @@ protected: // Async callback to handle removal of our default submit void HandleDefaultSubmitRemoval(); // // Submit Helpers // // /** - * Attempt to submit (submission might be deferred) + * Attempt to submit (submission might be deferred) * (called by DoSubmitOrReset) * * @param aPresContext the presentation context * @param aEvent the DOM event that was passed to us for the submit */ nsresult DoSubmit(nsEvent* aEvent); /** * Prepare the submission object (called by DoSubmit) * * @param aFormSubmission the submission object * @param aEvent the DOM event that was passed to us for the submit */ - nsresult BuildSubmission(nsFormSubmission** aFormSubmission, + nsresult BuildSubmission(nsFormSubmission** aFormSubmission, nsEvent* aEvent); /** * Perform the submission (called by DoSubmit and FlushPendingSubmission) * * @param aFormSubmission the submission object */ nsresult SubmitSubmission(nsFormSubmission* aFormSubmission); @@ -425,16 +527,26 @@ protected: bool CheckFormValidity(nsIMutableArray* aInvalidElements) const; // Clear the mImageNameLookupTable and mImageElements. void Clear(); // Insert a element into the past names map. void AddToPastNamesMap(const nsAString& aName, nsISupports* aChild); + nsresult + AddElementToTableInternal( + nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable, + nsIContent* aChild, const nsAString& aName); + + nsresult + RemoveElementFromTableInternal( + nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable, + nsIContent* aChild, const nsAString& aName); + public: /** * Flush a possible pending submission. If there was a scripted submission * triggered by a button or image, the submission was defered. This method * forces the pending submission to be submitted. (happens when the handler * returns false or there is an action/target change in the script) */ void FlushPendingSubmission();
--- a/content/html/content/test/reflect.js +++ b/content/html/content/test/reflect.js @@ -53,40 +53,28 @@ function reflectString(aParameters) element.setAttribute(contentAttr, null); is(element.getAttribute(contentAttr), "null", "null should have been stringified to 'null' for '" + contentAttr + "'"); is(element[idlAttr], "null", "null should have been stringified to 'null' for '" + idlAttr + "'"); element.removeAttribute(contentAttr); element[idlAttr] = null; - // TODO: remove this ugly hack when null stringification will work as expected. - var todoAttrs = { - form: [ "acceptCharset", "name", "target" ], - }; - if (!(element.localName in todoAttrs) || todoAttrs[element.localName].indexOf(idlAttr) == -1) { - if (treatNullAs == "EmptyString") { - is(element.getAttribute(contentAttr), "", - "null should have been stringified to '' for '" + contentAttr + "'"); - is(element[idlAttr], "", - "null should have been stringified to '' for '" + idlAttr + "'"); - } else { - is(element.getAttribute(contentAttr), "null", - "null should have been stringified to 'null' for '" + contentAttr + "'"); - is(element[idlAttr], "null", - "null should have been stringified to 'null' for '" + contentAttr + "'"); - } - element.removeAttribute(contentAttr); + if (treatNullAs == "EmptyString") { + is(element.getAttribute(contentAttr), "", + "null should have been stringified to '' for '" + contentAttr + "'"); + is(element[idlAttr], "", + "null should have been stringified to '' for '" + idlAttr + "'"); } else { - todo_is(element.getAttribute(contentAttr), "null", + is(element.getAttribute(contentAttr), "null", "null should have been stringified to 'null' for '" + contentAttr + "'"); - todo_is(element[idlAttr], "null", + is(element[idlAttr], "null", "null should have been stringified to 'null' for '" + contentAttr + "'"); - element.removeAttribute(contentAttr); } + element.removeAttribute(contentAttr); // Tests various strings. var stringsToTest = [ // [ test value, expected result ] [ "", "" ], [ "null", "null" ], [ "undefined", "undefined" ], [ "foo", "foo" ],
--- a/content/html/content/test/test_bug879319.html +++ b/content/html/content/test/test_bug879319.html @@ -47,19 +47,19 @@ ok("tmp1" in form.elements, "tmp1 is in ok(!("tmp0" in form.elements), "tmp0 is not in form.elements"); ok(!("foo0" in form.elements), "foo0 is not in form.elements"); is(form.tmp0, input0, "Form.tmp0 == input0"); is(form.tmp1, input0, "Form.tmp1 == input0"); is(form.foo0, input0, "Form.foo0 is still here"); input0.setAttribute("form", ""); ok(!("foo0" in form.elements), "foo0 is not in form.elements"); -todo_is(form.foo0, undefined, "Form.foo0 should not still be here"); -todo_is(form.tmp0, undefined, "Form.tmp0 should not still be here"); -todo_is(form.tmp1, undefined, "Form.tmp1 should not still be here"); +is(form.foo0, undefined, "Form.foo0 should not still be here"); +is(form.tmp0, undefined, "Form.tmp0 should not still be here"); +is(form.tmp1, undefined, "Form.tmp1 should not still be here"); var input1 = document.getElementById("input1"); ok(input1, "input1 exists"); is(form.foo1, input1, "Form.foo1 should exist"); ok("foo1" in form.elements, "foo1 in form.elements"); is(input1.form, form, "input1.form is form"); @@ -68,24 +68,25 @@ ok("foo0" in form.elements, "foo0 is in is(form.foo0, input1, "Form.foo0 should be input1"); is(form.foo1, input1, "Form.foo1 should be input1"); var input2 = document.getElementById("input2"); ok(input2, "input2 exists"); is(form.foo2, input2, "Form.foo2 should exist"); input2.parentNode.removeChild(input2); ok(!("foo2" in form.elements), "foo2 is not in form.elements"); -todo_is(form.foo2, undefined, "Form.foo2 should not longer be there"); +is(form.foo2, undefined, "Form.foo2 should not longer be there"); var img0 = document.getElementById("img0"); ok(img0, "img0 exists"); is(form.bar0, img0, "Form.bar0 should exist"); img0.setAttribute("name", "old_bar0"); +is(form.old_bar0, img0, "Form.bar0 is still here"); is(form.bar0, img0, "Form.bar0 is still here"); img0.parentNode.removeChild(img0); -todo_is(form.bar0, undefined, "Form.bar0 should not be here"); +is(form.bar0, undefined, "Form.bar0 should not be here"); </script> </pre> </body> </html>
--- a/dom/bindings/BindingDeclarations.h +++ b/dom/bindings/BindingDeclarations.h @@ -423,16 +423,82 @@ private: // Forbid copy-construction and assignment Optional(const Optional& other) MOZ_DELETE; const Optional &operator=(const Optional &other) MOZ_DELETE; bool mPassed; const nsAString* mStr; }; +template<class T> +class NonNull +{ +public: + NonNull() +#ifdef DEBUG + : inited(false) +#endif + {} + + operator T&() { + MOZ_ASSERT(inited); + MOZ_ASSERT(ptr, "NonNull<T> was set to null"); + return *ptr; + } + + operator const T&() const { + MOZ_ASSERT(inited); + MOZ_ASSERT(ptr, "NonNull<T> was set to null"); + return *ptr; + } + + void operator=(T* t) { + ptr = t; + MOZ_ASSERT(ptr); +#ifdef DEBUG + inited = true; +#endif + } + + template<typename U> + void operator=(U* t) { + ptr = t->ToAStringPtr(); + MOZ_ASSERT(ptr); +#ifdef DEBUG + inited = true; +#endif + } + + T** Slot() { +#ifdef DEBUG + inited = true; +#endif + return &ptr; + } + + T* Ptr() { + MOZ_ASSERT(inited); + MOZ_ASSERT(ptr, "NonNull<T> was set to null"); + return ptr; + } + + // Make us work with smart-ptr helpers that expect a get() + T* get() const { + MOZ_ASSERT(inited); + MOZ_ASSERT(ptr); + return ptr; + } + +protected: + T* ptr; +#ifdef DEBUG + bool inited; +#endif +}; + // Class for representing sequences in arguments. We use a non-auto array // because that allows us to use sequences of sequences and the like. This // needs to be fallible because web content controls the length of the array, // and can easily try to create very large lengths. template<typename T> class Sequence : public FallibleTArray<T> { public:
--- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -1346,75 +1346,16 @@ GetPropertyOnPrototype(JSContext* cx, JS JS::Value* vp); bool HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy, DOMProxyHandler* handler, JS::Handle<jsid> id); template<class T> -class NonNull -{ -public: - NonNull() -#ifdef DEBUG - : inited(false) -#endif - {} - - operator T&() { - MOZ_ASSERT(inited); - MOZ_ASSERT(ptr, "NonNull<T> was set to null"); - return *ptr; - } - - operator const T&() const { - MOZ_ASSERT(inited); - MOZ_ASSERT(ptr, "NonNull<T> was set to null"); - return *ptr; - } - - void operator=(T* t) { - ptr = t; - MOZ_ASSERT(ptr); -#ifdef DEBUG - inited = true; -#endif - } - - template<typename U> - void operator=(U* t) { - ptr = t->ToAStringPtr(); - MOZ_ASSERT(ptr); -#ifdef DEBUG - inited = true; -#endif - } - - T* Ptr() { - MOZ_ASSERT(inited); - MOZ_ASSERT(ptr, "NonNull<T> was set to null"); - return ptr; - } - - // Make us work with smart-ptr helpers that expect a get() - T* get() const { - MOZ_ASSERT(inited); - MOZ_ASSERT(ptr); - return ptr; - } - -protected: - T* ptr; -#ifdef DEBUG - bool inited; -#endif -}; - -template<class T> class OwningNonNull { public: OwningNonNull() #ifdef DEBUG : inited(false) #endif {}
--- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -1615,17 +1615,16 @@ addExternalIface('DeviceRotationRate', h addExternalIface('mozIDOMApplication', nativeType='mozIDOMApplication', headerFile='nsIDOMApplicationRegistry.h') addExternalIface('CSSRuleList') addExternalIface('DOMStringList') addExternalIface('RTCDataChannel', nativeType='nsIDOMDataChannel') addExternalIface('File') addExternalIface('FileCallback', nativeType='nsIFileCallback', headerFile='nsIDOMHTMLCanvasElement.h') addExternalIface('HitRegionOptions', nativeType='nsISupports') -addExternalIface('HTMLFormElement', nativeType='mozilla::dom::HTMLFormElement') addExternalIface('IDBOpenDBRequest', nativeType='nsIIDBOpenDBRequest') addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver') addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True) addExternalIface('LockedFile') addExternalIface('MediaList') addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True) addExternalIface('MozBoxObject', nativeType='nsIBoxObject') addExternalIface('MozControllers', nativeType='nsIControllers')
--- a/dom/webidl/FormData.webidl +++ b/dom/webidl/FormData.webidl @@ -2,15 +2,13 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is * http://xhr.spec.whatwg.org */ -interface HTMLFormElement; - [Constructor(optional HTMLFormElement form)] interface FormData { void append(DOMString name, Blob value, optional DOMString filename); void append(DOMString name, DOMString value); -}; \ No newline at end of file +};
new file mode 100644 --- /dev/null +++ b/dom/webidl/HTMLFormElement.webidl @@ -0,0 +1,48 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * http://www.whatwg.org/specs/web-apps/current-work/#htmlformelement + * + * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and + * Opera Software ASA. You are granted a license to use, reproduce + * and create derivative works of this document. + */ + +[OverrideBuiltins] +interface HTMLFormElement : HTMLElement { + [Pure, SetterThrows] + attribute DOMString acceptCharset; + [Pure, SetterThrows] + attribute DOMString action; + [Pure, SetterThrows] + attribute DOMString autocomplete; + [Pure, SetterThrows] + attribute DOMString enctype; + [Pure, SetterThrows] + attribute DOMString encoding; + [Pure, SetterThrows] + attribute DOMString method; + [Pure, SetterThrows] + attribute DOMString name; + [Pure, SetterThrows] + attribute boolean noValidate; + [Pure, SetterThrows] + attribute DOMString target; + + [Constant] + readonly attribute HTMLCollection elements; + [Pure] + readonly attribute long length; + + getter Element (unsigned long index); + // TODO this should be: getter (RadioNodeList or HTMLInputElement or HTMLImageElement) (DOMString name); + getter nsISupports (DOMString name); + + [Throws] + void submit(); + void reset(); + boolean checkValidity(); +};
--- a/dom/webidl/WebIDL.mk +++ b/dom/webidl/WebIDL.mk @@ -104,16 +104,17 @@ webidl_files = \ HTMLDirectoryElement.webidl \ HTMLDivElement.webidl \ HTMLDListElement.webidl \ HTMLDocument.webidl \ HTMLElement.webidl \ HTMLEmbedElement.webidl \ HTMLFieldSetElement.webidl \ HTMLFontElement.webidl \ + HTMLFormElement.webidl \ HTMLFrameElement.webidl \ HTMLFrameSetElement.webidl \ HTMLHeadElement.webidl \ HTMLHeadingElement.webidl \ HTMLHRElement.webidl \ HTMLHtmlElement.webidl \ HTMLIFrameElement.webidl \ HTMLImageElement.webidl \
--- a/js/xpconnect/src/dom_quickstubs.qsconf +++ b/js/xpconnect/src/dom_quickstubs.qsconf @@ -55,24 +55,16 @@ members = [ 'nsIDOMProgressEvent.lengthComputable', 'nsIDOMProgressEvent.loaded', 'nsIDOMProgressEvent.total', #XXX Can't quickstub initProgressEvent because it has long long parameters. 'nsIDOMTouchList.*', - # dom/interfaces/html - 'nsIDOMHTMLFormElement.elements', - 'nsIDOMHTMLFormElement.name', - 'nsIDOMHTMLFormElement.submit', - 'nsIDOMHTMLFormElement.length', - 'nsIDOMHTMLFormElement.target', - 'nsIDOMHTMLFormElement.action', - # dom/interfaces/storage 'nsIDOMToString.toString', 'nsIDOMStorage.setItem', 'nsIDOMStorage.length', 'nsIDOMStorage.getItem', 'nsIDOMStorage.key', 'nsIDOMStorage.removeItem', 'nsIDOMStorage.clear',