/// <summary>Raises the <see cref="Retargeted"/> event.</summary>
		/// <param name="e">The data for the event.</param>
		protected virtual void OnRetargeted(GeckoRetargetedEventArgs e)
		{
			var evnt = ((EventHandler<GeckoRetargetedEventArgs>)Events[RetargetedEvent]);
			if (evnt != null) evnt(this, e);
		}
Esempio n. 2
0
		void nsIWebProgressListener.OnStateChange(nsIWebProgress aWebProgress, nsIRequest aRequest, uint aStateFlags, int aStatus) {
			const int NS_BINDING_ABORTED = unchecked((int)0x804B0002);
			
			#region validity checks
			// The request parametere may be null
			if (aRequest == null)
				return;

			// Ignore ViewSource requests, they don't provide the URL
			// see: http://mxr.mozilla.org/mozilla-central/source/netwerk/protocol/viewsource/nsViewSourceChannel.cpp#114
			{
				var viewSource = Xpcom.QueryInterface<nsIViewSourceChannel>( aRequest );
				if ( viewSource != null )
				{
					Marshal.ReleaseComObject( viewSource );
					return;
				}
			}
	
			#endregion validity checks

			using (var request = Gecko.Net.Request.CreateRequest(aRequest))
			{
				#region request parameters
				Uri destUri = null;
				Uri.TryCreate(request.Name, UriKind.Absolute, out destUri);
				var domWindow = aWebProgress.GetDOMWindowAttribute().Wrap(x => new GeckoWindow(x));

				/* This flag indicates that the state transition is for a request, which includes but is not limited to document requests.
				 * Other types of requests, such as requests for inline content (for example images and stylesheets) are considered normal requests.
				 */
				bool stateIsRequest = ((aStateFlags & nsIWebProgressListenerConstants.STATE_IS_REQUEST) != 0);

				/* This flag indicates that the state transition is for a document request. This flag is set in addition to STATE_IS_REQUEST.
				 * A document request supports the nsIChannel interface and its loadFlags attribute includes the nsIChannel ::LOAD_DOCUMENT_URI flag.
				 * A document request does not complete until all requests associated with the loading of its corresponding document have completed.
				 * This includes other document requests (for example corresponding to HTML <iframe> elements).
				 * The document corresponding to a document request is available via the DOMWindow attribute of onStateChange()'s aWebProgress parameter.
				 */
				bool stateIsDocument = ((aStateFlags & nsIWebProgressListenerConstants.STATE_IS_DOCUMENT) != 0);

				/* This flag indicates that the state transition corresponds to the start or stop of activity in the indicated nsIWebProgress instance.
				 * This flag is accompanied by either STATE_START or STATE_STOP, and it may be combined with other State Type Flags.
				 * 
				 * Unlike STATE_IS_WINDOW, this flag is only set when activity within the nsIWebProgress instance being observed starts or stops.
				 * If activity only occurs in a child nsIWebProgress instance, then this flag will be set to indicate the start and stop of that activity.
				 * For example, in the case of navigation within a single frame of a HTML frameset, a nsIWebProgressListener instance attached to the
				 * nsIWebProgress of the frameset window will receive onStateChange() calls with the STATE_IS_NETWORK flag set to indicate the start and
				 * stop of said navigation. In other words, an observer of an outer window can determine when activity, that may be constrained to a
				 * child window or set of child windows, starts and stops.
				 */
				bool stateIsNetwork = ((aStateFlags & nsIWebProgressListenerConstants.STATE_IS_NETWORK) != 0);

				/* This flag indicates that the state transition corresponds to the start or stop of activity in the indicated nsIWebProgress instance.
				 * This flag is accompanied by either STATE_START or STATE_STOP, and it may be combined with other State Type Flags.
				 * This flag is similar to STATE_IS_DOCUMENT. However, when a document request completes, two onStateChange() calls with STATE_STOP are generated.
				 * The document request is passed as aRequest to both calls. The first has STATE_IS_REQUEST and STATE_IS_DOCUMENT set, and the second has
				 * the STATE_IS_WINDOW flag set (and possibly the STATE_IS_NETWORK flag set as well -- see above for a description of when the STATE_IS_NETWORK
				 * flag may be set). This second STATE_STOP event may be useful as a way to partition the work that occurs when a document request completes.
				 */
				bool stateIsWindow = ((aStateFlags & nsIWebProgressListenerConstants.STATE_IS_WINDOW) != 0);
				#endregion request parameters

				#region STATE_START
				/* This flag indicates the start of a request.
				 * This flag is set when a request is initiated.
				 * The request is complete when onStateChange() is called for the same request with the STATE_STOP flag set.
				 */
				if ((aStateFlags & nsIWebProgressListenerConstants.STATE_START) != 0)
				{

					
					if (stateIsNetwork && domWindow.IsTopWindow())
					{
						IsBusy = true;

						GeckoNavigatingEventArgs ea = new GeckoNavigatingEventArgs(destUri, domWindow);
						OnNavigating(ea);

						if (ea.Cancel)
						{
							aRequest.Cancel(NS_BINDING_ABORTED);
							

							// clear busy state
							IsBusy = false;

							// clear progress bar
							OnProgressChanged(new GeckoProgressEventArgs(100, 100));

							// clear status bar
							StatusText = "";
						}
					}
					else if (stateIsDocument)
					{
						GeckoNavigatingEventArgs ea = new GeckoNavigatingEventArgs(destUri, domWindow);
						OnFrameNavigating(ea);

						if (ea.Cancel)
						{
							
							if (!Xpcom.IsLinux)
								aRequest.Cancel(NS_BINDING_ABORTED);
						}
					}
				}
				#endregion STATE_START

				#region STATE_REDIRECTING
				/* This flag indicates that a request is being redirected.
				 * The request passed to onStateChange() is the request that is being redirected.
				 * When a redirect occurs, a new request is generated automatically to process the new request.
				 * Expect a corresponding STATE_START event for the new request, and a STATE_STOP for the redirected request.
				 */
				else if ((aStateFlags & nsIWebProgressListenerConstants.STATE_REDIRECTING) != 0)
				{

					// make sure we're loading the top-level window
					GeckoRedirectingEventArgs ea = new GeckoRedirectingEventArgs(destUri, domWindow);
					OnRedirecting(ea);

					if (ea.Cancel)
					{
						aRequest.Cancel(NS_BINDING_ABORTED);
					}
				}
				#endregion STATE_REDIRECTING

				#region STATE_TRANSFERRING
				/* This flag indicates that data for a request is being transferred to an end consumer.
				 * This flag indicates that the request has been targeted, and that the user may start seeing content corresponding to the request.
				 */
				else if ((aStateFlags & nsIWebProgressListenerConstants.STATE_TRANSFERRING) != 0)
				{
				}
				#endregion STATE_TRANSFERRING

				#region STATE_STOP
				/* This flag indicates the completion of a request.
				 * The aStatus parameter to onStateChange() indicates the final status of the request.
				 */
				else if ((aStateFlags & nsIWebProgressListenerConstants.STATE_STOP) != 0)
				{
					/* aStatus
					 * Error status code associated with the state change.
					 * This parameter should be ignored unless aStateFlags includes the STATE_STOP bit.
					 * The status code indicates success or failure of the request associated with the state change.
					 * 
					 * Note: aStatus may be a success code even for server generated errors, such as the HTTP 404 File Not Found error.
					 * In such cases, the request itself should be queried for extended error information (for example for HTTP requests see nsIHttpChannel).
					 */

					if (stateIsNetwork)
					{
						// clear busy state
						IsBusy = false;
						if (aStatus == 0)
						{
							// navigating to a unrenderable file (.zip, .exe, etc.) causes the request pending;
							// also an OnStateChange call with aStatus:804B0004(NS_BINDING_RETARGETED) has been generated previously.
							if (!request.IsPending)
							{
								// kill any cached document and raise DocumentCompleted event
								OnDocumentCompleted(new GeckoDocumentCompletedEventArgs(destUri, domWindow));

								// clear progress bar
								OnProgressChanged(new GeckoProgressEventArgs(100, 100));
							}
						}
						else
						{
							OnNavigationError(new GeckoNavigationErrorEventArgs(request.Name, domWindow, aStatus));
						}
						// clear status bar
						StatusText = "";
					}

					if (stateIsRequest)
					{
						if ((aStatus & 0xff0000) == ((GeckoError.NS_ERROR_MODULE_SECURITY + GeckoError.NS_ERROR_MODULE_BASE_OFFSET) << 16))
						{
							var ea = new GeckoNSSErrorEventArgs(destUri, aStatus);
							OnNSSError(ea);
							if (ea.Handled)
							{
								aRequest.Cancel(GeckoError.NS_BINDING_ABORTED);
							}
						}

						if (aStatus == GeckoError.NS_BINDING_RETARGETED)
						{
							GeckoRetargetedEventArgs ea = new GeckoRetargetedEventArgs(destUri, domWindow, request);
							OnRetargeted(ea);
						}
					}
				}
				#endregion STATE_STOP
				if (domWindow!=null)
				{
					domWindow.Dispose();
				}
			}
		}