diff --git a/content/base/public/nsIXMLHttpRequest.idl b/content/base/public/nsIXMLHttpRequest.idl --- a/content/base/public/nsIXMLHttpRequest.idl +++ b/content/base/public/nsIXMLHttpRequest.idl @@ -30,25 +30,40 @@ * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -#include "nsISupports.idl" +#include "nsIDOMEventTarget.idl" interface nsIChannel; interface nsIDOMDocument; interface nsIDOMEventListener; interface nsIPrincipal; interface nsIScriptContext; interface nsIVariant; interface nsPIDOMWindow; + +[scriptable, uuid(6ce0a193-b033-4c3d-b748-f851b09261f5)] +interface nsIXMLHttpRequestEventTarget : nsIDOMEventTarget { + // event handler attributes + attribute nsIDOMEventListener onabort; + attribute nsIDOMEventListener onerror; + attribute nsIDOMEventListener onload; + attribute nsIDOMEventListener onloadstart; + attribute nsIDOMEventListener onprogress; +}; + +[scriptable, uuid(09ff3682-7759-4441-a765-f70e1a1fabcf)] +interface nsIXMLHttpRequestUpload : nsIXMLHttpRequestEventTarget { + // for future use +}; /** * Mozilla's XMLHttpRequest is modelled after Microsoft's IXMLHttpRequest * object. The goal has been to make Mozilla's version match Microsoft's * version as closely as possible, but there are bound to be some differences. * * In general, Microsoft's documentation for IXMLHttpRequest can be used. * Mozilla's interface definitions provide some additional documentation. The @@ -85,17 +100,17 @@ interface nsPIDOMWindow; * Though actually, if you use addEventListener from C++ weird things will * happen too, since the result will depend on what JS happens to be on the * stack when you do it.... * * Conclusion: Do not use event listeners on XMLHttpRequest from C++, unless * you're aware of all the security implications. And then think twice about * it. */ -[scriptable, uuid(acda85ab-d06c-4176-b834-6d129ca97ca3)] +[scriptable, uuid(aaf12811-45b3-4f10-aac1-41cffa9a6b46)] interface nsIXMLHttpRequest : nsISupports { /** * The request uses a channel in order to perform the * request. This attribute represents the channel used * for the request. NULL if the channel has not yet been * created. * @@ -318,16 +333,21 @@ interface nsIXMLHttpRequest : nsISupport * null. * @param scriptContext The script context to use for the request. May be * null. * @param ownerWindow The associated window for the request. May be null. */ [noscript] void init(in nsIPrincipal principal, in nsIScriptContext scriptContext, in nsPIDOMWindow ownerWindow); + + /** + * Upload process can be tracked by adding event listener to |upload|. + */ + readonly attribute nsIXMLHttpRequestUpload upload; }; [scriptable, uuid(261676b4-d508-43bf-b099-74635a0ee2e9)] interface nsIJSXMLHttpRequest : nsISupports { /** * Meant to be a script-only mechanism for setting a load event listener. * The attribute is expected to be JavaScript function object. When * the load event occurs, the function is invoked. diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -45,17 +45,16 @@ #include "nsIURI.h" #include "nsILoadGroup.h" #include "nsNetUtil.h" #include "nsThreadUtils.h" #include "nsIUploadChannel.h" #include "nsIDOMSerializer.h" #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" -#include "nsIEventListenerManager.h" #include "nsGUIEvent.h" #include "nsIPrivateDOMEvent.h" #include "prprf.h" #include "nsIDOMEventListener.h" #include "nsIJSContextStack.h" #include "nsJSEnvironment.h" #include "nsIScriptSecurityManager.h" #include "nsWeakPtr.h" @@ -88,16 +87,18 @@ #include "nsIMultiPartChannel.h" #include "nsIScriptObjectPrincipal.h" #include "nsIStorageStream.h" #include "nsIPromptFactory.h" #include "nsIWindowWatcher.h" #define LOAD_STR "load" #define ERROR_STR "error" +#define ABORT_STR "abort" +#define LOADSTART_STR "loadstart" #define PROGRESS_STR "progress" #define UPLOADPROGRESS_STR "uploadprogress" #define READYSTATE_STR "readystatechange" // CIDs // State #define XML_HTTP_REQUEST_UNINITIALIZED (1 << 0) // 0 @@ -284,16 +285,305 @@ GetDocumentFromScriptContext(nsIScriptCo if (window) { nsCOMPtr domdoc; window->GetDocument(getter_AddRefs(domdoc)); if (domdoc) { CallQueryInterface(domdoc, &doc); } } return doc; +} + +///////////////////////////////////////////// + +NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequestUpload) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXMLHttpRequestUpload) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnAbortListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadStartListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnProgressListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListenerManager) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXMLHttpRequestUpload) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnLoadListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnAbortListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnLoadStartListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnProgressListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLHttpRequestUpload) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLHttpRequestUpload) + NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequestUpload) + NS_INTERFACE_MAP_ENTRY(nsPIDOMEventTarget) + NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) + NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget) + NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(XMLHttpRequestUpload) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsXMLHttpRequestUpload, + nsIXMLHttpRequestUpload) +NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsXMLHttpRequestUpload, + nsIXMLHttpRequestUpload) + +NS_IMETHODIMP +nsXMLHttpRequestUpload::AddEventListener(const nsAString& aType, + nsIDOMEventListener* aListener, + PRBool aUseCapture) +{ + nsCOMPtr context; + GetContextForEventHandlers(getter_AddRefs(context)); + nsCOMPtr doc = GetDocumentFromScriptContext(context); + PRBool wantsUntrusted = doc && !nsContentUtils::IsChromeDoc(doc); + return AddEventListener(aType, aListener, aUseCapture, wantsUntrusted); +} + +/* void removeEventListener (in string type, in nsIDOMEventListener + listener); */ +NS_IMETHODIMP +nsXMLHttpRequestUpload::RemoveEventListener(const nsAString& aType, + nsIDOMEventListener* aListener, + PRBool aUseCapture) +{ + nsCOMPtr elm; + GetListenerManager(PR_FALSE, getter_AddRefs(elm)); + if (elm) { + PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE; + elm->RemoveEventListenerByType(aListener, aType, flags, nsnull); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::AddEventListener(const nsAString& aType, + nsIDOMEventListener *aListener, + PRBool aUseCapture, + PRBool aWantsUntrusted) +{ + nsCOMPtr elm; + GetListenerManager(PR_TRUE, getter_AddRefs(elm)); + NS_ENSURE_STATE(elm); + PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE; + if (aWantsUntrusted) { + flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED; + } + return elm->AddEventListenerByType(aListener, aType, flags, nsnull); +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::GetScriptTypeID(PRUint32 *aLang) +{ + *aLang = mLang; + return NS_OK; +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::SetScriptTypeID(PRUint32 aLang) +{ + mLang = aLang; + return NS_OK; +} + +/* boolean dispatchEvent (in nsIDOMEvent evt); */ +NS_IMETHODIMP +nsXMLHttpRequestUpload::DispatchEvent(nsIDOMEvent* aEvent, PRBool* aRetVal) +{ + nsEventStatus status = nsEventStatus_eIgnore; + nsresult rv = + nsEventDispatcher::DispatchDOMEvent(static_cast(this), + nsnull, aEvent, nsnull, &status); + + *aRetVal = (status != nsEventStatus_eConsumeNoDefault); + return rv; +} + +nsresult +nsXMLHttpRequestUpload::RemoveAddEventListener(const nsAString& aType, + nsRefPtr& aCurrent, + nsIDOMEventListener* aNew) +{ + if (aCurrent) { + RemoveEventListener(aType, aCurrent, PR_FALSE); + aCurrent = nsnull; + } + if (aNew) { + aCurrent = new nsDOMEventListenerWrapper(aNew); + NS_ENSURE_TRUE(aCurrent, NS_ERROR_OUT_OF_MEMORY); + AddEventListener(aType, aCurrent, PR_FALSE); + } + return NS_OK; +} + +nsresult +nsXMLHttpRequestUpload::GetInnerEventListener(nsRefPtr& aWrapper, + nsIDOMEventListener** aListener) +{ + NS_ENSURE_ARG_POINTER(aListener); + if (aWrapper) { + NS_ADDREF(*aListener = aWrapper->GetInner()); + } else { + *aListener = nsnull; + } + return NS_OK; +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::GetOnload(nsIDOMEventListener** aOnLoad) +{ + return GetInnerEventListener(mOnLoadListener, aOnLoad); +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::SetOnload(nsIDOMEventListener* aOnLoad) +{ + NS_NAMED_LITERAL_STRING(ls, LOAD_STR); + return RemoveAddEventListener(ls, mOnLoadListener, aOnLoad); +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::GetOnerror(nsIDOMEventListener** aOnerror) +{ + return GetInnerEventListener(mOnErrorListener, aOnerror); +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::SetOnerror(nsIDOMEventListener* aOnerror) +{ + NS_NAMED_LITERAL_STRING(es, ERROR_STR); + return RemoveAddEventListener(es, mOnErrorListener, aOnerror); +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::GetOnabort(nsIDOMEventListener** aOnabort) +{ + return GetInnerEventListener(mOnAbortListener, aOnabort); +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::SetOnabort(nsIDOMEventListener* aOnabort) +{ + NS_NAMED_LITERAL_STRING(as, ABORT_STR); + return RemoveAddEventListener(as, mOnAbortListener, aOnabort); +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::GetOnloadstart(nsIDOMEventListener** aOnloadstart) +{ + return GetInnerEventListener(mOnLoadStartListener, aOnloadstart); +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::SetOnloadstart(nsIDOMEventListener* aOnloadstart) +{ + NS_NAMED_LITERAL_STRING(lss, LOADSTART_STR); + return RemoveAddEventListener(lss, mOnLoadStartListener, aOnloadstart); +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::GetOnprogress(nsIDOMEventListener** aOnprogress) +{ + return GetInnerEventListener(mOnProgressListener, aOnprogress); +} + +NS_IMETHODIMP +nsXMLHttpRequestUpload::SetOnprogress(nsIDOMEventListener* aOnprogress) +{ + NS_NAMED_LITERAL_STRING(ps, PROGRESS_STR); + return RemoveAddEventListener(ps, mOnProgressListener, aOnprogress); +} + +nsresult +nsXMLHttpRequestUpload::PreHandleEvent(nsEventChainPreVisitor& aVisitor) +{ + aVisitor.mCanHandle = PR_TRUE; + aVisitor.mParentTarget = nsnull; + return NS_OK; +} + +nsresult +nsXMLHttpRequestUpload::PostHandleEvent(nsEventChainPostVisitor& aVisitor) +{ + return NS_OK; +} + +nsresult +nsXMLHttpRequestUpload::DispatchDOMEvent(nsEvent* aEvent, nsIDOMEvent* aDOMEvent, + nsPresContext* aPresContext, + nsEventStatus* aEventStatus) +{ + return + nsEventDispatcher::DispatchDOMEvent(static_cast(this), + aEvent, aDOMEvent, aPresContext, + aEventStatus); +} + +nsresult +nsXMLHttpRequestUpload::GetListenerManager(PRBool aCreateIfNotFound, + nsIEventListenerManager** aResult) +{ + if (!mListenerManager) { + if (!aCreateIfNotFound) { + *aResult = nsnull; + return NS_OK; + } + nsresult rv = NS_NewEventListenerManager(getter_AddRefs(mListenerManager)); + NS_ENSURE_SUCCESS(rv, rv); + mListenerManager->SetListenerTarget(static_cast(this)); + } + + NS_ADDREF(*aResult = mListenerManager); + return NS_OK; +} + +nsresult +nsXMLHttpRequestUpload::AddEventListenerByIID(nsIDOMEventListener *aListener, + const nsIID& aIID) +{ + nsCOMPtr elm; + GetListenerManager(PR_TRUE, getter_AddRefs(elm)); + if (elm) { + elm->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE); + } + return NS_OK; +} + +nsresult +nsXMLHttpRequestUpload::RemoveEventListenerByIID(nsIDOMEventListener *aListener, + const nsIID& aIID) +{ + nsCOMPtr elm; + GetListenerManager(PR_FALSE, getter_AddRefs(elm)); + if (elm) { + return elm->RemoveEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE); + } + return NS_OK; +} + +nsresult +nsXMLHttpRequestUpload::GetSystemEventGroup(nsIDOMEventGroup** aGroup) +{ + nsCOMPtr elm; + nsresult rv = GetListenerManager(PR_TRUE, getter_AddRefs(elm)); + if (elm) { + return elm->GetSystemEventGroupLM(aGroup); + } + return rv; +} + +nsresult +nsXMLHttpRequestUpload::GetContextForEventHandlers(nsIScriptContext** aContext) +{ + return mOwner->GetContextForEventHandlers(aContext); } ///////////////////////////////////////////// // // ///////////////////////////////////////////// nsXMLHttpRequest::nsXMLHttpRequest() @@ -429,16 +719,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN( NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListenerManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXMLParserStreamListener) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannelEventSink) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mProgressEventSink) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner) + + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mUpload, + nsIXMLHttpRequestUpload) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXMLHttpRequest) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannel) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReadRequest) @@ -451,16 +744,18 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mXMLParserStreamListener) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannelEventSink) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mProgressEventSink) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner) + + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mUpload) NS_IMPL_CYCLE_COLLECTION_UNLINK_END // QueryInterface implementation for nsXMLHttpRequest NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLHttpRequest) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLHttpRequest) NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequest) NS_INTERFACE_MAP_ENTRY(nsIJSXMLHttpRequest) @@ -992,20 +1287,16 @@ nsXMLHttpRequest::CreateEvent(const nsAS if (!privevent) { NS_IF_RELEASE(*aDOMEvent); return NS_ERROR_FAILURE; } if (!aType.IsEmpty()) { (*aDOMEvent)->InitEvent(aType, PR_FALSE, PR_FALSE); } - - privevent->SetTarget(this); - privevent->SetCurrentTarget(this); - privevent->SetOriginalTarget(this); // We assume anyone who managed to call CreateEvent is trusted privevent->SetTrusted(PR_TRUE); return NS_OK; } already_AddRefed @@ -1148,19 +1439,20 @@ nsXMLHttpRequest::OpenRequest(const nsAC nsCOMPtr loadGroup; GetLoadGroup(getter_AddRefs(loadGroup)); // nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active, which // in turn keeps STOP button from becoming active. If the consumer passed in // a progress event handler we must load with nsIRequest::LOAD_NORMAL or // necko won't generate any progress notifications nsLoadFlags loadFlags; - if (mListenerManager && + if ((mListenerManager && (mListenerManager->HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR)) || - mListenerManager->HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR)))) { + mListenerManager->HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR)))) || + (mUpload && mUpload->HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR)))) { loadFlags = nsIRequest::LOAD_NORMAL; } else { loadFlags = nsIRequest::LOAD_BACKGROUND; } rv = NS_NewChannel(getter_AddRefs(mChannel), uri, nsnull, loadGroup, nsnull, loadFlags); if (NS_FAILED(rv)) return rv; @@ -2188,29 +2480,32 @@ nsXMLHttpRequest::OnChannelRedirect(nsIC // NS_IMETHODIMP nsXMLHttpRequest::OnProgress(nsIRequest *aRequest, nsISupports *aContext, PRUint64 aProgress, PRUint64 aProgressMax) { // We're uploading if our state is XML_HTTP_REQUEST_OPENED or // XML_HTTP_REQUEST_SENT nsCOMPtr event; - nsresult rv = CreateEvent(((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState) - ? NS_LITERAL_STRING(UPLOADPROGRESS_STR) - : NS_LITERAL_STRING(PROGRESS_STR), + PRBool upload = !!((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState) + nsresult rv = CreateEvent(upload ? NS_LITERAL_STRING(UPLOADPROGRESS_STR) + : NS_LITERAL_STRING(PROGRESS_STR), getter_AddRefs(event)); NS_ENSURE_SUCCESS(rv, rv); nsRefPtr progressEvent = new nsXMLHttpProgressEvent(event, aProgress, aProgressMax); if (!progressEvent) return NS_ERROR_OUT_OF_MEMORY; event = progressEvent; DispatchDOMEvent(nsnull, event, nsnull, nsnull); + if (upload && mUpload) { + nsCOMPtr + } if (mProgressEventSink) { mProgressEventSink->OnProgress(aRequest, aContext, aProgress, aProgressMax); } return NS_OK; } @@ -2372,16 +2667,28 @@ nsXMLHttpRequest::GetSystemEventGroup(ns nsresult nsXMLHttpRequest::GetContextForEventHandlers(nsIScriptContext** aContext) { NS_IF_ADDREF(*aContext = mScriptContext); return NS_OK; } +NS_IMETHODIMP +nsXMLHttpRequest::GetUpload(nsIXMLHttpRequestUpload** aUpload) +{ + *aUpload = nsnull; + if (!mUpload) { + mUpload = new nsXMLHttpRequestUpload(this); + NS_ENSURE_TRUE(mUpload, NS_ERROR_OUT_OF_MEMORY); + } + NS_ADDREF(*aUpload = mUpload.get()); + return NS_OK; +} + NS_IMPL_ISUPPORTS1(nsXMLHttpRequest::nsHeaderVisitor, nsIHttpHeaderVisitor) NS_IMETHODIMP nsXMLHttpRequest:: nsHeaderVisitor::VisitHeader(const nsACString &header, const nsACString &value) { mHeaders.Append(header); mHeaders.Append(": "); mHeaders.Append(value); diff --git a/content/base/src/nsXMLHttpRequest.h b/content/base/src/nsXMLHttpRequest.h --- a/content/base/src/nsXMLHttpRequest.h +++ b/content/base/src/nsXMLHttpRequest.h @@ -63,16 +63,17 @@ #include "nsCycleCollectionParticipant.h" #include "nsIJSNativeInitializer.h" #include "nsPIDOMWindow.h" #include "nsIDOMLSProgressEvent.h" #include "nsClassHashtable.h" #include "nsHashKeys.h" #include "prclist.h" #include "prtime.h" +#include "nsIEventListenerManager.h" class nsILoadGroup; class nsDOMEventListenerWrapper : public nsIDOMEventListener { public: nsDOMEventListenerWrapper(nsIDOMEventListener* aListener) : mListener(aListener) {} @@ -80,16 +81,66 @@ public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMEventListenerWrapper) NS_DECL_NSIDOMEVENTLISTENER nsIDOMEventListener* GetInner() { return mListener; } protected: nsCOMPtr mListener; +}; + +class nsXMLHttpRequestUpload : public nsIXMLHttpRequestUpload, + public nsIDOMNSEventTarget, + public nsPIDOMEventTarget +{ +public: + nsXMLHttpRequestUpload(nsPIDOMEventTarget* aOwner) : + mOwner(aOwner), mLang(nsIProgrammingLanguage::JAVASCRIPT) {} + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXMLHttpRequestUpload, + nsIXMLHttpRequestUpload) + NS_DECL_NSIXMLHTTPREQUESTEVENTTARGET + NS_DECL_NSIXMLHTTPREQUESTUPLOAD + NS_DECL_NSIDOMEVENTTARGET + NS_DECL_NSIDOMNSEVENTTARGET + // nsPIDOMEventTarget + virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor); + virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor); + virtual nsresult DispatchDOMEvent(nsEvent* aEvent, nsIDOMEvent* aDOMEvent, + nsPresContext* aPresContext, + nsEventStatus* aEventStatus); + virtual nsresult GetListenerManager(PRBool aCreateIfNotFound, + nsIEventListenerManager** aResult); + virtual nsresult AddEventListenerByIID(nsIDOMEventListener *aListener, + const nsIID& aIID); + virtual nsresult RemoveEventListenerByIID(nsIDOMEventListener *aListener, + const nsIID& aIID); + virtual nsresult GetSystemEventGroup(nsIDOMEventGroup** aGroup); + virtual nsresult GetContextForEventHandlers(nsIScriptContext** aContext); + + PRBool HasListenersFor(const nsAString& aType) + { + return mListenerManager && mListenerManager->HasListenersFor(aType); + } +protected: + nsresult RemoveAddEventListener(const nsAString& aType, + nsRefPtr& aCurrent, + nsIDOMEventListener* aNew); + + nsresult GetInnerEventListener(nsRefPtr& aWrapper, + nsIDOMEventListener** aListener); + nsCOMPtr mOwner; + nsRefPtr mOnLoadListener; + nsRefPtr mOnErrorListener; + nsRefPtr mOnAbortListener; + nsRefPtr mOnLoadStartListener; + nsRefPtr mOnProgressListener; + nsCOMPtr mListenerManager; + PRUint32 mLang; }; class nsXMLHttpRequest : public nsIXMLHttpRequest, public nsIJSXMLHttpRequest, public nsIDOMLoadListener, public nsIDOMEventTarget, public nsIDOMNSEventTarget, public nsPIDOMEventTarget, @@ -269,18 +320,20 @@ protected: nsCOMPtr mChannelEventSink; nsCOMPtr mProgressEventSink; PRUint32 mState; // List of potentially dangerous headers explicitly set using // SetRequestHeader. nsTArray mExtraRequestHeaders; + + nsRefPtr mUpload; }; - + // helper class to expose a progress DOM Event class nsXMLHttpProgressEvent : public nsIDOMLSProgressEvent { public: nsXMLHttpProgressEvent(nsIDOMEvent * aInner, PRUint64 aCurrentProgress, PRUint64 aMaxProgress); virtual ~nsXMLHttpProgressEvent(); diff --git a/content/events/public/nsIPrivateDOMEvent.h b/content/events/public/nsIPrivateDOMEvent.h --- a/content/events/public/nsIPrivateDOMEvent.h +++ b/content/events/public/nsIPrivateDOMEvent.h @@ -99,10 +99,11 @@ NS_NewDOMSVGZoomEvent(nsIDOMEvent** aRes NS_NewDOMSVGZoomEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsGUIEvent* aEvent); #endif // MOZ_SVG nsresult NS_NewDOMXULCommandEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsXULCommandEvent* aEvent); nsresult NS_NewDOMCommandEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsCommandEvent* aEvent); nsresult NS_NewDOMMessageEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent); - +nsresult +NS_NewDOMProgressEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent); #endif // nsIPrivateDOMEvent_h__ diff --git a/content/events/src/Makefile.in b/content/events/src/Makefile.in --- a/content/events/src/Makefile.in +++ b/content/events/src/Makefile.in @@ -77,16 +77,17 @@ CPPSRCS = \ nsDOMMouseEvent.cpp \ nsDOMMutationEvent.cpp \ nsDOMPopupBlockedEvent.cpp \ nsDOMBeforeUnloadEvent.cpp \ nsDOMPageTransitionEvent.cpp \ nsDOMXULCommandEvent.cpp \ nsDOMCommandEvent.cpp \ nsDOMMessageEvent.cpp \ + nsDOMProgressEvent.cpp \ nsPrivateTextRange.cpp \ nsDOMEventGroup.cpp \ nsXMLEventsManager.cpp \ nsXMLEventsElement.cpp \ nsPLDOMEvent.cpp \ nsEventDispatcher.cpp \ nsIMEStateManager.cpp \ nsQueryContentEventHandler.cpp \ diff --git a/content/events/src/nsEventDispatcher.cpp b/content/events/src/nsEventDispatcher.cpp --- a/content/events/src/nsEventDispatcher.cpp +++ b/content/events/src/nsEventDispatcher.cpp @@ -648,11 +648,13 @@ nsEventDispatcher::CreateEvent(nsPresCon if (aEventType.LowerCaseEqualsLiteral("commandevent") || aEventType.LowerCaseEqualsLiteral("commandevents")) return NS_NewDOMCommandEvent(aDOMEvent, aPresContext, nsnull); if (aEventType.LowerCaseEqualsLiteral("datacontainerevent") || aEventType.LowerCaseEqualsLiteral("datacontainerevents")) return NS_NewDOMDataContainerEvent(aDOMEvent, aPresContext, nsnull); if (aEventType.LowerCaseEqualsLiteral("messageevent")) return NS_NewDOMMessageEvent(aDOMEvent, aPresContext, nsnull); + if (aEventType.LowerCaseEqualsLiteral("progressevent")) + return NS_NewDOMProgressEvent(aDOMEvent, aPresContext, nsnull); return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } diff --git a/dom/public/idl/events/Makefile.in b/dom/public/idl/events/Makefile.in --- a/dom/public/idl/events/Makefile.in +++ b/dom/public/idl/events/Makefile.in @@ -67,11 +67,12 @@ XPIDLSRCS = \ nsIDOMNSUIEvent.idl \ nsIDOMPopupBlockedEvent.idl \ nsIDOMBeforeUnloadEvent.idl \ nsIDOMNSEventTarget.idl \ nsIDOMSmartCardEvent.idl \ nsIDOMPageTransitionEvent.idl \ nsIDOMCommandEvent.idl \ nsIDOMMessageEvent.idl \ + nsIDOMProgressEvent.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/dom/public/nsDOMClassInfoID.h b/dom/public/nsDOMClassInfoID.h --- a/dom/public/nsDOMClassInfoID.h +++ b/dom/public/nsDOMClassInfoID.h @@ -419,16 +419,20 @@ enum nsDOMClassInfoID { // Data Events eDOMClassInfo_DataContainerEvent_id, // event used for cross-domain message-passing and for server-sent events in // HTML5 eDOMClassInfo_MessageEvent_id, + eDOMClassInfo_XMLHttpRequestUpload_id, + + eDOMClassInfo_ProgressEvent_id, + // This one better be the last one in this list eDOMClassInfoIDCount }; /** * nsIClassInfo helper macros */ diff --git a/dom/src/base/nsDOMClassInfo.cpp b/dom/src/base/nsDOMClassInfo.cpp --- a/dom/src/base/nsDOMClassInfo.cpp +++ b/dom/src/base/nsDOMClassInfo.cpp @@ -237,16 +237,17 @@ #include "nsIDOMCommandEvent.h" #include "nsIDOMPopupBlockedEvent.h" #include "nsIDOMBeforeUnloadEvent.h" #include "nsIDOMMutationEvent.h" #include "nsIDOMSmartCardEvent.h" #include "nsIDOMXULCommandEvent.h" #include "nsIDOMPageTransitionEvent.h" #include "nsIDOMMessageEvent.h" +#include "nsIDOMProgressEvent.h" #include "nsIDOMNSDocumentStyle.h" #include "nsIDOMDocumentRange.h" #include "nsIDOMDocumentTraversal.h" #include "nsIDOMDocumentXBL.h" #include "nsIDOMDocumentView.h" #include "nsIDOMElementCSSInlineStyle.h" #include "nsIDOMLinkStyle.h" #include "nsIDOMHTMLDocument.h" @@ -1182,16 +1183,18 @@ static nsDOMClassInfoData sClassInfoData DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(XMLSerializer, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(XMLHttpProgressEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(XMLHttpRequest, nsEventTargetSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(XMLHttpRequestUpload, nsEventTargetSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(ClientRect, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(ClientRectList, nsClientRectListSH, ARRAY_SCRIPTABLE_FLAGS) // Define MOZ_SVG_FOREIGNOBJECT here so that when it gets switched on, // we preserve binary compatibility. New classes should be added @@ -1227,16 +1230,19 @@ static nsDOMClassInfoData sClassInfoData NS_DEFINE_CLASSINFO_DATA(ModalContentWindow, nsWindowSH, DEFAULT_SCRIPTABLE_FLAGS | WINDOW_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(DataContainerEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(MessageEvent, nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) + + NS_DEFINE_CLASSINFO_DATA(ProgressEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) }; // Objects that shuld be constructable through |new Name();| struct nsContractIDMapData { PRInt32 mDOMClassInfoID; const char *mContractID; @@ -3287,16 +3293,22 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_BEGIN(XMLHttpRequest, nsIXMLHttpRequest) DOM_CLASSINFO_MAP_ENTRY(nsIXMLHttpRequest) DOM_CLASSINFO_MAP_ENTRY(nsIJSXMLHttpRequest) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) DOM_CLASSINFO_MAP_ENTRY(nsIInterfaceRequestor) DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(XMLHttpRequestUpload, nsIXMLHttpRequestUpload) + DOM_CLASSINFO_MAP_ENTRY(nsIXMLHttpRequestEventTarget) + DOM_CLASSINFO_MAP_ENTRY(nsIXMLHttpRequestUpload) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) + DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XMLHttpProgressEvent, nsIDOMEvent) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent) DOM_CLASSINFO_MAP_ENTRY(nsIDOMLSProgressEvent) DOM_CLASSINFO_MAP_END #if defined(MOZ_SVG) && defined(MOZ_SVG_FOREIGNOBJECT) DOM_CLASSINFO_MAP_BEGIN(SVGForeignObjectElement, nsIDOMSVGForeignObjectElement) DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGForeignObjectElement) @@ -3366,16 +3378,21 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_BEGIN(DataContainerEvent, nsIDOMDataContainerEvent) DOM_CLASSINFO_MAP_ENTRY(nsIDOMDataContainerEvent) DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_BEGIN(MessageEvent, nsIDOMMessageEvent) DOM_CLASSINFO_MAP_ENTRY(nsIDOMMessageEvent) + DOM_CLASSINFO_EVENT_MAP_ENTRIES + DOM_CLASSINFO_MAP_END + + DOM_CLASSINFO_MAP_BEGIN(ProgressEvent, nsIDOMProgressEvent) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMProgressEvent) DOM_CLASSINFO_EVENT_MAP_ENTRIES DOM_CLASSINFO_MAP_END #ifdef NS_DEBUG { PRUint32 i = NS_ARRAY_LENGTH(sClassInfoData); if (i != eDOMClassInfoIDCount) { --- /dev/null 2008-06-05 11:51:05.389205708 +0300 +++ mozilla/content/events/src/nsDOMProgressEvent.h 2008-06-05 18:17:00.000000000 +0300 @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Olli Pettay (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsDOMProgressEvent_h__ +#define nsDOMProgressEvent_h__ + +#include "nsIDOMProgressEvent.h" +#include "nsDOMEvent.h" +#include "nsCycleCollectionParticipant.h" + +class nsDOMProgressEvent : public nsIDOMProgressEvent, + public nsDOMEvent +{ +public: + nsDOMProgressEvent(nsPresContext* aPresContext, nsEvent* aEvent) + : nsDOMEvent(aPresContext, aEvent) + { + } + + NS_DECL_ISUPPORTS_INHERITED + + NS_DECL_NSIDOMPROGRESSEVENT + + // Forward to base class + NS_FORWARD_TO_NSDOMEVENT + +private: + PRBool mLengthComputable; + PRUint32 mLoaded; + PRUint32 mTotal; +}; + +#endif // nsDOMProgressEvent_h__ --- /dev/null 2008-06-05 11:51:05.389205708 +0300 +++ mozilla/content/events/src/nsDOMProgressEvent.cpp 2008-06-05 19:03:37.000000000 +0300 @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Olli Pettay (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsDOMProgressEvent.h" +#include "nsContentUtils.h" + +NS_INTERFACE_MAP_BEGIN(nsDOMProgressEvent) + NS_INTERFACE_MAP_ENTRY(nsIDOMProgressEvent) + NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(ProgressEvent) +NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent) + +NS_IMPL_ADDREF_INHERITED(nsDOMProgressEvent, nsDOMEvent) +NS_IMPL_RELEASE_INHERITED(nsDOMProgressEvent, nsDOMEvent) + +NS_IMETHODIMP +nsDOMProgressEvent::InitProgressEvent(const nsAString& aType, + PRBool aCanBubble, + PRBool aCancelable, + PRBool aLengthComputable, + PRUint32 aLoaded, + PRUint32 aTotal) +{ + nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable); + NS_ENSURE_SUCCESS(rv, rv); + + mLengthComputable = aLengthComputable; + mLoaded = aLoaded; + mTotal = aTotal; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMProgressEvent::InitProgressEventNS(const nsAString& aNamespaceURI, + const nsAString& aType, + PRBool aCanBubble, + PRBool aCancelable, + PRBool aLengthComputable, + PRUint32 aLoaded, + PRUint32 aTotal) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsDOMProgressEvent::GetLengthComputable(PRBool* aComputable) +{ + *aComputable = mLengthComputable; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMProgressEvent::GetLoaded(PRUint32* aLoaded) +{ + *aLoaded = mLoaded; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMProgressEvent::GetTotal(PRUint32* aTotal) +{ + *aTotal = mTotal; + return NS_OK; +} + +nsresult +NS_NewDOMProgressEvent(nsIDOMEvent** aInstancePtrResult, + nsPresContext* aPresContext, + nsEvent* aEvent) +{ + nsDOMProgressEvent* it = new nsDOMProgressEvent(aPresContext, aEvent); + if (nsnull == it) + return NS_ERROR_OUT_OF_MEMORY; + + return CallQueryInterface(it, aInstancePtrResult); +} --- /dev/null 2008-06-05 11:51:05.389205708 +0300 +++ mozilla/dom/public/idl/events/nsIDOMProgressEvent.idl 2008-06-05 18:10:15.000000000 +0300 @@ -0,0 +1,61 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Olli Pettay (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIDOMEvent.idl" + +[scriptable, uuid(06072bf2-2644-4042-9103-edc06df66ccf)] +interface nsIDOMProgressEvent : nsIDOMEvent +{ + readonly attribute boolean lengthComputable; + readonly attribute unsigned long loaded; + readonly attribute unsigned long total; + void initProgressEvent(in DOMString typeArg, + in boolean canBubbleArg, + in boolean cancelableArg, + in boolean lengthComputableArg, + in unsigned long loadedArg, + in unsigned long totalArg); + void initProgressEventNS(in DOMString namespaceURI, + in DOMString typeArg, + in boolean canBubbleArg, + in boolean cancelableArg, + in boolean lengthComputableArg, + in unsigned long loadedArg, + in unsigned long totalArg); + +};