Merge mozilla-central and tracemonkey.
authorChris Leary <cdleary@mozilla.com>
Mon, 23 May 2011 00:02:05 -0700
changeset 70208 0f9347d4012161d63903d1f187c7d35828e90ade
parent 70207 2bbaa4d2f580d4d91369b2d2eab366ec248d2afb (current diff)
parent 70138 11d04991cdd03376276ce319769a03079de35825 (diff)
child 70209 a3903f835a81f43b0c58fe8fbf1eb94f1ae3351e
child 71100 e80af925c117594e5440c780074d46f7cf59ee3f
push id76
push userbzbarsky@mozilla.com
push dateTue, 05 Jul 2011 17:00:57 +0000
treeherdermozilla-beta@d3a2732c35f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone6.0a1
first release with
nightly win64
0f9347d40121 / 6.0a1 / 20110523030219 / files
nightly linux32
nightly linux64
nightly mac
nightly win32
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly win64
Merge mozilla-central and tracemonkey.
accessible/tests/mochitest/text/Makefile.in
browser/base/content/stylePanel.jsm
browser/base/content/test/browser_inspector_domPanel.js
browser/base/content/test/browser_inspector_stylePanel.js
browser/locales/en-US/chrome/browser/inspector.properties
dom/base/nsDOMClassInfo.cpp
dom/plugins/base/nsJSNPRuntime.cpp
dom/plugins/base/nsNPAPIPlugin.cpp
testing/mochitest/pywebsocket/mod_pywebsocket/handshake/handshake.py
xpcom/base/nsSetDllDirectory.cpp
--- a/accessible/src/base/nsAccDocManager.h
+++ b/accessible/src/base/nsAccDocManager.h
@@ -194,33 +194,42 @@ private:
 
 #define NS_LOG_ACCDOC_URI(aDocument)                                           \
   nsIURI *uri = aDocument->GetDocumentURI();                                   \
   nsCAutoString spec;                                                          \
   uri->GetSpec(spec);                                                          \
   printf("uri: %s", spec);
 
 #define NS_LOG_ACCDOC_TYPE(aDocument)                                          \
-  PRBool isContent = nsCoreUtils::IsContentDocument(aDocument);                \
-  printf("%s document", (isContent ? "content" : "chrome"));
+  if (aDocument->IsActive()) {                                                 \
+    PRBool isContent = nsCoreUtils::IsContentDocument(aDocument);              \
+    printf("%s document", (isContent ? "content" : "chrome"));                 \
+  } else {                                                                     \
+    printf("document type: [failed]");                                         \
+  }
 
 #define NS_LOG_ACCDOC_SHELLSTATE(aDocument)                                    \
+  nsCAutoString docShellBusy;                                                  \
   nsCOMPtr<nsISupports> container = aDocument->GetContainer();                 \
-  nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);               \
-  PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE;                           \
-  docShell->GetBusyFlags(&busyFlags);                                          \
-  nsCAutoString docShellBusy;                                                  \
-  if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE)                               \
-    docShellBusy.AppendLiteral("'none'");                                      \
-  if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY)                                \
-    docShellBusy.AppendLiteral("'busy'");                                      \
-  if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD)                    \
-    docShellBusy.AppendLiteral(", 'before page load'");                        \
-  if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)                        \
-    docShellBusy.AppendLiteral(", 'page loading'");                            \
+  if (container) {                                                             \
+    nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);             \
+    PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE;                         \
+    docShell->GetBusyFlags(&busyFlags);                                        \
+    if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE)                             \
+      docShellBusy.AppendLiteral("'none'");                                    \
+    if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY)                              \
+      docShellBusy.AppendLiteral("'busy'");                                    \
+    if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD)                  \
+      docShellBusy.AppendLiteral(", 'before page load'");                      \
+    if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)                      \
+      docShellBusy.AppendLiteral(", 'page loading'");                          \
+  }                                                                            \
+  else {                                                                       \
+    docShellBusy.AppendLiteral("[failed]");                                    \
+  }                                                                            \
   printf("docshell busy: %s", docShellBusy.get());
 
 #define NS_LOG_ACCDOC_DOCSTATES(aDocument)                                     \
   const char *docState = 0;                                                    \
   nsIDocument::ReadyState docStateFlag = aDocument->GetReadyStateEnum();       \
   switch (docStateFlag) {                                                      \
     case nsIDocument::READYSTATE_UNINITIALIZED:                                \
      docState = "uninitialized";                                               \
@@ -331,30 +340,32 @@ private:
 
 #define NS_LOG_ACCDOC_DOCINFO_BEGIN                                            \
   printf("  {\n");
 #define NS_LOG_ACCDOC_DOCINFO_BODY(aDocument, aDocAcc)                         \
   {                                                                            \
     printf("    ");                                                            \
     NS_LOG_ACCDOC_ADDRESS(aDocument, aDocAcc)                                  \
     printf("\n    ");                                                          \
-    NS_LOG_ACCDOC_URI(aDocument)                                               \
-    printf("\n    ");                                                          \
-    NS_LOG_ACCDOC_SHELLSTATE(aDocument)                                        \
-    printf("; ");                                                              \
-    NS_LOG_ACCDOC_TYPE(aDocument)                                              \
-    printf("\n    ");                                                          \
-    NS_LOG_ACCDOC_DOCSTATES(aDocument)                                         \
-    printf("\n    ");                                                          \
-    NS_LOG_ACCDOC_DOCPRESSHELL(aDocument)                                      \
-    printf("\n    ");                                                          \
-    NS_LOG_ACCDOC_DOCLOADGROUP(aDocument)                                      \
-    printf(", ");                                                              \
-    NS_LOG_ACCDOC_DOCPARENT(aDocument)                                         \
-    printf("\n");                                                              \
+    if (aDocument) {                                                           \
+      NS_LOG_ACCDOC_URI(aDocument)                                             \
+      printf("\n    ");                                                        \
+      NS_LOG_ACCDOC_SHELLSTATE(aDocument)                                      \
+      printf("; ");                                                            \
+      NS_LOG_ACCDOC_TYPE(aDocument)                                            \
+      printf("\n    ");                                                        \
+      NS_LOG_ACCDOC_DOCSTATES(aDocument)                                       \
+      printf("\n    ");                                                        \
+      NS_LOG_ACCDOC_DOCPRESSHELL(aDocument)                                    \
+      printf("\n    ");                                                        \
+      NS_LOG_ACCDOC_DOCLOADGROUP(aDocument)                                    \
+      printf(", ");                                                            \
+      NS_LOG_ACCDOC_DOCPARENT(aDocument)                                       \
+      printf("\n");                                                            \
+    }                                                                          \
   }
 #define NS_LOG_ACCDOC_DOCINFO_END                                              \
   printf("  }\n");
 
 #define NS_LOG_ACCDOC_DOCINFO(aDocument, aDocAcc)                              \
   NS_LOG_ACCDOC_DOCINFO_BEGIN                                                  \
   NS_LOG_ACCDOC_DOCINFO_BODY(aDocument, aDocAcc)                               \
   NS_LOG_ACCDOC_DOCINFO_END
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -155,17 +155,18 @@ nsAccUtils::GetPositionAndSizeForXULSele
   *aSetSize = itemsCount;
   *aPosInSet = indexOf;
 
   for (PRUint32 index = 0; index < itemsCount; index++) {
     nsCOMPtr<nsIDOMXULSelectControlItemElement> currItem;
     control->GetItemAtIndex(index, getter_AddRefs(currItem));
     nsCOMPtr<nsINode> currNode(do_QueryInterface(currItem));
 
-    nsAccessible* itemAcc = GetAccService()->GetAccessible(currNode);
+    nsAccessible* itemAcc = currNode ?
+      GetAccService()->GetAccessible(currNode) : nsnull;
 
     if (!itemAcc || itemAcc->State() & states::INVISIBLE) {
       (*aSetSize)--;
       if (index < static_cast<PRUint32>(indexOf))
         (*aPosInSet)--;
     }
   }
 
@@ -196,17 +197,18 @@ nsAccUtils::GetPositionAndSizeForXULCont
 
   // Calculate set size and position in the set.
   *aSetSize = 0, *aPosInSet = 0;
   for (PRInt32 index = indexOf; index >= 0; index--) {
     nsCOMPtr<nsIDOMXULElement> item;
     container->GetItemAtIndex(index, getter_AddRefs(item));
     nsCOMPtr<nsINode> itemNode(do_QueryInterface(item));
 
-    nsAccessible* itemAcc = GetAccService()->GetAccessible(itemNode);
+    nsAccessible* itemAcc = itemNode ?
+      GetAccService()->GetAccessible(itemNode) : nsnull;
 
     if (itemAcc) {
       PRUint32 itemRole = Role(itemAcc);
       if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
         break; // We reached the beginning of our group.
 
       if (!(itemAcc->State() & states::INVISIBLE)) {
         (*aSetSize)++;
@@ -215,18 +217,19 @@ nsAccUtils::GetPositionAndSizeForXULCont
     }
   }
 
   for (PRInt32 index = indexOf + 1; index < static_cast<PRInt32>(itemsCount);
        index++) {
     nsCOMPtr<nsIDOMXULElement> item;
     container->GetItemAtIndex(index, getter_AddRefs(item));
     nsCOMPtr<nsINode> itemNode(do_QueryInterface(item));
-    
-    nsAccessible* itemAcc = GetAccService()->GetAccessible(itemNode);
+
+    nsAccessible* itemAcc =
+      itemNode ? GetAccService()->GetAccessible(itemNode) : nsnull;
 
     if (itemAcc) {
       PRUint32 itemRole = Role(itemAcc);
       if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
         break; // We reached the end of our group.
 
       if (!(itemAcc->State() & states::INVISIBLE))
         (*aSetSize)++;
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -837,16 +837,18 @@ nsAccessibilityService::GetAccessibleInS
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService public
 
 nsAccessible*
 nsAccessibilityService::GetAccessible(nsINode* aNode)
 {
+  NS_PRECONDITION(aNode, "Getting an accessible for null node! Crash.");
+
   nsDocAccessible* document = GetDocAccessible(aNode->GetOwnerDoc());
   return document ? document->GetAccessible(aNode) : nsnull;
 }
 
 nsAccessible*
 nsAccessibilityService::GetAccessibleOrContainer(nsINode* aNode,
                                                  nsIWeakReference* aWeakShell)
 {
--- a/accessible/src/base/nsBaseWidgetAccessible.cpp
+++ b/accessible/src/base/nsBaseWidgetAccessible.cpp
@@ -88,76 +88,65 @@ nsLeafAccessible::CacheChildren()
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsLinkableAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsLinkableAccessible::
   nsLinkableAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsAccessibleWrap(aContent, aShell),
-  mActionContent(nsnull),
+  mActionAcc(nsnull),
   mIsLink(PR_FALSE),
   mIsOnclick(PR_FALSE)
 {
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(nsLinkableAccessible, nsAccessibleWrap)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsLinkableAccessible. nsIAccessible
 
 NS_IMETHODIMP
 nsLinkableAccessible::TakeFocus()
 {
-  nsAccessible *actionAcc = GetActionAccessible();
-  if (actionAcc)
-    return actionAcc->TakeFocus();
-
-  return nsAccessibleWrap::TakeFocus();
+  return mActionAcc ? mActionAcc->TakeFocus() : nsAccessibleWrap::TakeFocus();
 }
 
 PRUint64
 nsLinkableAccessible::NativeState()
 {
   PRUint64 states = nsAccessibleWrap::NativeState();
   if (mIsLink) {
     states |= states::LINKED;
-    nsAccessible* actionAcc = GetActionAccessible();
-    if (actionAcc->State() & states::TRAVERSED)
+    if (mActionAcc->State() & states::TRAVERSED)
       states |= states::TRAVERSED;
   }
 
   return states;
 }
 
 NS_IMETHODIMP
 nsLinkableAccessible::GetValue(nsAString& aValue)
 {
   aValue.Truncate();
 
   nsAccessible::GetValue(aValue);
   if (!aValue.IsEmpty())
     return NS_OK;
 
-  if (mIsLink) {
-    nsAccessible *actionAcc = GetActionAccessible();
-    if (actionAcc)
-      return actionAcc->GetValue(aValue);
-  }
-
-  return NS_ERROR_NOT_IMPLEMENTED;
+  return mIsLink ? mActionAcc->GetValue(aValue) : NS_ERROR_NOT_IMPLEMENTED;
 }
 
 
 NS_IMETHODIMP
 nsLinkableAccessible::GetNumActions(PRUint8 *aNumActions)
 {
   NS_ENSURE_ARG_POINTER(aNumActions);
 
-  *aNumActions = mActionContent ? 1 : 0;
+  *aNumActions = mActionAcc ? 1 : 0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsLinkableAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
 {
   aName.Truncate();
 
@@ -177,125 +166,99 @@ nsLinkableAccessible::GetActionName(PRUi
 }
 
 NS_IMETHODIMP
 nsLinkableAccessible::DoAction(PRUint8 aIndex)
 {
   if (aIndex != eAction_Jump)
     return NS_ERROR_INVALID_ARG;
 
-  nsAccessible *actionAcc = GetActionAccessible();
-  if (actionAcc)
-    return actionAcc->DoAction(aIndex);
-  
-  return nsAccessibleWrap::DoAction(aIndex);
+  return mActionAcc ? mActionAcc->DoAction(aIndex) :
+    nsAccessibleWrap::DoAction(aIndex);
 }
 
 NS_IMETHODIMP
 nsLinkableAccessible::GetKeyboardShortcut(nsAString& aKeyboardShortcut)
 {
   aKeyboardShortcut.Truncate();
 
-  nsAccessible *actionAcc = GetActionAccessible();
-  if (actionAcc)
-    return actionAcc->GetKeyboardShortcut(aKeyboardShortcut);
-
-  return nsAccessible::GetKeyboardShortcut(aKeyboardShortcut);
+  return mActionAcc ? mActionAcc->GetKeyboardShortcut(aKeyboardShortcut) :
+    nsAccessible::GetKeyboardShortcut(aKeyboardShortcut);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsLinkableAccessible. nsAccessNode
 
 void
 nsLinkableAccessible::Shutdown()
 {
-  mActionContent = nsnull;
+  mIsLink = PR_FALSE;
+  mIsOnclick = PR_FALSE;
+  mActionAcc = nsnull;
   nsAccessibleWrap::Shutdown();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsLinkableAccessible: HyperLinkAccessible
 
 already_AddRefed<nsIURI>
 nsLinkableAccessible::GetAnchorURI(PRUint32 aAnchorIndex)
 {
   if (mIsLink) {
-    nsAccessible* link = GetActionAccessible();
-    if (link) {
-      NS_ASSERTION(link->IsHyperLink(),
-                   "nsIAccessibleHyperLink isn't implemented.");
+    NS_ASSERTION(mActionAcc->IsHyperLink(),
+                 "nsIAccessibleHyperLink isn't implemented.");
 
-      if (link->IsHyperLink())
-        return link->GetAnchorURI(aAnchorIndex);
-    }
+    if (mActionAcc->IsHyperLink())
+      return mActionAcc->GetAnchorURI(aAnchorIndex);
   }
 
   return nsnull;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsLinkableAccessible: nsAccessible protected
 
 void
 nsLinkableAccessible::BindToParent(nsAccessible* aParent,
                                    PRUint32 aIndexInParent)
 {
   nsAccessibleWrap::BindToParent(aParent, aIndexInParent);
 
   // Cache action content.
-  mActionContent = nsnull;
+  mActionAcc = nsnull;
   mIsLink = PR_FALSE;
   mIsOnclick = PR_FALSE;
 
-  nsIContent* walkUpContent = mContent;
-  PRBool isOnclick = nsCoreUtils::HasClickListener(walkUpContent);
-
-  if (isOnclick) {
-    mActionContent = walkUpContent;
+  if (nsCoreUtils::HasClickListener(mContent)) {
+    mActionAcc = this;
     mIsOnclick = PR_TRUE;
     return;
   }
 
-  while ((walkUpContent = walkUpContent->GetParent())) {
-    nsAccessible* walkUpAcc =
-      GetAccService()->GetAccessibleInWeakShell(walkUpContent, mWeakShell);
-
+  // XXX: The logic looks broken since the click listener may be registered
+  // on non accessible node in parent chain but this node is skipped when tree
+  // is traversed.
+  nsAccessible* walkUpAcc = this;
+  while ((walkUpAcc = walkUpAcc->GetParent()) && !walkUpAcc->IsDoc()) {
     if (walkUpAcc && walkUpAcc->Role() == nsIAccessibleRole::ROLE_LINK &&
         walkUpAcc->State() & states::LINKED) {
       mIsLink = PR_TRUE;
-      mActionContent = walkUpContent;
+      mActionAcc = walkUpAcc;
       return;
     }
 
-    isOnclick = nsCoreUtils::HasClickListener(walkUpContent);
-    if (isOnclick) {
-      mActionContent = walkUpContent;
+    if (nsCoreUtils::HasClickListener(walkUpAcc->GetContent())) {
+      mActionAcc = walkUpAcc;
       mIsOnclick = PR_TRUE;
       return;
     }
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsLinkableAccessible: protected
-
-nsAccessible *
-nsLinkableAccessible::GetActionAccessible() const
-{
-  // Return accessible for the action content if it's different from node of
-  // this accessible. If the action accessible is not null then it is used to
-  // redirect methods calls otherwise we use method implementation from the
-  // base class.
-  if (!mActionContent || mContent == mActionContent)
-    return nsnull;
-
-  return GetAccService()->GetAccessibleInWeakShell(mActionContent, mWeakShell);
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // nsEnumRoleAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsEnumRoleAccessible::
   nsEnumRoleAccessible(nsIContent *aNode, nsIWeakReference *aShell,
                        PRUint32 aRole) :
   nsAccessibleWrap(aNode, aShell), mRole(aRole)
 {
--- a/accessible/src/base/nsBaseWidgetAccessible.h
+++ b/accessible/src/base/nsBaseWidgetAccessible.h
@@ -103,24 +103,20 @@ public:
 
   // HyperLinkAccessible
   virtual already_AddRefed<nsIURI> GetAnchorURI(PRUint32 aAnchorIndex);
 
 protected:
   // nsAccessible
   virtual void BindToParent(nsAccessible* aParent, PRUint32 aIndexInParent);
 
-  // nsLinkableAccessible
-
   /**
-   * Return an accessible for cached action node.
+   * Parent accessible that provides an action for this linkable accessible.
    */
-  nsAccessible *GetActionAccessible() const;
-
-  nsCOMPtr<nsIContent> mActionContent;
+  nsAccessible* mActionAcc;
   PRPackedBool mIsLink;
   PRPackedBool mIsOnclick;
 };
 
 /**
  * A simple accessible that gets its enumerated role passed into constructor.
  */ 
 class nsEnumRoleAccessible : public nsAccessibleWrap
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -488,22 +488,20 @@ nsCoreUtils::IsErrorPage(nsIDocument *aD
   PRBool isAboutScheme = PR_FALSE;
   uri->SchemeIs("about", &isAboutScheme);
   if (!isAboutScheme)
     return PR_FALSE;
 
   nsCAutoString path;
   uri->GetPath(path);
 
-  nsCAutoString::const_iterator start, end;
-  path.BeginReading(start);
-  path.EndReading(end);
+  NS_NAMED_LITERAL_CSTRING(neterror, "neterror");
+  NS_NAMED_LITERAL_CSTRING(certerror, "certerror");
 
-  NS_NAMED_LITERAL_CSTRING(neterror, "neterror");
-  return FindInReadable(neterror, start, end);
+  return StringBeginsWith(path, neterror) || StringBeginsWith(path, certerror);
 }
 
 PRBool
 nsCoreUtils::IsCorrectFrameType(nsIFrame *aFrame, nsIAtom *aAtom)
 {
   NS_ASSERTION(aFrame != nsnull,
                "aFrame is null in call to IsCorrectFrameType!");
   NS_ASSERTION(aAtom != nsnull,
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -208,18 +208,18 @@ PRBool
 nsOuterDocAccessible::RemoveChild(nsAccessible *aAccessible)
 {
   nsAccessible *child = mChildren.SafeElementAt(0, nsnull);
   if (child != aAccessible) {
     NS_ERROR("Wrong child to remove!");
     return PR_FALSE;
   }
 
-  NS_LOG_ACCDOCDESTROY("remove document from outerdoc",
-                       child->GetDocumentNode())
+  NS_LOG_ACCDOCDESTROY_FOR("remove document from outerdoc",
+                           child->GetDocumentNode(), child)
   NS_LOG_ACCDOCDESTROY_ACCADDRESS("outerdoc", this)
 
   PRBool wasRemoved = nsAccessible::RemoveChild(child);
 
   NS_ASSERTION(!mChildren.Length(),
                "This child document of outerdoc accessible wasn't removed!");
 
   return wasRemoved;
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -1009,17 +1009,17 @@ nsresult nsHyperTextAccessible::GetTextH
   else {
     finalStartOffset = GetRelativeOffset(presShell, startFrame, startOffset,
                                          startAcc, amount, eDirPrevious,
                                          needsStart);
     NS_ENSURE_TRUE(finalStartOffset >= 0, NS_ERROR_FAILURE);
   }
 
   if (aType == eGetBefore) {
-    endOffset = aOffset;
+    finalEndOffset = aOffset;
   }
   else {
     // Start moving forward from the start so that we don't get 
     // 2 words/lines if the offset occurred on whitespace boundary
     // Careful, startOffset and endOffset are passed by reference to GetPosAndText() and changed
     // For BOUNDARY_LINE_END, make sure we start of this line
     startOffset = endOffset = finalStartOffset + (aBoundaryType == BOUNDARY_LINE_END);
     nsRefPtr<nsAccessible> endAcc;
--- a/accessible/tests/mochitest/events/docload_wnd.xul
+++ b/accessible/tests/mochitest/events/docload_wnd.xul
@@ -187,34 +187,34 @@
       {
         return "reload page";
       }
     }
 
     /**
      * Load wrong URI what results in error page loading.
      */
-    function loadErrorPageInvoker()
+    function loadErrorPageInvoker(aURL, aURLDescr)
     {
       this.invoke = function loadErrorPageInvoker_invoke()
       {
-        gTabBrowser.loadURI("www.wronguri.wronguri");
+        gTabBrowser.loadURI(aURL);
       }
 
       this.eventSeq = [
         // We don't expect state change for busy true, load stopped events since
         // things happen quickly and it's coalesced.
         new invokerChecker(EVENT_REORDER, getContainer),
         new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getDocument),
         new stateBusyChecker(false)
       ];
 
       this.getID = function loadErrorPageInvoker_getID()
       {
-        return "load error page";
+        return "load error page: '" + aURLDescr + "'";
       }
     }
 
     ////////////////////////////////////////////////////////////////////////////
     // Tests
 
     var gQueue = null;
 
@@ -225,17 +225,21 @@
     {
       gTabBrowser = document.getElementById("content");
 
       gQueue = new gOpenerWnd.eventQueue();
       gQueue.push(new loadURIInvoker("about:"));
       gQueue.push(new clickReloadBtnInvoker());
       gQueue.push(new loadURIInvoker("about:mozilla"));
       gQueue.push(new reloadInvoker());
-      gQueue.push(new loadErrorPageInvoker());
+      gQueue.push(new loadErrorPageInvoker("www.wronguri.wronguri",
+                                           "Server not found"));
+      gQueue.push(new loadErrorPageInvoker("https://nocert.example.com:443",
+                                          "Untrusted Connection"));
+
       gQueue.onFinish = function() { window.close(); }
       gQueue.invoke();
     }
 
     gOpenerWnd.addA11yLoadEvent(doTest);
   ]]>
   </script>
 
--- a/accessible/tests/mochitest/text/Makefile.in
+++ b/accessible/tests/mochitest/text/Makefile.in
@@ -45,15 +45,15 @@ relativesrcdir  = accessible/text
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
 		doc.html \
 		test_doc.html \
 		test_hypertext.html \
 		test_passwords.html \
-		$(warning test_singleline.html disabled due to bug 652459) \
-		$(warning test_whitespaces.html disabled due to bug 652459) \
+		test_singleline.html \
+		test_whitespaces.html \
 		test_words.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
--- a/accessible/tests/mochitest/text/test_singleline.html
+++ b/accessible/tests/mochitest/text/test_singleline.html
@@ -211,50 +211,50 @@
       // BOUNDARY_CHAR
       testCharBeforeOffset(IDs, 0, "", 0, 0);
       testCharBeforeOffset(IDs, 1, "h", 0, 1);
       testCharBeforeOffset(IDs, 14, "n", 13, 14);
       testCharBeforeOffset(IDs, 15, "d", 14, 15);
 
       // BOUNDARY_WORD_START
       testTextBeforeOffset(0, BOUNDARY_WORD_START, "", 0, 0,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+                           "input", kOk, kOk, kOk,
+                           "div", kOk, kOk, kOk,
+                           "editable", kOk, kOk, kOk,
+                           "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(1, BOUNDARY_WORD_START, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
       testTextBeforeOffset(5, BOUNDARY_WORD_START, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
       testTextBeforeOffset(6, BOUNDARY_WORD_START, "hello ", 0, 6,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+                           "input", kOk, kOk, kOk,
+                           "div", kOk, kOk, kOk,
+                           "editable", kOk, kOk, kOk,
+                           "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(7, BOUNDARY_WORD_START, "hello ", 0, 6,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
       testTextBeforeOffset(8, BOUNDARY_WORD_START, "hello ", 0, 6,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
       testTextBeforeOffset(9, BOUNDARY_WORD_START, "my ", 6, 9,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+                           "input", kOk, kOk, kOk,
+                           "div", kOk, kOk, kOk,
+                           "editable", kOk, kOk, kOk,
+                           "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(10, BOUNDARY_WORD_START, "my ", 6, 9,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
       testTextBeforeOffset(14, BOUNDARY_WORD_START, "my ", 6, 9,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
@@ -263,35 +263,35 @@
       testTextBeforeOffset(15, BOUNDARY_WORD_START, "my ", 6, 9,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
 
       // BOUNDARY_WORD_END
       testTextBeforeOffset(0, BOUNDARY_WORD_END, "", 0, 0,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+                           "input", kOk, kOk, kOk,
+                           "div", kOk, kOk, kOk,
+                           "editable", kOk, kOk, kOk,
+                           "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(1, BOUNDARY_WORD_END, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
       testTextBeforeOffset(5, BOUNDARY_WORD_END, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
       testTextBeforeOffset(6, BOUNDARY_WORD_END, "hello ", 0, 6,
-                           "input", kTodo, kTodo, kTodo,
-                           "div", kTodo, kTodo, kTodo,
-                           "editable", kTodo, kTodo, kTodo,
-                           "textarea", kTodo, kTodo, kTodo);
+                           "input", kTodo, kTodo, kOk,
+                           "div", kTodo, kTodo, kOk,
+                           "editable", kTodo, kTodo, kOk,
+                           "textarea", kTodo, kTodo, kOk);
       testTextBeforeOffset(7, BOUNDARY_WORD_END, "hello ", 0, 6,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
       testTextBeforeOffset(8, BOUNDARY_WORD_END, "hello ", 0, 6,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
@@ -315,20 +315,20 @@
       testTextBeforeOffset(15, BOUNDARY_WORD_END, " my", 5, 8,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
 
       // BOUNDARY_LINE_START
       testTextBeforeOffset(0, BOUNDARY_LINE_START, "", 0, 0,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+                           "input", kOk, kOk, kOk,
+                           "div", kOk, kOk, kOk,
+                           "editable", kOk, kOk, kOk,
+                           "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(1, BOUNDARY_LINE_START, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
       testTextBeforeOffset(14, BOUNDARY_LINE_START, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
@@ -337,20 +337,20 @@
       testTextBeforeOffset(15, BOUNDARY_LINE_START, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
 
       // BOUNDARY_LINE_END
       testTextBeforeOffset(0, BOUNDARY_LINE_END, "", 0, 0,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+                           "input", kOk, kOk, kOk,
+                           "div", kOk, kOk, kOk,
+                           "editable", kOk, kOk, kOk,
+                           "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(1, BOUNDARY_LINE_END, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
       testTextBeforeOffset(14, BOUNDARY_LINE_END, "", 0, 0,
                            "input", kOk, kOk, kOk,
                            "div", kOk, kOk, kOk,
--- a/accessible/tests/mochitest/text/test_whitespaces.html
+++ b/accessible/tests/mochitest/text/test_whitespaces.html
@@ -191,50 +191,50 @@
       testCharBeforeOffset(IDs, 6, " ", 5, 6);
       testCharBeforeOffset(IDs, 10, " ", 9, 10);
       testCharBeforeOffset(IDs, 11, " ", 10, 11);
       testCharBeforeOffset(IDs, 17, " ", 16, 17);
       testCharBeforeOffset(IDs, 19, " ", 18, 19);
 
       // BOUNDARY_WORD_START
       testTextBeforeOffset(0, BOUNDARY_WORD_START, "", 0, 0,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+                           "input", kOk, kOk, kOk,
+                           "div", kOk, kOk, kOk,
+                           "editable", kOk, kOk, kOk,
+                           "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(1, BOUNDARY_WORD_START, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
       testTextBeforeOffset(5, BOUNDARY_WORD_START, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
       testTextBeforeOffset(6, BOUNDARY_WORD_START, "Brave ", 0, 6,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+                           "input", kOk, kOk, kOk,
+                           "div", kOk, kOk, kOk,
+                           "editable", kOk, kOk, kOk,
+                           "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(9, BOUNDARY_WORD_START, "Brave ", 0, 6,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
       testTextBeforeOffset(10, BOUNDARY_WORD_START, "Brave ", 0, 6,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
       testTextBeforeOffset(11, BOUNDARY_WORD_START, "Sir  ", 6, 11,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+                           "input", kOk, kOk, kOk,
+                           "div", kOk, kOk, kOk,
+                           "editable", kOk, kOk, kOk,
+                           "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(15, BOUNDARY_WORD_START, "Sir  ", 6, 11,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
       testTextBeforeOffset(16, BOUNDARY_WORD_START, "Sir  ", 6, 11,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
@@ -246,37 +246,37 @@
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
       testTextBeforeOffset(18, BOUNDARY_WORD_START, "Sir  ", 6, 11,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
       testTextBeforeOffset(19, BOUNDARY_WORD_START, "Robin   ", 11, 19,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+                           "input", kOk, kOk, kOk,
+                           "div", kOk, kOk, kOk,
+                           "editable", kOk, kOk, kOk,
+                           "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(20, BOUNDARY_WORD_START, "Robin   ", 11, 19,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
       testTextBeforeOffset(21, BOUNDARY_WORD_START, "Robin   ", 11, 19,
                            "input", kTodo, kTodo, kTodo,
                            "div", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
 
       // BOUNDARY_WORD_END
       testTextBeforeOffset(0, BOUNDARY_WORD_END, "", 0, 0,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+                           "input", kOk, kOk, kOk,
+                           "div", kOk, kOk, kOk,
+                           "editable", kOk, kOk, kOk,
+                           "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(1, BOUNDARY_WORD_END, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
       testTextBeforeOffset(4, BOUNDARY_WORD_END, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1000,16 +1000,29 @@ pref("devtools.scratchpad.enabled", true
 // Enable tools for Chrome development.
 pref("devtools.chrome.enabled", false);
 
 // The last Web Console height. This is initially 0 which means that the Web
 // Console will use the default height next time it shows.
 // Change to -1 if you do not want the Web Console to remember its last height.
 pref("devtools.hud.height", 0);
 
+// Remember the Web Console position. Possible values:
+//   above - above the web page,
+//   below - below the web page,
+//   window - in a separate window/popup panel.
+pref("devtools.webconsole.position", "above");
+
+// The number of lines that are displayed in the web console for the Net,
+// CSS, JS and Web Developer categories.
+pref("devtools.hud.loglimit.network", 200);
+pref("devtools.hud.loglimit.cssparser", 200);
+pref("devtools.hud.loglimit.exception", 200);
+pref("devtools.hud.loglimit.console", 200);
+
 // Whether the character encoding menu is under the main Firefox button. This
 // preference is a string so that localizers can alter it.
 pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.properties");
 
 // Allow using tab-modal prompts when possible.
 pref("prompts.tab_modal.enabled", true);
 // Whether the Panorama should animate going in/out of tabs
 pref("browser.panorama.animate_zoom", true);
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -457,17 +457,16 @@ browser[tabmodalPromptShowing] {
 /* Status panel */
 
 statuspanel {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#statuspanel");
   position: fixed;
   margin-top: -3em;
   left: 0;
   max-width: 50%;
-  -moz-transition: opacity 100ms ease-out;
 }
 
 statuspanel:-moz-locale-dir(ltr)[mirror],
 statuspanel:-moz-locale-dir(rtl):not([mirror]) {
   left: auto;
   right: 0;
 }
 
@@ -477,16 +476,17 @@ statuspanel[type=status] {
 
 @media all and (max-width: 800px) {
   statuspanel[type=status] {
     min-width: 33%;
   }
 }
 
 statuspanel[type=overLink] {
+  -moz-transition: opacity 100ms ease-out;
   direction: ltr;
 }
 
 statuspanel[label=""] {
   -moz-transition: none;
   opacity: 0;
   pointer-events: none;
 }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1380,17 +1380,17 @@ function prepareForStartup() {
   gBrowser.addEventListener("PluginNotFound",     gPluginHandler, true);
   gBrowser.addEventListener("PluginCrashed",      gPluginHandler, true);
   gBrowser.addEventListener("PluginBlocklisted",  gPluginHandler, true);
   gBrowser.addEventListener("PluginOutdated",     gPluginHandler, true);
   gBrowser.addEventListener("PluginDisabled",     gPluginHandler, true);
   gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true);
 #ifdef XP_MACOSX
   gBrowser.addEventListener("npapi-carbon-event-model-failure", gPluginHandler, true);
-#endif 
+#endif
 
   Services.obs.addObserver(gPluginHandler.pluginCrashed, "plugin-crashed", false);
 
   window.addEventListener("AppCommand", HandleAppCommandEvent, true);
 
   var webNavigation;
   try {
     webNavigation = getWebNavigation();
@@ -6693,56 +6693,65 @@ var gPluginHandler = {
                                 }
                               },
                               true);
   },
 
   handleEvent : function(event) {
     let self = gPluginHandler;
     let plugin = event.target;
-    let hideBarPrefName;
+    let doc = plugin.ownerDocument;
 
     // We're expecting the target to be a plugin.
     if (!(plugin instanceof Ci.nsIObjectLoadingContent))
       return;
 
+    // Force a style flush, so that we ensure our binding is attached.
+    plugin.clientTop;
+
     switch (event.type) {
       case "PluginCrashed":
         self.pluginInstanceCrashed(plugin, event);
         break;
 
       case "PluginNotFound":
         // For non-object plugin tags, register a click handler to install the
         // plugin. Object tags can, and often do, deal with that themselves,
         // so don't stomp on the page developers toes.
-        if (!(plugin instanceof HTMLObjectElement))
-          self.addLinkClickCallback(plugin, "installSinglePlugin");
+        if (!(plugin instanceof HTMLObjectElement)) {
+          // We don't yet check to see if there's actually an installer available.
+          let installStatus = doc.getAnonymousElementByAttribute(plugin, "class", "installStatus");
+          installStatus.setAttribute("status", "ready");
+          let iconStatus = doc.getAnonymousElementByAttribute(plugin, "class", "icon");
+          iconStatus.setAttribute("status", "ready");
+
+          let installLink = doc.getAnonymousElementByAttribute(plugin, "class", "installPluginLink");
+          self.addLinkClickCallback(installLink, "installSinglePlugin", plugin);
+        }
         /* FALLTHRU */
+
       case "PluginBlocklisted":
       case "PluginOutdated":
-        hideBarPrefName = event.type == "PluginOutdated" ?
-                                "plugins.hide_infobar_for_outdated_plugin" :
-                                "plugins.hide_infobar_for_missing_plugin";
-        if (gPrefService.getBoolPref(hideBarPrefName))
-          return;
-
+#ifdef XP_MACOSX
+      case "npapi-carbon-event-model-failure":
+#endif
         self.pluginUnavailable(plugin, event.type);
         break;
-#ifdef XP_MACOSX
-      case "npapi-carbon-event-model-failure":
-        hideBarPrefName = "plugins.hide_infobar_for_carbon_failure_plugin";
-        if (gPrefService.getBoolPref(hideBarPrefName))
-          return;
-
-        self.pluginUnavailable(plugin, event.type);
+
+      case "PluginDisabled":
+        let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink");
+        self.addLinkClickCallback(manageLink, "managePlugins");
         break;
-#endif
-      case "PluginDisabled":
-        self.addLinkClickCallback(plugin, "managePlugins");
-        break;
+    }
+
+    // Hide the in-content UI if it's too big. The crashed plugin handler already did this.
+    if (event.type != "PluginCrashed") {
+      let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
+      if (self.isTooSmall(plugin, overlay))
+          overlay.style.visibility = "hidden";
     }
   },
 
   newPluginInstalled : function(event) {
     // browser elements are anonymous so we can't just use target.
     var browser = event.originalTarget;
     // clear the plugin list, now that at least one plugin has been installed
     browser.missingPlugins = null;
@@ -6752,20 +6761,20 @@ var gPluginHandler = {
     if (notification)
       notificationBox.removeNotification(notification);
 
     // reload the browser to make the new plugin show.
     browser.reload();
   },
 
   // Callback for user clicking on a missing (unsupported) plugin.
-  installSinglePlugin: function (aEvent) {
+  installSinglePlugin: function (plugin) {
     var missingPluginsArray = {};
 
-    var pluginInfo = getPluginInfo(aEvent.target);
+    var pluginInfo = getPluginInfo(plugin);
     missingPluginsArray[pluginInfo.mimetype] = pluginInfo;
 
     openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
                "PFSWindow", "chrome,centerscreen,resizable=yes",
                {plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
   },
 
   // Callback for user clicking on a disabled plugin
@@ -6805,19 +6814,16 @@ var gPluginHandler = {
     var notificationBox = gBrowser.getNotificationBox(browser);
 
     // Should only display one of these warnings per page.
     // In order of priority, they are: outdated > missing > blocklisted
     let outdatedNotification = notificationBox.getNotificationWithValue("outdated-plugins");
     let blockedNotification  = notificationBox.getNotificationWithValue("blocked-plugins");
     let missingNotification  = notificationBox.getNotificationWithValue("missing-plugins");
 
-    // If there is already an outdated plugin notification then do nothing
-    if (outdatedNotification)
-      return;
 
     function showBlocklistInfo() {
       var url = formatURL("extensions.blocklist.detailsURL", true);
       gBrowser.loadOneTab(url, {inBackground: false});
       return true;
     }
 
     function showOutdatedPluginsInfo() {
@@ -6839,17 +6845,17 @@ var gPluginHandler = {
 
 #ifdef XP_MACOSX
     function carbonFailurePluginsRestartBrowser()
     {
       // Notify all windows that an application quit has been requested.
       let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].
                          createInstance(Ci.nsISupportsPRBool);
       Services.obs.notifyObservers(cancelQuit, "quit-application-requested", null);
- 
+
       // Something aborted the quit process.
       if (cancelQuit.data)
         return;
 
       let as = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
       as.quit(Ci.nsIAppStartup.eRestarti386 | Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
     }
 #endif
@@ -6903,43 +6909,60 @@ var gPluginHandler = {
                                                          label     : gNavigatorBundle.getString("carbonFailurePluginsMessage.restartButton.label"),
                                                          accessKey : gNavigatorBundle.getString("carbonFailurePluginsMessage.restartButton.accesskey"),
                                                          popup     : null,
                                                          callback  : carbonFailurePluginsRestartBrowser
                                                       }],
                             }
 #endif
     };
+
+    // If there is already an outdated plugin notification then do nothing
+    if (outdatedNotification)
+      return;
+
 #ifdef XP_MACOSX
     if (eventType == "npapi-carbon-event-model-failure") {
-
-      let carbonFailureNotification = 
+      if (gPrefService.getBoolPref("plugins.hide_infobar_for_carbon_failure_plugin"))
+        return;
+
+      let carbonFailureNotification =
         notificationBox.getNotificationWithValue("carbon-failure-plugins");
 
       if (carbonFailureNotification)
          carbonFailureNotification.close();
 
       let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"].getService(Ci.nsIMacUtils);
       // if this is not a Universal build, just follow PluginNotFound path
       if (!macutils.isUniversalBinary)
         eventType = "PluginNotFound";
     }
 #endif
+
     if (eventType == "PluginBlocklisted") {
+      if (gPrefService.getBoolPref("plugins.hide_infobar_for_missing_plugin")) // XXX add a new pref?
+        return;
+
       if (blockedNotification || missingNotification)
         return;
     }
     else if (eventType == "PluginOutdated") {
+      if (gPrefService.getBoolPref("plugins.hide_infobar_for_outdated_plugin"))
+        return;
+
       // Cancel any notification about blocklisting/missing plugins
       if (blockedNotification)
         blockedNotification.close();
       if (missingNotification)
         missingNotification.close();
     }
     else if (eventType == "PluginNotFound") {
+      if (gPrefService.getBoolPref("plugins.hide_infobar_for_missing_plugin"))
+        return;
+
       if (missingNotification)
         return;
 
       // Cancel any notification about blocklisting plugins
       if (blockedNotification)
         blockedNotification.close();
     }
 
@@ -6985,32 +7008,23 @@ var gPluginHandler = {
     let pluginName      = aEvent.getData("pluginName");
     let pluginFilename  = aEvent.getData("pluginFilename");
     let pluginDumpID    = aEvent.getData("pluginDumpID");
     let browserDumpID   = aEvent.getData("browserDumpID");
 
     // Remap the plugin name to a more user-presentable form.
     pluginName = this.makeNicePluginName(pluginName, pluginFilename);
 
-    // Force a style flush, so that we ensure our binding is attached.
-    plugin.clientTop;
-
     let messageString = gNavigatorBundle.getFormattedString("crashedpluginsMessage.title", [pluginName]);
 
     //
     // Configure the crashed-plugin placeholder.
     //
     let doc = plugin.ownerDocument;
     let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
-
-    // The binding has role="link" here, since missing/disabled/blocked
-    // plugin UI has a onclick handler on the whole thing. This isn't needed
-    // for the plugin-crashed UI, because we use actual HTML links in the text.
-    overlay.removeAttribute("role");
-
     let statusDiv = doc.getAnonymousElementByAttribute(plugin, "class", "submitStatus");
 #ifdef MOZ_CRASHREPORTER
     let status;
 
     // Determine which message to show regarding crash reports.
     if (submittedReport) { // submitReports && !doPrompt, handled in observer
       status = "submitted";
     }
--- a/browser/base/content/scratchpad.js
+++ b/browser/base/content/scratchpad.js
@@ -53,34 +53,34 @@ const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource:///modules/PropertyPanel.jsm");
 
 const SCRATCHPAD_CONTEXT_CONTENT = 1;
-const SCRATCHPAD_CONTEXT_CHROME = 2;
+const SCRATCHPAD_CONTEXT_BROWSER = 2;
 const SCRATCHPAD_WINDOW_URL = "chrome://browser/content/scratchpad.xul";
 const SCRATCHPAD_L10N = "chrome://browser/locale/scratchpad.properties";
 const SCRATCHPAD_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
 const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
 
 /**
  * The scratchpad object handles the Scratchpad window functionality.
  */
 var Scratchpad = {
   /**
    * The script execution context. This tells Scratchpad in which context the
    * script shall execute.
    *
    * Possible values:
    *   - SCRATCHPAD_CONTEXT_CONTENT to execute code in the context of the current
    *   tab content window object.
-   *   - SCRATCHPAD_CONTEXT_CHROME to execute code in the context of the
+   *   - SCRATCHPAD_CONTEXT_BROWSER to execute code in the context of the
    *   currently active chrome window object.
    */
   executionContext: SCRATCHPAD_CONTEXT_CONTENT,
 
   /**
    * Retrieve the xul:textbox DOM element. This element holds the source code
    * the user writes and executes.
    */
@@ -116,42 +116,52 @@ var Scratchpad = {
    * Get the gBrowser object of the most recent browser window.
    */
   get gBrowser()
   {
     let recentWin = this.browserWindow;
     return recentWin ? recentWin.gBrowser : null;
   },
 
+  insertIntro: function SP_insertIntro()
+  {
+    this.textbox.value = this.strings.GetStringFromName("scratchpadIntro");
+  },
+
   /**
    * Cached Cu.Sandbox object for the active tab content window object.
    */
   _contentSandbox: null,
 
   /**
    * Get the Cu.Sandbox object for the active tab content window object. Note
    * that the returned object is cached for later reuse. The cached object is
-   * kept only for the current browser window and it is reset for each context
-   * switch or navigator:browser window switch.
+   * kept only for the current location in the current tab of the current
+   * browser window and it is reset for each context switch,
+   * navigator:browser window switch, tab switch or navigation.
    */
   get contentSandbox()
   {
     if (!this.browserWindow) {
       Cu.reportError(this.strings.
                      GetStringFromName("browserWindow.unavailable"));
       return;
     }
 
     if (!this._contentSandbox ||
-        this.browserWindow != this._previousBrowserWindow) {
+        this.browserWindow != this._previousBrowserWindow ||
+        this._previousBrowser != this.gBrowser.selectedBrowser ||
+        this._previousLocation != this.gBrowser.contentWindow.location.href) {
       let contentWindow = this.gBrowser.selectedBrowser.contentWindow;
       this._contentSandbox = new Cu.Sandbox(contentWindow,
         { sandboxPrototype: contentWindow, wantXrays: false });
 
       this._previousBrowserWindow = this.browserWindow;
+      this._previousBrowser = this.gBrowser.selectedBrowser;
+      this._previousLocation = contentWindow.location.href;
     }
 
     return this._contentSandbox;
   },
 
   /**
    * Cached Cu.Sandbox object for the most recently active navigator:browser
    * chrome window object.
@@ -278,53 +288,53 @@ var Scratchpad = {
            this.evalInContentSandbox(aString) :
            this.evalInChromeSandbox(aString);
   },
 
   /**
    * Execute the selected text (if any) or the entire textbox content in the
    * current context.
    */
-  execute: function SP_execute()
+  run: function SP_run()
   {
     let selection = this.selectedText || this.textbox.value;
     let result = this.evalForContext(selection);
     this.deselect();
     return [selection, result];
   },
 
   /**
    * Execute the selected text (if any) or the entire textbox content in the
    * current context. The resulting object is opened up in the Property Panel
    * for inspection.
    */
   inspect: function SP_inspect()
   {
-    let [selection, result] = this.execute();
+    let [selection, result] = this.run();
 
     if (result) {
       this.openPropertyPanel(selection, result);
     }
   },
 
   /**
    * Execute the selected text (if any) or the entire textbox content in the
-   * current context. The evaluation result is "printed" in the textbox after
+   * current context. The evaluation result is inserted into the textbox after
    * the selected text, or at the end of the textbox value if there is no
    * selected text.
    */
-  print: function SP_print()
+  display: function SP_display()
   {
     let selectionStart = this.textbox.selectionStart;
     let selectionEnd = this.textbox.selectionEnd;
     if (selectionStart == selectionEnd) {
       selectionEnd = this.textbox.value.length;
     }
 
-    let [selection, result] = this.execute();
+    let [selection, result] = this.run();
     if (!result) {
       return;
     }
 
     let firstPiece = this.textbox.value.slice(0, selectionEnd);
     let lastPiece = this.textbox.value.
                     slice(selectionEnd, this.textbox.value.length);
 
@@ -551,44 +561,46 @@ var Scratchpad = {
   },
 
   /**
    * Set the current execution context to be the active tab content window.
    */
   setContentContext: function SP_setContentContext()
   {
     let content = document.getElementById("sp-menu-content");
-    document.getElementById("sp-menu-chrome").removeAttribute("checked");
+    document.getElementById("sp-menu-browser").removeAttribute("checked");
     content.setAttribute("checked", true);
+    this.executionContext = SCRATCHPAD_CONTEXT_CONTENT;
     this.statusbarStatus.label = content.getAttribute("label");
-    this.executionContext = SCRATCHPAD_CONTEXT_CONTENT;
     this.resetContext();
   },
 
   /**
    * Set the current execution context to be the most recent chrome window.
    */
-  setChromeContext: function SP_setChromeContext()
+  setBrowserContext: function SP_setBrowserContext()
   {
-    let chrome = document.getElementById("sp-menu-chrome");
+    let browser = document.getElementById("sp-menu-browser");
     document.getElementById("sp-menu-content").removeAttribute("checked");
-    chrome.setAttribute("checked", true);
-    this.statusbarStatus.label = chrome.getAttribute("label");
-    this.executionContext = SCRATCHPAD_CONTEXT_CHROME;
+    browser.setAttribute("checked", true);
+    this.executionContext = SCRATCHPAD_CONTEXT_BROWSER;
+    this.statusbarStatus.label = browser.getAttribute("label");
     this.resetContext();
   },
 
   /**
    * Reset the cached Cu.Sandbox object for the current context.
    */
   resetContext: function SP_resetContext()
   {
     this._chromeSandbox = null;
     this._contentSandbox = null;
     this._previousWindow = null;
+    this._previousBrowser = null;
+    this._previousLocation = null;
   },
 
   /**
    * Gets the ID of the outer window of the given DOM window object.
    *
    * @param nsIDOMWindow aWindow
    * @return integer
    *         the outer window ID
@@ -599,28 +611,29 @@ var Scratchpad = {
            getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
   },
 
   /**
    * The Scratchpad window DOMContentLoaded event handler.
    */
   onLoad: function SP_onLoad()
   {
-    let chromeContextMenu = document.getElementById("sp-menu-chrome");
+    let chromeContextMenu = document.getElementById("sp-menu-browser");
     let errorConsoleMenu = document.getElementById("sp-menu-errorConsole");
     let errorConsoleCommand = document.getElementById("sp-cmd-errorConsole");
-    let chromeContextCommand = document.getElementById("sp-cmd-chromeContext");
+    let chromeContextCommand = document.getElementById("sp-cmd-browserContext");
 
     let chrome = Services.prefs.getBoolPref(DEVTOOLS_CHROME_ENABLED);
     if (chrome) {
       chromeContextMenu.removeAttribute("hidden");
       errorConsoleMenu.removeAttribute("hidden");
       errorConsoleCommand.removeAttribute("disabled");
       chromeContextCommand.removeAttribute("disabled");
     }
+    this.insertIntro();
   },
 };
 
 XPCOMUtils.defineLazyGetter(Scratchpad, "strings", function () {
   return Services.strings.createBundle(SCRATCHPAD_L10N);
 });
 
 addEventListener("DOMContentLoaded", Scratchpad.onLoad.bind(Scratchpad), false);
--- a/browser/base/content/scratchpad.xul
+++ b/browser/base/content/scratchpad.xul
@@ -65,21 +65,21 @@
   <command id="sp-cmd-save" oncommand="Scratchpad.saveFile();"/>
   <command id="sp-cmd-saveas" oncommand="Scratchpad.saveFileAs();"/>
 
   <!-- TODO: bug 650340 - implement printFile()
   <command id="sp-cmd-printFile" oncommand="Scratchpad.printFile();" disabled="true"/>
  -->
 
   <command id="sp-cmd-close" oncommand="window.close();"/>
-  <command id="sp-cmd-execute" oncommand="Scratchpad.execute();"/>
+  <command id="sp-cmd-run" oncommand="Scratchpad.run();"/>
   <command id="sp-cmd-inspect" oncommand="Scratchpad.inspect();"/>
-  <command id="sp-cmd-print" oncommand="Scratchpad.print();"/>
+  <command id="sp-cmd-display" oncommand="Scratchpad.display();"/>
   <command id="sp-cmd-contentContext" oncommand="Scratchpad.setContentContext();"/>
-  <command id="sp-cmd-chromeContext" oncommand="Scratchpad.setChromeContext();" disabled="true"/>
+  <command id="sp-cmd-browserContext" oncommand="Scratchpad.setBrowserContext();" disabled="true"/>
   <command id="sp-cmd-resetContext" oncommand="Scratchpad.resetContext();"/>
   <command id="sp-cmd-errorConsole" oncommand="Scratchpad.openErrorConsole();" disabled="true"/>
   <command id="sp-cmd-webConsole" oncommand="Scratchpad.openWebConsole();"/>
 </commandset>
 
 <keyset id="sp-keyset">
   <key id="sp-key-window"
        key="&newWindowCmd.commandkey;"
@@ -113,27 +113,27 @@
        key="&copyCmd.key;"
        modifiers="accel"/>
   <key id="key_paste"
        key="&pasteCmd.key;"
        modifiers="accel"/>
   <key id="key_selectAll" key="&selectAllCmd.key;" modifiers="accel"/>
   <key id="key_undo" key="&undoCmd.key;" modifiers="accel"/>
   <key id="key_redo" key="&undoCmd.key;" modifiers="accel,shift"/>
-  <key id="sp-key-execute"
-       key="&execute.key;"
-       command="sp-cmd-execute"
+  <key id="sp-key-run"
+       key="&run.key;"
+       command="sp-cmd-run"
        modifiers="accel"/>
   <key id="sp-key-inspect"
        key="&inspect.key;"
        command="sp-cmd-inspect"
        modifiers="accel"/>
-  <key id="sp-key-print"
-       key="&print.key;"
-       command="sp-cmd-print"
+  <key id="sp-key-display"
+       key="&display.key;"
+       command="sp-cmd-display"
        modifiers="accel"/>
   <key id="sp-key-errorConsole"
        key="&errorConsoleCmd.commandkey;"
        command="sp-cmd-errorConsole"
        modifiers="accel,shift"/>
   <key id="sp-key-webConsole"
        key="&webConsoleCmd.commandkey;"
        command="sp-cmd-webConsole"
@@ -215,17 +215,16 @@
                 accesskey="&pasteCmd.accesskey;"
                 command="cmd_paste"/>
       <menuseparator/>
       <menuitem id="sp-menu-selectAll"
                 label="&selectAllCmd.label;"
                 key="key_selectAll"
                 accesskey="&selectAllCmd.accesskey;"
                 command="cmd_selectAll"/>
-      <menuseparator/>
 
       <!-- TODO: bug 650345 - implement search and replace
       <menuitem id="sp-menu-find"
                 label="&findOnCmd.label;"
                 accesskey="&findOnCmd.accesskey;"
                 key="key_find"
                 disabled="true"
                 command="cmd_find"/>
@@ -233,48 +232,54 @@
                 label="&findAgainCmd.label;"
                 accesskey="&findAgainCmd.accesskey;"
                 key="key_findAgain"
                 disabled="true"
                 command="cmd_findAgain"/>
       <menuseparator id="sp-execute-separator"/>
       -->
 
-      <menuitem id="sp-text-execute"
-                label="&execute.label;"
-                accesskey="&execute.accesskey;"
-                key="sp-key-execute"
-                command="sp-cmd-execute"/>
+    </menupopup>
+  </menu>
+
+  <menu id="sp-execute-menu" label="&executeMenu.label;"
+        accesskey="&executeMenu.accesskey;">
+    <menupopup id="sp-menu_executepopup">
+      <menuitem id="sp-text-run"
+                label="&run.label;"
+                accesskey="&run.accesskey;"
+                key="sp-key-run"
+                command="sp-cmd-run"/>
       <menuitem id="sp-text-inspect"
                 label="&inspect.label;"
                 accesskey="&inspect.accesskey;"
                 key="sp-key-inspect"
                 command="sp-cmd-inspect"/>
-      <menuitem id="sp-text-print"
-                label="&print.label;"
-                accesskey="&print.accesskey;"
-                key="sp-key-print"
-                command="sp-cmd-print"/>
+      <menuitem id="sp-text-display"
+                label="&display.label;"
+                accesskey="&display.accesskey;"
+                key="sp-key-display"
+                command="sp-cmd-display"/>
     </menupopup>
   </menu>
 
-  <menu id="sp-context-menu"
-        label="&contextMenu.label;"
-        accesskey="&contextMenu.accesskey;">
-    <menupopup id="sp-menu-context">
+  <menu id="sp-environment-menu"
+        label="&environmentMenu.label;"
+        accesskey="&environmentMenu.accesskey;">
+    <menupopup id="sp-menu-environment">
       <menuitem id="sp-menu-content"
                 label="&contentContext.label;"
                 accesskey="&contentContext.accesskey;"
                 command="sp-cmd-contentContext"
                 checked="true"
                 type="radio"/>
-      <menuitem id="sp-menu-chrome" hidden="true"
-                command="sp-cmd-chromeContext"
-                label="&chromeContext.label;"
-                accesskey="&chromeContext.accesskey;"
+      <menuitem id="sp-menu-browser" hidden="true"
+                command="sp-cmd-browserContext"
+                label="&browserContext.label;"
+                accesskey="&browserContext.accesskey;"
                 type="radio"/>
       <menuseparator/>
       <menuitem id="sp-menu-resetContext"
                 command="sp-cmd-resetContext"
                 label="&resetContext.label;"
                 accesskey="&resetContext.accesskey;"/>
     </menupopup>
   </menu>
@@ -301,38 +306,38 @@
   <menupopup id="scratchpad-text-popup">
     <menuitem id="menu_cut"/>
     <menuitem id="menu_copy"/>
     <menuitem id="menu_paste"/>
     <menuitem id="menu_delete"/>
     <menuseparator/>
     <menuitem id="menu_selectAll"/>
     <menuseparator/>
-    <menuitem id="sp-text-execute"
-              label="&execute.label;"
-              accesskey="&execute.accesskey;"
-              key="sp-key-execute"
-              command="sp-cmd-execute"/>
+    <menuitem id="sp-text-run"
+              label="&run.label;"
+              accesskey="&run.accesskey;"
+              key="sp-key-run"
+              command="sp-cmd-run"/>
     <menuitem id="sp-text-inspect"
               label="&inspect.label;"
               accesskey="&inspect.accesskey;"
               key="sp-key-inspect"
               command="sp-cmd-inspect"/>
-    <menuitem id="sp-text-print"
-              label="&print.label;"
-              accesskey="&print.accesskey;"
-              key="sp-key-print"
-              command="sp-cmd-print"/>
+    <menuitem id="sp-text-display"
+              label="&display.label;"
+              accesskey="&display.accesskey;"
+              key="sp-key-display"
+              command="sp-cmd-display"/>
   </menupopup>
 </popupset>
 
 <textbox id="scratchpad-textbox"
          multiline="true"
          flex="1"
          context="scratchpad-text-popup"
-         placeholder="&textbox.placeholder;" />
+         placeholder="&textbox.placeholder1;" />
 <statusbar id="scratchpad-statusbar" align="end">
   <statusbarpanel id="scratchpad-status"
                   label="&contentContext.label;"
                   class="statusbarpanel-iconic-text"/>
   <spacer flex="1"/>
 </statusbar>
 </window>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2897,17 +2897,17 @@
               let numNormalTabs = tabs.length - numPinned;
               tabWidth = tabWidth * (numNormalTabs + 1) / numNormalTabs;
               if (tabWidth > this._tabDefaultMaxWidth)
                 tabWidth = this._tabDefaultMaxWidth;
             }
             tabWidth += "px";
             for (let i = numPinned; i < tabs.length; i++) {
               let tab = tabs[i];
-              tab.style.maxWidth = tabWidth;
+              tab.style.setProperty("max-width", tabWidth, "important");
               if (!isEndTab) { // keep tabs the same width
                 tab.style.MozTransition = "none";
                 tab.clientTop; // flush styles to skip animation; see bug 649247
                 tab.style.MozTransition = "";
               }
             }
             this._hasTabTempMaxWidth = true;
             this.tabbrowser.addEventListener("mousemove", this, false);
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -189,16 +189,17 @@ endif
                  browser_inspector_scrolling.js \
                  browser_inspector_store.js \
                  browser_inspector_tab_switch.js \
                  browser_inspector_treePanel_output.js \
                  browser_inspector_treePanel_input.html \
                  browser_inspector_treePanel_result.html \
                  browser_scratchpad_initialization.js \
                  browser_scratchpad_contexts.js \
+                 browser_scratchpad_tab_switch.js \
                  browser_scratchpad_execute_print.js \
                  browser_scratchpad_inspect.js \
                  browser_scratchpad_files.js \
                  browser_scratchpad_ui.js \
                  browser_scratchpad_bug_646070_chrome_context_pref.js \
                  browser_overflowScroll.js \
                  browser_locationBarExternalLoad.js \
                  browser_pageInfo.js \
--- a/browser/base/content/test/browser_pluginnotification.js
+++ b/browser/base/content/test/browser_pluginnotification.js
@@ -122,17 +122,22 @@ function test2() {
 function test3() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
   ok(!notificationBox.getNotificationWithValue("missing-plugins"), "Test 3, Should not have displayed the missing plugin notification");
   ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 3, Should not have displayed the blocked plugin notification");
   ok(!gTestBrowser.missingPlugins, "Test 3, Should not be a missing plugin list");
 
   new TabOpenListener("about:addons", test4, prepareTest5);
 
-  EventUtils.synthesizeMouse(gTestBrowser.contentDocument.getElementById("test"),
+  var pluginNode = gTestBrowser.contentDocument.getElementById("test");
+  ok(pluginNode, "Test 3, Found plugin in page");
+  var manageLink = gTestBrowser.contentDocument.getAnonymousElementByAttribute(pluginNode, "class", "managePluginsLink");
+  ok(manageLink, "Test 3, found 'manage' link in plugin-problem binding");
+
+  EventUtils.synthesizeMouse(manageLink,
                              5, 5, {}, gTestBrowser.contentWindow);
 }
 
 function test4(tab, win) {
   is(win.wrappedJSObject.gViewController.currentViewId, "addons://list/plugin", "Should have displayed the plugins pane");
   gBrowser.removeTab(tab);
 }
 
--- a/browser/base/content/test/browser_scratchpad_bug_646070_chrome_context_pref.js
+++ b/browser/base/content/test/browser_scratchpad_bug_646070_chrome_context_pref.js
@@ -31,17 +31,17 @@ function test()
 function runTests()
 {
   gScratchpadWindow.removeEventListener("load", arguments.callee, false);
 
   let sp = gScratchpadWindow.Scratchpad;
   ok(sp, "Scratchpad object exists in new window");
 
   let chromeContextMenu = gScratchpadWindow.document.
-                          getElementById("sp-menu-chrome");
+                          getElementById("sp-menu-browser");
   ok(chromeContextMenu, "Chrome context menuitem element exists");
   ok(!chromeContextMenu.hasAttribute("hidden"),
      "Chrome context menuitem is visible");
 
   let errorConsoleCommand = gScratchpadWindow.document.
                             getElementById("sp-cmd-errorConsole");
   ok(errorConsoleCommand, "Error console command element exists");
   ok(!errorConsoleCommand.hasAttribute("disabled"),
@@ -49,17 +49,17 @@ function runTests()
 
   let errorConsoleMenu = gScratchpadWindow.document.
                          getElementById("sp-menu-errorConsole");
   ok(errorConsoleMenu, "Error console menu element exists");
   ok(!errorConsoleMenu.hasAttribute("hidden"),
      "Error console menuitem is visible");
 
   let chromeContextCommand = gScratchpadWindow.document.
-                            getElementById("sp-cmd-chromeContext");
+                            getElementById("sp-cmd-browserContext");
   ok(chromeContextCommand, "Chrome context command element exists");
   ok(!chromeContextCommand.hasAttribute("disabled"),
      "Chrome context command is disabled");
 
   Services.prefs.setBoolPref(DEVTOOLS_CHROME_ENABLED, gOldPref);
 
   gScratchpadWindow.close();
   gScratchpadWindow = null;
--- a/browser/base/content/test/browser_scratchpad_contexts.js
+++ b/browser/base/content/test/browser_scratchpad_contexts.js
@@ -22,21 +22,21 @@ function test()
 
 function runTests()
 {
   gScratchpadWindow.removeEventListener("load", arguments.callee, false);
 
   let sp = gScratchpadWindow.Scratchpad;
 
   let contentMenu = gScratchpadWindow.document.getElementById("sp-menu-content");
-  let chromeMenu = gScratchpadWindow.document.getElementById("sp-menu-chrome");
+  let chromeMenu = gScratchpadWindow.document.getElementById("sp-menu-browser");
   let statusbar = sp.statusbarStatus;
 
   ok(contentMenu, "found #sp-menu-content");
-  ok(chromeMenu, "found #sp-menu-chrome");
+  ok(chromeMenu, "found #sp-menu-browser");
   ok(statusbar, "found Scratchpad.statusbarStatus");
 
   sp.setContentContext();
 
   is(sp.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_CONTENT,
      "executionContext is content");
 
   is(contentMenu.getAttribute("checked"), "true",
@@ -49,77 +49,77 @@ function runTests()
      "statusbar label is correct");
 
   ok(sp.textbox, "textbox exists");
   sp.textbox.value = "window.foobarBug636725 = 'aloha';";
 
   ok(!content.wrappedJSObject.foobarBug636725,
      "no content.foobarBug636725");
 
-  sp.execute();
+  sp.run();
 
   is(content.wrappedJSObject.foobarBug636725, "aloha",
      "content.foobarBug636725 has been set");
 
-  sp.setChromeContext();
+  sp.setBrowserContext();
 
-  is(sp.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_CHROME,
+  is(sp.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_BROWSER,
      "executionContext is chrome");
 
   is(chromeMenu.getAttribute("checked"), "true",
      "chrome menuitem is checked");
 
   ok(!contentMenu.hasAttribute("checked"),
      "content menuitem is not checked");
 
   is(statusbar.getAttribute("label"), chromeMenu.getAttribute("label"),
      "statusbar label is correct");
 
   sp.textbox.value = "window.foobarBug636725 = 'aloha2';";
 
   ok(!window.foobarBug636725, "no window.foobarBug636725");
 
-  sp.execute();
+  sp.run();
 
   is(window.foobarBug636725, "aloha2", "window.foobarBug636725 has been set");
 
   sp.textbox.value = "window.gBrowser";
 
-  is(typeof sp.execute()[1].addTab, "function",
+  is(typeof sp.run()[1].addTab, "function",
      "chrome context has access to chrome objects");
 
   // Check that the sandbox is cached.
 
   sp.textbox.value = "typeof foobarBug636725cache;";
-  is(sp.execute()[1], "undefined", "global variable does not exist");
+  is(sp.run()[1], "undefined", "global variable does not exist");
 
   sp.textbox.value = "var foobarBug636725cache = 'foo';";
-  sp.execute();
+  sp.run();
 
   sp.textbox.value = "typeof foobarBug636725cache;";
-  is(sp.execute()[1], "string",
+  is(sp.run()[1], "string",
      "global variable exists across two different executions");
 
   sp.resetContext();
 
-  is(sp.execute()[1], "undefined",
+  is(sp.run()[1], "undefined",
      "global variable no longer exists after calling resetContext()");
 
   sp.textbox.value = "var foobarBug636725cache2 = 'foo';";
-  sp.execute();
+  sp.run();
 
   sp.textbox.value = "typeof foobarBug636725cache2;";
-  is(sp.execute()[1], "string",
+  is(sp.run()[1], "string",
      "global variable exists across two different executions");
 
   sp.setContentContext();
 
   is(sp.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_CONTENT,
      "executionContext is content");
 
-  is(sp.execute()[1], "undefined",
+  is(sp.run()[1], "undefined",
      "global variable no longer exists after changing the context");
 
   gScratchpadWindow.close();
   gScratchpadWindow = null;
   gBrowser.removeCurrentTab();
   finish();
 }
--- a/browser/base/content/test/browser_scratchpad_execute_print.js
+++ b/browser/base/content/test/browser_scratchpad_execute_print.js
@@ -12,42 +12,42 @@ function test()
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
     gScratchpadWindow = Scratchpad.openScratchpad();
     gScratchpadWindow.addEventListener("load", runTests, false);
   }, true);
 
-  content.location = "data:text/html,<p>test execute() and print() in Scratchpad";
+  content.location = "data:text/html,<p>test run() and display() in Scratchpad";
 }
 
 function runTests()
 {
   gScratchpadWindow.removeEventListener("load", arguments.callee, false);
 
   let sp = gScratchpadWindow.Scratchpad;
 
   content.wrappedJSObject.foobarBug636725 = 1;
 
   ok(sp.textbox, "textbox exists");
   sp.textbox.value = "++window.foobarBug636725";
 
-  let exec = sp.execute();
+  let exec = sp.run();
   is(exec[0], sp.textbox.value, "execute()[0] is correct");
   is(exec[1], content.wrappedJSObject.foobarBug636725,
      "execute()[1] is correct");
 
   is(sp.textbox.value, "++window.foobarBug636725",
      "execute() does not change the textbox value");
 
   is(content.wrappedJSObject.foobarBug636725, 2,
      "execute() updated window.foobarBug636725");
 
-  sp.print();
+  sp.display();
 
   is(content.wrappedJSObject.foobarBug636725, 3,
      "print() updated window.foobarBug636725");
 
   is(sp.textbox.value, "++window.foobarBug636725/*\n3\n*/",
      "print() shows evaluation result in the textbox");
 
   is(sp.selectedText, "/*\n3\n*/", "selectedText is correct");
@@ -64,17 +64,17 @@ function runTests()
   is(sp.textbox.selectionStart, 1, "selectionStart is 1");
   is(sp.textbox.selectionEnd, 2, "selectionEnd is 2");
 
   sp.selectRange(0, 29);
 
   is(sp.textbox.selectionStart, 0, "selectionStart is 0");
   is(sp.textbox.selectionEnd, 29, "selectionEnd is 29");
 
-  exec = sp.execute();
+  exec = sp.run();
 
   is(exec[0], "window.foobarBug636725 = 'a';",
      "execute()[0] is correct");
   is(exec[1], "a",
      "execute()[1] is correct");
 
   is(sp.textbox.value, "window.foobarBug636725 = 'a';\n" +
                        "window.foobarBug636725 = 'b';",
@@ -83,17 +83,17 @@ function runTests()
   is(content.wrappedJSObject.foobarBug636725, "a",
      "execute() worked for the selected range");
 
   sp.textbox.value = "window.foobarBug636725 = 'c';\n" +
                      "window.foobarBug636725 = 'b';";
 
   sp.selectRange(0, 22);
 
-  sp.print();
+  sp.display();
 
   is(content.wrappedJSObject.foobarBug636725, "a",
      "print() worked for the selected range");
 
   is(sp.textbox.value, "window.foobarBug636725" +
                        "/*\na\n*/" +
                        " = 'c';\n" +
                        "window.foobarBug636725 = 'b';",
--- a/browser/base/content/test/browser_scratchpad_initialization.js
+++ b/browser/base/content/test/browser_scratchpad_initialization.js
@@ -23,22 +23,22 @@ function test()
 }
 
 function runTests()
 {
   gScratchpadWindow.removeEventListener("load", arguments.callee, false);
 
   let sp = gScratchpadWindow.Scratchpad;
   ok(sp, "Scratchpad object exists in new window");
-  is(typeof sp.execute, "function", "Scratchpad.execute() exists");
+  is(typeof sp.run, "function", "Scratchpad.run() exists");
   is(typeof sp.inspect, "function", "Scratchpad.inspect() exists");
-  is(typeof sp.print, "function", "Scratchpad.print() exists");
+  is(typeof sp.display, "function", "Scratchpad.display() exists");
 
   let chromeContextMenu = gScratchpadWindow.document.
-                          getElementById("sp-menu-chrome");
+                          getElementById("sp-menu-browser");
   ok(chromeContextMenu, "Chrome context menuitem element exists");
   is(chromeContextMenu.getAttribute("hidden"), "true",
      "Chrome context menuitem is hidden");
 
   let errorConsoleCommand = gScratchpadWindow.document.
                             getElementById("sp-cmd-errorConsole");
   ok(errorConsoleCommand, "Error console command element exists");
   is(errorConsoleCommand.getAttribute("disabled"), "true",
@@ -46,17 +46,17 @@ function runTests()
 
   let errorConsoleMenu = gScratchpadWindow.document.
                          getElementById("sp-menu-errorConsole");
   ok(errorConsoleMenu, "Error console menu element exists");
   is(errorConsoleMenu.getAttribute("hidden"), "true",
      "Error console menu item is hidden");
 
   let chromeContextCommand = gScratchpadWindow.document.
-                            getElementById("sp-cmd-chromeContext");
+                            getElementById("sp-cmd-browserContext");
   ok(chromeContextCommand, "Chrome context command element exists");
   is(chromeContextCommand.getAttribute("disabled"), "true",
      "Chrome context command is disabled");
 
   gScratchpadWindow.close();
   gScratchpadWindow = null;
   gBrowser.removeCurrentTab();
   finish();
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_scratchpad_tab_switch.js
@@ -0,0 +1,111 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Reference to the Scratchpad chrome window object.
+let gScratchpadWindow;
+let tab1;
+let tab2;
+let sp;
+
+function test()
+{
+  waitForExplicitFinish();
+
+  tab1 = gBrowser.addTab();
+  gBrowser.selectedTab = tab1;
+  gBrowser.selectedBrowser.addEventListener("load", function() {
+    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
+    tab2 = gBrowser.addTab();
+    gBrowser.selectedTab = tab2;
+    gBrowser.selectedBrowser.addEventListener("load", function() {
+      gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+      gScratchpadWindow = Scratchpad.openScratchpad();
+      gScratchpadWindow.addEventListener("load", runTests, false);
+    }, true);
+    content.location = "data:text/html,test context switch in Scratchpad tab 2";
+  }, true);
+
+  content.location = "data:text/html,test context switch in Scratchpad tab 1";
+}
+
+function runTests()
+{
+  gScratchpadWindow.removeEventListener("load", runTests, true);
+
+  sp = gScratchpadWindow.Scratchpad;
+
+  let contentMenu = gScratchpadWindow.document.getElementById("sp-menu-content");
+  let browserMenu = gScratchpadWindow.document.getElementById("sp-menu-browser");
+  let statusbar = sp.statusbarStatus;
+
+  ok(contentMenu, "found #sp-menu-content");
+  ok(browserMenu, "found #sp-menu-browser");
+  ok(statusbar, "found Scratchpad.statusbarStatus");
+
+  sp.setContentContext();
+
+  is(sp.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_CONTENT,
+     "executionContext is content");
+
+  is(contentMenu.getAttribute("checked"), "true",
+     "content menuitem is checked");
+
+  ok(!browserMenu.hasAttribute("checked"),
+     "chrome menuitem is not checked");
+
+  is(statusbar.getAttribute("label"), contentMenu.getAttribute("label"),
+     "statusbar label is correct");
+
+  ok(sp.textbox, "textbox exists");
+  sp.textbox.value = "window.foosbug653108 = 'aloha';";
+
+  ok(!content.wrappedJSObject.foosbug653108,
+     "no content.foosbug653108");
+
+  sp.run();
+
+  is(content.wrappedJSObject.foosbug653108, "aloha",
+     "content.foosbug653108 has been set");
+
+  gBrowser.tabContainer.addEventListener("TabSelect", runTests2, true);
+  gBrowser.selectedTab = tab1;
+}
+
+function runTests2() {
+  gBrowser.tabContainer.removeEventListener("TabSelect", runTests2, true);
+
+  ok(!window.foosbug653108, "no window.foosbug653108");
+
+  sp.textbox.value = "window.foosbug653108";
+  let result = sp.run();
+
+  isnot(result, "aloha", "window.foosbug653108 is not aloha");
+
+  sp.textbox.value = "window.foosbug653108 = 'ahoyhoy';";
+  sp.run();
+
+  is(content.wrappedJSObject.foosbug653108, "ahoyhoy",
+     "content.foosbug653108 has been set 2");
+
+  gBrowser.selectedBrowser.addEventListener("load", runTests3, true);
+  content.location = "data:text/html,test context switch in Scratchpad location 2";
+}
+
+function runTests3() {
+  gBrowser.selectedBrowser.removeEventListener("load", runTests3, true);
+  // Check that the sandbox is not cached.
+
+  sp.textbox.value = "typeof foosbug653108;";
+  is(sp.run()[1], "undefined", "global variable does not exist");
+
+  gScratchpadWindow.close();
+  gScratchpadWindow = null;
+  tab1 = null;
+  tab2 = null;
+  sp = null;
+  gBrowser.removeCurrentTab();
+  gBrowser.removeCurrentTab();
+  finish();
+}
--- a/browser/base/content/test/browser_scratchpad_ui.js
+++ b/browser/base/content/test/browser_scratchpad_ui.js
@@ -28,20 +28,21 @@ function runTests()
   let sp = gScratchpadWindow.Scratchpad;
   let doc = gScratchpadWindow.document;
 
   let methodsAndItems = {
     "sp-menu-newscratchpad": "openScratchpad",
     "sp-menu-open": "openFile",
     "sp-menu-save": "saveFile",
     "sp-menu-saveas": "saveFileAs",
-    "sp-text-execute": "execute",
+    "sp-text-run": "run",
     "sp-text-inspect": "inspect",
+    "sp-text-display": "display",
     "sp-menu-content": "setContentContext",
-    "sp-menu-chrome": "setChromeContext",
+    "sp-menu-browser": "setBrowserContext",
     "sp-menu-resetContext": "resetContext",
     "sp-menu-errorConsole": "openErrorConsole",
     "sp-menu-webConsole": "openWebConsole",
   };
 
   let lastMethodCalled = null;
   sp.__noSuchMethod__ = function(aMethodName) {
     lastMethodCalled = aMethodName;
--- a/browser/base/content/test/plugin_test.html
+++ b/browser/base/content/test/plugin_test.html
@@ -1,5 +1,5 @@
 <html>
 <body>
-<embed id="test" style="width: 100px; height: 100px" type="application/x-test">
+<embed id="test" style="width: 200px; height: 200px" type="application/x-test">
 </body>
 </html>
--- a/browser/components/preferences/aboutPermissions.js
+++ b/browser/components/preferences/aboutPermissions.js
@@ -582,33 +582,33 @@ let AboutPermissions = {
    *
    * @param aHost
    *        The host string corresponding to the site to delete.
    */
   deleteFromSitesList: function(aHost) {
     for each (let site in this._sites) {
       if (site.host.hasRootDomain(aHost)) {
         if (site == this._selectedSite) {
-          // Clear site data from the DOM to maximize privacy.
-          document.getElementById("site-label").value = "";
-          document.getElementById("permissions-box").hidden = true;
-          this._selectedSite = null;
+          // Replace site-specific interface with "All Sites" interface.
+          this.sitesList.selectedItem = document.getElementById("all-sites-item");
         }
-        
+
         this.sitesList.removeChild(site.listitem);
         delete this._sites[site.host];
       }
     }    
   },
 
   /**
    * Shows interface for managing site-specific permissions.
    */
   onSitesListSelect: function(event) {
     if (event.target.selectedItem.id == "all-sites-item") {
+      // Clear the header label value from the previously selected site.
+      document.getElementById("site-label").value = "";
       this.manageDefaultPermissions();
       return;
     }
 
     let host = event.target.value;
     let site = this._selectedSite = this._sites[host];
     document.getElementById("site-label").value = host;
     document.getElementById("header-deck").selectedPanel =
@@ -636,18 +636,16 @@ let AboutPermissions = {
    */
   updatePermissionsBox: function() {
     this._supportedPermissions.forEach(function(aType){
       this.updatePermission(aType);
     }, this);
 
     this.updatePasswordsCount();
     this.updateCookiesCount();
-
-    document.getElementById("permissions-box").hidden = false;
   },
 
   /**
    * Sets menulist for a given permission to the correct state, based on the
    * stored permission.
    *
    * @param aType
    *        The permission type string stored in permission manager.
--- a/browser/components/preferences/aboutPermissions.xul
+++ b/browser/components/preferences/aboutPermissions.xul
@@ -69,17 +69,17 @@
                    class="list"
                    onselect="AboutPermissions.onSitesListSelect(event);">
         <richlistitem id="all-sites-item"
                       class="site"
                       value="&sites.allSites;"/>                
       </richlistbox>
     </vbox>
 
-    <vbox id="permissions-box" hidden="true" flex="1">
+    <vbox id="permissions-box" flex="1">
 
       <deck id="header-deck">
         <hbox id="site-header" class="pref-item" align="center">
           <description id="site-description">
             &header.site.start;<label id="site-label"/>&header.site.end;
           </description>
           <label id="site-visit-count"/>
           <spacer flex="1"/>
--- a/browser/components/preferences/tests/browser_permissions.js
+++ b/browser/components/preferences/tests/browser_permissions.js
@@ -235,16 +235,20 @@ var tests = [
   },
 
   function test_forget_site() {
     // click "Forget About This Site" button
     gBrowser.contentDocument.getElementById("forget-site-button").doCommand();
 
     is(gSiteLabel.value, "", "site label cleared");
 
+    let allSitesItem = gBrowser.contentDocument.getElementById("all-sites-item");
+    is(gSitesList.selectedItem, allSitesItem,
+       "all sites item selected after forgetting selected site");
+
     // check to make sure site is gone from sites list
     let testSiteItem = getSiteItem(TEST_URI_2.host);
     ok(!testSiteItem, "site removed from sites list");
 
     // check to make sure we forgot all permissions corresponding to site
     for (let type in TEST_PERMS) {
       if (type == "password") {
         ok(Services.logins.getLoginSavingEnabled(TEST_URI_2.prePath),
--- a/browser/locales/en-US/chrome/browser/scratchpad.dtd
+++ b/browser/locales/en-US/chrome/browser/scratchpad.dtd
@@ -56,48 +56,77 @@
 <!ENTITY pasteCmd.label               "Paste">
 <!ENTITY pasteCmd.key                 "V">
 <!ENTITY pasteCmd.accesskey           "P">
 
 <!ENTITY selectAllCmd.label           "Select All">
 <!ENTITY selectAllCmd.key             "A">
 <!ENTITY selectAllCmd.accesskey       "A">
 
-<!ENTITY execute.label                "Execute">
-<!ENTITY execute.accesskey            "E">
-<!ENTITY execute.key                  "t">
+<!ENTITY run.label                    "Run">
+<!ENTITY run.accesskey                "R">
+<!ENTITY run.key                      "r">
 
 <!ENTITY inspect.label                "Inspect">
 <!ENTITY inspect.accesskey            "I">
 <!ENTITY inspect.key                  "i">
 
-<!ENTITY print.label                  "Print">
-<!ENTITY print.accesskey              "p">
-<!ENTITY print.key                    "r">
+<!ENTITY display.label                "Display">
+<!ENTITY display.accesskey            "D">
+<!ENTITY display.key                  "l">
 
+<!-- LOCALIZATION NOTE (environmentMenu.label, accesskey): This menu item was
+  -  renamed from "Context" to avoid confusion with the right-click context
+  -  menu in the text area. It refers to the JavaScript Environment (or context)
+  -  the user is evaluating against. I.e., Content (current tab) or Chrome
+  -  (browser).
+  -->
+<!ENTITY environmentMenu.label        "Environment">
+<!ENTITY environmentMenu.accesskey    "N">
+
+<!-- LOCALIZATION NOTE (contextMenu.label, accesskey): No longer used.
 <!ENTITY contextMenu.label            "Context">
 <!ENTITY contextMenu.accesskey        "C">
+  -->
 
 <!ENTITY contentContext.label         "Content">
 <!ENTITY contentContext.accesskey     "C">
 
+<!-- LOCALIZATION NOTE (browserContext.label, accesskey): This menu item is used
+  -  to select an execution environment for the browser window itself as opposed
+  -  to content. This is a feature for browser and addon developers and only
+  -  enabled via the devtools.chrome.enabled preference. Formerly, this label
+  -  was called "Chrome".
+  -->
+<!ENTITY browserContext.label         "Browser">
+<!ENTITY browserContext.accesskey     "B">
+
+<!-- LOCALIZATION NOTE (chromeContext.label, accesskey): No longer used.
 <!ENTITY chromeContext.label          "Chrome">
 <!ENTITY chromeContext.accesskey      "H">
+  -->
 
 <!-- LOCALIZATION NOTE (resetContext.label): This command allows the developer
-  -  to reset/clear the global object of the context where the code executes.
+  -  to reset/clear the global object of the environment where the code executes.
   -->
 <!ENTITY resetContext.label           "Reset">
 <!ENTITY resetContext.accesskey       "R">
 
+<!ENTITY executeMenu.label            "Execute">
+<!ENTITY executeMenu.accesskey        "X">
+
 <!ENTITY toolsMenu.label              "Tools">
 <!ENTITY toolsMenu.accesskey          "T">
 
 <!ENTITY errorConsoleCmd.label        "Error Console">
 <!ENTITY errorConsoleCmd.accesskey    "C">
 <!ENTITY errorConsoleCmd.commandkey   "j">
 
 <!ENTITY webConsoleCmd.label          "Web Console">
 <!ENTITY webConsoleCmd.accesskey      "W">
 <!ENTITY webConsoleCmd.commandkey     "k">
 
-<!ENTITY textbox.placeholder          "// Enter some JavaScript, select it, right click and select Execute, Inspect or Print.">
+<!-- LOCALIZATION NOTE (textbox.placeholder1): This is some placeholder text
+  -  that appears when the Scratchpad's text area is empty and unfocused.
+  -  It should be a one-line JavaScript comment, i.e., preceded by '//'
+  -->
+<!ENTITY textbox.placeholder1         "// Enter some JavaScript, select it, right click and select Run, Inspect or Display.">
 
--- a/browser/locales/en-US/chrome/browser/scratchpad.properties
+++ b/browser/locales/en-US/chrome/browser/scratchpad.properties
@@ -23,8 +23,13 @@ openFile.failed=Failed to read the file.
 
 # LOCALIZATION NOTE  (saveFileAs): This is the file picker title, when you save
 # a file in Scratchpad.
 saveFileAs=Save File As
 
 # LOCALIZATION NOTE  (saveFile.failed): This is the message displayed when file
 # save fails.
 saveFile.failed=The file save operation failed.
+
+# LOCALIZATION NOTE  (scratchpadIntro): This is a multi-line comment explaining
+# how to use the Scratchpad. Note that this should be a valid JavaScript
+# comment inside /* and */.
+scratchpadIntro=/*\n * This is a JavaScript Scratchpad.\n *\n * Enter some JavaScript, then Right Click or choose from the Execute Menu:\n * 1. Run to evaluate the selected text,\n * 2. Inspect to bring up an Object Inspector on the result, or,\n * 3. Display to insert the result in a comment after the selection.\n */\n\n
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -436,30 +436,33 @@ function FindProxyForURL(url, host)
                          '(.*?)' +
                          '(?::(\\\\\\\\d+))?/');
   var matches = regex.exec(url);
   if (!matches)
     return 'DIRECT';
   var isHttp = matches[1] == 'http';
   var isHttps = matches[1] == 'https';
   var isWebSocket = matches[1] == 'ws';
+  var isWebSocketSSL = matches[1] == 'wss';
   if (!matches[3])
   {
     if (isHttp | isWebSocket) matches[3] = '80';
-    if (isHttps) matches[3] = '443';
+    if (isHttps | isWebSocketSSL) matches[3] = '443';
   }
   if (isWebSocket)
     matches[1] = 'http';
+  if (isWebSocketSSL)
+    matches[1] = 'https';
 
   var origin = matches[1] + '://' + matches[2] + ':' + matches[3];
   if (origins.indexOf(origin) < 0)
     return 'DIRECT';
   if (isHttp)
     return 'PROXY %(remote)s:%(httpport)s';
-  if (isHttps || isWebSocket)
+  if (isHttps || isWebSocket || isWebSocketSSL)
     return 'PROXY %(remote)s:%(sslport)s';
   return 'DIRECT';
 }""" % { "origins": origins,
          "remote":  self.webServer,
          "httpport":self.httpPort,
          "sslport": self.sslPort }
       pacURL = "".join(pacURL.splitlines())
 
--- a/caps/src/nsNullPrincipalURI.cpp
+++ b/caps/src/nsNullPrincipalURI.cpp
@@ -146,16 +146,29 @@ nsNullPrincipalURI::GetPath(nsACString &
 
 NS_IMETHODIMP
 nsNullPrincipalURI::SetPath(const nsACString &aPath)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+nsNullPrincipalURI::GetRef(nsACString &_ref)
+{
+  _ref.Truncate();
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsNullPrincipalURI::SetRef(const nsACString &aRef)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsNullPrincipalURI::GetPrePath(nsACString &_prePath)
 {
   _prePath = mScheme + NS_LITERAL_CSTRING(":");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNullPrincipalURI::GetPort(PRInt32 *_port)
@@ -219,36 +232,51 @@ nsNullPrincipalURI::SetUserPass(const ns
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsNullPrincipalURI::Clone(nsIURI **_newURI)
 {
   nsCOMPtr<nsIURI> uri =
     new nsNullPrincipalURI(mScheme + NS_LITERAL_CSTRING(":") + mPath);
-  NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
   uri.forget(_newURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsNullPrincipalURI::CloneIgnoringRef(nsIURI **_newURI)
+{
+  // GetRef/SetRef not supported by nsNullPrincipalURI, so
+  // CloneIgnoringRef() is the same as Clone().
+  return Clone(_newURI);
+}
+
+NS_IMETHODIMP
 nsNullPrincipalURI::Equals(nsIURI *aOther, PRBool *_equals)
 {
   *_equals = PR_FALSE;
   nsNullPrincipalURI *otherURI;
   nsresult rv = aOther->QueryInterface(kNullPrincipalURIImplementationCID,
                                        (void **)&otherURI);
   if (NS_SUCCEEDED(rv)) {
     *_equals = (mScheme == otherURI->mScheme && mPath == otherURI->mPath);
     NS_RELEASE(otherURI);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsNullPrincipalURI::EqualsExceptRef(nsIURI *aOther, PRBool *_equals)
+{
+  // GetRef/SetRef not supported by nsNullPrincipalURI, so
+  // EqualsExceptRef() is the same as Equals().
+  return Equals(aOther, _equals);
+}
+
+NS_IMETHODIMP
 nsNullPrincipalURI::Resolve(const nsACString &aRelativePath,
                             nsACString &_resolvedURI)
 {
   _resolvedURI = aRelativePath;
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/configure.in
+++ b/configure.in
@@ -2022,18 +2022,18 @@ case "$target" in
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
     # If we're building with --enable-profiling, we need a frame pointer.
     if test -z "$MOZ_PROFILING"; then
         MOZ_OPTIMIZE_FLAGS="-O3 -fomit-frame-pointer"
     else
         MOZ_OPTIMIZE_FLAGS="-O3 -fno-omit-frame-pointer"
     fi
     _PEDANTIC=
-    CFLAGS="$CFLAGS -fpascal-strings -fno-common"
-    CXXFLAGS="$CXXFLAGS -fpascal-strings -fno-common"
+    CFLAGS="$CFLAGS -fno-common"
+    CXXFLAGS="$CXXFLAGS -fno-common"
     DLL_SUFFIX=".dylib"
     DSO_LDOPTS=''
     STRIP="$STRIP -x -S"
     _PLATFORM_DEFAULT_TOOLKIT='cairo-cocoa'
     TARGET_NSPR_MDCPUCFG='\"md/_darwin.cfg\"'
     # The ExceptionHandling framework is needed for Objective-C exception
     # logging code in nsObjCExceptions.h. Currently we only use that in debug
     # builds.
@@ -4856,17 +4856,17 @@ MOZ_XUL=1
 MOZ_ZIPWRITER=1
 NS_PRINTING=1
 MOZ_PDF_PRINTING=
 MOZ_DISABLE_DOMCRYPTO=
 NSS_DISABLE_DBM=
 NECKO_WIFI=1
 NECKO_COOKIES=1
 NECKO_DISK_CACHE=1
-NECKO_PROTOCOLS_DEFAULT="about data file ftp http res viewsource wyciwyg"
+NECKO_PROTOCOLS_DEFAULT="about data file ftp http res viewsource websocket wyciwyg"
 USE_ARM_KUSER=
 BUILD_CTYPES=1
 XPC_IDISPATCH_SUPPORT=
 
 
 case "${target}" in
 *android*|*darwin*)
     ACCESSIBILITY=
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -35,44 +35,47 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsDOMFile_h__
 #define nsDOMFile_h__
 
 #include "nsICharsetDetectionObserver.h"
+#include "nsIFile.h"
 #include "nsIDOMFile.h"
 #include "nsIDOMFileList.h"
 #include "nsIDOMFileError.h"
 #include "nsIInputStream.h"
 #include "nsIJSNativeInitializer.h"
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "mozilla/AutoRestore.h"
 #include "nsString.h"
 #include "nsIXMLHttpRequest.h"
 #include "prmem.h"
 #include "nsAutoPtr.h"
 
 class nsIFile;
 class nsIInputStream;
 class nsIClassInfo;
+class nsIBlobBuilder;
+
+nsresult NS_NewBlobBuilder(nsISupports* *aSupports);
+void ParseSize(PRInt64 aSize, PRInt64& aStart, PRInt64& aEnd);
 
 class nsDOMFile : public nsIDOMFile,
-                  public nsIDOMBlob_MOZILLA_2_0_BRANCH,
                   public nsIXHRSendable,
                   public nsICharsetDetectionObserver,
                   public nsIJSNativeInitializer
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMBLOB
   NS_DECL_NSIDOMFILE
-  NS_DECL_NSIDOMBLOB_MOZILLA_2_0_BRANCH
   NS_DECL_NSIXHRSENDABLE
 
   nsDOMFile(nsIFile *aFile, const nsAString& aContentType)
     : mFile(aFile),
       mContentType(aContentType),
       mIsFullFile(true)
   {}
 
--- a/content/base/public/nsIDOMFile.idl
+++ b/content/base/public/nsIDOMFile.idl
@@ -32,55 +32,58 @@
  * 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 "domstubs.idl"
 
+%{C++
+#include "jsapi.h"
+%}
+
 interface nsIDOMFileError;
 interface nsIInputStream;
 interface nsIURI;
 interface nsIPrincipal;
 interface nsIDOMBlob;
 
-[scriptable, uuid(5822776a-049c-4de7-adb6-dd9efc39d082)]
+[scriptable, uuid(d5237f31-443a-460b-9e42-449a135346f0)]
 interface nsIDOMBlob : nsISupports
 {
   readonly attribute unsigned long long size;
   readonly attribute DOMString type;
 
-  [noscript] nsIDOMBlob slice(in unsigned long long start,
-                              in unsigned long long length,
-                              [optional] in DOMString contentType);
-
   [noscript] readonly attribute nsIInputStream internalStream;
   // The caller is responsible for releasing the internalUrl from the
   // moz-filedata: protocol handler
   [noscript] DOMString getInternalUrl(in nsIPrincipal principal);
-};
 
-[scriptable, uuid(cb5b4191-a555-4e57-b8d2-88091184b59f)]
-interface nsIDOMBlob_MOZILLA_2_0_BRANCH : nsISupports
-{
   [optional_argc] nsIDOMBlob mozSlice(in long long start,
                                       [optional] in long long end,
                                       [optional] in DOMString contentType);
 };
 
-[scriptable, uuid(ae1405b0-e411-481e-9606-b29ec7982687)]
+[scriptable, uuid(91c9ebd9-2a4a-4a38-9412-ef492a2799be)]
 interface nsIDOMFile : nsIDOMBlob
 {
   readonly attribute DOMString name;
   readonly attribute DOMString mozFullPath;
 
   // This performs no security checks!
   [noscript] readonly attribute DOMString mozFullPathInternal;
 
   // These are all deprecated and not in spec. Will be removed in a future
   // release
   readonly attribute DOMString fileName;
   readonly attribute unsigned long long fileSize;
   DOMString getAsText(in DOMString encoding); // raises(FileException) on retrieval
   DOMString getAsDataURL();             // raises(FileException) on retrieval
   DOMString getAsBinary();              // raises(FileException) on retrieval
 };
+
+[scriptable, uuid(c4a77171-039b-4f84-97f9-820fb51626af)]
+interface nsIDOMBlobBuilder : nsISupports
+{
+  nsIDOMBlob getBlob([optional] in DOMString contentType);
+  [implicit_jscontext] void append(in jsval data);
+};
--- a/content/base/public/nsIObjectLoadingContent.idl
+++ b/content/base/public/nsIObjectLoadingContent.idl
@@ -46,17 +46,17 @@ interface nsIDOMClientRect;
 %{C++
 #include "nsNPAPIPluginInstance.h"
 %}
 [ptr] native nsNPAPIPluginInstancePtr(nsNPAPIPluginInstance);
 
 /**
  * This interface represents a content node that loads objects.
  */
-[scriptable, uuid(9558649a-7255-4b00-afb4-1171e9cdcead)]
+[scriptable, uuid(107e8048-d00f-4711-bd21-97184ccae0b1)]
 interface nsIObjectLoadingContent : nsISupports
 {
   const unsigned long TYPE_LOADING  = 0;
   const unsigned long TYPE_IMAGE    = 1;
   const unsigned long TYPE_PLUGIN   = 2;
   const unsigned long TYPE_DOCUMENT = 3;
   const unsigned long TYPE_NULL     = 4;
 
@@ -109,24 +109,16 @@ interface nsIObjectLoadingContent : nsIS
    * This can be called multiple times for different frames.
    *
    * This is noscript because this is an internal method that will go away, and
    * because nsIObjectFrame is unscriptable.
    */
   [noscript] void hasNewFrame(in nsIObjectFrame aFrame);
 
   /**
-   * Tells the object to paint directly in this location ignoring any
-   * positioning information that may have been provided otherwise
-   */
-  void setAbsoluteScreenPosition(in nsIDOMElement element,
-                                 in nsIDOMClientRect position,
-                                 in nsIDOMClientRect clip);
-
-  /**
    * If this object is in going to be printed, this method
    * returns the nsIObjectFrame object which should be used when
    * printing the plugin. The returned nsIFrame is in the original document,
    * not in the static clone.
    */
   [noscript] nsIFrame getPrintFrame();
 
   [noscript] void pluginCrashed(in nsIPluginTag pluginTag,
--- a/content/base/public/nsIWebSocket.idl
+++ b/content/base/public/nsIWebSocket.idl
@@ -46,20 +46,21 @@ interface nsPIDOMWindow;
 
 /**
  * The nsIWebSocket interface enables Web applications to maintain
  * bidirectional communications with server-side processes as described in:
  *
  * http://dev.w3.org/html5/websockets/
  *
  */
-[scriptable, uuid(4403cd57-07fc-477f-a062-d6ba7dd0781b)]
+[scriptable, uuid(431aea4c-568a-470e-b876-c57a29ff0fc6)]
 interface nsIWebSocket : nsISupports
 {
   readonly attribute DOMString url;
+  readonly attribute DOMString protocol;
 
   //ready state
   const unsigned short CONNECTING = 0;
   const unsigned short OPEN = 1;
   const unsigned short CLOSING = 2;
   const unsigned short CLOSED = 3;
   readonly attribute unsigned short readyState;
 
--- a/content/base/src/Link.cpp
+++ b/content/base/src/Link.cpp
@@ -302,23 +302,22 @@ Link::SetPort(const nsAString &aPort)
   SetHrefAttribute(uri);
   return NS_OK;
 }
 
 nsresult
 Link::SetHash(const nsAString &aHash)
 {
   nsCOMPtr<nsIURI> uri(GetURIToMutate());
-  nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
-  if (!url) {
+  if (!uri) {
     // Ignore failures to be compatible with NS4.
     return NS_OK;
   }
 
-  (void)url->SetRef(NS_ConvertUTF16toUTF8(aHash));
+  (void)uri->SetRef(NS_ConvertUTF16toUTF8(aHash));
   SetHrefAttribute(uri);
   return NS_OK;
 }
 
 nsresult
 Link::GetProtocol(nsAString &_protocol)
 {
   nsCOMPtr<nsIURI> uri(GetURI());
@@ -439,25 +438,24 @@ Link::GetPort(nsAString &_port)
 }
 
 nsresult
 Link::GetHash(nsAString &_hash)
 {
   _hash.Truncate();
 
   nsCOMPtr<nsIURI> uri(GetURI());
-  nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
-  if (!url) {
-    // Do not throw!  Not having a valid URI or URL should result in an empty
+  if (!uri) {
+    // Do not throw!  Not having a valid URI should result in an empty
     // string.
     return NS_OK;
   }
 
   nsCAutoString ref;
-  nsresult rv = url->GetRef(ref);
+  nsresult rv = uri->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
     NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
     _hash.Assign(PRUnichar('#'));
     AppendUTF8toUTF16(ref, _hash);
   }
   return NS_OK;
 }
 
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -87,16 +87,17 @@ CPPSRCS		= \
 		nsContentSink.cpp \
 		nsContentUtils.cpp \
 		nsCopySupport.cpp \
 		nsCrossSiteListenerProxy.cpp \
 		nsCSPService.cpp \
 		nsDataDocumentContentPolicy.cpp \
 		nsDOMAttribute.cpp \
 		nsDOMAttributeMap.cpp \
+		nsDOMBlobBuilder.cpp \
 		nsDOMDocumentType.cpp \
 		nsDOMEventTargetWrapperCache.cpp \
 		nsDOMFile.cpp \
 		nsDOMFileReader.cpp \
 		nsDOMLists.cpp \
 		nsDOMParser.cpp \
 		nsDOMSerializer.cpp \
 		nsDOMTokenList.cpp \
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -0,0 +1,399 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla File API.
+ *
+ * The Initial Developer of the Original Code is
+ *   Kyle Huey <me@kylehuey.com>
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "jstypedarray.h"
+#include "nsAutoPtr.h"
+#include "nsDOMClassInfo.h"
+#include "nsDOMFile.h"
+#include "nsIMultiplexInputStream.h"
+#include "nsStringStream.h"
+#include "nsTArray.h"
+#include "nsJSUtils.h"
+#include "nsContentUtils.h"
+#include "CheckedInt.h"
+
+// XXXkhuey shamelessly stolen from VideoUtils.h.  We should patch NSPR.
+#define PR_INT64_MAX (~((PRInt64)(1) << 63))
+#define PR_INT64_MIN (-PR_INT64_MAX - 1)
+
+using namespace mozilla;
+
+class nsDOMMultipartBlob : public nsDOMFile
+{
+public:
+  nsDOMMultipartBlob(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
+                     const nsAString& aContentType)
+    : nsDOMFile(nsnull, aContentType),
+      mBlobs(aBlobs)
+  {
+    mIsFullFile = false;
+    mStart = 0;
+    mLength = 0;
+  }
+
+  NS_IMETHOD GetSize(PRUint64*);
+  NS_IMETHOD GetInternalStream(nsIInputStream**);
+  NS_IMETHOD MozSlice(PRInt64 aStart, PRInt64 aEnd,
+                      const nsAString& aContentType, PRUint8 optional_argc,
+                      nsIDOMBlob **aBlob);
+
+protected:
+  nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
+};
+
+NS_IMETHODIMP
+nsDOMMultipartBlob::GetSize(PRUint64* aLength)
+{
+  nsresult rv;
+  *aLength = 0;
+
+  if (mLength) {
+    *aLength = mLength;
+    return NS_OK;
+  }
+
+  CheckedUint64 length = 0;
+
+  PRUint32 i;
+  PRUint32 len = mBlobs.Length();
+  for (i = 0; i < len; i++) {
+    nsIDOMBlob* blob = mBlobs.ElementAt(i).get();
+    PRUint64 l = 0;
+
+    rv = blob->GetSize(&l);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    length += l;
+  }
+
+  if (!length.valid())
+    return NS_ERROR_FAILURE;
+
+  mLength = length.value();
+  *aLength = mLength;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMultipartBlob::GetInternalStream(nsIInputStream** aStream)
+{
+  nsresult rv;
+  *aStream = nsnull;
+
+  nsCOMPtr<nsIMultiplexInputStream> stream =
+    do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
+  NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);
+
+  PRUint32 i;
+  for (i = 0; i < mBlobs.Length(); i++) {
+    nsCOMPtr<nsIInputStream> scratchStream;
+    nsIDOMBlob* blob = mBlobs.ElementAt(i).get();
+
+    rv = blob->GetInternalStream(getter_AddRefs(scratchStream));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = stream->AppendStream(scratchStream);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return CallQueryInterface(stream, aStream);
+}
+
+NS_IMETHODIMP
+nsDOMMultipartBlob::MozSlice(PRInt64 aStart, PRInt64 aEnd,
+                             const nsAString& aContentType,
+                             PRUint8 optional_argc,
+                             nsIDOMBlob **aBlob)
+{
+  nsresult rv;
+  *aBlob = nsnull;
+
+  // Truncate aStart and aEnd so that we stay within this file.
+  PRUint64 thisLength;
+  rv = GetSize(&thisLength);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!optional_argc) {
+    aEnd = (PRInt64)thisLength;
+  }
+
+  ParseSize((PRInt64)thisLength, aStart, aEnd);
+
+  // If we clamped to nothing we create an empty blob
+  nsTArray<nsCOMPtr<nsIDOMBlob> > blobs;
+
+  PRInt64 length = aEnd - aStart;
+  PRUint64 finalLength = length;
+  PRUint64 skipStart = aStart;
+
+  NS_ABORT_IF_FALSE(aStart + length <= thisLength, "Er, what?");
+
+  // Prune the list of blobs if we can
+  PRUint32 i;
+  for (i = 0; length && skipStart && i < mBlobs.Length(); i++) {
+    nsIDOMBlob* blob = mBlobs[i].get();
+
+    PRUint64 l;
+    rv = blob->GetSize(&l);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (skipStart < l) {
+      PRInt64 upperBound = NS_MIN<PRInt64>(l - skipStart, length);
+
+      nsCOMPtr<nsIDOMBlob> firstBlob;
+      rv = mBlobs.ElementAt(i)->MozSlice(skipStart, skipStart + upperBound,
+                                         aContentType, 2,
+                                         getter_AddRefs(firstBlob));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      // Avoid wrapping a single blob inside an nsDOMMultipartBlob
+      if (length == upperBound) {
+        firstBlob.forget(aBlob);
+        return NS_OK;
+      }
+
+      blobs.AppendElement(firstBlob);
+      length -= upperBound;
+      i++;
+      break;
+    }
+    skipStart -= l;
+  }
+
+  // Now append enough blobs until we're done
+  for (; length && i < mBlobs.Length(); i++) {
+    nsIDOMBlob* blob = mBlobs[i].get();
+
+    PRUint64 l;
+    rv = blob->GetSize(&l);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (length < l) {
+      nsCOMPtr<nsIDOMBlob> lastBlob;
+      rv = mBlobs.ElementAt(i)->MozSlice(0, length, aContentType, 2,
+                                         getter_AddRefs(lastBlob));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      blobs.AppendElement(lastBlob);
+    } else {
+      blobs.AppendElement(blob);
+    }
+    length -= NS_MIN<PRInt64>(l, length);
+  }
+
+  // we can create our blob now
+  nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartBlob(blobs, aContentType);
+  blob.forget(aBlob);
+  return NS_OK;
+}
+
+class nsDOMBlobBuilder : public nsIDOMBlobBuilder
+{
+public:
+  nsDOMBlobBuilder()
+    : mData(nsnull), mDataLen(0), mDataBufferLen(0)
+  {}
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMBLOBBUILDER
+protected:
+  nsresult AppendVoidPtr(void* aData, PRUint32 aLength);
+  nsresult AppendString(JSString* aString, JSContext* aCx);
+  nsresult AppendBlob(nsIDOMBlob* aBlob);
+  nsresult AppendArrayBuffer(js::ArrayBuffer* aBuffer);
+
+  bool ExpandBufferSize(PRUint64 aSize)
+  {
+    if (mDataBufferLen >= mDataLen + aSize) {
+      mDataLen += aSize;
+      return true;
+    }
+
+    // Start at 1 or we'll loop forever.
+    CheckedUint32 bufferLen = NS_MAX<PRUint32>(mDataBufferLen, 1);
+    while (bufferLen.valid() && bufferLen.value() < mDataLen + aSize)
+      bufferLen *= 2;
+
+    if (!bufferLen.valid())
+      return false;
+
+    // PR_ memory functions are still fallible
+    void* data = PR_Realloc(mData, bufferLen.value());
+    if (!data)
+      return false;
+
+    mData = data;
+    mDataBufferLen = bufferLen.value();
+    mDataLen += aSize;
+    return true;
+  }
+
+  void Flush() {
+    if (mData) {
+      // If we have some data, create a blob for it
+      // and put it on the stack
+
+      nsCOMPtr<nsIDOMBlob> blob =
+        new nsDOMMemoryFile(mData, mDataLen, EmptyString(), EmptyString());
+      mBlobs.AppendElement(blob);
+      mData = nsnull; // The nsDOMMemoryFile takes ownership of the buffer
+      mDataLen = 0;
+      mDataBufferLen = 0;
+    }
+  }
+
+  nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
+  void* mData;
+  PRUint64 mDataLen;
+  PRUint64 mDataBufferLen;
+};
+
+DOMCI_DATA(MozBlobBuilder, nsDOMBlobBuilder)
+
+NS_IMPL_ADDREF(nsDOMBlobBuilder)
+NS_IMPL_RELEASE(nsDOMBlobBuilder)
+NS_INTERFACE_MAP_BEGIN(nsDOMBlobBuilder)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMBlobBuilder)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozBlobBuilder)
+NS_INTERFACE_MAP_END
+
+nsresult
+nsDOMBlobBuilder::AppendVoidPtr(void* aData, PRUint32 aLength)
+{
+  NS_ENSURE_ARG_POINTER(aData);
+
+  PRUint64 offset = mDataLen;
+
+  if (!ExpandBufferSize(aLength))
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  memcpy((char*)mData + offset, aData, aLength);
+  return NS_OK;
+}
+
+nsresult
+nsDOMBlobBuilder::AppendString(JSString* aString, JSContext* aCx)
+{
+  nsDependentJSString xpcomStr;
+  if (!xpcomStr.init(aCx, aString)) {
+    return NS_ERROR_XPC_BAD_CONVERT_JS;
+  }
+
+  NS_ConvertUTF16toUTF8 utf8Str(xpcomStr);
+
+  return AppendVoidPtr((void*)utf8Str.Data(),
+                       utf8Str.Length());
+}
+
+nsresult
+nsDOMBlobBuilder::AppendBlob(nsIDOMBlob* aBlob)
+{
+  NS_ENSURE_ARG_POINTER(aBlob);
+
+  Flush();
+  mBlobs.AppendElement(aBlob);
+
+  return NS_OK;
+}
+
+nsresult
+nsDOMBlobBuilder::AppendArrayBuffer(js::ArrayBuffer* aBuffer)
+{
+  return AppendVoidPtr(aBuffer->data, aBuffer->byteLength);
+}
+
+/* nsIDOMBlob getBlob ([optional] in DOMString contentType); */
+NS_IMETHODIMP
+nsDOMBlobBuilder::GetBlob(const nsAString& aContentType,
+                          nsIDOMBlob** aBlob)
+{
+  NS_ENSURE_ARG(aBlob);
+
+  Flush();
+
+  nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartBlob(mBlobs,
+                                                     aContentType);
+  blob.forget(aBlob);
+
+  // NB: This is a willful violation of the spec.  The spec says that
+  // the existing contents of the BlobBuilder should be included
+  // in the next blob produced.  This seems silly and has been raised
+  // on the WHATWG listserv.
+  mBlobs.Clear();
+
+  return NS_OK;
+}
+
+/* [implicit_jscontext] void append (in jsval data); */
+NS_IMETHODIMP
+nsDOMBlobBuilder::Append(const jsval& aData, JSContext* aCx)
+{
+  // We need to figure out what our jsval is
+
+  // Is it an object?
+  if (JSVAL_IS_OBJECT(aData)) {
+    JSObject* obj = JSVAL_TO_OBJECT(aData);
+    NS_ASSERTION(obj, "Er, what?");
+
+    // Is it a Blob?
+    nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(
+      nsContentUtils::XPConnect()->
+        GetNativeOfWrapper(aCx, obj));
+    if (blob)
+      return AppendBlob(blob);
+
+    // Is it an array buffer?
+    if (js_IsArrayBuffer(obj)) {
+      js::ArrayBuffer* buffer = js::ArrayBuffer::fromJSObject(obj);
+      if (buffer)
+        return AppendArrayBuffer(buffer);
+    }
+  }
+
+  // If it's not a Blob or an ArrayBuffer, coerce it to a string
+  JSString* str = JS_ValueToString(aCx, aData);
+  NS_ENSURE_TRUE(str, NS_ERROR_FAILURE);
+
+  return AppendString(str, aCx);
+}
+
+nsresult NS_NewBlobBuilder(nsISupports* *aSupports)
+{
+  nsDOMBlobBuilder* builder = new nsDOMBlobBuilder();
+  return CallQueryInterface(builder, aSupports);
+}
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -44,17 +44,16 @@
 #include "nsDOMClassInfo.h"
 #include "nsDOMError.h"
 #include "nsICharsetAlias.h"
 #include "nsICharsetDetector.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIConverterInputStream.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
-#include "nsIFile.h"
 #include "nsIFileStreams.h"
 #include "nsIInputStream.h"
 #include "nsIIPCSerializable.h"
 #include "nsIMIMEService.h"
 #include "nsIPlatformCharset.h"
 #include "nsISeekableStream.h"
 #include "nsIUnicharInputStream.h"
 #include "nsIUnicodeDecoder.h"
@@ -135,17 +134,16 @@ nsresult DataOwnerAdapter::Create(DataOw
 // nsDOMFile implementation
 
 DOMCI_DATA(File, nsDOMFile)
 DOMCI_DATA(Blob, nsDOMFile)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMFile)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMBlob_MOZILLA_2_0_BRANCH)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFullFile)
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY(nsICharsetDetectionObserver)
   NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFullFile)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFullFile)
 NS_INTERFACE_MAP_END
 
@@ -289,30 +287,23 @@ ParseSize(PRInt64 aSize, PRInt64& aStart
   }
   else {
     aStart = newStartOffset.value();
     aEnd = newEndOffset.value();
   }
 }
 
 NS_IMETHODIMP
-nsDOMFile::Slice(PRUint64 aStart, PRUint64 aLength,
-                 const nsAString& aContentType, nsIDOMBlob **aBlob)
-{
-  return MozSlice(aStart, aStart + aLength, aContentType, 2, aBlob);
-}
-
-NS_IMETHODIMP
 nsDOMFile::MozSlice(PRInt64 aStart, PRInt64 aEnd,
                     const nsAString& aContentType, PRUint8 optional_argc,
                     nsIDOMBlob **aBlob)
 {
   *aBlob = nsnull;
 
-  // Truncate aLength and aStart so that we stay within this file.
+  // Truncate aStart and aEnd so that we stay within this file.
   PRUint64 thisLength;
   nsresult rv = GetSize(&thisLength);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!optional_argc) {
     aEnd = (PRInt64)thisLength;
   }
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -689,53 +689,46 @@ nsExternalResourceMap::RequestResource(n
   NS_PRECONDITION(aRequestingNode, "Must have a node");
   *aPendingLoad = nsnull;
   if (mHaveShutDown) {
     return nsnull;
   }
   
   // First, make sure we strip the ref from aURI.
   nsCOMPtr<nsIURI> clone;
-  aURI->Clone(getter_AddRefs(clone));
-  if (!clone) {
+  nsresult rv = aURI->CloneIgnoringRef(getter_AddRefs(clone));
+  if (NS_FAILED(rv) || !clone) {
     return nsnull;
   }
-  nsCOMPtr<nsIURL> url(do_QueryInterface(clone));
-  if (url) {
-    url->SetRef(EmptyCString());
-  }
   
   ExternalResource* resource;
   mMap.Get(clone, &resource);
   if (resource) {
     return resource->mDocument;
   }
 
   nsRefPtr<PendingLoad> load;
   mPendingLoads.Get(clone, getter_AddRefs(load));
   if (load) {
-    NS_ADDREF(*aPendingLoad = load);
+    load.forget(aPendingLoad);
     return nsnull;
   }
 
   load = new PendingLoad(aDisplayDocument);
-  if (!load) {
-    return nsnull;
-  }
 
   if (!mPendingLoads.Put(clone, load)) {
     return nsnull;
   }
 
   if (NS_FAILED(load->StartLoad(clone, aRequestingNode))) {
     // Make sure we don't thrash things by trying this load again, since
     // chances are it failed for good reasons (security check, etc).
     AddExternalResource(clone, nsnull, nsnull, aDisplayDocument);
   } else {
-    NS_ADDREF(*aPendingLoad = load);
+    load.forget(aPendingLoad);
   }
 
   return nsnull;
 }
 
 struct
 nsExternalResourceEnumArgs
 {
--- a/content/base/src/nsFileDataProtocolHandler.cpp
+++ b/content/base/src/nsFileDataProtocolHandler.cpp
@@ -142,22 +142,25 @@ public:
   // For use only from deserialization
   nsFileDataURI() : nsSimpleURI() {}
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIURIWITHPRINCIPAL
   NS_DECL_NSISERIALIZABLE
   NS_DECL_NSICLASSINFO
 
-  // Override Clone() and Equals()
-  NS_IMETHOD Clone(nsIURI** aClone);
-  NS_IMETHOD Equals(nsIURI* aOther, PRBool *aResult);
+  // Override CloneInternal() and EqualsInternal()
+  virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
+                                 nsIURI** aClone);
+  virtual nsresult EqualsInternal(nsIURI* aOther,
+                                  RefHandlingEnum aRefHandlingMode,
+                                  PRBool* aResult);
 
   // Override StartClone to hand back a nsFileDataURI
-  virtual nsSimpleURI* StartClone()
+  virtual nsSimpleURI* StartClone(RefHandlingEnum /* unused */)
   { return new nsFileDataURI(); }
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
 };
 
 NS_IMPL_ADDREF_INHERITED(nsFileDataURI, nsSimpleURI)
 NS_IMPL_RELEASE_INHERITED(nsFileDataURI, nsSimpleURI)
 NS_INTERFACE_MAP_BEGIN(nsFileDataURI)
@@ -208,22 +211,23 @@ nsFileDataURI::Write(nsIObjectOutputStre
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_WriteOptionalCompoundObject(aStream, mPrincipal,
                                         NS_GET_IID(nsIPrincipal),
                                         PR_TRUE);
 }
 
 // nsIURI methods:
-
-NS_IMETHODIMP
-nsFileDataURI::Clone(nsIURI** aClone)
+nsresult
+nsFileDataURI::CloneInternal(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
+                             nsIURI** aClone)
 {
   nsCOMPtr<nsIURI> simpleClone;
-  nsresult rv = nsSimpleURI::Clone(getter_AddRefs(simpleClone));
+  nsresult rv =
+    nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
   nsRefPtr<nsFileDataURI> uriCheck;
   rv = simpleClone->QueryInterface(kFILEDATAURICID, getter_AddRefs(uriCheck));
   NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) && uriCheck,
 		    "Unexpected!");
 #endif
@@ -231,18 +235,20 @@ nsFileDataURI::Clone(nsIURI** aClone)
   nsFileDataURI* fileDataURI = static_cast<nsFileDataURI*>(simpleClone.get());
 
   fileDataURI->mPrincipal = mPrincipal;
 
   simpleClone.forget(aClone);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsFileDataURI::Equals(nsIURI* aOther, PRBool *aResult)
+/* virtual */ nsresult
+nsFileDataURI::EqualsInternal(nsIURI* aOther,
+                              nsSimpleURI::RefHandlingEnum aRefHandlingMode,
+                              PRBool* aResult)
 {
   if (!aOther) {
     *aResult = PR_FALSE;
     return NS_OK;
   }
   
   nsRefPtr<nsFileDataURI> otherFileDataUri;
   aOther->QueryInterface(kFILEDATAURICID, getter_AddRefs(otherFileDataUri));
@@ -253,17 +259,18 @@ nsFileDataURI::Equals(nsIURI* aOther, PR
 
   nsresult rv = mPrincipal->Equals(otherFileDataUri->mPrincipal, aResult);
   NS_ENSURE_SUCCESS(rv, rv);
   
   if (!*aResult) {
     return NS_OK;
   }
 
-  return nsSimpleURI::Equals(otherFileDataUri, aResult);
+  return nsSimpleURI::EqualsInternal(otherFileDataUri, aRefHandlingMode,
+                                     aResult);
 }
 
 // nsIClassInfo methods:
 NS_IMETHODIMP 
 nsFileDataURI::GetInterfaces(PRUint32 *count, nsIID * **array)
 {
   *count = 0;
   *array = nsnull;
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -1575,49 +1575,29 @@ nsFrameLoader::CheckForRecursiveLoad(nsI
     }
 
     nsCOMPtr<nsIDocShellTreeItem> temp;
     temp.swap(parentAsItem);
     temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
   }
   
   // Bug 136580: Check for recursive frame loading
-  // pre-grab these for speed
-  nsCOMPtr<nsIURI> cloneURI;
-  rv = aURI->Clone(getter_AddRefs(cloneURI));
-  NS_ENSURE_SUCCESS(rv, rv);
-  
-  // Bug 98158/193011: We need to ignore data after the #
-  nsCOMPtr<nsIURL> cloneURL(do_QueryInterface(cloneURI)); // QI can fail
-  if (cloneURL) {
-    rv = cloneURL->SetRef(EmptyCString());
-    NS_ENSURE_SUCCESS(rv,rv);
-  }
-
   PRInt32 matchCount = 0;
   treeItem->GetSameTypeParent(getter_AddRefs(parentAsItem));
   while (parentAsItem) {
     // Check the parent URI with the URI we're loading
     nsCOMPtr<nsIWebNavigation> parentAsNav(do_QueryInterface(parentAsItem));
     if (parentAsNav) {
       // Does the URI match the one we're about to load?
       nsCOMPtr<nsIURI> parentURI;
       parentAsNav->GetCurrentURI(getter_AddRefs(parentURI));
       if (parentURI) {
-        nsCOMPtr<nsIURI> parentClone;
-        rv = parentURI->Clone(getter_AddRefs(parentClone));
-        NS_ENSURE_SUCCESS(rv, rv);
-        nsCOMPtr<nsIURL> parentURL(do_QueryInterface(parentClone));
-        if (parentURL) {
-          rv = parentURL->SetRef(EmptyCString());
-          NS_ENSURE_SUCCESS(rv,rv);
-        }
-
+        // Bug 98158/193011: We need to ignore data after the #
         PRBool equal;
-        rv = cloneURI->Equals(parentClone, &equal);
+        rv = aURI->EqualsExceptRef(parentURI, &equal);
         NS_ENSURE_SUCCESS(rv, rv);
         
         if (equal) {
           matchCount++;
           if (matchCount >= MAX_SAME_URL_CONTENT_FRAMES) {
             NS_WARNING("Too many nested content frames have the same url (recursion?) so giving up");
             return NS_ERROR_UNEXPECTED;
           }
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -2156,16 +2156,17 @@ nsNodeSelectorTearoff::QuerySelectorAll(
                                         nsIDOMNodeList **aReturn)
 {
   return nsGenericElement::doQuerySelectorAll(mNode, aSelector, aReturn);
 }
 
 //----------------------------------------------------------------------
 nsGenericElement::nsDOMSlots::nsDOMSlots()
   : nsINode::nsSlots(),
+    mDataset(nsnull),
     mBindingParent(nsnull)
 {
 }
 
 nsGenericElement::nsDOMSlots::~nsDOMSlots()
 {
   if (mAttributeMap) {
     mAttributeMap->DropReference();
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -61,16 +61,17 @@
 #include "mozFlushType.h"
 #include "nsDOMAttributeMap.h"
 #include "nsIWeakReference.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIDocument.h"
 #include "nsIDOMNodeSelector.h"
 #include "nsIDOMXPathNSResolver.h"
 #include "nsPresContext.h"
+#include "nsIDOMDOMStringMap.h"
 
 #ifdef MOZ_SMIL
 #include "nsISMILAttr.h"
 #endif // MOZ_SMIL
 
 class nsIDOMAttr;
 class nsIDOMEventListener;
 class nsIFrame;
@@ -929,20 +930,27 @@ public:
   {
   public:
     nsDOMSlots();
     virtual ~nsDOMSlots();
 
     /**
      * The .style attribute (an interface that forwards to the actual
      * style rules)
-     * @see nsGenericHTMLElement::GetStyle */
+     * @see nsGenericHTMLElement::GetStyle
+     */
     nsCOMPtr<nsICSSDeclaration> mStyle;
 
     /**
+     * The .dataset attribute.
+     * @see nsGenericHTMLElement::GetDataset
+     */
+    nsIDOMDOMStringMap* mDataset; // [Weak]
+
+    /**
      * SMIL Overridde style rules (for SMIL animation of CSS properties)
      * @see nsIContent::GetSMILOverrideStyle
      */
     nsCOMPtr<nsICSSDeclaration> mSMILOverrideStyle;
 
     /**
      * Holds any SMIL override style rules for this element.
      */
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -375,16 +375,17 @@ GK_ATOM(fixed, "fixed")
 GK_ATOM(fixedList, "Fixed-list")
 GK_ATOM(flags, "flags")
 GK_ATOM(flex, "flex")
 GK_ATOM(flexgroup, "flexgroup")
 GK_ATOM(flip, "flip")
 GK_ATOM(floating, "floating")
 GK_ATOM(floatList, "Float-list")
 GK_ATOM(floor, "floor")
+GK_ATOM(flowlength, "flowlength")
 GK_ATOM(focus, "focus")
 GK_ATOM(following, "following")
 GK_ATOM(followingSibling, "following-sibling")
 GK_ATOM(font, "font")
 GK_ATOM(fontWeight, "font-weight")
 GK_ATOM(fontpicker, "fontpicker")
 GK_ATOM(footer, "footer")
 GK_ATOM(_for, "for")
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -418,21 +418,22 @@ IsSupportedImage(const nsCString& aMimeT
   PRBool supported;
   nsresult rv = loader->SupportImageWithMimeType(aMimeType.get(), &supported);
   return NS_SUCCEEDED(rv) && supported;
 }
 
 static PRBool
 IsSupportedPlugin(const nsCString& aMIMEType)
 {
-  nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
-  if (!host) {
+  nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
+  nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
+  if (!pluginHost) {
     return PR_FALSE;
   }
-  nsresult rv = host->IsPluginEnabledForType(aMIMEType.get());
+  nsresult rv = pluginHost->IsPluginEnabledForType(aMIMEType.get());
   return NS_SUCCEEDED(rv);
 }
 
 static void
 GetExtensionFromURI(nsIURI* uri, nsCString& ext)
 {
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   if (url) {
@@ -453,23 +454,28 @@ GetExtensionFromURI(nsIURI* uri, nsCStri
  * in the given URI. The MIME type is returned in the mimeType out parameter.
  */
 static PRBool
 IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType)
 {
   nsCAutoString ext;
   GetExtensionFromURI(uri, ext);
 
-  if (ext.IsEmpty())
+  if (ext.IsEmpty()) {
     return PR_FALSE;
+  }
 
-  nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
+  nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
+  nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
+  if (!pluginHost) {
+    return PR_FALSE;
+  }
+
   const char* typeFromExt;
-  if (host &&
-      NS_SUCCEEDED(host->IsPluginEnabledForExtension(ext.get(), typeFromExt))) {
+  if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForExtension(ext.get(), typeFromExt))) {
     mimeType = typeFromExt;
     return PR_TRUE;
   }
   return PR_FALSE;
 }
 
 nsObjectLoadingContent::nsObjectLoadingContent()
   : mPendingInstantiateEvent(nsnull)
@@ -1717,18 +1723,18 @@ nsObjectLoadingContent::GetTypeOfContent
 
   return eType_Null;
 }
 
 nsresult
 nsObjectLoadingContent::TypeForClassID(const nsAString& aClassID,
                                        nsACString& aType)
 {
-  // Need a plugin host for any class id support
-  nsCOMPtr<nsIPluginHost> pluginHost(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
+  nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
+  nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
   if (!pluginHost) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (StringBeginsWith(aClassID, NS_LITERAL_STRING("java:"))) {
     // Supported if we have a java plugin
     aType.AssignLiteral("application/x-java-vm");
     nsresult rv = pluginHost->IsPluginEnabledForType("application/x-java-vm");
@@ -1957,21 +1963,23 @@ nsObjectLoadingContent::GetPluginSupport
 
   return hasAlternateContent ? ePluginOtherState :
     GetPluginDisabledState(aContentType);
 }
 
 /* static */ PluginSupportState
 nsObjectLoadingContent::GetPluginDisabledState(const nsCString& aContentType)
 {
-  nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
-  if (!host) {
+  nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
+  nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
+  if (!pluginHost) {
     return ePluginUnsupported;
   }
-  nsresult rv = host->IsPluginEnabledForType(aContentType.get());
+
+  nsresult rv = pluginHost->IsPluginEnabledForType(aContentType.get());
   if (rv == NS_ERROR_PLUGIN_DISABLED)
     return ePluginDisabled;
   if (rv == NS_ERROR_PLUGIN_BLOCKLISTED)
     return ePluginBlocklisted;
   return ePluginUnsupported;
 }
 
 void
@@ -2004,28 +2012,16 @@ nsObjectLoadingContent::CreateStaticClon
 NS_IMETHODIMP
 nsObjectLoadingContent::GetPrintFrame(nsIFrame** aFrame)
 {
   *aFrame = mPrintFrame.GetFrame();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsObjectLoadingContent::SetAbsoluteScreenPosition(nsIDOMElement* element,
-                                                  nsIDOMClientRect* position,
-                                                  nsIDOMClientRect* clip)
-{
-  nsIObjectFrame* frame = GetExistingFrame(eFlushLayout);
-  if (!frame)
-    return NS_ERROR_NOT_AVAILABLE;
-
-  return frame->SetAbsoluteScreenPosition(element, position, clip);
-}
-
-NS_IMETHODIMP
 nsObjectLoadingContent::PluginCrashed(nsIPluginTag* aPluginTag,
                                       const nsAString& pluginDumpID,
                                       const nsAString& browserDumpID,
                                       PRBool submittedCrashReport)
 {
   AutoNotifier notifier(this, PR_TRUE);
   UnloadContent();
   mFallbackReason = ePluginCrashed;
--- a/content/base/src/nsReferencedElement.cpp
+++ b/content/base/src/nsReferencedElement.cpp
@@ -35,68 +35,40 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsReferencedElement.h"
 #include "nsContentUtils.h"
 #include "nsIURI.h"
 #include "nsBindingManager.h"
-#include "nsIURL.h"
 #include "nsEscape.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsCycleCollectionParticipant.h"
 
-static PRBool EqualExceptRef(nsIURL* aURL1, nsIURL* aURL2)
-{
-  nsCOMPtr<nsIURI> u1;
-  nsCOMPtr<nsIURI> u2;
-
-  nsresult rv = aURL1->Clone(getter_AddRefs(u1));
-  if (NS_SUCCEEDED(rv)) {
-    rv = aURL2->Clone(getter_AddRefs(u2));
-  }
-  if (NS_FAILED(rv))
-    return PR_FALSE;
-
-  nsCOMPtr<nsIURL> url1 = do_QueryInterface(u1);
-  nsCOMPtr<nsIURL> url2 = do_QueryInterface(u2);
-  if (!url1 || !url2) {
-    NS_WARNING("Cloning a URL produced a non-URL");
-    return PR_FALSE;
-  }
-  url1->SetRef(EmptyCString());
-  url2->SetRef(EmptyCString());
-
-  PRBool equal;
-  rv = url1->Equals(url2, &equal);
-  return NS_SUCCEEDED(rv) && equal;
-}
-
 void
 nsReferencedElement::Reset(nsIContent* aFromContent, nsIURI* aURI,
                            PRBool aWatch, PRBool aReferenceImage)
 {
+  NS_ABORT_IF_FALSE(aFromContent, "Reset() expects non-null content pointer");
+  NS_ABORT_IF_FALSE(aURI, "Reset() expects non-null URI for referenced elem");
+
   Unlink();
 
-  nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
-  if (!url)
-    return;
-
   nsCAutoString refPart;
-  url->GetRef(refPart);
+  aURI->GetRef(refPart);
   // Unescape %-escapes in the reference. The result will be in the
   // origin charset of the URL, hopefully...
   NS_UnescapeURL(refPart);
 
   nsCAutoString charset;
-  url->GetOriginCharset(charset);
+  aURI->GetOriginCharset(charset);
   nsAutoString ref;
   nsresult rv = nsContentUtils::ConvertStringFromCharset(charset, refPart, ref);
   if (NS_FAILED(rv)) {
     CopyUTF8toUTF16(refPart, ref);
   }
   if (ref.IsEmpty())
     return;
 
@@ -104,19 +76,20 @@ nsReferencedElement::Reset(nsIContent* a
   nsIDocument *doc = aFromContent->GetCurrentDoc();
   if (!doc)
     return;
 
   nsIContent* bindingParent = aFromContent->GetBindingParent();
   if (bindingParent) {
     nsXBLBinding* binding = doc->BindingManager()->GetBinding(bindingParent);
     if (binding) {
-      nsCOMPtr<nsIURL> bindingDocumentURL =
-        do_QueryInterface(binding->PrototypeBinding()->DocURI());
-      if (EqualExceptRef(url, bindingDocumentURL)) {
+      PRBool isEqualExceptRef;
+      rv = aURI->EqualsExceptRef(binding->PrototypeBinding()->DocURI(),
+                                 &isEqualExceptRef);
+      if (NS_SUCCEEDED(rv) && isEqualExceptRef) {
         // XXX sXBL/XBL2 issue
         // Our content is an anonymous XBL element from a binding inside the
         // same document that the referenced URI points to. In order to avoid
         // the risk of ID collisions we restrict ourselves to anonymous
         // elements from this binding; specifically, URIs that are relative to
         // the binding document should resolve to the copy of the target
         // element that has been inserted into the bound document.
         // If the URI points to a different document we don't need this
@@ -134,23 +107,22 @@ nsReferencedElement::Reset(nsIContent* a
         }
 
         // We don't have watching working yet for XBL, so bail out here.
         return;
       }
     }
   }
 
-  nsCOMPtr<nsIURL> documentURL = do_QueryInterface(doc->GetDocumentURI());
-  // We've already checked that |url| is an nsIURL.  So if the document URI is
-  // not an nsIURL then |url| is certainly not going to be pointing to the same
-  // document as the document URI.
-  if (!documentURL || !EqualExceptRef(url, documentURL)) {
+  PRBool isEqualExceptRef;
+  rv = aURI->EqualsExceptRef(doc->GetDocumentURI(), &isEqualExceptRef);
+  if (NS_FAILED(rv) || !isEqualExceptRef) {
     nsRefPtr<nsIDocument::ExternalResourceLoad> load;
-    doc = doc->RequestExternalResource(url, aFromContent, getter_AddRefs(load));
+    doc = doc->RequestExternalResource(aURI, aFromContent,
+                                       getter_AddRefs(load));
     if (!doc) {
       if (!load || !aWatch) {
         // Nothing will ever happen here
         return;
       }
 
       DocumentLoadNotification* observer =
         new DocumentLoadNotification(this, ref);
--- a/content/base/src/nsWebSocket.cpp
+++ b/content/base/src/nsWebSocket.cpp
@@ -17,16 +17,17 @@
  *
  * The Initial Developer of the Original Code is
  * Wellington Fernando de Macedo.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *    Wellington Fernando de Macedo <wfernandom2004@gmail.com> (original author)
+ *    Patrick McManus <mcmanus@ducksong.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -45,74 +46,49 @@
 #include "nsIXPConnect.h"
 #include "nsContentUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsDOMError.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIDOMClassInfo.h"
 #include "nsDOMClassInfo.h"
 #include "jsapi.h"
-#include "nsNetUtil.h"
-#include "nsIStandardURL.h"
 #include "nsIURL.h"
 #include "nsIPrivateDOMEvent.h"
-#include "nsISocketTransportService.h"
-#include "nsIProtocolProxyCallback.h"
-#include "nsISocketTransport.h"
-#include "nsIAsyncInputStream.h"
-#include "nsIAsyncOutputStream.h"
-#include "nsICancelable.h"
 #include "nsIInterfaceRequestor.h"
-#include "nsISSLSocketControl.h"
-#include "nsISocketProviderService.h"
-#include "nsIProtocolProxyService2.h"
-#include "nsISocketProvider.h"
-#include "nsDeque.h"
-#include "nsICookieService.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsThreadUtils.h"
 #include "nsIDOMDocumentEvent.h"
 #include "nsIDOMMessageEvent.h"
-#include "nsIStandardURL.h"
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
 #include "nsIPrompt.h"
 #include "nsIStringBundle.h"
 #include "nsIConsoleService.h"
-#include "nsITimer.h"
-#include "nsIDNSListener.h"
-#include "nsIDNSRecord.h"
-#include "nsIDNSService.h"
 #include "nsLayoutStatics.h"
-#include "nsIHttpAuthenticableChannel.h"
-#include "nsIHttpChannelAuthProvider.h"
-#include "mozilla/Mutex.h"
 #include "nsIDOMCloseEvent.h"
 #include "nsICryptoHash.h"
 #include "jsdbgapi.h"
 #include "nsIJSContextStack.h"
 #include "nsJSUtils.h"
 #include "nsIScriptError.h"
+#include "nsNetUtil.h"
+#include "nsIWebSocketProtocol.h"
+#include "nsILoadGroup.h"
+#include "nsIRequest.h"
 
 using namespace mozilla;
 
-static nsIThread *gWebSocketThread = nsnull;
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsWebSocketEstablishedConnection
 ////////////////////////////////////////////////////////////////////////////////
 
-#define DEFAULT_BUFFER_SIZE 2048
 #define UTF_8_REPLACEMENT_CHAR    static_cast<PRUnichar>(0xFFFD)
 
-#define TIMEOUT_TRY_CONNECT_AGAIN         1000
-#define TIMEOUT_WAIT_FOR_SERVER_RESPONSE  20000
-#define TIMEOUT_WAIT_FOR_CLOSING          20000
-
 #define ENSURE_TRUE_AND_FAIL_IF_FAILED(x, ret)                            \
   PR_BEGIN_MACRO                                                          \
     if (NS_UNLIKELY(!(x))) {                                              \
        NS_WARNING("ENSURE_TRUE_AND_FAIL_IF_FAILED(" #x ") failed");       \
        FailConnection();                                                  \
        return ret;                                                        \
     }                                                                     \
   PR_END_MACRO
@@ -122,615 +98,106 @@ static nsIThread *gWebSocketThread = nsn
     nsresult __rv = res;                                                  \
     if (NS_FAILED(__rv)) {                                                \
       NS_ENSURE_SUCCESS_BODY(res, ret)                                    \
       FailConnection();                                                   \
       return ret;                                                         \
     }                                                                     \
   PR_END_MACRO
 
-#define CHECK_TRUE_AND_FAIL_IF_FAILED(x)                                  \
-  PR_BEGIN_MACRO                                                          \
-    if (NS_UNLIKELY(!(x))) {                                              \
-       NS_WARNING("CHECK_TRUE_AND_FAIL_IF_FAILED(" #x ") failed");        \
-       FailConnection();                                                  \
-       return;                                                            \
-    }                                                                     \
-  PR_END_MACRO
-
-#define CHECK_SUCCESS_AND_FAIL_IF_FAILED(res)                             \
-  PR_BEGIN_MACRO                                                          \
-    nsresult __rv = res;                                                  \
-    if (NS_FAILED(__rv)) {                                                \
-      NS_ENSURE_SUCCESS_BODY(res, ret)                                    \
-      FailConnection();                                                   \
-      return;                                                             \
-    }                                                                     \
-  PR_END_MACRO
-
-#define CHECK_SUCCESS_AND_FAIL_IF_FAILED2(res)                            \
-  PR_BEGIN_MACRO                                                          \
-    nsresult __rv = res;                                                  \
-    if (NS_FAILED(__rv)) {                                                \
-      NS_ENSURE_SUCCESS_BODY(res, ret)                                    \
-      thisObject->FailConnection();                                       \
-      return;                                                             \
-    }                                                                     \
-  PR_END_MACRO
-
-#define WARN_IF_FALSE_AND_RETURN(_expr, _msg)                             \
-  if (!(_expr)) {                                                         \
-    NS_WARNING(_msg);                                                     \
-    return;                                                               \
-  }
-
-#define DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(_method)                      \
-  nsresult _method();                                                     \
-  void MainRunnable##_method();
-
-#define IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(_method)                \
-  nsresult                                                                \
-  nsWebSocketEstablishedConnection::_method()                             \
-  {                                                                       \
-    if (!NS_IsMainThread()) {                                             \
-      nsCOMPtr<nsIRunnable> event =                                       \
-        NS_NewRunnableMethod(this, &nsWebSocketEstablishedConnection::    \
-                                    MainRunnable##_method);               \
-      if (!event) {                                                       \
-        return NS_ERROR_OUT_OF_MEMORY;                                    \
-      }                                                                   \
-      return NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);          \
-    }                                                                     \
-    MainRunnable##_method();                                              \
-    return NS_OK;                                                         \
-  }                                                                       \
-                                                                          \
-  void                                                                    \
-  nsWebSocketEstablishedConnection::MainRunnable##_method()               \
-  {                                                                       \
-    if (!mOwner) {                                                        \
-      return;                                                             \
-    }
-
-#define IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END                           \
-  }
-
-// protocol specific
-#define IS_HIGH_BIT_OF_FRAME_TYPE_SET(_v) ((_v & 0x80) == 0x80)
-#define IS_HIGH_BIT_OF_BYTE_SET(_v) ((_v & 0x80) == 0x80)
-#define START_BYTE_OF_MESSAGE 0x00
-#define END_BYTE_OF_MESSAGE 0xff
-#define START_BYTE_OF_CLOSE_FRAME 0xff
-#define END_BYTE_OF_CLOSE_FRAME 0x00
-
 // nsIInterfaceRequestor will be the unambiguous class for this class
 class nsWebSocketEstablishedConnection: public nsIInterfaceRequestor,
-                                        public nsIDNSListener,
-                                        public nsIProtocolProxyCallback,
-                                        public nsIInputStreamCallback,
-                                        public nsIOutputStreamCallback,
-                                        public nsIChannel,
-                                        public nsIHttpAuthenticableChannel
+                                        public nsIWebSocketListener,
+                                        public nsIRequest
 {
-friend class nsWSNetAddressComparator;
-friend class nsWSAutoClose;
-
 public:
   nsWebSocketEstablishedConnection();
   virtual ~nsWebSocketEstablishedConnection();
 
   NS_DECL_ISUPPORTS
-  NS_DECL_NSIDNSLISTENER
-  NS_DECL_NSIPROTOCOLPROXYCALLBACK
-  NS_DECL_NSIINPUTSTREAMCALLBACK
-  NS_DECL_NSIOUTPUTSTREAMCALLBACK
   NS_DECL_NSIINTERFACEREQUESTOR
+  NS_DECL_NSIWEBSOCKETLISTENER
   NS_DECL_NSIREQUEST
-  NS_DECL_NSICHANNEL
-  NS_DECL_NSIPROXIEDCHANNEL
-
-  // nsIHttpAuthenticableChannel.
-  // We can't use NS_DECL_NSIHTTPAUTHENTICABLECHANNEL because it duplicates
-  // cancel() and others.
-  NS_IMETHOD GetRequestMethod(nsACString &method);
-  NS_IMETHOD GetIsSSL(PRBool *aIsSSL);
-  NS_IMETHOD GetProxyMethodIsConnect(PRBool *aProxyMethodIsConnect);
-  NS_IMETHOD GetServerResponseHeader(nsACString & aServerResponseHeader);
-  NS_IMETHOD GetProxyChallenges(nsACString & aChallenges);
-  NS_IMETHOD GetWWWChallenges(nsACString & aChallenges);
-  NS_IMETHOD SetProxyCredentials(const nsACString & aCredentials);
-  NS_IMETHOD SetWWWCredentials(const nsACString & aCredentials);
-  NS_IMETHOD OnAuthAvailable();
-  NS_IMETHOD OnAuthCancelled(PRBool userCancel);
 
   nsresult Init(nsWebSocket *aOwner);
   nsresult Disconnect();
 
-  // These are called always on the main thread (they dispatch themselves).
-  // ATTENTION, these method when called can release both the WebSocket object
+  // these method when called can release both the WebSocket object
   // (i.e. mOwner) and its connection (i.e. *this*).
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(Close)
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(FailConnection)
+  nsresult Close();
+  nsresult FailConnection();
+  nsresult ConsoleError();
 
   PRBool HasOutgoingMessages()
-  { return mOutgoingMessages.GetSize() != 0; }
+  { return mOutgoingBufferedAmount != 0; }
 
   PRBool ClosedCleanly() { return mClosedCleanly; }
 
   nsresult PostMessage(const nsString& aMessage);
   PRUint32 GetOutgoingBufferedAmount() { return mOutgoingBufferedAmount; }
 
-  // prevent more than one instance from connecting at a time per IP
-  static nsTArray<nsRefPtr<nsWebSocketEstablishedConnection> >* sWSsConnecting;
-
 private:
-  enum WSFrameType {
-    eConnectFrame,
-    eUTF8MessageFrame,
-    eCloseFrame
-  };
-
-  struct nsWSFrame {
-    WSFrameType mType;
-    nsAutoPtr<nsCString> mData;
-  };
-
-  // We can only establish one connection at a time per IP address.
-  // TryConnect ensures this by checking sWSsConnecting.
-  // If there is a IP address entry there it tries again after
-  // TIMEOUT_TRY_CONNECT_AGAIN milliseconds.
-  static void TryConnect(nsITimer *aTimer,
-                         void     *aClosure);
-
-  // We wait for the initial server response for
-  // TIMEOUT_WAIT_FOR_SERVER_RESPONSE milliseconds
-  static void TimerInitialServerResponseCallback(nsITimer *aTimer,
-                                                 void     *aClosure);
 
-  // We wait TIMEOUT_WAIT_FOR_CLOSING milliseconds to the connection be closed
-  // after setting the readyState to CLOSING.
-  static void TimerForceCloseCallback(nsITimer *aTimer,
-                                      void     *aClosure);
-
-  // Similar to the Close method, but this one neither sends the close frame
-  // nor expects the connection to be closed (mStatus == CONN_CLOSED) to
-  // disconnect.
-  void ForceClose();
-
-  nsresult DoConnect();
-  nsresult HandleNewInputString(PRUint32 aStart);
-  nsresult AddAuthorizationHeaders(nsCString& aAuthHeaderStr,
-                                   PRBool     aIsProxyAuth);
-  nsresult AddCookiesToRequest(nsCString& aAuthHeaderStr);
-
-  // Returns the related number of the generated key.
-  PRUint32 GenerateSecKey(nsCString& aKey);
-  nsresult GenerateRequestKeys(nsCString& aKey1,
-                               nsCString& aKey2,
-                               nsCString& aKey3);
-
-  PRBool UsingHttpProxy();
-  nsresult Reset();
-  void RemoveFromLoadGroup();
-  nsresult ProcessHeaders();
-  nsresult PostData(nsCString  *aBuffer,
-                    WSFrameType aWSFrameType);
   nsresult PrintErrorOnConsole(const char       *aBundleURI,
                                const PRUnichar  *aError,
                                const PRUnichar **aFormatStrings,
                                PRUint32          aFormatStringsLen);
-
-  // auth specific methods
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(ProcessAuthentication)
-
-  // these are called always on the main thread (they dispatch themselves)
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(AddWSConnecting)
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(RemoveWSConnecting)
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(HandleSetCookieHeader)
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(DoInitialRequest)
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(Connected)
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(FrameError)
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(DispatchNewMessage)
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(Retry)
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(ResolveNextProxyAndConnect)
-  DECL_RUNNABLE_ON_MAIN_THREAD_METHOD(UpdateMustKeepAlive)
-
-  // called to cause the underlying socket to start speaking SSL
-  nsresult ProxyStartSSL();
-
-  // shared by both threads (the main and the socket ones)
-  Mutex   mLockDisconnect;
-  Mutex   mLockOutgoingMessages;
-  Mutex   mLockReceivedMessages;
-  nsCOMPtr<nsISocketTransport>    mSocketTransport;
-  nsCOMPtr<nsIAsyncInputStream>   mSocketInput;
-  nsCOMPtr<nsIAsyncOutputStream>  mSocketOutput;
-  nsCOMPtr<nsIProxyInfo>          mProxyInfo;
-  nsDeque mOutgoingMessages; // has nsWSFrame* which need to be sent
-  PRUint32 mBytesAlreadySentOfFirstOutString;
-  PRUint32 mOutgoingBufferedAmount; // not really necessary, but it is
-                                    // here for fast access.
-  nsDeque mReceivedMessages; // has nsCString* messages that need
-                             // to be dispatched as message events
-  nsCString mExpectedMD5Challenge;
-  nsWebSocket* mOwner; // WEAK
-
-  // used in mHeaders
-  enum {
-    kUpgradePos = 0,
-    kConnectionPos,
-    kSecWebSocketOriginPos,
-    kSecWebSocketLocationPos,
-    kSecWebSocketProtocolPos,
-    kSetCookiePos,
-    kProxyAuthenticatePos,
-    kServerPos,  // for digest auth
-    kHeadersLen
-  };
-
-  // used only by the socket thread
-  nsCString mBuffer;
-  PRUint32 mBytesInBuffer; // it is needed because mBuffer.SetLength() does
-                           // change also the buffer's Capacity.
-  nsCString mHeaders[kHeadersLen];
-  PRUint32 mLengthToDiscard;
-  PRPackedBool mReadingProxyConnectResponse;
-
-  // WebSockets should resolve proxy in this order:
-  //    (1) socks, (2) https, (3) http
-  enum ProxyConfig {
-    eNotResolvingProxy,
-    eResolvingSOCKSProxy,
-    eResolvingHTTPSProxy,
-    eResolvingHTTPProxy,
-    eResolvingProxyFailed
-  };
-  ProxyConfig mCurrentProxyConfig;
-
-  nsresult mProxyFailureReason;
-  nsCOMPtr<nsICancelable> mProxyResolveCancelable;
-  nsCOMPtr<nsICancelable> mDNSRequest;
-  PRNetAddr mPRNetAddr;
-
-  nsCOMPtr<nsITimer> mTryConnectTimer;
-  nsCOMPtr<nsITimer> mInitialServerResponseTimer;
-  nsCOMPtr<nsITimer> mCloseFrameServerResponseTimer;
-
-  // for nsIRequest implementation
-  nsCString mRequestName;
-  nsresult mFailureStatus;
+  nsresult UpdateMustKeepAlive();
+  
+  // Frames that have been sent to websockethandler but not placed on wire
+  PRUint32 mOutgoingBufferedAmount;
 
-  // auth specific data
-  nsCString mProxyCredentials;
-  nsCString mCredentials;
-  nsCOMPtr<nsIHttpChannelAuthProvider> mAuthProvider;
-  PRPackedBool mAuthenticating;
-
-  PRPackedBool mPostedCloseFrame;
-  PRPackedBool mSentCloseFrame;
-  PRPackedBool mClosedCleanly;
+  nsWebSocket* mOwner; // weak reference
+  nsCOMPtr<nsIWebSocketProtocol> mWebSocketProtocol;
 
-  /**
-   * A simple state machine used to manage the flow status of the input/output
-   * streams of the connection.
-   *
-   * CONN_NOT_CONNECTED (initial state)              ->
-   *                          CONN_CONNECTING |
-   *                          CONN_CLOSED
-   *
-   * CONN_CONNECTING                                 ->
-   *                          CONN_CONNECTING_TO_HTTP_PROXY |
-   *                          CONN_SENDING_INITIAL_REQUEST |
-   *                          CONN_CLOSED
-   *
-   * CONN_RETRYING_TO_AUTHENTICATE                   ->
-   *                          CONN_CONNECTING_TO_HTTP_PROXY |
-   *                          CONN_SENDING_INITIAL_REQUEST |
-   *                          CONN_CLOSED
-   *
-   * CONN_CONNECTING_TO_HTTP_PROXY                    ->
-   *                          CONN_READING_FIRST_CHAR_OF_RESPONSE_HEADER_NAME |
-   *                          CONN_CLOSED
-   *
-   * CONN_SENDING_INITIAL_REQUEST                    ->
-   *                          CONN_WAITING_RESPONSE_FOR_INITIAL_REQUEST |
-   *                          CONN_CLOSED
-   *
-   * CONN_WAITING_RESPONSE_FOR_INITIAL_REQUEST        ->
-   *                          CONN_READING_FIRST_CHAR_OF_RESPONSE_HEADER_NAME |
-   *                          CONN_CLOSED
-   *
-   * CONN_READING_FIRST_CHAR_OF_RESPONSE_HEADER_NAME  ->
-   *                          CONN_READING_RESPONSE_HEADER_NAME |
-   *                          CONN_WAITING_LF_CHAR_TO_CONNECTING |
-   *                          CONN_CLOSED
-   *
-   * CONN_READING_RESPONSE_HEADER_NAME                ->
-   *                          CONN_READING_RESPONSE_HEADER_VALUE |
-   *                          CONN_CLOSED
-   *
-   * CONN_READING_RESPONSE_HEADER_VALUE               ->
-   *                          CONN_WAITING_LF_CHAR_OF_RESPONSE_HEADER |
-   *                          CONN_CLOSED
-   *
-   * CONN_WAITING_LF_CHAR_OF_RESPONSE_HEADER          ->
-   *                          CONN_READING_FIRST_CHAR_OF_RESPONSE_HEADER_NAME |
-   *                          CONN_CLOSED
-   *
-   * CONN_WAITING_LF_CHAR_TO_CONNECTING               ->
-   *                          CONN_SENDING_INITIAL_REQUEST |
-   *                          CONN_READING_CHALLENGE_RESPONSE |
-   *                          CONN_RETRYING_TO_AUTHENTICATE |
-   *                          CONN_CLOSED
-   *
-   * CONN_READING_CHALLENGE_RESPONSE                  ->
-   *                          CONN_CONNECTED_AND_READY |
-   *                          CONN_CLOSED
-   *
-   * CONN_CONNECTED_AND_READY                         ->
-   *                          CONN_HIGH_BIT_OF_FRAME_TYPE_SET |
-   *                          CONN_HIGH_BIT_OF_FRAME_TYPE_NOT_SET |
-   *                          CONN_CLOSED
-   *
-   * CONN_HIGH_BIT_OF_FRAME_TYPE_SET                  ->
-   *                          CONN_READING_AND_DISCARDING_LENGTH_BYTES |
-   *                          CONN_SENDING_ACK_CLOSE_FRAME |
-   *                          CONN_CLOSED
-   *
-   * CONN_READING_AND_DISCARDING_LENGTH_BYTES         ->
-   *                          CONN_CONNECTED_AND_READY |
-   *                          CONN_CLOSED
-   *
-   * CONN_HIGH_BIT_OF_FRAME_TYPE_NOT_SET              ->
-   *                          CONN_CONNECTED_AND_READY |
-   *                          CONN_CLOSED
-   *
-   * CONN_SENDING_ACK_CLOSE_FRAME ->
-   *                          CONN_CLOSED
-   *
-   * CONN_CLOSED (final state)
-   *
-   */
+  PRPackedBool mClosedCleanly;
 
   enum ConnectionStatus {
     CONN_NOT_CONNECTED,
-    CONN_CONNECTING,
-    // connecting to the http proxy
-    CONN_RETRYING_TO_AUTHENTICATE,
-    CONN_CONNECTING_TO_HTTP_PROXY,
-    // doing the websocket handshake
-    CONN_SENDING_INITIAL_REQUEST,
-    CONN_WAITING_RESPONSE_FOR_INITIAL_REQUEST,
-    CONN_READING_FIRST_CHAR_OF_RESPONSE_HEADER_NAME,
-    CONN_READING_RESPONSE_HEADER_NAME,
-    CONN_READING_RESPONSE_HEADER_VALUE,
-    CONN_WAITING_LF_CHAR_OF_RESPONSE_HEADER,
-    CONN_WAITING_LF_CHAR_TO_CONNECTING,
-    CONN_READING_CHALLENGE_RESPONSE,
-    // the websocket connection is established
     CONN_CONNECTED_AND_READY,
-    CONN_HIGH_BIT_OF_FRAME_TYPE_SET,
-    CONN_READING_AND_DISCARDING_LENGTH_BYTES,
-    CONN_HIGH_BIT_OF_FRAME_TYPE_NOT_SET,
-    // the websocket server requested to close the connection and because of
-    // this the close frame in acknowledgement is expected to be sent
-    CONN_SENDING_ACK_CLOSE_FRAME,
-    // the websocket connection is closed (or it is going to)
     CONN_CLOSED
   };
-  // Shared by both threads (the main and the socket ones).
-  // The initial states (CONN_NOT_CONNECTED, CONN_CONNECTING,
-  // CONN_CONNECTING_TO_HTTP_PROXY and CONN_SENDING_INITIAL_REQUEST) are set by
-  // the main thread. The other ones are set by the socket thread.
+
   ConnectionStatus mStatus;
 };
 
-nsTArray<nsRefPtr<nsWebSocketEstablishedConnection> >*
-  nsWebSocketEstablishedConnection::sWSsConnecting = nsnull;
-
-//------------------------------------------------------------------------------
-// Helper classes
-//------------------------------------------------------------------------------
-
-class nsWSNetAddressComparator
-{
-public:
-  // when comparing, if the connection is under a proxy it'll use its hostname,
-  // otherwise it'll use its mPRNetAddr.
-  PRBool Equals(nsWebSocketEstablishedConnection* a,
-                nsWebSocketEstablishedConnection* b) const;
-  PRBool LessThan(nsWebSocketEstablishedConnection* a,
-                  nsWebSocketEstablishedConnection* b) const;
-};
-
-class nsWSAutoClose
-{
-public:
-  nsWSAutoClose(nsWebSocketEstablishedConnection* conn) : mConnection(conn)
-  {}
-
-  ~nsWSAutoClose() { mConnection->Close(); }
-
-private:
-  nsWebSocketEstablishedConnection* mConnection;
-};
-
-PRBool
-nsWSNetAddressComparator::Equals(nsWebSocketEstablishedConnection* a,
-                                 nsWebSocketEstablishedConnection* b) const
-{
-  NS_ASSERTION(a->mOwner && b->mOwner, "Unexpected disconnected connection");
-
-  if ((a->mProxyInfo && !b->mProxyInfo) ||
-      (!a->mProxyInfo && b->mProxyInfo)) {
-    return PR_FALSE;
-  }
-
-  if (a->mProxyInfo) {
-    return a->mOwner->mAsciiHost.Equals(b->mOwner->mAsciiHost);
-  }
-
-  if (a->mPRNetAddr.raw.family != b->mPRNetAddr.raw.family) {
-    return PR_FALSE;
-  }
-
-  if (a->mPRNetAddr.raw.family == PR_AF_INET) {
-    return a->mPRNetAddr.inet.ip == b->mPRNetAddr.inet.ip;
-  }
-
-  NS_ASSERTION(a->mPRNetAddr.raw.family == PR_AF_INET6,
-               "Invalid net raw family");
-
-  return a->mPRNetAddr.ipv6.ip.pr_s6_addr64[0] ==
-           b->mPRNetAddr.ipv6.ip.pr_s6_addr64[0] &&
-         a->mPRNetAddr.ipv6.ip.pr_s6_addr64[1] ==
-           b->mPRNetAddr.ipv6.ip.pr_s6_addr64[1];
-}
-
-PRBool
-nsWSNetAddressComparator::LessThan(nsWebSocketEstablishedConnection* a,
-                                   nsWebSocketEstablishedConnection* b) const
-{
-  NS_ASSERTION(a->mOwner && b->mOwner, "Unexpected disconnected connection");
-
-  if (a->mProxyInfo && !b->mProxyInfo) {
-    return PR_FALSE;
-  }
-
-  if (!a->mProxyInfo && b->mProxyInfo) {
-    return PR_TRUE;
-  }
-
-  if (a->mProxyInfo) {
-    return (a->mOwner->mAsciiHost < b->mOwner->mAsciiHost);
-  }
-
-  if (a->mPRNetAddr.raw.family == PR_AF_INET &&
-      b->mPRNetAddr.raw.family == PR_AF_INET6) {
-    return PR_TRUE;
-  }
-
-  if (a->mPRNetAddr.raw.family == PR_AF_INET6 &&
-      b->mPRNetAddr.raw.family == PR_AF_INET) {
-    return PR_FALSE;
-  }
-
-  if (a->mPRNetAddr.raw.family == PR_AF_INET &&
-      b->mPRNetAddr.raw.family == PR_AF_INET) {
-    return a->mPRNetAddr.inet.ip < b->mPRNetAddr.inet.ip;
-  }
-
-  NS_ASSERTION(a->mPRNetAddr.raw.family == PR_AF_INET6 &&
-               b->mPRNetAddr.raw.family == PR_AF_INET6,
-               "Invalid net raw family");
-
-  return a->mPRNetAddr.ipv6.ip.pr_s6_addr64[0] <
-           b->mPRNetAddr.ipv6.ip.pr_s6_addr64[0] ||
-         (a->mPRNetAddr.ipv6.ip.pr_s6_addr64[0] ==
-           b->mPRNetAddr.ipv6.ip.pr_s6_addr64[0] &&
-          a->mPRNetAddr.ipv6.ip.pr_s6_addr64[1] <
-           b->mPRNetAddr.ipv6.ip.pr_s6_addr64[1]);
-}
-
 //-----------------------------------------------------------------------------
 // nsWebSocketEstablishedConnection::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_THREADSAFE_ISUPPORTS9(nsWebSocketEstablishedConnection,
+NS_IMPL_THREADSAFE_ISUPPORTS3(nsWebSocketEstablishedConnection,
                               nsIInterfaceRequestor,
-                              nsIDNSListener,
-                              nsIProtocolProxyCallback,
-                              nsIInputStreamCallback,
-                              nsIOutputStreamCallback,
-                              nsIRequest,
-                              nsIChannel,
-                              nsIProxiedChannel,
-                              nsIHttpAuthenticableChannel)
+                              nsIWebSocketListener,
+                              nsIRequest)
 
 //-----------------------------------------------------------------------------
 // nsWebSocketEstablishedConnection methods:
 //-----------------------------------------------------------------------------
 
 nsWebSocketEstablishedConnection::nsWebSocketEstablishedConnection() :
-  mLockDisconnect("WebSocket's disconnect lock"),
-  mLockOutgoingMessages("WebSocket's outgoing messages lock"),
-  mLockReceivedMessages("WebSocket's received messages lock"),
-  mBytesAlreadySentOfFirstOutString(0),
   mOutgoingBufferedAmount(0),
   mOwner(nsnull),
-  mBytesInBuffer(0),
-  mLengthToDiscard(0),
-  mReadingProxyConnectResponse(PR_FALSE),
-  mCurrentProxyConfig(eNotResolvingProxy),
-  mProxyFailureReason(NS_OK),
-  mFailureStatus(NS_OK),
-  mAuthenticating(PR_FALSE),
-  mPostedCloseFrame(PR_FALSE),
-  mSentCloseFrame(PR_FALSE),
   mClosedCleanly(PR_FALSE),
   mStatus(CONN_NOT_CONNECTED)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsLayoutStatics::AddRef();
 }
 
 nsWebSocketEstablishedConnection::~nsWebSocketEstablishedConnection()
 {
-  NS_ASSERTION(!mOwner, "Disconnect wasn't called!");
-}
-
-nsresult
-nsWebSocketEstablishedConnection::PostData(nsCString *aBuffer,
-                                           WSFrameType aWSFrameType)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  nsAutoPtr<nsCString> data(aBuffer);
-
-  if (mStatus == CONN_CLOSED) {
-    NS_ASSERTION(mOwner, "Posting data after disconnecting the websocket!");
-    // the tcp connection has been closed, but the main thread hasn't received
-    // the event for disconnecting the object yet.
-    return NS_BASE_STREAM_CLOSED;
-  }
-
-  MutexAutoLock lockOut(mLockOutgoingMessages);
-
-  nsAutoPtr<nsWSFrame> frame(new nsWSFrame());
-  NS_ENSURE_TRUE(frame.get(), NS_ERROR_OUT_OF_MEMORY);
-  frame->mType = aWSFrameType;
-  frame->mData = data.forget();
-
-  nsresult rv;
-  PRInt32 sizeBefore = mOutgoingMessages.GetSize();
-  mOutgoingMessages.Push(frame.forget());
-  NS_ENSURE_TRUE(mOutgoingMessages.GetSize() == sizeBefore + 1,
-                 NS_ERROR_OUT_OF_MEMORY);
-  if (aWSFrameType == eUTF8MessageFrame) {
-    // without the START_BYTE_OF_MESSAGE and END_BYTE_OF_MESSAGE bytes
-    mOutgoingBufferedAmount += aBuffer->Length() - 2;
-  } else if (aWSFrameType == eCloseFrame) {
-    mPostedCloseFrame = PR_TRUE;
-  }
-
-  if (sizeBefore == 0) {
-    mBytesAlreadySentOfFirstOutString = 0;
-    rv = mSocketOutput->AsyncWait(this, 0, 0, gWebSocketThread);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  UpdateMustKeepAlive();
-
-  return NS_OK;
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  NS_ABORT_IF_FALSE(!mOwner, "Disconnect wasn't called!");
+  NS_ABORT_IF_FALSE(!mWebSocketProtocol, "Disconnect wasn't called!");
 }
 
 nsresult
 nsWebSocketEstablishedConnection::PostMessage(const nsString& aMessage)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   if (!mOwner) {
     return NS_OK;
   }
 
   // only send messages when connected
   NS_ENSURE_STATE(mStatus >= CONN_CONNECTED_AND_READY);
 
@@ -747,1208 +214,110 @@ nsWebSocketEstablishedConnection::PostMe
   rv = converter->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace,
                                          nsnull, UTF_8_REPLACEMENT_CHAR);
   ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
 
   PRInt32 inLen = aMessage.Length();
   PRInt32 maxLen;
   rv = converter->GetMaxLength(aMessage.BeginReading(), inLen, &maxLen);
   ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-  maxLen += 2;   // 2 bytes for START_BYTE_OF_MESSAGE and END_BYTE_OF_MESSAGE
 
-  nsAutoPtr<nsCString> buf(new nsCString());
-  ENSURE_TRUE_AND_FAIL_IF_FAILED(buf.get(), NS_ERROR_OUT_OF_MEMORY);
-
-  buf->SetLength(maxLen);
-  ENSURE_TRUE_AND_FAIL_IF_FAILED(buf->Length() == static_cast<PRUint32>(maxLen),
+  nsCString buf;
+  buf.SetLength(maxLen);
+  ENSURE_TRUE_AND_FAIL_IF_FAILED(buf.Length() == static_cast<PRUint32>(maxLen),
                                  NS_ERROR_OUT_OF_MEMORY);
 
-  char* start = buf->BeginWriting();
-  *start = static_cast<char>(START_BYTE_OF_MESSAGE);
-  ++start;
+  char* start = buf.BeginWriting();
 
   PRInt32 outLen = maxLen;
   rv = converter->Convert(aMessage.BeginReading(), &inLen, start, &outLen);
   if (NS_SUCCEEDED(rv)) {
     PRInt32 outLen2 = maxLen - outLen;
     rv = converter->Finish(start + outLen, &outLen2);
     outLen += outLen2;
   }
   if (NS_FAILED(rv) || rv == NS_ERROR_UENC_NOMAPPING) {
     // Yes, NS_ERROR_UENC_NOMAPPING is a success code
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
-  char* end = buf->BeginWriting() + outLen + 1;
-  *end = static_cast<char>(END_BYTE_OF_MESSAGE);
-
-  outLen += 2;
-
-  buf->SetLength(outLen);
-  ENSURE_TRUE_AND_FAIL_IF_FAILED(buf->Length() == static_cast<PRUint32>(outLen),
+  buf.SetLength(outLen);
+  ENSURE_TRUE_AND_FAIL_IF_FAILED(buf.Length() == static_cast<PRUint32>(outLen),
                                  NS_ERROR_UNEXPECTED);
 
-  rv = PostData(buf.forget(), eUTF8MessageFrame);
-  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-  return NS_OK;
-}
-
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(DoInitialRequest)
-{
-  nsresult rv;
-  nsString strRequestTmp;
-
-  nsAutoPtr<nsCString> buf(new nsCString());
-  CHECK_TRUE_AND_FAIL_IF_FAILED(buf.get());
-
-  // GET resource HTTP/1.1
-  buf->AppendLiteral("GET ");
-  buf->Append(mOwner->mResource);
-  buf->AppendLiteral(" HTTP/1.1\r\n");
-
-  nsCAutoString key_1, key_2, key_3;
-  rv = GenerateRequestKeys(key_1, key_2, key_3);
-  CHECK_SUCCESS_AND_FAIL_IF_FAILED(rv);
-
-  // the headers should be sent in a random order
-
-  enum eRequestHeader { upgradeHeader = 0, connectionHeader, hostHeader,
-                        originHeader, secWebSocketProtocolHeader,
-                        authorizationHeaders, cookieHeaders,
-                        secWebSocketKey1Header, secWebSocketKey2Header,
-                        numberRequestHeaders };
-  nsAutoTArray<PRUint32, numberRequestHeaders> headersToSend;
-  for (PRUint32 i = 0; i < numberRequestHeaders; ++i) {
-    headersToSend.AppendElement(i);
-  }
-
-  while (!headersToSend.IsEmpty()) {
-    PRUint8 headerPosToSendNow = rand() % headersToSend.Length();
-    eRequestHeader headerToSendNow =
-      static_cast<eRequestHeader>(headersToSend[headerPosToSendNow]);
-
-    switch (headerToSendNow)
-    {
-      case upgradeHeader:
-      {
-        buf->AppendLiteral("Upgrade: WebSocket\r\n");
-      }
-      break;
-
-      case connectionHeader:
-      {
-        buf->AppendLiteral("Connection: Upgrade\r\n");
-      }
-      break;
-
-      case hostHeader:
-      {
-        buf->AppendLiteral("Host: ");
-        buf->Append(mOwner->mAsciiHost);
-        buf->AppendLiteral(":");
-        buf->AppendInt(mOwner->mPort);
-        buf->AppendLiteral("\r\n");
-      }
-      break;
-
-      case originHeader:
-      {
-        buf->AppendLiteral("Origin: ");
-        buf->Append(mOwner->mOrigin);
-        buf->AppendLiteral("\r\n");
-      }
-      break;
-
-      case secWebSocketProtocolHeader:
-      {
-        if (!mOwner->mProtocol.IsEmpty()) {
-          buf->AppendLiteral("Sec-WebSocket-Protocol: ");
-          buf->Append(mOwner->mProtocol);
-          buf->AppendLiteral("\r\n");
-        }
-      }
-      break;
-
-      case authorizationHeaders:
-      {
-        rv = AddAuthorizationHeaders(*buf, PR_FALSE);
-        CHECK_SUCCESS_AND_FAIL_IF_FAILED(rv);
-      }
-      break;
-
-      case cookieHeaders:
-      {
-        rv = AddCookiesToRequest(*buf);
-        CHECK_SUCCESS_AND_FAIL_IF_FAILED(rv);
-      }
-      break;
-
-      case secWebSocketKey1Header:
-      {
-        buf->AppendLiteral("Sec-WebSocket-Key1: ");
-        buf->Append(key_1);
-        buf->AppendLiteral("\r\n");
-      }
-      break;
-
-      case secWebSocketKey2Header:
-      {
-        buf->AppendLiteral("Sec-WebSocket-Key2: ");
-        buf->Append(key_2);
-        buf->AppendLiteral("\r\n");
-      }
-      break;
-
-      case numberRequestHeaders:
-      break;
-    }
-
-    headersToSend.RemoveElementAt(headerPosToSendNow);
-  }
-
-  buf->AppendLiteral("\r\n");
-  buf->Append(key_3);
-
-  mStatus = CONN_SENDING_INITIAL_REQUEST;
-
-  rv = PostData(buf.forget(), eConnectFrame);
-  CHECK_SUCCESS_AND_FAIL_IF_FAILED(rv);
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-static
-nsresult
-GetHttpResponseCode(const nsCString& aLine, PRUint32 aLen,
-                    PRUint32 *aStatusCode, PRUint32 *aLineLen)
-{
-  // make sure we have HTTP at the beginning
-  if (aLen < 4) {
-    return NS_ERROR_IN_PROGRESS;
-  }
-  if (!StringBeginsWith(aLine, NS_LITERAL_CSTRING("HTTP"))) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  // get the response code
-  PRUint32 responseCode = 0;
-  PRUint8 responseCodeReadingState = 0; // 0:not reading, 1:reading,
-                                        // 2:done reading
-  char last2Chrs[2] = {'\0', '\0'};
-  PRUint32 i = 4;  // just after the HTTP
-  for (; i < aLen; ++i) {
-    if (responseCodeReadingState == 0 && aLine[i] == ' ') {
-      responseCodeReadingState = 1;
-    } else if (responseCodeReadingState == 1) {
-      if (aLine[i] == ' ') {
-        responseCodeReadingState = 2;
-      } else if (aLine[i] >= '0' && aLine[i] <= '9') {
-        responseCode = 10 * responseCode + (aLine[i] - '0');
-        if (responseCode > 999) { // the response code must be three digits long
-          return NS_ERROR_UNEXPECTED;
-        }
-      } else {
-        return NS_ERROR_UNEXPECTED;
-      }
-    }
-
-    last2Chrs[0] = last2Chrs[1];
-    last2Chrs[1] = aLine[i];
-    if (last2Chrs[0] == '\r' && last2Chrs[1] == '\n') { // CR LF
-      *aStatusCode = responseCode;
-      *aLineLen = i + 1;
-      return NS_OK;
-    }
-  }
-
-  return NS_ERROR_IN_PROGRESS;
-}
-
-nsresult
-nsWebSocketEstablishedConnection::HandleNewInputString(PRUint32 aStart)
-{
-  NS_ASSERTION(!NS_IsMainThread(), "Not running on socket thread");
-
-  if (mBytesInBuffer == 0 || aStart == mBytesInBuffer) {
-    return NS_OK;
+  if (mStatus == CONN_CLOSED) {
+    NS_ABORT_IF_FALSE(mOwner, "Posting data after disconnecting the websocket");
+    // the tcp connection has been closed, but the main thread hasn't received
+    // the event for disconnecting the object yet.
+    rv = NS_BASE_STREAM_CLOSED;
+  } else {
+    mOutgoingBufferedAmount += buf.Length();
+    mWebSocketProtocol->SendMsg(buf);
+    rv = NS_OK;
   }
 
-  NS_ENSURE_STATE(aStart < mBytesInBuffer);
-
-  nsresult rv;
-
-  switch (mStatus)
-  {
-    case CONN_CONNECTING_TO_HTTP_PROXY:
-    {
-      PRUint32 statusCode, lengthStr;
-
-      rv = GetHttpResponseCode(mBuffer, mBytesInBuffer, &statusCode,
-                               &lengthStr);
-      if (rv != NS_ERROR_IN_PROGRESS) {
-        NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
-
-        if (statusCode == 200) {
-          mReadingProxyConnectResponse = PR_TRUE;
-          mAuthenticating = PR_FALSE;
-        } else if (statusCode == 407) {
-          mReadingProxyConnectResponse = PR_TRUE;
-          mAuthenticating = PR_TRUE;
-        } else {
-          return NS_ERROR_UNEXPECTED;
-        }
-
-        mStatus = CONN_READING_FIRST_CHAR_OF_RESPONSE_HEADER_NAME;
-        mBuffer.Cut(0, lengthStr);
-        mBytesInBuffer -= lengthStr;
-
-        return HandleNewInputString(0);
-      }
-    }
-    break;
-
-    case CONN_SENDING_ACK_CLOSE_FRAME:
-    case CONN_CLOSED:
-    {
-      mBytesInBuffer = 0;
-    }
-    break;
-
-    case CONN_WAITING_RESPONSE_FOR_INITIAL_REQUEST:
-    {
-      PRUint32 statusCode, lengthStr;
-
-      rv = GetHttpResponseCode(mBuffer, mBytesInBuffer, &statusCode,
-                               &lengthStr);
-      if (rv != NS_ERROR_IN_PROGRESS) {
-        NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
-
-        if (statusCode != 101) {
-          return NS_ERROR_UNEXPECTED;
-        }
-
-        mReadingProxyConnectResponse = PR_FALSE;
-        mAuthenticating = PR_FALSE;
-
-        mStatus = CONN_READING_FIRST_CHAR_OF_RESPONSE_HEADER_NAME;
-        mBuffer.Cut(0, lengthStr);
-        mBytesInBuffer -= lengthStr;
-
-        // we have just received the server response. We must cancel this timer
-        // or it will fail the connection.
-        mInitialServerResponseTimer->Cancel();
-
-        return HandleNewInputString(0);
-      }
-    }
-    break;
-
-    case CONN_READING_FIRST_CHAR_OF_RESPONSE_HEADER_NAME:
-    {
-      if (mBuffer[aStart] == '\r') {
-        mStatus = CONN_WAITING_LF_CHAR_TO_CONNECTING;
-        return HandleNewInputString(aStart + 1);
-      }
-
-      NS_ENSURE_STATE(mBuffer[aStart] != '\n');
-
-      mStatus = CONN_READING_RESPONSE_HEADER_NAME;
-      return HandleNewInputString(aStart);
-    }
-    break;
-
-    case CONN_READING_RESPONSE_HEADER_NAME:
-    {
-      PRUint32 i;
-      for (i = aStart; i < mBytesInBuffer; ++i) {
-        NS_ENSURE_STATE(mBuffer[i] != '\r' && mBuffer[i] != '\n');
-
-        if (mBuffer[i] == ':') {
-          mStatus = CONN_READING_RESPONSE_HEADER_VALUE;
-          return HandleNewInputString(i + 1);
-        }
-      }
-    }
-    break;
-
-    case CONN_READING_RESPONSE_HEADER_VALUE:
-    {
-      PRUint32 i;
-      for (i = aStart; i < mBytesInBuffer; ++i) {
-        if (mBuffer[i] == '\r') {
-          mStatus = CONN_WAITING_LF_CHAR_OF_RESPONSE_HEADER;
-          return HandleNewInputString(i + 1);
-        }
-
-        NS_ENSURE_STATE(mBuffer[i] != '\n');
-      }
-    }
-    break;
-
-    case CONN_WAITING_LF_CHAR_OF_RESPONSE_HEADER:
-    {
-      NS_ENSURE_STATE(mBuffer[aStart] == '\n');
-
-      PRUint32 posColon = mBuffer.FindChar(':');
-      PRUint32 posCR = mBuffer.FindChar('\r');
-
-      const nsCSubstring& headerName = Substring(mBuffer, 0, posColon);
-
-      nsCString headerValue;
-      if (mBuffer[posColon + 1] == 0x20 && posColon + 2 != posCR) {
-        headerValue = Substring(mBuffer, posColon + 2, posCR - posColon - 2);
-      } else if (posColon + 1 != posCR) {
-        headerValue = Substring(mBuffer, posColon + 1, posCR - posColon - 1);
-      } else {
-        ; // No header value
-      }
-
-      NS_ENSURE_STATE(!headerName.IsEmpty());
-
-      PRInt32 headerPos = -1;
-      if (mReadingProxyConnectResponse) {
-        if (headerName.LowerCaseEqualsLiteral("proxy-authenticate")) {
-          headerPos = kProxyAuthenticatePos;
-        }
-      } else {
-        if (headerName.LowerCaseEqualsLiteral("upgrade")) {
-          headerPos = kUpgradePos;
-        } else if (headerName.LowerCaseEqualsLiteral("connection")) {
-          headerPos = kConnectionPos;
-        } else if (headerName.LowerCaseEqualsLiteral("sec-websocket-origin")) {
-          headerPos = kSecWebSocketOriginPos;
-        } else if (headerName.LowerCaseEqualsLiteral("sec-websocket-location")) {
-          headerPos = kSecWebSocketLocationPos;
-        } else if (headerName.LowerCaseEqualsLiteral("sec-websocket-protocol")) {
-          headerPos = kSecWebSocketProtocolPos;
-        } else if (headerName.LowerCaseEqualsLiteral("set-cookie")) {
-          headerPos = kSetCookiePos;
-        }
-      }
-      if (headerPos == -1 && headerName.LowerCaseEqualsLiteral("server")) {
-        headerPos = kServerPos;
-      }
-
-      if (headerPos != -1) {
-        NS_ENSURE_STATE(mHeaders[headerPos].IsEmpty());
-        mHeaders[headerPos] = headerValue;
-      }
-
-      mStatus = CONN_READING_FIRST_CHAR_OF_RESPONSE_HEADER_NAME;
-      mBuffer.Cut(0, aStart + 1);
-      mBytesInBuffer -= aStart + 1;
-
-      return HandleNewInputString(0);
-    }
-    break;
-
-    case CONN_WAITING_LF_CHAR_TO_CONNECTING:
-    {
-      NS_ENSURE_STATE(mBuffer[aStart] == '\n');
-
-      rv = ProcessHeaders();
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
-
-      if (mAuthenticating) {
-        Reset();
-        mStatus = CONN_RETRYING_TO_AUTHENTICATE;
-        return ProcessAuthentication();
-      }
-
-      if (mReadingProxyConnectResponse) {
-        if (mOwner->mSecure) {
-          rv = ProxyStartSSL();
-          NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
-        }
-
-        mBytesInBuffer = 0;
-        return DoInitialRequest();
-      }
-
-      mStatus = CONN_READING_CHALLENGE_RESPONSE;
-
-      mBuffer.Cut(0, aStart + 1);
-      mBytesInBuffer -= aStart + 1;
-      return HandleNewInputString(0);
-    }
-
-    case CONN_READING_CHALLENGE_RESPONSE:
-    {
-      NS_ENSURE_STATE(aStart == 0);
-
-      if (mBytesInBuffer < 16) {
-        return NS_OK;
-      }
-
-      const nsCSubstring& receivedMD5Challenge = Substring(mBuffer, 0, 16);
-      if (!mExpectedMD5Challenge.Equals(receivedMD5Challenge)) {
-        return NS_ERROR_UNEXPECTED;
-      }
-
-      mStatus = CONN_CONNECTED_AND_READY;
-      rv = Connected();
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
-
-      mBuffer.Cut(0, aStart + 16);
-      mBytesInBuffer -= aStart + 16;
-      return HandleNewInputString(0);
-    }
-
-    case CONN_CONNECTED_AND_READY:
-    {
-      NS_ENSURE_STATE(aStart == 0);
-      PRUint8 frameType = mBuffer[0];
-
-      if (IS_HIGH_BIT_OF_FRAME_TYPE_SET(frameType)) {
-        mStatus = CONN_HIGH_BIT_OF_FRAME_TYPE_SET;
-        mLengthToDiscard = 0;
-      } else {
-        mStatus = CONN_HIGH_BIT_OF_FRAME_TYPE_NOT_SET;
-      }
-
-      return HandleNewInputString(1);
-    }
-    break;
-
-    case CONN_HIGH_BIT_OF_FRAME_TYPE_SET:
-    {
-      PRUint32 i;
-      PRUint8 frameType = mBuffer[0];
-      for (i = aStart; i < mBytesInBuffer; ++i) {
-        PRUint8 b, bv;
-        b = mBuffer[i];
-        bv = (b & 0x7f);
-
-        // prevent overflow
-        NS_ENSURE_STATE(mLengthToDiscard <= ((PR_UINT32_MAX - bv) / 128));
-
-        mLengthToDiscard = mLengthToDiscard * 128 + bv;
-
-        if (!IS_HIGH_BIT_OF_BYTE_SET(b)) {
-          // check if it is the close frame
-          if (mLengthToDiscard == 0 && frameType == START_BYTE_OF_CLOSE_FRAME) {
-            mBytesInBuffer = 0;
-            if (mSentCloseFrame) {
-              mClosedCleanly = PR_TRUE;
-              mStatus = CONN_CLOSED;
-            } else {
-              mStatus = CONN_SENDING_ACK_CLOSE_FRAME;
-            }
-            return Close();
-          }
-          FrameError();
-          mStatus = CONN_READING_AND_DISCARDING_LENGTH_BYTES;
-          return HandleNewInputString(i + 1);
-        }
-      }
-      mBytesInBuffer = 0;
-    }
-    break;
-
-    case CONN_READING_AND_DISCARDING_LENGTH_BYTES:
-    {
-      if (mBytesInBuffer - aStart >= mLengthToDiscard) {
-        mBuffer.Cut(0, aStart + mLengthToDiscard);
-        mBytesInBuffer -= aStart + mLengthToDiscard;
-
-        mStatus = CONN_CONNECTED_AND_READY;
-        return HandleNewInputString(0);
-      }
-
-      mLengthToDiscard -= mBytesInBuffer - aStart;
-      mBytesInBuffer = 0;
-    }
-    break;
-
-    case CONN_HIGH_BIT_OF_FRAME_TYPE_NOT_SET:
-    {
-      PRUint32 i;
-      for (i = aStart; i < mBytesInBuffer; ++i) {
-        PRUint8 b;
-        b = mBuffer[i];
-        if (b == END_BYTE_OF_MESSAGE) {
-          PRUint8 frameType = mBuffer[0];
-          if (frameType == START_BYTE_OF_MESSAGE) {
-            // get the message, without the START_BYTE_OF_MESSAGE and
-            // END_BYTE_OF_MESSAGE bytes
-            nsAutoPtr<nsCString> dataMessage(new nsCString());
-            NS_ENSURE_TRUE(dataMessage.get(), NS_ERROR_OUT_OF_MEMORY);
-            dataMessage->Assign(Substring(mBuffer, 1, i - 1));
-
-            // push the new message onto our stack
-            {
-              MutexAutoLock lockIn(mLockReceivedMessages);
-
-              PRInt32 sizeBefore = mReceivedMessages.GetSize();
-              mReceivedMessages.Push(dataMessage.forget());
-              NS_ENSURE_TRUE(mReceivedMessages.GetSize() == sizeBefore + 1,
-                             NS_ERROR_OUT_OF_MEMORY);
-            }
-
-            // and dispatch it
-            rv = DispatchNewMessage();
-            NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
-          } else {
-            FrameError();
-          }
-
-          mBuffer.Cut(0, i + 1);
-          mBytesInBuffer -= i + 1;
-
-          mStatus = CONN_CONNECTED_AND_READY;
-          return HandleNewInputString(0);
-        }
-      }
-    }
-    break;
-
-    default:
-      NS_ASSERTION(PR_FALSE, "Invalid state.");
-  }
+  UpdateMustKeepAlive();
+  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-nsWebSocketEstablishedConnection::AddAuthorizationHeaders(nsCString& aStr,
-                                                          PRBool aIsProxyAuth)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  mAuthProvider->AddAuthorizationHeaders();
-
-  if (UsingHttpProxy() && !mProxyCredentials.IsEmpty()) {
-    aStr.AppendLiteral("Proxy-Authorization: ");
-    aStr.Append(mProxyCredentials);
-    aStr.AppendLiteral("\r\n");
-  }
-
-  if (!aIsProxyAuth && !mCredentials.IsEmpty()) {
-    aStr.AppendLiteral("Authorization: ");
-    aStr.Append(mCredentials);
-    aStr.AppendLiteral("\r\n");
-  }
-  return NS_OK;
-}
-
-nsresult
-nsWebSocketEstablishedConnection::AddCookiesToRequest(nsCString& aStr)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  // get the content of the cookie request header
-  nsCOMPtr<nsICookieService> cookieService =
-    do_GetService(NS_COOKIESERVICE_CONTRACTID);
-  nsCOMPtr<nsIDocument> doc =
-    nsContentUtils::GetDocumentFromScriptContext(mOwner->mScriptContext);
-
-  if (!cookieService || !doc) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIURI> documentURI = doc->GetDocumentURI();
-  if (!documentURI) {
-    return NS_OK;
-  }
-
-  nsXPIDLCString cookieValue;
-  cookieService->GetCookieStringFromHttp(documentURI,
-                                         documentURI,
-                                         nsnull,
-                                         getter_Copies(cookieValue));
-  if (!cookieValue.IsEmpty()) {
-    aStr.AppendLiteral("Cookie: ");
-    aStr.Append(cookieValue);
-    aStr.AppendLiteral("\r\n");
-  }
-
-  return NS_OK;
-}
-
-PRUint32
-nsWebSocketEstablishedConnection::GenerateSecKey(nsCString& aKey)
-{
-  PRUint32 i;
-
-  PRUint32 spaces = rand() % 12 + 1;
-  PRUint32 max = PR_UINT32_MAX / spaces;
-  PRUint32 number = rand() % max;
-  PRUint32 product = number * spaces;
-
-  nsCAutoString key;
-
-  key.AppendInt(product);
-
-  // Insert between one and twelve random characters from the ranges
-  // U+0021 to U+002F and U+003A to U+007E into the key at random
-  // positions.
-  PRUint32 numberOfCharsToInsert = rand() % 12 + 1;
-  for (i = 0; i < numberOfCharsToInsert; ++i) {
-    PRUint32 posToInsert = rand() % key.Length();
-    char charToInsert =
-      rand() % 2 == 0 ?
-        static_cast<char>(0x21 + (rand() % (0x2F - 0x21 + 1))) :
-        static_cast<char>(0x3A + (rand() % (0x7E - 0x3A + 1)));
-
-    key.Insert(charToInsert, posToInsert);
-  }
-
-  // Insert /spaces/ U+0020 SPACE characters into the key at random
-  // positions other than the start or end of the string.
-  for (i = 0; i < spaces; ++i) {
-    PRUint32 posToInsert = rand() % (key.Length() - 1) + 1;
-    key.Insert(static_cast<char>(0x20), posToInsert);
-  }
-
-  aKey = key;
-  return number;
-}
-
-nsresult
-nsWebSocketEstablishedConnection::GenerateRequestKeys(nsCString& aKey1,
-                                                      nsCString& aKey2,
-                                                      nsCString& aKey3)
-{
-  nsresult rv;
-  PRUint32 i;
-
-  nsCAutoString key_1;
-  PRUint32 number_1;
-
-  nsCAutoString key_2;
-  PRUint32 number_2;
-
-  // generate the sec-keys headers values
-  number_1 = GenerateSecKey(key_1);
-  number_2 = GenerateSecKey(key_2);
-
-  // key3 must be a string consisting of eight random bytes
-  nsCAutoString key_3;
-  for (i = 0; i < 8; ++i) {
-    // get a byte between 1 and 255. 0x00 was discarted to prevent possible
-    // issues in ws servers.
-    key_3 += static_cast<char>(rand() % 0xff + 1);
-  }
-
-  // since we have the keys, we calculate the server md5 challenge response,
-  // which is the md5 string of the concatenation of /number_1/, expressed as
-  // a big-endian 32 bit integer, /number_2/, expressed as a big-endian
-  // 32 bit integer, and the eight bytes of /key_3/
-
-  nsCOMPtr<nsICryptoHash> md5CryptoHash =
-    do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = md5CryptoHash->Init(nsICryptoHash::MD5);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PRUint8 data[16];
-  for (i = 1; i <= 4; ++i) {
-    data[i - 1] = static_cast<PRUint8>(number_1 >> (32 - i * 8));
-  }
-  for (i = 1; i <= 4; ++i) {
-    data[i + 3] = static_cast<PRUint8>(number_2 >> (32 - i * 8));
-  }
-  for (i = 0; i < 8; ++i) {
-    data[i + 8] = static_cast<PRUint8>(key_3[i]);
-  }
-
-  rv = md5CryptoHash->Update(data, 16);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = md5CryptoHash->Finish(PR_FALSE, mExpectedMD5Challenge);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  aKey1 = key_1;
-  aKey2 = key_2;
-  aKey3 = key_3;
-
-  return NS_OK;
-}
-
-PRBool
-nsWebSocketEstablishedConnection::UsingHttpProxy()
-{
-  if (!mProxyInfo) {
-    return PR_FALSE;
-  }
-
-  nsCAutoString proxyType;
-  mProxyInfo->GetType(proxyType);
-  return proxyType.EqualsLiteral("http");
-}
-
-// it is called by both main and socket threads under the mLockDisconnect
-nsresult
-nsWebSocketEstablishedConnection::Reset()
-{
-  RemoveWSConnecting();
-
-  mStatus = CONN_NOT_CONNECTED;
-
-  if (mSocketTransport) {
-    mSocketTransport->Close(NS_OK);
-    mSocketTransport = nsnull;
-  }
-  mSocketInput = nsnull;
-  mSocketOutput = nsnull;
-
-  while (mOutgoingMessages.GetSize() != 0) {
-    delete static_cast<nsWSFrame*>(mOutgoingMessages.PopFront());
-  }
-
-  while (mReceivedMessages.GetSize() != 0) {
-    delete static_cast<nsCString*>(mReceivedMessages.PopFront());
-  }
-
-  mBytesAlreadySentOfFirstOutString = 0;
-  mBytesInBuffer = 0;
-
-  return NS_OK;
-}
-
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(Connected)
-{
-  RemoveWSConnecting();
-
-  if (mAuthProvider) {
-    mAuthProvider->Disconnect(NS_ERROR_ABORT);
-    mAuthProvider = nsnull;
-  }
-
-  mOwner->SetReadyState(nsIWebSocket::OPEN);
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(FrameError)
-{
-  nsresult rv =
-    mOwner->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch the error event");
-  }
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(DispatchNewMessage)
-{
-  nsresult rv;
-
-  while (PR_TRUE) {
-    nsAutoPtr<nsCString> data;
-
-    {
-      MutexAutoLock lockIn(mLockReceivedMessages);
-
-      if (mReceivedMessages.GetSize() == 0) {
-        return;
-      }
-
-      data = static_cast<nsCString*>(mReceivedMessages.PopFront());
-    }
-
-    rv = mOwner->CreateAndDispatchMessageEvent(data);
-    if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to dispatch the message event");
-    }
-  }
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-nsresult
-nsWebSocketEstablishedConnection::ProxyStartSSL()
-{
-  NS_ASSERTION(!NS_IsMainThread(), "Not running on socket thread");
-
-  nsCOMPtr<nsISupports> securityInfo;
-  nsresult rv = mSocketTransport->GetSecurityInfo(getter_AddRefs(securityInfo));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(securityInfo, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return ssl->ProxyStartSSL();
-}
-
-nsresult
 nsWebSocketEstablishedConnection::Init(nsWebSocket *aOwner)
 {
-  // test if it has been alredy initialized
-  NS_ASSERTION(!mOwner, "WebSocket's connection is already initialized");
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  NS_ABORT_IF_FALSE(!mOwner, "WebSocket's connection is already initialized");
 
   nsresult rv;
-
   mOwner = aOwner;
 
   if (mOwner->mSecure) {
-    // HACK: make sure PSM gets initialized on the main thread.
-    nsCOMPtr<nsISocketProviderService> spserv =
-      do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID);
-    NS_ENSURE_STATE(spserv);
-
-    nsCOMPtr<nsISocketProvider> provider;
-    rv = spserv->GetSocketProvider("ssl", getter_AddRefs(provider));
-    NS_ENSURE_SUCCESS(rv, rv);
+    mWebSocketProtocol =
+      do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv);
   }
-
-  mTryConnectTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
+  else {
+    mWebSocketProtocol =
+      do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv);
+  }
+  NS_ENSURE_SUCCESS(rv, rv);
+  
+  rv = mWebSocketProtocol->SetNotificationCallbacks(this);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mInitialServerResponseTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // add ourselves to the document's load group
+  // add ourselves to the document's load group and
+  // provide the http stack the loadgroup info too
   nsCOMPtr<nsILoadGroup> loadGroup;
   rv = GetLoadGroup(getter_AddRefs(loadGroup));
-  NS_ENSURE_SUCCESS(rv, rv);
   if (loadGroup) {
+    rv = mWebSocketProtocol->SetLoadGroup(loadGroup);
+    NS_ENSURE_SUCCESS(rv, rv);
     rv = loadGroup->AddRequest(this, nsnull);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  mAuthProvider =
-    do_CreateInstance("@mozilla.org/network/http-channel-auth-provider;1",
-                      &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = mAuthProvider->Init(this);
+  if (!mOwner->mProtocol.IsEmpty())
+    rv = mWebSocketProtocol->SetProtocol(mOwner->mProtocol);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  CopyUTF16toUTF8(mOwner->mOriginalURL, mRequestName);
-
-  if (!sWSsConnecting) {
-    sWSsConnecting =
-      new nsTArray<nsRefPtr<nsWebSocketEstablishedConnection> >();
-    ENSURE_TRUE_AND_FAIL_IF_FAILED(sWSsConnecting, NS_ERROR_OUT_OF_MEMORY);
-  }
-
-  if (!gWebSocketThread) {
-    rv = NS_NewThread(&gWebSocketThread);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  rv = ResolveNextProxyAndConnect();
+  nsCString utf8Origin;
+  CopyUTF16toUTF8(mOwner->mUTF16Origin, utf8Origin);
+  rv = mWebSocketProtocol->AsyncOpen(mOwner->mURI,
+                                     utf8Origin, this, nsnull);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-nsWebSocketEstablishedConnection::DoConnect()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  nsresult rv;
-
-  rv = AddWSConnecting();
-  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-  mStatus = CONN_CONNECTING;
-
-  nsCOMPtr<nsISocketTransportService> sts =
-    do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
-  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-  // configure the socket type based on the connection type requested.
-  const char* types[1];
-  nsAdoptingCString value =
-    nsContentUtils::GetCharPref("network.http.default-socket-type");
-
-  if (mOwner->mSecure) {
-    types[0] = "ssl";
-  } else {
-    if (value.IsEmpty()) {
-      types[0] = nsnull;
-    } else {
-      types[0] = value.get();
-    }
-  }
-
-  nsCOMPtr<nsISocketTransport> strans;
-  PRUint32 typeCount = (types[0] != nsnull ? 1 : 0);
-
-  rv = sts->CreateTransport(types, typeCount, mOwner->mAsciiHost, mOwner->mPort,
-                            mProxyInfo, getter_AddRefs(strans));
-  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-  rv = strans->SetSecurityCallbacks(this);
-  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-  nsCOMPtr<nsIOutputStream> outStream;
-  rv = strans->OpenOutputStream(nsITransport::OPEN_UNBUFFERED, 0, 0,
-                                getter_AddRefs(outStream));
-  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-  nsCOMPtr<nsIInputStream> inStream;
-  rv = strans->OpenInputStream(nsITransport::OPEN_UNBUFFERED, 0, 0,
-                               getter_AddRefs(inStream));
-  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-  mSocketTransport = strans;
-  mSocketInput = do_QueryInterface(inStream);
-  mSocketOutput = do_QueryInterface(outStream);
-  mProxyResolveCancelable = nsnull;
-
-  if (!UsingHttpProxy()) {
-    rv = DoInitialRequest();
-    ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-    return NS_OK;
-  }
-
-  nsAutoPtr<nsCString> buf(new nsCString());
-  ENSURE_TRUE_AND_FAIL_IF_FAILED(buf.get(), NS_ERROR_OUT_OF_MEMORY);
-
-  nsString strRequestTmp;
-
-  // CONNECT host:port HTTP/1.1
-  buf->AppendLiteral("CONNECT ");
-  buf->Append(mOwner->mAsciiHost);
-  buf->AppendLiteral(":");
-  buf->AppendInt(mOwner->mPort);
-  buf->AppendLiteral(" HTTP/1.1\r\n");
-
-  // Host
-  // all HTTP/1.1 requests must include a Host header (even though it
-  // may seem redundant in this case; see bug 82388).
-  buf->AppendLiteral("Host: ");
-  buf->Append(mOwner->mAsciiHost);
-  buf->AppendLiteral(":");
-  buf->AppendInt(mOwner->mPort);
-  buf->AppendLiteral("\r\n");
-
-  // Proxy Authorization
-  rv = AddAuthorizationHeaders(*buf, PR_TRUE);
-  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-  buf->AppendLiteral("\r\n");
-
-  mStatus = CONN_CONNECTING_TO_HTTP_PROXY;
-
-  rv = PostData(buf.forget(), eConnectFrame);
-  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-  return NS_OK;
-}
-
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(AddWSConnecting)
-{
-#ifdef DEBUG
-  PRUint32 index =
-    sWSsConnecting->BinaryIndexOf(this, nsWSNetAddressComparator());
-  NS_ASSERTION(index == nsTArray<PRNetAddr>::NoIndex,
-               "The ws connection shouldn't be already added in the "
-               "serialization list.");
-  bool inserted = !!
-#endif
-  sWSsConnecting->InsertElementSorted(this, nsWSNetAddressComparator());
-  NS_ASSERTION(inserted, "Couldn't insert the ws connection into the "
-                         "serialization list.");
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(RemoveWSConnecting)
-{
-  if (mStatus == CONN_NOT_CONNECTED) {
-    return;
-  }
-  PRUint32 index =
-    sWSsConnecting->BinaryIndexOf(this, nsWSNetAddressComparator());
-  if (index != nsTArray<PRNetAddr>::NoIndex) {
-    sWSsConnecting->RemoveElementAt(index);
-  }
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-// static
-void
-nsWebSocketEstablishedConnection::TryConnect(nsITimer* aTimer,
-                                             void* aClosure)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  nsresult rv;
-  nsRefPtr<nsWebSocketEstablishedConnection> thisObject =
-    static_cast<nsWebSocketEstablishedConnection*>(aClosure);
-
-  if (!thisObject->mOwner) { // we have been disconnected
-    return;
-  }
-
-  PRUint32 index = sWSsConnecting->BinaryIndexOf(thisObject,
-                                                 nsWSNetAddressComparator());
-  if (index != nsTArray<PRNetAddr>::NoIndex) {
-    // try again after TIMEOUT_TRY_CONNECT_AGAIN second
-    rv = thisObject->mTryConnectTimer->
-      InitWithFuncCallback(TryConnect, thisObject,
-                           TIMEOUT_TRY_CONNECT_AGAIN, nsITimer::TYPE_ONE_SHOT);
-    CHECK_SUCCESS_AND_FAIL_IF_FAILED2(rv);
-  } else {
-    rv = thisObject->DoConnect();
-    CHECK_SUCCESS_AND_FAIL_IF_FAILED2(rv);
-  }
-}
-
-// static
-void
-nsWebSocketEstablishedConnection::
-  TimerInitialServerResponseCallback(nsITimer* aTimer,
-                                     void* aClosure)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  nsRefPtr<nsWebSocketEstablishedConnection> thisObject =
-    static_cast<nsWebSocketEstablishedConnection*>(aClosure);
-
-  if (!thisObject->mOwner) { // we have been disconnected
-    return;
-  }
-
-  thisObject->FailConnection();
-}
-
-// static
-void
-nsWebSocketEstablishedConnection::TimerForceCloseCallback(nsITimer* aTimer,
-                                                          void* aClosure)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  nsRefPtr<nsWebSocketEstablishedConnection> thisObject =
-    static_cast<nsWebSocketEstablishedConnection*>(aClosure);
-
-  if (!thisObject->mOwner) { // we have been disconnected
-    return;
-  }
-
-  thisObject->ForceClose();
-}
-
-nsresult
-nsWebSocketEstablishedConnection::ProcessHeaders()
-{
-  NS_ASSERTION(!NS_IsMainThread(), "Not running on socket thread");
-
-  nsresult rv;
-
-  if (mAuthenticating) {
-    if (mHeaders[kProxyAuthenticatePos].IsEmpty())
-      return NS_ERROR_UNEXPECTED;
-    return NS_OK;
-  }
-
-  if (mReadingProxyConnectResponse) {
-    return NS_OK;
-  }
-
-  // test the upgrade header
-
-  if (!mHeaders[kUpgradePos].EqualsLiteral("WebSocket")) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  // test the connection header
-
-  if (!mHeaders[kConnectionPos].LowerCaseEqualsLiteral("upgrade")) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  // test the sec-websocket-origin header
-
-  nsCString responseOriginHeader = mHeaders[kSecWebSocketOriginPos];
-  ToLowerCase(responseOriginHeader);
-
-  if (!responseOriginHeader.Equals(mOwner->mOrigin)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  // test the sec-websocket-location header
-
-  nsCString validWebSocketLocation1, validWebSocketLocation2;
-  validWebSocketLocation1.Append(mOwner->mSecure ? "wss://" : "ws://");
-  validWebSocketLocation1.Append(mOwner->mAsciiHost);
-  validWebSocketLocation1.Append(":");
-  validWebSocketLocation1.AppendInt(mOwner->mPort);
-  validWebSocketLocation1.Append(mOwner->mResource);
-
-  if ((mOwner->mSecure && mOwner->mPort != DEFAULT_WSS_SCHEME_PORT) ||
-      (!mOwner->mSecure && mOwner->mPort != DEFAULT_WS_SCHEME_PORT)) {
-    validWebSocketLocation2 = validWebSocketLocation1;
-  } else {
-    validWebSocketLocation2.Append(mOwner->mSecure ? "wss://" : "ws://");
-    validWebSocketLocation2.Append(mOwner->mAsciiHost);
-    validWebSocketLocation2.Append(mOwner->mResource);
-  }
-
-  if (!mHeaders[kSecWebSocketLocationPos].Equals(validWebSocketLocation1) &&
-      !mHeaders[kSecWebSocketLocationPos].Equals(validWebSocketLocation2)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  // handle the sec-websocket-protocol header
-  if (!mOwner->mProtocol.IsEmpty() &&
-      !mHeaders[kSecWebSocketProtocolPos].
-        Equals(mOwner->mProtocol)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  // handle the set-cookie header
-
-  if (!mHeaders[kSetCookiePos].IsEmpty()) {
-    rv = HandleSetCookieHeader();
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  return NS_OK;
-}
-
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(HandleSetCookieHeader)
-{
-  nsresult rv;
-
-  nsCOMPtr<nsICookieService> cookieService =
-    do_GetService(NS_COOKIESERVICE_CONTRACTID);
-  nsCOMPtr<nsIDocument> doc =
-    nsContentUtils::GetDocumentFromScriptContext(mOwner->mScriptContext);
-
-  if (!cookieService || !doc) {
-    return;
-  }
-
-  nsCOMPtr<nsIURI> documentURI = doc->GetDocumentURI();
-  if (!documentURI) {
-    return;
-  }
-
-  nsCOMPtr<nsIPromptFactory> wwatch =
-    do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
-  CHECK_SUCCESS_AND_FAIL_IF_FAILED(rv);
-
-  nsCOMPtr<nsIPrompt> prompt;
-  nsCOMPtr<nsPIDOMWindow> outerWindow = doc->GetWindow();
-  rv = wwatch->GetPrompt(outerWindow, NS_GET_IID(nsIPrompt),
-                         getter_AddRefs(prompt));
-  CHECK_SUCCESS_AND_FAIL_IF_FAILED(rv);
-
-  rv = cookieService->SetCookieStringFromHttp(documentURI,
-                                              documentURI,
-                                              prompt,
-                                              mHeaders[kSetCookiePos].get(),
-                                              nsnull,
-                                              nsnull);
-  CHECK_SUCCESS_AND_FAIL_IF_FAILED(rv);
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-nsresult
 nsWebSocketEstablishedConnection::PrintErrorOnConsole(const char *aBundleURI,
                                                       const PRUnichar *aError,
                                                       const PRUnichar **aFormatStrings,
                                                       PRUint32 aFormatStringsLen)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   nsresult rv;
 
   nsCOMPtr<nsIStringBundleService> bundleService =
     do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIStringBundle> strBundle;
@@ -1985,864 +354,227 @@ nsWebSocketEstablishedConnection::PrintE
   // print the error message directly to the JS console
   nsCOMPtr<nsIScriptError> logError(do_QueryInterface(errorObject));
   rv = console->LogMessage(logError);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(Close)
+// when this is called the browser side wants no more part of it
+nsresult
+nsWebSocketEstablishedConnection::Close()
 {
-  nsresult rv;
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   // Disconnect() can release this object, so we keep a
   // reference until the end of the method
   nsRefPtr<nsWebSocketEstablishedConnection> kungfuDeathGrip = this;
 
   if (mOwner->mReadyState == nsIWebSocket::CONNECTING) {
     mOwner->SetReadyState(nsIWebSocket::CLOSING);
     mOwner->SetReadyState(nsIWebSocket::CLOSED);
     Disconnect();
-    return;
+    return NS_OK;
   }
 
   mOwner->SetReadyState(nsIWebSocket::CLOSING);
-  if (!mCloseFrameServerResponseTimer) {
-    mCloseFrameServerResponseTimer =
-      do_CreateInstance("@mozilla.org/timer;1", &rv);
-
-    if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to create mCloseFrameServerResponseTimer.");
-    } else {
-      rv = mCloseFrameServerResponseTimer->
-        InitWithFuncCallback(TimerForceCloseCallback, this,
-                             TIMEOUT_WAIT_FOR_CLOSING, nsITimer::TYPE_ONE_SHOT);
-      if (NS_FAILED(rv)) {
-        NS_WARNING("Failed to start the ForceClose timeout.");
-      }
-    }
-  }
 
   if (mStatus == CONN_CLOSED) {
     mOwner->SetReadyState(nsIWebSocket::CLOSED);
     Disconnect();
-  } else if (!mPostedCloseFrame) {
-    nsAutoPtr<nsCString> closeFrame(new nsCString());
-    if (!closeFrame.get()) {
-      return;
-    }
-
-    closeFrame->SetLength(2);
-    if (closeFrame->Length() != 2) {
-      return;
-    }
-
-    closeFrame->SetCharAt(START_BYTE_OF_CLOSE_FRAME, 0);
-    closeFrame->SetCharAt(END_BYTE_OF_CLOSE_FRAME, 1);
+    return NS_OK;
+  }
 
-    rv = PostData(closeFrame.forget(), eCloseFrame);
-    if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to post the close frame");
-      return;
-    }
-  } else {
-    // Probably failed to send the close frame. Just disconnect.
-    Disconnect();
-  }
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-void
-nsWebSocketEstablishedConnection::ForceClose()
-{
-  // Disconnect() can release this object, so we keep a
-  // reference until the end of the method
-  nsRefPtr<nsWebSocketEstablishedConnection> kungfuDeathGrip = this;
-
-  mOwner->SetReadyState(nsIWebSocket::CLOSING);
-  mOwner->SetReadyState(nsIWebSocket::CLOSED);
-  Disconnect();
+  return mWebSocketProtocol->Close();
 }
 
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(FailConnection)
+nsresult
+nsWebSocketEstablishedConnection::ConsoleError()
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsresult rv;
-  nsWSAutoClose autoClose(this);
-
-  if (mFailureStatus == NS_OK) {
-    mFailureStatus = NS_ERROR_UNEXPECTED;
-  }
-
+  if (!mOwner) return NS_OK;
+  
   nsCAutoString targetSpec;
   rv = mOwner->mURI->GetSpec(targetSpec);
-  WARN_IF_FALSE_AND_RETURN(NS_SUCCEEDED(rv), "Failed to get targetSpec");
-
-  NS_ConvertUTF8toUTF16 specUTF16(targetSpec);
-  const PRUnichar *formatStrings[] = { specUTF16.get() };
-
-  if (mStatus < CONN_CONNECTED_AND_READY) {
-    if (mCurrentProxyConfig == eResolvingProxyFailed) {
-      PrintErrorOnConsole("chrome://browser/locale/appstrings.properties",
-                          NS_LITERAL_STRING("proxyConnectFailure").get(),
-                          nsnull, 0);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Failed to get targetSpec");
+  } else {
+    NS_ConvertUTF8toUTF16 specUTF16(targetSpec);
+    const PRUnichar *formatStrings[] = { specUTF16.get() };
+    
+    if (mStatus < CONN_CONNECTED_AND_READY) {
+      PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
+                          NS_LITERAL_STRING("connectionFailure").get(),
+                          formatStrings, NS_ARRAY_LENGTH(formatStrings));
+    } else {
+      PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
+                          NS_LITERAL_STRING("netInterrupt").get(),
+                          formatStrings, NS_ARRAY_LENGTH(formatStrings));
     }
-    PrintErrorOnConsole("chrome://browser/locale/appstrings.properties",
-                        NS_LITERAL_STRING("connectionFailure").get(),
-                        formatStrings, NS_ARRAY_LENGTH(formatStrings));
-  } else {
-    PrintErrorOnConsole("chrome://browser/locale/appstrings.properties",
-                        NS_LITERAL_STRING("netInterrupt").get(),
-                        formatStrings, NS_ARRAY_LENGTH(formatStrings));
   }
+  /// todo some sepcific errors - like for message too large
+  return rv;
 }
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
+
+
+nsresult
+nsWebSocketEstablishedConnection::FailConnection()
+{
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  nsresult rv = ConsoleError();
+  Close();
+  return rv;
+}
 
 nsresult
 nsWebSocketEstablishedConnection::Disconnect()
 {
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  {
-    if (!mOwner) {
-      return NS_OK;
-    }
- 
-    MutexAutoLock lockDisconnect(mLockDisconnect);
-
-    // If mOwner is deleted when calling mOwner->DontKeepAliveAnyMore()
-    // then this method can be called again, and we will get a deadlock.
-    nsRefPtr<nsWebSocket> kungfuDeathGrip = mOwner;
-
-    mOwner->DontKeepAliveAnyMore();
-
-    RemoveWSConnecting();
-
-    mStatus = CONN_CLOSED;
-    mOwner = nsnull;
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
-    if (mAuthProvider) {
-      mAuthProvider->Disconnect(NS_ERROR_ABORT);
-      mAuthProvider = nsnull;
-    }
-
-    if (mTryConnectTimer) {
-      mTryConnectTimer->Cancel();
-      mTryConnectTimer = nsnull;
-    }
-
-    if (mInitialServerResponseTimer) {
-      mInitialServerResponseTimer->Cancel();
-      mInitialServerResponseTimer = nsnull;
-    }
-
-    if (mCloseFrameServerResponseTimer) {
-      mCloseFrameServerResponseTimer->Cancel();
-      mCloseFrameServerResponseTimer = nsnull;
-    }
+  if (!mOwner) {
+    return NS_OK;
+  }
+  
+  nsCOMPtr<nsILoadGroup> loadGroup;
+  GetLoadGroup(getter_AddRefs(loadGroup));
+  if (loadGroup)
+    loadGroup->RemoveRequest(this, nsnull, NS_OK);
 
-    if (mProxyResolveCancelable) {
-      mProxyResolveCancelable->Cancel(NS_ERROR_ABORT);
-      mProxyResolveCancelable = nsnull;
-    }
-
-    if (mDNSRequest) {
-      mDNSRequest->Cancel(NS_ERROR_ABORT);
-      mDNSRequest = nsnull;
-    }
+  // If mOwner is deleted when calling mOwner->DontKeepAliveAnyMore()
+  // then this method can be called again, and we will get a deadlock.
+  nsRefPtr<nsWebSocket> kungfuDeathGrip = mOwner;
+  
+  mOwner->DontKeepAliveAnyMore();
+  mStatus = CONN_CLOSED;
+  mOwner = nsnull;
+  mWebSocketProtocol = nsnull;
 
-    if (mSocketInput) {
-      mSocketInput->Close();
-      mSocketInput = nsnull;
-    }
-    if (mSocketOutput) {
-      mSocketOutput->Close();
-      mSocketOutput = nsnull;
-    }
-    if (mSocketTransport) {
-      mSocketTransport->Close(NS_OK);
-      mSocketTransport = nsnull;
-    }
-    mProxyInfo = nsnull;
-
-    while (mOutgoingMessages.GetSize() != 0) {
-      delete static_cast<nsWSFrame*>(mOutgoingMessages.PopFront());
-    }
-
-    while (mReceivedMessages.GetSize() != 0) {
-      delete static_cast<nsCString*>(mReceivedMessages.PopFront());
-    }
-
-    // Remove ourselves from the document's load group. nsIRequest expects
-    // this be done asynchronously.
-    nsCOMPtr<nsIRunnable> event =
-      NS_NewRunnableMethod(this, &nsWebSocketEstablishedConnection::
-                                  RemoveFromLoadGroup);
-    if (event) {
-      NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
-    }
-
-    nsLayoutStatics::Release();
-  }
-
+  nsLayoutStatics::Release();
   return NS_OK;
 }
 
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(Retry)
-{
-  nsresult rv;
-
-  for (PRUint32 i = 0; i < kHeadersLen; ++i) {
-    mHeaders[i].Truncate();
-  }
-
-  rv = OnProxyAvailable(nsnull, mOwner->mURI, mProxyInfo, NS_OK);
-  CHECK_SUCCESS_AND_FAIL_IF_FAILED(rv);
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(ResolveNextProxyAndConnect)
-{
-  nsresult rv;
-
-  if (mCurrentProxyConfig == eResolvingProxyFailed) {
-    return;
-  }
-
-  nsCOMPtr<nsIProtocolProxyService2> proxyService =
-    do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed getting proxyService");
-    mCurrentProxyConfig = eResolvingProxyFailed;
-    mFailureStatus = NS_ERROR_UNKNOWN_PROXY_HOST;
-    FailConnection();
-    return;
-  }
-
-  if (mProxyInfo) {
-    // If there was already a proxy info it means we tried to connect to its
-    // proxy, but we couldn't. We have to remove the connection from the
-    // serialization list, reset it, and try to get a failover proxy.
-
-    {
-      MutexAutoLock lockDisconnect(mLockDisconnect);
-      rv = Reset();
-      CHECK_SUCCESS_AND_FAIL_IF_FAILED(rv);
-    }
-
-    nsCOMPtr<nsIProxyInfo> pi;
-    rv = proxyService->GetFailoverForProxy(mProxyInfo, mOwner->mURI,
-                                           mProxyFailureReason,
-                                           getter_AddRefs(pi));
-    if (NS_FAILED(rv)) {
-      mProxyInfo = nsnull;
-      ResolveNextProxyAndConnect();
-      return;
-    }
-
-    OnProxyAvailable(nsnull, mOwner->mURI, pi, NS_OK);
-    return;
-  }
-
-  // if (!mProxyInfo)
-
-  PRUint32 flags = nsIProtocolProxyService::RESOLVE_IGNORE_URI_SCHEME;
-
-  if (mCurrentProxyConfig == eNotResolvingProxy) {
-    mCurrentProxyConfig = eResolvingSOCKSProxy;
-    flags |= nsIProtocolProxyService::RESOLVE_PREFER_SOCKS_PROXY;
-  } else if (mCurrentProxyConfig == eResolvingSOCKSProxy) {
-    flags |= nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY;
-    mCurrentProxyConfig = eResolvingHTTPSProxy;
-  } else if (mCurrentProxyConfig == eResolvingHTTPSProxy) {
-    mCurrentProxyConfig = eResolvingHTTPProxy;
-  } else if (mCurrentProxyConfig == eResolvingHTTPProxy) {
-    mCurrentProxyConfig = eResolvingProxyFailed;
-    mFailureStatus = NS_ERROR_UNKNOWN_PROXY_HOST;
-    FailConnection();
-    return;
-  }
-
-  rv = proxyService->AsyncResolve(mOwner->mURI,
-                                  flags, this,
-                                  getter_AddRefs(mProxyResolveCancelable));
-  if (NS_FAILED(rv)) {
-    ResolveNextProxyAndConnect();
-    return;
-  }
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(UpdateMustKeepAlive)
-{
-  mOwner->UpdateMustKeepAlive();
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-void
-nsWebSocketEstablishedConnection::RemoveFromLoadGroup()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-  nsCOMPtr<nsILoadGroup> loadGroup;
-  GetLoadGroup(getter_AddRefs(loadGroup));
-  if (loadGroup) {
-    loadGroup->RemoveRequest(this, nsnull, NS_OK);
-  }
-}
-
-//-----------------------------------------------------------------------------
-// Authentication
-//-----------------------------------------------------------------------------
-
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_BEGIN(ProcessAuthentication)
+nsresult
+nsWebSocketEstablishedConnection::UpdateMustKeepAlive()
 {
-  nsresult rv = mAuthProvider->ProcessAuthentication(407, PR_FALSE);
-
-  if (rv == NS_ERROR_IN_PROGRESS) {
-    return;
-  }
-
-  if (NS_FAILED(rv)) {
-    NS_WARNING("ProcessAuthentication failed");
-    FailConnection();
-    return;
-  }
-
-  Retry();
-}
-IMPL_RUNNABLE_ON_MAIN_THREAD_METHOD_END
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-#define NOT_IMPLEMENTED_IF_FUNC_BEGIN(_func)                                   \
-  NS_IMETHODIMP                                                                \
-  nsWebSocketEstablishedConnection::_func
-
-#define NOT_IMPLEMENTED_IF_FUNC_END(_func)                                     \
-  {                                                                            \
-    return NS_ERROR_NOT_IMPLEMENTED;                                           \
-  }
-
-#define NOT_IMPLEMENTED_IF_FUNC_0(_func)                                       \
-  NOT_IMPLEMENTED_IF_FUNC_BEGIN(_func) ()                                      \
-  NOT_IMPLEMENTED_IF_FUNC_END(_func)
-
-#define NOT_IMPLEMENTED_IF_FUNC_1(_func, _arg)                                 \
-  NOT_IMPLEMENTED_IF_FUNC_BEGIN(_func) (_arg)                                  \
-  NOT_IMPLEMENTED_IF_FUNC_END(_func)
-
-#define NOT_IMPLEMENTED_IF_FUNC_2(_func, _arg1, arg2)                          \
-  NOT_IMPLEMENTED_IF_FUNC_BEGIN(_func) (_arg1, arg2)                           \
-  NOT_IMPLEMENTED_IF_FUNC_END(_func)
-
-//-----------------------------------------------------------------------------
-// nsWebSocketEstablishedConnection::nsIRequest
-//-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetName(nsACString &aName)
-{
-  aName = mRequestName;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::IsPending(PRBool *aValue)
-{
-  *aValue = !!(mOwner);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetStatus(nsresult *aStatus)
-{
-  *aStatus = mFailureStatus;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::Cancel(nsresult aStatus)
-{
-  if (!mOwner) {
-    return NS_OK;
-  }
-
-  mFailureStatus = aStatus;
-
-  return Close();
-}
-
-NOT_IMPLEMENTED_IF_FUNC_0(Suspend)
-NOT_IMPLEMENTED_IF_FUNC_0(Resume)
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetLoadGroup(nsILoadGroup **aLoadGroup)
-{
-  *aLoadGroup = nsnull;
-  if (!mOwner)
-    return NS_OK;
-
-  nsCOMPtr<nsIDocument> doc =
-    nsContentUtils::GetDocumentFromScriptContext(mOwner->mScriptContext);
-
-  if (doc) {
-    *aLoadGroup = doc->GetDocumentLoadGroup().get();  // already_AddRefed
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::SetLoadGroup(nsILoadGroup *aLoadGroup)
-{
-  return NS_ERROR_UNEXPECTED;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetLoadFlags(nsLoadFlags *aLoadFlags)
-{
-  *aLoadFlags = nsIRequest::LOAD_BACKGROUND;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::SetLoadFlags(nsLoadFlags aLoadFlags)
-{
-  // we won't change the load flags at all.
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  mOwner->UpdateMustKeepAlive();
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
-// nsWebSocketEstablishedConnection::nsIChannel
-//-----------------------------------------------------------------------------
-
-NOT_IMPLEMENTED_IF_FUNC_1(GetOriginalURI, nsIURI **originalURI)
-NOT_IMPLEMENTED_IF_FUNC_1(SetOriginalURI, nsIURI *originalURI)
-NOT_IMPLEMENTED_IF_FUNC_1(GetOwner, nsISupports **owner)
-NOT_IMPLEMENTED_IF_FUNC_1(SetOwner, nsISupports *owner)
-NOT_IMPLEMENTED_IF_FUNC_1(SetNotificationCallbacks,
-                          nsIInterfaceRequestor *callbacks)
-NOT_IMPLEMENTED_IF_FUNC_1(GetSecurityInfo, nsISupports **securityInfo)
-NOT_IMPLEMENTED_IF_FUNC_1(GetContentType, nsACString &value)
-NOT_IMPLEMENTED_IF_FUNC_1(SetContentType, const nsACString &value)
-NOT_IMPLEMENTED_IF_FUNC_1(GetContentCharset, nsACString &value)
-NOT_IMPLEMENTED_IF_FUNC_1(SetContentCharset, const nsACString &value)
-NOT_IMPLEMENTED_IF_FUNC_1(GetContentLength, PRInt32 *value)
-NOT_IMPLEMENTED_IF_FUNC_1(SetContentLength, PRInt32 value)
-NOT_IMPLEMENTED_IF_FUNC_1(Open, nsIInputStream **_retval)
-NOT_IMPLEMENTED_IF_FUNC_2(AsyncOpen, nsIStreamListener *listener,
-                          nsISupports *context)
-
-//-----------------------------------------------------------------------------
-// nsWebSocketEstablishedConnection::nsIHttpAuthenticableChannel
+// nsWebSocketEstablishedConnection::nsIWebSocketListener methods:
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetProxyInfo(nsIProxyInfo **result)
-{
-  NS_IF_ADDREF(*result = mProxyInfo);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetIsSSL(PRBool *aIsSSL)
-{
-  *aIsSSL = mOwner->mSecure;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetProxyMethodIsConnect(PRBool *aProxyMethodIsConnect)
+nsWebSocketEstablishedConnection::OnMessageAvailable(nsISupports *aContext,
+                                                     const nsACString & aMsg)
 {
-  *aProxyMethodIsConnect = UsingHttpProxy();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetURI(nsIURI **aURI)
-{
-  NS_IF_ADDREF(*aURI = mOwner->mURI);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetNotificationCallbacks(nsIInterfaceRequestor **callbacks)
-{
-  NS_ADDREF(*callbacks = this);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetRequestMethod(nsACString &method)
-{
-  if (mAuthenticating) {
-    method.AssignLiteral("CONNECT");
-  } else {
-    method.AssignLiteral("GET");
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  if (!mOwner)
+    return NS_ERROR_NOT_AVAILABLE;
+  
+  // Dispatch New Message
+  nsresult rv = mOwner->CreateAndDispatchMessageEvent(aMsg);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Failed to dispatch the message event");
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetServerResponseHeader(nsACString &value)
+nsWebSocketEstablishedConnection::OnBinaryMessageAvailable(
+  nsISupports *aContext,
+  const nsACString & aMsg)
 {
-  if (mHeaders[kServerPos].IsEmpty()) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  value.Assign(mHeaders[kServerPos]);
-  return NS_OK;
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetProxyChallenges(nsACString &value)
-{
-  if (mHeaders[kProxyAuthenticatePos].IsEmpty()) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-  value.Assign(mHeaders[kProxyAuthenticatePos]);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::GetWWWChallenges(nsACString &value)
+nsWebSocketEstablishedConnection::OnStart(nsISupports *aContext)
 {
-  return NS_ERROR_NOT_AVAILABLE;
-}
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  if (!mOwner)
+    return NS_OK;
 
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::SetProxyCredentials(const nsACString &value)
-{
-  mProxyCredentials.Assign(value);
-  return NS_OK;
-}
+  if (!mOwner->mProtocol.IsEmpty())
+    mWebSocketProtocol->GetProtocol(mOwner->mProtocol);
 
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::SetWWWCredentials(const nsACString &value)
-{
-  mCredentials.Assign(value);
+  mStatus = CONN_CONNECTED_AND_READY;
+  mOwner->SetReadyState(nsIWebSocket::OPEN);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsWebSocketEstablishedConnection::OnAuthAvailable()
+nsWebSocketEstablishedConnection::OnStop(nsISupports *aContext,
+                                         nsresult aStatusCode)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  if (!mOwner) {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  if (!mOwner)
     return NS_OK;
-  }
-
-  return Retry();
-}
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::OnAuthCancelled(PRBool userCancel)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  if (!mOwner) {
-    return NS_OK;
-  }
 
-  if (!userCancel) {
-    return FailConnection();
-  }
-
-  return Close();
-}
+  mClosedCleanly = NS_SUCCEEDED(aStatusCode);
 
-//-----------------------------------------------------------------------------
-// nsWebSocketEstablishedConnection::nsIDNSListener
-//-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::OnLookupComplete(nsICancelable *aRequest,
-                                                   nsIDNSRecord  *aRec,
-                                                   nsresult       aStatus)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  if (!mOwner) {
-    return NS_ERROR_ABORT;
+  if (aStatusCode == NS_BASE_STREAM_CLOSED && 
+      mOwner->mReadyState >= nsIWebSocket::CLOSING) {
+    // don't generate an error event just because of an unclean close
+    aStatusCode = NS_OK;
   }
 
-  mDNSRequest = nsnull;
-  mFailureStatus = aStatus;
-  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(aStatus, aStatus);
-
-  nsresult rv;
-
-  rv = aRec->GetNextAddr(mOwner->mPort, &mPRNetAddr);
-  ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-  TryConnect(nsnull, this);
-
-  return NS_OK;
-}
-
-//-----------------------------------------------------------------------------
-// nsWebSocketEstablishedConnection::nsIProtocolProxyCallback
-//-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-nsWebSocketEstablishedConnection::OnProxyAvailable(nsICancelable *aRequest,
-                                                   nsIURI *aUri,
-                                                   nsIProxyInfo *aProxyInfo,
-                                                   nsresult aStatus)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
-
-  nsresult rv;
-
-  if (!mOwner) {
-    return NS_ERROR_ABORT;
+  if (NS_FAILED(aStatusCode)) {
+    ConsoleError();
+    if (mOwner && mOwner->mReadyState != nsIWebSocket::CONNECTING) {
+      nsresult rv =
+        mOwner->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
+      if (NS_FAILED(rv))
+        NS_WARNING("Failed to dispatch the error event");
+    }
   }
 
-  if (NS_FAILED(aStatus)) {
-    return ResolveNextProxyAndConnect();
+  mStatus = CONN_CLOSED;
+  if (mOwner) {
+    mOwner->SetReadyState(nsIWebSocket::CLOSED);
+    Disconnect();
   }
-
-  mProxyInfo = aProxyInfo;
-
-  if (mProxyInfo) {
-    TryConnect(nsnull, this);
-  } else {
-    // we need the server IP address because it must connect only one instance
-    // per IP address at a time.
-
-    nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv);
-    ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-    nsCOMPtr<nsIThread> thread = do_GetMainThread();
-    rv = dns->AsyncResolve(mOwner->mAsciiHost,
-                           0, this, thread, getter_AddRefs(mDNSRequest));
-    ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-  }
-
   return NS_OK;
 }
 
-//-----------------------------------------------------------------------------
-// nsWebSocketEstablishedConnection::nsIInputStreamCallback methods:
-//-----------------------------------------------------------------------------
-
-nsresult
-nsWebSocketEstablishedConnection::OnInputStreamReady(nsIAsyncInputStream *aStream)
+NS_IMETHODIMP
+nsWebSocketEstablishedConnection::OnAcknowledge(nsISupports *aContext,
+                                                PRUint32 aSize)
 {
-  NS_ASSERTION(!NS_IsMainThread(), "Not running on socket thread");
-
-  nsresult rv;
-
-  {
-    MutexAutoLock lockDisconnect(mLockDisconnect);
-
-    if (!mOwner) {
-      return NS_ERROR_ABORT;
-    }
-
-    NS_ASSERTION(aStream == mSocketInput, "unexpected stream");
-
-    while (PR_TRUE) {
-      if (mBuffer.Length() - mBytesInBuffer < DEFAULT_BUFFER_SIZE) {
-        PRUint32 newLen = mBuffer.Length() + DEFAULT_BUFFER_SIZE;
-        mBuffer.SetLength(newLen);
-        ENSURE_TRUE_AND_FAIL_IF_FAILED(mBuffer.Length() == newLen,
-                                       NS_ERROR_OUT_OF_MEMORY);
-      }
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
-      PRUint32 read;
-      rv = aStream->Read(mBuffer.BeginWriting() + mBytesInBuffer,
-                         DEFAULT_BUFFER_SIZE, &read);
-      if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
-        break;
-      }
-      mFailureStatus = rv;
-      ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-
-      // check if the stream has been closed
-      if (read == 0) {
-        // If we are asking for credentials then the old connection has been
-        // closed. In this case we have to reset the WebSocket, not Close it.
-        if (mStatus != CONN_RETRYING_TO_AUTHENTICATE) {
-          mStatus = CONN_CLOSED;
-          mFailureStatus = NS_BASE_STREAM_CLOSED;
-          if (mStatus < CONN_CONNECTED_AND_READY) {
-            FailConnection();
-          } else {
-            Close();
-          }
-        }
-        return NS_BASE_STREAM_CLOSED;
-      }
-
-      PRUint32 start = mBytesInBuffer;
-      mBytesInBuffer += read;
-      rv = HandleNewInputString(start);
-      ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-    }
-
-    rv = mSocketInput->AsyncWait(this, 0, 0, gWebSocketThread);
-    ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-  }
-
+  if (aSize > mOutgoingBufferedAmount)
+    return NS_ERROR_UNEXPECTED;
+  
+  mOutgoingBufferedAmount -= aSize;
   return NS_OK;
 }
 
-//-----------------------------------------------------------------------------
-// nsWebSocketEstablishedConnection::nsIOutputStreamCallback methods:
-//-----------------------------------------------------------------------------
-
-nsresult
-nsWebSocketEstablishedConnection::OnOutputStreamReady(nsIAsyncOutputStream *aStream)
+NS_IMETHODIMP
+nsWebSocketEstablishedConnection::OnServerClose(nsISupports *aContext)
 {
-  NS_ASSERTION(!NS_IsMainThread(), "Not running on socket thread");
-
-  nsresult rv;
-
-  {
-    MutexAutoLock lockDisconnect(mLockDisconnect);
-
-    if (!mOwner) {
-      return NS_ERROR_ABORT;
-    }
-
-    NS_ASSERTION(aStream == mSocketOutput, "unexpected stream");
-
-    {
-      MutexAutoLock lockOut(mLockOutgoingMessages);
-
-      while (PR_TRUE) {
-        if (mOutgoingMessages.GetSize() == 0) {
-          break;
-        }
-
-        // send what we can of the 1st string
-
-        nsWSFrame *frameToSend =
-          static_cast<nsWSFrame*>(mOutgoingMessages.PeekFront());
-        nsCString *strToSend = frameToSend->mData;
-        PRUint32 sizeToSend =
-          strToSend->Length() - mBytesAlreadySentOfFirstOutString;
-        PRBool currentStrHasStartFrameByte =
-          (mBytesAlreadySentOfFirstOutString == 0);
-
-        if (sizeToSend != 0) {
-          PRUint32 written;
-          rv = aStream->Write(strToSend->get() + mBytesAlreadySentOfFirstOutString,
-                              sizeToSend, &written);
-          if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
-            break;
-          }
-
-          // on proxy errors when connecting, try to failover
-          if ((mStatus == CONN_CONNECTING_TO_HTTP_PROXY ||
-               (mStatus == CONN_SENDING_INITIAL_REQUEST && mProxyInfo)) &&
-              (rv == NS_ERROR_PROXY_CONNECTION_REFUSED ||
-               rv == NS_ERROR_UNKNOWN_PROXY_HOST ||
-               rv == NS_ERROR_NET_TIMEOUT ||
-               rv == NS_ERROR_NET_RESET)) {
-            mProxyFailureReason = rv;
-            return ResolveNextProxyAndConnect();
-          }
-
-          mFailureStatus = rv;
-          ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
-          if (written == 0) {
-            mStatus = CONN_CLOSED;
-            mFailureStatus = NS_BASE_STREAM_CLOSED;
-            if (mStatus < CONN_CONNECTED_AND_READY) {
-              FailConnection();
-            } else {
-              Close();
-            }
-            return NS_BASE_STREAM_CLOSED;
-          }
-
-          if (frameToSend->mType == eUTF8MessageFrame) {
-            PRBool currentStrHasEndFrameByte =
-              (mBytesAlreadySentOfFirstOutString + written ==
-               strToSend->Length());
-
-            // START_BYTE_OF_MESSAGE and END_BYTE_OF_MESSAGE bytes don't count
-            if (currentStrHasStartFrameByte) {
-              if (currentStrHasEndFrameByte) {
-                mOutgoingBufferedAmount -= written - 2;
-              } else {
-                mOutgoingBufferedAmount -= written - 1;
-              }
-            } else {
-              if (currentStrHasEndFrameByte) {
-                mOutgoingBufferedAmount -= written - 1;
-              } else {
-                mOutgoingBufferedAmount -= written;
-              }
-            }
-          }
-
-          mBytesAlreadySentOfFirstOutString += written;
-        }
-
-        sizeToSend = strToSend->Length() - mBytesAlreadySentOfFirstOutString;
-        if (sizeToSend != 0) { // if different, we try sending what remain after
-          break;
-        }
-
-        // ok, send the next string
-        if (frameToSend->mType == eCloseFrame) {
-          mSentCloseFrame = PR_TRUE;
-        }
-        mOutgoingMessages.PopFront();
-        delete frameToSend;
-        mBytesAlreadySentOfFirstOutString = 0;
-        UpdateMustKeepAlive();
-      }
-
-      if (mOutgoingMessages.GetSize() != 0) {
-        rv = mSocketOutput->AsyncWait(this, 0, 0, gWebSocketThread);
-        ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-      } else {
-        if (mStatus == CONN_SENDING_ACK_CLOSE_FRAME && mSentCloseFrame) {
-          mClosedCleanly = PR_TRUE;
-          mStatus = CONN_CLOSED;
-          return Close();
-        }
-
-        if (mStatus == CONN_SENDING_INITIAL_REQUEST ||
-            mStatus == CONN_CONNECTING_TO_HTTP_PROXY) {
-          if (mStatus == CONN_SENDING_INITIAL_REQUEST) {
-            mStatus = CONN_WAITING_RESPONSE_FOR_INITIAL_REQUEST;
-
-            rv = mInitialServerResponseTimer->
-              InitWithFuncCallback(TimerInitialServerResponseCallback, this,
-                                   TIMEOUT_WAIT_FOR_SERVER_RESPONSE,
-                                   nsITimer::TYPE_ONE_SHOT);
-            ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-          }
-          rv = mSocketInput->AsyncWait(this, 0, 0, gWebSocketThread);
-          ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv);
-        }
-      }
-    }
-  }
-
+  Close();                                        /* reciprocate! */
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsWebSocketEstablishedConnection::nsIInterfaceRequestor
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsWebSocketEstablishedConnection::GetInterface(const nsIID &aIID,
                                                void **aResult)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Not running on main thread");
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
       aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
     nsresult rv;
 
     nsCOMPtr<nsIDocument> doc =
       nsContentUtils::GetDocumentFromScriptContext(mOwner->mScriptContext);
 
@@ -2868,20 +600,22 @@ nsWebSocketEstablishedConnection::GetInt
 nsWebSocket::nsWebSocket() : mKeepingAlive(PR_FALSE),
                              mCheckMustKeepAlive(PR_TRUE),
                              mTriggeredCloseEvent(PR_FALSE),
                              mReadyState(nsIWebSocket::CONNECTING),
                              mOutgoingBufferedAmount(0),
                              mScriptLine(0),
                              mWindowID(0)
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 }
 
 nsWebSocket::~nsWebSocket()
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   if (mConnection) {
     mConnection->Disconnect();
     mConnection = nsnull;
   }
   if (mListenerManager) {
     mListenerManager->Disconnect();
     mListenerManager = nsnull;
   }
@@ -2938,16 +672,17 @@ NS_IMPL_RELEASE_INHERITED(nsWebSocket, n
  */
 NS_IMETHODIMP
 nsWebSocket::Initialize(nsISupports* aOwner,
                         JSContext* aContext,
                         JSObject* aObject,
                         PRUint32 aArgc,
                         jsval* aArgv)
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsAutoString urlParam, protocolParam;
 
   if (!PrefEnabled()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   if (aArgc != 1 && aArgc != 2) {
     return NS_ERROR_DOM_SYNTAX_ERR;
@@ -3006,23 +741,23 @@ nsWebSocket::Initialize(nsISupports* aOw
 
 //-----------------------------------------------------------------------------
 // nsWebSocket methods:
 //-----------------------------------------------------------------------------
 
 nsresult
 nsWebSocket::EstablishConnection()
 {
-  NS_ASSERTION(!mConnection, "mConnection should be null");
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  NS_ABORT_IF_FALSE(!mConnection, "mConnection should be null");
 
   nsresult rv;
 
   nsRefPtr<nsWebSocketEstablishedConnection> conn =
     new nsWebSocketEstablishedConnection();
-  NS_ENSURE_TRUE(conn, NS_ERROR_OUT_OF_MEMORY);
 
   rv = conn->Init(this);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mConnection = conn;
 
   return NS_OK;
 }
@@ -3045,16 +780,17 @@ public:
 private:
   nsRefPtr<nsWebSocket> mWebSocket;
   PRBool mWasClean;
 };
 
 nsresult
 nsWebSocket::CreateAndDispatchSimpleEvent(const nsString& aName)
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsresult rv;
 
   rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIDOMEvent> event;
@@ -3068,50 +804,52 @@ nsWebSocket::CreateAndDispatchSimpleEven
   nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
   rv = privateEvent->SetTrusted(PR_TRUE);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return DispatchDOMEvent(nsnull, event, nsnull, nsnull);
 }
 
 nsresult
-nsWebSocket::CreateAndDispatchMessageEvent(nsCString *aData)
+nsWebSocket::CreateAndDispatchMessageEvent(const nsACString& aData)
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsresult rv;
-
+  
   rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return NS_OK;
   }
 
   // create an event that uses the MessageEvent interface,
   // which does not bubble, is not cancelable, and has no default action
 
   nsCOMPtr<nsIDOMEvent> event;
   rv = NS_NewDOMMessageEvent(getter_AddRefs(event), nsnull, nsnull);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDOMMessageEvent> messageEvent = do_QueryInterface(event);
   rv = messageEvent->InitMessageEvent(NS_LITERAL_STRING("message"),
                                       PR_FALSE, PR_FALSE,
-                                      NS_ConvertUTF8toUTF16(*aData),
-                                      NS_ConvertUTF8toUTF16(mOrigin),
+                                      NS_ConvertUTF8toUTF16(aData),
+                                      mUTF16Origin,
                                       EmptyString(), nsnull);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
   rv = privateEvent->SetTrusted(PR_TRUE);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return DispatchDOMEvent(nsnull, event, nsnull, nsnull);
 }
 
 nsresult
 nsWebSocket::CreateAndDispatchCloseEvent(PRBool aWasClean)
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsresult rv;
 
   mTriggeredCloseEvent = PR_TRUE;
 
   rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return NS_OK;
   }
@@ -3134,73 +872,71 @@ nsWebSocket::CreateAndDispatchCloseEvent
   NS_ENSURE_SUCCESS(rv, rv);
 
   return DispatchDOMEvent(nsnull, event, nsnull, nsnull);
 }
 
 PRBool
 nsWebSocket::PrefEnabled()
 {
-  return nsContentUtils::GetBoolPref("network.websocket.enabled", PR_TRUE) &&
-    nsContentUtils::GetBoolPref("network.websocket.override-security-block",
-                                PR_FALSE);
+  return nsContentUtils::GetBoolPref("network.websocket.enabled", PR_TRUE);
 }
 
 void
 nsWebSocket::SetReadyState(PRUint16 aNewReadyState)
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsresult rv;
 
   if (mReadyState == aNewReadyState) {
     return;
   }
 
-  NS_ASSERTION((aNewReadyState == nsIWebSocket::OPEN) ||
-               (aNewReadyState == nsIWebSocket::CLOSING) ||
-               (aNewReadyState == nsIWebSocket::CLOSED),
-               "unexpected readyState");
+  NS_ABORT_IF_FALSE((aNewReadyState == nsIWebSocket::OPEN)    ||
+                    (aNewReadyState == nsIWebSocket::CLOSING) ||
+                    (aNewReadyState == nsIWebSocket::CLOSED),
+                    "unexpected readyState");
 
   if (aNewReadyState == nsIWebSocket::OPEN) {
-    NS_ASSERTION(mReadyState == nsIWebSocket::CONNECTING,
-                 "unexpected readyState transition");
+    NS_ABORT_IF_FALSE(mReadyState == nsIWebSocket::CONNECTING,
+                      "unexpected readyState transition");
     mReadyState = aNewReadyState;
 
     rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("open"));
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to dispatch the open event");
     }
     UpdateMustKeepAlive();
     return;
   }
 
   if (aNewReadyState == nsIWebSocket::CLOSING) {
-    NS_ASSERTION((mReadyState == nsIWebSocket::CONNECTING) ||
-                 (mReadyState == nsIWebSocket::OPEN),
-                 "unexpected readyState transition");
+    NS_ABORT_IF_FALSE((mReadyState == nsIWebSocket::CONNECTING) ||
+                      (mReadyState == nsIWebSocket::OPEN),
+                      "unexpected readyState transition");
     mReadyState = aNewReadyState;
     return;
   }
 
   if (aNewReadyState == nsIWebSocket::CLOSED) {
-    NS_ASSERTION(mReadyState == nsIWebSocket::CLOSING,
-                 "unexpected readyState transition");
     mReadyState = aNewReadyState;
 
-    // The close event must be dispatched asynchronously.
-    nsCOMPtr<nsIRunnable> event =
-      new nsWSCloseEvent(this, mConnection->ClosedCleanly());
+    if (mConnection) {
+      // The close event must be dispatched asynchronously.
+      nsCOMPtr<nsIRunnable> event =
+        new nsWSCloseEvent(this, mConnection->ClosedCleanly());
+      mOutgoingBufferedAmount += mConnection->GetOutgoingBufferedAmount();
+      mConnection = nsnull; // this is no longer necessary
 
-    mOutgoingBufferedAmount += mConnection->GetOutgoingBufferedAmount();
-    mConnection = nsnull; // this is no longer necessary
-
-    rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
-    if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to dispatch the close event");
-      mTriggeredCloseEvent = PR_TRUE;
-      UpdateMustKeepAlive();
+      rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
+      if (NS_FAILED(rv)) {
+        NS_WARNING("Failed to dispatch the close event");
+        mTriggeredCloseEvent = PR_TRUE;
+        UpdateMustKeepAlive();
+      }
     }
   }
 }
 
 nsresult
 nsWebSocket::ParseURL(const nsString& aURL)
 {
   nsresult rv;
@@ -3255,19 +991,19 @@ nsWebSocket::ParseURL(const nsString& aU
      mPort = (port == -1) ? DEFAULT_WS_SCHEME_PORT : port;
   } else if (scheme.LowerCaseEqualsLiteral("wss")) {
     mSecure = PR_TRUE;
     mPort = (port == -1) ? DEFAULT_WSS_SCHEME_PORT : port;
   } else {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
-  mOrigin = origin;
-  ToLowerCase(mOrigin);
-
+  ToLowerCase(origin);
+  CopyUTF8toUTF16(origin, mUTF16Origin);
+    
   mAsciiHost = host;
   ToLowerCase(mAsciiHost);
 
   mResource = filePath;
   if (!query.IsEmpty()) {
     mResource.AppendLiteral("?");
     mResource.Append(query);
   }
@@ -3276,19 +1012,17 @@ nsWebSocket::ParseURL(const nsString& aU
   for (i = 0; i < length; ++i) {
     if (mResource[i] < static_cast<PRUnichar>(0x0021) ||
         mResource[i] > static_cast<PRUnichar>(0x007E)) {
       return NS_ERROR_DOM_SYNTAX_ERR;
     }
   }
 
   mOriginalURL = aURL;
-
   mURI = parsedURL;
-
   return NS_OK;
 }
 
 nsresult
 nsWebSocket::SetProtocol(const nsString& aProtocol)
 {
   if (aProtocol.IsEmpty()) {
     return NS_ERROR_DOM_SYNTAX_ERR;
@@ -3312,16 +1046,17 @@ nsWebSocket::SetProtocol(const nsString&
 //   1. the object has registered event listeners that can be triggered
 //      ("strong event listeners");
 //   2. there are outgoing not sent messages.
 //-----------------------------------------------------------------------------
 
 void
 nsWebSocket::UpdateMustKeepAlive()
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   if (!mCheckMustKeepAlive) {
     return;
   }
 
   PRBool shouldKeepAlive = PR_FALSE;
 
   if (mListenerManager) {
     switch (mReadyState)
@@ -3363,58 +1098,62 @@ nsWebSocket::UpdateMustKeepAlive()
     mKeepingAlive = PR_TRUE;
     static_cast<nsPIDOMEventTarget*>(this)->AddRef();
   }
 }
 
 void
 nsWebSocket::DontKeepAliveAnyMore()
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   if (mKeepingAlive) {
     mKeepingAlive = PR_FALSE;
     static_cast<nsPIDOMEventTarget*>(this)->Release();
   }
   mCheckMustKeepAlive = PR_FALSE;
 }
 
 NS_IMETHODIMP
 nsWebSocket::AddEventListener(const nsAString& aType,
                               nsIDOMEventListener* aListener,
                               PRBool aUseCapture)
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsresult rv = nsDOMEventTargetHelper::AddEventListener(aType,
                                                          aListener,
                                                          aUseCapture);
   if (NS_SUCCEEDED(rv)) {
     UpdateMustKeepAlive();
   }
   return rv;
 }
 
 NS_IMETHODIMP
 nsWebSocket::RemoveEventListener(const nsAString& aType,
                                  nsIDOMEventListener* aListener,
                                  PRBool aUseCapture)
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsresult rv = nsDOMEventTargetHelper::RemoveEventListener(aType,
                                                             aListener,
                                                             aUseCapture);
   if (NS_SUCCEEDED(rv)) {
     UpdateMustKeepAlive();
   }
   return rv;
 }
 
 NS_IMETHODIMP
 nsWebSocket::AddEventListener(const nsAString& aType,
                               nsIDOMEventListener *aListener,
                               PRBool aUseCapture,
                               PRBool aWantsUntrusted,
                               PRUint8 optional_argc)
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsresult rv = nsDOMEventTargetHelper::AddEventListener(aType,
                                                          aListener,
                                                          aUseCapture,
                                                          aWantsUntrusted,
                                                          optional_argc);
   if (NS_SUCCEEDED(rv)) {
     UpdateMustKeepAlive();
   }
@@ -3428,16 +1167,23 @@ nsWebSocket::AddEventListener(const nsAS
 NS_IMETHODIMP
 nsWebSocket::GetUrl(nsAString& aURL)
 {
   aURL = mOriginalURL;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsWebSocket::GetProtocol(nsAString& aProtocol)
+{
+  CopyUTF8toUTF16(mProtocol, aProtocol);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsWebSocket::GetReadyState(PRUint16 *aReadyState)
 {
   *aReadyState = mReadyState;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebSocket::GetBufferedAmount(PRUint32 *aBufferedAmount)
@@ -3467,16 +1213,17 @@ nsWebSocket::GetBufferedAmount(PRUint32 
 NS_WEBSOCKET_IMPL_DOMEVENTLISTENER(open, mOnOpenListener)
 NS_WEBSOCKET_IMPL_DOMEVENTLISTENER(error, mOnErrorListener)
 NS_WEBSOCKET_IMPL_DOMEVENTLISTENER(message, mOnMessageListener)
 NS_WEBSOCKET_IMPL_DOMEVENTLISTENER(close, mOnCloseListener)
 
 NS_IMETHODIMP
 nsWebSocket::Send(const nsAString& aData, PRBool *aRet)
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   *aRet = PR_FALSE;
 
   if (mReadyState == nsIWebSocket::CONNECTING) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   // We need to check if there isn't unpaired surrogates.
   PRUint32 i, length = aData.Length();
@@ -3503,16 +1250,17 @@ nsWebSocket::Send(const nsAString& aData
   *aRet = NS_SUCCEEDED(rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebSocket::Close()
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   if (mReadyState == nsIWebSocket::CLOSING ||
       mReadyState == nsIWebSocket::CLOSED) {
     return NS_OK;
   }
 
   if (mReadyState == nsIWebSocket::CONNECTING) {
     // FailConnection() can release the object, so we keep a reference
     // before calling it
@@ -3533,16 +1281,17 @@ nsWebSocket::Close()
  */
 NS_IMETHODIMP
 nsWebSocket::Init(nsIPrincipal* aPrincipal,
                   nsIScriptContext* aScriptContext,
                   nsPIDOMWindow* aOwnerWindow,
                   const nsAString& aURL,
                   const nsAString& aProtocol)
 {
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsresult rv;
 
   NS_ENSURE_ARG(aPrincipal);
 
   if (!PrefEnabled()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
@@ -3588,119 +1337,98 @@ nsWebSocket::Init(nsIPrincipal* aPrincip
 
   // the constructor should throw a SYNTAX_ERROR only if it fails to parse the
   // url parameter, so we don't care about the EstablishConnection result.
   EstablishConnection();
 
   return NS_OK;
 }
 
-// static
-void
-nsWebSocket::ReleaseGlobals()
+//-----------------------------------------------------------------------------
+// nsWebSocketEstablishedConnection::nsIRequest
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+nsWebSocketEstablishedConnection::GetName(nsACString &aName)
 {
-  if (nsWebSocketEstablishedConnection::sWSsConnecting) {
-    nsWebSocketEstablishedConnection::sWSsConnecting->Clear();
-    delete nsWebSocketEstablishedConnection::sWSsConnecting;
-    nsWebSocketEstablishedConnection::sWSsConnecting = nsnull;
-  }
-  if (gWebSocketThread) {
-    gWebSocketThread->Shutdown();
-    NS_RELEASE(gWebSocketThread);
-  }
+  if (!mOwner)
+    return NS_ERROR_UNEXPECTED;
+  
+  CopyUTF16toUTF8(mOwner->mOriginalURL, aName);
+  return NS_OK;
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// nsWSProtocolHandler
-////////////////////////////////////////////////////////////////////////////////
-
-NS_IMPL_ISUPPORTS2(nsWSProtocolHandler,
-                   nsIProtocolHandler, nsIProxiedProtocolHandler)
-
 NS_IMETHODIMP
-nsWSProtocolHandler::GetScheme(nsACString& aScheme)
+nsWebSocketEstablishedConnection::IsPending(PRBool *aValue)
 {
-  aScheme.AssignLiteral("ws");
+  *aValue = !!(mOwner);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsWSProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort)
+nsWebSocketEstablishedConnection::GetStatus(nsresult *aStatus)
 {
-  *aDefaultPort = DEFAULT_WS_SCHEME_PORT;
+  *aStatus = NS_OK;
   return NS_OK;
 }
 
+// probably means window went away or stop button pressed
 NS_IMETHODIMP
-nsWSProtocolHandler::GetProtocolFlags(PRUint32 *aProtocolFlags)
+nsWebSocketEstablishedConnection::Cancel(nsresult aStatus)
 {
-  *aProtocolFlags = URI_STD | URI_NON_PERSISTABLE | URI_DOES_NOT_RETURN_DATA |
-                    ALLOWS_PROXY | ALLOWS_PROXY_HTTP | URI_DANGEROUS_TO_LOAD;
-  return NS_OK;
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+
+  if (!mOwner) {
+    return NS_OK;
+  }
+
+  ConsoleError();
+  return Close();
 }
 
 NS_IMETHODIMP
-nsWSProtocolHandler::NewURI(const nsACString& aSpec,
-                            const char *aCharset,
-                            nsIURI *aBaseURI,
-                            nsIURI **aURI)
+nsWebSocketEstablishedConnection::Suspend()
 {
-  nsresult rv;
-  nsCOMPtr<nsIStandardURL> url(do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv));
-  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsWebSocketEstablishedConnection::Resume()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
 
-  PRInt32 defaultPort;
-  GetDefaultPort(&defaultPort);
+NS_IMETHODIMP
+nsWebSocketEstablishedConnection::GetLoadGroup(nsILoadGroup **aLoadGroup)
+{
+  *aLoadGroup = nsnull;
+  if (!mOwner)
+    return NS_OK;
 
-  rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY,
-                 defaultPort, aSpec, aCharset, aBaseURI);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIDocument> doc =
+    nsContentUtils::GetDocumentFromScriptContext(mOwner->mScriptContext);
 
-  rv = CallQueryInterface(url, aURI);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (doc) {
+    *aLoadGroup = doc->GetDocumentLoadGroup().get();  // already_AddRefed
+  }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsWSProtocolHandler::NewChannel(nsIURI *aURI,
-                                nsIChannel **aChannel)
+nsWebSocketEstablishedConnection::SetLoadGroup(nsILoadGroup *aLoadGroup)
 {
-  return NS_ERROR_NOT_AVAILABLE;
-}
-
-NS_IMETHODIMP
-nsWSProtocolHandler::NewProxiedChannel(nsIURI *aURI,
-                                       nsIProxyInfo* aProxyInfo,
-                                       nsIChannel **aChannel)
-{
-  return NS_ERROR_NOT_AVAILABLE;
+  return NS_ERROR_UNEXPECTED;
 }
 
 NS_IMETHODIMP
-nsWSProtocolHandler::AllowPort(PRInt32 aPort,
-                               const char *aScheme,
-                               PRBool *aAllowPort)
+nsWebSocketEstablishedConnection::GetLoadFlags(nsLoadFlags *aLoadFlags)
 {
-  PRInt32 defaultPort;
-  GetDefaultPort(&defaultPort);
-
-  *aAllowPort = (aPort == defaultPort);
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsWSSProtocolHandler
-////////////////////////////////////////////////////////////////////////////////
-
-NS_IMETHODIMP
-nsWSSProtocolHandler::GetScheme(nsACString& aScheme)
-{
-  aScheme.AssignLiteral("wss");
+  *aLoadFlags = nsIRequest::LOAD_BACKGROUND;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsWSSProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort)
+nsWebSocketEstablishedConnection::SetLoadFlags(nsLoadFlags aLoadFlags)
 {
-  *aDefaultPort = DEFAULT_WSS_SCHEME_PORT;
+  // we won't change the load flags at all.
   return NS_OK;
 }
--- a/content/base/src/nsWebSocket.h
+++ b/content/base/src/nsWebSocket.h
@@ -45,17 +45,16 @@
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsIJSNativeInitializer.h"
 #include "nsIPrincipal.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIDOMEventListener.h"
 #include "nsDOMEventTargetWrapperCache.h"
 #include "nsAutoPtr.h"
-#include "nsIProxiedProtocolHandler.h"
 
 #define DEFAULT_WS_SCHEME_PORT  80
 #define DEFAULT_WSS_SCHEME_PORT 443
 
 #define NS_WEBSOCKET_CID                            \
  { /* 7ca25214-98dc-40a6-bc1f-41ddbe41f46c */       \
   0x7ca25214, 0x98dc, 0x40a6,                       \
  {0xbc, 0x1f, 0x41, 0xdd, 0xbe, 0x41, 0xf4, 0x6c} }
@@ -96,32 +95,30 @@ public:
 
   // nsIDOMNSEventTarget
   NS_IMETHOD AddEventListener(const nsAString& aType,
                               nsIDOMEventListener *aListener,
                               PRBool aUseCapture,
                               PRBool aWantsUntrusted,
                               PRUint8 optional_argc);
 
-  static void ReleaseGlobals();
-
   // Determine if preferences allow WebSocket
   static PRBool PrefEnabled();
 
   const PRUint64 WindowID() const { return mWindowID; }
   const nsCString& GetScriptFile() const { return mScriptFile; }
   const PRUint32 GetScriptLine() const { return mScriptLine; }
 
 protected:
   nsresult ParseURL(const nsString& aURL);
   nsresult SetProtocol(const nsString& aProtocol);
   nsresult EstablishConnection();
 
   nsresult CreateAndDispatchSimpleEvent(const nsString& aName);
-  nsresult CreateAndDispatchMessageEvent(nsCString *aData);
+  nsresult CreateAndDispatchMessageEvent(const nsACString& aData);
   nsresult CreateAndDispatchCloseEvent(PRBool aWasClean);
 
   // called from mConnection accordingly to the situation
   void SetReadyState(PRUint16 aNewReadyState);
 
   // if there are "strong event listeners" (see comment in nsWebSocket.cpp) or
   // outgoing not sent messages then this method keeps the object alive
   // when js doesn't have strong references to it.
@@ -142,17 +139,18 @@ protected:
 
   PRPackedBool mKeepingAlive;
   PRPackedBool mCheckMustKeepAlive;
   PRPackedBool mTriggeredCloseEvent;
 
   nsCString mAsciiHost;  // hostname
   PRUint32  mPort;
   nsCString mResource; // [filepath[?query]]
-  nsCString mOrigin;
+  nsString  mUTF16Origin;
+  
   nsCOMPtr<nsIURI> mURI;
   nsCString mProtocol;
 
   PRUint16 mReadyState;
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
 
   nsRefPtr<nsWebSocketEstablishedConnection> mConnection;
@@ -170,49 +168,9 @@ protected:
   PRUint32 mScriptLine;
   PRUint64 mWindowID;
 
 private:
   nsWebSocket(const nsWebSocket& x);   // prevent bad usage
   nsWebSocket& operator=(const nsWebSocket& x);
 };
 
-#define NS_WSPROTOCOLHANDLER_CONTRACTID \
-    NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ws"
-
-#define NS_WSSPROTOCOLHANDLER_CONTRACTID \
-    NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "wss"
-
-#define NS_WSPROTOCOLHANDLER_CID                     \
-{ /* a4e6aa3b-b6db-4809-aa11-e292e074cbc4 */         \
-    0xa4e6aa3b,                                      \
-    0xb6db,                                          \
-    0x4809,                                          \
-    {0xaa, 0x11, 0xe2, 0x92, 0xe0, 0x74, 0xcb, 0xc4} \
-}
-
-#define NS_WSSPROTOCOLHANDLER_CID                    \
-{ /* c6531804-b5c8-4a53-80bf-e339b82d3161 */         \
-    0xc6531804,                                      \
-    0xb5c8,                                          \
-    0x4a53,                                          \
-    {0x80, 0xbf, 0xe3, 0x39, 0xb8, 0x2d, 0x31, 0x61} \
-}
-
-class nsWSProtocolHandler: public nsIProxiedProtocolHandler
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIPROTOCOLHANDLER
-  NS_DECL_NSIPROXIEDPROTOCOLHANDLER
-
-  nsWSProtocolHandler() {};
-};
-
-class nsWSSProtocolHandler: public nsWSProtocolHandler
-{
-public:
-  NS_IMETHOD GetScheme(nsACString & aScheme);
-  NS_IMETHOD GetDefaultPort(PRInt32 *aDefaultPort);
-  nsWSSProtocolHandler() {};
-};
-
 #endif
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -476,16 +476,18 @@ include $(topsrcdir)/config/rules.mk
 		test_bug604592.html \
 		test_bug628938.html \
 		test_bug626262.html \
 		test_plugin_freezing.html \
 		test_bug638112.html \
 		bug638112-response.txt \
 		bug638112.sjs \
 		test_bug656283.html \
+		test_blobbuilder.html \
+		fileutils.js \
 		$(NULL)
 
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 windows,$(MOZ_WIDGET_TOOLKIT)))
 _TEST_FILES2 += 	test_copyimage.html \
 		$(NULL)
 endif
 
--- a/content/base/test/file_websocket_wsh.py
+++ b/content/base/test/file_websocket_wsh.py
@@ -1,16 +1,19 @@
 from mod_pywebsocket import msgutil
 
 import time
 import sys
 
 # see the list of tests in test_websocket.html
 
 def web_socket_do_extra_handshake(request):
+  # must set request.ws_protocol to the selected version from ws_requested_protocols
+  request.ws_protocol = request.ws_requested_protocols[0]
+
   if request.ws_protocol == "test 2.1":
     time.sleep(5)
     pass
   elif request.ws_protocol == "test 9":
     time.sleep(5)
     pass
   elif request.ws_protocol == "test 10":
     time.sleep(5)
@@ -37,16 +40,17 @@ def web_socket_transfer_data(request):
     resp = "wrong message"
     if msgutil.receive_message(request) == "3":
       resp = "4"
     msgutil.send_message(request, resp.decode('utf-8'))
     resp = "wrong message"
     if msgutil.receive_message(request) == "5":
       resp = "あいうえお"
     msgutil.send_message(request, resp.decode('utf-8'))
+    msgutil.close_connection(request)
   elif request.ws_protocol == "test 7":
     try:
       while not request.client_terminated:
         msgutil.receive_message(request)
     except msgutil.ConnectionTerminatedException, e:
       pass
     msgutil.send_message(request, "server data")
     msgutil.send_message(request, "server data")
@@ -57,24 +61,27 @@ def web_socket_transfer_data(request):
     msgutil.close_connection(request, True)
   elif request.ws_protocol == "test 10":
     msgutil.close_connection(request)
   elif request.ws_protocol == "test 11":
     resp = "wrong message"
     if msgutil.receive_message(request) == "client data":
       resp = "server data"
     msgutil.send_message(request, resp.decode('utf-8'))
+    msgutil.close_connection(request)
+  elif request.ws_protocol == "test 12":
+    msgutil.close_connection(request)
   elif request.ws_protocol == "test 13":
     # first one binary message containing the byte 0x61 ('a')
     request.connection.write('\xff\x01\x61')
     # after a bad utf8 message
     request.connection.write('\x01\x61\xff')
     msgutil.close_connection(request)
   elif request.ws_protocol == "test 14":
-    request.connection.write('\xff\x00')
+    msgutil.close_connection(request)
     msgutil.send_message(request, "server data")
   elif request.ws_protocol == "test 15":
     msgutil.close_connection(request, True)
     return
   elif request.ws_protocol == "test 17" or request.ws_protocol == "test 21":
     time.sleep(5)
     resp = "wrong message"
     if msgutil.receive_message(request) == "client data":
--- a/content/base/test/file_ws_basic_tests_wsh.py
+++ b/content/base/test/file_ws_basic_tests_wsh.py
@@ -1,11 +1,14 @@
 from mod_pywebsocket import msgutil
 
 def web_socket_do_extra_handshake(request):
+  # must set request.ws_protocol to the selected version from ws_requested_protocols
+  request.ws_protocol = request.ws_requested_protocols[0]
+
   if (request.ws_protocol == 'error'):
       raise ValueError('Error')
   pass
 
 def web_socket_transfer_data(request):
   while True:
     line = msgutil.receive_message(request)
     if line == 'protocol':
new file mode 100644
--- /dev/null
+++ b/content/base/test/fileutils.js
@@ -0,0 +1,272 @@
+// Utility functions
+var testRanCounter = 0;
+var expectedTestCount = 0;
+
+function testHasRun() {
+ //alert(testRanCounter);
+ ++testRanCounter;
+ if (testRanCounter == expectedTestCount) {
+    SimpleTest.finish();
+  }
+}
+
+
+function testFile(file, contents, test) {
+  SimpleTest.requestLongerTimeout(2);
+
+  // Load file using FileReader
+  var r = new FileReader();
+  r.onload = getFileReaderLoadHandler(contents, contents.length, "FileReader.readAsBinaryString of " + test);
+  r.readAsBinaryString(file);
+  expectedTestCount++;
+
+  // Load file using URL.createObjectURL and XMLHttpRequest
+  var xhr = new XMLHttpRequest;
+  xhr.open("GET", URL.createObjectURL(file));
+  xhr.onload = getXHRLoadHandler(contents, contents.length, false,
+                                 "XMLHttpRequest load of " + test);
+  xhr.overrideMimeType('text/plain; charset=x-user-defined');
+  xhr.send();
+  expectedTestCount++;
+
+  // Send file to server using FormData and XMLHttpRequest
+  xhr = new XMLHttpRequest();
+  xhr.onload = function(event) {
+    checkMPSubmission(JSON.parse(event.target.responseText),
+                      [{ name: "hello", value: "world"},
+                       { name: "myfile",
+                         value: contents,
+                         fileName: file.name || "",
+                         contentType: file.type || "application/octet-stream" }]);
+    testHasRun();
+  }
+  xhr.open("POST", "../../html/content/test/form_submit_server.sjs");
+  var fd = new FormData;
+  fd.append("hello", "world");
+  fd.append("myfile", file);
+  xhr.send(fd);
+  expectedTestCount++;
+
+  // Send file to server using plain XMLHttpRequest
+  var xhr = new XMLHttpRequest;
+  xhr.open("POST", "file_XHRSendData.sjs");
+  xhr.onload = function (event) {
+    is(event.target.getResponseHeader("Result-Content-Type"),
+       file.type ? file.type : null,
+       "request content-type in XMLHttpRequest send of " + test);
+    is(event.target.getResponseHeader("Result-Content-Length"),
+       file.size,
+       "request content-length in XMLHttpRequest send of " + test);
+  };
+  xhr.addEventListener("load",
+                       getXHRLoadHandler(contents, contents.length, true,
+                                         "XMLHttpRequest send of " + test),
+                       false);
+  xhr.overrideMimeType('text/plain; charset=x-user-defined');
+  xhr.send(file);
+  expectedTestCount++;
+}
+
+function getFileReaderLoadHandler(expectedResult, expectedLength, testName) {
+  return function (event) {
+    is(event.target.readyState, FileReader.DONE,
+       "[FileReader] readyState in test " + testName);
+    is(event.target.error, null,
+       "[FileReader] no error in test " + testName);
+    // Do not use |is(event.target.result, expectedResult, "...");| that may output raw binary data.
+    is(event.target.result.length, expectedResult.length,
+       "[FileReader] Length of result in test " + testName);
+    ok(event.target.result == expectedResult,
+       "[FileReader] Content of result in test " + testName);
+    is(event.lengthComputable, true,
+       "[FileReader] lengthComputable in test " + testName);
+    is(event.loaded, expectedLength,
+       "[FileReader] Loaded length in test " + testName);
+    is(event.total, expectedLength,
+       "[FileReader] Total length in test " + testName);
+    testHasRun();
+  }
+}
+
+function getXHRLoadHandler(expectedResult, expectedLength, statusWorking, testName) {
+  return function (event) {
+    is(event.target.readyState, 4,
+       "[XHR] readyState in test " + testName);
+    if (statusWorking) {
+      is(event.target.status, 200,
+         "[XHR] no error in test " + testName);
+    }
+    else {
+      todo(event.target.status, 200,
+           "[XHR] no error in test " + testName);
+    }
+    // Do not use |is(convertXHRBinary(event.target.responseText), expectedResult, "...");| that may output raw binary data.
+    var convertedData = convertXHRBinary(event.target.responseText);
+    is(convertedData.length, expectedResult.length,
+       "[XHR] Length of result in test " + testName);
+    ok(convertedData == expectedResult,
+       "[XHR] Content of result in test " + testName);
+    is(event.lengthComputable, true,
+       "[XHR] lengthComputable in test " + testName);
+    is(event.loaded, expectedLength,
+       "[XHR] Loaded length in test " + testName);
+    is(event.total, expectedLength,
+       "[XHR] Total length in test " + testName);
+
+    testHasRun();
+  }
+}
+
+function convertXHRBinary(s) {
+  var res = "";
+  for (var i = 0; i < s.length; ++i) {
+    res += String.fromCharCode(s.charCodeAt(i) & 255);
+  }
+  return res;
+}
+
+function testHasRun() {
+ //alert(testRanCounter);
+ ++testRanCounter;
+ if (testRanCounter == expectedTestCount) {
+    SimpleTest.finish();
+  }
+}
+
+function createFileWithData(fileData) {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
+  var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
+  testFile.append("fileAPItestfile2-" + fileNum);
+  fileNum++;
+  var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
+  outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
+                 0666, 0);
+  outStream.write(fileData, fileData.length);
+  outStream.close();
+
+  var fileList = document.getElementById('fileList');
+  fileList.value = testFile.path;
+
+  return fileList.files[0];
+}
+
+function gc() {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+        .getInterface(Components.interfaces.nsIDOMWindowUtils)
+        .garbageCollect();
+}
+
+function checkMPSubmission(sub, expected) {
+  function getPropCount(o) {
+    var x, l = 0;
+    for (x in o) ++l;
+    return l;
+  }
+
+  is(sub.length, expected.length,
+     "Correct number of items");
+  var i;
+  for (i = 0; i < expected.length; ++i) {
+    if (!("fileName" in expected[i])) {
+      is(sub[i].headers["Content-Disposition"],
+         "form-data; name=\"" + expected[i].name + "\"",
+         "Correct name (A)");
+      is (getPropCount(sub[i].headers), 1,
+          "Wrong number of headers (A)");
+    }
+    else {
+      is(sub[i].headers["Content-Disposition"],
+         "form-data; name=\"" + expected[i].name + "\"; filename=\"" +
+           expected[i].fileName + "\"",
+         "Correct name (B)");
+      is(sub[i].headers["Content-Type"],
+         expected[i].contentType,
+         "Correct content type (B)");
+      is (getPropCount(sub[i].headers), 2,
+          "Wrong number of headers (B)");
+    }
+    // Do not use |is(sub[i].body, expected[i].value, "...");| that may output raw binary data.
+    is(sub[i].body.length, expected[i].value.length,
+       "Length of correct value");
+    ok(sub[i].body == expected[i].value,
+       "Content of correct value");
+  }
+}
+
+function testSlice(file, size, type, contents, fileType) {
+  is(file.type, type, fileType + " file is correct type");
+  is(file.size, size, fileType + " file is correct size");
+  ok(file instanceof File, fileType + " file is a File");
+  ok(file instanceof Blob, fileType + " file is also a Blob");
+  
+  var slice = file.mozSlice(0, size);
+  ok(slice instanceof Blob, fileType + " fullsize slice is a Blob");
+  ok(!(slice instanceof File), fileType + " fullsize slice is not a File");
+  
+  slice = file.mozSlice(0, 1234);
+  ok(slice instanceof Blob, fileType + " sized slice is a Blob");
+  ok(!(slice instanceof File), fileType + " sized slice is not a File");
+  
+  slice = file.mozSlice(0, size, "foo/bar");
+  is(slice.type, "foo/bar", fileType + " fullsize slice foo/bar type");
+
+  slice = file.mozSlice(0, 5432, "foo/bar");
+  is(slice.type, "foo/bar", fileType + " sized slice foo/bar type");
+  
+  is(slice.mozSlice(0, 10).type, "", fileType + " slice-slice type");
+  is(slice.mozSlice(0, 10).size, 10, fileType + " slice-slice size");
+  is(slice.mozSlice(0, 10, "hello/world").type, "hello/world", fileType + " slice-slice hello/world type");
+  is(slice.mozSlice(0, 10, "hello/world").size, 10, fileType + " slice-slice hello/world size");
+
+  var indexes = [[0, size, size],
+                 [0, 1234, 1234],
+                 [size-500, size, 500],
+                 [size-500, size+500, 500],
+                 [size+500, size+1500, 0],
+                 [0, 0, 0],
+                 [1000, 1000, 0],
+                 [size, size, 0],
+                 [0, undefined, size],
+                 [100, undefined, size-100],
+                 [-100, undefined, 100],
+                 [100, -100, size-200],
+                 [-size-100, undefined, size],
+                 [-2*size-100, 500, 500],
+                 [0, -size-100, 0],
+                 [100, -size-100, 0],
+                 [50, -size+100, 50],
+                 [0, 33000, 33000],
+                 [1000, 34000, 33000],
+                ];
+  
+  for (var i = 0; i < indexes.length; ++i) {
+    var sliceContents;
+    var testName;
+    if (indexes[i][1] == undefined) {
+      slice = file.mozSlice(indexes[i][0]);
+      sliceContents = contents.slice(indexes[i][0]);
+      testName = fileType + " slice(" + indexes[i][0] + ")";
+    }
+    else {
+      slice = file.mozSlice(indexes[i][0], indexes[i][1]);
+      sliceContents = contents.slice(indexes[i][0], indexes[i][1]);
+      testName = fileType + " slice(" + indexes[i][0] + ", " + indexes[i][1] + ")";
+    }
+    is(slice.type, "", testName + " type");
+    is(slice.size, indexes[i][2], testName + " size");
+    is(sliceContents.length, indexes[i][2], testName + " data size");
+    testFile(slice, sliceContents, testName);
+  }
+
+  // Slice of slice
+  var slice = file.mozSlice(0, 40000);
+  testFile(slice.mozSlice(5000, 42000), contents.slice(5000, 40000), "file slice slice");
+  
+  // ...of slice of slice
+  slice = slice.mozSlice(5000, 42000).mozSlice(400, 700);
+  SpecialPowers.gc();
+  testFile(slice, contents.slice(5400, 5700), "file slice slice slice");
+}
+
--- a/content/base/test/test_CrossSiteXHR_cache.html
+++ b/content/base/test/test_CrossSiteXHR_cache.html
@@ -414,16 +414,25 @@ function runTest() {
              method: "GET",
              noOrigin: 1,
            },
            { pass: 0,
              method: "DELETE"
            },
            ];
 
+  for (let i = 0; i < 110; i++) {
+    tests.push({ newTest: "*******" },
+               { pass: 1,
+                 method: "DELETE",
+                 allowMethods: "DELETE",
+                 cacheTime: 3600,
+               });
+  }
+
   baseURL = "http://mochi.test:8888/tests/content/base/test/" +
              "file_CrossSiteXHR_cache_server.sjs?";
   setStateURL = baseURL + "setState=";
 
   var unique = Date.now();
   for each (test in tests) {
     if (test.newTest) {
       unique++;
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_blobbuilder.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=648997
+-->
+<head>
+  <title>Test for Bug 648997</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="fileutils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=648997">Mozilla Bug 648997</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript;version=1.7">
+
+// We're prefixing still
+window.BlobBuilder = window.MozBlobBuilder;
+
+/** Test for Bug 648997 **/
+var blobBuilder = BlobBuilder();
+ok(blobBuilder, "BlobBuilder should exist");
+
+ok(blobBuilder.append, "BlobBuilder should have an append method");
+ok(blobBuilder.getBlob, "BlobBuilder should have a getBlob method");
+
+try {
+blobBuilder.append();
+ok(false, "NOT REACHED");
+} catch(e) {
+ok(true, "an empty argument to append should throw");
+}
+
+blobBuilder.append("squiggle");
+let blob1 = blobBuilder.getBlob();
+blobBuilder.append("ohai");
+let blob2 = blobBuilder.getBlob();
+
+let aB = new ArrayBuffer(16);
+var int8View = new Int8Array(aB);
+for (var i = 0; i < 16; i++) {
+  int8View[i] = i+65;
+}
+
+let testData = 
+ [
+    // Test 3 strings
+    [["foo", "bar", "baz"], [{start: 0, length: 9, contents: "foobarbaz"},
+                             {start: 0, length: 3, contents: "foo"},
+                             {start: 3, length:6, contents:  "barbaz"},
+                             {start: 6, length: 3, contents:  "baz"},
+                             {start: 6, length: 6, elength: 3, contents: "baz"},
+                             {start: 0, length: 9, contents:  "foobarbaz"},
+                             {start: 0, length: 11, elength: 9, contents: "foobarbaz"},
+                             {start: 10, length: 5, elength: 0, contents: ""}]],
+    // Test string, Blob, string
+    [["foo", blob1, "baz"], [{start: 0, length: 3, contents:  "foo"},
+                             {start: 3, length: 8, contents:  "squiggle"},
+                             {start: 2, length: 2, contents:  "os"},
+                             {start: 10, length: 2, contents: "eb"}]],
+    // Test blob, string, blob
+    [[blob1, "foo", blob1], [{start: 0, length: 8, contents:  "squiggle"},
+                             {start: 7, length: 2, contents:  "ef"},
+                             {start: 10, length: 2, contents: "os"},
+                             {start: 1, length: 3, contents:  "qui"},
+                             {start: 12, length: 3, contents: "qui"},
+                             {start: 40, length: 20, elength: 0, contents: ""}]],
+    // Test blobs all the way down
+    [[blob2, blob1, blob2], [{start: 0, length: 4, contents:  "ohai"},
+                             {start: 4, length: 8, contents:  "squiggle"},
+                             {start: 12, length: 4, contents: "ohai"},
+                             {start: 1, length: 2, contents:  "ha"},
+                             {start: 5, length: 4, contents:  "quig"}]],
+    // Test an array buffer
+    [[aB, blob1, "foo"],    [{start: 0, length: 8, contents:  "ABCDEFGH"},
+                             {start: 8, length:10, contents:  "IJKLMNOPsq"},
+                             {start: 17, length: 3, contents: "qui"},
+                             {start: 4, length: 8, contents:  "EFGHIJKL"}]],
+    // Test type coercion of a number
+    [[3, aB, "foo"],        [{start: 0, length: 8, contents:  "3ABCDEFG"},
+                             {start: 8, length:10, contents:  "HIJKLMNOPf"},
+                             {start: 17, length: 4, elength: 3, contents: "foo"},
+                             {start: 4, length: 8, contents:  "DEFGHIJK"}]]
+ ];
+
+let testCounter = 0;
+
+function doTest(data) {
+  testCounter++;
+
+  [blobs, tests] = data;
+
+  function runTest(test) {
+
+    let bb = new BlobBuilder();
+    ok(bb, "BlobBuilder should exist");
+
+    function doAppend(blob) {
+      bb.append(blob);
+	  blob.expando = bb; // Do we leak?
+    }
+
+    blobs.forEach(doAppend);
+    ok(true, "Test " + testCounter + " appended all successfully");
+    let blob = bb.getBlob();
+    ok(blob, "Test " + testCounter + " got blob");
+    ok(blob instanceof Blob, "Test " + testCounter + " blob is a Blob");
+    //ok(!(blob instanceof File), "Test " + testCounter + " blob is not a File");
+
+    let slice = blob.mozSlice(test.start, test.start + test.length);
+    ok(slice, "Test " + testCounter + " got slice");
+    ok(slice instanceof Blob, "Test " + testCounter + " slice is a Blob");
+    //ok(!(slice instanceof File), "Test " + testCounter + " slice is not a File");
+    is(slice.size,"elength" in test ? test.elength : test.length,
+       "Test " + testCounter + " slice is correct size");
+
+    testFile(slice, test.contents, "Test " + testCounter,
+             "elength" in test ? test.elength : test.length);
+  }
+  tests.forEach(runTest);
+  SpecialPowers.gc();
+}
+
+SimpleTest.waitForExplicitFinish();
+testData.forEach(doTest);
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/base/test/test_fileapi_slice.html
+++ b/content/base/test/test_fileapi_slice.html
@@ -2,34 +2,33 @@
 <html>
 <head>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=575946
 -->
   <title>Test for Bug 575946</title>
   <script type="text/javascript" src="/MochiKit/packed.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="fileutils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=575946">Mozilla Bug 575946</a>
 <p id="display">
   <canvas id=canvas width=1000 height=1000 hidden></canvas>
   <canvas id=testcanvas hidden></canvas>
   <input id="fileList" type="file"></input>
 </p>
 <div id="content" style="display: none">
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 var fileNum = 1;
-var testRanCounter = 0;
-var expectedTestCount = 0;
 SimpleTest.waitForExplicitFinish();
 
 // Create files containing data we'll test with. We'll want long
 // strings to ensure they span multiple buffers while loading
 
 // Create a decent-sized image
 cx = $("canvas").getContext('2d');
 var s = cx.canvas.width;
@@ -64,93 +63,18 @@ var size = fileData.length;
 
 // This might fail if we dramatically improve the png encoder. If that happens
 // please increase the complexity or size of the image generated above to ensure
 // that we're testing with files that are large enough.
 ok(size > 65536, "test data sufficiently large");
 
 
 // Test that basic properties work
-function testFile(file, size, type, contents, fileType) {
-  is(file.type, type, fileType + " file is correct type");
-  is(file.size, size, fileType + " file is correct size");
-  ok(file instanceof File, fileType + " file is a File");
-  ok(file instanceof Blob, fileType + " file is also a Blob");
-  
-  var slice = file.mozSlice(0, size);
-  ok(slice instanceof Blob, fileType + " fullsize slice is a Blob");
-  ok(!(slice instanceof File), fileType + " fullsize slice is not a File");
-  
-  slice = file.mozSlice(0, 1234);
-  ok(slice instanceof Blob, fileType + " sized slice is a Blob");
-  ok(!(slice instanceof File), fileType + " sized slice is not a File");
-  
-  slice = file.mozSlice(0, size, "foo/bar");
-  is(slice.type, "foo/bar", fileType + " fullsize slice foo/bar type");
-
-  slice = file.mozSlice(0, 5432, "foo/bar");
-  is(slice.type, "foo/bar", fileType + " sized slice foo/bar type");
-  
-  is(slice.mozSlice(0, 10).type, "", fileType + " slice-slice type");
-  is(slice.mozSlice(0, 10).size, 10, fileType + " slice-slice size");
-  is(slice.mozSlice(0, 10, "hello/world").type, "hello/world", fileType + " slice-slice hello/world type");
-  is(slice.mozSlice(0, 10, "hello/world").size, 10, fileType + " slice-slice hello/world size");
-
-  var indexes = [[0, size, size],
-                 [0, 1234, 1234],
-                 [size-500, size, 500],
-                 [size-500, size+500, 500],
-                 [size+500, size+1500, 0],
-                 [0, 0, 0],
-                 [1000, 1000, 0],
-                 [size, size, 0],
-                 [0, undefined, size],
-                 [100, undefined, size-100],
-                 [-100, undefined, 100],
-                 [100, -100, size-200],
-                 [-size-100, undefined, size],
-                 [-2*size-100, 500, 500],
-                 [0, -size-100, 0],
-                 [100, -size-100, 0],
-                 [50, -size+100, 50],
-                 [0, 33000, 33000],
-                 [1000, 34000, 33000],
-                ];
-  
-  for (var i = 0; i < indexes.length; ++i) {
-    var sliceContents;
-    var testName;
-    if (indexes[i][1] == undefined) {
-      slice = file.mozSlice(indexes[i][0]);
-      sliceContents = contents.slice(indexes[i][0]);
-      testName = fileType + " slice(" + indexes[i][0] + ")";
-    }
-    else {
-      slice = file.mozSlice(indexes[i][0], indexes[i][1]);
-      sliceContents = contents.slice(indexes[i][0], indexes[i][1]);
-      testName = fileType + " slice(" + indexes[i][0] + ", " + indexes[i][1] + ")";
-    }
-    is(slice.type, "", testName + " type");
-    is(slice.size, indexes[i][2], testName + " size");
-    is(sliceContents.length, indexes[i][2], testName + " data size");
-    checkFileContents(slice, sliceContents, testName);
-  }
-
-  // Slice of slice
-  var slice = file.mozSlice(0, 40000);
-  checkFileContents(slice.mozSlice(5000, 42000), contents.slice(5000, 40000), "file slice slice");
-  
-  // ...of slice of slice
-  slice = slice.mozSlice(5000, 42000).mozSlice(400, 700);
-  gc();
-  checkFileContents(slice, contents.slice(5400, 5700), "file slice slice slice");
-}
-
-testFile(memFile, size, "image/png", fileData, "memFile");
-testFile(fileFile, size, "", fileData, "fileFile");
+testSlice(memFile, size, "image/png", fileData, "memFile");
+testSlice(fileFile, size, "", fileData, "fileFile");
 
 
 // Try loading directly from slice into an image
 var testBinaryData = "";
 for (var i = 0; i < 256; i++) {
   testBinaryData += String.fromCharCode(i);
 }
 while (testBinaryData.length < 20000) {
@@ -204,197 +128,11 @@ expectedTestCount++;
 // image past end
 var imgfile = createFileWithData(testBinaryData + fileData);
 is(imgfile.size, size + testBinaryData.length, "correct file size (past end)");
 var img = new Image;
 img.src = URL.createObjectURL(imgfile.mozSlice(testBinaryData.length, testBinaryData.length + size + 1000));
 img.onload = imageLoadHandler;
 expectedTestCount++;
 
-
-// Utility functions
-function checkFileContents(file, contents, test) {
-  SimpleTest.requestLongerTimeout(2);
-
-  // Load file using FileReader
-  var r = new FileReader();
-  r.onload = getFileReaderLoadHandler(contents, contents.length, "FileReader.readAsBinaryString of " + test);
-  r.readAsBinaryString(file);
-  expectedTestCount++;
-
-  // Load file using URL.createObjectURL and XMLHttpRequest
-  var xhr = new XMLHttpRequest;
-  xhr.open("GET", URL.createObjectURL(file));
-  xhr.onload = getXHRLoadHandler(contents, contents.length, false,
-                                 "XMLHttpRequest load of " + test);
-  xhr.overrideMimeType('text/plain; charset=x-user-defined');
-  xhr.send();
-  expectedTestCount++;
-
-  // Send file to server using FormData and XMLHttpRequest
-  xhr = new XMLHttpRequest();
-  xhr.onload = function(event) {
-    checkMPSubmission(JSON.parse(event.target.responseText),
-                      [{ name: "hello", value: "world"},
-                       { name: "myfile",
-                         value: contents,
-                         fileName: file.name || "",
-                         contentType: file.type || "application/octet-stream" }]);
-    testHasRun();
-  }
-  xhr.open("POST", "../../html/content/test/form_submit_server.sjs");
-  var fd = new FormData;
-  fd.append("hello", "world");
-  fd.append("myfile", file);
-  xhr.send(fd);
-  expectedTestCount++;
-
-  // Send file to server using plain XMLHttpRequest
-  var xhr = new XMLHttpRequest;
-  xhr.open("POST", "file_XHRSendData.sjs");
-  xhr.onload = function (event) {
-    is(event.target.getResponseHeader("Result-Content-Type"),
-       file.type ? file.type : null,
-       "request content-type in XMLHttpRequest send of " + test);
-    is(event.target.getResponseHeader("Result-Content-Length"),
-       file.size,
-       "request content-length in XMLHttpRequest send of " + test);
-  };
-  xhr.addEventListener("load",
-                       getXHRLoadHandler(contents, contents.length, true,
-                                         "XMLHttpRequest send of " + test),
-                       false);
-  xhr.overrideMimeType('text/plain; charset=x-user-defined');
-  xhr.send(file);
-  expectedTestCount++;
-}
-
-function getFileReaderLoadHandler(expectedResult, expectedLength, testName) {
-  return function (event) {
-    is(event.target.readyState, FileReader.DONE,
-       "[FileReader] readyState in test " + testName);
-    is(event.target.error, null,
-       "[FileReader] no error in test " + testName);
-    // Do not use |is(event.target.result, expectedResult, "...");| that may output raw binary data.
-    is(event.target.result.length, expectedResult.length,
-       "[FileReader] Length of result in test " + testName);
-    ok(event.target.result == expectedResult,
-       "[FileReader] Content of result in test " + testName);
-    is(event.lengthComputable, true,
-       "[FileReader] lengthComputable in test " + testName);
-    is(event.loaded, expectedLength,
-       "[FileReader] Loaded length in test " + testName);
-    is(event.total, expectedLength,
-       "[FileReader] Total length in test " + testName);
-    testHasRun();
-  }
-}
-
-function getXHRLoadHandler(expectedResult, expectedLength, statusWorking, testName) {
-  return function (event) {
-    is(event.target.readyState, 4,
-       "[XHR] readyState in test " + testName);
-    if (statusWorking) {
-      is(event.target.status, 200,
-         "[XHR] no error in test " + testName);
-    }
-    else {
-      todo(event.target.status, 200,
-           "[XHR] no error in test " + testName);
-    }
-    // Do not use |is(convertXHRBinary(event.target.responseText), expectedResult, "...");| that may output raw binary data.
-    var convertedData = convertXHRBinary(event.target.responseText);
-    is(convertedData.length, expectedResult.length,
-       "[XHR] Length of result in test " + testName);
-    ok(convertedData == expectedResult,
-       "[XHR] Content of result in test " + testName);
-    is(event.lengthComputable, true,
-       "[XHR] lengthComputable in test " + testName);
-    is(event.loaded, expectedLength,
-       "[XHR] Loaded length in test " + testName);
-    is(event.total, expectedLength,
-       "[XHR] Total length in test " + testName);
-
-    testHasRun();
-  }
-}
-
-function convertXHRBinary(s) {
-  var res = "";
-  for (var i = 0; i < s.length; ++i) {
-    res += String.fromCharCode(s.charCodeAt(i) & 255);
-  }
-  return res;
-}
-
-function testHasRun() {
- //alert(testRanCounter);
- ++testRanCounter;
- if (testRanCounter == expectedTestCount) {
-    SimpleTest.finish();
-  }
-}
-
-function createFileWithData(fileData) {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
-  var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
-  testFile.append("fileAPItestfile2-" + fileNum);
-  fileNum++;
-  var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
-  outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
-                 0666, 0);
-  outStream.write(fileData, fileData.length);
-  outStream.close();
-
-  var fileList = document.getElementById('fileList');
-  fileList.value = testFile.path;
-
-  return fileList.files[0];
-}
-
-function gc() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-        .getInterface(Components.interfaces.nsIDOMWindowUtils)
-        .garbageCollect();
-}
-
-function checkMPSubmission(sub, expected) {
-  function getPropCount(o) {
-    var x, l = 0;
-    for (x in o) ++l;
-    return l;
-  }
-
-  is(sub.length, expected.length,
-     "Correct number of items");
-  var i;
-  for (i = 0; i < expected.length; ++i) {
-    if (!("fileName" in expected[i])) {
-      is(sub[i].headers["Content-Disposition"],
-         "form-data; name=\"" + expected[i].name + "\"",
-         "Correct name (A)");
-      is (getPropCount(sub[i].headers), 1,
-          "Wrong number of headers (A)");
-    }
-    else {
-      is(sub[i].headers["Content-Disposition"],
-         "form-data; name=\"" + expected[i].name + "\"; filename=\"" +
-           expected[i].fileName + "\"",
-         "Correct name (B)");
-      is(sub[i].headers["Content-Type"],
-         expected[i].contentType,
-         "Correct content type (B)");
-      is (getPropCount(sub[i].headers), 2,
-          "Wrong number of headers (B)");
-    }
-    // Do not use |is(sub[i].body, expected[i].value, "...");| that may output raw binary data.
-    is(sub[i].body.length, expected[i].value.length,
-       "Length of correct value");
-    ok(sub[i].body == expected[i].value,
-       "Content of correct value");
-  }
-}
-
 </script>
 </pre>
 </body> </html>
--- a/content/base/test/test_websocket.html
+++ b/content/base/test/test_websocket.html
@@ -46,17 +46,16 @@
  */
 
 var first_test = 1;
 var last_test = 22;
 
 var current_test = first_test;
 
 var timeoutToAbortTest = 60000;
-var timeoutToOpenWS = 25000;
 var all_ws = [];
 
 function shouldNotOpen(e)
 {
   var ws = e.target;
   ok(false, "onopen shouldn't be called on test " + ws._testNumber + "!");
 }
 
@@ -259,40 +258,49 @@ function test6()
   var counter = 1;
   ws.onopen = function()
   {
     ws.send(counter);
   }
   ws.onmessage = function(e)
   {
     if (counter == 5) {
-      ok(e.data == "あいうえお");
+      ok(e.data == "あいうえお", "test 6 counter 5 data ok");
       ws.close();
       doTest(7);
     } else {
       ok(e.data == counter+1, "bad counter");
       counter += 2;
       ws.send(counter);
     }
   }
   ws.onclose = shouldCloseCleanly;
 }
 
 function test7()
 {
-  var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 7");
-  ws.onopen = function()
-  {
-    ws.close();
-  }
-  ws.onclose = function(e)
-  {
-    shouldCloseNotCleanly(e);
-    doTest(8);
-  };
+// with pywebsockets for -06 ths test no longer does anything useful
+// as the server handles the receipt of the close event directly, not
+// as part of the wsh - so we cannot fake the non-clean close which is
+// what we're trying to do here.
+
+  ok(true, "test disabled");
+  current_test++;
+  doTest(8);
+
+//  var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 7");
+//  ws.onopen = function()
+//  {
+//    ws.close();
+//  }
+//  ws.onclose = function(e)
+//  {
+//    shouldCloseNotCleanly(e);
+//    doTest(8);
+//  };
 }
 
 function test8()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 8");
   ws.onopen = function()
   {
     ws.close();
@@ -333,31 +341,34 @@ function test10()
   {
     doTest(11);
   }
 }
 
 function test11()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 11");
-  ok(ws.readyState == 0, "bad readyState in test 11!");
+  ok(ws.readyState == 0, "create bad readyState in test 11!");
   ws.onopen = function()
   {
-    ok(ws.readyState == 1, "bad readyState in test 11!");
+    ok(ws.readyState == 1, "open bad readyState in test 11!");
     ws.send("client data");
   }
   ws.onmessage = function(e)
   {
     ok(e.data == "server data", "bad received message in test 11!");
     ws.close();
-    ok(ws.readyState == 2, "bad readyState in test 11!");
+
+// this ok() is disabled due to a race condition - it state may have
+// advanced through 2 (closing) and into 3 (closed) before it is evald
+//    ok(ws.readyState == 2, "onmessage bad readyState in test 11!");
   }
   ws.onclose = function(e)
   {
-    ok(ws.readyState == 3, "bad readyState in test 11!");
+    ok(ws.readyState == 3, "onclose bad readyState in test 11!");
     shouldCloseCleanly(e);
     doTest(12);
   }
 }
 
 function test12()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 12");
@@ -367,33 +378,44 @@ function test12()
       // send an unpaired surrogate
       ws.send(String.fromCharCode(0xD800));
       ok(false, "couldn't send an unpaired surrogate!");
     }
     catch (e) {
       ok(true, "couldn't send an unpaired surrogate!");
     }
     ws.close();
+
+// there isnt really a server implementation of test 12, so just
+// ignore an error
+    ws.onerror = function()
+    {
+    }
+
     doTest(13);
   };
 }
 
 function test13()
 {
+    // previous versions of this test counted the number of protocol errors returned, but the 
+    // protocol stack typically closes down after reporting a protocol level error - trying
+    // to resync is too dangerous
+
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 13");
   ws._timesCalledOnError = 0;
   ws.onerror = function()
   {
     ws._timesCalledOnError++;
-    if (ws._timesCalledOnError == 2) {
-      ok(true, "test 13 succeeded");
-      doTest(14);
-    }
   }
-  ws.onclose = shouldCloseCleanly;
+  ws.onclose = function(e)
+  {
+    ok(ws._timesCalledOnError > 0, "no error events");
+    doTest(14);
+  }
 }
 
 function test14()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 14");
   ws.onmessage = function()
   {
     ok(false, "shouldn't received message after the server sent the close frame");
@@ -408,32 +430,44 @@ function test14()
 function test15()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 15");
   ws.onclose = function(e)
   {
     shouldCloseNotCleanly(e);
     doTest(16);
   };
+
+  // termination of the connection might cause an error event if it happens in OPEN
+  ws.onerror = function()
+  {
+  }
+
 }
 
 function test16()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 16");
   ws.onopen = function()
   {
     ws.close();
     ok(!ws.send("client data"), "shouldn't send message after calling close()");
     doTest(17);
   }
   ws.onmessage = function()
   {
     ok(false, "shouldn't send message after calling close()");
   }
-  ws.onclose = shouldCloseCleanly;
+
+  ws.onerror = function()
+  {
+  }
+  ws.onclose = function()
+  {
+  }
 }
 
 var status_test17 = "not started";
 
 window._test17 = function()
 {
   var local_ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 17");
   local_ws._testNumber = "local17";
@@ -588,41 +622,29 @@ function test22()
   ws.onopen = shouldNotOpen;
   ws.onclose = function(e)
   {
     shouldCloseNotCleanly(e);
     doTest(23);
   };
 }
 
-var domBranch;
-var oldPrefVal;
-
 function finishWSTest()
 {
   for (i = 0; i < all_ws.length; ++i) {
     if (all_ws[i] != shouldNotReceiveCloseEvent &&
         !all_ws[i]._receivedCloseEvent) {
       ok(false, "didn't called close on test " + all_ws[i]._testNumber + "!");
     }
   }
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  domBranch.setBoolPref("override-security-block", oldPrefVal);
   SimpleTest.finish();
 }
 
 function testWebSocket ()
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var prefService =
-      Components.classes["@mozilla.org/preferences-service;1"]
-      .getService(Components.interfaces.nsIPrefService);
-  domBranch = prefService.getBranch("network.websocket.");
-  oldPrefVal = domBranch.getBoolPref("override-security-block");
-  domBranch.setBoolPref("override-security-block", true);
   doTest(first_test);
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 
--- a/content/base/test/test_websocket_hello.html
+++ b/content/base/test/test_websocket_hello.html
@@ -12,48 +12,32 @@
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=472529">Mozilla Bug </a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 var ws;
-var oldPrefVal;
-var domBranch;
-
-function finishWSTest() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    domBranch.setBoolPref("override-security-block", oldPrefVal);
-    SimpleTest.finish();
-}
 
 function testWebSocket () {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var prefService =
-      Components.classes["@mozilla.org/preferences-service;1"]
-      .getService(Components.interfaces.nsIPrefService);
-  domBranch = prefService.getBranch("network.websocket.");
-  oldPrefVal = domBranch.getBoolPref("override-security-block");
-  domBranch.setBoolPref("override-security-block", true);
-
   ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_websocket_hello");
   ws.onopen = function(e) {
     ws.send("data");
   }
   ws.onclose = function(e) {
   }
   ws.onerror = function(e) {
     ok(false, "onerror called!");
-    finishWSTest();
+    SimpleTest.finish();
   }
   ws.onmessage = function(e) {
     is(e.data, "Hello world!", "Wrong data");
     ws.close();
-    finishWSTest();
+    SimpleTest.finish();
   }
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 <div>
--- a/content/base/test/test_ws_basic_tests.html
+++ b/content/base/test/test_ws_basic_tests.html
@@ -12,45 +12,33 @@
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=472529">Mozilla Bug </a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 var ws;
-var oldPrefVal;
-var domBranch;
 
 var params = ["protocol", "resource", "origin", "end"];
 var results = ["test", "/tests/content/base/test/file_ws_basic_tests", "http://mochi.test:8888", "end"];
 
 function forcegc(){
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   Components.utils.forceGC();
   var wu =  window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                   .getInterface(Components.interfaces.nsIDOMWindowUtils);
   wu.garbageCollect();
 }
 
 function finishWSTest() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    domBranch.setBoolPref("override-security-block", oldPrefVal);
     SimpleTest.finish();
 }
 
 function testWebSocket () {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var prefService =
-      Components.classes["@mozilla.org/preferences-service;1"]
-      .getService(Components.interfaces.nsIPrefService);
-  domBranch = prefService.getBranch("network.websocket.");
-  oldPrefVal = domBranch.getBoolPref("override-security-block");
-  domBranch.setBoolPref("override-security-block", true);
-
   var url = "ws://mochi.test:8888/tests/content/base/test/file_ws_basic_tests";
   ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_ws_basic_tests", "test");
   is(ws.url, url, "Wrong Websocket.url!");
   ws.onopen = function(e) {
     for (var i = 0; i < params.length; ++i) {
       document.getElementById('log').textContent += "sending " + params[i] + "\n";
       ws.send(params[i]);
     }
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -122,16 +122,39 @@ WebGLContext::WebGLContext()
     mVertexAttrib0Vector[3] = 1;
     mFakeVertexAttrib0BufferObjectVector[0] = 0;
     mFakeVertexAttrib0BufferObjectVector[1] = 0;
     mFakeVertexAttrib0BufferObjectVector[2] = 0;
     mFakeVertexAttrib0BufferObjectVector[3] = 1;
     mFakeVertexAttrib0BufferObjectSize = 0;
     mFakeVertexAttrib0BufferObject = 0;
     mFakeVertexAttrib0BufferStatus = VertexAttrib0Status::Default;
+
+    // these are de default values, see 6.2 State tables in the OpenGL ES 2.0.25 spec
+    mColorWriteMask[0] = 1;
+    mColorWriteMask[1] = 1;
+    mColorWriteMask[2] = 1;
+    mColorWriteMask[3] = 1;
+    mDepthWriteMask = 1;
+    mColorClearValue[0] = 0.f;
+    mColorClearValue[1] = 0.f;
+    mColorClearValue[2] = 0.f;
+    mColorClearValue[3] = 0.f;
+    mDepthClearValue = 1.f;
+    mStencilClearValue = 0;
+    mStencilRefFront = 0;
+    mStencilRefBack = 0;
+    mStencilValueMaskFront = 0xffffffff;
+    mStencilValueMaskBack  = 0xffffffff;
+    mStencilWriteMaskFront = 0xffffffff;
+    mStencilWriteMaskBack  = 0xffffffff;
+
+    mScissorTestEnabled = 0;
+    mDitherEnabled = 1;
+    mBackbufferClearingStatus = BackbufferClearingStatus::NotClearedSinceLastPresented;
 }
 
 WebGLContext::~WebGLContext()
 {
     DestroyResourcesAndContext();
 }
 
 static PLDHashOperator
@@ -307,41 +330,34 @@ GetBoolFromPropertyBag(nsIPropertyBag *b
 NS_IMETHODIMP
 WebGLContext::SetContextOptions(nsIPropertyBag *aOptions)
 {
     if (!aOptions)
         return NS_OK;
 
     WebGLContextOptions newOpts;
 
-    // defaults are: yes: depth, alpha, premultipliedAlpha; no: stencil
-    if (!GetBoolFromPropertyBag(aOptions, "stencil", &newOpts.stencil))
-        newOpts.stencil = false;
-
-    if (!GetBoolFromPropertyBag(aOptions, "depth", &newOpts.depth))
-        newOpts.depth = true;
-
-    if (!GetBoolFromPropertyBag(aOptions, "alpha", &newOpts.alpha))
-        newOpts.alpha = true;
-
-    if (!GetBoolFromPropertyBag(aOptions, "premultipliedAlpha", &newOpts.premultipliedAlpha))
-        newOpts.premultipliedAlpha = true;
-
-    GetBoolFromPropertyBag(aOptions, "antialiasHint", &newOpts.antialiasHint);
+    GetBoolFromPropertyBag(aOptions, "stencil", &newOpts.stencil);
+    GetBoolFromPropertyBag(aOptions, "depth", &newOpts.depth);
+    GetBoolFromPropertyBag(aOptions, "alpha", &newOpts.alpha);
+    GetBoolFromPropertyBag(aOptions, "premultipliedAlpha", &newOpts.premultipliedAlpha);
+    GetBoolFromPropertyBag(aOptions, "antialias", &newOpts.antialias);
+    GetBoolFromPropertyBag(aOptions, "preserveDrawingBuffer", &newOpts.preserveDrawingBuffer);
 
     // enforce that if stencil is specified, we also give back depth
     newOpts.depth |= newOpts.stencil;
 
 #if 0
-    LogMessage("aaHint: %d stencil: %d depth: %d alpha: %d premult: %d\n",
-               newOpts.antialiasHint ? 1 : 0,
+    LogMessage("aaHint: %d stencil: %d depth: %d alpha: %d premult: %d preserve: %d\n",
+               newOpts.antialias ? 1 : 0,
                newOpts.stencil ? 1 : 0,
                newOpts.depth ? 1 : 0,
                newOpts.alpha ? 1 : 0,
-               newOpts.premultipliedAlpha ? 1 : 0);
+               newOpts.premultipliedAlpha ? 1 : 0,
+               newOpts.preserveDrawingBuffer ? 1 : 0);
 #endif
 
     if (mOptionsFrozen && newOpts != mOptions) {
         // Error if the options are already frozen, and the ones that were asked for
         // aren't the same as what they were originally.
         return NS_ERROR_FAILURE;
     }
 
@@ -698,16 +714,18 @@ WebGLContext::GetCanvasLayer(nsDisplayLi
 
     canvasLayer->Initialize(data);
     PRUint32 flags = gl->CreationFormat().alpha == 0 ? Layer::CONTENT_OPAQUE : 0;
     canvasLayer->SetContentFlags(flags);
     canvasLayer->Updated();
 
     mResetLayer = PR_FALSE;
 
+    mBackbufferClearingStatus = BackbufferClearingStatus::NotClearedSinceLastPresented;
+
     return canvasLayer.forget().get();
 }
 
 NS_IMETHODIMP
 WebGLContext::GetContextAttributes(jsval *aResult)
 {
     JSContext *cx = nsContentUtils::GetCurrentJSContext();
     if (!cx)
@@ -726,16 +744,19 @@ WebGLContext::GetContextAttributes(jsval
         !JS_DefineProperty(cx, obj, "depth", cf.depth > 0 ? JSVAL_TRUE : JSVAL_FALSE,
                            NULL, NULL, JSPROP_ENUMERATE) ||
         !JS_DefineProperty(cx, obj, "stencil", cf.stencil > 0 ? JSVAL_TRUE : JSVAL_FALSE,
                            NULL, NULL, JSPROP_ENUMERATE) ||
         !JS_DefineProperty(cx, obj, "antialias", JSVAL_FALSE,
                            NULL, NULL, JSPROP_ENUMERATE) ||
         !JS_DefineProperty(cx, obj, "premultipliedAlpha",
                            mOptions.premultipliedAlpha ? JSVAL_TRUE : JSVAL_FALSE,
+                           NULL, NULL, JSPROP_ENUMERATE) ||
+        !JS_DefineProperty(cx, obj, "preserveDrawingBuffer",
+                           mOptions.preserveDrawingBuffer ? JSVAL_TRUE : JSVAL_FALSE,
                            NULL, NULL, JSPROP_ENUMERATE))
     {
         *aResult = JSVAL_VOID;
         return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
 }
@@ -761,16 +782,132 @@ WebGLContext::MozGetUnderlyingParamStrin
 
     default:
         return NS_ERROR_INVALID_ARG;
     }
 
     return NS_OK;
 }
 
+NS_IMETHODIMP
+WebGLContext::GetExtension(const nsAString& aName, nsIWebGLExtension **retval)
+{
+    *retval = nsnull;
+
+    // handle simple extensions that don't need custom objects first
+    WebGLExtensionID ei = WebGLExtensionID_Max;
+    if (aName.EqualsLiteral("OES_texture_float")) {
+        MakeContextCurrent();
+
+        PRBool avail = gl->IsExtensionSupported(gl->IsGLES2() ? "GL_OES_texture_float" : "GL_ARB_texture_float");
+        if (avail)
+            ei = WebGL_OES_texture_float;
+    }
+
+    // create a WebGLExtension object for extensions that don't
+    // have any additional tokens or methods
+    if (ei != WebGLExtensionID_Max) {
+        if (!IsExtensionEnabled(ei)) {
+            mEnabledExtensions[ei] = new WebGLExtension(this);
+        }
+        NS_ADDREF(*retval = mEnabledExtensions[ei]);
+    }
+
+    return NS_OK;
+}
+
+void
+WebGLContext::ForceClearFramebufferWithDefaultValues(PRUint32 mask, const nsIntRect& viewportRect)
+{
+    MakeContextCurrent();
+
+    PRBool initializeColorBuffer = 0 != (mask & LOCAL_GL_COLOR_BUFFER_BIT);
+    PRBool initializeDepthBuffer = 0 != (mask & LOCAL_GL_DEPTH_BUFFER_BIT);
+    PRBool initializeStencilBuffer = 0 != (mask & LOCAL_GL_STENCIL_BUFFER_BIT);
+
+    // prepare GL state for clearing
+    gl->fDisable(LOCAL_GL_SCISSOR_TEST);
+    gl->fDisable(LOCAL_GL_DITHER);
+    gl->PushViewportRect(viewportRect);
+
+    if (initializeColorBuffer) {
+        gl->fColorMask(1, 1, 1, 1);
+        gl->fClearColor(0.f, 0.f, 0.f, 0.f);
+    }
+
+    if (initializeDepthBuffer) {
+        gl->fDepthMask(1);
+        gl->fClearDepth(1.0f);
+    }
+
+    if (initializeStencilBuffer) {
+        gl->fStencilMask(0xffffffff);
+        gl->fClearStencil(0);
+    }
+
+    // do clear
+    gl->fClear(mask);
+
+    // restore GL state after clearing
+    if (initializeColorBuffer) {
+        gl->fColorMask(mColorWriteMask[0],
+                       mColorWriteMask[1],
+                       mColorWriteMask[2],
+                       mColorWriteMask[3]);
+        gl->fClearColor(mColorClearValue[0],
+                        mColorClearValue[1],
+                        mColorClearValue[2],
+                        mColorClearValue[3]);
+    }
+
+    if (initializeDepthBuffer) {
+        gl->fDepthMask(mDepthWriteMask);
+        gl->fClearDepth(mDepthClearValue);
+    }
+
+    if (initializeStencilBuffer) {
+        gl->fStencilMaskSeparate(LOCAL_GL_FRONT, mStencilWriteMaskFront);
+        gl->fStencilMaskSeparate(LOCAL_GL_BACK, mStencilWriteMaskBack);
+        gl->fClearStencil(mStencilClearValue);
+    }
+
+    gl->PopViewportRect();
+
+    if (mDitherEnabled)
+        gl->fEnable(LOCAL_GL_DITHER);
+    else
+        gl->fDisable(LOCAL_GL_DITHER);
+
+    if (mScissorTestEnabled)
+        gl->fEnable(LOCAL_GL_SCISSOR_TEST);
+    else
+        gl->fDisable(LOCAL_GL_SCISSOR_TEST);
+}
+
+void
+WebGLContext::EnsureBackbufferClearedAsNeeded()
+{
+    if (mOptions.preserveDrawingBuffer)
+        return;
+
+    NS_ABORT_IF_FALSE(!mBoundFramebuffer,
+                      "EnsureBackbufferClearedAsNeeded must not be called when a FBO is bound");
+
+    if (mBackbufferClearingStatus != BackbufferClearingStatus::NotClearedSinceLastPresented)
+        return;
+
+    mBackbufferClearingStatus = BackbufferClearingStatus::ClearedToDefaultValues;
+
+    ForceClearFramebufferWithDefaultValues(LOCAL_GL_COLOR_BUFFER_BIT |
+                                           LOCAL_GL_DEPTH_BUFFER_BIT |
+                                           LOCAL_GL_STENCIL_BUFFER_BIT,
+                                           nsIntRect(0, 0, mWidth, mHeight));
+
+    Invalidate();
+}
 
 //
 // XPCOM goop
 //
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
 
@@ -896,16 +1033,28 @@ NS_IMETHODIMP base::SetName(WebGLuint aN
 
 NAME_NOT_SUPPORTED(WebGLTexture)
 NAME_NOT_SUPPORTED(WebGLBuffer)
 NAME_NOT_SUPPORTED(WebGLProgram)
 NAME_NOT_SUPPORTED(WebGLShader)
 NAME_NOT_SUPPORTED(WebGLFramebuffer)
 NAME_NOT_SUPPORTED(WebGLRenderbuffer)
 
+NS_IMPL_ADDREF(WebGLExtension)
+NS_IMPL_RELEASE(WebGLExtension)
+
+DOMCI_DATA(WebGLExtension, WebGLExtension)
+
+NS_INTERFACE_MAP_BEGIN(WebGLExtension)
+  NS_INTERFACE_MAP_ENTRY(WebGLExtension)
+  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtension)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtension)
+NS_INTERFACE_MAP_END
+
 /* [noscript] attribute WebGLint location; */
 NS_IMETHODIMP
 WebGLUniformLocation::GetLocation(WebGLint *aLocation)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
@@ -964,14 +1113,8 @@ WebGLContext::GetSupportedExtensions(nsI
 
 NS_IMETHODIMP
 WebGLContext::IsContextLost(WebGLboolean *retval)
 {
     *retval = PR_FALSE;
     return NS_OK;
 }
 
-NS_IMETHODIMP
-WebGLContext::GetExtension(const nsAString& aName, nsISupports **retval)
-{
-    *retval = nsnull;
-    return NS_OK;
-}
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -79,18 +79,23 @@ class WebGLZeroingObject;
 class WebGLContextBoundObject;
 
 enum FakeBlackStatus { DoNotNeedFakeBlack, DoNeedFakeBlack, DontKnowIfNeedFakeBlack };
 
 struct VertexAttrib0Status {
     enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };
 };
 
+struct BackbufferClearingStatus {
+    enum { NotClearedSinceLastPresented, ClearedToDefaultValues, HasBeenDrawnTo };
+};
+
 struct WebGLTexelFormat {
-    enum { Generic, Auto, RGBA8, RGB8, RGBX8, BGRA8, BGR8, BGRX8, RGBA5551, RGBA4444, RGB565, R8, RA8, A8 };
+    enum { Generic, Auto, RGBA8, RGB8, RGBX8, BGRA8, BGR8, BGRX8, RGBA5551, RGBA4444, RGB565, R8, RA8, A8,
+           RGBA32F, RGB32F, A32F, R32F, RA32F };
 };
 
 struct WebGLTexelPremultiplicationOp {
     enum { Generic, None, Premultiply, Unmultiply };
 };
 
 int GetWebGLTexelFormat(GLenum format, GLenum type);
 
@@ -279,43 +284,40 @@ struct WebGLVertexAttribData {
         return size * componentSize();
     }
 };
 
 struct WebGLContextOptions {
     // these are defaults
     WebGLContextOptions()
         : alpha(true), depth(true), stencil(false),
-          premultipliedAlpha(true), antialiasHint(false)
+          premultipliedAlpha(true), antialias(false),
+          preserveDrawingBuffer(false)
     { }
 
     bool operator==(const WebGLContextOptions& other) const {
         return
             alpha == other.alpha &&
             depth == other.depth &&
             stencil == other.stencil &&
             premultipliedAlpha == other.premultipliedAlpha &&
-            antialiasHint == other.antialiasHint;
+            antialias == other.antialias &&
+            preserveDrawingBuffer == other.preserveDrawingBuffer;
     }
 
     bool operator!=(const WebGLContextOptions& other) const {
-        return
-            alpha != other.alpha ||
-            depth != other.depth ||
-            stencil != other.stencil ||
-            premultipliedAlpha != other.premultipliedAlpha ||
-            antialiasHint != other.antialiasHint;
+        return !operator==(other);
     }
 
     bool alpha;
     bool depth;
     bool stencil;
-
     bool premultipliedAlpha;
-    bool antialiasHint;
+    bool antialias;
+    bool preserveDrawingBuffer;
 };
 
 class WebGLContext :
     public nsIDOMWebGLRenderingContext,
     public nsICanvasRenderingContextInternal,
     public nsSupportsWeakReference
 {
 public:
@@ -372,16 +374,26 @@ public:
                                                  CanvasLayer *aOldLayer,
                                                  LayerManager *aManager);
     void MarkContextClean() { mInvalidated = PR_FALSE; }
 
     // a number that increments every time we have an event that causes
     // all context resources to be lost.
     PRUint32 Generation() { return mGeneration.value(); }
 
+    // this is similar to GLContext::ClearSafely, but is more comprehensive
+    // (takes care of scissor, stencil write mask, dithering, viewport...)
+    // WebGL has more complex needs than GLContext as content controls GL state.
+    void ForceClearFramebufferWithDefaultValues(PRUint32 mask, const nsIntRect& viewportRect);
+
+    // if the preserveDrawingBuffer context option is false, we need to clear the back buffer
+    // after it's been presented to the compositor. This function does that if needed.
+    // See section 2.2 in the WebGL spec.
+    void EnsureBackbufferClearedAsNeeded();
+
 protected:
     void SetDontKnowIfNeedFakeBlack() {
         mFakeBlackStatus = DontKnowIfNeedFakeBlack;
     }
 
     PRBool NeedFakeBlack();
     void BindFakeBlackTextures();
     void UnbindFakeBlackTextures();
@@ -420,50 +432,64 @@ protected:
     PRInt32 mGLMaxTextureSize;
     PRInt32 mGLMaxCubeMapTextureSize;
     PRInt32 mGLMaxTextureImageUnits;
     PRInt32 mGLMaxVertexTextureImageUnits;
     PRInt32 mGLMaxVaryingVectors;
     PRInt32 mGLMaxFragmentUniformVectors;
     PRInt32 mGLMaxVertexUniformVectors;
 
+    // extensions
+    enum WebGLExtensionID {
+        WebGL_OES_texture_float,
+        WebGLExtensionID_Max
+    };
+    nsCOMPtr<nsIWebGLExtension> mEnabledExtensions[WebGLExtensionID_Max];
+    PRBool IsExtensionEnabled(WebGLExtensionID ext) const {
+        NS_ABORT_IF_FALSE(ext >= 0 && ext < WebGLExtensionID_Max, "bogus index!");
+        return mEnabledExtensions[ext] != nsnull;
+    }
+
     PRBool SafeToCreateCanvas3DContext(nsHTMLCanvasElement *canvasElement);
     PRBool InitAndValidateGL();
     PRBool ValidateBuffers(PRInt32* maxAllowedCount, const char *info);
     PRBool ValidateCapabilityEnum(WebGLenum cap, const char *info);
     PRBool ValidateBlendEquationEnum(WebGLenum cap, const char *info);
     PRBool ValidateBlendFuncDstEnum(WebGLenum mode, const char *info);
     PRBool ValidateBlendFuncSrcEnum(WebGLenum mode, const char *info);
     PRBool ValidateBlendFuncEnumsCompatibility(WebGLenum sfactor, WebGLenum dfactor, const char *info);
     PRBool ValidateTextureTargetEnum(WebGLenum target, const char *info);
     PRBool ValidateComparisonEnum(WebGLenum target, const char *info);
     PRBool ValidateStencilOpEnum(WebGLenum action, const char *info);
     PRBool ValidateFaceEnum(WebGLenum face, const char *info);
     PRBool ValidateBufferUsageEnum(WebGLenum target, const char *info);
-    PRBool ValidateTexFormatAndType(WebGLenum format, WebGLenum type,
+    PRBool ValidateTexFormatAndType(WebGLenum format, WebGLenum type, int jsArrayType,
                                       PRUint32 *texelSize, const char *info);
     PRBool ValidateDrawModeEnum(WebGLenum mode, const char *info);
     PRBool ValidateAttribIndex(WebGLuint index, const char *info);
+    PRBool ValidateStencilParamsForDrawCall();
 
     void Invalidate();
     void DestroyResourcesAndContext();
 
     void MakeContextCurrent() { gl->MakeCurrent(); }
 
     // helpers
     nsresult TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum internalformat,
                              WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero, WebGLint border,
                              WebGLenum format, WebGLenum type,
                              void *data, PRUint32 byteLength,
+                             int jsArrayType,
                              int srcFormat, PRBool srcPremultiplied);
     nsresult TexSubImage2D_base(WebGLenum target, WebGLint level,
                                 WebGLint xoffset, WebGLint yoffset,
                                 WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero,
                                 WebGLenum format, WebGLenum type,
                                 void *pixels, PRUint32 byteLength,
+                                int jsArrayType,
                                 int srcFormat, PRBool srcPremultiplied);
     nsresult ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height,
                              WebGLenum format, WebGLenum type, void *data, PRUint32 byteLength);
     nsresult TexParameter_base(WebGLenum target, WebGLenum pname,
                                WebGLint *intParamPtr, WebGLfloat *floatParamPtr);
 
     void ConvertImage(size_t width, size_t height, size_t srcStride, size_t dstStride,
                       const PRUint8*src, PRUint8 *dst,
@@ -561,18 +587,28 @@ protected:
     PRBool mBlackTexturesAreInitialized;
 
     WebGLfloat mVertexAttrib0Vector[4];
     WebGLfloat mFakeVertexAttrib0BufferObjectVector[4];
     size_t mFakeVertexAttrib0BufferObjectSize;
     GLuint mFakeVertexAttrib0BufferObject;
     int mFakeVertexAttrib0BufferStatus;
 
-    WebGLint mStencilRef;
-    WebGLuint mStencilValueMask, mStencilWriteMask;
+    WebGLint mStencilRefFront, mStencilRefBack;
+    WebGLuint mStencilValueMaskFront, mStencilValueMaskBack,
+              mStencilWriteMaskFront, mStencilWriteMaskBack;
+    realGLboolean mColorWriteMask[4];
+    realGLboolean mDepthWriteMask;
+    realGLboolean mScissorTestEnabled;
+    realGLboolean mDitherEnabled;
+    WebGLfloat mColorClearValue[4];
+    WebGLint mStencilClearValue;
+    WebGLfloat mDepthClearValue;
+
+    int mBackbufferClearingStatus;
 
 public:
     // console logging helpers
     static void LogMessage(const char *fmt, ...);
     static void LogMessage(const char *fmt, va_list ap);
     void LogMessageIfVerbose(const char *fmt, ...);
     void LogMessageIfVerbose(const char *fmt, va_list ap);
 
@@ -873,17 +909,17 @@ protected:
         }
         WebGLsizei mWidth, mHeight;
         WebGLenum mFormat, mType;
         PRBool mIsDefined;
     };
 
 public:
 
-    ImageInfo& ImageInfoAt(size_t level, size_t face) {
+    ImageInfo& ImageInfoAt(size_t level, size_t face = 0) {
 #ifdef DEBUG
         if (face >= mFacesCount)
             NS_ERROR("wrong face index, must be 0 for TEXTURE_2D and at most 5 for cube maps");
 #endif
         // no need to check level as a wrong value would be caught by ElementAt().
         return mImageInfos.ElementAt(level * mFacesCount + face);
     }
 
@@ -912,16 +948,22 @@ protected:
     PRBool mHaveGeneratedMipmap;
     FakeBlackStatus mFakeBlackStatus;
 
     void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) {
         mMaxLevelWithCustomImages = PR_MAX(mMaxLevelWithCustomImages, aMaxLevelWithCustomImages);
         mImageInfos.EnsureLengthAtLeast((mMaxLevelWithCustomImages + 1) * mFacesCount);
     }
 
+    PRBool CheckFloatTextureFilterParams() const {
+        // Without OES_texture_float_linear, only NEAREST and NEAREST_MIMPAMP_NEAREST are supported
+        return (mMagFilter == LOCAL_GL_NEAREST) &&
+            (mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
+    }
+
     PRBool DoesMinFilterRequireMipmap() const {
         return !(mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_LINEAR);
     }
 
     PRBool AreBothWrapModesClampToEdge() const {
         return mWrapS == LOCAL_GL_CLAMP_TO_EDGE && mWrapT == LOCAL_GL_CLAMP_TO_EDGE;
     }
 
@@ -1138,31 +1180,31 @@ public:
             {
                 if (DoesMinFilterRequireMipmap())
                 {
                     if (!IsMipmapTexture2DComplete()) {
                         mContext->LogMessageIfVerbose
                             ("%s is a 2D texture, with a minification filter requiring a mipmap, "
                              "and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black);
                         mFakeBlackStatus = DoNeedFakeBlack;
-                    } else if (!ImageInfoAt(0, 0).IsPowerOfTwo()) {
+                    } else if (!ImageInfoAt(0).IsPowerOfTwo()) {
                         mContext->LogMessageIfVerbose
                             ("%s is a 2D texture, with a minification filter requiring a mipmap, "
                              "and either its width or height is not a power of two.", msg_rendering_as_black);
                         mFakeBlackStatus = DoNeedFakeBlack;
                     }
                 }
                 else // no mipmap required
                 {
-                    if (!ImageInfoAt(0, 0).IsPositive()) {
+                    if (!ImageInfoAt(0).IsPositive()) {
                         mContext->LogMessageIfVerbose
                             ("%s is a 2D texture and its width or height is equal to zero.",
                              msg_rendering_as_black);
                         mFakeBlackStatus = DoNeedFakeBlack;
-                    } else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(0, 0).IsPowerOfTwo()) {
+                    } else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(0).IsPowerOfTwo()) {
                         mContext->LogMessageIfVerbose
                             ("%s is a 2D texture, with a minification filter not requiring a mipmap, "
                              "with its width or height not a power of two, and with a wrap mode "
                              "different from CLAMP_TO_EDGE.", msg_rendering_as_black);
                         mFakeBlackStatus = DoNeedFakeBlack;
                     }
                 }
             }
@@ -1761,107 +1803,47 @@ protected:
     // protected because WebGLContext should only call InitializeRenderbuffers
     void InitializeRenderbuffers()
     {
         mContext->MakeContextCurrent();
 
         if (mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) != LOCAL_GL_FRAMEBUFFER_COMPLETE)
             return;
 
-        PRBool initializeColorBuffer = mColorAttachment.HasUninitializedRenderbuffer();
-        PRBool initializeDepthBuffer = mDepthAttachment.HasUninitializedRenderbuffer() ||
-                                       mDepthStencilAttachment.HasUninitializedRenderbuffer();
-        PRBool initializeStencilBuffer = mStencilAttachment.HasUninitializedRenderbuffer() ||
-                                         mDepthStencilAttachment.HasUninitializedRenderbuffer();
+        PRUint32 mask = 0;
 
-        realGLboolean savedColorMask[4] = {0};
-        realGLboolean savedDepthMask = 0;
-        GLuint savedStencilMask = 0;
-        GLfloat savedColorClearValue[4] = {0.f};
-        GLfloat savedDepthClearValue = 0.f;
-        GLint savedStencilClearValue = 0;
-        GLuint clearBits = 0;
+        if (mColorAttachment.HasUninitializedRenderbuffer())
+            mask |= LOCAL_GL_COLOR_BUFFER_BIT;
 
-        realGLboolean wasScissorTestEnabled = mContext->gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST);
-        mContext->gl->fDisable(LOCAL_GL_SCISSOR_TEST);
-
-        realGLboolean wasDitherEnabled = mContext->gl->fIsEnabled(LOCAL_GL_DITHER);
-        mContext->gl->fDisable(LOCAL_GL_DITHER);
-
-        mContext->gl->PushViewportRect(nsIntRect(0,0,width(),height()));
-
-        if (initializeColorBuffer) {
-            mContext->gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, savedColorMask);
-            mContext->gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, savedColorClearValue);
-            mContext->gl->fColorMask(1, 1, 1, 1);
-            mContext->gl->fClearColor(0.f, 0.f, 0.f, 0.f);
-            clearBits |= LOCAL_GL_COLOR_BUFFER_BIT;
+        if (mDepthAttachment.HasUninitializedRenderbuffer() ||
+            mDepthStencilAttachment.HasUninitializedRenderbuffer())
+        {
+            mask |= LOCAL_GL_DEPTH_BUFFER_BIT;
         }
 
-        if (initializeDepthBuffer) {
-            mContext->gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &savedDepthMask);
-            mContext->gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &savedDepthClearValue);
-            mContext->gl->fDepthMask(1);
-            mContext->gl->fClearDepth(0.f);
-            clearBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
-        }
-
-        if (initializeStencilBuffer) {
-            mContext->gl->fGetIntegerv(LOCAL_GL_STENCIL_WRITEMASK, reinterpret_cast<GLint*>(&savedStencilMask));
-            mContext->gl->fGetIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &savedStencilClearValue);
-            mContext->gl->fStencilMask(0xffffffff);
-            mContext->gl->fClearStencil(0);
-            clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
+        if (mStencilAttachment.HasUninitializedRenderbuffer() ||
+            mDepthStencilAttachment.HasUninitializedRenderbuffer())
+        {
+            mask |= LOCAL_GL_STENCIL_BUFFER_BIT;
         }
 
         // the one useful line of code
-        mContext->gl->fClear(clearBits);
+        mContext->ForceClearFramebufferWithDefaultValues(mask, nsIntRect(0,0,width(),height()));
 
-        if (initializeColorBuffer) {
-            mContext->gl->fColorMask(savedColorMask[0],
-                                     savedColorMask[1],
-                                     savedColorMask[2],
-                                     savedColorMask[3]);
-            mContext->gl->fClearColor(savedColorClearValue[0],
-                                      savedColorClearValue[1],
-                                      savedColorClearValue[2],
-                                      savedColorClearValue[3]);
+        if (mColorAttachment.HasUninitializedRenderbuffer())
             mColorAttachment.Renderbuffer()->SetInitialized(PR_TRUE);
-        }
-
-        if (initializeDepthBuffer) {
-            mContext->gl->fDepthMask(savedDepthMask);
-            mContext->gl->fClearDepth(savedDepthClearValue);
-            if (mDepthAttachment.Renderbuffer())
-                mDepthAttachment.Renderbuffer()->SetInitialized(PR_TRUE);
-        }
 
-        if (initializeStencilBuffer) {
-            mContext->gl->fStencilMask(savedStencilMask);
-            mContext->gl->fClearStencil(savedStencilClearValue);
-            if (mStencilAttachment.Renderbuffer())
-                mStencilAttachment.Renderbuffer()->SetInitialized(PR_TRUE);
-        }
-
-        if (initializeDepthBuffer && initializeStencilBuffer) {
-            if (mDepthStencilAttachment.Renderbuffer())
-                mDepthStencilAttachment.Renderbuffer()->SetInitialized(PR_TRUE);
-        }
+        if (mDepthAttachment.HasUninitializedRenderbuffer())
+            mDepthAttachment.Renderbuffer()->SetInitialized(PR_TRUE);
 
-        mContext->gl->PopViewportRect();
+        if (mStencilAttachment.HasUninitializedRenderbuffer())
+            mStencilAttachment.Renderbuffer()->SetInitialized(PR_TRUE);
 
-        if (wasDitherEnabled)
-            mContext->gl->fEnable(LOCAL_GL_DITHER);
-        else
-            mContext->gl->fDisable(LOCAL_GL_DITHER);
-
-        if (wasScissorTestEnabled)
-            mContext->gl->fEnable(LOCAL_GL_DITHER);
-        else
-            mContext->gl->fDisable(LOCAL_GL_SCISSOR_TEST);
+        if (mDepthStencilAttachment.HasUninitializedRenderbuffer())
+            mDepthStencilAttachment.Renderbuffer()->SetInitialized(PR_TRUE);
     }
 
     WebGLuint mName;
     PRPackedBool mDeleted;
     PRBool mHasEverBeenBound;
 
     // we only store pointers to attached renderbuffers, not to attached textures, because
     // we will only need to initialize renderbuffers. Textures are already initialized.
@@ -1934,16 +1916,36 @@ protected:
     PRBool mDeleted;
     WebGLint mSize;
     WebGLenum mType;
     nsString mName;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLActiveInfo, WEBGLACTIVEINFO_PRIVATE_IID)
 
+#define WEBGLEXTENSION_PRIVATE_IID \
+    {0x457dd0b2, 0x9f77, 0x4c23, {0x95, 0x70, 0x9d, 0x62, 0x65, 0xc1, 0xa4, 0x81}}
+class WebGLExtension :
+    public nsIWebGLExtension,
+    public WebGLContextBoundObject,
+    public WebGLZeroingObject
+{
+public:
+    WebGLExtension(WebGLContext *baseContext)
+        : WebGLContextBoundObject(baseContext)
+    {}
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIWEBGLEXTENSION
+
+    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLEXTENSION_PRIVATE_IID)
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(WebGLExtension, WEBGLACTIVEINFO_PRIVATE_IID)
+
 /**
  ** Template implementations
  **/
 
 /* Helper function taking a BaseInterfaceType pointer and check that
  * it matches the required concrete implementation type (if it's
  * non-null), that it's not null/deleted unless we allowed it to, and
  * obtain a pointer to the concrete object.
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -60,16 +60,17 @@
 #include "angle/ShaderLang.h"
 #endif
 
 #include "WebGLTexelConversions.h"
 
 using namespace mozilla;
 
 static PRBool BaseTypeAndSizeFromUniformType(WebGLenum uType, WebGLenum *baseType, WebGLint *unitSize);
+static WebGLenum InternalFormatForFormatAndType(WebGLenum format, WebGLenum type, bool isGLES2);
 
 /* Helper macros for when we're just wrapping a gl method, so that
  * we can avoid having to type this 500 times.  Note that these MUST
  * NOT BE USED if we need to check any of the parameters.
  */
 
 #define GL_SAME_METHOD_0(glname, name)                          \
 NS_IMETHODIMP WebGLContext::name() {                            \
@@ -581,37 +582,91 @@ WebGLContext::CheckFramebufferStatus(Web
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::Clear(PRUint32 mask)
 {
     MakeContextCurrent();
 
-    if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
-        return NS_OK;
-
     PRUint32 m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT);
-    if (mask != m) {
+    if (mask != m)
         return ErrorInvalidValue("clear: invalid mask bits");
+
+    PRBool needClearCallHere = PR_TRUE;
+
+    if (mBoundFramebuffer) {
+        if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
+            return NS_OK;
+    } else {
+        // no FBO is bound, so we are clearing the backbuffer here
+        EnsureBackbufferClearedAsNeeded();
+        PRBool valuesAreDefault = mColorClearValue[0] == 0.0f &&
+                                  mColorClearValue[1] == 0.0f &&
+                                  mColorClearValue[2] == 0.0f &&
+                                  mColorClearValue[3] == 0.0f &&
+                                  mDepthClearValue    == 1.0f &&
+                                  mStencilClearValue  == 0;
+        if (valuesAreDefault &&
+            mBackbufferClearingStatus == BackbufferClearingStatus::ClearedToDefaultValues)
+        {
+            needClearCallHere = PR_FALSE;
+        }
     }
 
-    gl->fClear(mask);
-    Invalidate();
+    if (needClearCallHere) {
+        gl->fClear(mask);
+        mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
+        Invalidate();
+    }
 
     return NS_OK;
 }
 
-GL_SAME_METHOD_4(ClearColor, ClearColor, WebGLfloat, WebGLfloat, WebGLfloat, WebGLfloat)
-
-GL_SAME_METHOD_1(ClearDepth, ClearDepth, WebGLfloat)
-
-GL_SAME_METHOD_1(ClearStencil, ClearStencil, WebGLint)
-
-GL_SAME_METHOD_4(ColorMask, ColorMask, WebGLboolean, WebGLboolean, WebGLboolean, WebGLboolean)
+NS_IMETHODIMP
+WebGLContext::ClearColor(WebGLfloat r, WebGLfloat g, WebGLfloat b, WebGLfloat a)
+{
+    MakeContextCurrent();
+    mColorClearValue[0] = r;
+    mColorClearValue[1] = g;
+    mColorClearValue[2] = b;
+    mColorClearValue[3] = a;
+    gl->fClearColor(r, g, b, a);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+WebGLContext::ClearDepth(WebGLfloat v)
+{
+    MakeContextCurrent();
+    mDepthClearValue = v;
+    gl->fClearDepth(v);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+WebGLContext::ClearStencil(WebGLint v)
+{
+    MakeContextCurrent();
+    mStencilClearValue = v;
+    gl->fClearStencil(v);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+WebGLContext::ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a)
+{
+    MakeContextCurrent();
+    mColorWriteMask[0] = r;
+    mColorWriteMask[1] = g;
+    mColorWriteMask[2] = b;
+    mColorWriteMask[3] = a;
+    gl->fColorMask(r, g, b, a);
+    return NS_OK;
+}
 
 nsresult
 WebGLContext::CopyTexSubImage2D_base(WebGLenum target,
                                      WebGLint level,
                                      WebGLenum internalformat,
                                      WebGLint xoffset,
                                      WebGLint yoffset,
                                      WebGLint x,
@@ -637,17 +692,17 @@ WebGLContext::CopyTexSubImage2D_base(Web
 
         // the rect doesn't fit in the framebuffer
 
         /*** first, we initialize the texture as black ***/
 
         // first, compute the size of the buffer we should allocate to initialize the texture as black
 
         PRUint32 texelSize = 0;
-        if (!ValidateTexFormatAndType(internalformat, LOCAL_GL_UNSIGNED_BYTE, &texelSize, info))
+        if (!ValidateTexFormatAndType(internalformat, LOCAL_GL_UNSIGNED_BYTE, -1, &texelSize, info))
             return NS_OK;
 
         CheckedUint32 checked_plainRowSize = CheckedUint32(width) * texelSize;
 
         PRUint32 unpackAlignment = mPixelStoreUnpackAlignment;
 
         // alignedRowSize = row size rounded up to next multiple of packAlignment
         CheckedUint32 checked_alignedRowSize
@@ -1075,17 +1130,24 @@ WebGLContext::DepthFunc(WebGLenum func)
     if (!ValidateComparisonEnum(func, "depthFunc"))
         return NS_OK;
 
     MakeContextCurrent();
     gl->fDepthFunc(func);
     return NS_OK;
 }
 
-GL_SAME_METHOD_1(DepthMask, DepthMask, WebGLboolean)
+NS_IMETHODIMP
+WebGLContext::DepthMask(WebGLboolean b)
+{
+    MakeContextCurrent();
+    mDepthWriteMask = b;
+    gl->fDepthMask(b);
+    return NS_OK;
+}
 
 NS_IMETHODIMP
 WebGLContext::DepthRange(WebGLfloat zNear, WebGLfloat zFar)
 {
     if (zNear > zFar)
         return ErrorInvalidOperation("depthRange: the near value is greater than the far value!");
 
     MakeContextCurrent();
@@ -1296,16 +1358,19 @@ NS_IMETHODIMP
 WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
 {
     if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
         return NS_OK;
 
     if (first < 0 || count < 0)
         return ErrorInvalidValue("DrawArrays: negative first or count");
 
+    if (!ValidateStencilParamsForDrawCall())
+        return NS_OK;
+
     // If count is 0, there's nothing to do.
     if (count == 0)
         return NS_OK;
 
     // If there is no current program, this is silently ignored.
     // Any checks below this depend on a program being available.
     if (!mCurrentProgram)
         return NS_OK;
@@ -1319,41 +1384,49 @@ WebGLContext::DrawArrays(GLenum mode, We
     if (!checked_firstPlusCount.valid())
         return ErrorInvalidOperation("drawArrays: overflow in first+count");
 
     if (checked_firstPlusCount.value() > maxAllowedCount)
         return ErrorInvalidOperation("drawArrays: bound vertex attribute buffers do not have sufficient size for given first and count");
 
     MakeContextCurrent();
 
-    if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
-        return NS_OK;
+    if (mBoundFramebuffer) {
+        if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
+            return NS_OK;
+    } else {
+        EnsureBackbufferClearedAsNeeded();
+    }
 
     BindFakeBlackTextures();
     DoFakeVertexAttrib0(checked_firstPlusCount.value());
 
     gl->fDrawArrays(mode, first, count);
 
     UndoFakeVertexAttrib0();
     UnbindFakeBlackTextures();
 
+    mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
     Invalidate();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, WebGLint byteOffset)
 {
     if (!ValidateDrawModeEnum(mode, "drawElements: mode"))
         return NS_OK;
 
     if (count < 0 || byteOffset < 0)
         return ErrorInvalidValue("DrawElements: negative count or offset");
 
+    if (!ValidateStencilParamsForDrawCall())
+        return NS_OK;
+
     // If count is 0, there's nothing to do.
     if (count == 0)
         return NS_OK;
 
     CheckedUint32 checked_byteCount;
 
     if (type == LOCAL_GL_UNSIGNED_SHORT) {
         checked_byteCount = 2 * CheckedUint32(count);
@@ -1417,47 +1490,70 @@ WebGLContext::DrawElements(WebGLenum mod
             return ErrorInvalidOperation(
                 "DrawElements: bound vertex attribute buffers do not have sufficient "
                 "size for given indices from the bound element array");
         }
     }
 
     MakeContextCurrent();
 
-    if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
-        return NS_OK;
+    if (mBoundFramebuffer) {
+        if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
+            return NS_OK;
+    } else {
+        EnsureBackbufferClearedAsNeeded();
+    }
 
     BindFakeBlackTextures();
     DoFakeVertexAttrib0(checked_maxIndexPlusOne.value());
 
     gl->fDrawElements(mode, count, type, (GLvoid*) (byteOffset));
 
     UndoFakeVertexAttrib0();
     UnbindFakeBlackTextures();
 
+    mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
     Invalidate();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP WebGLContext::Enable(WebGLenum cap)
 {
     if (!ValidateCapabilityEnum(cap, "enable"))
         return NS_OK;
 
+    switch(cap) {
+        case LOCAL_GL_SCISSOR_TEST:
+            mScissorTestEnabled = 1;
+            break;
+        case LOCAL_GL_DITHER:
+            mDitherEnabled = 1;
+            break;
+    }
+
     MakeContextCurrent();
     gl->fEnable(cap);
     return NS_OK;
 }
 
 NS_IMETHODIMP WebGLContext::Disable(WebGLenum cap)
 {
     if (!ValidateCapabilityEnum(cap, "disable"))
         return NS_OK;
 
+    switch(cap) {
+        case LOCAL_GL_SCISSOR_TEST:
+            mScissorTestEnabled = 0;
+            break;
+        case LOCAL_GL_DITHER:
+            mDitherEnabled = 0;
+            break;
+    }
+
     MakeContextCurrent();
     gl->fDisable(cap);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::EnableVertexAttribArray(WebGLuint index)
 {
@@ -2852,19 +2948,24 @@ WebGLContext::ReadPixels_base(WebGLint x
     if (!checked_neededByteLength.valid())
         return ErrorInvalidOperation("ReadPixels: integer overflow computing the needed buffer size");
 
     if (checked_neededByteLength.value() > byteLength)
         return ErrorInvalidOperation("ReadPixels: buffer too small");
 
     MakeContextCurrent();
 
-    // prevent readback of arbitrary video memory through uninitialized renderbuffers!
-    if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
-        return NS_OK;
+    if (mBoundFramebuffer) {
+        // prevent readback of arbitrary video memory through uninitialized renderbuffers!
+        if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
+            return NS_OK;
+    } else {
+        EnsureBackbufferClearedAsNeeded();
+    }
+
 
     if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, boundWidth, boundHeight)) {
         // the easy case: we're not reading out-of-range pixels
         gl->fReadPixels(x, y, width, height, format, type, data);
     } else {
         // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
         // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
         // to do that for us, because passing out of range parameters to a buggy OpenGL implementation
@@ -3066,63 +3167,84 @@ WebGLContext::Scissor(WebGLint x, WebGLi
 }
 
 NS_IMETHODIMP
 WebGLContext::StencilFunc(WebGLenum func, WebGLint ref, WebGLuint mask)
 {
     if (!ValidateComparisonEnum(func, "stencilFunc: func"))
         return NS_OK;
 
-    mStencilRef = ref;
-    mStencilValueMask = mask;
+    mStencilRefFront = ref;
+    mStencilRefBack = ref;
+    mStencilValueMaskFront = mask;
+    mStencilValueMaskBack = mask;
 
     MakeContextCurrent();
     gl->fStencilFunc(func, ref, mask);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::StencilFuncSeparate(WebGLenum face, WebGLenum func, WebGLint ref, WebGLuint mask)
 {
     if (!ValidateFaceEnum(face, "stencilFuncSeparate: face") ||
         !ValidateComparisonEnum(func, "stencilFuncSeparate: func"))
         return NS_OK;
 
-    if (face != LOCAL_GL_FRONT_AND_BACK && (ref != mStencilRef || mask != mStencilValueMask))
-        return ErrorInvalidOperation("stencilFuncSeparate: WebGL doesn't currently allow specifying "
-                                     "different values for front and back.");
-
-    mStencilRef = ref;
-    mStencilValueMask = mask;
+    switch (face) {
+        case LOCAL_GL_FRONT_AND_BACK:
+            mStencilRefFront = ref;
+            mStencilRefBack = ref;
+            mStencilValueMaskFront = mask;
+            mStencilValueMaskBack = mask;
+            break;
+        case LOCAL_GL_FRONT:
+            mStencilRefFront = ref;
+            mStencilValueMaskFront = mask;
+            break;
+        case LOCAL_GL_BACK:
+            mStencilRefBack = ref;
+            mStencilValueMaskBack = mask;
+            break;
+    }
 
     MakeContextCurrent();
     gl->fStencilFuncSeparate(face, func, ref, mask);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::StencilMask(WebGLuint mask)
 {
-    mStencilWriteMask = mask;
+    mStencilWriteMaskFront = mask;
+    mStencilWriteMaskBack = mask;
 
     MakeContextCurrent();
     gl->fStencilMask(mask);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::StencilMaskSeparate(WebGLenum face, WebGLuint mask)
 {
     if (!ValidateFaceEnum(face, "stencilMaskSeparate: face"))
         return NS_OK;
 
-    if (face != LOCAL_GL_FRONT_AND_BACK && mask != mStencilWriteMask)
-        return ErrorInvalidOperation("stencilMaskSeparate: WebGL doesn't currently allow specifying "
-                                     "different values for front and back.");
-    mStencilWriteMask = mask;
+    switch (face) {
+        case LOCAL_GL_FRONT_AND_BACK:
+            mStencilWriteMaskFront = mask;
+            mStencilWriteMaskBack = mask;
+            break;
+        case LOCAL_GL_FRONT:
+            mStencilWriteMaskFront = mask;
+            break;
+        case LOCAL_GL_BACK:
+            mStencilWriteMaskBack = mask;
+            break;
+    }
 
     MakeContextCurrent();
     gl->fStencilMaskSeparate(face, mask);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::StencilOp(WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass)
@@ -3158,28 +3280,31 @@ struct WebGLImageConverter
     const PRUint8 *src;
     PRUint8 *dst;
 
     WebGLImageConverter()
     {
         memset(this, 0, sizeof(WebGLImageConverter));
     }
 
-    template<typename SrcType, typename DstType,
-         void unpackingFunc(const SrcType*, PRUint8*),
-         void packingFunc(const PRUint8*, DstType*)>
+    template<typename SrcType, typename DstType, typename UnpackType,
+         void unpackingFunc(const SrcType*, UnpackType*),
+         void packingFunc(const UnpackType*, DstType*)>
     void run()
     {
+        // Note -- even though the functions take UnpackType, the
+        // pointers below are all in terms of PRUint8; otherwise
+        // pointer math starts getting tricky.
         for (size_t src_row = 0; src_row < height; ++src_row) {
             size_t dst_row = flip ? (height - 1 - src_row) : src_row;
             PRUint8 *dst_row_ptr = dst + dst_row * dstStride;
             const PRUint8 *src_row_ptr = src + src_row * srcStride;
             const PRUint8 *src_row_end = src_row_ptr + width * srcTexelSize; // != src_row_ptr + byteStride
             while (src_row_ptr != src_row_end) {
-                PRUint8 tmp[4];
+                UnpackType tmp[4];
                 unpackingFunc(reinterpret_cast<const SrcType*>(src_row_ptr), tmp);
                 packingFunc(tmp, reinterpret_cast<DstType*>(dst_row_ptr));
                 src_row_ptr += srcTexelSize;
                 dst_row_ptr += dstTexelSize;
             }
         }
     }
 };
@@ -3200,16 +3325,18 @@ WebGLContext::ConvertImage(size_t width,
         // fast exit path: we just have to memcpy all the rows.
         //
         // The case where absolutely nothing needs to be done is supposed to have
         // been handled earlier (in TexImage2D_base, etc).
         //
         // So the case we're handling here is when even though no format conversion is needed,
         // we still might have to flip vertically and/or to adjust to a different stride.
 
+        NS_ASSERTION(mPixelStoreFlipY || srcStride != dstStride, "Performance trap -- should handle this case earlier, to avoid memcpy");
+
         size_t row_size = width * dstTexelSize; // doesn't matter, src and dst formats agree
         const PRUint8* src_row = src;
         const PRUint8* src_end = src + height * srcStride;
 
         PRUint8* dst_row = mPixelStoreFlipY ? dst + (height-1) * dstStride : dst;
         ptrdiff_t dstStrideSigned(dstStride);
         ptrdiff_t dst_delta = mPixelStoreFlipY ? -dstStrideSigned : dstStrideSigned;
 
@@ -3234,27 +3361,27 @@ WebGLContext::ConvertImage(size_t width,
     int premultiplicationOp = (!srcPremultiplied && dstPremultiplied) ? WebGLTexelPremultiplicationOp::Premultiply
                             : (srcPremultiplied && !dstPremultiplied) ? WebGLTexelPremultiplicationOp::Unmultiply
                             : WebGLTexelPremultiplicationOp::None;
 
 #define HANDLE_DSTFORMAT(format, SrcType, DstType, unpackFunc, packFunc) \
         case WebGLTexelFormat::format: \
             switch (premultiplicationOp) { \
                 case WebGLTexelPremultiplicationOp::Premultiply: \
-                    converter.run<SrcType, DstType, \
+                    converter.run<SrcType, DstType, PRUint8,          \
                                   WebGLTexelConversions::unpackFunc, \
                                   WebGLTexelConversions::packFunc##Premultiply>(); \
                 break; \
                 case WebGLTexelPremultiplicationOp::Unmultiply: \
-                    converter.run<SrcType, DstType, \
+                    converter.run<SrcType, DstType, PRUint8, \
                                   WebGLTexelConversions::unpackFunc, \
                                   WebGLTexelConversions::packFunc##Unmultiply>(); \
                 break; \
                 default: \
-                    converter.run<SrcType, DstType, \
+                    converter.run<SrcType, DstType, PRUint8, \
                                   WebGLTexelConversions::unpackFunc, \
                                   WebGLTexelConversions::packFunc>(); \
                 break; \
             } \
             break;
 
 #define HANDLE_SRCFORMAT(format, size, SrcType, unpackFunc) \
         case WebGLTexelFormat::format: \
@@ -3264,39 +3391,76 @@ WebGLContext::ConvertImage(size_t width,
                 HANDLE_DSTFORMAT(RGB8,     SrcType, PRUint8,  unpackFunc, packRGBA8ToRGB8) \
                 HANDLE_DSTFORMAT(R8,       SrcType, PRUint8,  unpackFunc, packRGBA8ToR8) \
                 HANDLE_DSTFORMAT(RA8,      SrcType, PRUint8,  unpackFunc, packRGBA8ToRA8) \
                 HANDLE_DSTFORMAT(RGBA5551, SrcType, PRUint16, unpackFunc, packRGBA8ToUnsignedShort5551) \
                 HANDLE_DSTFORMAT(RGBA4444, SrcType, PRUint16, unpackFunc, packRGBA8ToUnsignedShort4444) \
                 HANDLE_DSTFORMAT(RGB565,   SrcType, PRUint16, unpackFunc, packRGBA8ToUnsignedShort565) \
                 /* A8 needs to be special-cased as it doesn't have color channels to premultiply */ \
                 case WebGLTexelFormat::A8: \
-                    converter.run<SrcType, PRUint8, \
+                    converter.run<SrcType, PRUint8, PRUint8,          \
                                   WebGLTexelConversions::unpackFunc, \
                                   WebGLTexelConversions::packRGBA8ToA8>(); \
                     break; \
                 default: \
                     NS_ASSERTION(PR_FALSE, "Coding error?! Should never reach this point."); \
                     return; \
             } \
             break;
 
+#define HANDLE_FLOAT_DSTFORMAT(format, unpackFunc, packFunc) \
+        case WebGLTexelFormat::format: \
+            switch (premultiplicationOp) { \
+                case WebGLTexelPremultiplicationOp::Premultiply: \
+                    converter.run<float, float, float,                \
+                                  WebGLTexelConversions::unpackFunc, \
+                                  WebGLTexelConversions::packFunc##Premultiply>(); \
+                break; \
+                case WebGLTexelPremultiplicationOp::Unmultiply: \
+                    NS_ASSERTION(PR_FALSE, "Floating point can't be un-premultiplied -- we have no premultiplied source data!"); \
+                break; \
+                default: \
+                    converter.run<float, float, float,                \
+                                  WebGLTexelConversions::unpackFunc, \
+                                  WebGLTexelConversions::packFunc>(); \
+                break; \
+            } \
+            break;
+
+#define HANDLE_FLOAT_SRCFORMAT(format, size, unpackFunc)                \
+        case WebGLTexelFormat::format:                                  \
+            converter.srcTexelSize = size;                              \
+            switch (dstFormat) {                                        \
+                HANDLE_FLOAT_DSTFORMAT(RGB32F, unpackFunc, packRGBA32FToRGB32F) \
+                HANDLE_FLOAT_DSTFORMAT(A32F,   unpackFunc, packRGBA32FToA32F) \
+                HANDLE_FLOAT_DSTFORMAT(R32F,   unpackFunc, packRGBA32FToR32F) \
+                HANDLE_FLOAT_DSTFORMAT(RA32F,  unpackFunc, packRGBA32FToRA32F) \
+                default: \
+                    NS_ASSERTION(PR_FALSE, "Coding error?! Should never reach this point."); \
+                    return; \
+            } \
+            break;
+        
     switch (srcFormat) {
         HANDLE_SRCFORMAT(RGBA8,    4, PRUint8,  unpackRGBA8ToRGBA8)
         HANDLE_SRCFORMAT(RGBX8,    4, PRUint8,  unpackRGB8ToRGBA8)
         HANDLE_SRCFORMAT(RGB8,     3, PRUint8,  unpackRGB8ToRGBA8)
         HANDLE_SRCFORMAT(BGRA8,    4, PRUint8,  unpackBGRA8ToRGBA8)
         HANDLE_SRCFORMAT(BGRX8,    4, PRUint8,  unpackBGR8ToRGBA8)
         HANDLE_SRCFORMAT(BGR8,     3, PRUint8,  unpackBGR8ToRGBA8)
         HANDLE_SRCFORMAT(R8,       1, PRUint8,  unpackR8ToRGBA8)
         HANDLE_SRCFORMAT(A8,       1, PRUint8,  unpackA8ToRGBA8)
         HANDLE_SRCFORMAT(RA8,      2, PRUint8,  unpackRA8ToRGBA8)
         HANDLE_SRCFORMAT(RGBA5551, 2, PRUint16, unpackRGBA5551ToRGBA8)
         HANDLE_SRCFORMAT(RGBA4444, 2, PRUint16, unpackRGBA4444ToRGBA8)
         HANDLE_SRCFORMAT(RGB565,   2, PRUint16, unpackRGB565ToRGBA8)
+        HANDLE_FLOAT_SRCFORMAT(RGB32F,  12, unpackRGB32FToRGBA32F)
+        HANDLE_FLOAT_SRCFORMAT(RA32F,    8, unpackRA32FToRGBA32F)
+        HANDLE_FLOAT_SRCFORMAT(R32F,     4, unpackR32FToRGBA32F)
+        HANDLE_FLOAT_SRCFORMAT(A32F,     4, unpackA32FToRGBA32F)
         default:
             NS_ASSERTION(PR_FALSE, "Coding error?! Should never reach this point.");
             return;
     }
 }
 
 nsresult
 WebGLContext::DOMElementToImageSurface(nsIDOMElement *imageOrCanvas,
@@ -3353,17 +3517,20 @@ WebGLContext::DOMElementToImageSurface(n
 
 #define OBTAIN_UNIFORM_LOCATION(info)                                   \
     WebGLUniformLocation *location_object;                              \
     PRBool isNull;                                                      \
     if (!GetConcreteObject(info, ploc, &location_object, &isNull))      \
         return NS_OK;                                                   \
     if (isNull)                                                         \
         return NS_OK;                                                   \
-    if (mCurrentProgram != location_object->Program())                  \
+    /* the need to check specifically for !mCurrentProgram here is explained in bug 657556 */ \
+    if (!mCurrentProgram) \
+        return ErrorInvalidOperation("%s: no program is currently bound", info); \
+    if (mCurrentProgram != location_object->Program()) \
         return ErrorInvalidOperation("%s: this uniform location doesn't correspond to the current program", info); \
     if (mCurrentProgram->Generation() != location_object->ProgramGeneration())            \
         return ErrorInvalidOperation("%s: This uniform location is obsolete since the program has been relinked", info); \
     GLint location = location_object->Location();
 
 #define SIMPLE_ARRAY_METHOD_UNIFORM(name, cnt, arrayType, ptrType)      \
 NS_IMETHODIMP                                                           \
 WebGLContext::name(PRInt32 dummy) {                                     \
@@ -3590,21 +3757,19 @@ WebGLContext::ValidateProgram(nsIWebGLPr
 {
     WebGLuint progname;
     if (!GetGLName<WebGLProgram>("validateProgram", pobj, &progname))
         return NS_OK;
 
     MakeContextCurrent();
 
 #ifdef XP_MACOSX
-    if (gl->Vendor() == gl::GLContext::VendorNVIDIA) {
-        LogMessageIfVerbose("validateProgram: implemented as a no-operation "
-                            "on Mac/NVIDIA to work around a driver crash");
-        return NS_OK;
-    }
+    // see bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed with Mac OS 10.6.7
+    LogMessageIfVerbose("validateProgram: implemented as a no-operation on Mac to work around crashes");
+    return NS_OK;
 #endif
 
     gl->fValidateProgram(progname);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -3935,16 +4100,17 @@ WebGLContext::TexImage2D(PRInt32 dummy)
 }
 
 nsresult
 WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum internalformat,
                               WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero,
                               WebGLint border,
                               WebGLenum format, WebGLenum type,
                               void *data, PRUint32 byteLength,
+                              int jsArrayType, // a TypedArray format enum, or -1 if not relevant
                               int srcFormat, PRBool srcPremultiplied)
 {
     switch (target) {
         case LOCAL_GL_TEXTURE_2D:
             break;
         case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
         case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
         case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
@@ -3991,17 +4157,17 @@ WebGLContext::TexImage2D_base(WebGLenum 
               is_pot_assuming_nonnegative(height)))
             return ErrorInvalidValue("texImage2D: with level > 0, width and height must be powers of two");
     }
 
     if (border != 0)
         return ErrorInvalidValue("TexImage2D: border must be 0");
 
     PRUint32 texelSize = 0;
-    if (!ValidateTexFormatAndType(format, type, &texelSize, "texImage2D"))
+    if (!ValidateTexFormatAndType(format, type, jsArrayType, &texelSize, "texImage2D"))
         return NS_OK;
 
     CheckedUint32 checked_plainRowSize = CheckedUint32(width) * texelSize;
 
     PRUint32 unpackAlignment = mPixelStoreUnpackAlignment;
 
     // alignedRowSize = row size rounded up to next multiple of packAlignment
     CheckedUint32 checked_alignedRowSize
@@ -4023,16 +4189,20 @@ WebGLContext::TexImage2D_base(WebGLenum 
 
     if (!tex)
         return ErrorInvalidOperation("texImage2D: no texture is bound to this target");
 
     tex->SetImageInfo(target, level, width, height, format, type);
 
     MakeContextCurrent();
 
+    // Handle ES2 and GL differences in floating point internal formats.  Note that
+    // format == internalformat, as checked above and as required by ES.
+    internalformat = InternalFormatForFormatAndType(format, type, gl->IsGLES2());
+
     if (byteLength) {
         int dstFormat = GetWebGLTexelFormat(format, type);
         int actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
         size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
 
         size_t dstPlainRowSize = texelSize * width;
         size_t unpackAlignment = mPixelStoreUnpackAlignment;
         size_t dstStride = ((dstPlainRowSize + unpackAlignment-1) / unpackAlignment) * unpackAlignment;
@@ -4076,40 +4246,43 @@ NS_IMETHODIMP
 WebGLContext::TexImage2D_buf(WebGLenum target, WebGLint level, WebGLenum internalformat,
                              WebGLsizei width, WebGLsizei height, WebGLint border,
                              WebGLenum format, WebGLenum type,
                              js::ArrayBuffer *pixels)
 {
     return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
                            pixels ? pixels->data : 0,
                            pixels ? pixels->byteLength : 0,
+                           -1,
                            WebGLTexelFormat::Auto, PR_FALSE);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexImage2D_array(WebGLenum target, WebGLint level, WebGLenum internalformat,
                                WebGLsizei width, WebGLsizei height, WebGLint border,
                                WebGLenum format, WebGLenum type,
                                js::TypedArray *pixels)
 {
     return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
                            pixels ? pixels->data : 0,
                            pixels ? pixels->byteLength : 0,
+                           (int) pixels->type,
                            WebGLTexelFormat::Auto, PR_FALSE);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexImage2D_imageData(WebGLenum target, WebGLint level, WebGLenum internalformat,
                                WebGLsizei width, WebGLsizei height, WebGLint border,
                                WebGLenum format, WebGLenum type,
                                js::TypedArray *pixels)
 {
     return TexImage2D_base(target, level, internalformat, width, height, 4*width, border, format, type,
                            pixels ? pixels->data : 0,
                            pixels ? pixels->byteLength : 0,
+                           -1,
                            WebGLTexelFormat::RGBA8, PR_FALSE);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexImage2D_dom(WebGLenum target, WebGLint level, WebGLenum internalformat,
                              WebGLenum format, GLenum type, nsIDOMElement *elt)
 {
     nsRefPtr<gfxImageSurface> isurf;
@@ -4120,31 +4293,33 @@ WebGLContext::TexImage2D_dom(WebGLenum t
         return rv;
 
     PRUint32 byteLength = isurf->Stride() * isurf->Height();
 
     return TexImage2D_base(target, level, internalformat,
                            isurf->Width(), isurf->Height(), isurf->Stride(), 0,
                            format, type,
                            isurf->Data(), byteLength,
+                           -1,
                            srcFormat, mPixelStorePremultiplyAlpha);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexSubImage2D(PRInt32 dummy)
 {
     return NS_ERROR_FAILURE;
 }
 
 nsresult
 WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
                                  WebGLint xoffset, WebGLint yoffset,
                                  WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero,
                                  WebGLenum format, WebGLenum type,
                                  void *pixels, PRUint32 byteLength,