Merge m-c --> cedar
authorChris Jones <jones.chris.g@gmail.com>
Wed, 15 Sep 2010 18:28:06 -0500
changeset 54118 2aded27629f8c34e4dcde5fe9f487e44bbe56e01
parent 54117 6a177cc98bac9e0702c728a699d7ad6d47af7b05 (current diff)
parent 53996 3406ae8889f932b8a8cef352ce2650860f16b0c0 (diff)
child 54119 30fc6b4def84e93de1ee0d723425d74b4bb77a38
push id15768
push userdougt@mozilla.com
push dateThu, 16 Sep 2010 01:40:23 +0000
treeherdermozilla-central@cdb90b48f19f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.0b7pre
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
Merge m-c --> cedar
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/PBrowser.ipdl
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
layout/base/nsDocumentViewer.cpp
layout/base/nsIDocumentViewer.h
--- a/content/base/public/nsContentErrors.h
+++ b/content/base/public/nsContentErrors.h
@@ -86,9 +86,13 @@
 
 #define NS_FINDBROADCASTER_AWAIT_OVERLAYS \
   NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 14)
 
 /* Error codes for CSP */
 #define NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION \
   NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_SECURITY, 99)
 
+/* Error codes for XBL */
+#define NS_ERROR_XBL_BLOCKED \
+  NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 15)
+
 #endif // nsContentErrors_h___
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -299,16 +299,20 @@ public:
   inline PRBool IsInNamespace(PRInt32 aNamespace) const {
     return mNodeInfo->NamespaceID() == aNamespace;
   }
 
   inline PRBool IsHTML() const {
     return IsInNamespace(kNameSpaceID_XHTML);
   }
 
+  inline PRBool IsHTML(nsIAtom* aTag) const {
+    return mNodeInfo->Equals(aTag, kNameSpaceID_XHTML);
+  }
+
   inline PRBool IsSVG() const {
     /* Some things in the SVG namespace are not in fact SVG elements */
     return IsNodeOfType(eSVG);
   }
 
   inline PRBool IsXUL() const {
     return IsInNamespace(kNameSpaceID_XUL);
   }
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -1415,22 +1415,23 @@ public:
    * Document state bits have the form NS_DOCUMENT_STATE_* and are declared in
    * nsIDocument.h.
    */
   virtual PRInt32 GetDocumentState() = 0;
 
   virtual nsISupports* GetCurrentContentSink() = 0;
 
   /**
-   * Register a filedata uri as being "owned" by this document. I.e. that its
-   * lifetime is connected with this document. When the document goes away it
-   * should "kill" the uri by calling
+   * Register/Unregister a filedata uri as being "owned" by this document. 
+   * I.e. that its lifetime is connected with this document. When the document
+   * goes away it should "kill" the uri by calling
    * nsFileDataProtocolHandler::RemoveFileDataEntry
    */
-  virtual void RegisterFileDataUri(nsACString& aUri) = 0;
+  virtual void RegisterFileDataUri(const nsACString& aUri) = 0;
+  virtual void UnregisterFileDataUri(const nsACString& aUri) = 0;
 
   virtual void SetScrollToRef(nsIURI *aDocumentURI) = 0;
   virtual void ScrollToRef() = 0;
   virtual void ResetScrolledToRefAlready() = 0;
   virtual void SetChangeScrollPosWhenScrollingToRef(PRBool aValue) = 0;
 
   /**
    * This method is similar to GetElementById() from nsIDOMDocument but it
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -7905,22 +7905,28 @@ nsDocument::UnsuppressEventHandlingAndFi
 
 nsISupports*
 nsDocument::GetCurrentContentSink()
 {
   return mParser ? mParser->GetContentSink() : nsnull;
 }
 
 void
-nsDocument::RegisterFileDataUri(nsACString& aUri)
+nsDocument::RegisterFileDataUri(const nsACString& aUri)
 {
   mFileDataUris.AppendElement(aUri);
 }
 
 void
+nsDocument::UnregisterFileDataUri(const nsACString& aUri)
+{
+  mFileDataUris.RemoveElement(aUri);
+}
+
+void
 nsDocument::SetScrollToRef(nsIURI *aDocumentURI)
 {
   if (!aDocumentURI) {
     return;
   }
 
   nsCAutoString ref;
 
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -951,17 +951,18 @@ public:
 
   virtual nsresult LoadChromeSheetSync(nsIURI* uri, PRBool isAgentSheet,
                                        nsCSSStyleSheet** sheet);
 
   virtual nsISupports* GetCurrentContentSink();
 
   virtual PRInt32 GetDocumentState();
 
-  virtual void RegisterFileDataUri(nsACString& aUri);
+  virtual void RegisterFileDataUri(const nsACString& aUri);
+  virtual void UnregisterFileDataUri(const nsACString& aUri);
 
   // Only BlockOnload should call this!
   void AsyncBlockOnload();
 
   virtual void SetScrollToRef(nsIURI *aDocumentURI);
   virtual void ScrollToRef();
   virtual void ResetScrolledToRefAlready();
   virtual void SetChangeScrollPosWhenScrollingToRef(PRBool aValue);
--- a/content/base/src/nsFormData.cpp
+++ b/content/base/src/nsFormData.cpp
@@ -34,32 +34,34 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsFormData.h"
 #include "nsIVariant.h"
 #include "nsIInputStream.h"
 #include "nsIDOMFile.h"
 #include "nsContentUtils.h"
+#include "nsHTMLFormElement.h"
 
 nsFormData::nsFormData()
   : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nsnull)
 {
 }
 
 // -------------------------------------------------------------------------
 // nsISupports
 
 DOMCI_DATA(FormData, nsFormData)
 
 NS_IMPL_ADDREF(nsFormData)
 NS_IMPL_RELEASE(nsFormData)
 NS_INTERFACE_MAP_BEGIN(nsFormData)
   NS_INTERFACE_MAP_ENTRY(nsIDOMFormData)
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(FormData)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFormData)
 NS_INTERFACE_MAP_END
 
 // -------------------------------------------------------------------------
 // nsFormSubmission
 nsresult
 nsFormData::GetEncodedSubmission(nsIURI* aURI,
@@ -125,17 +127,17 @@ nsFormData::Append(const nsAString& aNam
 
   nsString valAsString;
   valAsString.Adopt(stringData, stringLen);
 
   return AddNameValuePair(aName, valAsString);
 }
 
 // -------------------------------------------------------------------------
-// nsIDXHRSendable
+// nsIXHRSendable
 
 NS_IMETHODIMP
 nsFormData::GetSendInfo(nsIInputStream** aBody, nsACString& aContentType,
                         nsACString& aCharset)
 {
   nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nsnull);
   
   for (PRUint32 i = 0; i < mFormData.Length(); ++i) {
@@ -148,8 +150,40 @@ nsFormData::GetSendInfo(nsIInputStream**
   }
 
   fs.GetContentType(aContentType);
   aCharset.Truncate();
   NS_ADDREF(*aBody = fs.GetSubmissionBody());
 
   return NS_OK;
 }
+
+
+// -------------------------------------------------------------------------
+// nsIJSNativeInitializer
+
+NS_IMETHODIMP
+nsFormData::Initialize(nsISupports* aOwner,
+                       JSContext* aCx,
+                       JSObject* aObj,
+                       PRUint32 aArgc,
+                       jsval* aArgv)
+{
+  if (aArgc > 0) {
+    if (JSVAL_IS_PRIMITIVE(aArgv[0])) {
+      return NS_ERROR_UNEXPECTED;
+    }
+    nsCOMPtr<nsIContent> formCont = do_QueryInterface(
+      nsContentUtils::XPConnect()->
+        GetNativeOfWrapper(aCx, JSVAL_TO_OBJECT(aArgv[0])));
+    
+    if (!formCont || !formCont->IsHTML(nsGkAtoms::form)) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    nsresult rv = static_cast<nsHTMLFormElement*>(formCont.get())->
+      WalkFormElements(this);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+
+  return NS_OK;
+}
--- a/content/base/src/nsFormData.h
+++ b/content/base/src/nsFormData.h
@@ -35,22 +35,24 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsFormData_h__
 #define nsFormData_h__
 
 #include "nsIDOMFormData.h"
 #include "nsIXMLHttpRequest.h"
 #include "nsFormSubmission.h"
+#include "nsIJSNativeInitializer.h"
 #include "nsTArray.h"
 
 class nsIDOMFile;
 
 class nsFormData : public nsIDOMFormData,
                    public nsIXHRSendable,
+                   public nsIJSNativeInitializer,
                    public nsFormSubmission
 {
 public:
   nsFormData();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMFORMDATA
   NS_DECL_NSIXHRSENDABLE
@@ -58,16 +60,18 @@ public:
   // nsFormSubmission
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream);
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue);
   virtual nsresult AddNameFilePair(const nsAString& aName,
                                    nsIDOMFile* aFile);
 
+  NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
+                        PRUint32 aArgc, jsval* aArgv);
 private:
   struct FormDataTuple
   {
     nsString name;
     nsString stringValue;
     nsCOMPtr<nsIDOMFile> fileValue;
     PRBool valueIsFile;
   };
--- a/content/base/test/test_bug543870.html
+++ b/content/base/test/test_bug543870.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
-  <title>Test for Cross Site XMLHttpRequest</title>
+  <title>Test for File urls</title>
   <script type="text/javascript" src="/MochiKit/packed.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onload="gen.next()">
 <p id="display">
 <iframe id=inner></iframe>
 <iframe id=iframe></iframe>
@@ -33,35 +33,52 @@ SimpleTest.waitForExplicitFinish();
 function runTest() {
   inner = document.getElementById('inner');
   img = document.getElementById('img');
   iframe = document.getElementById('iframe');
   inner.onload = function() { gen.send("inner loaded"); };
 
   // Attempt to load a image in this document
   var file = getFile("file_bug543870_img.jpg");
-  img.src = file.url;
+  var fileurl = createBlobURL(file);
+  img.src = fileurl;
   var e = (yield);
   is(e.type, "load", "loaded successfully");
   is(img.width, 120, "correct width");
   is(img.height, 90, "correct height");
 
+  // Revoke url and attempt to load a image in this document
+  img.src = "file_bug543870_img.jpg";
+  is((yield).type, "load", "successfull reset image");
+  revokeBlobURL(fileurl);
+  todo(false, "urls need to act like 404s, not fail to parse");
+/*  img.src = fileurl;
+  var e = (yield);
+  is(e.type, "error", "failed successfully");
+  isnot(img.width, 120, "correct error width");
+  isnot(img.height, 90, "correct error height");
+*/
+  // Generate new fileurl and make sure it's different from the old
+  var oldFileurl = fileurl;
+  var fileurl = createBlobURL(file);
+  isnot(fileurl, oldFileurl, "createBlobURL generated the same url twice");
+
   // Attempt to load an image in a different same-origin document
   inner.src = innerSameSiteURI;
   yield;
-  inner.contentWindow.postMessage(JSON.stringify({img:file.url}), "*");
+  inner.contentWindow.postMessage(JSON.stringify({img:fileurl}), "*");
   var res = (yield);
   is(res.type, "load", "loaded successfully");
   is(res.width, 120, "correct width");
   is(res.height, 90, "correct height");
   
   // Attempt to load an image in a different cross-origin document
   inner.src = innerCrossSiteURI;
   yield;
-  inner.contentWindow.postMessage(JSON.stringify({img:file.url}), "*");
+  inner.contentWindow.postMessage(JSON.stringify({img:fileurl}), "*");
   var res = (yield);
   is(res.type, "error", "failed successfully");
   isnot(res.width, 120, "correct error width");
   isnot(res.height, 90, "correct error height");
 
   // Attempt to load a HTML document in an iframe in this document
   iframe.onload = function() { gen.next(); };
   iframe.src = "file_bug543870_doc.html";
@@ -71,17 +88,18 @@ function runTest() {
      "iframe loaded successfully");
   is(iframe.contentDocument.getElementById("img").width, 120,
      "image in iframe width");
   is(iframe.contentDocument.getElementById("img").height, 90,
      "image in iframe height");
 
   // Attempt to load a HTML document in an iframe in this document, using file url
   file = getFile("file_bug543870_doc.html");
-  iframe.src = file.url;
+  fileurl = createBlobURL(file);
+  iframe.src = fileurl;
   yield;
   is(iframe.contentDocument.getElementsByTagName("p")[0].textContent,
      "This here is a document!",
      "iframe loaded successfully");
   isnot(iframe.contentDocument.getElementById("img").width, 120,
         "failed image in iframe width");
   isnot(iframe.contentDocument.getElementById("img").height, 90,
         "failed image in iframe height");
@@ -91,50 +109,51 @@ function runTest() {
   is((yield), "inner loaded", "correct gen.next()");
   inner.contentWindow.postMessage(JSON.stringify({iframe:"file_bug543870_doc.html"}), "*");
   var res = (yield);
   is(res.type, "load", "loaded successfully");
   is(res.text, "This here is a document!", "loaded successfully");
   is(res.imgWidth, 120, "correct width");
 
   // Attempt to load a HTML document in an iframe in inner document, using file url
-  inner.contentWindow.postMessage(JSON.stringify({iframe:file.url}), "*");
+  inner.contentWindow.postMessage(JSON.stringify({iframe:fileurl}), "*");
   var res = (yield);
   is(res.type, "load", "loaded successfully");
   is(res.text, "This here is a document!", "loaded successfully");
   isnot(res.imgWidth, 120, "correct width");
 
   // Attempt to load a HTML document in an iframe in inner cross-site document, using file url
   inner.src = innerCrossSiteURI;
   is((yield), "inner loaded", "correct gen.next()");
-  inner.contentWindow.postMessage(JSON.stringify({iframe:file.url}), "*");
+  inner.contentWindow.postMessage(JSON.stringify({iframe:fileurl}), "*");
   var res = (yield);
   is(res.type, "error", "load failed successfully");
 
   // Attempt to load file url using XHR
   file = getFile("file_bug543870_text.txt");
+  fileurl = createBlobURL(file);
   xhr = new XMLHttpRequest;
   xhr.onload = function() { gen.send("XHR finished"); };
-  xhr.open("GET", file.url);
+  xhr.open("GET", fileurl);
   xhr.send();
   is((yield), "XHR finished", "correct gen.next()");
   xhr.responseText == "Yarr, here be plaintext file, ya landlubber\n";
 
   // Attempt to load file url using XHR in inner document
   inner.src = innerSameSiteURI;
   is((yield), "inner loaded", "correct gen.next()");
-  inner.contentWindow.postMessage(JSON.stringify({xhr:file.url}), "*");
+  inner.contentWindow.postMessage(JSON.stringify({xhr:fileurl}), "*");
   var res = (yield);
   is(res.didThrow, undefined, "load successful");
   is(res.text, "Yarr, here be plaintext file, ya landlubber\n", "load successful");
 
   // Attempt to load file url using XHR
   inner.src = innerCrossSiteURI;
   is((yield), "inner loaded", "correct gen.next()");
-  inner.contentWindow.postMessage(JSON.stringify({xhr:file.url}), "*");
+  inner.contentWindow.postMessage(JSON.stringify({xhr:fileurl}), "*");
   var res = (yield);
   is(res.didThrow, true, "load failed successfully");
 
   SimpleTest.finish();
 
   yield;
 }
 
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -1571,29 +1571,16 @@ nsHTMLFormElement::GetEncoding(nsAString
 }
  
 NS_IMETHODIMP
 nsHTMLFormElement::SetEncoding(const nsAString& aEncoding)
 {
   return SetEnctype(aEncoding);
 }
 
-NS_IMETHODIMP
-nsHTMLFormElement::GetFormData(nsIDOMFormData** aFormData)
-{
-  nsRefPtr<nsFormData> fd = new nsFormData();
-
-  nsresult rv = WalkFormElements(fd);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *aFormData = fd.forget().get();
-
-  return NS_OK;
-}
- 
 NS_IMETHODIMP    
 nsHTMLFormElement::GetLength(PRInt32* aLength)
 {
   PRUint32 length;
   nsresult rv = mControls->GetLength(&length);
   *aLength = length;
   return rv;
 }
--- a/content/html/content/src/nsHTMLFormElement.h
+++ b/content/html/content/src/nsHTMLFormElement.h
@@ -279,16 +279,25 @@ public:
    * @return Whether the form is valid.
    *
    * @note Do not call this method if novalidate/formnovalidate is used.
    * @note This method might disappear with bug 592124, hopefuly.
    */
   bool CheckValidFormSubmission();
 
   virtual nsXPCClassInfo* GetClassInfo();
+
+  /**
+   * Walk over the form elements and call SubmitNamesValues() on them to get
+   * their data pumped into the FormSubmitter.
+   *
+   * @param aFormSubmission the form submission object
+   */
+  nsresult WalkFormElements(nsFormSubmission* aFormSubmission);
+
 protected:
   class RemoveElementRunnable;
   friend class RemoveElementRunnable;
 
   class RemoveElementRunnable : public nsRunnable {
   public:
     RemoveElementRunnable(nsHTMLFormElement* aForm, PRBool aNotify):
       mForm(aForm), mNotify(aNotify)
@@ -333,23 +342,16 @@ protected:
   nsresult BuildSubmission(nsFormSubmission** aFormSubmission, 
                            nsEvent* aEvent);
   /**
    * Perform the submission (called by DoSubmit and FlushPendingSubmission)
    *
    * @param aFormSubmission the submission object
    */
   nsresult SubmitSubmission(nsFormSubmission* aFormSubmission);
-  /**
-   * Walk over the form elements and call SubmitNamesValues() on them to get
-   * their data pumped into the FormSubmitter.
-   *
-   * @param aFormSubmission the form submission object
-   */
-  nsresult WalkFormElements(nsFormSubmission* aFormSubmission);
 
   /**
    * Notify any submit observers of the submit.
    *
    * @param aActionURL the URL being submitted to
    * @param aCancelSubmit out param where submit observers can specify that the
    *        submit should be cancelled.
    */
--- a/content/html/content/test/test_formSubmission.html
+++ b/content/html/content/test/test_formSubmission.html
@@ -603,25 +603,25 @@ function runTest() {
   yield;
   submission = JSON.parse(iframe.contentDocument.documentElement.textContent);
   checkPlainSubmission(submission, expectedSub);
 
   // Send form using XHR and FormData
   xhr = new XMLHttpRequest();
   xhr.onload = function() { gen.next(); };
   xhr.open("POST", "form_submit_server.sjs");
-  xhr.send(form.getFormData());
+  xhr.send(new FormData(form));
   yield; // Wait for XHR load
   checkMPSubmission(JSON.parse(xhr.responseText), expectedSub);
   
   // Send disabled form using XHR and FormData
   setDisabled(document.getElementsByTagName("input"), true);
   setDisabled(document.getElementsByTagName("select"), true);
   xhr.open("POST", "form_submit_server.sjs");
-  xhr.send(form.getFormData());
+  xhr.send(new FormData(form));
   yield;
   checkMPSubmission(JSON.parse(xhr.responseText), []);
   setDisabled(document.getElementsByTagName("input"), false);
   setDisabled(document.getElementsByTagName("select"), false);
   
   // Send FormData
   function addToFormData(fd) {
     fd.append("aName", "aValue");
@@ -632,17 +632,17 @@ function runTest() {
   var fd = new FormData();
   addToFormData(fd);
   xhr.open("POST", "form_submit_server.sjs");
   xhr.send(fd);
   yield;
   checkMPSubmission(JSON.parse(xhr.responseText), expectedAugment);
 
   // Augment <form> using FormData
-  fd = form.getFormData();
+  fd = new FormData(form);
   addToFormData(fd);
   xhr.open("POST", "form_submit_server.sjs");
   xhr.send(fd);
   yield;
   checkMPSubmission(JSON.parse(xhr.responseText),
                     expectedSub.concat(expectedAugment));
 
   SimpleTest.finish();
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -1927,17 +1927,18 @@ nsHTMLDocument::OpenCommon(const nsACStr
     // Remember the old scope in case the call to SetNewDocument changes it.
     nsCOMPtr<nsIScriptGlobalObject> oldScope(do_QueryReferent(mScopeObject));
 
 #ifdef DEBUG
     PRBool willReparent = mWillReparent;
     mWillReparent = PR_TRUE;
 #endif
 
-    rv = window->SetNewDocument(this, nsnull);
+    // Should this pass PR_TRUE for aForceReuseInnerWindow?
+    rv = window->SetNewDocument(this, nsnull, PR_FALSE);
     NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
     mWillReparent = willReparent;
 #endif
 
     // Now make sure we're not flagged as the initial document anymore, now
     // that we've had stuff done to us.  From now on, if anyone tries to
--- a/content/xbl/src/nsXBLService.cpp
+++ b/content/xbl/src/nsXBLService.cpp
@@ -71,16 +71,17 @@
 #include "nsXBLPrototypeBinding.h"
 #include "nsXBLDocumentInfo.h"
 #include "nsCRT.h"
 #include "nsContentUtils.h"
 #include "nsSyncLoadService.h"
 #include "nsIDOM3Node.h"
 #include "nsContentPolicyUtils.h"
 #include "nsTArray.h"
+#include "nsContentErrors.h"
 
 #include "nsIPresShell.h"
 #include "nsIDocumentObserver.h"
 #include "nsFrameManager.h"
 #include "nsStyleContext.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptError.h"
 
@@ -1102,31 +1103,31 @@ nsXBLService::LoadBindingDocumentInfo(ns
     // clobbering it in our table.  That makes things very confused, leading to
     // misbehavior and crashes.
     rv = nsContentUtils::
       CheckSecurityBeforeLoad(aBindingURI, aOriginPrincipal,
                               nsIScriptSecurityManager::ALLOW_CHROME,
                               gAllowDataURIs,
                               nsIContentPolicy::TYPE_XBL,
                               aBoundDocument);
-    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED);
 
     if (!IsSystemOrChromeURLPrincipal(aOriginPrincipal)) {
       // Also make sure that we're same-origin with the bound document
       // except if the stylesheet has the system principal.
       if (!(gAllowDataURIs && SchemeIs(aBindingURI, "data")) &&
           !SchemeIs(aBindingURI, "chrome")) {
         rv = aBoundDocument->NodePrincipal()->CheckMayLoad(aBindingURI,
                                                            PR_TRUE);
-        NS_ENSURE_SUCCESS(rv, rv);
+        NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED);
       }
 
       // Finally check if this document is allowed to use XBL at all.
       NS_ENSURE_TRUE(aBoundDocument->AllowXULXBL(),
-                     NS_ERROR_NOT_AVAILABLE);
+                     NS_ERROR_XBL_BLOCKED);
     }
   }
 
   *aResult = nsnull;
   nsRefPtr<nsXBLDocumentInfo> info;
 
   nsCOMPtr<nsIURI> documentURI;
   rv = aBindingURI->Clone(getter_AddRefs(documentURI));
--- a/content/xbl/test/Makefile.in
+++ b/content/xbl/test/Makefile.in
@@ -67,12 +67,15 @@ include $(topsrcdir)/config/rules.mk
 		file_bug379959_cross.html \
 		file_bug379959_xbl.xml \
 		test_bug468210.xhtml \
 		test_bug481558.html \
 		file_bug481558css.sjs \
 		file_bug481558.xbl \
 		test_bug526178.xhtml \
 		test_bug542406.xhtml \
+		test_bug591198.html \
+		file_bug591198_xbl.xml \
+		file_bug591198_inner.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/content/xbl/test/file_bug591198_inner.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <style>
+      #b {
+        -moz-binding: url("file_bug591198_xbl.xml#xbltest");
+      }
+      span {
+        white-space: nowrap;
+      }
+    </style>
+    <script>
+function sendResults() {
+  var res = {
+    widths: []
+  };
+
+  ps = document.getElementsByTagName('span');
+  for (var i = 0; i < ps.length; i++) {
+    res.widths.push(ps[i].offsetWidth);
+  }
+  
+  try {
+    res.anonChildCount =
+      document.getAnonymousNodes(document.getElementById('b')).length;
+  }
+  catch (ex) {}
+
+  parent.postMessage(JSON.stringify(res), "*");
+}
+    </script>
+  </head>
+  <body onload="sendResults();">
+    <div><span id=b>long long text here</span></div>
+    <div><span>long long text here</span></div>
+    <div><span>PASS</span></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/xbl/test/file_bug591198_xbl.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<bindings id="xbltestBindings" xmlns="http://www.mozilla.org/xbl"
+          xmlns:html="http://www.w3.org/1999/xhtml">
+  <binding id="xbltest"><content>PASS<html:b style="display:none"><children/></html:b></content></binding>
+</bindings>
new file mode 100644
--- /dev/null
+++ b/content/xbl/test/test_bug591198.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=591198
+-->
+<head>
+  <title>Test for Bug 591198</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+</head>
+<body onload="gen.next();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=591198">Mozilla Bug 591198</a>
+<iframe id=iframe></iframe>
+<pre id="test">
+<script class="testbody" type="text/javascript;version=1.8">
+
+SimpleTest.waitForExplicitFinish();
+
+gen = runTest();
+
+function runTest() {
+  let iframe = $('iframe');
+  window.addEventListener("message", function(e) {
+    gen.send(JSON.parse(e.data));
+  }, false);
+  
+  iframe.src = "file_bug591198_inner.html";
+  let res = (yield);
+  is(res.widths[0], res.widths[2], "binding was rendered");
+  isnot(res.widths[0], res.widths[1], "binding was rendered");
+  is(res.anonChildCount, 2, "correct number of anon children");
+
+  iframe.src = "http://noxul.example.com/tests/content/xbl/test/file_bug591198_inner.html";
+  let res = (yield);
+  is(res.widths[0], res.widths[1], "binding was not rendered");
+  isnot(res.widths[0], res.widths[2], "binding was not rendered");
+  is("anonChildCount" in res, false, "no anon children");
+
+  SimpleTest.finish();
+  yield;
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -83,16 +83,17 @@
 #include "nsIPrompt.h"
 #include "nsIDOMWindowInternal.h"
 #include "nsIChannel.h"
 #include "nsIPrincipal.h"
 #include "nsXMLPrettyPrinter.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIContentPolicy.h"
+#include "nsIDocumentViewer.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentErrors.h"
 #include "nsIDOMProcessingInstruction.h"
 #include "nsNodeUtils.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIHTMLDocument.h"
 #include "mozAutoDocUpdate.h"
 #include "nsMimeTypes.h"
@@ -381,19 +382,19 @@ nsXMLContentSink::OnDocumentCreated(nsID
 
   nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aResultDocument);
   if (htmlDoc) {
     htmlDoc->SetDocWriteDisabled(PR_TRUE);
   }
 
   nsCOMPtr<nsIContentViewer> contentViewer;
   mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
-  if (contentViewer) {
-    nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aResultDocument);
-    return contentViewer->SetDOMDocument(doc);
+  nsCOMPtr<nsIDocumentViewer> docViewer = do_QueryInterface(contentViewer);
+  if (docViewer) {
+    return docViewer->SetDocumentInternal(aResultDocument, PR_TRUE);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXMLContentSink::OnTransformDone(nsresult aResult,
                                   nsIDocument* aResultDocument)
 {
new file mode 100644
--- /dev/null
+++ b/docshell/test/chrome/582176_xml.xml
@@ -0,0 +1,2 @@
+<?xml-stylesheet type="text/xsl" href="582176_xslt.xsl"?>
+<out/>
new file mode 100644
--- /dev/null
+++ b/docshell/test/chrome/582176_xslt.xsl
@@ -0,0 +1,8 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:template match="out">
+    <html>
+      <head><title>XSLT result doc</title></head>
+      <body><p>xslt result</p></body>
+    </html>
+  </xsl:template>
+</xsl:stylesheet>
--- a/docshell/test/chrome/Makefile.in
+++ b/docshell/test/chrome/Makefile.in
@@ -48,16 +48,18 @@ include $(topsrcdir)/config/rules.mk
 		92598_nostore.html^headers^ \
 		112564_nocache.html \
 		112564_nocache.html^headers^ \
 		215405_nostore.html \
 		215405_nostore.html^headers^ \
 		215405_nocache.html \
 		215405_nocache.html^headers^ \
 		582176_dummy.html \
+		582176_xml.xml \
+		582176_xslt.xsl \
 		$(NULL)
 
 _TEST_FILES =	\
 		test_bug92598.xul \
 		bug92598_window.xul \
 		92598_nostore.html \
 		test_bug112564.xul \
 		bug112564_window.xul \
--- a/docshell/test/chrome/bug582176_window.xul
+++ b/docshell/test/chrome/bug582176_window.xul
@@ -65,16 +65,22 @@
       is(notificationCount, 2, "Should notify on second navigation");
 
       browser.goBack();
       yield;
       is(browser.contentWindow.wrappedJSObject.testVar, 1,
          "variable should still be there");
       is(notificationCount, 2, "Should not notify on back navigation");
 
+      browser.loadURI("http://mochi.test:8888/tests/docshell/test/chrome/582176_xml.xml");
+      yield;
+      is(browser.contentDocument.body.textContent, "xslt result",
+         "Transform performed successfully");
+      is(notificationCount, 3, "Should notify only once on XSLT navigation");
+
       os.removeObserver(observer, "content-document-global-created")
 
       // Tell the framework the test is finished.  Include the final 'yield' 
       // statement to prevent a StopIteration exception from being thrown.
       finish();
       yield;
     }
     
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -163,16 +163,18 @@
 #include "nsIScriptEventManager.h" // For GetInterface()
 #include "nsIConsoleService.h"
 #include "nsIControllers.h"
 #include "nsIControllerContext.h"
 #include "nsGlobalWindowCommands.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsCSSProps.h"
+#include "nsFileDataProtocolHandler.h"
+#include "nsIDOMFile.h"
 #include "nsIURIFixup.h"
 #include "mozilla/FunctionTimer.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsEventDispatcher.h"
 #include "nsIObserverService.h"
 #include "nsIXULAppInfo.h"
 #include "nsNetUtil.h"
 #include "nsFocusManager.h"
@@ -1581,17 +1583,18 @@ WindowStateHolder::~WindowStateHolder()
     mInnerWindow->FreeInnerObjects(PR_TRUE);
   }
 }
 
 NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder)
 
 nsresult
 nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
-                               nsISupports* aState)
+                               nsISupports* aState,
+                               PRBool aForceReuseInnerWindow)
 {
   NS_TIME_FUNCTION;
 
   NS_PRECONDITION(mDocumentPrincipal == nsnull,
                   "mDocumentPrincipal prematurely set!");
 
   if (!aDocument) {
     NS_ERROR("SetNewDocument(null) called!");
@@ -1605,17 +1608,18 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     }
 
     // Refuse to set a new document if the call came from an inner
     // window that's not the current inner window.
     if (mOuterWindow->GetCurrentInnerWindow() != this) {
       return NS_ERROR_NOT_AVAILABLE;
     }
 
-    return GetOuterWindowInternal()->SetNewDocument(aDocument, aState);
+    return GetOuterWindowInternal()->SetNewDocument(aDocument, aState,
+                                                    aForceReuseInnerWindow);
   }
 
   NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
 
   if (IsFrozen()) {
     // This outer is now getting its first inner, thaw the outer now
     // that it's ready and is getting an inner window.
 
@@ -1624,16 +1628,25 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
   // XXX Brain transplant outer window JSObject and create new one!
 
   NS_ASSERTION(!GetCurrentInnerWindow() ||
                GetCurrentInnerWindow()->GetExtantDocument() == mDocument,
                "Uh, mDocument doesn't match the current inner window "
                "document!");
 
+  PRBool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
+  if (aForceReuseInnerWindow &&
+      !wouldReuseInnerWindow &&
+      mDoc &&
+      mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
+    NS_ERROR("Attempted forced inner window reuse while changing principal");
+    return NS_ERROR_UNEXPECTED;
+  }
+
   nsresult rv = NS_OK;
 
   nsCOMPtr<nsIDocument> oldDoc(do_QueryInterface(mDocument));
 
   nsIScriptContext *scx = GetContextInternal();
   NS_ENSURE_TRUE(scx, NS_ERROR_NOT_INITIALIZED);
 
   JSContext *cx = (JSContext *)scx->GetNativeContext();
@@ -1663,17 +1676,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
   /* No mDocShell means we're already been partially closed down.  When that
      happens, setting status isn't a big requirement, so don't. (Doesn't happen
      under normal circumstances, but bug 49615 describes a case.) */
 
   nsContentUtils::AddScriptRunner(
     NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus));
 
-  PRBool reUseInnerWindow = WouldReuseInnerWindow(aDocument);
+  PRBool reUseInnerWindow = aForceReuseInnerWindow || wouldReuseInnerWindow;
 
   // Remember the old document's principal.
   nsIPrincipal *oldPrincipal = nsnull;
   if (oldDoc) {
     oldPrincipal = oldDoc->NodePrincipal();
   }
 
   // Drop our reference to the navigator object unless we're reusing
@@ -2943,16 +2956,45 @@ nsGlobalWindow::GetApplicationCache(nsID
   }
 
   NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsGlobalWindow::CreateBlobURL(nsIDOMFile* aFile, nsAString& aURL)
+{
+  FORWARD_TO_INNER(CreateBlobURL, (aFile, aURL), NS_ERROR_UNEXPECTED);
+
+  NS_ENSURE_STATE(mDoc);
+
+  nsresult rv = aFile->GetInternalUrl(aURL);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mDoc->RegisterFileDataUri(NS_LossyConvertUTF16toASCII(aURL));
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGlobalWindow::RevokeBlobURL(const nsAString& aURL)
+{
+  FORWARD_TO_INNER(RevokeBlobURL, (aURL), NS_ERROR_UNEXPECTED);
+
+  NS_ENSURE_STATE(mDoc);
+
+  NS_LossyConvertUTF16toASCII asciiurl(aURL);
+  mDoc->UnregisterFileDataUri(asciiurl);
+  nsFileDataProtocolHandler::RemoveFileDataEntry(asciiurl);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
 {
   FORWARD_TO_OUTER(GetCrypto, (aCrypto), NS_ERROR_NOT_INITIALIZED);
 
   if (!mCrypto) {
     mCrypto = do_CreateInstance(kCryptoContractID);
   }
 
@@ -9778,25 +9820,27 @@ nsGlobalModalWindow::SetReturnValue(nsIV
 
   mReturnValue = aRetVal;
 
   return NS_OK;
 }
 
 nsresult
 nsGlobalModalWindow::SetNewDocument(nsIDocument *aDocument,
-                                    nsISupports *aState)
+                                    nsISupports *aState,
+                                    PRBool aForceReuseInnerWindow)
 {
   // If we're loading a new document into a modal dialog, clear the
   // return value that was set, if any, by the current document.
   if (aDocument) {
     mReturnValue = nsnull;
   }
 
-  return nsGlobalWindow::SetNewDocument(aDocument, aState);
+  return nsGlobalWindow::SetNewDocument(aDocument, aState,
+                                        aForceReuseInnerWindow);
 }
 
 //*****************************************************************************
 // nsGlobalWindow: Creator Function (This should go away)
 //*****************************************************************************
 
 nsresult
 NS_NewScriptGlobalObject(PRBool aIsChrome, PRBool aIsModalContentWindow,
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -343,17 +343,18 @@ public:
                                                      const nsIID& aIID);
   virtual NS_HIDDEN_(nsresult) RemoveEventListenerByIID(nsIDOMEventListener *aListener,
                                                         const nsIID& aIID);
   virtual NS_HIDDEN_(nsresult) GetSystemEventGroup(nsIDOMEventGroup** aGroup);
   virtual NS_HIDDEN_(nsIScriptContext*) GetContextForEventHandlers(nsresult* aRv);
 
   virtual NS_HIDDEN_(void) SetDocShell(nsIDocShell* aDocShell);
   virtual NS_HIDDEN_(nsresult) SetNewDocument(nsIDocument *aDocument,
-                                              nsISupports *aState);
+                                              nsISupports *aState,
+                                              PRBool aForceReuseInnerWindow);
   void DispatchDOMWindowCreated();
   virtual NS_HIDDEN_(void) SetOpenerWindow(nsIDOMWindowInternal *aOpener,
                                            PRBool aOriginalOpener);
   virtual NS_HIDDEN_(void) EnsureSizeUpToDate();
 
   virtual NS_HIDDEN_(void) EnterModalState();
   virtual NS_HIDDEN_(void) LeaveModalState();
 
@@ -912,17 +913,18 @@ public:
   }
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMMODALCONTENTWINDOW
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
 
   virtual NS_HIDDEN_(nsresult) SetNewDocument(nsIDocument *aDocument,
-                                              nsISupports *aState);
+                                              nsISupports *aState,
+                                              PRBool aForceReuseInnerWindow);
 
 protected:
   nsCOMPtr<nsIVariant> mReturnValue;
 };
 
 
 //*****************************************************************************
 // nsNavigator: Script "navigator" object
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -72,18 +72,18 @@ class nsIDocument;
 class nsIScriptTimeoutHandler;
 struct nsTimeout;
 class nsScriptObjectHolder;
 class nsXBLPrototypeHandler;
 class nsIArray;
 class nsPIWindowRoot;
 
 #define NS_PIDOMWINDOW_IID \
-{ 0x4beac1da, 0x513e, 0x4a8b, \
-  { 0x96, 0x94, 0x1c, 0xf6, 0x4f, 0xba, 0xa8, 0x1c } }
+{ 0x8d8be7db, 0xffaa, 0x4962, \
+  { 0xa7, 0x27, 0xb7, 0x0f, 0xc9, 0xfa, 0xd3, 0x0e } }
 
 class nsPIDOMWindow : public nsIDOMWindowInternal
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMWINDOW_IID)
 
   virtual nsPIDOMWindow* GetPrivateRoot() = 0;
 
@@ -368,17 +368,18 @@ public:
    * an inner window the call will be forewarded to the outer window,
    * if the inner window is not the current inner window an
    * NS_ERROR_NOT_AVAILABLE error code will be returned. This may be
    * called with a pointer to the current document, in that case the
    * document remains unchanged, but a new inner window will be
    * created.
    */
   virtual nsresult SetNewDocument(nsIDocument *aDocument,
-                                  nsISupports *aState) = 0;
+                                  nsISupports *aState,
+                                  PRBool aForceReuseInnerWindow) = 0;
 
   /**
    * Set the opener window.  aOriginalOpener is true if and only if this is the
    * original opener for the window.  That is, it can only be true at most once
    * during the life cycle of a window, and then only the first time
    * SetOpenerWindow is called.  It might never be true, of course, if the
    * window does not have an opener when it's created.
    */
--- a/dom/interfaces/base/nsIDOMWindow2.idl
+++ b/dom/interfaces/base/nsIDOMWindow2.idl
@@ -33,24 +33,32 @@
  * 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 "nsIDOMWindow.idl"
 
 interface nsIDOMOfflineResourceList;
+interface nsIDOMFile;
 
-[scriptable, uuid(73c5fa35-3add-4c87-a303-a850ccf4d65a)]
+[scriptable, uuid(63239526-27b0-44ff-be4e-ee1c8ee2212e)]
 interface nsIDOMWindow2 : nsIDOMWindow
 {
   /**
    * Get the window root for this window. This is useful for hooking
    * up event listeners to this window and every other window nested
    * in the window root.
    */
   [noscript] readonly attribute nsIDOMEventTarget windowRoot;
 
   /**
    * Get the application cache object for this window.
    */
   readonly attribute nsIDOMOfflineResourceList applicationCache;
+
+  /**
+   * Create and revoke blob urls. createBlobURL will always return a new URL
+   * with the lifetime of the current Document.
+   */
+  DOMString createBlobURL(in nsIDOMFile file);
+  void revokeBlobURL(in DOMString URL);
 };
--- a/dom/interfaces/html/nsIDOMNSHTMLFormElement.idl
+++ b/dom/interfaces/html/nsIDOMNSHTMLFormElement.idl
@@ -36,15 +36,14 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
 interface nsIDOMFormData;
 
-[scriptable, uuid(55bdaf9b-eacb-49d6-b4b1-a27e61ed54fc)]
+[scriptable, uuid(d38a782f-f33c-4a8d-85a9-0d5da3650064)]
 interface nsIDOMNSHTMLFormElement : nsISupports
 {
            attribute DOMString        encoding;
-  nsIDOMFormData getFormData();
   boolean        checkValidity();
 };
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -43,16 +43,17 @@
 
 #include "ContentChild.h"
 #include "TabChild.h"
 
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/ipc/XPCShellEnvironment.h"
 #include "mozilla/jsipc/PContextWrapperChild.h"
+#include "mozilla/dom/ExternalHelperAppChild.h"
 
 #include "nsIObserverService.h"
 #include "nsTObserverArray.h"
 #include "nsIObserver.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXULAppAPI.h"
@@ -293,16 +294,36 @@ ContentChild::AllocPNecko()
 
 bool 
 ContentChild::DeallocPNecko(PNeckoChild* necko)
 {
     delete necko;
     return true;
 }
 
+PExternalHelperAppChild*
+ContentChild::AllocPExternalHelperApp(const IPC::URI& uri,
+                                      const nsCString& aMimeContentType,
+                                      const nsCString& aContentDisposition,
+                                      const bool& aForceSave,
+                                      const PRInt64& aContentLength)
+{
+    ExternalHelperAppChild *child = new ExternalHelperAppChild();
+    child->AddRef();
+    return child;
+}
+
+bool
+ContentChild::DeallocPExternalHelperApp(PExternalHelperAppChild* aService)
+{
+    ExternalHelperAppChild *child = static_cast<ExternalHelperAppChild*>(aService);
+    child->Release();
+    return true;
+}
+
 bool
 ContentChild::RecvRegisterChrome(const nsTArray<ChromePackage>& packages,
                                  const nsTArray<ResourceMapping>& resources,
                                  const nsTArray<OverrideMapping>& overrides)
 {
     nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
     nsChromeRegistryContent* chromeRegistry =
         static_cast<nsChromeRegistryContent*>(registrySvc.get());
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -78,16 +78,24 @@ public:
 
     virtual PTestShellChild* AllocPTestShell();
     virtual bool DeallocPTestShell(PTestShellChild*);
     virtual bool RecvPTestShellConstructor(PTestShellChild*);
 
     virtual PNeckoChild* AllocPNecko();
     virtual bool DeallocPNecko(PNeckoChild*);
 
+    virtual PExternalHelperAppChild *AllocPExternalHelperApp(
+            const IPC::URI& uri,
+            const nsCString& aMimeContentType,
+            const nsCString& aContentDisposition,
+            const bool& aForceSave,
+            const PRInt64& aContentLength);
+    virtual bool DeallocPExternalHelperApp(PExternalHelperAppChild *aService);
+
     virtual bool RecvRegisterChrome(const nsTArray<ChromePackage>& packages,
                                     const nsTArray<ResourceMapping>& resources,
                                     const nsTArray<OverrideMapping>& overrides);
 
     virtual bool RecvSetOffline(const PRBool& offline);
 
     virtual bool RecvNotifyVisited(const IPC::URI& aURI);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -54,16 +54,18 @@
 #include "nsThreadUtils.h"
 #include "nsChromeRegistryChrome.h"
 #include "nsExternalHelperAppService.h"
 #include "nsCExternalHandlerService.h"
 #include "nsFrameMessageManager.h"
 #include "nsIAlertsService.h"
 #include "nsToolkitCompsCID.h"
 
+#include "mozilla/dom/ExternalHelperAppParent.h"
+
 #ifdef ANDROID
 #include "AndroidBridge.h"
 using namespace mozilla;
 #endif
 
 using namespace mozilla::ipc;
 using namespace mozilla::net;
 using namespace mozilla::places;
@@ -418,16 +420,37 @@ ContentParent::AllocPNecko()
 
 bool 
 ContentParent::DeallocPNecko(PNeckoParent* necko)
 {
     delete necko;
     return true;
 }
 
+PExternalHelperAppParent*
+ContentParent::AllocPExternalHelperApp(const IPC::URI& uri,
+                                       const nsCString& aMimeContentType,
+                                       const nsCString& aContentDisposition,
+                                       const bool& aForceSave,
+                                       const PRInt64& aContentLength)
+{
+    ExternalHelperAppParent *parent = new ExternalHelperAppParent(uri, aContentLength);
+    parent->AddRef();
+    parent->Init(this, aMimeContentType, aContentDisposition, aForceSave);
+    return parent;
+}
+
+bool
+ContentParent::DeallocPExternalHelperApp(PExternalHelperAppParent* aService)
+{
+    ExternalHelperAppParent *parent = static_cast<ExternalHelperAppParent *>(aService);
+    parent->Release();
+    return true;
+}
+
 void
 ContentParent::ReportChildAlreadyBlocked()
 {
     if (!mRunToCompletionDepth) {
 #ifdef DEBUG
         printf("Running to completion...\n");
 #endif
         mRunToCompletionDepth = 1;
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -109,16 +109,24 @@ private:
     virtual bool DeallocPBrowser(PBrowserParent* frame);
 
     virtual PTestShellParent* AllocPTestShell();
     virtual bool DeallocPTestShell(PTestShellParent* shell);
 
     virtual PNeckoParent* AllocPNecko();
     virtual bool DeallocPNecko(PNeckoParent* necko);
 
+    virtual PExternalHelperAppParent* AllocPExternalHelperApp(
+            const IPC::URI& uri,
+            const nsCString& aMimeContentType,
+            const nsCString& aContentDisposition,
+            const bool& aForceSave,
+            const PRInt64& aContentLength);
+    virtual bool DeallocPExternalHelperApp(PExternalHelperAppParent* aService);
+
     virtual bool RecvGetPrefType(const nsCString& prefName,
             PRInt32* retValue, nsresult* rv);
 
     virtual bool RecvGetBoolPref(const nsCString& prefName,
             PRBool* retValue, nsresult* rv);
 
     virtual bool RecvGetIntPref(const nsCString& prefName,
             PRInt32* retValue, nsresult* rv);
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -38,17 +38,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 include protocol PContent;
 include protocol PContentDialog;
 include protocol PDocumentRenderer;
 include protocol PDocumentRendererShmem;
 include protocol PDocumentRendererNativeID;
 include protocol PContentPermissionRequest;
-include protocol PExternalHelperApp;
 include protocol PRenderFrame;
 
 include "TabMessageUtils.h";
 include "gfxMatrix.h";
 include "mozilla/net/NeckoMessageUtils.h";
 include "IPC/nsGUIEventIPC.h";
 
 using gfxMatrix;
@@ -67,17 +66,16 @@ rpc protocol PBrowser
 {
     manager PContent;
 
     manages PContentDialog;
     manages PDocumentRenderer;
     manages PDocumentRendererShmem;
     manages PDocumentRendererNativeID;
     manages PContentPermissionRequest;
-    manages PExternalHelperApp;
     manages PRenderFrame;
 
 both:
     AsyncMessage(nsString aMessage, nsString aJSON);
 
 parent:
     /**
      * When child sends this message, parent should move focus to
@@ -123,20 +121,16 @@ parent:
     /**
      * Create a layout frame (encapsulating a remote layer tree) for
      * the page that is currently loaded in the <browser>.
      */
     async PRenderFrame();
 
     __delete__();
 
-    PExternalHelperApp(URI uri, nsCString aMimeContentType,
-                       nsCString aContentDisposition, bool aForceSave,
-                       PRInt64 aContentLength);
-
 child:
     /**
      * Notify the remote browser that it has been Show()n on this
      * side, with the given |visibleRect|.  This message is expected
      * to trigger creation of the remote browser's "widget".
      *
      * |Show()| and |Move()| take IntSizes rather than Rects because
      * content processes always render to a virtual <0, 0> top-left
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -34,16 +34,17 @@
  * 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 protocol PBrowser;
 include protocol PTestShell;
 include protocol PNecko;
+include protocol PExternalHelperApp;
 
 include "mozilla/chrome/RegistryMessageUtils.h";
 include "mozilla/net/NeckoMessageUtils.h";
 
 using ChromePackage;
 using ResourceMapping;
 using OverrideMapping;
 using IPC::URI;
@@ -51,16 +52,17 @@ using IPC::URI;
 namespace mozilla {
 namespace dom {
 
 rpc protocol PContent
 {
     manages PBrowser;
     manages PTestShell;
     manages PNecko;
+    manages PExternalHelperApp;
 
 child:
     PBrowser(PRUint32 chromeFlags);
 
     PTestShell();
 
     RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources,
                    OverrideMapping[] overrides);
@@ -105,15 +107,19 @@ parent:
 
     ShowAlertNotification(nsString imageUrl, 
                           nsString title, 
                           nsString text, 
                           PRBool textClickable,
                           nsString cookie,
                           nsString name);
 
+    PExternalHelperApp(URI uri, nsCString aMimeContentType,
+                       nsCString aContentDisposition, bool aForceSave,
+                       PRInt64 aContentLength);
+
 both:
      AsyncMessage(nsString aMessage, nsString aJSON);
 
 };
 
 }
 }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -52,17 +52,16 @@
 #include "nsIWebProgress.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsThreadUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "mozilla/ipc/DocumentRendererChild.h"
 #include "mozilla/ipc/DocumentRendererShmemChild.h"
 #include "mozilla/ipc/DocumentRendererNativeIDChild.h"
-#include "mozilla/dom/ExternalHelperAppChild.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsISupportsImpl.h"
 #include "nsIURI.h"
 #include "nsIWebBrowserFocus.h"
 #include "nsIDOMEvent.h"
 #include "nsIPrivateDOMEvent.h"
@@ -1279,29 +1278,8 @@ TabChildGlobal::GetJSContextForEventHand
 nsIPrincipal* 
 TabChildGlobal::GetPrincipal()
 {
   if (!mTabChild)
     return nsnull;
   return mTabChild->GetPrincipal();
 }
 
-PExternalHelperAppChild*
-TabChild::AllocPExternalHelperApp(const IPC::URI& uri,
-                                  const nsCString& aMimeContentType,
-                                  const nsCString& aContentDisposition,
-                                  const bool& aForceSave,
-                                  const PRInt64& aContentLength)
-{
-  ExternalHelperAppChild *child = new ExternalHelperAppChild();
-  child->AddRef();
-  return child;
-}
-
-bool
-TabChild::DeallocPExternalHelperApp(PExternalHelperAppChild* aService)
-{
-  ExternalHelperAppChild *child = static_cast<ExternalHelperAppChild*>(aService);
-  child->Release();
-  return true;
-}
-
-
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -222,23 +222,16 @@ public:
             const PRUint32& flags,
             const bool& flush);
     virtual PContentDialogChild* AllocPContentDialog(const PRUint32&,
                                                      const nsCString&,
                                                      const nsCString&,
                                                      const nsTArray<int>&,
                                                      const nsTArray<nsString>&);
     virtual bool DeallocPContentDialog(PContentDialogChild* aDialog);
-    virtual PExternalHelperAppChild *AllocPExternalHelperApp(
-            const IPC::URI& uri,
-            const nsCString& aMimeContentType,
-            const nsCString& aContentDisposition,
-            const bool& aForceSave,
-            const PRInt64& aContentLength);
-    virtual bool DeallocPExternalHelperApp(PExternalHelperAppChild *aService);
     static void ParamsToArrays(nsIDialogParamBlock* aParams,
                                nsTArray<int>& aIntParams,
                                nsTArray<nsString>& aStringParams);
     static void ArraysToParams(const nsTArray<int>& aIntParams,
                                const nsTArray<nsString>& aStringParams,
                                nsIDialogParamBlock* aParams);
 
     virtual PDocumentRendererShmemChild* AllocPDocumentRendererShmem(
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -31,17 +31,16 @@
  * 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 "mozilla/dom/ExternalHelperAppParent.h"
 #include "TabParent.h"
 
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/ipc/DocumentRendererParent.h"
 #include "mozilla/ipc/DocumentRendererShmemParent.h"
 #include "mozilla/ipc/DocumentRendererNativeIDParent.h"
 #include "mozilla/layout/RenderFrameParent.h"
 
@@ -824,31 +823,10 @@ TabParent::ShouldDelayDialogs()
 
 already_AddRefed<nsFrameLoader>
 TabParent::GetFrameLoader() const
 {
   nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(mFrameElement);
   return frameLoaderOwner ? frameLoaderOwner->GetFrameLoader() : nsnull;
 }
 
-PExternalHelperAppParent*
-TabParent::AllocPExternalHelperApp(const IPC::URI& uri,
-                                   const nsCString& aMimeContentType,
-                                   const nsCString& aContentDisposition,
-                                   const bool& aForceSave,
-                                   const PRInt64& aContentLength)
-{
-  ExternalHelperAppParent *parent = new ExternalHelperAppParent(uri, aContentLength);
-  parent->AddRef();
-  parent->Init(this, aMimeContentType, aContentDisposition, aForceSave);
-  return parent;
-}
-
-bool
-TabParent::DeallocPExternalHelperApp(PExternalHelperAppParent* aService)
-{
-  ExternalHelperAppParent *parent = static_cast<ExternalHelperAppParent *>(aService);
-  parent->Release();
-  return true;
-}
-
 } // namespace tabs
 } // namespace mozilla
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -37,17 +37,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_tabs_TabParent_h
 #define mozilla_tabs_TabParent_h
 
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/PContentDialogParent.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
-#include "mozilla/dom/PExternalHelperApp.h"
 
 #include "jsapi.h"
 #include "nsCOMPtr.h"
 #include "nsITabParent.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsIWebProgress.h"
 #include "nsIWebProgressListener.h"
 #include "nsWeakReference.h"
@@ -142,24 +141,16 @@ public:
                                                       const nsTArray<int>& aIntParams,
                                                       const nsTArray<nsString>& aStringParams);
     virtual bool DeallocPContentDialog(PContentDialogParent* aDialog)
     {
       delete aDialog;
       return true;
     }
 
-    virtual PExternalHelperAppParent* AllocPExternalHelperApp(
-            const IPC::URI& uri,
-            const nsCString& aMimeContentType,
-            const nsCString& aContentDisposition,
-            const bool& aForceSave,
-            const PRInt64& aContentLength);
-    virtual bool DeallocPExternalHelperApp(PExternalHelperAppParent* aService);
-
     void LoadURL(nsIURI* aURI);
     // XXX/cjones: it's not clear what we gain by hiding these
     // message-sending functions under a layer of indirection and
     // eating the return values
     void Show(const nsIntSize& size);
     void Move(const nsIntSize& size);
     void Activate();
     void SendMouseEvent(const nsAString& aType, float aX, float aY,
--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
@@ -375,16 +375,23 @@ cairo_d2d_finish_device(cairo_device_t *
 	// S_OK and done = TRUE when the GPU is done. Any other return value
 	// means we need to break out or risk an infinite loop.
 	if (FAILED(query->GetData(&done, sizeof(BOOL), 0))) {
 	    break;
 	}
     }
 }
 
+ID3D10Device1*
+cairo_d2d_device_get_device(cairo_device_t *device)
+{
+    cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
+    return d2d_device->mD3D10Device;  
+}
+
 static void
 _cairo_d2d_setup_for_blend(cairo_d2d_device_t *device)
 {
     device->mD3D10Device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
     device->mD3D10Device->IASetInputLayout(device->mInputLayout);
 
     UINT stride = sizeof(Vertex);
     UINT offset = 0;
--- a/gfx/cairo/cairo/src/cairo-win32.h
+++ b/gfx/cairo/cairo/src/cairo-win32.h
@@ -167,16 +167,22 @@ cairo_addref_device(cairo_device_t *devi
  * should be executed manually when a different device is going to be accessing
  * the same surface data. This will also block until the device is finished
  * processing all work.
  */
 void
 cairo_d2d_finish_device(cairo_device_t *device);
 
 /**
+ * Gets the D3D10 device used by a certain cairo_device_t.
+ */
+struct ID3D10Device1*
+cairo_d2d_device_get_device(cairo_device_t *device);
+
+/**
  * Create a D2D surface for an HWND
  *
  * \param device Device used to create the surface
  * \param wnd Handle for the window
  * \param content Content of the window, should be COLOR_ALPHA for transparent windows
  * \return New cairo surface
  */
 cairo_public cairo_surface_t *
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -42,17 +42,17 @@
 #include "gfxWindowsSurface.h"
 #include "gfxWindowsPlatform.h"
 
 namespace mozilla {
 namespace layers {
 
 CanvasLayerD3D9::~CanvasLayerD3D9()
 {
-  if (mD3DManager->deviceManager()) {
+  if (mD3DManager) {
     mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this);
   }
 }
 
 void
 CanvasLayerD3D9::Initialize(const Data& aData)
 {
   NS_ASSERTION(mSurface == nsnull, "BasicCanvasLayer::Initialize called twice!");
@@ -286,16 +286,23 @@ CanvasLayerD3D9::CleanResources()
 {
   if (mD3DManager->deviceManager()->HasDynamicTextures()) {
     // In this case we have a texture in POOL_DEFAULT
     mTexture = nsnull;
   }
 }
 
 void
+CanvasLayerD3D9::LayerManagerDestroyed()
+{
+  mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this);
+  mD3DManager = nsnull;
+}
+
+void
 CanvasLayerD3D9::CreateTexture()
 {
   if (mD3DManager->deviceManager()->HasDynamicTextures()) {
     device()->CreateTexture(mBounds.width, mBounds.height, 1, D3DUSAGE_DYNAMIC,
                             D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
                             getter_AddRefs(mTexture), NULL);    
   } else {
     // D3DPOOL_MANAGED is fine here since we require Dynamic Textures for D3D9Ex
--- a/gfx/layers/d3d9/CanvasLayerD3D9.h
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.h
@@ -67,16 +67,17 @@ public:
   // CanvasLayer implementation
   virtual void Initialize(const Data& aData);
   virtual void Updated(const nsIntRect& aRect);
 
   // LayerD3D9 implementation
   virtual Layer* GetLayer();
   virtual void RenderLayer();
   virtual void CleanResources();
+  virtual void LayerManagerDestroyed();
 
   void CreateTexture();
 
 protected:
   typedef mozilla::gl::GLContext GLContext;
 
   // Indicates whether our texture was obtained through D2D interop.
   bool mIsInteropTexture;
--- a/gfx/layers/d3d9/ContainerLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp
@@ -260,10 +260,19 @@ ContainerLayerD3D9::RenderLayer()
 
     mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER);
 
     device()->SetTexture(0, renderTexture);
     device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
   }
 }
 
+void
+ContainerLayerD3D9::LayerManagerDestroyed()
+{
+  while (mFirstChild) {
+    GetFirstChildD3D9()->LayerManagerDestroyed();
+    RemoveChild(mFirstChild);
+  }
+}
+
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/d3d9/ContainerLayerD3D9.h
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.h
@@ -61,14 +61,16 @@ public:
   /* LayerD3D9 implementation */
   Layer* GetLayer();
 
   LayerD3D9* GetFirstChildD3D9();
 
   PRBool IsEmpty();
 
   void RenderLayer();
+
+  virtual void LayerManagerDestroyed();
 };
 
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_CONTAINERLAYERD3D9_H */
--- a/gfx/layers/d3d9/DeviceManagerD3D9.cpp
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.cpp
@@ -176,16 +176,17 @@ SwapChainD3D9::Reset()
   mSwapChain = nsnull;
 }
 
 #define HAS_CAP(a, b) (((a) & (b)) == (b))
 #define LACKS_CAP(a, b) !(((a) & (b)) == (b))
 
 DeviceManagerD3D9::DeviceManagerD3D9()
   : mHasDynamicTextures(false)
+  , mDeviceWasRemoved(false)
 {
 }
 
 DeviceManagerD3D9::~DeviceManagerD3D9()
 {
   LayerManagerD3D9::OnDeviceManagerDestroy(this);
 }
 
@@ -487,42 +488,44 @@ DeviceManagerD3D9::SetShaderMode(ShaderM
 bool
 DeviceManagerD3D9::VerifyReadyForRendering()
 {
   HRESULT hr = mDevice->TestCooperativeLevel();
 
   if (SUCCEEDED(hr)) {
     if (IsD3D9Ex()) {
       hr = mDeviceEx->CheckDeviceState(mFocusWnd);
+
+      if (hr == D3DERR_DEVICEREMOVED) {
+        mDeviceWasRemoved = true;
+        LayerManagerD3D9::OnDeviceManagerDestroy(this);
+        return false;
+      }
+
       if (FAILED(hr)) {
         D3DPRESENT_PARAMETERS pp;
         memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS));
 
         pp.BackBufferWidth = 1;
         pp.BackBufferHeight = 1;
         pp.BackBufferFormat = D3DFMT_A8R8G8B8;
         pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
         pp.Windowed = TRUE;
         pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
         pp.hDeviceWindow = mFocusWnd;
         
         hr = mDeviceEx->ResetEx(&pp, NULL);
-        // Handle D3DERR_DEVICEREMOVED!
         if (FAILED(hr)) {
           return false;
         }
       }
     }
     return true;
   }
 
-  if (hr != D3DERR_DEVICENOTRESET) {
-    return false;
-  }
-
   for(unsigned int i = 0; i < mLayersWithResources.Length(); i++) {
     mLayersWithResources[i]->CleanResources();
   }
   for(unsigned int i = 0; i < mSwapChains.Length(); i++) {
     mSwapChains[i]->Reset();
   }
   
   D3DPRESENT_PARAMETERS pp;
@@ -533,17 +536,23 @@ DeviceManagerD3D9::VerifyReadyForRenderi
   pp.BackBufferFormat = D3DFMT_A8R8G8B8;
   pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
   pp.Windowed = TRUE;
   pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
   pp.hDeviceWindow = mFocusWnd;
 
   hr = mDevice->Reset(&pp);
 
+  if (hr == D3DERR_DEVICELOST) {
+    return false;
+  }
+
   if (FAILED(hr)) {
+    mDeviceWasRemoved = true;
+    LayerManagerD3D9::OnDeviceManagerDestroy(this);
     return false;
   }
 
   return true;
 }
 
 bool
 DeviceManagerD3D9::VerifyCaps()
--- a/gfx/layers/d3d9/DeviceManagerD3D9.h
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.h
@@ -138,17 +138,22 @@ public:
     SOLIDCOLORLAYER
   };
 
   void SetShaderMode(ShaderMode aMode);
 
   /** 
    * Return pointer to the Nv3DVUtils instance 
    */ 
-  Nv3DVUtils *GetNv3DVUtils()  { return mNv3DVUtils; } 
+  Nv3DVUtils *GetNv3DVUtils()  { return mNv3DVUtils; }
+
+  /**
+   * Returns true if this device was removed.
+   */
+  bool DeviceWasRemoved() { return mDeviceWasRemoved; }
 
   /**
    * We keep a list of all layers here that may have hardware resource allocated
    * so we can clean their resources on reset.
    */
   nsTArray<LayerD3D9*> mLayersWithResources;
 private:
   friend class SwapChainD3D9;
@@ -201,16 +206,19 @@ private:
   /* Our focus window - this is really a dummy window we can associate our
    * device with.
    */
   HWND mFocusWnd;
 
   /* If this device supports dynamic textures */
   bool mHasDynamicTextures;
 
+  /* If this device was removed */
+  bool mDeviceWasRemoved;
+
   /* Nv3DVUtils instance */ 
   nsAutoPtr<Nv3DVUtils> mNv3DVUtils; 
 
   /**
    * Verifies all required device capabilities are present.
    */
   bool VerifyCaps();
 };
--- a/gfx/layers/d3d9/LayerManagerD3D9.cpp
+++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp
@@ -47,56 +47,49 @@
 #include "gfxWindowsPlatform.h"
 #ifdef CAIRO_HAS_D2D_SURFACE
 #include "gfxD2DSurface.h"
 #endif
 
 namespace mozilla {
 namespace layers {
 
-DeviceManagerD3D9 *LayerManagerD3D9::mDeviceManager = nsnull;
+DeviceManagerD3D9 *LayerManagerD3D9::mDefaultDeviceManager = nsnull;
 
 LayerManagerD3D9::LayerManagerD3D9(nsIWidget *aWidget)
   : mIs3DEnabled(PR_FALSE)
 {
-    mWidget = aWidget;
-    mCurrentCallbackInfo.Callback = NULL;
-    mCurrentCallbackInfo.CallbackData = NULL;
+  mWidget = aWidget;
+  mCurrentCallbackInfo.Callback = NULL;
+  mCurrentCallbackInfo.CallbackData = NULL;
 }
 
 LayerManagerD3D9::~LayerManagerD3D9()
 {
-  /* Important to release this first since it also holds a reference to the
-   * device manager
-   */
-  mSwapChain = nsnull;
-
-  if (mDeviceManager && mDeviceManager->Release() == 0) {
-    mDeviceManager = nsnull;
-  }
+  Destroy();
 }
 
 PRBool
 LayerManagerD3D9::Initialize()
 {
   /* Check the user preference for whether 3d video is enabled or not */ 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); 
   prefs->GetBoolPref("gfx.3d_video.enabled", &mIs3DEnabled); 
 
-  if (!mDeviceManager) {
+  if (!mDefaultDeviceManager) {
     mDeviceManager = new DeviceManagerD3D9;
-    mDeviceManager->AddRef();
 
     if (!mDeviceManager->Init()) {
-      mDeviceManager->Release();
       mDeviceManager = nsnull;
       return PR_FALSE;
     }
+
+    mDefaultDeviceManager = mDeviceManager;
   } else {
-    mDeviceManager->AddRef();
+    mDeviceManager = mDefaultDeviceManager;
   }
 
   mSwapChain = mDeviceManager->
     CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW));
 
   if (!mSwapChain) {
     return PR_FALSE;
   }
@@ -106,16 +99,32 @@ LayerManagerD3D9::Initialize()
 
 void
 LayerManagerD3D9::SetClippingRegion(const nsIntRegion &aClippingRegion)
 {
   mClippingRegion = aClippingRegion;
 }
 
 void
+LayerManagerD3D9::Destroy()
+{
+  if (!IsDestroyed()) {
+    if (mRoot) {
+      static_cast<LayerD3D9*>(mRoot->ImplData())->LayerManagerDestroyed();
+    }
+    /* Important to release this first since it also holds a reference to the
+     * device manager
+     */
+    mSwapChain = nsnull;
+    mDeviceManager = nsnull;
+  }
+  LayerManager::Destroy();
+}
+
+void
 LayerManagerD3D9::BeginTransaction()
 {
 }
 
 void
 LayerManagerD3D9::BeginTransactionWithTarget(gfxContext *aTarget)
 {
   mTarget = aTarget;
--- a/gfx/layers/d3d9/LayerManagerD3D9.h
+++ b/gfx/layers/d3d9/LayerManagerD3D9.h
@@ -102,16 +102,18 @@ public:
    * \param aClippingRegion Region to clip to. Setting an empty region
    * will disable clipping.
    */
   void SetClippingRegion(const nsIntRegion& aClippingRegion);
 
   /*
    * LayerManager implementation.
    */
+  virtual void Destroy();
+
   void BeginTransaction();
 
   void BeginTransactionWithTarget(gfxContext* aTarget);
 
   void EndConstruction();
 
   struct CallbackInfo {
     DrawThebesLayerCallback Callback;
@@ -138,16 +140,17 @@ public:
   virtual already_AddRefed<ImageContainer> CreateImageContainer();
 
   virtual already_AddRefed<gfxASurface>
     CreateOptimalSurface(const gfxIntSize &aSize,
                          gfxASurface::gfxImageFormat imageFormat);
 
   virtual LayersBackend GetBackendType() { return LAYERS_D3D9; }
   virtual void GetBackendName(nsAString& name) { name.AssignLiteral("Direct3D 9"); }
+  bool DeviceWasRemoved() { return deviceManager()->DeviceWasRemoved(); }
 
   /*
    * Helper methods.
    */
   void SetClippingEnabled(PRBool aEnabled);
 
   void SetShaderMode(DeviceManagerD3D9::ShaderMode aMode)
     { mDeviceManager->SetShaderMode(aMode); }
@@ -161,27 +164,30 @@ public:
   Nv3DVUtils *GetNv3DVUtils()  { return mDeviceManager ? mDeviceManager->GetNv3DVUtils() : NULL; } 
 
   /** 
    * Indicate whether 3D is enabled or not 
    */ 
   PRBool Is3DEnabled() { return mIs3DEnabled; } 
 
   static void OnDeviceManagerDestroy(DeviceManagerD3D9 *aDeviceManager) {
-    if(aDeviceManager == mDeviceManager)
-      mDeviceManager = nsnull;
+    if(aDeviceManager == mDefaultDeviceManager)
+      mDefaultDeviceManager = nsnull;
   }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() const { return "D3D9"; }
 #endif // MOZ_LAYERS_HAVE_LOG
 
 private:
-  /* Device manager instance */
-  static DeviceManagerD3D9 *mDeviceManager;
+  /* Default device manager instance */
+  static DeviceManagerD3D9 *mDefaultDeviceManager;
+
+  /* Device manager instance for this layer manager */
+  nsRefPtr<DeviceManagerD3D9> mDeviceManager;
 
   /* Swap chain associated with this layer manager */
   nsRefPtr<SwapChainD3D9> mSwapChain;
 
   /* Widget associated with this layer manager */
   nsIWidget *mWidget;
 
   /*
@@ -234,16 +240,19 @@ public:
   virtual void RenderLayer() = 0;
 
   /* This function may be used on device resets to clear all VRAM resources
    * that a layer might be using.
    */
   virtual void CleanResources() {}
 
   IDirect3DDevice9 *device() const { return mD3DManager->device(); }
+
+  /* Called by the layer manager when it's destroyed */
+  virtual void LayerManagerDestroyed() {}
 protected:
   LayerManagerD3D9 *mD3DManager;
 };
 
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_LAYERMANAGERD3D9_H */
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -52,17 +52,17 @@ ThebesLayerD3D9::ThebesLayerD3D9(LayerMa
   , mD2DSurfaceInitialized(false)
 {
   mImplData = static_cast<LayerD3D9*>(this);
   aManager->deviceManager()->mLayersWithResources.AppendElement(this);
 }
 
 ThebesLayerD3D9::~ThebesLayerD3D9()
 {
-  if (mD3DManager->deviceManager()) {
+  if (mD3DManager) {
     mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this);
   }
 }
 
 /**
  * Retention threshold - amount of pixels intersection required to enable
  * layer content retention. This is a guesstimate. Profiling could be done to
  * figure out the optimal threshold.
@@ -270,16 +270,23 @@ ThebesLayerD3D9::RenderLayer()
 }
 
 void
 ThebesLayerD3D9::CleanResources()
 {
   mTexture = nsnull;
 }
 
+void
+ThebesLayerD3D9::LayerManagerDestroyed()
+{
+  mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this);
+  mD3DManager = nsnull;
+}
+
 Layer*
 ThebesLayerD3D9::GetLayer()
 {
   return this;
 }
 
 PRBool
 ThebesLayerD3D9::IsEmpty()
--- a/gfx/layers/d3d9/ThebesLayerD3D9.h
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.h
@@ -58,16 +58,17 @@ public:
   /* ThebesLayer implementation */
   void InvalidateRegion(const nsIntRegion& aRegion);
 
   /* LayerD3D9 implementation */
   Layer* GetLayer();
   virtual PRBool IsEmpty();
   virtual void RenderLayer();
   virtual void CleanResources();
+  virtual void LayerManagerDestroyed();
 
 private:
   /*
    * D3D9 texture
    */
   nsRefPtr<IDirect3DTexture9> mTexture;
 
   /* Checks if our D2D surface has the right content type */
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -207,187 +207,23 @@ gfxWindowsPlatform::gfxWindowsPlatform()
     CoInitialize(NULL); 
 
     mScreenDC = GetDC(NULL);
 
 #ifdef MOZ_FT2_FONTS
     FT_Init_FreeType(&gPlatformFTLibrary);
 #endif
 
-/* Pick the default render mode differently between
- * desktop, Windows Mobile, and Windows CE.
- */
-#if defined(WINCE_WINDOWS_MOBILE)
-    mRenderMode = RENDER_IMAGE_DDRAW16;
-#elif defined(WINCE)
-    mRenderMode = RENDER_DDRAW_GL;
-#else
-    mRenderMode = RENDER_GDI;
-#endif
-
-    nsCOMPtr<nsIPrefBranch2> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
-    
-    OSVERSIONINFOA versionInfo;
-    versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
-    ::GetVersionExA(&versionInfo);
-    bool isVistaOrHigher = versionInfo.dwMajorVersion >= 6;
-
-    PRBool safeMode = PR_FALSE;
-    nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
-    if (xr)
-      xr->GetInSafeMode(&safeMode);
-
 #ifdef CAIRO_HAS_D2D_SURFACE
-    PRBool d2dDisabled = PR_FALSE;
-    PRBool d2dBlocked = PR_FALSE;
-
-    nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
-    if (gfxInfo) {
-        PRInt32 status;
-        if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) {
-            if (status != nsIGfxInfo::FEATURE_STATUS_UNKNOWN &&
-                status != nsIGfxInfo::FEATURE_AVAILABLE)
-            {
-                d2dDisabled = PR_TRUE;
-                if (status == nsIGfxInfo::FEATURE_BLOCKED) {
-                    d2dBlocked = PR_TRUE;
-                }
-            }
-        }
-    }
-
     NS_RegisterMemoryReporter(new D2DCacheReporter());
     NS_RegisterMemoryReporter(new D2DVRAMReporter());
-    mD2DDevice = NULL;
-
-    nsresult rv = pref->GetBoolPref("gfx.direct2d.disabled", &d2dDisabled);
-    if (NS_FAILED(rv))
-        d2dDisabled = PR_FALSE;
-
-    if (isVistaOrHigher && !d2dDisabled && !d2dBlocked && !safeMode) {
-        // We need a DWriteFactory to work.
-        HMODULE d3d10module = LoadLibraryA("d3d10_1.dll");
-        D3D10CreateDevice1Func createD3DDevice = (D3D10CreateDevice1Func)
-            GetProcAddress(d3d10module, "D3D10CreateDevice1");
-        nsRefPtr<ID3D10Device1> device;
-
-        if (createD3DDevice) {
-            // We try 10.0 first even though we prefer 10.1, since we want to
-            // fail as fast as possible if 10.x isn't supported.
-            HRESULT hr = createD3DDevice(
-	        NULL, 
-	        D3D10_DRIVER_TYPE_HARDWARE,
-	        NULL,
-	        D3D10_CREATE_DEVICE_BGRA_SUPPORT |
-	        D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
-	        D3D10_FEATURE_LEVEL_10_0,
-	        D3D10_1_SDK_VERSION,
-	        getter_AddRefs(device));
-
-            if (SUCCEEDED(hr)) {
-                // We have 10.0, let's try 10.1.
-                // XXX - This adds an additional 10-20ms for people who are
-                // getting direct2d. We'd really like to do something more
-                // clever.
-                nsRefPtr<ID3D10Device1> device1;
-                hr = createD3DDevice(
-	            NULL, 
-	            D3D10_DRIVER_TYPE_HARDWARE,
-	            NULL,
-	            D3D10_CREATE_DEVICE_BGRA_SUPPORT |
-	            D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
-	            D3D10_FEATURE_LEVEL_10_1,
-	            D3D10_1_SDK_VERSION,
-	            getter_AddRefs(device1));
-
-                if (SUCCEEDED(hr)) {
-                    device = device1;
-                }
-
-                mD2DDevice = cairo_d2d_create_device_from_d3d10device(device);
-                if (mD2DDevice) {
-                    mRenderMode = RENDER_DIRECT2D;
-                }
-            }
-        }
-    }
+    mD2DDevice = nsnull;
 #endif
 
-#ifdef CAIRO_HAS_DWRITE_FONT
-    PRBool useDirectWrite = PR_FALSE;
-
-    rv = pref->GetBoolPref(
-        "gfx.font_rendering.directwrite.enabled", &useDirectWrite);
-    if (NS_FAILED(rv)) {
-        useDirectWrite = PR_FALSE;
-    }
-
-    // Enable when it's preffed on -and- we're using Vista or higher. Or when
-    // we're going to use D2D.
-    if ((useDirectWrite && isVistaOrHigher) || mRenderMode == RENDER_DIRECT2D) {
-        DWriteCreateFactoryFunc createDWriteFactory = (DWriteCreateFactoryFunc)
-            GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory");
-
-        if (createDWriteFactory) {
-            /**
-             * I need a direct pointer to be able to cast to IUnknown**, I also
-             * need to remember to release this because the nsRefPtr will
-             * AddRef it.
-             */
-            IDWriteFactory *factory;
-            HRESULT hr = createDWriteFactory(
-                DWRITE_FACTORY_TYPE_SHARED,
-                __uuidof(IDWriteFactory),
-                reinterpret_cast<IUnknown**>(&factory));
-            mDWriteFactory = factory;
-            factory->Release();
-        }
-    }
-#endif
-
-    PRInt32 rmode;
-    if (!safeMode &&
-	NS_SUCCEEDED(pref->GetIntPref("mozilla.widget.render-mode", &rmode))) {
-        if (rmode >= 0 && rmode < RENDER_MODE_MAX) {
-#ifdef CAIRO_HAS_DWRITE_FONT
-            if (rmode != RENDER_DIRECT2D && !useDirectWrite) {
-                mDWriteFactory = nsnull;
-            }
-#endif
-#ifndef CAIRO_HAS_DDRAW_SURFACE
-            if (rmode == RENDER_DDRAW || rmode == RENDER_DDRAW_GL)
-                rmode = RENDER_IMAGE_STRETCH24;
-#endif
-            if (rmode == RENDER_DIRECT2D) {
-#ifndef CAIRO_HAS_D2D_SURFACE
-                return;
-#else
-                if (d2dBlocked) {
-                    return;
-                }
-
-                if (!mD2DDevice) {
-                    mD2DDevice = cairo_d2d_create_device();
-                    if (!mD2DDevice) {
-                        return;
-                    }
-                }
-#ifdef CAIRO_HAS_DWRITE_FONT
-                if (!GetDWriteFactory()) {
-#endif
-                    // D2D doesn't work without DirectWrite.
-                    return;
-#ifdef CAIRO_HAS_DWRITE_FONT
-                }
-#endif
-#endif
-            }
-            mRenderMode = (RenderMode) rmode;
-        }
-    }
+    UpdateRenderMode();
 }
 
 gfxWindowsPlatform::~gfxWindowsPlatform()
 {
     ::ReleaseDC(NULL, mScreenDC);
     // not calling FT_Done_FreeType because cairo may still hold references to
     // these FT_Faces.  See bug 458169.
 #ifdef CAIRO_HAS_D2D_SURFACE
@@ -398,16 +234,183 @@ gfxWindowsPlatform::~gfxWindowsPlatform(
 
     /* 
      * Uninitialize COM 
      */ 
     CoUninitialize(); 
 
 }
 
+void
+gfxWindowsPlatform::UpdateRenderMode()
+{
+/* Pick the default render mode differently between
+ * desktop, Windows Mobile, and Windows CE.
+ */
+#if defined(WINCE_WINDOWS_MOBILE)
+    mRenderMode = RENDER_IMAGE_DDRAW16;
+#elif defined(WINCE)
+    mRenderMode = RENDER_DDRAW_GL;
+#else
+    mRenderMode = RENDER_GDI;
+#endif
+
+    OSVERSIONINFOA versionInfo;
+    versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+    ::GetVersionExA(&versionInfo);
+    bool isVistaOrHigher = versionInfo.dwMajorVersion >= 6;
+
+    PRBool safeMode = PR_FALSE;
+    nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
+    if (xr)
+      xr->GetInSafeMode(&safeMode);
+
+    nsCOMPtr<nsIPrefBranch2> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
+    nsresult rv;
+
+    PRBool preferDirectWrite = PR_FALSE;
+
+    rv = pref->GetBoolPref(
+        "gfx.font_rendering.directwrite.enabled", &preferDirectWrite);
+    if (NS_FAILED(rv)) {
+        preferDirectWrite = PR_FALSE;
+    }
+
+    mUseDirectWrite = preferDirectWrite;
+
+#ifdef CAIRO_HAS_D2D_SURFACE
+    PRBool d2dDisabled = PR_FALSE;
+    PRBool d2dForceEnabled = PR_FALSE;
+    PRBool d2dBlocked = PR_FALSE;
+
+    nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
+    if (gfxInfo) {
+        PRInt32 status;
+        if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) {
+            if (status != nsIGfxInfo::FEATURE_STATUS_UNKNOWN &&
+                status != nsIGfxInfo::FEATURE_AVAILABLE)
+            {
+                d2dDisabled = PR_TRUE;
+                if (status == nsIGfxInfo::FEATURE_BLOCKED) {
+                    d2dBlocked = PR_TRUE;
+                }
+            }
+        }
+    }
+
+    rv = pref->GetBoolPref("gfx.direct2d.disabled", &d2dDisabled);
+    if (NS_FAILED(rv))
+        d2dDisabled = PR_FALSE;
+    rv = pref->GetBoolPref("gfx.direct2d.force-enabled", &d2dForceEnabled);
+    if (NS_FAILED(rv))
+        d2dDisabled = PR_FALSE;
+
+    bool tryD2D = !d2dBlocked || d2dForceEnabled;
+    
+    // Do not ever try if d2d is explicitly disabled.
+    if (d2dDisabled) {
+        tryD2D = false;
+    }
+
+    if (isVistaOrHigher  && !safeMode && tryD2D) {
+        VerifyD2DDevice(d2dForceEnabled);
+        if (mD2DDevice) {
+            mRenderMode = RENDER_DIRECT2D;
+            mUseDirectWrite = PR_TRUE;
+        }
+    } else {
+        mD2DDevice = nsnull;
+    }
+#endif
+
+#ifdef CAIRO_HAS_DWRITE_FONT
+    // Enable when it's preffed on -and- we're using Vista or higher. Or when
+    // we're going to use D2D.
+    if (!mDWriteFactory && (mUseDirectWrite && isVistaOrHigher)) {
+        DWriteCreateFactoryFunc createDWriteFactory = (DWriteCreateFactoryFunc)
+            GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory");
+
+        if (createDWriteFactory) {
+            /**
+             * I need a direct pointer to be able to cast to IUnknown**, I also
+             * need to remember to release this because the nsRefPtr will
+             * AddRef it.
+             */
+            IDWriteFactory *factory;
+            HRESULT hr = createDWriteFactory(
+                DWRITE_FACTORY_TYPE_SHARED,
+                __uuidof(IDWriteFactory),
+                reinterpret_cast<IUnknown**>(&factory));
+            mDWriteFactory = factory;
+            factory->Release();
+        }
+    }
+#endif
+}
+
+void
+gfxWindowsPlatform::VerifyD2DDevice(PRBool aAttemptForce)
+{
+#ifdef CAIRO_HAS_D2D_SURFACE
+    if (mD2DDevice) {
+        ID3D10Device1 *device = cairo_d2d_device_get_device(mD2DDevice);
+
+        if (SUCCEEDED(device->GetDeviceRemovedReason())) {
+            return;
+        }
+        mD2DDevice = nsnull;
+    }
+
+    HMODULE d3d10module = LoadLibraryA("d3d10_1.dll");
+    D3D10CreateDevice1Func createD3DDevice = (D3D10CreateDevice1Func)
+        GetProcAddress(d3d10module, "D3D10CreateDevice1");
+    nsRefPtr<ID3D10Device1> device;
+
+    if (createD3DDevice) {
+        // We try 10.0 first even though we prefer 10.1, since we want to
+        // fail as fast as possible if 10.x isn't supported.
+        HRESULT hr = createD3DDevice(
+            NULL, 
+            D3D10_DRIVER_TYPE_HARDWARE,
+            NULL,
+            D3D10_CREATE_DEVICE_BGRA_SUPPORT |
+            D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
+            D3D10_FEATURE_LEVEL_10_0,
+            D3D10_1_SDK_VERSION,
+            getter_AddRefs(device));
+
+        if (SUCCEEDED(hr)) {
+            // We have 10.0, let's try 10.1.
+            // XXX - This adds an additional 10-20ms for people who are
+            // getting direct2d. We'd really like to do something more
+            // clever.
+            nsRefPtr<ID3D10Device1> device1;
+            hr = createD3DDevice(
+                NULL, 
+                D3D10_DRIVER_TYPE_HARDWARE,
+                NULL,
+                D3D10_CREATE_DEVICE_BGRA_SUPPORT |
+                D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
+                D3D10_FEATURE_LEVEL_10_1,
+                D3D10_1_SDK_VERSION,
+                getter_AddRefs(device1));
+
+            if (SUCCEEDED(hr)) {
+                device = device1;
+            }
+
+            mD2DDevice = cairo_d2d_create_device_from_d3d10device(device);
+        }
+    }
+
+    if (!mD2DDevice && aAttemptForce) {
+        mD2DDevice = cairo_d2d_create_device();
+    }
+#endif
+}
 gfxPlatformFontList*
 gfxWindowsPlatform::CreatePlatformFontList()
 {
 #ifdef MOZ_FT2_FONTS
     return new gfxFT2FontList();
 #else
 #ifdef CAIRO_HAS_DWRITE_FONT
     if (!GetDWriteFactory()) {
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -144,16 +144,31 @@ public:
 
         /* max */
         RENDER_MODE_MAX
     };
 
     RenderMode GetRenderMode() { return mRenderMode; }
     void SetRenderMode(RenderMode rmode) { mRenderMode = rmode; }
 
+    /**
+     * Updates render mode with relation to the current preferences and
+     * available devices.
+     */
+    void UpdateRenderMode();
+
+    /**
+     * Verifies a D2D device is present and working, will attempt to create one
+     * it is non-functional or non-existant.
+     *
+     * \param aAttemptForce Attempt to force D2D cairo device creation by using
+     * cairo device creation routines.
+     */
+    void VerifyD2DDevice(PRBool aAttemptForce);
+
     HDC GetScreenDC() { return mScreenDC; }
 
     nsresult GetFontList(nsIAtom *aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts);
 
     nsresult UpdateFontList();
 
@@ -210,18 +225,18 @@ public:
         kWindows7 = 0x60001
     };
 
     static PRInt32 WindowsOSVersion();
 
     virtual void FontsPrefsChanged(nsIPrefBranch *aPrefBranch, const char *aPref);
 
 #ifdef CAIRO_HAS_DWRITE_FONT
-    IDWriteFactory *GetDWriteFactory() { return mDWriteFactory; }
-    inline PRBool DWriteEnabled() { return !!mDWriteFactory; }
+    IDWriteFactory *GetDWriteFactory() { return mUseDirectWrite ? mDWriteFactory : nsnull; }
+    inline PRBool DWriteEnabled() { return mUseDirectWrite; }
 #else
     inline PRBool DWriteEnabled() { return PR_FALSE; }
 #endif
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *GetD2DDevice() { return mD2DDevice; }
 #endif
 
 #ifdef MOZ_FT2_FONTS
@@ -233,16 +248,18 @@ protected:
 
     PRBool mUseClearTypeForDownloadableFonts;
     PRBool mUseClearTypeAlways;
     HDC mScreenDC;
 
 private:
     void Init();
 
+    PRBool mUseDirectWrite;
+
 #ifdef CAIRO_HAS_DWRITE_FONT
     nsRefPtr<IDWriteFactory> mDWriteFactory;
 #endif
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *mD2DDevice;
 #endif
 
     virtual qcms_profile* GetPlatformCMSOutputProfile();
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2336,17 +2336,17 @@ nsCSSFrameConstructor::ConstructDocEleme
     if (!xblService)
       return NS_ERROR_FAILURE;
 
     nsRefPtr<nsXBLBinding> binding;
     rv = xblService->LoadBindings(aDocElement, display->mBinding->mURI,
                                   display->mBinding->mOriginPrincipal,
                                   PR_FALSE, getter_AddRefs(binding),
                                   &resolveStyle);
-    if (NS_FAILED(rv))
+    if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
       return NS_OK; // Binding will load asynchronously.
 
     if (binding) {
       // For backwards compat, keep firing the root's constructor
       // after all of its kids' constructors.  So tell the binding
       // manager about it right now.
       mDocument->BindingManager()->AddToAttachedQueue(binding);
     }
@@ -5090,17 +5090,17 @@ nsCSSFrameConstructor::AddFrameConstruct
     if (!newPendingBinding) {
       return;
     }
     nsresult rv = xblService->LoadBindings(aContent, display->mBinding->mURI,
                                            display->mBinding->mOriginPrincipal,
                                            PR_FALSE,
                                            getter_AddRefs(newPendingBinding->mBinding),
                                            &resolveStyle);
-    if (NS_FAILED(rv))
+    if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
       return;
 
     if (newPendingBinding->mBinding) {
       pendingBinding = newPendingBinding;
       // aState takes over owning newPendingBinding
       aState.AddPendingBinding(newPendingBinding.forget());
     }
 
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -321,16 +321,18 @@ public:
   NS_DECL_ISUPPORTS
 
   // nsIContentViewer interface...
   NS_DECL_NSICONTENTVIEWER
 
   // nsIDocumentViewer interface...
   NS_IMETHOD GetPresShell(nsIPresShell** aResult);
   NS_IMETHOD GetPresContext(nsPresContext** aResult);
+  NS_IMETHOD SetDocumentInternal(nsIDocument* aDocument,
+                                 PRBool aForceReuseInnerWindow);
   /**
    * Find the view to use as the container view for MakeWindow. Returns
    * null if this will be the root of a view manager hierarchy. In that
    * case, if mParentWidget is null then this document should not even
    * be displayed.
    */
   virtual nsIView* FindContainerView();
 
@@ -947,17 +949,17 @@ DocumentViewerImpl::InitInternal(nsIWidg
     nsCOMPtr<nsPIDOMWindow> window;
     requestor->GetInterface(NS_GET_IID(nsPIDOMWindow),
                             getter_AddRefs(window));
 
     if (window) {
       nsCOMPtr<nsIDocument> curDoc =
         do_QueryInterface(window->GetExtantDocument());
       if (!mIsPageMode || curDoc != mDocument) {
-        window->SetNewDocument(mDocument, aState);
+        window->SetNewDocument(mDocument, aState, PR_FALSE);
         nsJSContext::LoadStart();
       }
     }
   }
 
   if (aDoCreation && mPresContext) {
     // The ViewManager and Root View was created above (in
     // MakeWindow())...
@@ -1677,55 +1679,62 @@ DocumentViewerImpl::SetDOMDocument(nsIDO
   // to the document.
 
   // XXX Right now, this method assumes that the layout of the current
   // document hasn't started yet.  More cleanup will probably be
   // necessary to make this method work for the case when layout *has*
   // occurred for the current document.
   // That work can happen when and if it is needed.
 
-  nsresult rv;
   if (!aDocument)
     return NS_ERROR_NULL_POINTER;
 
-  nsCOMPtr<nsIDocument> newDoc = do_QueryInterface(aDocument, &rv);
-  if (NS_FAILED(rv)) return rv;
+  nsCOMPtr<nsIDocument> newDoc = do_QueryInterface(aDocument);
+  NS_ENSURE_TRUE(newDoc, NS_ERROR_UNEXPECTED);
+
+  return SetDocumentInternal(newDoc, PR_FALSE);
+}
+
+NS_IMETHODIMP
+DocumentViewerImpl::SetDocumentInternal(nsIDocument* aDocument,
+                                        PRBool aForceReuseInnerWindow)
+{
 
   // Set new container
   nsCOMPtr<nsISupports> container = do_QueryReferent(mContainer);
-  newDoc->SetContainer(container);
-
-  if (mDocument != newDoc) {
+  aDocument->SetContainer(container);
+
+  if (mDocument != aDocument) {
     // Replace the old document with the new one. Do this only when
     // the new document really is a new document.
-    mDocument = newDoc;
+    mDocument = aDocument;
 
     // Set the script global object on the new document
     nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(container);
     if (window) {
-      window->SetNewDocument(newDoc, nsnull);
+      window->SetNewDocument(aDocument, nsnull, aForceReuseInnerWindow);
     }
 
     // Clear the list of old child docshells. CChild docshells for the new
     // document will be constructed as frames are created.
-    if (!newDoc->IsStaticDocument()) {
+    if (!aDocument->IsStaticDocument()) {
       nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(container);
       if (node) {
         PRInt32 count;
         node->GetChildCount(&count);
         for (PRInt32 i = 0; i < count; ++i) {
           nsCOMPtr<nsIDocShellTreeItem> child;
           node->GetChildAt(0, getter_AddRefs(child));
           node->RemoveChild(child);
         }
       }
     }
   }
 
-  rv = SyncParentSubDocMap();
+  nsresult rv = SyncParentSubDocMap();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Replace the current pres shell with a new shell for the new document
 
   nsCOMPtr<nsILinkHandler> linkHandler;
   if (mPresShell) {
     nsSize currentSize(0, 0);
 
--- a/layout/base/nsIDocumentViewer.h
+++ b/layout/base/nsIDocumentViewer.h
@@ -44,30 +44,33 @@
 
 class nsIDocument;
 class nsPresContext;
 class nsIPresShell;
 class nsIStyleSheet;
 class nsIView;
 
 #define NS_IDOCUMENT_VIEWER_IID \
-  { 0x79c0bdbf, 0xf508, 0x4970, \
-    { 0x94, 0x65, 0x03, 0x5e, 0xda, 0x2c, 0x02, 0x72 } }
+  { 0x5a5c9a1d, 0x49c4, 0x4f3f, \
+    { 0x80, 0xcd, 0x12, 0x09, 0x5b, 0x1e, 0x1f, 0x61 } }
 
 /**
  * A document viewer is a kind of content viewer that uses NGLayout
  * to manage the presentation of the content.
  */
 class nsIDocumentViewer : public nsIContentViewer
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_VIEWER_IID)
   
   NS_IMETHOD GetPresShell(nsIPresShell** aResult) = 0;
   
   NS_IMETHOD GetPresContext(nsPresContext** aResult) = 0;
 
+  NS_IMETHOD SetDocumentInternal(nsIDocument* aDocument,
+                                 PRBool aForceReuseInnerWindow) = 0;
+
   virtual nsIView* FindContainerView() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentViewer, NS_IDOCUMENT_VIEWER_IID)
 
 #endif /* nsIDocumentViewer_h___ */
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3197,33 +3197,33 @@ pref("network.tcp.sendbuffer", 131072);
 #endif
 #endif
 
 #ifdef WINCE
 pref("mozilla.widget.disable-native-theme", true);
 pref("gfx.color_management.mode", 0);
 #endif
 
-// Initialize default render-mode.
-pref("mozilla.widget.render-mode", -1);
-
 // Default value of acceleration for all widgets.
 #ifdef XP_WIN
 pref("layers.accelerate-all", true);
 #else
 pref("layers.accelerate-all", false);
 #endif
 
 // Whether to allow acceleration on layers at all.
 pref("layers.accelerate-none", false);
 
 #ifdef XP_WIN
 #ifndef WINCE
 // Whether to disable the automatic detection and use of direct2d.
 pref("gfx.direct2d.disabled", false);
+// Whether to attempt to enable Direct2D regardless of automatic detection or
+// blacklisting
+pref("gfx.direct2d.force-enabled", false);
 
 pref("layers.prefer-opengl", false);
 #endif
 #endif
 
 // Enable/Disable the geolocation API for content
 pref("geo.enabled", true);
 
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -1548,35 +1548,32 @@ nsCacheService::OpenCacheEntry(nsCacheSe
                                           accessRequested,
                                           blockingMode,
                                           listener,
                                           &request);
     if (NS_FAILED(rv))  return rv;
 
     CACHE_LOG_DEBUG(("Created request %p\n", request));
 
-#if 0 // Disabled because of bug 589296
     // Process the request on the background thread if we are on the main thread
     // and the the request is asynchronous
     if (NS_IsMainThread() && listener && gService->mCacheIOThread) {
         nsCOMPtr<nsIRunnable> ev =
             new nsProcessRequestEvent(request);
         if (ev) {
             rv = gService->mCacheIOThread->Dispatch(ev, NS_DISPATCH_NORMAL);
         } else {
             rv = NS_ERROR_OUT_OF_MEMORY;
         }
 
         // delete request if we didn't post the event
         if (NS_FAILED(rv))
             delete request;
     }
-    else 
-#endif
-    {
+    else {
         rv = gService->ProcessRequest(request, PR_TRUE, result);
 
         // delete requests that have completed
         if (!(listener && (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION)))
             delete request;
     }
 
     return rv;
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -58,16 +58,17 @@ namespace net {
 
 HttpBaseChannel::HttpBaseChannel()
   : mStartPos(LL_MAXUINT)
   , mStatus(NS_OK)
   , mLoadFlags(LOAD_NORMAL)
   , mPriority(PRIORITY_NORMAL)
   , mCaps(0)
   , mRedirectionLimit(gHttpHandler->RedirectionLimit())
+  , mApplyConversion(PR_TRUE)
   , mCanceled(PR_FALSE)
   , mIsPending(PR_FALSE)
   , mWasOpened(PR_FALSE)
   , mResponseHeadersModified(PR_FALSE)
   , mAllowPipelining(PR_TRUE)
   , mForceAllowThirdPartyCookie(PR_FALSE)
   , mUploadStreamHasHeaders(PR_FALSE)
   , mInheritApplicationCache(PR_TRUE)
@@ -152,20 +153,21 @@ HttpBaseChannel::Init(nsIURI *aURI,
 
   return rv;
 }
 
 //-----------------------------------------------------------------------------
 // HttpBaseChannel::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS_INHERITED7(HttpBaseChannel,
+NS_IMPL_ISUPPORTS_INHERITED8(HttpBaseChannel,
                              nsHashPropertyBag, 
                              nsIRequest,
                              nsIChannel,
+                             nsIEncodedChannel,
                              nsIHttpChannel,
                              nsIHttpChannelInternal,
                              nsIUploadChannel,
                              nsIUploadChannel2,
                              nsISupportsPriority)
 
 //-----------------------------------------------------------------------------
 // HttpBaseChannel::nsIRequest
@@ -370,17 +372,17 @@ HttpBaseChannel::GetContentLength(PRInt3
   // XXX truncates to 32 bit
   *aContentLength = mResponseHead->ContentLength();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::SetContentLength(PRInt32 value)
 {
-  NS_NOTYETIMPLEMENTED("nsHttpChannel::SetContentLength");
+  NS_NOTYETIMPLEMENTED("HttpBaseChannel::SetContentLength");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::Open(nsIInputStream **aResult)
 {
   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
   return NS_ImplementChannelOpen(this, aResult);
@@ -481,16 +483,229 @@ HttpBaseChannel::ExplicitSetUploadStream
   }
 
   mUploadStreamHasHeaders = aStreamHasHeaders;
   mUploadStream = aStream;
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
+// HttpBaseChannel::nsIEncodedChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+HttpBaseChannel::GetApplyConversion(PRBool *value)
+{
+  *value = mApplyConversion;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetApplyConversion(PRBool value)
+{
+  LOG(("HttpBaseChannel::SetApplyConversion [this=%p value=%d]\n", this, value));
+  mApplyConversion = value;
+  return NS_OK;
+}
+
+nsresult
+HttpBaseChannel::ApplyContentConversions()
+{
+  if (!mResponseHead)
+    return NS_OK;
+
+  LOG(("nsHttpChannel::ApplyContentConversions [this=%p]\n", this));
+
+  if (!mApplyConversion) {
+    LOG(("not applying conversion per mApplyConversion\n"));
+    return NS_OK;
+  }
+
+  const char *val = mResponseHead->PeekHeader(nsHttp::Content_Encoding);
+  if (gHttpHandler->IsAcceptableEncoding(val)) {
+    nsCOMPtr<nsIStreamConverterService> serv;
+    nsresult rv = gHttpHandler->
+            GetStreamConverterService(getter_AddRefs(serv));
+    // we won't fail to load the page just because we couldn't load the
+    // stream converter service.. carry on..
+    if (NS_SUCCEEDED(rv)) {
+      nsCOMPtr<nsIStreamListener> converter;
+      nsCAutoString from(val);
+      ToLowerCase(from);
+      rv = serv->AsyncConvertData(from.get(),
+                                  "uncompressed",
+                                  mListener,
+                                  mListenerContext,
+                                  getter_AddRefs(converter));
+      if (NS_SUCCEEDED(rv)) {
+        LOG(("converter installed from \'%s\' to \'uncompressed\'\n", val));
+        mListener = converter;
+      }
+    }
+  } else if (val != nsnull) {
+    LOG(("Unknown content encoding '%s', ignoring\n", val));
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings)
+{
+  if (!mResponseHead) {
+    *aEncodings = nsnull;
+    return NS_OK;
+  }
+    
+  const char *encoding = mResponseHead->PeekHeader(nsHttp::Content_Encoding);
+  if (!encoding) {
+    *aEncodings = nsnull;
+    return NS_OK;
+  }
+  nsContentEncodings* enumerator = new nsContentEncodings(this, encoding);
+  NS_ADDREF(*aEncodings = enumerator);
+  return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// HttpBaseChannel::nsContentEncodings <public>
+//-----------------------------------------------------------------------------
+
+HttpBaseChannel::nsContentEncodings::nsContentEncodings(nsIHttpChannel* aChannel,
+                                                        const char* aEncodingHeader)
+  : mEncodingHeader(aEncodingHeader)
+  , mChannel(aChannel)
+  , mReady(PR_FALSE)
+{
+  mCurEnd = aEncodingHeader + strlen(aEncodingHeader);
+  mCurStart = mCurEnd;
+}
+    
+HttpBaseChannel::nsContentEncodings::~nsContentEncodings()
+{
+}
+
+//-----------------------------------------------------------------------------
+// HttpBaseChannel::nsContentEncodings::nsISimpleEnumerator
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+HttpBaseChannel::nsContentEncodings::HasMore(PRBool* aMoreEncodings)
+{
+  if (mReady) {
+    *aMoreEncodings = PR_TRUE;
+    return NS_OK;
+  }
+
+  nsresult rv = PrepareForNext();
+  *aMoreEncodings = NS_SUCCEEDED(rv);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::nsContentEncodings::GetNext(nsACString& aNextEncoding)
+{
+  aNextEncoding.Truncate();
+  if (!mReady) {
+    nsresult rv = PrepareForNext();
+    if (NS_FAILED(rv)) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+
+  const nsACString & encoding = Substring(mCurStart, mCurEnd);
+
+  nsACString::const_iterator start, end;
+  encoding.BeginReading(start);
+  encoding.EndReading(end);
+
+  PRBool haveType = PR_FALSE;
+  if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("gzip"), start, end)) {
+    aNextEncoding.AssignLiteral(APPLICATION_GZIP);
+    haveType = PR_TRUE;
+  }
+
+  if (!haveType) {
+    encoding.BeginReading(start);
+    if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("compress"), start, end)) {
+      aNextEncoding.AssignLiteral(APPLICATION_COMPRESS);
+      haveType = PR_TRUE;
+    }
+  }
+    
+  if (!haveType) {
+    encoding.BeginReading(start);
+    if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("deflate"), start, end)) {
+      aNextEncoding.AssignLiteral(APPLICATION_ZIP);
+      haveType = PR_TRUE;
+    }
+  }
+
+  // Prepare to fetch the next encoding
+  mCurEnd = mCurStart;
+  mReady = PR_FALSE;
+  
+  if (haveType)
+    return NS_OK;
+
+  NS_WARNING("Unknown encoding type");
+  return NS_ERROR_FAILURE;
+}
+
+//-----------------------------------------------------------------------------
+// HttpBaseChannel::nsContentEncodings::nsISupports
+//-----------------------------------------------------------------------------
+
+NS_IMPL_ISUPPORTS1(HttpBaseChannel::nsContentEncodings, nsIUTF8StringEnumerator)
+
+//-----------------------------------------------------------------------------
+// HttpBaseChannel::nsContentEncodings <private>
+//-----------------------------------------------------------------------------
+
+nsresult
+HttpBaseChannel::nsContentEncodings::PrepareForNext(void)
+{
+  NS_ASSERTION(mCurStart == mCurEnd, "Indeterminate state");
+    
+  // At this point both mCurStart and mCurEnd point to somewhere
+  // past the end of the next thing we want to return
+    
+  while (mCurEnd != mEncodingHeader) {
+    --mCurEnd;
+    if (*mCurEnd != ',' && !nsCRT::IsAsciiSpace(*mCurEnd))
+      break;
+  }
+  if (mCurEnd == mEncodingHeader)
+    return NS_ERROR_NOT_AVAILABLE; // no more encodings
+  ++mCurEnd;
+        
+  // At this point mCurEnd points to the first char _after_ the
+  // header we want.  Furthermore, mCurEnd - 1 != mEncodingHeader
+    
+  mCurStart = mCurEnd - 1;
+  while (mCurStart != mEncodingHeader &&
+         *mCurStart != ',' && !nsCRT::IsAsciiSpace(*mCurStart))
+    --mCurStart;
+  if (*mCurStart == ',' || nsCRT::IsAsciiSpace(*mCurStart))
+    ++mCurStart; // we stopped because of a weird char, so move up one
+        
+  // At this point mCurStart and mCurEnd bracket the encoding string
+  // we want.  Check that it's not "identity"
+  if (Substring(mCurStart, mCurEnd).Equals("identity",
+                                           nsCaseInsensitiveCStringComparator())) {
+    mCurEnd = mCurStart;
+    return PrepareForNext();
+  }
+        
+  mReady = PR_TRUE;
+  return NS_OK;
+}
+
+
+//-----------------------------------------------------------------------------
 // HttpBaseChannel::nsIHttpChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpBaseChannel::GetRequestMethod(nsACString& aMethod)
 {
   aMethod = mRequestHead.Method();
   return NS_OK;
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -43,22 +43,24 @@
 
 #include "nsHttp.h"
 #include "nsAutoPtr.h"
 #include "nsHashPropertyBag.h"
 #include "nsProxyInfo.h"
 #include "nsHttpRequestHead.h"
 #include "nsHttpResponseHead.h"
 #include "nsHttpConnectionInfo.h"
+#include "nsIEncodedChannel.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIUploadChannel.h"
 #include "nsIUploadChannel2.h"
 #include "nsIProgressEventSink.h"
 #include "nsIURI.h"
+#include "nsIStringEnumerator.h"
 #include "nsISupportsPriority.h"
 #include "nsIApplicationCache.h"
 #include "nsIResumableChannel.h"
 
 #define DIE_WITH_ASYNC_OPEN_MSG()                                              \
   do {                                                                         \
     fprintf(stderr,                                                            \
             "*&*&*&*&*&*&*&**&*&&*& FATAL ERROR: '%s' "                        \
@@ -86,16 +88,17 @@ typedef enum { eUploadStream_null = -1,
 /*
  * This class is a partial implementation of nsIHttpChannel.  It contains code
  * shared by nsHttpChannel and HttpChannelChild. 
  * - Note that this class has nothing to do with nsBaseChannel, which is an
  *   earlier effort at a base class for channels that somehow never made it all
  *   the way to the HTTP channel.
  */
 class HttpBaseChannel : public nsHashPropertyBag
+                      , public nsIEncodedChannel
                       , public nsIHttpChannel
                       , public nsIHttpChannelInternal
                       , public nsIUploadChannel
                       , public nsIUploadChannel2
                       , public nsISupportsPriority
                       , public nsIResumableChannel
 {
 public:
@@ -128,16 +131,21 @@ public:
   NS_IMETHOD GetContentType(nsACString& aContentType);
   NS_IMETHOD SetContentType(const nsACString& aContentType);
   NS_IMETHOD GetContentCharset(nsACString& aContentCharset);
   NS_IMETHOD SetContentCharset(const nsACString& aContentCharset);
   NS_IMETHOD GetContentLength(PRInt32 *aContentLength);
   NS_IMETHOD SetContentLength(PRInt32 aContentLength);
   NS_IMETHOD Open(nsIInputStream **aResult);
 
+  // nsIEncodedChannel
+  NS_IMETHOD GetApplyConversion(PRBool *value);
+  NS_IMETHOD SetApplyConversion(PRBool value);
+  NS_IMETHOD GetContentEncodings(nsIUTF8StringEnumerator** aEncodings);
+
   // HttpBaseChannel::nsIHttpChannel
   NS_IMETHOD GetRequestMethod(nsACString& aMethod);
   NS_IMETHOD SetRequestMethod(const nsACString& aMethod);
   NS_IMETHOD GetReferrer(nsIURI **referrer);
   NS_IMETHOD SetReferrer(nsIURI *referrer);
   NS_IMETHOD GetRequestHeader(const nsACString& aHeader, nsACString& aValue);
   NS_IMETHOD SetRequestHeader(const nsACString& aHeader, 
                               const nsACString& aValue, PRBool aMerge);
@@ -170,17 +178,43 @@ public:
 
   // nsISupportsPriority
   NS_IMETHOD GetPriority(PRInt32 *value);
   NS_IMETHOD AdjustPriority(PRInt32 delta);
 
   // nsIResumableChannel
   NS_IMETHOD GetEntityID(nsACString& aEntityID);
 
+  class nsContentEncodings : public nsIUTF8StringEnumerator
+    {
+    public:
+        NS_DECL_ISUPPORTS
+        NS_DECL_NSIUTF8STRINGENUMERATOR
+
+        nsContentEncodings(nsIHttpChannel* aChannel, const char* aEncodingHeader);
+        virtual ~nsContentEncodings();
+        
+    private:
+        nsresult PrepareForNext(void);
+        
+        // We do not own the buffer.  The channel owns it.
+        const char* mEncodingHeader;
+        const char* mCurStart;  // points to start of current header
+        const char* mCurEnd;  // points to end of current header
+        
+        // Hold a ref to our channel so that it can't go away and take the
+        // header with it.
+        nsCOMPtr<nsIHttpChannel> mChannel;
+        
+        PRPackedBool mReady;
+    };
+
 protected:
+  nsresult ApplyContentConversions();
+
   void AddCookiesToRequest();
   virtual nsresult SetupReplacementChannel(nsIURI *,
                                            nsIChannel *,
                                            PRBool preserveMethod);
 
   // Helper function to simplify getting notification callbacks.
   template <class T>
   void GetCallback(nsCOMPtr<T> &aResult)
@@ -217,16 +251,17 @@ protected:
   PRUint64                          mStartPos;
 
   nsresult                          mStatus;
   PRUint32                          mLoadFlags;
   PRInt16                           mPriority;
   PRUint8                           mCaps;
   PRUint8                           mRedirectionLimit;
 
+  PRUint32                          mApplyConversion            : 1;
   PRUint32                          mCanceled                   : 1;
   PRUint32                          mIsPending                  : 1;
   PRUint32                          mWasOpened                  : 1;
   PRUint32                          mResponseHeadersModified    : 1;
   PRUint32                          mAllowPipelining            : 1;
   PRUint32                          mForceAllowThirdPartyCookie : 1;
   PRUint32                          mUploadStreamHasHeaders     : 1;
   PRUint32                          mInheritApplicationCache    : 1;
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -134,17 +134,16 @@ NS_IMETHODIMP_(nsrefcnt) HttpChannelChil
 }
 
 NS_INTERFACE_MAP_BEGIN(HttpChannelChild)
   NS_INTERFACE_MAP_ENTRY(nsIRequest)
   NS_INTERFACE_MAP_ENTRY(nsIChannel)
   NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
   NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
   NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel)
-  NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
   NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
   NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
   NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
   NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
   NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
   NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
   NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAssociatedContentSecurity, GetAssociatedContentSecurity())
@@ -289,22 +288,27 @@ HttpChannelChild::OnStartRequest(const n
   mIsFromCache = isFromCache;
   mCacheEntryAvailable = cacheEntryAvailable;
   mCacheExpirationTime = cacheExpirationTime;
   mCachedCharset = cachedCharset;
 
   AutoEventEnqueuer ensureSerialDispatch(this);
 
   nsresult rv = mListener->OnStartRequest(this, mListenerContext);
-  if (NS_SUCCEEDED(rv)) {
-    if (mResponseHead)
-      SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
-  } else {
+  if (NS_FAILED(rv)) {
     Cancel(rv);
+    return;
   }
+
+  if (mResponseHead)
+    SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
+
+  rv = ApplyContentConversions();
+  if (NS_FAILED(rv))
+    Cancel(rv);
 }
 
 class DataAvailableEvent : public ChildChannelEvent
 {
  public:
   DataAvailableEvent(HttpChannelChild* child,
                      const nsCString& data,
                      const PRUint32& offset,
@@ -986,39 +990,16 @@ HttpChannelChild::IsFromCache(PRBool *va
   if (!mIsPending)
     return NS_ERROR_NOT_AVAILABLE;
 
   *value = mIsFromCache;
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
-// HttpChannelChild::nsIEncodedChannel
-//-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-HttpChannelChild::GetContentEncodings(nsIUTF8StringEnumerator **result)
-{
-  DROP_DEAD();
-}
-
-/* attribute boolean applyConversion; */
-NS_IMETHODIMP
-HttpChannelChild::GetApplyConversion(PRBool *aApplyConversion)
-{
-  DROP_DEAD();
-}
-
-NS_IMETHODIMP
-HttpChannelChild::SetApplyConversion(PRBool aApplyConversion)
-{
-  DROP_DEAD();
-}
-
-//-----------------------------------------------------------------------------
 // HttpChannelChild::nsIResumableChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpChannelChild::ResumeAt(PRUint64 startPos, const nsACString& entityID)
 {
   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
   mStartPos = startPos;
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -49,43 +49,40 @@
 #include "nsIStreamListener.h"
 #include "nsILoadGroup.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIProgressEventSink.h"
 #include "nsICacheInfoChannel.h"
 #include "nsIApplicationCache.h"
 #include "nsIApplicationCacheChannel.h"
-#include "nsIEncodedChannel.h"
 #include "nsIUploadChannel2.h"
 #include "nsIResumableChannel.h"
 #include "nsIProxiedChannel.h"
 #include "nsITraceableChannel.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIAssociatedContentSecurity.h"
 
 namespace mozilla {
 namespace net {
 
 class ChildChannelEvent;
 
 class HttpChannelChild : public PHttpChannelChild
                        , public HttpBaseChannel
                        , public nsICacheInfoChannel
-                       , public nsIEncodedChannel
                        , public nsIProxiedChannel
                        , public nsITraceableChannel
                        , public nsIApplicationCacheChannel
                        , public nsIAsyncVerifyRedirectCallback
                        , public nsIAssociatedContentSecurity
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSICACHEINFOCHANNEL
-  NS_DECL_NSIENCODEDCHANNEL
   NS_DECL_NSIPROXIEDCHANNEL
   NS_DECL_NSITRACEABLECHANNEL
   NS_DECL_NSIAPPLICATIONCACHECONTAINER
   NS_DECL_NSIAPPLICATIONCACHECHANNEL
   NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
   NS_DECL_NSIASSOCIATEDCONTENTSECURITY
 
   HttpChannelChild();
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -287,16 +287,20 @@ HttpChannelParent::OnStartRequest(nsIReq
 
   PRBool isFromCache = false;
   chan->IsFromCache(&isFromCache);
   PRUint32 expirationTime = nsICache::NO_EXPIRATION_TIME;
   chan->GetCacheTokenExpirationTime(&expirationTime);
   nsCString cachedCharset;
   chan->GetCacheTokenCachedCharset(cachedCharset);
 
+  nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(aRequest);
+  if (encodedChannel)
+    encodedChannel->SetApplyConversion(PR_FALSE);
+
   // Keep the cache entry for future use in RecvSetCacheTokenCachedCharset().
   // It could be already released by nsHttpChannel at that time.
   chan->GetCacheToken(getter_AddRefs(mCacheDescriptor));
 
   nsCString secInfoSerialization;
   nsCOMPtr<nsISupports> secInfoSupp;
   chan->GetSecurityInfo(getter_AddRefs(secInfoSupp));
   if (secInfoSupp) {
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -112,19 +112,20 @@ AutoRedirectVetoNotifier::ReportRedirect
 // nsHttpChannel <public>
 //-----------------------------------------------------------------------------
 
 nsHttpChannel::nsHttpChannel()
     : mLogicalOffset(0)
     , mCacheAccess(0)
     , mPostID(0)
     , mRequestTime(0)
+    , mOnCacheEntryAvailableCallback(nsnull)
+    , mAsyncCacheOpen(PR_FALSE)
     , mPendingAsyncCallOnResume(nsnull)
     , mSuspendCount(0)
-    , mApplyConversion(PR_TRUE)
     , mCachedContentIsValid(PR_FALSE)
     , mCachedContentIsPartial(PR_FALSE)
     , mTransactionReplaced(PR_FALSE)
     , mAuthRetryPending(PR_FALSE)
     , mResuming(PR_FALSE)
     , mInitedCacheEntry(PR_FALSE)
     , mCacheForOfflineUse(PR_FALSE)
     , mCachingOpportunistically(PR_FALSE)
@@ -222,33 +223,31 @@ nsHttpChannel::Connect(PRBool firstTime)
     }
 
     // ensure that we are using a valid hostname
     if (!net_IsValidHostName(nsDependentCString(mConnectionInfo->Host())))
         return NS_ERROR_UNKNOWN_HOST;
 
     // true when called from AsyncOpen
     if (firstTime) {
-        PRBool delayed = PR_FALSE;
-
         // are we offline?
         PRBool offline = gIOService->IsOffline();
         if (offline)
             mLoadFlags |= LOAD_ONLY_FROM_CACHE;
         else if (PL_strcmp(mConnectionInfo->ProxyType(), "unknown") == 0)
             return ResolveProxy();  // Lazily resolve proxy info
 
         // Don't allow resuming when cache must be used
         if (mResuming && (mLoadFlags & LOAD_ONLY_FROM_CACHE)) {
             LOG(("Resuming from cache is not supported yet"));
             return NS_ERROR_DOCUMENT_NOT_CACHED;
         }
 
         // open a cache entry for this channel...
-        rv = OpenCacheEntry(offline, &delayed);
+        rv = OpenCacheEntry();
 
         if (NS_FAILED(rv)) {
             LOG(("OpenCacheEntry failed [rv=%x]\n", rv));
             // if this channel is only allowed to pull from the cache, then
             // we must fail if we were unable to open a cache entry.
             if (mLoadFlags & LOAD_ONLY_FROM_CACHE) {
                 // If we have a fallback URI (and we're not already
                 // falling back), process the fallback asynchronously.
@@ -262,17 +261,17 @@ nsHttpChannel::Connect(PRBool firstTime)
 
         // if cacheForOfflineUse has been set, open up an offline cache
         // entry to update
         if (mCacheForOfflineUse) {
             rv = OpenOfflineCacheEntryForWriting();
             if (NS_FAILED(rv)) return rv;
         }
 
-        if (NS_SUCCEEDED(rv) && delayed)
+        if (NS_SUCCEEDED(rv) && mAsyncCacheOpen)
             return NS_OK;
     }
 
     // we may or may not have a cache entry at this point
     if (mCacheEntry) {
         // inspect the cache entry to determine whether or not we need to go
         // out to net to validate it.  this call sets mCachedContentIsValid
         // and may set request headers as required for cache validation.
@@ -295,32 +294,47 @@ nsHttpChannel::Connect(PRBool firstTime)
         else if (mLoadFlags & LOAD_ONLY_FROM_CACHE) {
             // the cache contains the requested resource, but it must be 
             // validated before we can reuse it.  since we are not allowed
             // to hit the net, there's nothing more to do.  the document
             // is effectively not in the cache.
             return NS_ERROR_DOCUMENT_NOT_CACHED;
         }
     }
+    else if (mLoadFlags & LOAD_ONLY_FROM_CACHE) {
+        // If we have a fallback URI (and we're not already
+        // falling back), process the fallback asynchronously.
+        if (!mFallbackChannel && !mFallbackKey.IsEmpty()) {
+            return AsyncCall(&nsHttpChannel::HandleAsyncFallback);
+        }
+        return NS_ERROR_DOCUMENT_NOT_CACHED;
+    }
 
     // check to see if authorization headers should be included
     mAuthProvider->AddAuthorizationHeaders();
 
     if (mLoadFlags & LOAD_NO_NETWORK_IO) {
         return NS_ERROR_DOCUMENT_NOT_CACHED;
     }
 
     // hit the net...
     rv = SetupTransaction();
     if (NS_FAILED(rv)) return rv;
 
     rv = gHttpHandler->InitiateTransaction(mTransaction, mPriority);
     if (NS_FAILED(rv)) return rv;
 
-    return mTransactionPump->AsyncRead(this, nsnull);
+    rv = mTransactionPump->AsyncRead(this, nsnull);
+    if (NS_FAILED(rv)) return rv;
+
+    PRUint32 suspendCount = mSuspendCount;
+    while (suspendCount--)
+        mTransactionPump->Suspend();
+
+    return NS_OK;
 }
 
 // called when Connect fails
 nsresult
 nsHttpChannel::AsyncAbort(nsresult status)
 {
     LOG(("nsHttpChannel::AsyncAbort [this=%p status=%x]\n", this, status));
 
@@ -657,57 +671,16 @@ nsHttpChannel::SetupTransaction()
         return rv;
     }
 
     rv = nsInputStreamPump::Create(getter_AddRefs(mTransactionPump),
                                    responseStream);
     return rv;
 }
 
-nsresult
-nsHttpChannel::ApplyContentConversions()
-{
-    if (!mResponseHead)
-        return NS_OK;
-
-    LOG(("nsHttpChannel::ApplyContentConversions [this=%p]\n", this));
-
-    if (!mApplyConversion) {
-        LOG(("not applying conversion per mApplyConversion\n"));
-        return NS_OK;
-    }
-
-    const char *val = mResponseHead->PeekHeader(nsHttp::Content_Encoding);
-    if (gHttpHandler->IsAcceptableEncoding(val)) {
-        nsCOMPtr<nsIStreamConverterService> serv;
-        nsresult rv = gHttpHandler->
-                GetStreamConverterService(getter_AddRefs(serv));
-        // we won't fail to load the page just because we couldn't load the
-        // stream converter service.. carry on..
-        if (NS_SUCCEEDED(rv)) {
-            nsCOMPtr<nsIStreamListener> converter;
-            nsCAutoString from(val);
-            ToLowerCase(from);
-            rv = serv->AsyncConvertData(from.get(),
-                                        "uncompressed",
-                                        mListener,
-                                        mListenerContext,
-                                        getter_AddRefs(converter));
-            if (NS_SUCCEEDED(rv)) {
-                LOG(("converter installed from \'%s\' to \'uncompressed\'\n", val));
-                mListener = converter;
-            }
-        }
-    } else if (val != nsnull) {
-        LOG(("Unknown content encoding '%s', ignoring\n", val));
-    }
-
-    return NS_OK;
-}
-
 // NOTE: This function duplicates code from nsBaseChannel. This will go away
 // once HTTP uses nsBaseChannel (part of bug 312760)
 static void
 CallTypeSniffers(void *aClosure, const PRUint8 *aData, PRUint32 aCount)
 {
   nsIChannel *chan = static_cast<nsIChannel*>(aClosure);
 
   const nsCOMArray<nsIContentSniffer>& sniffers =
@@ -1959,21 +1932,21 @@ IsSubRangeRequest(nsHttpRequestHead &aRe
     if (!aRequestHead.PeekHeader(nsHttp::Range))
         return PR_FALSE;
     nsCAutoString byteRange;
     aRequestHead.GetHeader(nsHttp::Range, byteRange);
     return !byteRange.EqualsLiteral("bytes=0-");
 }
 
 nsresult
-nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed)
+nsHttpChannel::OpenCacheEntry()
 {
     nsresult rv;
 
-    *delayed = PR_FALSE;
+    mAsyncCacheOpen = PR_FALSE;
     mLoadedFromApplicationCache = PR_FALSE;
 
     LOG(("nsHttpChannel::OpenCacheEntry [this=%p]", this));
 
     // make sure we're not abusing this function
     NS_PRECONDITION(!mCacheEntry, "cache entry already open");
 
     nsCAutoString cacheKey;
@@ -2000,33 +1973,20 @@ nsHttpChannel::OpenCacheEntry(PRBool off
 
     // Don't cache byte range requests which are subranges, only cache 0-
     // byte range requests.
     if (IsSubRangeRequest(mRequestHead))
         return NS_OK;
 
     GenerateCacheKey(mPostID, cacheKey);
 
-    // Get a cache session with appropriate storage policy
-    nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
-
     // Set the desired cache access mode accordingly...
     nsCacheAccessMode accessRequested;
-    if (offline || (mLoadFlags & INHIBIT_CACHING)) {
-        // If we have been asked to bypass the cache and not write to the
-        // cache, then don't use the cache at all.  Unless we're actually
-        // offline, which takes precedence over BYPASS_LOCAL_CACHE.
-        if (BYPASS_LOCAL_CACHE(mLoadFlags) && !offline)
-            return NS_ERROR_NOT_AVAILABLE;
-        accessRequested = nsICache::ACCESS_READ;
-    }
-    else if (BYPASS_LOCAL_CACHE(mLoadFlags))
-        accessRequested = nsICache::ACCESS_WRITE; // replace cache entry
-    else
-        accessRequested = nsICache::ACCESS_READ_WRITE; // normal browsing
+    rv = DetermineCacheAccess(&accessRequested);
+    if (NS_FAILED(rv)) return rv;
 
     if (!mApplicationCache && mInheritApplicationCache) {
         // Pick up an application cache from the notification
         // callbacks if available
         nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer;
         GetCallback(appCacheContainer);
 
         if (appCacheContainer) {
@@ -2045,134 +2005,240 @@ nsHttpChannel::OpenCacheEntry(PRBool off
             nsresult rv = appCacheService->ChooseApplicationCache
                 (cacheKey, getter_AddRefs(mApplicationCache));
             NS_ENSURE_SUCCESS(rv, rv);
         }
     }
 
     nsCOMPtr<nsICacheSession> session;
 
-    // Will be set to true if we've found the right session, but need
-    // to open the cache entry asynchronously.
-    PRBool waitingForValidation = PR_FALSE;
-
     // If we have an application cache, we check it first.
     if (mApplicationCache) {
         nsCAutoString appCacheClientID;
         mApplicationCache->GetClientID(appCacheClientID);
 
         nsCOMPtr<nsICacheService> serv =
             do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = serv->CreateSession(appCacheClientID.get(),
                                  nsICache::STORE_OFFLINE,
                                  nsICache::STREAM_BASED,
                                  getter_AddRefs(session));
         NS_ENSURE_SUCCESS(rv, rv);
 
-        // we'll try to synchronously open the cache entry... however,
-        // it may be in use and not yet validated, in which case we'll
-        // try asynchronously opening the cache entry.
-        //
-        // We open with ACCESS_READ only, because we don't want to
-        // overwrite the offline cache entry non-atomically.
-        // ACCESS_READ will prevent us from writing to the offline
-        // cache as a normal cache entry.
-        rv = session->OpenCacheEntry(cacheKey,
-                                     nsICache::ACCESS_READ, PR_FALSE,
-                                     getter_AddRefs(mCacheEntry));
-        if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
-            accessRequested = nsICache::ACCESS_READ;
-            waitingForValidation = PR_TRUE;
-            rv = NS_OK;
-        }
-
-        if (NS_FAILED(rv) && !mCacheForOfflineUse && !mFallbackChannel) {
-            // Check for namespace match.
-            nsCOMPtr<nsIApplicationCacheNamespace> namespaceEntry;
-            rv = mApplicationCache->GetMatchingNamespace
-                (cacheKey, getter_AddRefs(namespaceEntry));
-            NS_ENSURE_SUCCESS(rv, rv);
-
-            PRUint32 namespaceType = 0;
-            if (!namespaceEntry ||
-                NS_FAILED(namespaceEntry->GetItemType(&namespaceType)) ||
-                (namespaceType &
-                 (nsIApplicationCacheNamespace::NAMESPACE_FALLBACK |
-                  nsIApplicationCacheNamespace::NAMESPACE_OPPORTUNISTIC |
-                  nsIApplicationCacheNamespace::NAMESPACE_BYPASS)) == 0) {
-                // When loading from an application cache, only items
-                // on the whitelist or matching a
-                // fallback/opportunistic namespace should hit the
-                // network...
-                mLoadFlags |= LOAD_ONLY_FROM_CACHE;
-
-                // ... and if there were an application cache entry,
-                // we would have found it earlier.
-                return NS_ERROR_CACHE_KEY_NOT_FOUND;
+        if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY) {
+            // must use synchronous open for LOAD_BYPASS_LOCAL_CACHE_IF_BUSY
+            rv = session->OpenCacheEntry(cacheKey,
+                                         nsICache::ACCESS_READ, PR_FALSE,
+                                         getter_AddRefs(mCacheEntry));
+            if (NS_SUCCEEDED(rv)) {
+                mCacheEntry->GetAccessGranted(&mCacheAccess);
+                LOG(("nsHttpChannel::OpenCacheEntry [this=%p grantedAccess=%d]",
+                    this, mCacheAccess));
+                mLoadedFromApplicationCache = PR_TRUE;
+                return NS_OK;
+            } else if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
+                LOG(("bypassing local cache since it is busy\n"));
+                // Don't try to load normal cache entry
+                return NS_ERROR_NOT_AVAILABLE;
             }
-
-            if (namespaceType &
-                nsIApplicationCacheNamespace::NAMESPACE_FALLBACK) {
-                rv = namespaceEntry->GetData(mFallbackKey);
-                NS_ENSURE_SUCCESS(rv, rv);
-            }
-
-            if ((namespaceType &
-                 nsIApplicationCacheNamespace::NAMESPACE_OPPORTUNISTIC) &&
-                mLoadFlags & LOAD_DOCUMENT_URI) {
-                // Document loads for items in an opportunistic namespace
-                // should be placed in the offline cache.
-                nsCString clientID;
-                mApplicationCache->GetClientID(clientID);
-
-                mCacheForOfflineUse = !clientID.IsEmpty();
-                SetOfflineCacheClientID(clientID);
-                mCachingOpportunistically = PR_TRUE;
+        } else {
+            mOnCacheEntryAvailableCallback =
+                &nsHttpChannel::OnOfflineCacheEntryAvailable;
+            // We open with ACCESS_READ only, because we don't want to
+            // overwrite the offline cache entry non-atomically.
+            // ACCESS_READ will prevent us from writing to the offline
+            // cache as a normal cache entry.
+            rv = session->AsyncOpenCacheEntry(cacheKey,
+                                              nsICache::ACCESS_READ,
+                                              this);
+
+            if (NS_SUCCEEDED(rv)) {
+                mAsyncCacheOpen = PR_TRUE;
+                return NS_OK;
             }
         }
-        else if (NS_SUCCEEDED(rv)) {
-            // We successfully opened an offline cache session and the entry,
-            // now indiciate we load from the offline cache.
-            mLoadedFromApplicationCache = PR_TRUE;
+
+        // sync or async opening failed
+        return OnOfflineCacheEntryAvailable(nsnull, nsICache::ACCESS_NONE,
+                                            rv, PR_TRUE);
+    }
+
+    return OpenNormalCacheEntry(PR_TRUE);
+}
+
+nsresult
+nsHttpChannel::OnOfflineCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
+                                            nsCacheAccessMode aAccess,
+                                            nsresult aEntryStatus,
+                                            PRBool aIsSync)
+{
+    nsresult rv;
+
+    if (NS_SUCCEEDED(aEntryStatus)) {
+        // We successfully opened an offline cache session and the entry,
+        // so indicate we will load from the offline cache.
+        mLoadedFromApplicationCache = PR_TRUE;
+        mCacheEntry = aEntry;
+        mCacheAccess = aAccess;
+    }
+
+    if (mCanceled && NS_FAILED(mStatus)) {
+        LOG(("channel was canceled [this=%p status=%x]\n", this, mStatus));
+        return mStatus;
+    }
+
+    if (NS_SUCCEEDED(aEntryStatus))
+        // Called from OnCacheEntryAvailable, advance to the next state
+        return Connect(PR_FALSE);
+
+    if (!mCacheForOfflineUse && !mFallbackChannel) {
+        nsCAutoString cacheKey;
+        GenerateCacheKey(mPostID, cacheKey);
+
+        // Check for namespace match.
+        nsCOMPtr<nsIApplicationCacheNamespace> namespaceEntry;
+        rv = mApplicationCache->GetMatchingNamespace
+            (cacheKey, getter_AddRefs(namespaceEntry));
+        if (NS_FAILED(rv) && !aIsSync)
+            return Connect(PR_FALSE);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        PRUint32 namespaceType = 0;
+        if (!namespaceEntry ||
+            NS_FAILED(namespaceEntry->GetItemType(&namespaceType)) ||
+            (namespaceType &
+             (nsIApplicationCacheNamespace::NAMESPACE_FALLBACK |
+              nsIApplicationCacheNamespace::NAMESPACE_OPPORTUNISTIC |
+              nsIApplicationCacheNamespace::NAMESPACE_BYPASS)) == 0) {
+            // When loading from an application cache, only items
+            // on the whitelist or matching a
+            // fallback/opportunistic namespace should hit the
+            // network...
+            mLoadFlags |= LOAD_ONLY_FROM_CACHE;
+
+            // ... and if there were an application cache entry,
+            // we would have found it earlier.
+            return aIsSync ? NS_ERROR_CACHE_KEY_NOT_FOUND : Connect(PR_FALSE);
+        }
+
+        if (namespaceType &
+            nsIApplicationCacheNamespace::NAMESPACE_FALLBACK) {
+            rv = namespaceEntry->GetData(mFallbackKey);
+            if (NS_FAILED(rv) && !aIsSync)
+                return Connect(PR_FALSE);
+            NS_ENSURE_SUCCESS(rv, rv);
+        }
+
+        if ((namespaceType &
+             nsIApplicationCacheNamespace::NAMESPACE_OPPORTUNISTIC) &&
+            mLoadFlags & LOAD_DOCUMENT_URI) {
+            // Document loads for items in an opportunistic namespace
+            // should be placed in the offline cache.
+            nsCString clientID;
+            mApplicationCache->GetClientID(clientID);
+
+            mCacheForOfflineUse = !clientID.IsEmpty();
+            SetOfflineCacheClientID(clientID);
+            mCachingOpportunistically = PR_TRUE;
         }
     }
 
-    if (!mCacheEntry && !waitingForValidation) {
-        rv = gHttpHandler->GetCacheSession(storagePolicy,
-                                           getter_AddRefs(session));
-        if (NS_FAILED(rv)) return rv;
-
+    return OpenNormalCacheEntry(aIsSync);
+}
+
+
+nsresult
+nsHttpChannel::OpenNormalCacheEntry(PRBool aIsSync)
+{
+    NS_ASSERTION(!mCacheEntry, "We have already mCacheEntry");
+
+    nsresult rv;
+
+    nsCAutoString cacheKey;
+    GenerateCacheKey(mPostID, cacheKey);
+
+    nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
+
+    nsCOMPtr<nsICacheSession> session;
+    rv = gHttpHandler->GetCacheSession(storagePolicy,
+                                       getter_AddRefs(session));
+    if (NS_FAILED(rv)) return rv;
+
+    nsCacheAccessMode accessRequested;
+    rv = DetermineCacheAccess(&accessRequested);
+    if (NS_FAILED(rv)) return rv;
+
+    if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY) {
+        if (!aIsSync) {
+            // Unexpected state: we were called from OnCacheEntryAvailable(),
+            // so LOAD_BYPASS_LOCAL_CACHE_IF_BUSY shouldn't be set. Unless
+            // somebody altered mLoadFlags between OpenCacheEntry() and
+            // OnCacheEntryAvailable()...
+            NS_WARNING(
+                "OpenNormalCacheEntry() called from OnCacheEntryAvailable() "
+                "when LOAD_BYPASS_LOCAL_CACHE_IF_BUSY was specified");
+        }
+
+        // must use synchronous open for LOAD_BYPASS_LOCAL_CACHE_IF_BUSY
         rv = session->OpenCacheEntry(cacheKey, accessRequested, PR_FALSE,
                                      getter_AddRefs(mCacheEntry));
-        if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
-            waitingForValidation = PR_TRUE;
-            rv = NS_OK;
+        if (NS_SUCCEEDED(rv)) {
+            mCacheEntry->GetAccessGranted(&mCacheAccess);
+            LOG(("nsHttpChannel::OpenCacheEntry [this=%p grantedAccess=%d]",
+                this, mCacheAccess));
         }
-        if (NS_FAILED(rv)) return rv;
-    }
-
-    if (waitingForValidation) {
-        // access to the cache entry has been denied (because the
-        // cache entry is probably in use by another channel).
-        if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY) {
+        else if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
             LOG(("bypassing local cache since it is busy\n"));
-            return NS_ERROR_NOT_AVAILABLE;
+            rv = NS_ERROR_NOT_AVAILABLE;
         }
+    }
+    else {
+        mOnCacheEntryAvailableCallback =
+            &nsHttpChannel::OnNormalCacheEntryAvailable;
         rv = session->AsyncOpenCacheEntry(cacheKey, accessRequested, this);
-        if (NS_FAILED(rv)) return rv;
-        // we'll have to wait for the cache entry
-        *delayed = PR_TRUE;
+        if (NS_SUCCEEDED(rv)) {
+            mAsyncCacheOpen = PR_TRUE;
+            return NS_OK;
+        }
     }
-    else if (NS_SUCCEEDED(rv)) {
-        mCacheEntry->GetAccessGranted(&mCacheAccess);
-        LOG(("nsHttpChannel::OpenCacheEntry [this=%p grantedAccess=%d]", this, mCacheAccess));
+
+    if (!aIsSync)
+        // Called from OnCacheEntryAvailable, advance to the next state
+        rv = Connect(PR_FALSE);
+
+    return rv;
+}
+
+nsresult
+nsHttpChannel::OnNormalCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
+                                           nsCacheAccessMode aAccess,
+                                           nsresult aEntryStatus,
+                                           PRBool aIsSync)
+{
+    NS_ASSERTION(!aIsSync, "aIsSync should be false");
+
+    if (NS_SUCCEEDED(aEntryStatus)) {
+        mCacheEntry = aEntry;
+        mCacheAccess = aAccess;
     }
-    return rv;
+
+    if (mCanceled && NS_FAILED(mStatus)) {
+        LOG(("channel was canceled [this=%p status=%x]\n", this, mStatus));
+        return mStatus;
+    }
+
+    if ((mLoadFlags & LOAD_ONLY_FROM_CACHE) && NS_FAILED(aEntryStatus))
+        // if this channel is only allowed to pull from the cache, then
+        // we must fail if we were unable to open a cache entry.
+        return NS_ERROR_DOCUMENT_NOT_CACHED;
+
+    // advance to the next state...
+    return Connect(PR_FALSE);
 }
 
 
 nsresult
 nsHttpChannel::OpenOfflineCacheEntryForWriting()
 {
     nsresult rv;
 
@@ -2705,17 +2771,24 @@ nsHttpChannel::ReadFromCache()
     rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(stream));
     if (NS_FAILED(rv)) return rv;
 
     rv = nsInputStreamPump::Create(getter_AddRefs(mCachePump),
                                    stream, nsInt64(-1), nsInt64(-1), 0, 0,
                                    PR_TRUE);
     if (NS_FAILED(rv)) return rv;
 
-    return mCachePump->AsyncRead(this, mListenerContext);
+    rv = mCachePump->AsyncRead(this, mListenerContext);
+    if (NS_FAILED(rv)) return rv;
+
+    PRUint32 suspendCount = mSuspendCount;
+    while (suspendCount--)
+        mCachePump->Suspend();
+
+    return NS_OK;
 }
 
 void
 nsHttpChannel::CloseCacheEntry(PRBool doomOnFailure)
 {
     if (!mCacheEntry)
         return;
 
@@ -3359,17 +3432,16 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
     NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
     NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
     NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
     NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel)
     NS_INTERFACE_MAP_ENTRY(nsICachingChannel)
     NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
     NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
     NS_INTERFACE_MAP_ENTRY(nsICacheListener)
-    NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
     NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
     NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
     NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
     NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
     NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyCallback)
     NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
     NS_INTERFACE_MAP_ENTRY(nsIHttpAuthenticableChannel)
     NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
@@ -3577,58 +3649,16 @@ nsHttpChannel::GetServicingRemoteChannel
 }
 NS_IMETHODIMP
 nsHttpChannel::SetServicingRemoteChannel(PRBool value)
 {
     mRemoteChannel = value;
     return NS_OK;
 }
 //-----------------------------------------------------------------------------
-// nsHttpChannel::nsIEncodedChannel
-//-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-nsHttpChannel::GetApplyConversion(PRBool *value)
-{
-    NS_ENSURE_ARG_POINTER(value);
-    *value = mApplyConversion;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetApplyConversion(PRBool value)
-{
-    LOG(("nsHttpChannel::SetApplyConversion [this=%p value=%d]\n", this, value));
-    mApplyConversion = value;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings)
-{
-    NS_PRECONDITION(aEncodings, "Null out param");
-    if (!mResponseHead) {
-        *aEncodings = nsnull;
-        return NS_OK;
-    }
-    
-    const char *encoding = mResponseHead->PeekHeader(nsHttp::Content_Encoding);
-    if (!encoding) {
-        *aEncodings = nsnull;
-        return NS_OK;
-    }
-    nsContentEncodings* enumerator = new nsContentEncodings(this, encoding);
-    if (!enumerator)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    NS_ADDREF(*aEncodings = enumerator);
-    return NS_OK;
-}
-
-//-----------------------------------------------------------------------------
 // nsHttpChannel::nsISupportsPriority
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpChannel::SetPriority(PRInt32 value)
 {
     PRInt16 newValue = NS_CLAMP(value, PR_INT16_MIN, PR_INT16_MAX);
     if (mPriority == newValue)
@@ -4380,46 +4410,44 @@ nsHttpChannel::ResumeAt(PRUint64 aStartP
 // nsHttpChannel::nsICacheListener
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry,
                                      nsCacheAccessMode access,
                                      nsresult status)
 {
+    nsresult rv;
+
     LOG(("nsHttpChannel::OnCacheEntryAvailable [this=%p entry=%p "
          "access=%x status=%x]\n", this, entry, access, status));
 
     // if the channel's already fired onStopRequest, then we should ignore
     // this event.
     if (!mIsPending)
         return NS_OK;
 
-    // otherwise, we have to handle this event.
-    if (NS_SUCCEEDED(status)) {
-        mCacheEntry = entry;
-        mCacheAccess = access;
-    }
-
-    nsresult rv;
-
-    if (mCanceled && NS_FAILED(mStatus)) {
-        LOG(("channel was canceled [this=%p status=%x]\n", this, mStatus));
-        rv = mStatus;
-    }
-    else if ((mLoadFlags & LOAD_ONLY_FROM_CACHE) && NS_FAILED(status))
-        // if this channel is only allowed to pull from the cache, then
-        // we must fail if we were unable to open a cache entry.
-        rv = NS_ERROR_DOCUMENT_NOT_CACHED;
-    else
-        // advance to the next state...
-        rv = Connect(PR_FALSE);
-
-    // a failure from Connect means that we have to abort the channel.
+    nsOnCacheEntryAvailableCallback callback = mOnCacheEntryAvailableCallback;
+    mOnCacheEntryAvailableCallback = nsnull;
+
+    NS_ASSERTION(callback,
+        "nsHttpChannel::OnCacheEntryAvailable called without callback");
+    rv = ((*this).*callback)(entry, access, status, PR_FALSE);
+
     if (NS_FAILED(rv)) {
+        LOG(("AsyncOpenCacheEntry failed [rv=%x]\n", rv));
+        if (mLoadFlags & LOAD_ONLY_FROM_CACHE) {
+            // If we have a fallback URI (and we're not already
+            // falling back), process the fallback asynchronously.
+            if (!mFallbackChannel && !mFallbackKey.IsEmpty()) {
+                rv = AsyncCall(&nsHttpChannel::HandleAsyncFallback);
+                if (NS_SUCCEEDED(rv))
+                    return rv;
+            }
+        }
         CloseCacheEntry(PR_TRUE);
         AsyncAbort(rv);
     }
 
     return NS_OK;
 }
 
 nsresult
@@ -4468,17 +4496,24 @@ nsHttpChannel::DoAuthRetry(nsAHttpConnec
         nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
         if (seekable)
             seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
     }
 
     rv = gHttpHandler->InitiateTransaction(mTransaction, mPriority);
     if (NS_FAILED(rv)) return rv;
 
-    return mTransactionPump->AsyncRead(this, nsnull);
+    rv = mTransactionPump->AsyncRead(this, nsnull);
+    if (NS_FAILED(rv)) return rv;
+
+    PRUint32 suspendCount = mSuspendCount;
+    while (suspendCount--)
+        mTransactionPump->Suspend();
+
+    return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel::nsIApplicationCacheChannel
 //-----------------------------------------------------------------------------
 NS_IMETHODIMP
 nsHttpChannel::GetApplicationCache(nsIApplicationCache **out)
 {
@@ -4627,155 +4662,16 @@ nsHttpChannel::PopRedirectAsyncFunc(nsCo
 {
     NS_ASSERTION(func == mRedirectFuncStack[mRedirectFuncStack.Length() - 1],
         "Trying to pop wrong method from redirect async stack!");
 
     mRedirectFuncStack.TruncateLength(mRedirectFuncStack.Length() - 1);
 }
 
 //-----------------------------------------------------------------------------
-// nsHttpChannel::nsContentEncodings <public>
-//-----------------------------------------------------------------------------
-
-nsHttpChannel::nsContentEncodings::nsContentEncodings(nsIHttpChannel* aChannel,
-                                                          const char* aEncodingHeader) :
-    mEncodingHeader(aEncodingHeader), mChannel(aChannel), mReady(PR_FALSE)
-{
-    mCurEnd = aEncodingHeader + strlen(aEncodingHeader);
-    mCurStart = mCurEnd;
-}
-    
-nsHttpChannel::nsContentEncodings::~nsContentEncodings()
-{
-}
-
-//-----------------------------------------------------------------------------
-// nsHttpChannel::nsContentEncodings::nsISimpleEnumerator
-//-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-nsHttpChannel::nsContentEncodings::HasMore(PRBool* aMoreEncodings)
-{
-    if (mReady) {
-        *aMoreEncodings = PR_TRUE;
-        return NS_OK;
-    }
-    
-    nsresult rv = PrepareForNext();
-    *aMoreEncodings = NS_SUCCEEDED(rv);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::nsContentEncodings::GetNext(nsACString& aNextEncoding)
-{
-    aNextEncoding.Truncate();
-    if (!mReady) {
-        nsresult rv = PrepareForNext();
-        if (NS_FAILED(rv)) {
-            return NS_ERROR_FAILURE;
-        }
-    }
-
-    const nsACString & encoding = Substring(mCurStart, mCurEnd);
-
-    nsACString::const_iterator start, end;
-    encoding.BeginReading(start);
-    encoding.EndReading(end);
-
-    PRBool haveType = PR_FALSE;
-    if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("gzip"),
-                                      start,
-                                      end)) {
-        aNextEncoding.AssignLiteral(APPLICATION_GZIP);
-        haveType = PR_TRUE;
-    }
-
-    if (!haveType) {
-        encoding.BeginReading(start);
-        if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("compress"),
-                                          start,
-                                          end)) {
-            aNextEncoding.AssignLiteral(APPLICATION_COMPRESS);
-                                           
-            haveType = PR_TRUE;
-        }
-    }
-    
-    if (! haveType) {
-        encoding.BeginReading(start);
-        if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("deflate"),
-                                          start,
-                                          end)) {
-            aNextEncoding.AssignLiteral(APPLICATION_ZIP);
-            haveType = PR_TRUE;
-        }
-    }
-
-    // Prepare to fetch the next encoding
-    mCurEnd = mCurStart;
-    mReady = PR_FALSE;
-    
-    if (haveType)
-        return NS_OK;
-
-    NS_WARNING("Unknown encoding type");
-    return NS_ERROR_FAILURE;
-}
-
-//-----------------------------------------------------------------------------
-// nsHttpChannel::nsContentEncodings::nsISupports
-//-----------------------------------------------------------------------------
-
-NS_IMPL_ISUPPORTS1(nsHttpChannel::nsContentEncodings, nsIUTF8StringEnumerator)
-
-//-----------------------------------------------------------------------------
-// nsHttpChannel::nsContentEncodings <private>
-//-----------------------------------------------------------------------------
-
-nsresult
-nsHttpChannel::nsContentEncodings::PrepareForNext(void)
-{
-    NS_PRECONDITION(mCurStart == mCurEnd, "Indeterminate state");
-    
-    // At this point both mCurStart and mCurEnd point to somewhere
-    // past the end of the next thing we want to return
-    
-    while (mCurEnd != mEncodingHeader) {
-        --mCurEnd;
-        if (*mCurEnd != ',' && !nsCRT::IsAsciiSpace(*mCurEnd))
-            break;
-    }
-    if (mCurEnd == mEncodingHeader)
-        return NS_ERROR_NOT_AVAILABLE; // no more encodings
-    ++mCurEnd;
-        
-    // At this point mCurEnd points to the first char _after_ the
-    // header we want.  Furthermore, mCurEnd - 1 != mEncodingHeader
-    
-    mCurStart = mCurEnd - 1;
-    while (mCurStart != mEncodingHeader &&
-           *mCurStart != ',' && !nsCRT::IsAsciiSpace(*mCurStart))
-        --mCurStart;
-    if (*mCurStart == ',' || nsCRT::IsAsciiSpace(*mCurStart))
-        ++mCurStart; // we stopped because of a weird char, so move up one
-        
-    // At this point mCurStart and mCurEnd bracket the encoding string
-    // we want.  Check that it's not "identity"
-    if (Substring(mCurStart, mCurEnd).Equals("identity",
-                                             nsCaseInsensitiveCStringComparator())) {
-        mCurEnd = mCurStart;
-        return PrepareForNext();
-    }
-        
-    mReady = PR_TRUE;
-    return NS_OK;
-}
-
-//-----------------------------------------------------------------------------
 // nsStreamListenerWrapper <private>
 //-----------------------------------------------------------------------------
 
 // Wrapper class to make replacement of nsHttpChannel's listener
 // from JavaScript possible. It is workaround for bug 433711.
 class nsStreamListenerWrapper : public nsIStreamListener
 {
 public:
@@ -4876,13 +4772,34 @@ nsHttpChannel::DetermineStoragePolicy()
 {
     nsCacheStoragePolicy policy = nsICache::STORE_ANYWHERE;
     if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
         policy = nsICache::STORE_IN_MEMORY;
 
     return policy;
 }
 
+nsresult
+nsHttpChannel::DetermineCacheAccess(nsCacheAccessMode *_retval)
+{
+    PRBool offline = gIOService->IsOffline();
+
+    if (offline || (mLoadFlags & INHIBIT_CACHING)) {
+        // If we have been asked to bypass the cache and not write to the
+        // cache, then don't use the cache at all.  Unless we're actually
+        // offline, which takes precedence over BYPASS_LOCAL_CACHE.
+        if (BYPASS_LOCAL_CACHE(mLoadFlags) && !offline)
+            return NS_ERROR_NOT_AVAILABLE;
+        *_retval = nsICache::ACCESS_READ;
+    }
+    else if (BYPASS_LOCAL_CACHE(mLoadFlags))
+        *_retval = nsICache::ACCESS_WRITE; // replace cache entry
+    else
+        *_retval = nsICache::ACCESS_READ_WRITE; // normal browsing
+
+    return NS_OK;
+}
+
 void
 nsHttpChannel::AsyncOnExamineCachedResponse()
 {
     gHttpHandler->OnExamineCachedResponse(this);
 }
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -50,18 +50,16 @@
 #include "nsThreadUtils.h"
 #include "nsTArray.h"
 
 #include "nsIHttpEventSink.h"
 #include "nsICachingChannel.h"
 #include "nsICacheEntryDescriptor.h"
 #include "nsICacheListener.h"
 #include "nsIApplicationCacheChannel.h"
-#include "nsIEncodedChannel.h"
-#include "nsIStringEnumerator.h"
 #include "nsIPrompt.h"
 #include "nsIResumableChannel.h"
 #include "nsIProtocolProxyCallback.h"
 #include "nsICancelable.h"
 #include "nsIHttpAuthenticableChannel.h"
 #include "nsITraceableChannel.h"
 #include "nsIHttpChannelAuthProvider.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
@@ -74,33 +72,31 @@ using namespace mozilla::net;
 //-----------------------------------------------------------------------------
 // nsHttpChannel
 //-----------------------------------------------------------------------------
 
 class nsHttpChannel : public HttpBaseChannel
                     , public nsIStreamListener
                     , public nsICachingChannel
                     , public nsICacheListener
-                    , public nsIEncodedChannel
                     , public nsITransportEventSink
                     , public nsIProtocolProxyCallback
                     , public nsIHttpAuthenticableChannel
                     , public nsITraceableChannel
                     , public nsIApplicationCacheChannel
                     , public nsIAsyncVerifyRedirectCallback
                     , public nsIHttpChannelParentInternal
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSICACHEINFOCHANNEL
     NS_DECL_NSICACHINGCHANNEL
     NS_DECL_NSICACHELISTENER
-    NS_DECL_NSIENCODEDCHANNEL
     NS_DECL_NSITRANSPORTEVENTSINK
     NS_DECL_NSIPROTOCOLPROXYCALLBACK
     NS_DECL_NSIPROXIEDCHANNEL
     NS_DECL_NSITRACEABLECHANNEL
     NS_DECL_NSIAPPLICATIONCACHECONTAINER
     NS_DECL_NSIAPPLICATIONCACHECHANNEL
     NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
     NS_DECL_NSIHTTPCHANNELPARENTINTERNAL
@@ -175,17 +171,16 @@ private:
 
     PRBool   RequestIsConditional();
     nsresult Connect(PRBool firstTime = PR_TRUE);
     nsresult AsyncAbort(nsresult status);
     // Send OnStartRequest/OnStopRequest to our listener, if any.
     void     HandleAsyncNotifyListener();
     void     DoNotifyListener();
     nsresult SetupTransaction();
-    nsresult ApplyContentConversions();
     nsresult CallOnStartRequest();
     nsresult ProcessResponse();
     nsresult ContinueProcessResponse(nsresult);
     nsresult ProcessNormal();
     nsresult ContinueProcessNormal(nsresult);
     nsresult ProcessNotModified();
     nsresult AsyncProcessRedirection(PRUint32 httpStatus);
     nsresult ContinueProcessRedirection(nsresult);
@@ -213,17 +208,26 @@ private:
     nsresult ProxyFailover();
     nsresult AsyncDoReplaceWithProxy(nsIProxyInfo *);
     nsresult ContinueDoReplaceWithProxy(nsresult);
     void HandleAsyncReplaceWithProxy();
     nsresult ContinueHandleAsyncReplaceWithProxy(nsresult);
     nsresult ResolveProxy();
 
     // cache specific methods
-    nsresult OpenCacheEntry(PRBool offline, PRBool *delayed);
+    nsresult OpenCacheEntry();
+    nsresult OnOfflineCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
+                                          nsCacheAccessMode aAccess,
+                                          nsresult aResult,
+                                          PRBool aSync);
+    nsresult OpenNormalCacheEntry(PRBool aSync);
+    nsresult OnNormalCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
+                                         nsCacheAccessMode aAccess,
+                                         nsresult aResult,
+                                         PRBool aSync);
     nsresult OpenOfflineCacheEntryForWriting();
     nsresult GenerateCacheKey(PRUint32 postID, nsACString &key);
     nsresult UpdateExpirationTime();
     nsresult CheckCache();
     nsresult ShouldUpdateOfflineCacheEntry(PRBool *shouldCacheForOfflineUse);
     nsresult ReadFromCache();
     void     CloseCacheEntry(PRBool doomOnFailure);
     void     CloseOfflineCacheEntry();
@@ -231,16 +235,17 @@ private:
     nsresult InitOfflineCacheEntry();
     nsresult AddCacheEntryHeaders(nsICacheEntryDescriptor *entry);
     nsresult StoreAuthorizationMetaData(nsICacheEntryDescriptor *entry);
     nsresult FinalizeCacheEntry();
     nsresult InstallCacheListener(PRUint32 offset = 0);
     nsresult InstallOfflineCacheListener();
     void     MaybeInvalidateCacheEntryForSubsequentGet();
     nsCacheStoragePolicy DetermineStoragePolicy();
+    nsresult DetermineCacheAccess(nsCacheAccessMode *_retval);
     void     AsyncOnExamineCachedResponse();
 
     // Handle the bogus Content-Encoding Apache sometimes sends
     void ClearBogusContentEncodingIfNeeded();
 
     // byte range request specific methods
     nsresult SetupByteRangeRequest(PRUint32 partialLen);
     nsresult ProcessPartialContent();
@@ -273,16 +278,21 @@ private:
     // cache specific data
     nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
     nsRefPtr<nsInputStreamPump>       mCachePump;
     nsAutoPtr<nsHttpResponseHead>     mCachedResponseHead;
     nsCacheAccessMode                 mCacheAccess;
     PRUint32                          mPostID;
     PRUint32                          mRequestTime;
 
+    typedef nsresult (nsHttpChannel:: *nsOnCacheEntryAvailableCallback)(
+        nsICacheEntryDescriptor *, nsCacheAccessMode, nsresult, PRBool);
+    nsOnCacheEntryAvailableCallback   mOnCacheEntryAvailableCallback;
+    PRBool                            mAsyncCacheOpen;
+
     nsCOMPtr<nsICacheEntryDescriptor> mOfflineCacheEntry;
     nsCacheAccessMode                 mOfflineCacheAccess;
     nsCString                         mOfflineCacheClientID;
 
     // auth specific data
     nsCOMPtr<nsIHttpChannelAuthProvider> mAuthProvider;
 
     // Function pointer that can be set to indicate that we got suspended while
@@ -303,17 +313,16 @@ private:
     nsCString                         mFallbackKey;
 
     friend class AutoRedirectVetoNotifier;
     nsCOMPtr<nsIURI>                  mRedirectURI;
     nsCOMPtr<nsIChannel>              mRedirectChannel;
     PRUint32                          mRedirectType;
 
     // state flags
-    PRUint32                          mApplyConversion          : 1;
     PRUint32                          mCachedContentIsValid     : 1;
     PRUint32                          mCachedContentIsPartial   : 1;
     PRUint32                          mTransactionReplaced      : 1;
     PRUint32                          mAuthRetryPending         : 1;
     PRUint32                          mResuming                 : 1;
     PRUint32                          mInitedCacheEntry         : 1;
     PRUint32                          mCacheForOfflineUse       : 1;
     // True if mCacheForOfflineUse was set because we were caching
@@ -330,40 +339,16 @@ private:
     PRUint32                          mFallingBack              : 1;
     PRUint32                          mWaitingForRedirectCallback : 1;
     // True iff this channel is servicing a remote HttpChannelChild
     PRUint32                          mRemoteChannel : 1;
     // True if mRequestTime has been set. In such a case it is safe to update
     // the cache entry's expiration time. Otherwise, it is not(see bug 567360).
     PRUint32                          mRequestTimeInitialized : 1;
 
-    class nsContentEncodings : public nsIUTF8StringEnumerator
-    {
-    public:
-        NS_DECL_ISUPPORTS
-        NS_DECL_NSIUTF8STRINGENUMERATOR
-
-        nsContentEncodings(nsIHttpChannel* aChannel, const char* aEncodingHeader);
-        virtual ~nsContentEncodings();
-        
-    private:
-        nsresult PrepareForNext(void);
-        
-        // We do not own the buffer.  The channel owns it.
-        const char* mEncodingHeader;
-        const char* mCurStart;  // points to start of current header
-        const char* mCurEnd;  // points to end of current header
-        
-        // Hold a ref to our channel so that it can't go away and take the
-        // header with it.
-        nsCOMPtr<nsIHttpChannel> mChannel;
-        
-        PRPackedBool mReady;
-    };
-
     nsTArray<nsContinueRedirectionFunc> mRedirectFuncStack;
 
     nsresult WaitForRedirectCallback();
     void PushRedirectAsyncFunc(nsContinueRedirectionFunc func);
     void PopRedirectAsyncFunc(nsContinueRedirectionFunc func);
 };
 
 #endif // nsHttpChannel_h__
--- a/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp
+++ b/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp
@@ -32,16 +32,17 @@
  * 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 "nsTXTToHTMLConv.h"
 #include "nsNetUtil.h"
+#include "nsEscape.h"
 #include "nsStringStream.h"
 #include "nsAutoPtr.h"
 
 #define TOKEN_DELIMITERS NS_LITERAL_STRING("\t\r\n ").get()
 
 // nsISupports methods
 NS_IMPL_ISUPPORTS4(nsTXTToHTMLConv,
                    nsIStreamConverter,
@@ -304,21 +305,34 @@ nsTXTToHTMLConv::CatHTML(PRInt32 front, 
         // replace the entire token (from delimiter to delimiter)
         mBuffer.Cut(front, back - front);
         mBuffer.Insert(mToken->modText, front);
         cursor = front+modLen;
     } else {
         nsString linkText;
         // href is implied
         mBuffer.Mid(linkText, front, back-front);
+
         mBuffer.Insert(NS_LITERAL_STRING("<a href=\""), front);
         cursor += front+9;
-        if (modLen)
+        if (modLen) {
             mBuffer.Insert(mToken->modText, cursor);
-        cursor += modLen-front+back;
+            cursor += modLen;
+        }
+
+        NS_ConvertUTF16toUTF8 linkTextUTF8(linkText);
+        nsCString escaped;
+        if (NS_EscapeURL(linkTextUTF8.Data(), linkTextUTF8.Length(), esc_Minimal, escaped)) {
+            mBuffer.Cut(cursor, back - front);
+            CopyUTF8toUTF16(escaped, linkText);
+            mBuffer.Insert(linkText, cursor);
+            back = front + linkText.Length();
+        }
+
+        cursor += back-front;
         mBuffer.Insert(NS_LITERAL_STRING("\">"), cursor);
         cursor += 2;
         mBuffer.Insert(linkText, cursor);
         cursor += linkText.Length();
         mBuffer.Insert(NS_LITERAL_STRING("</a>"), cursor);
         cursor += 4;
     }
     mToken = nsnull; // indicates completeness
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -511,17 +511,18 @@ function do_get_profile() {
                        .createInstance(Components.interfaces.nsILocalFile);
   file.initWithPath(profd);
 
   let dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
                          .getService(Components.interfaces.nsIProperties);
   let provider = {
     getFile: function(prop, persistent) {
       persistent.value = true;
-      if (prop == "ProfD" || prop == "ProfLD" || prop == "ProfDS") {
+      if (prop == "ProfD" || prop == "ProfLD" || prop == "ProfDS" ||
+          prop == "ProfLDS" || prop == "TmpD") {
         return file.clone();
       }
       throw Components.results.NS_ERROR_FAILURE;
     },
     QueryInterface: function(iid) {
       if (iid.equals(Components.interfaces.nsIDirectoryServiceProvider) ||
           iid.equals(Components.interfaces.nsISupports)) {
         return this;
--- a/uriloader/exthandler/ExternalHelperAppParent.cpp
+++ b/uriloader/exthandler/ExternalHelperAppParent.cpp
@@ -36,17 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "ExternalHelperAppParent.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIExternalHelperAppService.h"
-#include "mozilla/dom/TabParent.h"
+#include "mozilla/dom/ContentParent.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsStringStream.h"
 
 #include "mozilla/unused.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -64,35 +64,30 @@ ExternalHelperAppParent::ExternalHelperA
   , mPending(PR_FALSE)
   , mLoadFlags(0)
   , mStatus(NS_OK)
   , mContentLength(aContentLength)
 {
 }
 
 void
-ExternalHelperAppParent::Init(TabParent *parent,
+ExternalHelperAppParent::Init(ContentParent *parent,
                               const nsCString& aMimeContentType,
                               const nsCString& aContentDisposition,
                               const PRBool& aForceSave)
 {
   nsHashPropertyBag::Init();
 
-  NS_ASSERTION(parent, "must have a non-null TabParent");
-  nsCOMPtr<nsIContent> frame = do_QueryInterface(parent->GetOwnerElement());
-  nsCOMPtr<nsISupports> container = frame->GetOwnerDoc()->GetContainer();
-  nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(container);
-
   nsCOMPtr<nsIExternalHelperAppService> helperAppService =
     do_GetService(NS_EXTERNALHELPERAPPSERVICE_CONTRACTID);
   NS_ASSERTION(helperAppService, "No Helper App Service!");
 
   SetPropertyAsInt64(NS_CHANNEL_PROP_CONTENT_LENGTH, mContentLength);
   SetContentDisposition(aContentDisposition);
-  helperAppService->DoContent(aMimeContentType, this, ir,
+  helperAppService->DoContent(aMimeContentType, this, nsnull,
                               aForceSave, getter_AddRefs(mListener));
 }
 
 bool
 ExternalHelperAppParent::RecvOnStartRequest(const nsCString& entityID)
 {
   mEntityID = entityID;
   mPending = PR_TRUE;
--- a/uriloader/exthandler/ExternalHelperAppParent.h
+++ b/uriloader/exthandler/ExternalHelperAppParent.h
@@ -44,17 +44,17 @@
 
 namespace IPC {
 class URI;
 }
 
 namespace mozilla {
 namespace dom {
 
-class TabParent;
+class ContentParent;
 
 class ExternalHelperAppParent : public PExternalHelperAppParent
                               , public nsHashPropertyBag
                               , public nsIChannel
                               , public nsIMultiPartChannel
                               , public nsIResumableChannel
 {
 public:
@@ -64,17 +64,17 @@ public:
     NS_DECL_NSIMULTIPARTCHANNEL
     NS_DECL_NSIRESUMABLECHANNEL
 
     bool RecvOnStartRequest(const nsCString& entityID);
     bool RecvOnDataAvailable(const nsCString& data, const PRUint32& offset, const PRUint32& count);
     bool RecvOnStopRequest(const nsresult& code);
     
     ExternalHelperAppParent(const IPC::URI& uri, const PRInt64& contentLength);
-    void Init(TabParent *parent,
+    void Init(ContentParent *parent,
               const nsCString& aMimeContentType,
               const nsCString& aContentDisposition,
               const PRBool& aForceSave);
     virtual ~ExternalHelperAppParent();
 
 private:
   nsCOMPtr<nsIStreamListener> mListener;
   nsCOMPtr<nsIURI> mURI;
--- a/uriloader/exthandler/PExternalHelperApp.ipdl
+++ b/uriloader/exthandler/PExternalHelperApp.ipdl
@@ -30,24 +30,24 @@
  * 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 protocol PBrowser;
+include protocol PContent;
 
 namespace mozilla {
 namespace dom {
 
 protocol PExternalHelperApp
 {
-  manager PBrowser;
+  manager PContent;
 
 parent:
   OnStartRequest(nsCString entityID);
   OnDataAvailable(nsCString data, PRUint32 offset, PRUint32 count);
   OnStopRequest(nsresult code);
 
 child:
   Cancel(nsresult aStatus);
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -135,17 +135,17 @@
 
 #include "nsIRandomGenerator.h"
 #include "plbase64.h"
 #include "prmem.h"
 
 #include "nsIPrivateBrowsingService.h"
 
 #ifdef MOZ_IPC
-#include "TabChild.h"
+#include "ContentChild.h"
 #include "nsXULAppAPI.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocShellTreeItem.h"
 #include "ExternalHelperAppChild.h"
 #endif
 
 // Buffer file writes in 32kb chunks
@@ -679,42 +679,35 @@ NS_IMETHODIMP nsExternalHelperAppService
   nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
   nsCOMPtr<nsIURI> uri;
   if (channel)
     channel->GetURI(getter_AddRefs(uri));
 
 #ifdef MOZ_IPC
   PRInt64 contentLength = GetContentLengthAsInt64(aRequest);
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
-    // We need to get a hold of a TabChild so that we can begin forwarding
+    // We need to get a hold of a ContentChild so that we can begin forwarding
     // this data to the parent.  In the HTTP case, this is unfortunate, since
     // we're actually passing data from parent->child->parent wastefully, but
     // the Right Fix will eventually be to short-circuit those channels on the
     // parent side based on some sort of subscription concept.
-    nsCOMPtr<nsIDocShell> docshell(do_GetInterface(aWindowContext));
-    nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(docshell);
-    nsCOMPtr<nsIDocShellTreeOwner> owner;
-    item->GetTreeOwner(getter_AddRefs(owner));
-    NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
-
-    nsCOMPtr<nsITabChild> tabchild = do_GetInterface(owner);
-    if (!tabchild)
+    using mozilla::dom::ContentChild;
+    using mozilla::dom::ExternalHelperAppChild;
+    ContentChild *child = ContentChild::GetSingleton();
+    if (!child)
       return NS_ERROR_FAILURE;
 
     nsCString disp;
     if (channel)
       ExtractDisposition(channel, disp);
 
     // Now we build a protocol for forwarding our data to the parent.  The
     // protocol will act as a listener on the child-side and create a "real"
     // helperAppService listener on the parent-side, via another call to
     // DoContent.
-    using mozilla::dom::TabChild;
-    using mozilla::dom::ExternalHelperAppChild;
-    TabChild *child = static_cast<TabChild*>(tabchild.get());
     mozilla::dom::PExternalHelperAppChild *pc;
     pc = child->SendPExternalHelperAppConstructor(IPC::URI(uri),
                                                   nsCString(aMimeContentType),
                                                   disp,
                                                   aForceSave, contentLength);
     ExternalHelperAppChild *childListener = static_cast<ExternalHelperAppChild *>(pc);
 
     NS_ADDREF(*aStreamListener = childListener);
@@ -1588,34 +1581,22 @@ NS_IMETHODIMP nsExternalAppHandler::OnSt
       }
     }
   }
 
   // Close the underlying DOMWindow if there is no refresh header
   // and it was opened specifically for the download
   MaybeCloseWindow();
 
-#ifdef MOZ_IPC
-  // At this point, the child process has done everything it can usefully do
-  // for OnStartRequest.
-  if (XRE_GetProcessType() == GeckoProcessType_Content)
-     return NS_OK;
-#endif
-
-  rv = SetUpTempFile(aChannel);
-  if (NS_FAILED(rv)) {
-    mCanceled = PR_TRUE;
-    request->Cancel(rv);
-    nsAutoString path;
-    if (mTempFile)
-      mTempFile->GetPath(path);
-    SendStatusChange(kWriteError, rv, request, path);
-    return NS_OK;
-  }
-
+  // In an IPC setting, we're allowing the child process, here, to make
+  // decisions about decoding the channel (e.g. decompression).  It will
+  // still forward the decoded (uncompressed) data back to the parent.
+  // Con: Uncompressed data means more IPC overhead.
+  // Pros: ExternalHelperAppParent doesn't need to implement nsIEncodedChannel.
+  //       Parent process doesn't need to expect CPU time on decompression.
   nsCOMPtr<nsIEncodedChannel> encChannel = do_QueryInterface( aChannel );
   if (encChannel) 
   {
     // Turn off content encoding conversions if needed
     PRBool applyConversion = PR_TRUE;
 
     nsCOMPtr<nsIURL> sourceURL(do_QueryInterface(mSourceUrl));
     if (sourceURL)
@@ -1643,16 +1624,34 @@ NS_IMETHODIMP nsExternalAppHandler::OnSt
           }
         }
       }    
     }
 
     encChannel->SetApplyConversion( applyConversion );
   }
 
+#ifdef MOZ_IPC
+  // At this point, the child process has done everything it can usefully do
+  // for OnStartRequest.
+  if (XRE_GetProcessType() == GeckoProcessType_Content)
+     return NS_OK;
+#endif
+
+  rv = SetUpTempFile(aChannel);
+  if (NS_FAILED(rv)) {
+    mCanceled = PR_TRUE;
+    request->Cancel(rv);
+    nsAutoString path;
+    if (mTempFile)
+      mTempFile->GetPath(path);
+    SendStatusChange(kWriteError, rv, request, path);
+    return NS_OK;
+  }
+
   // Inform channel it is open on behalf of a download to prevent caching.
   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(aChannel);
   if (httpInternal) {
     httpInternal->SetChannelIsForDownload(PR_TRUE);
   }
 
   // now that the temp file is set up, find out if we need to invoke a dialog
   // asking the user what they want us to do with this content...
@@ -1872,16 +1871,19 @@ void nsExternalAppHandler::SendStatusCha
             if(NS_SUCCEEDED(bundle->FormatStringFromName(msgId.get(), strings, 1, getter_Copies(msgText))))
             {
               if (mWebProgressListener)
               {
                 // We have a listener, let it handle the error.
                 mWebProgressListener->OnStatusChange(nsnull, (type == kReadError) ? aRequest : nsnull, rv, msgText);
               }
               else
+#ifdef MOZ_IPC
+              if (XRE_GetProcessType() == GeckoProcessType_Default)
+#endif
               {
                 // We don't have a listener.  Simply show the alert ourselves.
                 nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mWindowContext));
                 nsXPIDLString title;
                 bundle->FormatStringFromName(NS_LITERAL_STRING("title").get(),
                                              strings,
                                              1,
                                              getter_Copies(title));
--- a/uriloader/exthandler/tests/Makefile.in
+++ b/uriloader/exthandler/tests/Makefile.in
@@ -46,16 +46,20 @@ DIRS += mochitest \
         $(NULL)
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE          = test_uriloader_exthandler
 
 XPCSHELL_TESTS  = unit
 
+ifdef MOZ_IPC
+XPCSHELL_TESTS += unit_ipc
+endif
+
 CPPSRCS =	\
 		WriteArgument.cpp \
 		$(NULL)
 
 SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX))
 
 include $(topsrcdir)/config/config.mk
 
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/tests/unit_ipc/test_encoding.js
@@ -0,0 +1,258 @@
+
+do_get_profile();
+do_load_httpd_js();
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+// Dynamically generates a classID for our component, registers it to mask
+// the existing component, and stored the masked components classID to be
+// restored later, when we unregister.
+function registerTemporaryComponent(comp)
+{
+  let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+  if (!comp.prototype.classID) {
+    let uuidgen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
+    comp.prototype.classID = uuidgen.generateUUID();
+  }
+  comp.prototype.maskedClassID = Components.ID(Cc[comp.prototype.contractID].number);
+  if (!comp.prototype.factory)
+    comp.prototype.factory = getFactory(comp);
+  registrar.registerFactory(comp.prototype.classID, "", comp.prototype.contractID, comp.prototype.factory);
+}
+
+function unregisterTemporaryComponent(comp)
+{
+  let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+  registrar.unregisterFactory(comp.prototype.classID, comp.prototype.factory);
+  registrar.registerFactory(comp.prototype.maskedClassID, "", comp.prototype.contractID, null);
+}
+
+let DownloadListener = {
+  init: function () {
+    let obs = Services.obs;
+    obs.addObserver(this, "dl-done", true);
+  },
+
+  observe: function (subject, topic, data) {
+    this.onFinished(subject, topic, data);
+  },
+
+  QueryInterface: function (iid) {
+    if (iid.equals(Ci.nsIObserver) ||
+        iid.equals(Ci.nsISupportsWeakReference) ||
+        iid.equals(Ci.nsISupports))
+      return this;
+
+    throw Cr.NS_ERROR_NO_INTERFACE;
+  }
+}
+DownloadListener.init();
+
+function HelperAppDlg() { }
+HelperAppDlg.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
+  contractID: "@mozilla.org/helperapplauncherdialog;1",
+  show: function (launcher, ctx, reason) {
+    launcher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.saveToFile;
+    launcher.launchWithApplication(null, false);
+  },
+
+  promptForSaveToFile: function (launcher, ctx, defaultFile, suggestedExtension, forcePrompt) { }
+}
+
+// Stolen from XPCOMUtils, since this handy function is not public there
+function getFactory(comp)
+{
+  return {
+    createInstance: function (outer, iid) {
+      if (outer)
+        throw Cr.NS_ERROR_NO_AGGREGATION;
+      return (new comp()).QueryInterface(iid);
+    }
+  }
+}
+registerTemporaryComponent(HelperAppDlg);
+
+function initChildTestEnv()
+{
+  sendCommand('                                                                \
+    const Cc = Components.classes;                                             \
+    const Ci = Components.interfaces;                                          \
+    const Cr = Components.results;                                             \
+    function WindowContext() { }                                               \
+                                                                               \
+    WindowContext.prototype = {                                                \
+      getInterface: function (iid) {                                           \
+        if (iid.equals(Ci.nsIInterfaceRequestor) ||                            \
+            iid.equals(Ci.nsIURIContentListener) ||                            \
+            iid.equals(Ci.nsILoadGroup) ||                                     \
+            iid.equals(Ci.nsIDocumentLoader) ||                                \
+            iid.equals(Ci.nsIDOMWindow))                                       \
+          return this;                                                         \
+                                                                               \
+        throw Cr.NS_ERROR_NO_INTERFACE;                                        \
+      },                                                                       \
+                                                                               \
+      /* nsIURIContentListener */                                              \
+      onStartURIOpen: function (uri) { },                                      \
+      isPreferred: function (type, desiredtype) { return false; },             \
+                                                                               \
+      /* nsILoadGroup */                                                       \
+      addRequest: function (request, context) { },                             \
+      removeRequest: function (request, context, status) { }                   \
+    };                                                                         \
+                                                                               \
+    var ioservice = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);\
+    var uriloader = Cc["@mozilla.org/uriloader;1"].getService(Ci.nsIURILoader);\
+  ');
+}
+
+function testFinisher(endFunc) {
+  let ef = endFunc;
+  return function (file) {
+    ef(file);
+    runNextTest();
+  }
+}
+
+function runChildTestSet(set)
+{
+  DownloadListener.onFinished = testFinisher(set[2]);
+  sendCommand('\
+  let uri = ioservice.newURI("http://localhost:4444' + set[0] + '", null, null);\
+  let channel = ioservice.newChannelFromURI(uri);                              \
+  uriloader.openURI(channel, true, new WindowContext());                       \
+  ');
+}
+
+var httpserver = null;
+let currentTest = 0;
+function runNextTest()
+{
+  if (currentTest == tests.length) {
+    httpserver.stop(do_test_finished);
+    return;
+  }
+
+  let set = tests[currentTest++];
+  runChildTestSet(set);
+}
+
+const responseBody = [0x1f, 0x8b, 0x08, 0x00, 0x16, 0x5a, 0x8a, 0x48, 0x02,
+		      0x03, 0x2b, 0x49, 0x2d, 0x2e, 0xe1, 0x02, 0x00, 0xc6,
+		      0x35, 0xb9, 0x3b, 0x05, 0x00, 0x00, 0x00];
+
+/*
+ * First test:  a file with Content-Type application/x-gzip and Content-Encoding gzip
+ * should not be decoded in a round-trip
+ */
+function testResponse1(metadata, response) {
+  response.setHeader("Content-Type", "application/x-gzip", false);
+  response.setHeader("Content-Encoding", "gzip", false);
+  response.setHeader("Content-Disposition", "attachment", false);
+
+  var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
+  bos.setOutputStream(response.bodyOutputStream);
+  bos.writeByteArray(responseBody, responseBody.length);
+}
+
+function finishTest1(subject, topic, data) {
+  let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
+  do_check_true(file.path.search("test1.gz") != 0);
+  let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
+  fis.init(file, -1, -1, 0);
+  let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
+  bis.setInputStream(fis);
+  let str = bis.readByteArray(bis.available());
+  do_check_true(str.length == responseBody.length);
+
+  let cmp = 0;
+  for (i = 0; i < str.length; i++) {
+    cmp += str[i] - responseBody[i];
+    if (cmp != 0) break;
+  }
+  do_check_true(cmp == 0);
+}
+
+/*
+ * Second test:  a file with Content-Type text/html and Content-Encoding gzip
+ * should not be decoded in a round-trip, if its filename ends in ".gz".
+ * We specify a Content-disposition header to force it to be saved as a file.
+ */
+function testResponse2(metadata, response) {
+  response.setHeader("Content-Type", "text/html", false);
+  response.setHeader("Content-Encoding", "gzip", false);
+  response.setHeader("Content-Disposition", "attachment", false);
+
+  var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
+  bos.setOutputStream(response.bodyOutputStream);
+  bos.writeByteArray(responseBody, responseBody.length);
+}
+
+function finishTest2(subject, topic, data) {
+  let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
+  do_check_true(file.path.search("test2.gz") != 0);
+  let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
+  fis.init(file, -1, -1, 0);
+  let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
+  bis.setInputStream(fis);
+  let str = bis.readByteArray(bis.available());
+  do_check_true(str.length == responseBody.length);
+
+  let cmp = 0;
+  for (i = 0; i < str.length; i++) {
+    cmp += str[i] - responseBody[i];
+    if (cmp != 0) break;
+  }
+  do_check_true(cmp == 0);
+}
+
+function testResponse3(metadata, response) {
+  response.setHeader("Content-Type", "text/html", false);
+  response.setHeader("Content-Encoding", "gzip", false);
+  response.setHeader("Content-Disposition", "attachment", false);
+
+  var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
+  bos.setOutputStream(response.bodyOutputStream);
+  bos.writeByteArray(responseBody, responseBody.length);
+}
+
+function finishTest3(subject, topic, data) {
+  let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
+  do_check_true(file.path.search("test3.txt") != 0);
+  let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
+  fis.init(file, -1, -1, 0);
+  let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
+  bis.setInputStream(fis);
+  let str = bis.readByteArray(bis.available());
+  let decodedBody = [ 116, 101, 115, 116, 10 ]; // 't','e','s','t','\n'
+  do_check_true(str.length == decodedBody.length);
+
+  let cmp = 0;
+  for (i = 0; i < str.length; i++) {
+    cmp += str[i] - decodedBody[i];
+    if (cmp != 0) break;
+  }
+  do_check_true(cmp == 0);
+}
+
+let tests = [
+  [ "/test1.gz", testResponse1, finishTest1 ],
+  [ "/test2.gz", testResponse2, finishTest2 ],
+  [ "/test3.txt", testResponse3, finishTest3 ],
+];
+
+function run_test() {
+//  do_load_child_test_harness();
+  httpserver = new nsHttpServer();
+  httpserver.start(4444);
+  do_test_pending();
+
+  initChildTestEnv();
+
+  for each (set in tests)
+    httpserver.registerPathHandler(set[0], set[1]);
+
+  runNextTest();
+}
--- a/widget/src/windows/nsWindowGfx.cpp
+++ b/widget/src/windows/nsWindowGfx.cpp
@@ -740,19 +740,29 @@ DDRAW_FAILED:
         break;
       case LayerManager::LAYERS_OPENGL:
         static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager())->
           SetClippingRegion(event.region);
         result = DispatchWindowEvent(&event, eventStatus);
         break;
 #ifdef MOZ_ENABLE_D3D9_LAYER
       case LayerManager::LAYERS_D3D9:
-        static_cast<mozilla::layers::LayerManagerD3D9*>(GetLayerManager())->
-          SetClippingRegion(event.region);
-        result = DispatchWindowEvent(&event, eventStatus);
+        {
+          LayerManagerD3D9 *layerManagerD3D9 =
+            static_cast<mozilla::layers::LayerManagerD3D9*>(GetLayerManager());
+          layerManagerD3D9->SetClippingRegion(event.region);
+          result = DispatchWindowEvent(&event, eventStatus);
+          if (layerManagerD3D9->DeviceWasRemoved()) {
+            mLayerManager = nsnull;
+            // When our device was removed, we should have gfxWindowsPlatform
+            // check if its render mode is up to date!
+            gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
+            Invalidate(PR_FALSE);
+          }
+        }
         break;
 #endif
       default:
         NS_ERROR("Unknown layers backend used!");
         break;
     }
   }
 
--- a/xpcom/glue/nsISupportsImpl.h
+++ b/xpcom/glue/nsISupportsImpl.h
@@ -1221,16 +1221,20 @@ NS_IMETHODIMP_(nsrefcnt) Class::Release(
     NS_IMPL_ADDREF_INHERITED(Class, Super)                                    \
     NS_IMPL_RELEASE_INHERITED(Class, Super)                                   \
 
 #define NS_IMPL_ISUPPORTS_INHERITED7(Class, Super, i1, i2, i3, i4, i5, i6, i7) \
     NS_IMPL_QUERY_INTERFACE_INHERITED7(Class, Super, i1, i2, i3, i4, i5, i6, i7) \
     NS_IMPL_ADDREF_INHERITED(Class, Super)                                    \
     NS_IMPL_RELEASE_INHERITED(Class, Super)                                   \
 
+#define NS_IMPL_ISUPPORTS_INHERITED8(Class, Super, i1, i2, i3, i4, i5, i6, i7, i8) \
+    NS_IMPL_QUERY_INTERFACE_INHERITED8(Class, Super, i1, i2, i3, i4, i5, i6, i7, i8) \
+    NS_IMPL_ADDREF_INHERITED(Class, Super)                                    \
+    NS_IMPL_RELEASE_INHERITED(Class, Super)                                   \
 /*
  * Macro to glue together a QI that starts with an interface table
  * and segues into an interface map (e.g. it uses singleton classinfo
  * or tearoffs).
  */
 #define NS_INTERFACE_TABLE_TO_MAP_SEGUE \
   if (rv == NS_OK) return rv; \
   nsISupports* foundInterface;