merge mozilla-inbound to mozilla-central
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 24 Apr 2014 11:38:32 +0200
changeset 180279 6965a913e858b6feb2944649940a646f40eb4037
parent 180278 a0e703ba2ae6ac7c9db9df1ff1531732e28882a9 (current diff)
parent 180242 6ea4ce828d069fa99f3e1526f40eaeb193de17a3 (diff)
child 180293 c8055a00235db1ddadfdd74e1d8181537117c23c
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
milestone31.0a1
merge mozilla-inbound to mozilla-central
--- a/accessible/src/jsat/TraversalRules.jsm
+++ b/accessible/src/jsat/TraversalRules.jsm
@@ -126,17 +126,16 @@ var gSimpleMatchFunc = function gSimpleM
       if (parent.childCount > 1 && aAccessible.indexInParent == 0 &&
           parent.role == Roles.LISTITEM)
         return Filters.IGNORE;
 
       return Filters.MATCH;
     }
   case Roles.GRAPHIC:
     return TraversalRules._shouldSkipImage(aAccessible);
-  case Roles.LINK:
   case Roles.HEADER:
   case Roles.HEADING:
     if ((aAccessible.childCount > 0 || aAccessible.name) &&
         hasZeroOrSingleChildDescendants()) {
       return Filters.MATCH | Filters.IGNORE_SUBTREE;
     } else {
       return Filters.IGNORE;
     }
--- a/configure.in
+++ b/configure.in
@@ -5045,20 +5045,16 @@ AC_SUBST(MOZ_IPDL_TESTS)
 dnl ========================================================
 dnl = Disable building dbm
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(dbm,
 [  --disable-dbm           Disable building dbm],
     NSS_DISABLE_DBM=1,
     NSS_DISABLE_DBM=)
 
-dnl bi-directional support always on
-IBMBIDI=1
-AC_DEFINE(IBMBIDI)
-
 dnl ========================================================
 dnl accessibility support on by default on all platforms
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(accessibility,
 [  --disable-accessibility Disable accessibility support],
     ACCESSIBILITY=,
     ACCESSIBILITY=1 )
 if test "$ACCESSIBILITY"; then
@@ -8482,17 +8478,16 @@ AC_SUBST(JAVAC)
 AC_SUBST(JAVAH)
 AC_SUBST(JAR)
 AC_SUBST(JARSIGNER)
 AC_SUBST(KEYTOOL)
 
 AC_SUBST(MOZ_PROFILELOCKING)
 
 AC_SUBST(ENABLE_TESTS)
-AC_SUBST(IBMBIDI)
 AC_SUBST(MOZ_UNIVERSALCHARDET)
 AC_SUBST(ACCESSIBILITY)
 AC_SUBST(MOZ_SPELLCHECK)
 AC_SUBST(MOZ_ANDROID_OMTC)
 AC_SUBST(MOZ_ANDROID_ANR_REPORTER)
 AC_SUBST(MOZ_CRASHREPORTER)
 AC_SUBST(MOZ_CRASHREPORTER_INJECTOR)
 AC_SUBST(MOZ_CRASHREPORTER_UPLOAD_FULL_SYMBOLS)
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -128,19 +128,17 @@ typedef void* (*DeferredFinalizeAppendFu
 
 // Called to finalize a number of objects. Slice is the number of objects
 // to finalize, or if it's UINT32_MAX, all objects should be finalized.
 // Return value indicates whether it finalized all objects in the buffer.
 typedef bool (*DeferredFinalizeFunction)(uint32_t slice, void* data);
 
 } // namespace mozilla
 
-#ifdef IBMBIDI
 class nsIBidiKeyboard;
-#endif
 
 extern const char kLoadAsData[];
 
 // Stolen from nsReadableUtils, but that's OK, since we can declare the same
 // name multiple times.
 const nsAFlatString& EmptyString();
 const nsAFlatCString& EmptyCString();
 
@@ -456,20 +454,18 @@ public:
     return sNameSpaceManager;
   }
 
   static nsIIOService* GetIOService()
   {
     return sIOService;
   }
 
-#ifdef IBMBIDI
   static nsIBidiKeyboard* GetBidiKeyboard();
-#endif
-  
+
   /**
    * Get the cache security manager service. Can return null if the layout
    * module has been shut down.
    */
   static nsIScriptSecurityManager* GetSecurityManager()
   {
     return sSecurityManager;
   }
@@ -2200,19 +2196,17 @@ private:
   static nsIStringBundle* sStringBundles[PropertiesFile_COUNT];
 
   static nsIContentPolicy* sContentPolicyService;
   static bool sTriedToGetContentPolicy;
 
   static nsILineBreaker* sLineBreaker;
   static nsIWordBreaker* sWordBreaker;
 
-#ifdef IBMBIDI
   static nsIBidiKeyboard* sBidiKeyboard;
-#endif
 
   static bool sInitialized;
   static uint32_t sScriptBlockerCount;
 #ifdef DEBUG
   static uint32_t sDOMNodeRemovedSuppressCount;
 #endif
   static uint32_t sMicroTaskLevel;
   // Not an nsCOMArray because removing elements from those is slower
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -172,19 +172,17 @@
 #include "nsViewManager.h"
 #include "nsViewportInfo.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsXULPopupManager.h"
 #include "xpcprivate.h" // nsXPConnect
 #include "HTMLSplitOnSpacesTokenizer.h"
 #include "nsContentTypeParser.h"
 
-#ifdef IBMBIDI
 #include "nsIBidiKeyboard.h"
-#endif
 
 extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end,
                                       const char** next, char16_t* result);
 extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
                                  int ns_aware, const char** colon);
 
 class imgLoader;
 
@@ -205,19 +203,17 @@ nsDataHashtable<nsISupportsHashKey, Even
 nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nullptr;
 nsCOMArray<nsIAtom>* nsContentUtils::sUserDefinedEvents = nullptr;
 nsIStringBundleService *nsContentUtils::sStringBundleService;
 nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT];
 nsIContentPolicy *nsContentUtils::sContentPolicyService;
 bool nsContentUtils::sTriedToGetContentPolicy = false;
 nsILineBreaker *nsContentUtils::sLineBreaker;
 nsIWordBreaker *nsContentUtils::sWordBreaker;
-#ifdef IBMBIDI
 nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr;
-#endif
 uint32_t nsContentUtils::sScriptBlockerCount = 0;
 #ifdef DEBUG
 uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
 #endif
 uint32_t nsContentUtils::sMicroTaskLevel = 0;
 nsTArray< nsCOMPtr<nsIRunnable> >* nsContentUtils::sBlockedScriptRunners = nullptr;
 uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0;
 nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr;
@@ -942,29 +938,27 @@ nsContentUtils::ParseSandboxAttributeToF
   IF_KEYWORD(allowtopnavigation, SANDBOXED_TOPLEVEL_NAVIGATION)
   IF_KEYWORD(allowpointerlock, SANDBOXED_POINTER_LOCK)
   IF_KEYWORD(allowpopups, SANDBOXED_AUXILIARY_NAVIGATION)
 
   return out;
 #undef IF_KEYWORD
 }
 
-#ifdef IBMBIDI
 nsIBidiKeyboard*
 nsContentUtils::GetBidiKeyboard()
 {
   if (!sBidiKeyboard) {
     nsresult rv = CallGetService("@mozilla.org/widget/bidikeyboard;1", &sBidiKeyboard);
     if (NS_FAILED(rv)) {
       sBidiKeyboard = nullptr;
     }
   }
   return sBidiKeyboard;
 }
-#endif
 
 template <class OutputIterator>
 struct NormalizeNewlinesCharTraits {
   public:
     typedef typename OutputIterator::value_type value_type;
 
   public:
     NormalizeNewlinesCharTraits(OutputIterator& aIterator) : mIterator(aIterator) { }
@@ -1439,19 +1433,17 @@ nsContentUtils::Shutdown()
   NS_IF_RELEASE(sStringBundleService);
   NS_IF_RELEASE(sConsoleService);
   sXPConnect = nullptr;
   NS_IF_RELEASE(sSecurityManager);
   NS_IF_RELEASE(sParserService);
   NS_IF_RELEASE(sIOService);
   NS_IF_RELEASE(sLineBreaker);
   NS_IF_RELEASE(sWordBreaker);
-#ifdef IBMBIDI
   NS_IF_RELEASE(sBidiKeyboard);
-#endif
 
   delete sAtomEventTable;
   sAtomEventTable = nullptr;
   delete sStringEventTable;
   sStringEventTable = nullptr;
   delete sUserDefinedEvents;
   sUserDefinedEvents = nullptr;
 
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -27,16 +27,18 @@
 #include "nsIProtocolHandler.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIDOMClassInfo.h"
 #include "nsIDOMFile.h"
 #include "xpcpublic.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/StructuredCloneUtils.h"
+#include "mozilla/dom/PBlobChild.h"
+#include "mozilla/dom/PBlobParent.h"
 #include "JavaScriptChild.h"
 #include "JavaScriptParent.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "nsPrintfCString.h"
 #include <algorithm>
 
 #ifdef ANDROID
 #include <android/log.h>
@@ -123,16 +125,41 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
                                                    mChrome && mIsBroadcaster)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageSender,
                                                    mChrome && !mIsBroadcaster)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameMessageManager)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameMessageManager)
 
+enum ActorFlavorEnum {
+  Parent = 0,
+  Child
+};
+
+template <ActorFlavorEnum>
+struct BlobTraits
+{ };
+
+template <>
+struct BlobTraits<Parent>
+{
+  typedef mozilla::dom::BlobParent BlobType;
+  typedef mozilla::dom::PBlobParent ProtocolType;
+  typedef mozilla::dom::ContentParent ConcreteContentManagerType;
+};
+
+template <>
+struct BlobTraits<Child>
+{
+  typedef mozilla::dom::BlobChild BlobType;
+  typedef mozilla::dom::PBlobChild ProtocolType;
+  typedef mozilla::dom::ContentChild ConcreteContentManagerType;
+};
+
 template<ActorFlavorEnum>
 struct DataBlobs
 { };
 
 template<>
 struct DataBlobs<Parent>
 {
   typedef BlobTraits<Parent>::ProtocolType ProtocolType;
@@ -175,17 +202,18 @@ BuildClonedMessageData(typename BlobTrai
   buffer.dataLength = aData.mDataLength;
   const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
   if (!blobs.IsEmpty()) {
     typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
     InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
     uint32_t length = blobs.Length();
     blobList.SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
-      Blob<Flavor>* protocolActor = aManager->GetOrCreateActorForBlob(blobs[i]);
+      typename BlobTraits<Flavor>::BlobType* protocolActor =
+        aManager->GetOrCreateActorForBlob(blobs[i]);
       if (!protocolActor) {
         return false;
       }
       blobList.AppendElement(protocolActor);
     }
   }
   return true;
 }
@@ -215,17 +243,18 @@ UnpackClonedMessageData(const ClonedMess
   const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aData);
   StructuredCloneData cloneData;
   cloneData.mData = buffer.data;
   cloneData.mDataLength = buffer.dataLength;
   if (!blobs.IsEmpty()) {
     uint32_t length = blobs.Length();
     cloneData.mClosure.mBlobs.SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
-      Blob<Flavor>* blob = static_cast<Blob<Flavor>*>(blobs[i]);
+      auto* blob =
+        static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
       MOZ_ASSERT(blob);
       nsCOMPtr<nsIDOMBlob> domBlob = blob->GetBlob();
       MOZ_ASSERT(domBlob);
       cloneData.mClosure.mBlobs.AppendElement(domBlob);
     }
   }
   return cloneData;
 }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8425,16 +8425,23 @@ nsGlobalWindow::EnterModalState()
 
       if (activeShell) {
         nsRefPtr<nsFrameSelection> frameSelection = activeShell->FrameSelection();
         frameSelection->SetMouseDownState(false);
       }
     }
   }
 
+  // If there are any drag and drop operations in flight, try to end them.
+  nsCOMPtr<nsIDragService> ds =
+    do_GetService("@mozilla.org/widget/dragservice;1");
+  if (ds) {
+    ds->EndDragSession(true);
+  }
+
   // Clear the capturing content if it is under topDoc.
   // Usually the activeESM check above does that, but there are cases when
   // we don't have activeESM, or it is for different document.
   nsIDocument* topDoc = topWin->GetExtantDoc();
   nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
   if (capturingContent && topDoc &&
       nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
     nsIPresShell::SetCapturingContent(nullptr, 0);
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/UIEvent.h"
 
 #include "ContentEventHandler.h"
+#include "IMEContentObserver.h"
 #include "WheelHandlingHelper.h"
 
 #include "nsCOMPtr.h"
 #include "nsFocusManager.h"
 #include "nsIContent.h"
 #include "nsINodeInfo.h"
 #include "nsIDocument.h"
 #include "nsIFrame.h"
@@ -332,16 +333,18 @@ EventStateManager::Init()
     Prefs::Init();
   }
 
   return NS_OK;
 }
 
 EventStateManager::~EventStateManager()
 {
+  ReleaseCurrentIMEContentObserver();
+
   if (sActiveESM == this) {
     sActiveESM = nullptr;
   }
   if (Prefs::ClickHoldContextMenu())
     KillClickHoldTimer();
 
   if (mDocument == sMouseOverDocument)
     sMouseOverDocument = nullptr;
@@ -405,34 +408,61 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
    NS_INTERFACE_MAP_ENTRY(nsIObserver)
    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(EventStateManager)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(EventStateManager)
 
-NS_IMPL_CYCLE_COLLECTION_16(EventStateManager,
+NS_IMPL_CYCLE_COLLECTION_17(EventStateManager,
                             mCurrentTargetContent,
                             mGestureDownContent,
                             mGestureDownFrameOwner,
                             mLastLeftMouseDownContent,
                             mLastLeftMouseDownContentParent,
                             mLastMiddleMouseDownContent,
                             mLastMiddleMouseDownContentParent,
                             mLastRightMouseDownContent,
                             mLastRightMouseDownContentParent,
                             mActiveContent,
                             mHoverContent,
                             mURLTargetContent,
                             mMouseEnterLeaveHelper,
                             mPointersEnterLeaveHelper,
                             mDocument,
+                            mIMEContentObserver,
                             mAccessKeys)
 
+void
+EventStateManager::ReleaseCurrentIMEContentObserver()
+{
+  if (mIMEContentObserver) {
+    mIMEContentObserver->DisconnectFromEventStateManager();
+  }
+  mIMEContentObserver = nullptr;
+}
+
+void
+EventStateManager::OnStartToObserveContent(
+                     IMEContentObserver* aIMEContentObserver)
+{
+  ReleaseCurrentIMEContentObserver();
+  mIMEContentObserver = aIMEContentObserver;
+}
+
+void
+EventStateManager::OnStopObservingContent(
+                     IMEContentObserver* aIMEContentObserver)
+{
+  aIMEContentObserver->DisconnectFromEventStateManager();
+  NS_ENSURE_TRUE_VOID(mIMEContentObserver == aIMEContentObserver);
+  mIMEContentObserver = nullptr;
+}
+
 nsresult
 EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
                                   WidgetEvent* aEvent,
                                   nsIFrame* aTargetFrame,
                                   nsEventStatus* aStatus)
 {
   NS_ENSURE_ARG_POINTER(aStatus);
   NS_ENSURE_ARG(aPresContext);
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -29,16 +29,17 @@ class nsIMarkupDocumentViewer;
 class nsIScrollableFrame;
 class nsITimer;
 class nsPresContext;
 
 namespace mozilla {
 
 class EnterLeaveDispatcher;
 class EventStates;
+class IMEContentObserver;
 class ScrollbarsForWheel;
 class WheelTransaction;
 
 namespace dom {
 class DataTransfer;
 class TabParent;
 } // namespace dom
 
@@ -129,16 +130,24 @@ public:
    *                  frame reconstructions that may occur, but this does not
    *                  affect the return value.
    */
   bool SetContentState(nsIContent* aContent, EventStates aState);
   void ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
   bool EventStatusOK(WidgetGUIEvent* aEvent);
 
   /**
+   * EventStateManager stores IMEContentObserver while it's observing contents.
+   * Following mehtods are called by IMEContentObserver when it starts to
+   * observe or stops observing the content.
+   */
+  void OnStartToObserveContent(IMEContentObserver* aIMEContentObserver);
+  void OnStopObservingContent(IMEContentObserver* aIMEContentObserver);
+
+  /**
    * Register accesskey on the given element. When accesskey is activated then
    * the element will be notified via nsIContent::PerformAccesskey() method.
    *
    * @param  aContent  the given element
    * @param  aKey      accesskey
    */
   void RegisterAccessKey(nsIContent* aContent, uint32_t aKey);
 
@@ -772,16 +781,18 @@ protected:
 
   bool DispatchCrossProcessEvent(WidgetEvent* aEvent,
                                  nsFrameLoader* aRemote,
                                  nsEventStatus *aStatus);
   bool HandleCrossProcessEvent(WidgetEvent* aEvent,
                                nsIFrame* aTargetFrame,
                                nsEventStatus* aStatus);
 
+  void ReleaseCurrentIMEContentObserver();
+
 private:
   static inline void DoStateChange(dom::Element* aElement,
                                    EventStates aState, bool aAddState);
   static inline void DoStateChange(nsIContent* aContent, EventStates aState,
                                    bool aAddState);
   static void UpdateAncestorState(nsIContent* aStartNode,
                                   nsIContent* aStopBefore,
                                   EventStates aState,
@@ -834,16 +845,18 @@ private:
   nsCOMPtr<nsIContent> mActiveContent;
   nsCOMPtr<nsIContent> mHoverContent;
   static nsCOMPtr<nsIContent> sDragOverContent;
   nsCOMPtr<nsIContent> mURLTargetContent;
 
   nsPresContext* mPresContext;      // Not refcnted
   nsCOMPtr<nsIDocument> mDocument;   // Doesn't necessarily need to be owner
 
+  nsRefPtr<IMEContentObserver> mIMEContentObserver;
+
   uint32_t mLClickCount;
   uint32_t mMClickCount;
   uint32_t mRClickCount;
 
   bool m_haveShutdown;
 
   // Time at which we began handling user input.
   static TimeStamp sHandlingInputStart;
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=2 sw=2 et tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ContentEventHandler.h"
 #include "IMEContentObserver.h"
 #include "mozilla/AsyncEventDispatcher.h"
+#include "mozilla/EventStateManager.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/dom/Element.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsGkAtoms.h"
 #include "nsIAtom.h"
 #include "nsIContent.h"
@@ -28,32 +29,45 @@
 #include "nsPresContext.h"
 #include "nsThreadUtils.h"
 #include "nsWeakReference.h"
 
 namespace mozilla {
 
 using namespace widget;
 
-NS_IMPL_ISUPPORTS5(IMEContentObserver,
-                   nsIMutationObserver,
-                   nsISelectionListener,
-                   nsIReflowObserver,
-                   nsIScrollObserver,
-                   nsISupportsWeakReference)
+NS_IMPL_CYCLE_COLLECTION_5(IMEContentObserver,
+                           mWidget, mSelection,
+                           mRootContent, mEditableNode, mDocShell)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IMEContentObserver)
+ NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
+ NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
+ NS_INTERFACE_MAP_ENTRY(nsIReflowObserver)
+ NS_INTERFACE_MAP_ENTRY(nsIScrollObserver)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISelectionListener)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(IMEContentObserver)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver)
 
 IMEContentObserver::IMEContentObserver()
+  : mESM(nullptr)
 {
 }
 
 void
 IMEContentObserver::Init(nsIWidget* aWidget,
                          nsPresContext* aPresContext,
                          nsIContent* aContent)
 {
+  mESM = aPresContext->EventStateManager();
+  mESM->OnStartToObserveContent(this);
+
   mWidget = aWidget;
   mEditableNode = IMEStateManager::GetRootEditableNode(aPresContext, aContent);
   if (!mEditableNode) {
     return;
   }
 
   nsIPresShell* presShell = aPresContext->PresShell();
 
@@ -169,16 +183,27 @@ IMEContentObserver::Destroy()
   if (mUpdatePreference.WantPositionChanged() && mDocShell) {
     mDocShell->RemoveWeakScrollObserver(this);
     mDocShell->RemoveWeakReflowObserver(this);
   }
   mRootContent = nullptr;
   mEditableNode = nullptr;
   mDocShell = nullptr;
   mUpdatePreference.mWantUpdates = nsIMEUpdatePreference::NOTIFY_NOTHING;
+
+  if (mESM) {
+    mESM->OnStopObservingContent(this);
+    mESM = nullptr;
+  }
+}
+
+void
+IMEContentObserver::DisconnectFromEventStateManager()
+{
+  mESM = nullptr;
 }
 
 bool
 IMEContentObserver::IsManaging(nsPresContext* aPresContext,
                                nsIContent* aContent)
 {
   if (!mSelection || !mRootContent || !mEditableNode) {
     return false; // failed to initialize.
--- a/dom/events/IMEContentObserver.h
+++ b/dom/events/IMEContentObserver.h
@@ -4,58 +4,69 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_IMEContentObserver_h_
 #define mozilla_IMEContentObserver_h_
 
 #include "mozilla/Attributes.h"
 #include "nsCOMPtr.h"
+#include "nsCycleCollectionParticipant.h"
 #include "nsIDocShell.h" // XXX Why does only this need to be included here?
 #include "nsIReflowObserver.h"
 #include "nsISelectionListener.h"
 #include "nsIScrollObserver.h"
 #include "nsIWidget.h" // for nsIMEUpdatePreference
 #include "nsStubMutationObserver.h"
 #include "nsWeakReference.h"
 
 class nsIContent;
 class nsINode;
 class nsISelection;
 class nsPresContext;
 
 namespace mozilla {
 
+class EventStateManager;
+
 // IMEContentObserver notifies widget of any text and selection changes
 // in the currently focused editor
 class IMEContentObserver MOZ_FINAL : public nsISelectionListener,
                                      public nsStubMutationObserver,
                                      public nsIReflowObserver,
                                      public nsIScrollObserver,
                                      public nsSupportsWeakReference
 {
 public:
   IMEContentObserver();
 
-  NS_DECL_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IMEContentObserver,
+                                           nsISelectionListener)
   NS_DECL_NSISELECTIONLISTENER
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_DECL_NSIREFLOWOBSERVER
 
   // nsIScrollObserver
   virtual void ScrollPositionChanged() MOZ_OVERRIDE;
 
   void Init(nsIWidget* aWidget, nsPresContext* aPresContext,
             nsIContent* aContent);
   void Destroy();
+  /**
+   * IMEContentObserver is stored by EventStateManager during observing.
+   * DisconnectFromEventStateManager() is called when EventStateManager stops
+   * storing the instance.
+   */
+  void DisconnectFromEventStateManager();
   bool IsManaging(nsPresContext* aPresContext, nsIContent* aContent);
   bool IsEditorHandlingEventForComposition() const;
   bool KeepAliveDuringDeactive() const
   {
     return mUpdatePreference.WantDuringDeactive();
   }
   nsIWidget* GetWidget() const { return mWidget; }
   nsresult GetSelectionAndRoot(nsISelection** aSelection,
@@ -65,15 +76,18 @@ private:
   void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
   void ObserveEditableNode();
 
   nsCOMPtr<nsIWidget> mWidget;
   nsCOMPtr<nsISelection> mSelection;
   nsCOMPtr<nsIContent> mRootContent;
   nsCOMPtr<nsINode> mEditableNode;
   nsCOMPtr<nsIDocShell> mDocShell;
+
+  EventStateManager* mESM;
+
   nsIMEUpdatePreference mUpdatePreference;
   uint32_t mPreAttrChangeLength;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_IMEContentObserver_h_
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -1,69 +1,68 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=4 ts=8 et tw=80 : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "Blob.h"
+
+#include "ContentChild.h"
+#include "ContentParent.h"
+#include "FileDescriptorSetChild.h"
+#include "jsapi.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
-
-#include "base/basictypes.h"
-
-#include "Blob.h"
-
+#include "mozilla/Monitor.h"
+#include "mozilla/unused.h"
+#include "mozilla/dom/PBlobStreamChild.h"
+#include "mozilla/dom/PBlobStreamParent.h"
+#include "mozilla/dom/PFileDescriptorSetParent.h"
+#include "mozilla/ipc/InputStreamUtils.h"
+#include "nsCOMPtr.h"
+#include "nsDOMFile.h"
 #include "nsIDOMFile.h"
 #include "nsIInputStream.h"
 #include "nsIIPCSerializableInputStream.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsIRemoteBlob.h"
 #include "nsISeekableStream.h"
-
-#include "mozilla/Monitor.h"
-#include "mozilla/unused.h"
-#include "mozilla/ipc/InputStreamUtils.h"
-#include "mozilla/dom/PFileDescriptorSetParent.h"
-#include "nsDOMFile.h"
+#include "nsNetCID.h"
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
-#include "jsapi.h"
-
-#include "ContentChild.h"
-#include "ContentParent.h"
-#include "nsNetCID.h"
-#include "FileDescriptorSetChild.h"
 
 #define PRIVATE_REMOTE_INPUT_STREAM_IID \
   {0x30c7699f, 0x51d2, 0x48c8, {0xad, 0x56, 0xc0, 0x16, 0xd7, 0x6f, 0x71, 0x27}}
 
+using namespace mozilla;
 using namespace mozilla::dom;
-using namespace mozilla::dom::ipc;
 using namespace mozilla::ipc;
 
 namespace {
 
-/**
- * Ensure that a nsCOMPtr/nsRefPtr is released on the main thread.
- */
+enum ActorType
+{
+  ChildActor,
+  ParentActor
+};
+
+// Ensure that a nsCOMPtr/nsRefPtr is released on the main thread.
 template <template <class> class SmartPtr, class T>
 void
 ProxyReleaseToMainThread(SmartPtr<T>& aDoomed)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
   nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
   NS_ENSURE_TRUE_VOID(mainThread);
 
   if (NS_FAILED(NS_ProxyRelease(mainThread, aDoomed, true))) {
     NS_WARNING("Failed to proxy release to main thread!");
   }
 }
 
-
 class NS_NO_VTABLE IPrivateRemoteInputStream : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(PRIVATE_REMOTE_INPUT_STREAM_IID)
 
   // This will return the underlying stream.
   virtual nsIInputStream*
   BlockAndGetInternalStream() = 0;
@@ -150,40 +149,41 @@ class RemoteInputStream : public nsIInpu
                           public nsISeekableStream,
                           public nsIIPCSerializableInputStream,
                           public IPrivateRemoteInputStream
 {
   mozilla::Monitor mMonitor;
   nsCOMPtr<nsIInputStream> mStream;
   nsCOMPtr<nsIDOMBlob> mSourceBlob;
   nsISeekableStream* mWeakSeekableStream;
-  ActorFlavorEnum mOrigin;
+  ActorType mOrigin;
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
-  RemoteInputStream(nsIDOMBlob* aSourceBlob, ActorFlavorEnum aOrigin)
+  RemoteInputStream(nsIDOMBlob* aSourceBlob, ActorType aOrigin)
   : mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob),
     mWeakSeekableStream(nullptr), mOrigin(aOrigin)
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(aSourceBlob);
   }
 
   void
   Serialize(InputStreamParams& aParams,
             FileDescriptorArray& /* aFileDescriptors */)
   {
     nsCOMPtr<nsIRemoteBlob> remote = do_QueryInterface(mSourceBlob);
     MOZ_ASSERT(remote);
 
-    if (mOrigin == Parent) {
+    if (mOrigin == ParentActor) {
       aParams = RemoteInputStreamParams(
         static_cast<PBlobParent*>(remote->GetPBlob()), nullptr);
     } else {
+      MOZ_ASSERT(mOrigin == ChildActor);
       aParams = RemoteInputStreamParams(
         nullptr, static_cast<PBlobChild*>(remote->GetPBlob()));
     }
   }
 
   bool
   Deserialize(const InputStreamParams& aParams,
               const FileDescriptorArray& /* aFileDescriptors */)
@@ -426,182 +426,102 @@ NS_IMPL_RELEASE(RemoteInputStream)
 NS_INTERFACE_MAP_BEGIN(RemoteInputStream)
   NS_INTERFACE_MAP_ENTRY(nsIInputStream)
   NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream())
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
   NS_INTERFACE_MAP_ENTRY(IPrivateRemoteInputStream)
 NS_INTERFACE_MAP_END
 
-template <ActorFlavorEnum ActorFlavor>
-class InputStreamActor : public BlobTraits<ActorFlavor>::StreamType
+class InputStreamChild MOZ_FINAL
+  : public PBlobStreamChild
 {
   nsRefPtr<RemoteInputStream> mRemoteStream;
 
 public:
-  InputStreamActor(RemoteInputStream* aRemoteStream)
+  InputStreamChild(RemoteInputStream* aRemoteStream)
   : mRemoteStream(aRemoteStream)
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(aRemoteStream);
   }
 
-  InputStreamActor()
+  InputStreamChild()
   {
     MOZ_ASSERT(NS_IsMainThread());
   }
 
 private:
   // This method is only called by the IPDL message machinery.
   virtual bool
   Recv__delete__(const InputStreamParams& aParams,
                  const OptionalFileDescriptorSet& aFDs) MOZ_OVERRIDE;
 };
 
-template <>
-bool
-InputStreamActor<Parent>::Recv__delete__(const InputStreamParams& aParams,
-                                         const OptionalFileDescriptorSet& aFDs)
+class InputStreamParent MOZ_FINAL
+  : public PBlobStreamParent
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mRemoteStream);
-
-  if (aFDs.type() != OptionalFileDescriptorSet::Tvoid_t) {
-    NS_WARNING("Child cannot send FileDescriptors to the parent!");
-    return false;
-  }
-
-  nsTArray<FileDescriptor> fds;
-  nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds);
-  if (!stream) {
-    return false;
-  }
-
-  MOZ_ASSERT(fds.IsEmpty());
+  nsRefPtr<RemoteInputStream> mRemoteStream;
 
-  mRemoteStream->SetStream(stream);
-  return true;
-}
-
-template <>
-bool
-InputStreamActor<Child>::Recv__delete__(const InputStreamParams& aParams,
-                                        const OptionalFileDescriptorSet& aFDs)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mRemoteStream);
-
-  nsTArray<FileDescriptor> fds;
-  if (aFDs.type() == OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
-    FileDescriptorSetChild* fdSetActor =
-      static_cast<FileDescriptorSetChild*>(aFDs.get_PFileDescriptorSetChild());
-    MOZ_ASSERT(fdSetActor);
-
-    fdSetActor->ForgetFileDescriptors(fds);
-    MOZ_ASSERT(!fds.IsEmpty());
-
-    fdSetActor->Send__delete__(fdSetActor);
+public:
+  InputStreamParent(RemoteInputStream* aRemoteStream)
+  : mRemoteStream(aRemoteStream)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(aRemoteStream);
   }
 
-  nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds);
-  if (!stream) {
-    return false;
+  InputStreamParent()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
   }
 
-  mRemoteStream->SetStream(stream);
-  return true;
-}
-
-template <ActorFlavorEnum ActorFlavor>
-inline
-already_AddRefed<nsIDOMBlob>
-GetBlobFromParams(const SlicedBlobConstructorParams& aParams)
-{
-  static_assert(ActorFlavor == Parent,
-                "No other flavor is supported here!");
-
-  BlobParent* actor =
-    const_cast<BlobParent*>(
-      static_cast<const BlobParent*>(aParams.sourceParent()));
-  MOZ_ASSERT(actor);
-
-  return actor->GetBlob();
-}
+private:
+  // This method is only called by the IPDL message machinery.
+  virtual bool
+  Recv__delete__(const InputStreamParams& aParams,
+                 const OptionalFileDescriptorSet& aFDs) MOZ_OVERRIDE;
+};
 
-template <>
-inline
-already_AddRefed<nsIDOMBlob>
-GetBlobFromParams<Child>(const SlicedBlobConstructorParams& aParams)
-{
-  BlobChild* actor =
-    const_cast<BlobChild*>(
-      static_cast<const BlobChild*>(aParams.sourceChild()));
-  MOZ_ASSERT(actor);
-
-  return actor->GetBlob();
-}
-
-inline
-void
-SetBlobOnParams(BlobChild* aActor, SlicedBlobConstructorParams& aParams)
-{
-  aParams.sourceChild() = aActor;
-}
-
-inline
-void
-SetBlobOnParams(BlobParent* aActor, SlicedBlobConstructorParams& aParams)
-{
-  aParams.sourceParent() = aActor;
-}
-
-inline
 nsDOMFileBase*
 ToConcreteBlob(nsIDOMBlob* aBlob)
 {
   // XXX This is only safe so long as all blob implementations in our tree
   //     inherit nsDOMFileBase. If that ever changes then this will need to grow
   //     a real interface or something.
   return static_cast<nsDOMFileBase*>(aBlob);
 }
 
 } // anonymous namespace
 
-namespace mozilla {
-namespace dom {
-namespace ipc {
-
 // Each instance of this class will be dispatched to the network stream thread
 // pool to run the first time where it will open the file input stream. It will
 // then dispatch itself back to the main thread to send the child process its
 // response (assuming that the child has not crashed). The runnable will then
 // dispatch itself to the thread pool again in order to close the file input
 // stream.
-class BlobTraits<Parent>::BaseType::OpenStreamRunnable : public nsRunnable
+class BlobParent::OpenStreamRunnable MOZ_FINAL
+  : public nsRunnable
 {
   friend class nsRevocableEventPtr<OpenStreamRunnable>;
 
-  typedef BlobTraits<Parent> TraitsType;
-  typedef TraitsType::BaseType BlobActorType;
-  typedef TraitsType::StreamType BlobStreamProtocolType;
-
   // Only safe to access these pointers if mRevoked is false!
-  BlobActorType* mBlobActor;
-  BlobStreamProtocolType* mStreamActor;
+  BlobParent* mBlobActor;
+  PBlobStreamParent* mStreamActor;
 
   nsCOMPtr<nsIInputStream> mStream;
   nsCOMPtr<nsIIPCSerializableInputStream> mSerializable;
   nsCOMPtr<nsIEventTarget> mTarget;
 
   bool mRevoked;
   bool mClosing;
 
 public:
-  OpenStreamRunnable(BlobActorType* aBlobActor,
-                     BlobStreamProtocolType* aStreamActor,
+  OpenStreamRunnable(BlobParent* aBlobActor,
+                     PBlobStreamParent* aStreamActor,
                      nsIInputStream* aStream,
                      nsIIPCSerializableInputStream* aSerializable,
                      nsIEventTarget* aTarget)
   : mBlobActor(aBlobActor), mStreamActor(aStreamActor), mStream(aStream),
     mSerializable(aSerializable), mTarget(aTarget), mRevoked(false),
     mClosing(false)
   {
     MOZ_ASSERT(NS_IsMainThread());
@@ -728,36 +648,36 @@ private:
       nsAutoTArray<FileDescriptor, 10> fds;
       serializable->Serialize(params, fds);
 
       MOZ_ASSERT(params.type() != InputStreamParams::T__None);
 
       PFileDescriptorSetParent* fdSet = nullptr;
 
       if (!fds.IsEmpty()) {
-        Blob<Parent>* blob = static_cast<Blob<Parent>*>(mBlobActor);
+        auto* manager = static_cast<ContentParent*>(mBlobActor->Manager());
+        MOZ_ASSERT(manager);
 
-        MOZ_ASSERT(blob->Manager());
-
-        fdSet = blob->Manager()->SendPFileDescriptorSetConstructor(fds[0]);
+        fdSet = manager->SendPFileDescriptorSetConstructor(fds[0]);
         if (fdSet) {
           for (uint32_t index = 1; index < fds.Length(); index++) {
             unused << fdSet->SendAddFileDescriptor(fds[index]);
           }
         }
       }
 
       OptionalFileDescriptorSet optionalFDs;
       if (fdSet) {
         optionalFDs = fdSet;
       } else {
         optionalFDs = mozilla::void_t();
       }
 
-      unused << mStreamActor->Send__delete__(mStreamActor, params, optionalFDs);
+      unused <<
+        PBlobStreamParent::Send__delete__(mStreamActor, params, optionalFDs);
 
       mBlobActor->NoteRunnableCompleted(this);
 
 #ifdef DEBUG
       mBlobActor = nullptr;
       mStreamActor = nullptr;
 #endif
     }
@@ -769,513 +689,465 @@ private:
 
     nsresult rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 };
 
-BlobTraits<Parent>::BaseType::BaseType()
-{
-}
+/*******************************************************************************
+ * BlobChild::RemoteBlob Declaration
+ ******************************************************************************/
 
-BlobTraits<Parent>::BaseType::~BaseType()
-{
-}
-
-void
-BlobTraits<Parent>::BaseType::NoteRunnableCompleted(
-                    BlobTraits<Parent>::BaseType::OpenStreamRunnable* aRunnable)
+class BlobChild::RemoteBlob MOZ_FINAL
+  : public nsDOMFile
+  , public nsIRemoteBlob
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  class StreamHelper;
+  class SliceHelper;
 
-  for (uint32_t index = 0; index < mOpenStreamRunnables.Length(); index++) {
-    nsRevocableEventPtr<BaseType::OpenStreamRunnable>& runnable =
-      mOpenStreamRunnables[index];
+  BlobChild* mActor;
 
-    if (runnable.get() == aRunnable) {
-      runnable.Forget();
-      mOpenStreamRunnables.RemoveElementAt(index);
-      return;
-    }
+public:
+  RemoteBlob(const nsAString& aName,
+             const nsAString& aContentType,
+             uint64_t aLength,
+             uint64_t aModDate)
+    : nsDOMFile(aName, aContentType, aLength, aModDate)
+    , mActor(nullptr)
+  {
+    mImmutable = true;
+  }
+
+  RemoteBlob(const nsAString& aContentType, uint64_t aLength)
+    : nsDOMFile(aContentType, aLength)
+    , mActor(nullptr)
+  {
+    mImmutable = true;
   }
 
-  MOZ_CRASH("Runnable not in our array!");
-}
-
-template <ActorFlavorEnum ActorFlavor>
-struct RemoteBlobBase;
+  RemoteBlob()
+    : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
+    , mActor(nullptr)
+  {
+    mImmutable = true;
+  }
 
-template <>
-struct RemoteBlobBase<Parent>
-{
-  InputStreamParams mInputStreamParams;
-};
+  void
+  SetActor(BlobChild* aActor)
+  {
+    MOZ_ASSERT(!aActor || !mActor);
+    mActor = aActor;
+  }
 
-template <>
-struct RemoteBlobBase<Child>
-{ };
+  NS_DECL_ISUPPORTS_INHERITED
+
+  virtual already_AddRefed<nsIDOMBlob>
+  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
+              MOZ_OVERRIDE;
 
-template <ActorFlavorEnum ActorFlavor>
-class RemoteBlob : public RemoteBlobBase<ActorFlavor>,
-                   public nsDOMFile,
-                   public nsIRemoteBlob
-{
-public:
-  typedef RemoteBlob<ActorFlavor> SelfType;
-  typedef Blob<ActorFlavor> ActorType;
-  typedef InputStreamActor<ActorFlavor> StreamActorType;
-  typedef typename ActorType::ConstructorParamsType ConstructorParamsType;
+  NS_IMETHOD
+  GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
+
+  NS_IMETHOD
+  GetLastModifiedDate(JSContext* cx,
+                      JS::MutableHandle<JS::Value> aLastModifiedDate)
+                      MOZ_OVERRIDE;
+
+  virtual void*
+  GetPBlob() MOZ_OVERRIDE;
 
 private:
-  ActorType* mActor;
-
-  virtual ~RemoteBlob()
+  ~RemoteBlob()
   {
     if (mActor) {
       mActor->NoteDyingRemoteBlob();
     }
   }
+};
+
+class BlobChild::RemoteBlob::StreamHelper MOZ_FINAL
+  : public nsRunnable
+{
+  mozilla::Monitor mMonitor;
+  BlobChild* mActor;
+  nsCOMPtr<nsIDOMBlob> mSourceBlob;
+  nsRefPtr<RemoteInputStream> mInputStream;
+  bool mDone;
+
+public:
+  StreamHelper(BlobChild* aActor, nsIDOMBlob* aSourceBlob)
+    : mMonitor("BlobChild::RemoteBlob::StreamHelper::mMonitor")
+    , mActor(aActor)
+    , mSourceBlob(aSourceBlob)
+    , mDone(false)
+  {
+    // This may be created on any thread.
+    MOZ_ASSERT(aActor);
+    MOZ_ASSERT(aSourceBlob);
+  }
 
   nsresult
-  GetInternalStreamViaHelper(nsIInputStream** aStream)
+  GetStream(nsIInputStream** aInputStream)
   {
-    if (!mActor) {
+    // This may be called on any thread.
+    MOZ_ASSERT(aInputStream);
+    MOZ_ASSERT(mActor);
+    MOZ_ASSERT(!mInputStream);
+    MOZ_ASSERT(!mDone);
+
+    if (NS_IsMainThread()) {
+      RunInternal(false);
+    }
+    else {
+      nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+      NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
+
+      nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      {
+        MonitorAutoLock lock(mMonitor);
+        while (!mDone) {
+          lock.Wait();
+        }
+      }
+    }
+
+    MOZ_ASSERT(!mActor);
+    MOZ_ASSERT(mDone);
+
+    if (!mInputStream) {
       return NS_ERROR_UNEXPECTED;
     }
 
-    nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
-    return helper->GetStream(aStream);
+    mInputStream.forget(aInputStream);
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    RunInternal(true);
+    return NS_OK;
   }
 
-  class StreamHelper : public nsRunnable
+private:
+  void
+  RunInternal(bool aNotify)
   {
-    typedef Blob<ActorFlavor> ActorType;
-    typedef InputStreamActor<ActorFlavor> StreamActorType;
-
-    mozilla::Monitor mMonitor;
-    ActorType* mActor;
-    nsCOMPtr<nsIDOMBlob> mSourceBlob;
-    nsRefPtr<RemoteInputStream> mInputStream;
-    bool mDone;
-
-  public:
-    StreamHelper(ActorType* aActor, nsIDOMBlob* aSourceBlob)
-    : mMonitor("RemoteBlob::StreamHelper::mMonitor"), mActor(aActor),
-      mSourceBlob(aSourceBlob), mDone(false)
-    {
-      // This may be created on any thread.
-      MOZ_ASSERT(aActor);
-      MOZ_ASSERT(aSourceBlob);
-    }
-
-    nsresult
-    GetStream(nsIInputStream** aInputStream)
-    {
-      // This may be called on any thread.
-      MOZ_ASSERT(aInputStream);
-      MOZ_ASSERT(mActor);
-      MOZ_ASSERT(!mInputStream);
-      MOZ_ASSERT(!mDone);
-
-      if (NS_IsMainThread()) {
-        RunInternal(false);
-      }
-      else {
-        nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-        NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
-
-        nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        {
-          MonitorAutoLock lock(mMonitor);
-          while (!mDone) {
-            lock.Wait();
-          }
-        }
-      }
-
-      MOZ_ASSERT(!mActor);
-      MOZ_ASSERT(mDone);
-
-      if (!mInputStream) {
-        return NS_ERROR_UNEXPECTED;
-      }
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(mActor);
+    MOZ_ASSERT(!mInputStream);
+    MOZ_ASSERT(!mDone);
 
-      mInputStream.forget(aInputStream);
-      return NS_OK;
-    }
-
-    NS_IMETHOD
-    Run()
-    {
-      MOZ_ASSERT(NS_IsMainThread());
-      RunInternal(true);
-      return NS_OK;
-    }
-
-  private:
-    void
-    RunInternal(bool aNotify)
-    {
-      MOZ_ASSERT(NS_IsMainThread());
-      MOZ_ASSERT(mActor);
-      MOZ_ASSERT(!mInputStream);
-      MOZ_ASSERT(!mDone);
-
-      nsRefPtr<RemoteInputStream> stream = new RemoteInputStream(mSourceBlob,
-                                                                 ActorFlavor);
-
-      StreamActorType* streamActor = new StreamActorType(stream);
-      if (mActor->SendPBlobStreamConstructor(streamActor)) {
-        stream.swap(mInputStream);
-      }
-
-      mActor = nullptr;
+    nsRefPtr<RemoteInputStream> stream =
+      new RemoteInputStream(mSourceBlob, ChildActor);
 
-      if (aNotify) {
-        MonitorAutoLock lock(mMonitor);
-        mDone = true;
-        lock.Notify();
-      }
-      else {
-        mDone = true;
-      }
-    }
-  };
-
-  class SliceHelper : public nsRunnable
-  {
-    typedef Blob<ActorFlavor> ActorType;
-
-    mozilla::Monitor mMonitor;
-    ActorType* mActor;
-    nsCOMPtr<nsIDOMBlob> mSlice;
-    uint64_t mStart;
-    uint64_t mLength;
-    nsString mContentType;
-    bool mDone;
-
-  public:
-    SliceHelper(ActorType* aActor)
-    : mMonitor("RemoteBlob::SliceHelper::mMonitor"), mActor(aActor), mStart(0),
-      mLength(0), mDone(false)
-    {
-      // This may be created on any thread.
-      MOZ_ASSERT(aActor);
+    InputStreamChild* streamActor = new InputStreamChild(stream);
+    if (mActor->SendPBlobStreamConstructor(streamActor)) {
+      stream.swap(mInputStream);
     }
 
-    nsresult
-    GetSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
-             nsIDOMBlob** aSlice)
-    {
-      // This may be called on any thread.
-      MOZ_ASSERT(aSlice);
-      MOZ_ASSERT(mActor);
-      MOZ_ASSERT(!mSlice);
-      MOZ_ASSERT(!mDone);
+    mActor = nullptr;
 
-      mStart = aStart;
-      mLength = aLength;
-      mContentType = aContentType;
+    if (aNotify) {
+      MonitorAutoLock lock(mMonitor);
+      mDone = true;
+      lock.Notify();
+    }
+    else {
+      mDone = true;
+    }
+  }
+};
+
+class BlobChild::RemoteBlob::SliceHelper MOZ_FINAL
+  : public nsRunnable
+{
+  mozilla::Monitor mMonitor;
+  BlobChild* mActor;
+  nsCOMPtr<nsIDOMBlob> mSlice;
+  uint64_t mStart;
+  uint64_t mLength;
+  nsString mContentType;
+  bool mDone;
 
-      if (NS_IsMainThread()) {
-        RunInternal(false);
-      }
-      else {
-        nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-        NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
+public:
+  SliceHelper(BlobChild* aActor)
+    : mMonitor("BlobChild::RemoteBlob::SliceHelper::mMonitor")
+    , mActor(aActor)
+    , mStart(0)
+    , mLength(0)
+    , mDone(false)
+  {
+    // This may be created on any thread.
+    MOZ_ASSERT(aActor);
+  }
 
-        nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
-        NS_ENSURE_SUCCESS(rv, rv);
+  nsresult
+  GetSlice(uint64_t aStart,
+           uint64_t aLength,
+           const nsAString& aContentType,
+           nsIDOMBlob** aSlice)
+  {
+    // This may be called on any thread.
+    MOZ_ASSERT(aSlice);
+    MOZ_ASSERT(mActor);
+    MOZ_ASSERT(!mSlice);
+    MOZ_ASSERT(!mDone);
 
-        {
-          MonitorAutoLock lock(mMonitor);
-          while (!mDone) {
-            lock.Wait();
-          }
+    mStart = aStart;
+    mLength = aLength;
+    mContentType = aContentType;
+
+    if (NS_IsMainThread()) {
+      RunInternal(false);
+    }
+    else {
+      nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+      NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
+
+      nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      {
+        MonitorAutoLock lock(mMonitor);
+        while (!mDone) {
+          lock.Wait();
         }
       }
-
-      MOZ_ASSERT(!mActor);
-      MOZ_ASSERT(mDone);
-
-      if (!mSlice) {
-        return NS_ERROR_UNEXPECTED;
-      }
-
-      mSlice.forget(aSlice);
-      return NS_OK;
-    }
-
-    NS_IMETHOD
-    Run()
-    {
-      MOZ_ASSERT(NS_IsMainThread());
-      RunInternal(true);
-      return NS_OK;
     }
 
-  private:
-    void
-    RunInternal(bool aNotify)
-    {
-      MOZ_ASSERT(NS_IsMainThread());
-      MOZ_ASSERT(mActor);
-      MOZ_ASSERT(!mSlice);
-      MOZ_ASSERT(!mDone);
-
-      NS_ENSURE_TRUE_VOID(mActor->Manager());
-
-      NormalBlobConstructorParams normalParams;
-      normalParams.contentType() = mContentType;
-      normalParams.length() = mLength;
-
-      typename ActorType::ConstructorParamsType params;
-      ActorType::BaseType::SetBlobConstructorParams(params, normalParams);
-
-      ActorType* newActor = ActorType::Create(mActor->Manager(), params);
-      MOZ_ASSERT(newActor);
-
-      SlicedBlobConstructorParams slicedParams;
-      slicedParams.contentType() = mContentType;
-      slicedParams.begin() = mStart;
-      slicedParams.end() = mStart + mLength;
-      SetBlobOnParams(mActor, slicedParams);
-
-      typename ActorType::OtherSideConstructorParamsType otherSideParams;
-      ActorType::BaseType::SetBlobConstructorParams(otherSideParams,
-                                                    slicedParams);
-
-      if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) {
-        mSlice = newActor->GetBlob();
-      }
-
-      mActor = nullptr;
+    MOZ_ASSERT(!mActor);
+    MOZ_ASSERT(mDone);
 
-      if (aNotify) {
-        MonitorAutoLock lock(mMonitor);
-        mDone = true;
-        lock.Notify();
-      }
-      else {
-        mDone = true;
-      }
-    }
-  };
-
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-
-  RemoteBlob(const nsAString& aName, const nsAString& aContentType,
-             uint64_t aLength, uint64_t aModDate)
-  : nsDOMFile(aName, aContentType, aLength, aModDate), mActor(nullptr)
-  {
-    mImmutable = true;
-  }
-
-  RemoteBlob(const nsAString& aContentType, uint64_t aLength)
-  : nsDOMFile(aContentType, aLength), mActor(nullptr)
-  {
-    mImmutable = true;
-  }
-
-  RemoteBlob()
-  : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
-  , mActor(nullptr)
-  {
-    mImmutable = true;
-  }
-
-  void
-  SetActor(ActorType* aActor)
-  {
-    MOZ_ASSERT(!aActor || !mActor);
-    mActor = aActor;
-  }
-
-  void
-  MaybeSetInputStream(const ConstructorParamsType& aParams);
-
-  virtual already_AddRefed<nsIDOMBlob>
-  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
-              MOZ_OVERRIDE
-  {
-    if (!mActor) {
-      return nullptr;
+    if (!mSlice) {
+      return NS_ERROR_UNEXPECTED;
     }
 
-    nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
-
-    nsCOMPtr<nsIDOMBlob> slice;
-    nsresult rv =
-      helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
-    NS_ENSURE_SUCCESS(rv, nullptr);
-
-    return slice.forget();
+    mSlice.forget(aSlice);
+    return NS_OK;
   }
 
   NS_IMETHOD
-  GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
-
-  virtual void*
-  GetPBlob() MOZ_OVERRIDE
+  Run()
   {
-    return static_cast<typename ActorType::ProtocolType*>(mActor);
+    MOZ_ASSERT(NS_IsMainThread());
+    RunInternal(true);
+    return NS_OK;
   }
 
-  NS_IMETHOD
-  GetLastModifiedDate(JSContext* cx,
-                      JS::MutableHandle<JS::Value> aLastModifiedDate) MOZ_OVERRIDE
+private:
+  void
+  RunInternal(bool aNotify)
   {
-    if (IsDateUnknown()) {
-      aLastModifiedDate.setNull();
-    } else {
-      JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate);
-      if (!date) {
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
-      aLastModifiedDate.setObject(*date);
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(mActor);
+    MOZ_ASSERT(!mSlice);
+    MOZ_ASSERT(!mDone);
+
+    NS_ENSURE_TRUE_VOID(mActor->Manager());
+
+    NormalBlobConstructorParams normalParams;
+    normalParams.contentType() = mContentType;
+    normalParams.length() = mLength;
+
+    auto* manager = static_cast<ContentChild*>(mActor->Manager());
+    MOZ_ASSERT(manager);
+
+    BlobChild* newActor = BlobChild::Create(manager, normalParams);
+    MOZ_ASSERT(newActor);
+
+    SlicedBlobConstructorParams slicedParams;
+    slicedParams.contentType() = mContentType;
+    slicedParams.begin() = mStart;
+    slicedParams.end() = mStart + mLength;
+    slicedParams.sourceChild() = mActor;
+
+    ParentBlobConstructorParams otherSideParams;
+    otherSideParams.blobParams() = slicedParams;
+    otherSideParams.optionalInputStreamParams() = mozilla::void_t();
+
+    if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) {
+      mSlice = newActor->GetBlob();
     }
-    return NS_OK;
+
+    mActor = nullptr;
+
+    if (aNotify) {
+      MonitorAutoLock lock(mMonitor);
+      mDone = true;
+      lock.Notify();
+    }
+    else {
+      mDone = true;
+    }
   }
 };
 
-template <>
-void
-RemoteBlob<Parent>::MaybeSetInputStream(const ConstructorParamsType& aParams)
+/*******************************************************************************
+ * BlobChild::RemoteBlob Implementation
+ ******************************************************************************/
+
+NS_IMPL_ISUPPORTS_INHERITED1(BlobChild::RemoteBlob, nsDOMFile, nsIRemoteBlob)
+
+already_AddRefed<nsIDOMBlob>
+BlobChild::
+RemoteBlob::CreateSlice(uint64_t aStart,
+                        uint64_t aLength,
+                        const nsAString& aContentType)
 {
-  if (aParams.optionalInputStreamParams().type() ==
-      OptionalInputStreamParams::TInputStreamParams) {
-    mInputStreamParams =
-      aParams.optionalInputStreamParams().get_InputStreamParams();
+  if (!mActor) {
+    return nullptr;
   }
+
+  nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
+
+  nsCOMPtr<nsIDOMBlob> slice;
+  nsresult rv =
+    helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  return slice.forget();
 }
 
-template <>
-void
-RemoteBlob<Child>::MaybeSetInputStream(const ConstructorParamsType& aParams)
+NS_IMETHODIMP
+BlobChild::
+RemoteBlob::GetInternalStream(nsIInputStream** aStream)
 {
-  // Nothing needed on the child side!
+  if (!mActor) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
+  return helper->GetStream(aStream);
 }
 
-template <>
 NS_IMETHODIMP
-RemoteBlob<Parent>::GetInternalStream(nsIInputStream** aStream)
+BlobChild::
+RemoteBlob::GetLastModifiedDate(JSContext* cx,
+                                JS::MutableHandle<JS::Value> aLastModifiedDate)
 {
-  if (mInputStreamParams.type() != InputStreamParams::T__None) {
-    nsTArray<FileDescriptor> fds;
-    nsCOMPtr<nsIInputStream> realStream =
-      DeserializeInputStream(mInputStreamParams, fds);
-    if (!realStream) {
-      NS_WARNING("Failed to deserialize stream!");
-      return NS_ERROR_UNEXPECTED;
+  if (IsDateUnknown()) {
+    aLastModifiedDate.setNull();
+  } else {
+    JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate);
+    if (!date) {
+      return NS_ERROR_OUT_OF_MEMORY;
     }
-
-    nsCOMPtr<nsIInputStream> stream =
-      new BlobInputStreamTether(realStream, this);
-    stream.forget(aStream);
-    return NS_OK;
+    aLastModifiedDate.setObject(*date);
   }
-
-  return GetInternalStreamViaHelper(aStream);
+  return NS_OK;
 }
 
-template <>
-NS_IMETHODIMP
-RemoteBlob<Child>::GetInternalStream(nsIInputStream** aStream)
+void*
+BlobChild::
+RemoteBlob::GetPBlob()
 {
-  return GetInternalStreamViaHelper(aStream);
+  return static_cast<PBlobChild*>(mActor);
 }
 
-template <ActorFlavorEnum ActorFlavor>
-Blob<ActorFlavor>::Blob(ContentManager* aManager, nsIDOMBlob* aBlob)
-: mBlob(aBlob), mRemoteBlob(nullptr), mOwnsBlob(true)
-, mBlobIsFile(false), mManager(aManager)
+/*******************************************************************************
+ * BlobChild
+ ******************************************************************************/
+
+BlobChild::BlobChild(ContentChild* aManager, nsIDOMBlob* aBlob)
+  : mBlob(aBlob)
+  , mRemoteBlob(nullptr)
+  , mStrongManager(aManager)
+  , mOwnsBlob(true)
+  , mBlobIsFile(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aManager);
   MOZ_ASSERT(aBlob);
-  MOZ_ASSERT(aManager);
+
   aBlob->AddRef();
 
   nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
   mBlobIsFile = !!file;
 }
 
-template <ActorFlavorEnum ActorFlavor>
-Blob<ActorFlavor>::Blob(ContentManager* aManager,
-                        const ConstructorParamsType& aParams)
-: mBlob(nullptr), mRemoteBlob(nullptr), mOwnsBlob(false)
-, mBlobIsFile(false), mManager(aManager)
+BlobChild::BlobChild(ContentChild* aManager,
+                     const ChildBlobConstructorParams& aParams)
+  : mBlob(nullptr)
+  , mRemoteBlob(nullptr)
+  , mStrongManager(aManager)
+  , mOwnsBlob(false)
+  , mBlobIsFile(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aManager);
 
-  ChildBlobConstructorParams::Type paramType =
-    BaseType::GetBlobConstructorParams(aParams).type();
+  ChildBlobConstructorParams::Type paramsType = aParams.type();
 
   mBlobIsFile =
-    paramType == ChildBlobConstructorParams::TFileBlobConstructorParams ||
-    paramType == ChildBlobConstructorParams::TMysteryBlobConstructorParams;
+    paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams ||
+    paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams;
 
-  nsRefPtr<RemoteBlobType> remoteBlob = CreateRemoteBlob(aParams);
+  nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams);
   MOZ_ASSERT(remoteBlob);
 
   remoteBlob->SetActor(this);
-  remoteBlob->MaybeSetInputStream(aParams);
   remoteBlob.forget(&mRemoteBlob);
 
   mBlob = mRemoteBlob;
   mOwnsBlob = true;
 }
 
-template <ActorFlavorEnum ActorFlavor>
-Blob<ActorFlavor>*
-Blob<ActorFlavor>::Create(ContentManager* aManager,
-                          const ConstructorParamsType& aParams)
+BlobChild::~BlobChild()
+{
+}
+
+BlobChild*
+BlobChild::Create(ContentChild* aManager,
+                  const ChildBlobConstructorParams& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aManager);
 
-  const ChildBlobConstructorParams& blobParams =
-    BaseType::GetBlobConstructorParams(aParams);
-
-  switch (blobParams.type()) {
+  switch (aParams.type()) {
     case ChildBlobConstructorParams::TNormalBlobConstructorParams:
     case ChildBlobConstructorParams::TFileBlobConstructorParams:
     case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
-      return new Blob<ActorFlavor>(aManager, aParams);
+      return new BlobChild(aManager, aParams);
 
     case ChildBlobConstructorParams::TSlicedBlobConstructorParams: {
       const SlicedBlobConstructorParams& params =
-        blobParams.get_SlicedBlobConstructorParams();
+        aParams.get_SlicedBlobConstructorParams();
 
-      nsCOMPtr<nsIDOMBlob> source = GetBlobFromParams<ActorFlavor>(params);
+      auto* actor =
+        const_cast<BlobChild*>(
+          static_cast<const BlobChild*>(params.sourceChild()));
+      MOZ_ASSERT(actor);
+
+      nsCOMPtr<nsIDOMBlob> source = actor->GetBlob();
       MOZ_ASSERT(source);
 
       nsCOMPtr<nsIDOMBlob> slice;
       nsresult rv =
         source->Slice(params.begin(), params.end(), params.contentType(), 3,
                       getter_AddRefs(slice));
       NS_ENSURE_SUCCESS(rv, nullptr);
 
-      return new Blob<ActorFlavor>(aManager, slice);
+      return new BlobChild(aManager, slice);
     }
 
     default:
       MOZ_CRASH("Unknown params!");
   }
 
   return nullptr;
 }
 
-template <ActorFlavorEnum ActorFlavor>
 already_AddRefed<nsIDOMBlob>
-Blob<ActorFlavor>::GetBlob()
+BlobChild::GetBlob()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mBlob);
 
   nsCOMPtr<nsIDOMBlob> blob;
 
   // Remote blobs are held alive until the first call to GetBlob. Thereafter we
   // only hold a weak reference. Normal blobs are held alive until the actor is
@@ -1288,151 +1160,944 @@ Blob<ActorFlavor>::GetBlob()
     blob = mBlob;
   }
 
   MOZ_ASSERT(blob);
 
   return blob.forget();
 }
 
-template <ActorFlavorEnum ActorFlavor>
 bool
-Blob<ActorFlavor>::SetMysteryBlobInfo(const nsString& aName,
-                                      const nsString& aContentType,
-                                      uint64_t aLength,
-                                      uint64_t aLastModifiedDate)
+BlobChild::SetMysteryBlobInfo(const nsString& aName,
+                              const nsString& aContentType,
+                              uint64_t aLength,
+                              uint64_t aLastModifiedDate)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mBlob);
   MOZ_ASSERT(mRemoteBlob);
   MOZ_ASSERT(aLastModifiedDate != UINT64_MAX);
 
-  ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType,
-                                     aLength, aLastModifiedDate);
+  ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength,
+                                     aLastModifiedDate);
 
-  FileBlobConstructorParams params(aName, aContentType,
-                                   aLength, aLastModifiedDate);
-  return ProtocolType::SendResolveMystery(params);
+  FileBlobConstructorParams params(aName, aContentType, aLength,
+                                   aLastModifiedDate);
+  return SendResolveMystery(params);
 }
 
-template <ActorFlavorEnum ActorFlavor>
 bool
-Blob<ActorFlavor>::SetMysteryBlobInfo(const nsString& aContentType,
-                                      uint64_t aLength)
+BlobChild::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mBlob);
   MOZ_ASSERT(mRemoteBlob);
 
   nsString voidString;
   voidString.SetIsVoid(true);
 
-  ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType,
-                                     aLength, UINT64_MAX);
+  ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength,
+                                     UINT64_MAX);
 
   NormalBlobConstructorParams params(aContentType, aLength);
-  return ProtocolType::SendResolveMystery(params);
+  return SendResolveMystery(params);
 }
 
-template <ActorFlavorEnum ActorFlavor>
-already_AddRefed<typename Blob<ActorFlavor>::RemoteBlobType>
-Blob<ActorFlavor>::CreateRemoteBlob(const ConstructorParamsType& aParams)
+already_AddRefed<BlobChild::RemoteBlob>
+BlobChild::CreateRemoteBlob(const ChildBlobConstructorParams& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  const ChildBlobConstructorParams& blobParams =
-    BaseType::GetBlobConstructorParams(aParams);
+  nsRefPtr<RemoteBlob> remoteBlob;
 
-  nsRefPtr<RemoteBlobType> remoteBlob;
-
-  switch (blobParams.type()) {
+  switch (aParams.type()) {
     case ChildBlobConstructorParams::TNormalBlobConstructorParams: {
       const NormalBlobConstructorParams& params =
-        blobParams.get_NormalBlobConstructorParams();
-      remoteBlob = new RemoteBlobType(params.contentType(), params.length());
+        aParams.get_NormalBlobConstructorParams();
+      remoteBlob = new RemoteBlob(params.contentType(), params.length());
       break;
     }
 
     case ChildBlobConstructorParams::TFileBlobConstructorParams: {
       const FileBlobConstructorParams& params =
-        blobParams.get_FileBlobConstructorParams();
+        aParams.get_FileBlobConstructorParams();
       remoteBlob =
-        new RemoteBlobType(params.name(), params.contentType(),
-                           params.length(), params.modDate());
+        new RemoteBlob(params.name(), params.contentType(), params.length(),
+                       params.modDate());
       break;
     }
 
     case ChildBlobConstructorParams::TMysteryBlobConstructorParams: {
-      remoteBlob = new RemoteBlobType();
+      remoteBlob = new RemoteBlob();
       break;
     }
 
     default:
       MOZ_CRASH("Unknown params!");
   }
 
   MOZ_ASSERT(remoteBlob);
 
   if (NS_FAILED(remoteBlob->SetMutable(false))) {
     MOZ_CRASH("Failed to make remote blob immutable!");
   }
 
   return remoteBlob.forget();
 }
 
-template <ActorFlavorEnum ActorFlavor>
 void
-Blob<ActorFlavor>::NoteDyingRemoteBlob()
+BlobChild::NoteDyingRemoteBlob()
 {
   MOZ_ASSERT(mBlob);
   MOZ_ASSERT(mRemoteBlob);
   MOZ_ASSERT(!mOwnsBlob);
 
   // This may be called on any thread due to the fact that RemoteBlob is
   // designed to be passed between threads. We must start the shutdown process
   // on the main thread, so we proxy here if necessary.
   if (!NS_IsMainThread()) {
     nsCOMPtr<nsIRunnable> runnable =
-      NS_NewNonOwningRunnableMethod(this,
-                                    &Blob<ActorFlavor>::NoteDyingRemoteBlob);
+      NS_NewNonOwningRunnableMethod(this, &BlobChild::NoteDyingRemoteBlob);
     if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
       MOZ_ASSERT(false, "Should never fail!");
     }
 
     return;
   }
 
   // Must do this before calling Send__delete__ or we'll crash there trying to
   // access a dangling pointer.
   mBlob = nullptr;
   mRemoteBlob = nullptr;
 
-  mozilla::unused << ProtocolType::Send__delete__(this);
+  PBlobChild::Send__delete__(this);
 }
 
-template <ActorFlavorEnum ActorFlavor>
 void
-Blob<ActorFlavor>::ActorDestroy(ActorDestroyReason aWhy)
+BlobChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mRemoteBlob) {
     mRemoteBlob->SetActor(nullptr);
   }
 
   if (mBlob && mOwnsBlob) {
     mBlob->Release();
   }
 
-  mManager = nullptr;
+  mStrongManager = nullptr;
+}
+
+PBlobStreamChild*
+BlobChild::AllocPBlobStreamChild()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  return new InputStreamChild();
+}
+
+bool
+BlobChild::RecvPBlobStreamConstructor(PBlobStreamChild* aActor)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aActor);
+  MOZ_ASSERT(mBlob);
+  MOZ_ASSERT(!mRemoteBlob);
+
+  nsCOMPtr<nsIInputStream> stream;
+  nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
+    do_QueryInterface(stream);
+  if (!serializable) {
+    MOZ_ASSERT(false, "Must be serializable!");
+    return false;
+  }
+
+  InputStreamParams params;
+  nsTArray<FileDescriptor> fds;
+  serializable->Serialize(params, fds);
+
+  MOZ_ASSERT(params.type() != InputStreamParams::T__None);
+  MOZ_ASSERT(fds.IsEmpty());
+
+  return aActor->Send__delete__(aActor, params, mozilla::void_t());
+}
+
+bool
+BlobChild::DeallocPBlobStreamChild(PBlobStreamChild* aActor)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  delete static_cast<InputStreamChild*>(aActor);
+  return true;
+}
+
+bool
+BlobChild::RecvResolveMystery(const ResolveMysteryParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mBlob);
+  MOZ_ASSERT(!mRemoteBlob);
+  MOZ_ASSERT(mOwnsBlob);
+
+  if (!mBlobIsFile) {
+    MOZ_ASSERT(false, "Must always be a file!");
+    return false;
+  }
+
+  nsDOMFileBase* blob = ToConcreteBlob(mBlob);
+
+  switch (aParams.type()) {
+    case ResolveMysteryParams::TNormalBlobConstructorParams: {
+      const NormalBlobConstructorParams& params =
+        aParams.get_NormalBlobConstructorParams();
+      nsString voidString;
+      voidString.SetIsVoid(true);
+      blob->SetLazyData(voidString, params.contentType(), params.length(),
+                        UINT64_MAX);
+      break;
+    }
+
+    case ResolveMysteryParams::TFileBlobConstructorParams: {
+      const FileBlobConstructorParams& params =
+        aParams.get_FileBlobConstructorParams();
+      blob->SetLazyData(params.name(), params.contentType(), params.length(),
+                        params.modDate());
+      break;
+    }
+
+    default:
+      MOZ_CRASH("Unknown params!");
+  }
+
+  return true;
 }
 
-template <ActorFlavorEnum ActorFlavor>
+/*******************************************************************************
+ * BlobParent::RemoteBlob Declaration
+ ******************************************************************************/
+
+class BlobParent::RemoteBlob MOZ_FINAL
+  : public nsDOMFile
+  , public nsIRemoteBlob
+{
+  class StreamHelper;
+  class SliceHelper;
+
+  BlobParent* mActor;
+  InputStreamParams mInputStreamParams;
+
+public:
+  RemoteBlob(const nsAString& aName,
+             const nsAString& aContentType,
+             uint64_t aLength,
+             uint64_t aModDate)
+    : nsDOMFile(aName, aContentType, aLength, aModDate)
+    , mActor(nullptr)
+  {
+    mImmutable = true;
+  }
+
+  RemoteBlob(const nsAString& aContentType, uint64_t aLength)
+    : nsDOMFile(aContentType, aLength)
+    , mActor(nullptr)
+  {
+    mImmutable = true;
+  }
+
+  RemoteBlob()
+    : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
+    , mActor(nullptr)
+  {
+    mImmutable = true;
+  }
+
+  void
+  SetActor(BlobParent* aActor)
+  {
+    MOZ_ASSERT(!aActor || !mActor);
+    mActor = aActor;
+  }
+
+  void
+  MaybeSetInputStream(const ParentBlobConstructorParams& aParams)
+  {
+    if (aParams.optionalInputStreamParams().type() ==
+        OptionalInputStreamParams::TInputStreamParams) {
+      mInputStreamParams =
+        aParams.optionalInputStreamParams().get_InputStreamParams();
+    }
+  }
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  virtual already_AddRefed<nsIDOMBlob>
+  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
+              MOZ_OVERRIDE;
+
+  NS_IMETHOD
+  GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
+
+  NS_IMETHOD
+  GetLastModifiedDate(JSContext* cx,
+                      JS::MutableHandle<JS::Value> aLastModifiedDate)
+                      MOZ_OVERRIDE;
+
+  virtual void*
+  GetPBlob() MOZ_OVERRIDE;
+
+private:
+  ~RemoteBlob()
+  {
+    if (mActor) {
+      mActor->NoteDyingRemoteBlob();
+    }
+  }
+};
+
+class BlobParent::RemoteBlob::StreamHelper MOZ_FINAL
+  : public nsRunnable
+{
+  mozilla::Monitor mMonitor;
+  BlobParent* mActor;
+  nsCOMPtr<nsIDOMBlob> mSourceBlob;
+  nsRefPtr<RemoteInputStream> mInputStream;
+  bool mDone;
+
+public:
+  StreamHelper(BlobParent* aActor, nsIDOMBlob* aSourceBlob)
+    : mMonitor("BlobParent::RemoteBlob::StreamHelper::mMonitor")
+    , mActor(aActor)
+    , mSourceBlob(aSourceBlob)
+    , mDone(false)
+  {
+    // This may be created on any thread.
+    MOZ_ASSERT(aActor);
+    MOZ_ASSERT(aSourceBlob);
+  }
+
+  nsresult
+  GetStream(nsIInputStream** aInputStream)
+  {
+    // This may be called on any thread.
+    MOZ_ASSERT(aInputStream);
+    MOZ_ASSERT(mActor);
+    MOZ_ASSERT(!mInputStream);
+    MOZ_ASSERT(!mDone);
+
+    if (NS_IsMainThread()) {
+      RunInternal(false);
+    }
+    else {
+      nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+      NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
+
+      nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      {
+        MonitorAutoLock lock(mMonitor);
+        while (!mDone) {
+          lock.Wait();
+        }
+      }
+    }
+
+    MOZ_ASSERT(!mActor);
+    MOZ_ASSERT(mDone);
+
+    if (!mInputStream) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    mInputStream.forget(aInputStream);
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    RunInternal(true);
+    return NS_OK;
+  }
+
+private:
+  void
+  RunInternal(bool aNotify)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(mActor);
+    MOZ_ASSERT(!mInputStream);
+    MOZ_ASSERT(!mDone);
+
+    nsRefPtr<RemoteInputStream> stream =
+      new RemoteInputStream(mSourceBlob, ParentActor);
+
+    InputStreamParent* streamActor = new InputStreamParent(stream);
+    if (mActor->SendPBlobStreamConstructor(streamActor)) {
+      stream.swap(mInputStream);
+    }
+
+    mActor = nullptr;
+
+    if (aNotify) {
+      MonitorAutoLock lock(mMonitor);
+      mDone = true;
+      lock.Notify();
+    }
+    else {
+      mDone = true;
+    }
+  }
+};
+
+class BlobParent::RemoteBlob::SliceHelper MOZ_FINAL
+  : public nsRunnable
+{
+  mozilla::Monitor mMonitor;
+  BlobParent* mActor;
+  nsCOMPtr<nsIDOMBlob> mSlice;
+  uint64_t mStart;
+  uint64_t mLength;
+  nsString mContentType;
+  bool mDone;
+
+public:
+  SliceHelper(BlobParent* aActor)
+    : mMonitor("BlobParent::RemoteBlob::SliceHelper::mMonitor")
+    , mActor(aActor)
+    , mStart(0)
+    , mLength(0)
+    , mDone(false)
+  {
+    // This may be created on any thread.
+    MOZ_ASSERT(aActor);
+  }
+
+  nsresult
+  GetSlice(uint64_t aStart,
+           uint64_t aLength,
+           const nsAString& aContentType,
+           nsIDOMBlob** aSlice)
+  {
+    // This may be called on any thread.
+    MOZ_ASSERT(aSlice);
+    MOZ_ASSERT(mActor);
+    MOZ_ASSERT(!mSlice);
+    MOZ_ASSERT(!mDone);
+
+    mStart = aStart;
+    mLength = aLength;
+    mContentType = aContentType;
+
+    if (NS_IsMainThread()) {
+      RunInternal(false);
+    }
+    else {
+      nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+      NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
+
+      nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      {
+        MonitorAutoLock lock(mMonitor);
+        while (!mDone) {
+          lock.Wait();
+        }
+      }
+    }
+
+    MOZ_ASSERT(!mActor);
+    MOZ_ASSERT(mDone);
+
+    if (!mSlice) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    mSlice.forget(aSlice);
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    RunInternal(true);
+    return NS_OK;
+  }
+
+private:
+  void
+  RunInternal(bool aNotify)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(mActor);
+    MOZ_ASSERT(!mSlice);
+    MOZ_ASSERT(!mDone);
+
+    NS_ENSURE_TRUE_VOID(mActor->Manager());
+
+    NormalBlobConstructorParams normalParams;
+    normalParams.contentType() = mContentType;
+    normalParams.length() = mLength;
+
+    ParentBlobConstructorParams params;
+    params.blobParams() = normalParams;
+    params.optionalInputStreamParams() = void_t();
+
+    auto* manager = static_cast<ContentParent*>(mActor->Manager());
+    MOZ_ASSERT(manager);
+
+    BlobParent* newActor = BlobParent::Create(manager, params);
+    MOZ_ASSERT(newActor);
+
+    SlicedBlobConstructorParams slicedParams;
+    slicedParams.contentType() = mContentType;
+    slicedParams.begin() = mStart;
+    slicedParams.end() = mStart + mLength;
+    slicedParams.sourceParent() = mActor;
+
+    ChildBlobConstructorParams otherSideParams = slicedParams;
+
+    if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) {
+      mSlice = newActor->GetBlob();
+    }
+
+    mActor = nullptr;
+
+    if (aNotify) {
+      MonitorAutoLock lock(mMonitor);
+      mDone = true;
+      lock.Notify();
+    }
+    else {
+      mDone = true;
+    }
+  }
+};
+
+/*******************************************************************************
+ * BlobChild::RemoteBlob Implementation
+ ******************************************************************************/
+
+NS_IMPL_ISUPPORTS_INHERITED1(BlobParent::RemoteBlob, nsDOMFile, nsIRemoteBlob)
+
+already_AddRefed<nsIDOMBlob>
+BlobParent::
+RemoteBlob::CreateSlice(uint64_t aStart,
+                        uint64_t aLength,
+                        const nsAString& aContentType)
+{
+  if (!mActor) {
+    return nullptr;
+  }
+
+  nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
+
+  nsCOMPtr<nsIDOMBlob> slice;
+  nsresult rv =
+    helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  return slice.forget();
+}
+
+NS_IMETHODIMP
+BlobParent::
+RemoteBlob::GetInternalStream(nsIInputStream** aStream)
+{
+  if (mInputStreamParams.type() != InputStreamParams::T__None) {
+    nsTArray<FileDescriptor> fds;
+    nsCOMPtr<nsIInputStream> realStream =
+      DeserializeInputStream(mInputStreamParams, fds);
+    if (!realStream) {
+      NS_WARNING("Failed to deserialize stream!");
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    nsCOMPtr<nsIInputStream> stream =
+      new BlobInputStreamTether(realStream, this);
+    stream.forget(aStream);
+    return NS_OK;
+  }
+
+  if (!mActor) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
+  return helper->GetStream(aStream);
+}
+
+NS_IMETHODIMP
+BlobParent::
+RemoteBlob::GetLastModifiedDate(JSContext* cx,
+                                JS::MutableHandle<JS::Value> aLastModifiedDate)
+{
+  if (IsDateUnknown()) {
+    aLastModifiedDate.setNull();
+  } else {
+    JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate);
+    if (!date) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    aLastModifiedDate.setObject(*date);
+  }
+  return NS_OK;
+}
+
+void*
+BlobParent::
+RemoteBlob::GetPBlob()
+{
+  return static_cast<PBlobParent*>(mActor);
+}
+
+/*******************************************************************************
+ * BlobParent
+ ******************************************************************************/
+
+BlobParent::BlobParent(ContentParent* aManager, nsIDOMBlob* aBlob)
+  : mBlob(aBlob)
+  , mRemoteBlob(nullptr)
+  , mStrongManager(aManager)
+  , mOwnsBlob(true)
+  , mBlobIsFile(false)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aManager);
+  MOZ_ASSERT(aBlob);
+
+  aBlob->AddRef();
+
+  nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
+  mBlobIsFile = !!file;
+}
+
+BlobParent::BlobParent(ContentParent* aManager,
+                       const ParentBlobConstructorParams& aParams)
+  : mBlob(nullptr)
+  , mRemoteBlob(nullptr)
+  , mStrongManager(aManager)
+  , mOwnsBlob(false)
+  , mBlobIsFile(false)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aManager);
+
+  ChildBlobConstructorParams::Type paramsType = aParams.blobParams().type();
+
+  mBlobIsFile =
+    paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams ||
+    paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams;
+
+  nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams);
+  MOZ_ASSERT(remoteBlob);
+
+  remoteBlob->SetActor(this);
+  remoteBlob->MaybeSetInputStream(aParams);
+  remoteBlob.forget(&mRemoteBlob);
+
+  mBlob = mRemoteBlob;
+  mOwnsBlob = true;
+}
+
+BlobParent::~BlobParent()
+{
+}
+
+BlobParent*
+BlobParent::Create(ContentParent* aManager,
+                   const ParentBlobConstructorParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aManager);
+
+  const ChildBlobConstructorParams& blobParams = aParams.blobParams();
+
+  switch (blobParams.type()) {
+    case ChildBlobConstructorParams::TNormalBlobConstructorParams:
+    case ChildBlobConstructorParams::TFileBlobConstructorParams:
+    case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
+      return new BlobParent(aManager, aParams);
+
+    case ChildBlobConstructorParams::TSlicedBlobConstructorParams: {
+      const SlicedBlobConstructorParams& params =
+        blobParams.get_SlicedBlobConstructorParams();
+
+      auto* actor =
+        const_cast<BlobParent*>(
+          static_cast<const BlobParent*>(params.sourceParent()));
+      MOZ_ASSERT(actor);
+
+      nsCOMPtr<nsIDOMBlob> source = actor->GetBlob();
+      MOZ_ASSERT(source);
+
+      nsCOMPtr<nsIDOMBlob> slice;
+      nsresult rv =
+        source->Slice(params.begin(), params.end(), params.contentType(), 3,
+                      getter_AddRefs(slice));
+      NS_ENSURE_SUCCESS(rv, nullptr);
+
+      return new BlobParent(aManager, slice);
+    }
+
+    default:
+      MOZ_CRASH("Unknown params!");
+  }
+
+  return nullptr;
+}
+
+already_AddRefed<nsIDOMBlob>
+BlobParent::GetBlob()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mBlob);
+
+  nsCOMPtr<nsIDOMBlob> blob;
+
+  // Remote blobs are held alive until the first call to GetBlob. Thereafter we
+  // only hold a weak reference. Normal blobs are held alive until the actor is
+  // destroyed.
+  if (mRemoteBlob && mOwnsBlob) {
+    blob = dont_AddRef(mBlob);
+    mOwnsBlob = false;
+  }
+  else {
+    blob = mBlob;
+  }
+
+  MOZ_ASSERT(blob);
+
+  return blob.forget();
+}
+
 bool
-Blob<ActorFlavor>::RecvResolveMystery(const ResolveMysteryParams& aParams)
+BlobParent::SetMysteryBlobInfo(const nsString& aName,
+                               const nsString& aContentType,
+                               uint64_t aLength,
+                               uint64_t aLastModifiedDate)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mBlob);
+  MOZ_ASSERT(mRemoteBlob);
+  MOZ_ASSERT(aLastModifiedDate != UINT64_MAX);
+
+  ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength,
+                                     aLastModifiedDate);
+
+  FileBlobConstructorParams params(aName, aContentType, aLength,
+                                   aLastModifiedDate);
+  return SendResolveMystery(params);
+}
+
+bool
+BlobParent::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mBlob);
+  MOZ_ASSERT(mRemoteBlob);
+
+  nsString voidString;
+  voidString.SetIsVoid(true);
+
+  ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength,
+                                     UINT64_MAX);
+
+  NormalBlobConstructorParams params(aContentType, aLength);
+  return SendResolveMystery(params);
+}
+
+already_AddRefed<BlobParent::RemoteBlob>
+BlobParent::CreateRemoteBlob(const ParentBlobConstructorParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  const ChildBlobConstructorParams& blobParams = aParams.blobParams();
+
+  nsRefPtr<RemoteBlob> remoteBlob;
+
+  switch (blobParams.type()) {
+    case ChildBlobConstructorParams::TNormalBlobConstructorParams: {
+      const NormalBlobConstructorParams& params =
+        blobParams.get_NormalBlobConstructorParams();
+      remoteBlob = new RemoteBlob(params.contentType(), params.length());
+      break;
+    }
+
+    case ChildBlobConstructorParams::TFileBlobConstructorParams: {
+      const FileBlobConstructorParams& params =
+        blobParams.get_FileBlobConstructorParams();
+      remoteBlob =
+        new RemoteBlob(params.name(), params.contentType(), params.length(),
+                       params.modDate());
+      break;
+    }
+
+    case ChildBlobConstructorParams::TMysteryBlobConstructorParams: {
+      remoteBlob = new RemoteBlob();
+      break;
+    }
+
+    default:
+      MOZ_CRASH("Unknown params!");
+  }
+
+  MOZ_ASSERT(remoteBlob);
+
+  if (NS_FAILED(remoteBlob->SetMutable(false))) {
+    MOZ_CRASH("Failed to make remote blob immutable!");
+  }
+
+  return remoteBlob.forget();
+}
+
+void
+BlobParent::NoteDyingRemoteBlob()
+{
+  MOZ_ASSERT(mBlob);
+  MOZ_ASSERT(mRemoteBlob);
+  MOZ_ASSERT(!mOwnsBlob);
+
+  // This may be called on any thread due to the fact that RemoteBlob is
+  // designed to be passed between threads. We must start the shutdown process
+  // on the main thread, so we proxy here if necessary.
+  if (!NS_IsMainThread()) {
+    nsCOMPtr<nsIRunnable> runnable =
+      NS_NewNonOwningRunnableMethod(this, &BlobParent::NoteDyingRemoteBlob);
+    if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
+      MOZ_ASSERT(false, "Should never fail!");
+    }
+
+    return;
+  }
+
+  // Must do this before calling Send__delete__ or we'll crash there trying to
+  // access a dangling pointer.
+  mBlob = nullptr;
+  mRemoteBlob = nullptr;
+
+  mozilla::unused << PBlobParent::Send__delete__(this);
+}
+
+void
+BlobParent::NoteRunnableCompleted(OpenStreamRunnable* aRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  for (uint32_t index = 0; index < mOpenStreamRunnables.Length(); index++) {
+    nsRevocableEventPtr<OpenStreamRunnable>& runnable =
+      mOpenStreamRunnables[index];
+
+    if (runnable.get() == aRunnable) {
+      runnable.Forget();
+      mOpenStreamRunnables.RemoveElementAt(index);
+      return;
+    }
+  }
+
+  MOZ_CRASH("Runnable not in our array!");
+}
+
+void
+BlobParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mRemoteBlob) {
+    mRemoteBlob->SetActor(nullptr);
+  }
+
+  if (mBlob && mOwnsBlob) {
+    mBlob->Release();
+  }
+
+  mStrongManager = nullptr;
+}
+
+PBlobStreamParent*
+BlobParent::AllocPBlobStreamParent()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  return new InputStreamParent();
+}
+
+bool
+BlobParent::RecvPBlobStreamConstructor(PBlobStreamParent* aActor)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aActor);
+  MOZ_ASSERT(mBlob);
+  MOZ_ASSERT(!mRemoteBlob);
+
+  nsCOMPtr<nsIInputStream> stream;
+  nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(mBlob);
+
+  nsCOMPtr<IPrivateRemoteInputStream> remoteStream;
+  if (remoteBlob) {
+    remoteStream = do_QueryInterface(stream);
+  }
+
+  // There are three cases in which we can use the stream obtained from the blob
+  // directly as our serialized stream:
+  //
+  //   1. The blob is not a remote blob.
+  //   2. The blob is a remote blob that represents this actor.
+  //   3. The blob is a remote blob representing a different actor but we
+  //      already have a non-remote, i.e. serialized, serialized stream.
+  //
+  // In all other cases we need to be on a background thread before we can get
+  // to the real stream.
+  nsCOMPtr<nsIIPCSerializableInputStream> serializableStream;
+  if (!remoteBlob ||
+      static_cast<PBlobParent*>(remoteBlob->GetPBlob()) == this ||
+      !remoteStream) {
+    serializableStream = do_QueryInterface(stream);
+    if (!serializableStream) {
+      MOZ_ASSERT(false, "Must be serializable!");
+      return false;
+    }
+  }
+
+  nsCOMPtr<nsIEventTarget> target =
+    do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(target, false);
+
+  nsRefPtr<OpenStreamRunnable> runnable =
+    new OpenStreamRunnable(this, aActor, stream, serializableStream, target);
+
+  rv = runnable->Dispatch();
+  NS_ENSURE_SUCCESS(rv, false);
+
+  // nsRevocableEventPtr lacks some of the operators needed for anything nicer.
+  *mOpenStreamRunnables.AppendElement() = runnable;
+  return true;
+}
+
+bool
+BlobParent::DeallocPBlobStreamParent(PBlobStreamParent* aActor)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  delete static_cast<InputStreamParent*>(aActor);
+  return true;
+}
+
+bool
+BlobParent::RecvResolveMystery(const ResolveMysteryParams& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mBlob);
   MOZ_ASSERT(!mRemoteBlob);
   MOZ_ASSERT(mOwnsBlob);
 
   if (!mBlobIsFile) {
     MOZ_ASSERT(false, "Must always be a file!");
@@ -1462,141 +2127,59 @@ Blob<ActorFlavor>::RecvResolveMystery(co
 
     default:
       MOZ_CRASH("Unknown params!");
   }
 
   return true;
 }
 
-template <>
 bool
-Blob<Parent>::RecvPBlobStreamConstructor(StreamType* aActor)
+InputStreamChild::Recv__delete__(const InputStreamParams& aParams,
+                                 const OptionalFileDescriptorSet& aFDs)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mBlob);
-  MOZ_ASSERT(!mRemoteBlob);
+  MOZ_ASSERT(mRemoteStream);
 
-  nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
-  NS_ENSURE_SUCCESS(rv, false);
+  nsTArray<FileDescriptor> fds;
+  if (aFDs.type() == OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
+    FileDescriptorSetChild* fdSetActor =
+      static_cast<FileDescriptorSetChild*>(aFDs.get_PFileDescriptorSetChild());
+    MOZ_ASSERT(fdSetActor);
 
-  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(mBlob);
+    fdSetActor->ForgetFileDescriptors(fds);
+    MOZ_ASSERT(!fds.IsEmpty());
 
-  nsCOMPtr<IPrivateRemoteInputStream> remoteStream;
-  if (remoteBlob) {
-    remoteStream = do_QueryInterface(stream);
+    fdSetActor->Send__delete__(fdSetActor);
   }
 
-  // There are three cases in which we can use the stream obtained from the blob
-  // directly as our serialized stream:
-  //
-  //   1. The blob is not a remote blob.
-  //   2. The blob is a remote blob that represents this actor.
-  //   3. The blob is a remote blob representing a different actor but we
-  //      already have a non-remote, i.e. serialized, serialized stream.
-  //
-  // In all other cases we need to be on a background thread before we can get
-  // to the real stream.
-  nsCOMPtr<nsIIPCSerializableInputStream> serializableStream;
-  if (!remoteBlob ||
-      static_cast<ProtocolType*>(remoteBlob->GetPBlob()) == this ||
-      !remoteStream) {
-    serializableStream = do_QueryInterface(stream);
-    if (!serializableStream) {
-      MOZ_ASSERT(false, "Must be serializable!");
-      return false;
-    }
-  }
-
-  nsCOMPtr<nsIEventTarget> target =
-    do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(target, false);
-
-  nsRefPtr<BaseType::OpenStreamRunnable> runnable =
-    new BaseType::OpenStreamRunnable(this, aActor, stream, serializableStream,
-                                     target);
-
-  rv = runnable->Dispatch();
-  NS_ENSURE_SUCCESS(rv, false);
-
-  nsRevocableEventPtr<BaseType::OpenStreamRunnable>* arrayMember =
-    mOpenStreamRunnables.AppendElement();
-  *arrayMember = runnable;
-  return true;
-}
-
-template <>
-bool
-Blob<Child>::RecvPBlobStreamConstructor(StreamType* aActor)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mBlob);
-  MOZ_ASSERT(!mRemoteBlob);
-
-  nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
-  NS_ENSURE_SUCCESS(rv, false);
-
-  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
-    do_QueryInterface(stream);
-  if (!serializable) {
-    MOZ_ASSERT(false, "Must be serializable!");
+  nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds);
+  if (!stream) {
     return false;
   }
 
-  InputStreamParams params;
-  nsTArray<FileDescriptor> fds;
-  serializable->Serialize(params, fds);
-
-  MOZ_ASSERT(params.type() != InputStreamParams::T__None);
-  MOZ_ASSERT(fds.IsEmpty());
-
-  return aActor->Send__delete__(aActor, params, mozilla::void_t());
-}
-
-BlobTraits<Parent>::StreamType*
-BlobTraits<Parent>::BaseType::AllocPBlobStreamParent()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  return new InputStreamActor<Parent>();
-}
-
-BlobTraits<Child>::StreamType*
-BlobTraits<Child>::BaseType::AllocPBlobStreamChild()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  return new InputStreamActor<Child>();
-}
-
-bool
-BlobTraits<Parent>::BaseType::DeallocPBlobStreamParent(BlobTraits<Parent>::StreamType* aActor)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  delete aActor;
+  mRemoteStream->SetStream(stream);
   return true;
 }
 
 bool
-BlobTraits<Child>::BaseType::DeallocPBlobStreamChild(BlobTraits<Child>::StreamType* aActor)
+InputStreamParent::Recv__delete__(const InputStreamParams& aParams,
+                                  const OptionalFileDescriptorSet& aFDs)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  delete aActor;
+  MOZ_ASSERT(mRemoteStream);
+
+  if (aFDs.type() != OptionalFileDescriptorSet::Tvoid_t) {
+    NS_WARNING("Child cannot send FileDescriptors to the parent!");
+    return false;
+  }
+
+  nsTArray<FileDescriptor> fds;
+  nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds);
+  if (!stream) {
+    return false;
+  }
+
+  MOZ_ASSERT(fds.IsEmpty());
+
+  mRemoteStream->SetStream(stream);
   return true;
 }
-
-template <ActorFlavorEnum ActorFlavor>
-NS_IMPL_ADDREF_INHERITED(RemoteBlob<ActorFlavor>, nsDOMFile)
-
-template <ActorFlavorEnum ActorFlavor>
-NS_IMPL_RELEASE_INHERITED(RemoteBlob<ActorFlavor>, nsDOMFile)
-
-template <ActorFlavorEnum ActorFlavor>
-NS_IMPL_QUERY_INTERFACE_INHERITED1(RemoteBlob<ActorFlavor>, nsDOMFile,
-                                                            nsIRemoteBlob)
-
-// Explicit instantiation of both classes.
-template class Blob<Parent>;
-template class Blob<Child>;
-
-} // namespace ipc
-} // namespace dom
-} // namespace mozilla
--- a/dom/ipc/Blob.h
+++ b/dom/ipc/Blob.h
@@ -1,248 +1,196 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* vim: set sw=4 ts=8 et tw=80 : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ipc_Blob_h
 #define mozilla_dom_ipc_Blob_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/PBlobChild.h"
 #include "mozilla/dom/PBlobParent.h"
-#include "mozilla/dom/PBlobStreamChild.h"
-#include "mozilla/dom/PBlobStreamParent.h"
-
 #include "nsAutoPtr.h"
-#include "nsCOMPtr.h"
 #include "nsTArray.h"
 
 class nsIDOMBlob;
-template<class T> class nsRevocableEventPtr;
+class nsString;
+template <class> class nsRevocableEventPtr;
 
 namespace mozilla {
 namespace dom {
 
+class ContentChild;
 class ContentParent;
-class ContentChild;
-
-namespace ipc {
-
-enum ActorFlavorEnum
-{
-  Parent = 0,
-  Child
-};
-
-template <ActorFlavorEnum>
-struct BlobTraits;
-
-template <>
-struct BlobTraits<Parent>
-{
-  typedef mozilla::dom::PBlobParent ProtocolType;
-  typedef mozilla::dom::PBlobStreamParent StreamType;
-  typedef mozilla::dom::ParentBlobConstructorParams ConstructorParamsType;
-  typedef mozilla::dom::ChildBlobConstructorParams
-          OtherSideConstructorParamsType;
-  typedef mozilla::dom::ContentParent ConcreteContentManagerType;
-
-  // BaseType on the parent side is a bit more complicated than for the child
-  // side. In the case of nsIInputStreams backed by files we need to ensure that
-  // the files are actually opened and closed on a background thread before we
-  // can send their file handles across to the child. The child process could
-  // crash during this process so we need to make sure we cancel the intended
-  // response in such a case. We do that by holding an array of
-  // nsRevocableEventPtr. If the child crashes then this actor will be destroyed
-  // and the nsRevocableEventPtr destructor will cancel any stream events that
-  // are currently in flight.
-  class BaseType : public ProtocolType
-  {
-  public:
-    static const ChildBlobConstructorParams&
-    GetBlobConstructorParams(const ConstructorParamsType& aParams)
-    {
-      return aParams.blobParams();
-    }
-
-    static void
-    SetBlobConstructorParams(ConstructorParamsType& aParams,
-                             const ChildBlobConstructorParams& aBlobParams)
-    {
-      aParams.blobParams() = aBlobParams;
-      aParams.optionalInputStreamParams() = mozilla::void_t();
-    }
-
-    static void
-    SetBlobConstructorParams(OtherSideConstructorParamsType& aParams,
-                             const ChildBlobConstructorParams& aBlobParams)
-    {
-      aParams = aBlobParams;
-    }
-
-  protected:
-    virtual StreamType*
-    AllocPBlobStreamParent() MOZ_OVERRIDE;
-
-    virtual bool
-    DeallocPBlobStreamParent(StreamType* aActor) MOZ_OVERRIDE;
-
-    BaseType();
-    virtual ~BaseType();
-
-    class OpenStreamRunnable;
-    friend class OpenStreamRunnable;
-
-    void
-    NoteRunnableCompleted(OpenStreamRunnable* aRunnable);
-
-    nsTArray<nsRevocableEventPtr<OpenStreamRunnable> > mOpenStreamRunnables;
-  };
-};
+class PBlobStreamChild;
+class PBlobStreamParent;
 
-template <>
-struct BlobTraits<Child>
+class BlobChild MOZ_FINAL
+  : public PBlobChild
 {
-  typedef mozilla::dom::PBlobChild ProtocolType;
-  typedef mozilla::dom::PBlobStreamChild StreamType;
-  typedef mozilla::dom::ChildBlobConstructorParams ConstructorParamsType;
-  typedef mozilla::dom::ParentBlobConstructorParams
-          OtherSideConstructorParamsType;
-  typedef mozilla::dom::ContentChild ConcreteContentManagerType;
-
-
-  class BaseType : public ProtocolType
-  {
-  public:
-    static const ChildBlobConstructorParams&
-    GetBlobConstructorParams(const ConstructorParamsType& aParams)
-    {
-      return aParams;
-    }
-
-    static void
-    SetBlobConstructorParams(ConstructorParamsType& aParams,
-                             const ChildBlobConstructorParams& aBlobParams)
-    {
-      aParams = aBlobParams;
-    }
-
-    static void
-    SetBlobConstructorParams(OtherSideConstructorParamsType& aParams,
-                             const ChildBlobConstructorParams& aBlobParams)
-    {
-      aParams.blobParams() = aBlobParams;
-      aParams.optionalInputStreamParams() = mozilla::void_t();
-    }
+  friend class ContentChild;
 
-  protected:
-    virtual StreamType*
-    AllocPBlobStreamChild() MOZ_OVERRIDE;
-
-    virtual bool
-    DeallocPBlobStreamChild(StreamType* aActor) MOZ_OVERRIDE;
-
-    BaseType()
-    { }
-
-    virtual ~BaseType()
-    { }
-  };
-};
-
-template <ActorFlavorEnum>
-class RemoteBlob;
+  class RemoteBlob;
+  friend class RemoteBlob;
 
-template <ActorFlavorEnum ActorFlavor>
-class Blob : public BlobTraits<ActorFlavor>::BaseType
-{
-  friend class RemoteBlob<ActorFlavor>;
-  friend class BlobTraits<ActorFlavor>::BaseType;
+  nsIDOMBlob* mBlob;
+  RemoteBlob* mRemoteBlob;
+  nsRefPtr<ContentChild> mStrongManager;
 
-public:
-  typedef typename BlobTraits<ActorFlavor>::ConcreteContentManagerType ContentManager;
-  typedef typename BlobTraits<ActorFlavor>::ProtocolType ProtocolType;
-  typedef typename BlobTraits<ActorFlavor>::StreamType StreamType;
-  typedef typename BlobTraits<ActorFlavor>::ConstructorParamsType
-          ConstructorParamsType;
-  typedef typename BlobTraits<ActorFlavor>::OtherSideConstructorParamsType
-          OtherSideConstructorParamsType;
-  typedef typename BlobTraits<ActorFlavor>::BaseType BaseType;
-  typedef RemoteBlob<ActorFlavor> RemoteBlobType;
-  typedef mozilla::ipc::IProtocolManager<
-                      mozilla::ipc::IProtocol>::ActorDestroyReason
-          ActorDestroyReason;
-
-protected:
-  nsIDOMBlob* mBlob;
-  RemoteBlobType* mRemoteBlob;
   bool mOwnsBlob;
   bool mBlobIsFile;
 
 public:
   // This create function is called on the sending side.
-  static Blob*
-  Create(ContentManager* aManager, nsIDOMBlob* aBlob)
+  static BlobChild*
+  Create(ContentChild* aManager, nsIDOMBlob* aBlob)
   {
-    return new Blob(aManager, aBlob);
+    return new BlobChild(aManager, aBlob);
   }
 
-  // This create function is called on the receiving side.
-  static Blob*
-  Create(ContentManager* aManager, const ConstructorParamsType& aParams);
+  // Get the blob associated with this actor. This may always be called on the
+  // sending side. It may also be called on the receiving side unless this is a
+  // "mystery" blob that has not yet received a SetMysteryBlobInfo() call.
+  already_AddRefed<nsIDOMBlob>
+  GetBlob();
+
+  // Use this for files.
+  bool
+  SetMysteryBlobInfo(const nsString& aName,
+                     const nsString& aContentType,
+                     uint64_t aLength,
+                     uint64_t aLastModifiedDate);
+
+  // Use this for non-file blobs.
+  bool
+  SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength);
+
+private:
+  // This constructor is called on the sending side.
+  BlobChild(ContentChild* aManager, nsIDOMBlob* aBlob);
+
+  // This constructor is called on the receiving side.
+  BlobChild(ContentChild* aManager, const ChildBlobConstructorParams& aParams);
+
+  // Only destroyed by ContentChild.
+  ~BlobChild();
+
+  // This create function is called on the receiving side by ContentChild.
+  static BlobChild*
+  Create(ContentChild* aManager, const ChildBlobConstructorParams& aParams);
+
+  static already_AddRefed<RemoteBlob>
+  CreateRemoteBlob(const ChildBlobConstructorParams& aParams);
+
+  void
+  NoteDyingRemoteBlob();
+
+  // These methods are only called by the IPDL message machinery.
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvResolveMystery(const ResolveMysteryParams& aParams) MOZ_OVERRIDE;
+
+  virtual PBlobStreamChild*
+  AllocPBlobStreamChild() MOZ_OVERRIDE;
+
+  virtual bool
+  RecvPBlobStreamConstructor(PBlobStreamChild* aActor) MOZ_OVERRIDE;
+
+  virtual bool
+  DeallocPBlobStreamChild(PBlobStreamChild* aActor) MOZ_OVERRIDE;
+};
+
+class BlobParent MOZ_FINAL
+  : public PBlobParent
+{
+  friend class ContentParent;
+
+  class OpenStreamRunnable;
+  friend class OpenStreamRunnable;
+
+  class RemoteBlob;
+  friend class RemoteBlob;
+
+  nsIDOMBlob* mBlob;
+  RemoteBlob* mRemoteBlob;
+  nsRefPtr<ContentParent> mStrongManager;
+
+  // nsIInputStreams backed by files must ensure that the files are actually
+  // opened and closed on a background thread before we can send their file
+  // handles across to the child. The child process could crash during this
+  // process so we need to make sure we cancel the intended response in such a
+  // case. We do that by holding an array of nsRevocableEventPtr. If the child
+  // crashes then this actor will be destroyed and the nsRevocableEventPtr
+  // destructor will cancel any stream events that are currently in flight.
+  nsTArray<nsRevocableEventPtr<OpenStreamRunnable>> mOpenStreamRunnables;
+
+  bool mOwnsBlob;
+  bool mBlobIsFile;
+
+public:
+  // This create function is called on the sending side.
+  static BlobParent*
+  Create(ContentParent* aManager, nsIDOMBlob* aBlob)
+  {
+    return new BlobParent(aManager, aBlob);
+  }
 
   // Get the blob associated with this actor. This may always be called on the
   // sending side. It may also be called on the receiving side unless this is a
   // "mystery" blob that has not yet received a SetMysteryBlobInfo() call.
   already_AddRefed<nsIDOMBlob>
   GetBlob();
 
   // Use this for files.
   bool
   SetMysteryBlobInfo(const nsString& aName, const nsString& aContentType,
                      uint64_t aLength, uint64_t aLastModifiedDate);
 
   // Use this for non-file blobs.
   bool
   SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength);
 
-  ContentManager* Manager()
-  {
-    return mManager;
-  }
-
 private:
   // This constructor is called on the sending side.
-  Blob(ContentManager* aManager, nsIDOMBlob* aBlob);
+  BlobParent(ContentParent* aManager, nsIDOMBlob* aBlob);
 
   // This constructor is called on the receiving side.
-  Blob(ContentManager* aManager, const ConstructorParamsType& aParams);
+  BlobParent(ContentParent* aManager,
+             const ParentBlobConstructorParams& aParams);
+
+  ~BlobParent();
 
-  static already_AddRefed<RemoteBlobType>
-  CreateRemoteBlob(const ConstructorParamsType& aParams);
+  // This create function is called on the receiving side by ContentParent.
+  static BlobParent*
+  Create(ContentParent* aManager, const ParentBlobConstructorParams& aParams);
+
+  static already_AddRefed<RemoteBlob>
+  CreateRemoteBlob(const ParentBlobConstructorParams& aParams);
 
   void
   NoteDyingRemoteBlob();
 
+  void
+  NoteRunnableCompleted(OpenStreamRunnable* aRunnable);
+
   // These methods are only called by the IPDL message machinery.
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
-  virtual bool
-  RecvResolveMystery(const ResolveMysteryParams& aParams) MOZ_OVERRIDE;
+  virtual PBlobStreamParent*
+  AllocPBlobStreamParent() MOZ_OVERRIDE;
 
   virtual bool
-  RecvPBlobStreamConstructor(StreamType* aActor) MOZ_OVERRIDE;
-
-  nsRefPtr<ContentManager> mManager;
-};
+  RecvPBlobStreamConstructor(PBlobStreamParent* aActor) MOZ_OVERRIDE;
 
-} // namespace ipc
+  virtual bool
+  DeallocPBlobStreamParent(PBlobStreamParent* aActor) MOZ_OVERRIDE;
 
-typedef mozilla::dom::ipc::Blob<mozilla::dom::ipc::Child> BlobChild;
-typedef mozilla::dom::ipc::Blob<mozilla::dom::ipc::Parent> BlobParent;
+  virtual bool
+  RecvResolveMystery(const ResolveMysteryParams& aParams) MOZ_OVERRIDE;
+};
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ipc_Blob_h
--- a/gfx/layers/client/ClientTiledThebesLayer.h
+++ b/gfx/layers/client/ClientTiledThebesLayer.h
@@ -39,16 +39,19 @@ class ClientTiledThebesLayer : public Th
                                public ClientLayer
 {
   typedef ThebesLayer Base;
 
 public:
   ClientTiledThebesLayer(ClientLayerManager* const aManager);
   ~ClientTiledThebesLayer();
 
+  // Override name to distinguish it from ClientThebesLayer in layer dumps
+  virtual const char* Name() const { return "TiledThebesLayer"; }
+
   // Thebes Layer
   virtual Layer* AsLayer() { return this; }
   virtual void InvalidateRegion(const nsIntRegion& aRegion) {
     mInvalidRegion.Or(mInvalidRegion, aRegion);
     mValidRegion.Sub(mValidRegion, aRegion);
     mLowPrecisionValidRegion.Sub(mLowPrecisionValidRegion, aRegion);
   }
 
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -112,17 +112,17 @@ CompositableHost::RemoveMaskEffect()
 TemporaryRef<CompositableBackendSpecificData> CreateCompositableBackendSpecificDataOGL();
 
 /* static */ TemporaryRef<CompositableHost>
 CompositableHost::Create(const TextureInfo& aTextureInfo)
 {
   RefPtr<CompositableHost> result;
   switch (aTextureInfo.mCompositableType) {
   case BUFFER_BRIDGE:
-    MOZ_CRASH("Cannot create an image bridge compositable this way");
+    NS_ERROR("Cannot create an image bridge compositable this way");
     break;
   case BUFFER_CONTENT_INC:
     result = new ContentHostIncremental(aTextureInfo);
     break;
   case BUFFER_TILED:
   case BUFFER_SIMPLE_TILED:
     result = new TiledContentHost(aTextureInfo);
     break;
@@ -131,17 +131,17 @@ CompositableHost::Create(const TextureIn
     break;
   case COMPOSITABLE_CONTENT_SINGLE:
     result = new ContentHostSingleBuffered(aTextureInfo);
     break;
   case COMPOSITABLE_CONTENT_DOUBLE:
     result = new ContentHostDoubleBuffered(aTextureInfo);
     break;
   default:
-    MOZ_CRASH("Unknown CompositableType");
+    NS_ERROR("Unknown CompositableType");
   }
   // We know that Tiled buffers don't use the compositable backend-specific
   // data, so don't bother creating it.
   if (result && aTextureInfo.mCompositableType != BUFFER_TILED) {
     RefPtr<CompositableBackendSpecificData> data = CreateCompositableBackendSpecificDataOGL();
     result->SetCompositableBackendSpecificData(data);
   }
   return result;
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -199,21 +199,22 @@ public:
    * Ensure that a suitable texture host exists in this compsitable.
    *
    * Only used with ContentHostIncremental.
    *
    * No SurfaceDescriptor or TextureIdentifier is provider as we
    * don't have a single surface for the texture contents, and we
    * need to allocate our own one to be updated later.
    */
-  virtual void CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
+  virtual bool CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
                                          const TextureInfo& aTextureInfo,
                                          const nsIntRect& aBufferRect)
   {
-    MOZ_ASSERT(false, "should be implemented or not used");
+    NS_ERROR("should be implemented or not used");
+    return false;
   }
 
   /**
    * Returns the front buffer.
    */
   virtual TextureHost* GetAsTextureHost() { return nullptr; }
 
   virtual LayerRenderState GetRenderState() = 0;
--- a/gfx/layers/composite/ContentHost.cpp
+++ b/gfx/layers/composite/ContentHost.cpp
@@ -405,25 +405,26 @@ ContentHostIncremental::~ContentHostIncr
 void
 ContentHostIncremental::DestroyTextures()
 {
   mSource = nullptr;
   mSourceOnWhite = nullptr;
   mUpdateList.Clear();
 }
 
-void
+bool
 ContentHostIncremental::CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
                                                   const TextureInfo& aTextureInfo,
                                                   const nsIntRect& aBufferRect)
 {
   mUpdateList.AppendElement(new TextureCreationRequest(aTextureInfo,
                                                        aBufferRect));
   mDeAllocator = aAllocator;
   FlushUpdateQueue();
+  return true;
 }
 
 void
 ContentHostIncremental::UpdateIncremental(TextureIdentifier aTextureId,
                                           SurfaceDescriptor& aSurface,
                                           const nsIntRegion& aUpdated,
                                           const nsIntRect& aBufferRect,
                                           const nsIntPoint& aBufferRotation)
--- a/gfx/layers/composite/ContentHost.h
+++ b/gfx/layers/composite/ContentHost.h
@@ -255,17 +255,17 @@ class ContentHostIncremental : public Co
 public:
   ContentHostIncremental(const TextureInfo& aTextureInfo);
   ~ContentHostIncremental();
 
   virtual CompositableType GetType() { return BUFFER_CONTENT_INC; }
 
   virtual LayerRenderState GetRenderState() MOZ_OVERRIDE { return LayerRenderState(); }
 
-  virtual void CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
+  virtual bool CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
                                          const TextureInfo& aTextureInfo,
                                          const nsIntRect& aBufferRect) MOZ_OVERRIDE;
 
   virtual void UpdateIncremental(TextureIdentifier aTextureId,
                                  SurfaceDescriptor& aSurface,
                                  const nsIntRegion& aUpdated,
                                  const nsIntRect& aBufferRect,
                                  const nsIntPoint& aBufferRotation) MOZ_OVERRIDE;
--- a/gfx/layers/composite/TiledContentHost.h
+++ b/gfx/layers/composite/TiledContentHost.h
@@ -42,17 +42,16 @@ class Matrix4x4;
 }
 
 namespace layers {
 
 class Compositor;
 class ISurfaceAllocator;
 class Layer;
 class ThebesBufferData;
-class TiledThebesLayerComposite;
 struct EffectChain;
 
 
 class TileHost {
 public:
   // Constructs a placeholder TileHost. See the comments above
   // TiledLayerBuffer for more information on what this is used for;
   // essentially, this is a sentinel used to represent an invalid or blank
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -73,19 +73,23 @@ CompositableParentManager::ReceiveCompos
     case CompositableOperation::TOpCreatedIncrementalTexture: {
       MOZ_LAYERS_LOG(("[ParentSide] Created texture"));
       const OpCreatedIncrementalTexture& op = aEdit.get_OpCreatedIncrementalTexture();
 
       CompositableParent* compositableParent =
         static_cast<CompositableParent*>(op.compositableParent());
       CompositableHost* compositable = compositableParent->GetCompositableHost();
 
-      compositable->CreatedIncrementalTexture(compositableParent->GetCompositableManager(),
-                                              op.textureInfo(),
-                                              op.bufferRect());
+      bool success =
+        compositable->CreatedIncrementalTexture(compositableParent->GetCompositableManager(),
+                                                op.textureInfo(),
+                                                op.bufferRect());
+      if (!success) {
+        return false;
+      }
       break;
     }
     case CompositableOperation::TOpPaintTextureRegion: {
       MOZ_LAYERS_LOG(("[ParentSide] Paint ThebesLayer"));
 
       const OpPaintTextureRegion& op = aEdit.get_OpPaintTextureRegion();
       CompositableParent* compositableParent = static_cast<CompositableParent*>(op.compositableParent());
       CompositableHost* compositable =
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -10,17 +10,16 @@
 #include "CompositableHost.h"           // for CompositableParent, Get, etc
 #include "ImageLayers.h"                // for ImageLayer
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "ShadowLayerParent.h"          // for ShadowLayerParent
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxPoint3D.h"                 // for gfxPoint3D
 #include "CompositableTransactionParent.h"  // for EditReplyVector
 #include "ShadowLayersManager.h"        // for ShadowLayersManager
-#include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/BasePoint3D.h"    // for BasePoint3D
 #include "mozilla/layers/CanvasLayerComposite.h"
 #include "mozilla/layers/ColorLayerComposite.h"
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ContainerLayerComposite.h"
 #include "mozilla/layers/ImageLayerComposite.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
@@ -514,17 +513,20 @@ LayerTransactionParent::RecvUpdate(const
       }
       cast(op.compositableParent())->SetCompositorID(
         mLayerManager->GetCompositor()->GetCompositorID());
       break;
     }
     case Edit::TOpAttachAsyncCompositable: {
       const OpAttachAsyncCompositable& op = edit.get_OpAttachAsyncCompositable();
       CompositableParent* compositableParent = CompositableMap::Get(op.containerID());
-      MOZ_ASSERT(compositableParent, "CompositableParent not found in the map");
+      if (!compositableParent) {
+        NS_ERROR("CompositableParent not found in the map");
+        return false;
+      }
       if (!Attach(cast(op.layerParent()), compositableParent, true)) {
         return false;
       }
       compositableParent->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID());
       break;
     }
     default:
       NS_RUNTIMEABORT("not reached");
@@ -669,23 +671,27 @@ LayerTransactionParent::RecvGetAnimation
 bool
 LayerTransactionParent::RecvSetAsyncScrollOffset(PLayerParent* aLayer,
                                                  const int32_t& aX, const int32_t& aY)
 {
   if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
     return false;
   }
 
-  ContainerLayer* layer = cast(aLayer)->AsLayer()->AsContainerLayer();
+  Layer* layer = cast(aLayer)->AsLayer();
   if (!layer) {
-    return true;
+    return false;
   }
-  AsyncPanZoomController* controller = layer->GetAsyncPanZoomController();
+  ContainerLayer* containerLayer = layer->AsContainerLayer();
+  if (!containerLayer) {
+    return false;
+  }
+  AsyncPanZoomController* controller = containerLayer->GetAsyncPanZoomController();
   if (!controller) {
-    return true;
+    return false;
   }
   controller->SetTestAsyncScrollOffset(CSSPoint(aX, aY));
   return true;
 }
 
 bool
 LayerTransactionParent::Attach(ShadowLayerParent* aLayerParent,
                                CompositableParent* aCompositable,
@@ -699,17 +705,19 @@ LayerTransactionParent::Attach(ShadowLay
   if (!layer) {
     return false;
   }
 
   Compositor* compositor
     = static_cast<LayerManagerComposite*>(aLayerParent->AsLayer()->Manager())->GetCompositor();
 
   CompositableHost* compositable = aCompositable->GetCompositableHost();
-  MOZ_ASSERT(compositable);
+  if (!compositable) {
+    return false;
+  }
   if (!layer->SetCompositableHost(compositable)) {
     // not all layer types accept a compositable, see bug 967824
     return false;
   }
   compositable->Attach(aLayerParent->AsLayer(),
                        compositor,
                        aIsAsyncVideo
                          ? CompositableHost::ALLOW_REATTACH
--- a/gfx/thebes/gfxFT2Utils.cpp
+++ b/gfx/thebes/gfxFT2Utils.cpp
@@ -119,24 +119,36 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
     gfxFloat lineHeight;
     if (os2 && os2->sTypoAscender && yScale > 0.0) {
         aMetrics->emAscent = os2->sTypoAscender * yScale;
         aMetrics->emDescent = -os2->sTypoDescender * yScale;
         FT_Short typoHeight =
             os2->sTypoAscender - os2->sTypoDescender + os2->sTypoLineGap;
         lineHeight = typoHeight * yScale;
 
-        // maxAscent/maxDescent get used for frame heights, and some fonts
-        // don't have the HHEA table ascent/descent set (bug 279032).
-        // We use NS_round here to parallel the pixel-rounded values that
-        // freetype gives us for ftMetrics.ascender/descender.
-        aMetrics->maxAscent =
-            std::max(aMetrics->maxAscent, NS_round(aMetrics->emAscent));
-        aMetrics->maxDescent =
-            std::max(aMetrics->maxDescent, NS_round(aMetrics->emDescent));
+        // If the OS/2 fsSelection USE_TYPO_METRICS bit is set,
+        // or if this is an OpenType Math font,
+        // set maxAscent/Descent from the sTypo* fields instead of hhea.
+        const uint16_t kUseTypoMetricsMask = 1 << 7;
+        FT_ULong length = 0;
+        if ((os2->fsSelection & kUseTypoMetricsMask) ||
+            0 == FT_Load_Sfnt_Table(mFace, FT_MAKE_TAG('M','A','T','H'),
+                                    0, nullptr, &length)) {
+            aMetrics->maxAscent = NS_round(aMetrics->emAscent);
+            aMetrics->maxDescent = NS_round(aMetrics->emDescent);
+        } else {
+            // maxAscent/maxDescent get used for frame heights, and some fonts
+            // don't have the HHEA table ascent/descent set (bug 279032).
+            // We use NS_round here to parallel the pixel-rounded values that
+            // freetype gives us for ftMetrics.ascender/descender.
+            aMetrics->maxAscent =
+                std::max(aMetrics->maxAscent, NS_round(aMetrics->emAscent));
+            aMetrics->maxDescent =
+                std::max(aMetrics->maxDescent, NS_round(aMetrics->emDescent));
+        }
     } else {
         aMetrics->emAscent = aMetrics->maxAscent;
         aMetrics->emDescent = aMetrics->maxDescent;
         lineHeight = FLOAT_FROM_26_6(ftMetrics.height);
     }
 
     cairo_text_extents_t extents;
     *aSpaceGlyph = GetCharExtents(' ', &extents);
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -2026,30 +2026,33 @@ gfxFont::~gfxFont()
     if (mGlyphChangeObservers) {
         mGlyphChangeObservers->EnumerateEntries(NotifyFontDestroyed, nullptr);
     }
 }
 
 gfxFloat
 gfxFont::GetGlyphHAdvance(gfxContext *aCtx, uint16_t aGID)
 {
+    if (!SetupCairoFont(aCtx)) {
+        return 0;
+    }
     if (ProvidesGlyphWidths()) {
         return GetGlyphWidth(aCtx, aGID) / 65536.0;
     }
     if (mFUnitsConvFactor == 0.0f) {
         GetMetrics();
     }
     NS_ASSERTION(mFUnitsConvFactor > 0.0f,
                  "missing font unit conversion factor");
     if (!mHarfBuzzShaper) {
         mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
     }
     gfxHarfBuzzShaper* shaper =
         static_cast<gfxHarfBuzzShaper*>(mHarfBuzzShaper.get());
-    if (!shaper->Initialize() || !SetupCairoFont(aCtx)) {
+    if (!shaper->Initialize()) {
         return 0;
     }
     return shaper->GetGlyphHAdvance(aCtx, aGID) / 65536.0;
 }
 
 /*static*/
 PLDHashOperator
 gfxFont::AgeCacheEntry(CacheHashEntry *aEntry, void *aUserData)
--- a/intl/unicharutil/util/nsBidiUtils.h
+++ b/intl/unicharutil/util/nsBidiUtils.h
@@ -100,20 +100,16 @@ typedef enum nsCharType nsCharType;
    }
 
   /**
    * Give an nsString.
    * @return true if the string contains right-to-left characters
    */
    bool HasRTLChars(const nsAString& aString);
 
-// --------------------------------------------------
-// IBMBIDI 
-// --------------------------------------------------
-//
 // These values are shared with Preferences dialog
 //  ------------------
 //  If Pref values are to be changed
 //  in the XUL file of Prefs. the values
 //  Must be changed here too..
 //  ------------------
 //
 #define IBMBIDI_TEXTDIRECTION_STR       "bidi.direction"
--- a/ipc/dbus/DBusUtils.h
+++ b/ipc/dbus/DBusUtils.h
@@ -53,22 +53,20 @@ private:
 };
 
 /**
  * DBusReplyHandler represents a handler for DBus reply messages. Inherit
  * from this class and implement the Handle method. The method Callback
  * should be passed to the DBus send function, with the class instance as
  * user-data argument.
  */
-class DBusReplyHandler : public mozilla::RefCounted<DBusReplyHandler>
+class DBusReplyHandler
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_TYPENAME(DBusReplyHandler)
-  virtual ~DBusReplyHandler() {
-  }
+  NS_INLINE_DECL_REFCOUNTING(DBusReplyHandler)
 
   /**
    * Implements a call-back function for DBus. The supplied value for
    * aData must be a pointer to an instance of DBusReplyHandler.
    */
   static void Callback(DBusMessage* aReply, void* aData);
 
   /**
@@ -84,16 +82,20 @@ protected:
   DBusReplyHandler(const DBusReplyHandler& aHandler)
   {
   }
 
   DBusReplyHandler& operator = (const DBusReplyHandler& aRhs)
   {
     return *this;
   }
+
+  virtual ~DBusReplyHandler()
+  {
+  }
 };
 
 void log_and_free_dbus_error(DBusError* err,
                              const char* function,
                              DBusMessage* msg = nullptr);
 
 int dbus_returns_int32(DBusMessage *reply);
 
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -228,19 +228,19 @@ AddressOf(AsmJSImmKind kind, ExclusiveCo
       case AsmJSImm_aeabi_idivmod:
         return RedirectCall(FuncCast(__aeabi_idivmod), Args_General2);
       case AsmJSImm_aeabi_uidivmod:
         return RedirectCall(FuncCast(__aeabi_uidivmod), Args_General2);
 #endif
       case AsmJSImm_ModD:
         return RedirectCall(FuncCast(NumberMod), Args_Double_DoubleDouble);
       case AsmJSImm_SinD:
-        return RedirectCall(FuncCast<double (double)>(math_sin_impl), Args_Double_Double);
+        return RedirectCall(FuncCast<double (double)>(sin), Args_Double_Double);
       case AsmJSImm_CosD:
-        return RedirectCall(FuncCast<double (double)>(math_cos_impl), Args_Double_Double);
+        return RedirectCall(FuncCast<double (double)>(cos), Args_Double_Double);
       case AsmJSImm_TanD:
         return RedirectCall(FuncCast<double (double)>(tan), Args_Double_Double);
       case AsmJSImm_ASinD:
         return RedirectCall(FuncCast<double (double)>(asin), Args_Double_Double);
       case AsmJSImm_ACosD:
         return RedirectCall(FuncCast<double (double)>(acos), Args_Double_Double);
       case AsmJSImm_ATanD:
         return RedirectCall(FuncCast<double (double)>(atan), Args_Double_Double);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4343,30 +4343,35 @@ bool
 CodeGenerator::visitMathFunctionD(LMathFunctionD *ins)
 {
     Register temp = ToRegister(ins->temp());
     FloatRegister input = ToFloatRegister(ins->input());
     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
 
     const MathCache *mathCache = ins->mir()->cache();
 
+    masm.setupUnalignedABICall(mathCache ? 2 : 1, temp);
+    if (mathCache) {
+        masm.movePtr(ImmPtr(mathCache), temp);
+        masm.passABIArg(temp);
+    }
+    masm.passABIArg(input, MoveOp::DOUBLE);
+
 #   define MAYBE_CACHED(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached)
 
     void *funptr = nullptr;
     switch (ins->mir()->function()) {
       case MMathFunction::Log:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_log));
         break;
       case MMathFunction::Sin:
-        funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_sin_impl);
-        mathCache = nullptr;
+        funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_sin));
         break;
       case MMathFunction::Cos:
-        funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_cos_impl);
-        mathCache = nullptr;
+        funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_cos));
         break;
       case MMathFunction::Exp:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_exp));
         break;
       case MMathFunction::Tan:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_tan));
         break;
       case MMathFunction::ATan:
@@ -4414,39 +4419,29 @@ CodeGenerator::visitMathFunctionD(LMathF
       case MMathFunction::Trunc:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_trunc));
         break;
       case MMathFunction::Cbrt:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_cbrt));
         break;
       case MMathFunction::Floor:
         funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_floor_impl);
-        mathCache = nullptr;
         break;
       case MMathFunction::Ceil:
         funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_ceil_impl);
-        mathCache = nullptr;
         break;
       case MMathFunction::Round:
         funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_round_impl);
-        mathCache = nullptr;
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Unknown math function");
     }
 
 #   undef MAYBE_CACHED
 
-    masm.setupUnalignedABICall(mathCache ? 2 : 1, temp);
-    if (mathCache) {
-        masm.movePtr(ImmPtr(mathCache), temp);
-        masm.passABIArg(temp);
-    }
-    masm.passABIArg(input, MoveOp::DOUBLE);
-
     masm.callWithABI(funptr, MoveOp::DOUBLE);
     return true;
 }
 
 bool
 CodeGenerator::visitMathFunctionF(LMathFunctionF *ins)
 {
     Register temp = ToRegister(ins->temp());
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -327,165 +327,47 @@ js::math_clz32(JSContext *cx, unsigned a
         args.rval().setInt32(32);
         return true;
     }
 
     args.rval().setInt32(mozilla::CountLeadingZeroes32(n));
     return true;
 }
 
-/*
- * Fast sine and cosine approximation code, based on the sin [0] and cos [1]
- * implementations [2] in the cephes library [3].
- * Some of the optimization ideas are inspired by the fast_sincos in VDT [4].
- *
- * This implementation satisfies the requirements for sin and cos in JS [5].
- * However, it does not take the standard's recommendation to use fdlibm [6],
- * nor does it take advantage of the standard's intent to permit JS to use the
- * system C math library.
- *
- * The code carefully avoids branching, to avoid the cost of mispredictions
- * either on random input sets or on input sets straddling a boundary condition
- * in the algorithm. It contains only one branch, which is for testing for
- * unusual inputs (infinities, NaNs, and extremely large values), and it
- * should be very predictable.
- *
- * This implementation computes both a sin and cos value even when only one
- * of the two is needed. While creating specialized routines for computing just
- * sin or just cost would allow them to do less work, the speed benefits would
- * be expected to be marginal, and not worth the extra code it would take, given
- * that we'll still want the ability to compute sin and cos together anyway.
- *
- * [0] http://netlib.org/cephes/doubldoc.html#sin
- * [1] http://netlib.org/cephes/doubldoc.html#cos
- * [2] http://netlib.org/cephes/cmath.tgz
- * [3] http://netlib.org/cephes/
- * [4] https://svnweb.cern.ch/trac/vdt
- * [5] http://www.ecma-international.org/ecma-262/5.1/#sec-15.8.2
- * [6] http://netlib.org/fdlibm
- */
-
-static double polevl_sin(double z, double zz)
-{
-    // Constants generated using Mathematica's GeneralMiniMaxApproximation
-    double ans = 1.59046813973877163292e-10; // 6152825598094877 / exp2(85)
-    ans *= zz;
-    ans += -2.50509001624159785668e-08; // -7571170002733246 / exp2(78)
-    ans *= zz;
-    ans +=  2.75573146431678644161e-06; //  6506786951439440 / exp2(71)
-    ans *= zz;
-    ans += -1.98412698327005105692e-04; // -7320136534024805 / exp2(65)
-    ans *= zz;
-    ans +=  8.33333333332626768897e-03; //  4803839602524456 / exp2(59)
-    ans *= zz;
-    ans += -1.66666666666666490881e-01; // -6004799503160655 / exp2(55)
-    ans *= zz * z;
-    ans += z;
-    return ans;
-}
-
-static double polevl_cos(double zz)
+double
+js::math_cos_impl(MathCache *cache, double x)
 {
-    // Constants generated using Mathematica's GeneralMiniMaxApproximation.
-    // This set uses one less coefficient than usual implementations to
-    // increase performance, raising the maximum approximation error to 2 bits.
-    double ans = 2.06467337476762997948e-9;
-    ans *= zz;
-    ans += -2.75555495413759160741e-7;
-    ans *= zz;
-    ans +=  2.48015808595638122085e-5;
-    ans *= zz;
-    ans += -1.38888888779622760722e-3;
-    ans *= zz;
-    ans +=  4.16666666665987187046e-2;
-    ans *= zz;
-    ans += -4.99999999999999888978e-1;
-    ans *= zz;
-    ans += 1.0;
-    return ans;
-}
-
-namespace {
-struct sincos_result { double s, c; };
-}
-
-static sincos_result fast_sincos(double x)
-{
-    // Make argument non-negative but save the sign.
-    double orig_sign = js_copysign(1.0, x);
-    double absx = fabs(x);
-
-    // The optimized algorithm below doesn't currently support values of x beyond
-    // pow(2, 32) - 2. If x is beyond the range we support, fall back to the libm
-    // implementation. This check also handles the Infinity and NaN input cases.
-    // abs(x) < (221069929647945 / pow(2,16))
-    if (MOZ_UNLIKELY(!(absx < 3.37325942455970764160e9))) {
-        sincos_result result = {
-            sin(x),
-            cos(x)
-        };
-        return result;
-    }
-
-    static const double m_4_pi = 1.27323954473516276487; // 4.0 / M_PI
-    uint32_t i = static_cast<uint32_t>(absx * m_4_pi);
-
-    // Integer and fractional part modulo one octant.
-    uint32_t quad_index = ((i + 1) >> 1) & 3;
-    double y = static_cast<double>(i + (i & 1));
-
-    // Extended precision modular arithmetic
-    double e0 = y * -7.85398006439208984375e-1;  // 1647099 / pow(2,21)
-    double e1 = y * -1.56958208208379801363e-7;  // 1380619 / pow(2,43)
-    double e2 = y * -3.11168608594830669189e-14; // 4930663418217751 / pow(2,97)
-    double z = absx + e0 + e1 + e2;
-
-    // Compute the sin/cos in quadrant 0.
-    double zz = z * z;
-    double q0_sin = polevl_sin(z, zz);
-    double q0_cos = polevl_cos(zz);
-
-    // Reflect the result into the correct quadrant.
-    const double reflect[4] = {
-      q0_sin, q0_cos, -q0_sin, -q0_cos
-    };
-
-    // Adjust the sine value by the sign of the input.
-    // Missed optimization: C++ doesn't provide convenient access to
-    // floating-point xor; hand-written assembler could change the copysign
-    // above to use 0.0 instead of 1.0, and then just xor the sign with p[0]
-    // here instead of multiplying.
-    sincos_result result = {
-        reflect[quad_index] * orig_sign,
-        reflect[(quad_index + 1) & 3]
-    };
-    return result;
+    return cache->lookup(cos, x);
 }
 
 double
-js::math_cos_impl(double x)
+js::math_cos_uncached(double x)
 {
-    return fast_sincos(x).c;
+    return cos(x);
 }
 
 bool
 js::math_cos(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
         args.rval().setNaN();
         return true;
     }
 
     double x;
     if (!ToNumber(cx, args[0], &x))
         return false;
 
-    double z = math_cos_impl(x);
+    MathCache *mathCache = cx->runtime()->getMathCache(cx);
+    if (!mathCache)
+        return false;
+
+    double z = math_cos_impl(mathCache, x);
     args.rval().setDouble(z);
     return true;
 }
 
 #ifdef _WIN32
 #define EXP_IF_OUT_OF_RANGE(x)                  \
     if (!IsNaN(x)) {                            \
         if (x == PositiveInfinity<double>())    \
@@ -926,36 +808,46 @@ js::math_round(JSContext *cx, unsigned a
         return false;
 
     double z = math_round_impl(x);
     args.rval().setNumber(z);
     return true;
 }
 
 double
-js::math_sin_impl(double x)
+js::math_sin_impl(MathCache *cache, double x)
 {
-    return fast_sincos(x).s;
+    return cache->lookup(sin, x);
+}
+
+double
+js::math_sin_uncached(double x)
+{
+    return sin(x);
 }
 
 bool
 js::math_sin(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
         args.rval().setNaN();
         return true;
     }
 
     double x;
     if (!ToNumber(cx, args[0], &x))
         return false;
 
-    double z = math_sin_impl(x);
+    MathCache *mathCache = cx->runtime()->getMathCache(cx);
+    if (!mathCache)
+        return false;
+
+    double z = math_sin_impl(mathCache, x);
     args.rval().setDouble(z);
     return true;
 }
 
 bool
 js_math_sqrt(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -123,23 +123,29 @@ math_log_impl(MathCache *cache, double x
 
 extern double
 math_log_uncached(double x);
 
 extern bool
 math_sin(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern double
-math_sin_impl(double x);
+math_sin_impl(MathCache *cache, double x);
+
+extern double
+math_sin_uncached(double x);
 
 extern bool
 math_cos(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern double
-math_cos_impl(double x);
+math_cos_impl(MathCache *cache, double x);
+
+extern double
+math_cos_uncached(double x);
 
 extern bool
 math_exp(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern double
 math_exp_impl(MathCache *cache, double x);
 
 extern double
--- a/js/src/tests/lib/jittests.py
+++ b/js/src/tests/lib/jittests.py
@@ -369,16 +369,22 @@ def check_output(out, err, rc, timed_out
         if line.startswith('Trace stats check failed'):
             return False
 
     for line in err.split('\n'):
         if 'Assertion failed:' in line:
             return False
 
     if rc != test.expect_status:
+        # Tests which expect a timeout check for exit code 6.
+        # Sometimes 0 is returned on Windows for unknown reasons.
+        # See bug 899697.
+        if sys.platform in ['win32', 'cygwin'] and rc == 0:
+            return True
+
         # Allow a non-zero exit code if we want to allow OOM, but only if we
         # actually got OOM.
         return test.allow_oom and 'out of memory' in err and 'Assertion failure' not in err
 
     return True
 
 def print_tinderbox(ok, res):
     # Output test failures in a TBPL parsable format, eg:
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -2681,16 +2681,17 @@ ContainerState::InvalidateForLayerChange
   ThebesDisplayItemLayerUserData* data =
     static_cast<ThebesDisplayItemLayerUserData*>(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData));
   // If the frame is marked as invalidated, and didn't specify a rect to invalidate  then we want to
   // invalidate both the old and new bounds, otherwise we only want to invalidate the changed areas.
   // If we do get an invalid rect, then we want to add this on top of the change areas.
   nsRect invalid;
   nsRegion combined;
   nsPoint shift = aTopLeft - data->mLastAnimatedGeometryRootOrigin;
+  bool notifyRenderingChanged = true;
   if (!oldLayer) {
     // This item is being added for the first time, invalidate its entire area.
     //TODO: We call GetGeometry again in AddThebesDisplayItem, we should reuse this.
     combined = aClip.ApplyNonRoundedIntersection(aGeometry->ComputeInvalidationRegion());
 #ifdef MOZ_DUMP_PAINTING
     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
       printf_stderr("Display item type %s(%p) added to layer %p!\n", aItem->Name(), aItem->Frame(), aNewLayer);
     }
@@ -2703,16 +2704,31 @@ ContainerState::InvalidateForLayerChange
 #ifdef MOZ_DUMP_PAINTING
     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
       printf_stderr("Display item type %s(%p) (in layer %p) belongs to an invalidated frame!\n", aItem->Name(), aItem->Frame(), aNewLayer);
     }
 #endif
   } else {
     // Let the display item check for geometry changes and decide what needs to be
     // repainted.
+
+    // We have an optimization to cache the drawing background-attachment: fixed canvas
+    // background images so we can scroll and just blit them when they are flattened into
+    // the same layer as scrolling content. NotifyRenderingChanged is only used to tell
+    // the canvas bg image item to purge this cache. We want to be careful not to accidentally
+    // purge the cache if we are just invalidating due to scrolling (ie the background image
+    // moves on the scrolling layer but it's rendering stays the same) so if
+    // AddOffsetAndComputeDifference is the only thing that will invalidate we skip the
+    // NotifyRenderingChanged call (ComputeInvalidationRegion for background images also calls
+    // NotifyRenderingChanged if anything changes).
+    if (oldGeometry->ComputeInvalidationRegion() == aGeometry->ComputeInvalidationRegion() &&
+        *oldClip == aClip && invalid.IsEmpty() && changedFrames.Length() == 0) {
+      notifyRenderingChanged = false;
+    }
+
     oldGeometry->MoveBy(shift);
     aItem->ComputeInvalidationRegion(mBuilder, oldGeometry, &combined);
     oldClip->AddOffsetAndComputeDifference(shift, oldGeometry->ComputeInvalidationRegion(),
                                            aClip, aGeometry->ComputeInvalidationRegion(),
                                            &combined);
 
     // Add in any rect that the frame specified
     combined.Or(combined, invalid);
@@ -2730,17 +2746,19 @@ ContainerState::InvalidateForLayerChange
     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
       if (!combined.IsEmpty()) {
         printf_stderr("Display item type %s(%p) (in layer %p) changed geometry!\n", aItem->Name(), aItem->Frame(), aNewLayer);
       }
     }
 #endif
   }
   if (!combined.IsEmpty()) {
-    aItem->NotifyRenderingChanged();
+    if (notifyRenderingChanged) {
+      aItem->NotifyRenderingChanged();
+    }
     InvalidatePostTransformRegion(newThebesLayer,
         combined.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
         GetTranslationForThebesLayer(newThebesLayer));
   }
 }
 
 void
 FrameLayerBuilder::AddThebesDisplayItem(ThebesLayerData* aLayerData,
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -3,22 +3,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIStyleSheetService.idl',
 ]
 
-if CONFIG['IBMBIDI']:
-    UNIFIED_SOURCES += [
-        'nsBidi.cpp',
-        'nsBidiPresUtils.cpp',
-    ]
-
 if CONFIG['MOZ_DEBUG']:
     UNIFIED_SOURCES += [
         'nsAutoLayoutPhase.cpp',
     ]
 
 XPIDL_MODULE = 'layout_base'
 
 EXPORTS += [
@@ -67,16 +61,18 @@ EXPORTS.mozilla += [
 UNIFIED_SOURCES += [
     'ActiveLayerTracker.cpp',
     'DisplayItemClip.cpp',
     'DisplayListClipState.cpp',
     'FrameLayerBuilder.cpp',
     'FramePropertyTable.cpp',
     'GeometryUtils.cpp',
     'MaskLayerImageCache.cpp',
+    'nsBidi.cpp',
+    'nsBidiPresUtils.cpp',
     'nsCaret.cpp',
     'nsCounterManager.cpp',
     'nsCSSColorUtils.cpp',
     'nsCSSFrameConstructor.cpp',
     'nsCSSRendering.cpp',
     'nsCSSRenderingBorders.cpp',
     'nsDisplayList.cpp',
     'nsDisplayListInvalidation.cpp',
--- a/layout/base/nsBidi.cpp
+++ b/layout/base/nsBidi.cpp
@@ -1,14 +1,13 @@
 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifdef IBMBIDI
 
 #include "nsBidi.h"
 #include "nsUnicodeProperties.h"
 #include "nsCRTGlue.h"
 
 using namespace mozilla::unicode;
 
 // These are #defined in <sys/regset.h> under Solaris 10 x86
@@ -2213,9 +2212,8 @@ nsresult nsBidi::WriteReverse(const char
   }
 
   if(aSrcLength>0) {
     *aDestSize = doWriteReverse(aSrc, aSrcLength, aDest, aOptions);
   }
   return NS_OK;
 }
 #endif // FULL_BIDI_ENGINE
-#endif // IBMBIDI
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -1,15 +1,13 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifdef IBMBIDI
-
 #include "nsBidiPresUtils.h"
 #include "nsGkAtoms.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include "nsBidiUtils.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsContainerFrame.h"
 #include "nsInlineFrame.h"
@@ -2240,9 +2238,8 @@ nsBidiPresUtils::BidiLevelFromStyle(nsSt
   }
 
   if (aStyleContext->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
     return NSBIDI_RTL;
   }
 
   return NSBIDI_LTR;
 }
-#endif // IBMBIDI
--- a/layout/base/nsBidiPresUtils.h
+++ b/layout/base/nsBidiPresUtils.h
@@ -2,18 +2,16 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsBidiPresUtils_h___
 #define nsBidiPresUtils_h___
 
-#ifdef IBMBIDI
-
 #include "nsBidi.h"
 #include "nsBidiUtils.h"
 #include "nsHashKeys.h"
 #include "nsCoord.h"
 
 #ifdef DrawText
 #undef DrawText
 #endif
@@ -507,11 +505,9 @@ private:
                                      nsBidiLevel aBaseDirection,
                                      nsBidi* aBidiEngine);
 
   static void WriteReverse(const char16_t* aSrc,
                            uint32_t aSrcLength,
                            char16_t* aDest);
 };
 
-#endif // IBMBIDI
-
 #endif /* nsBidiPresUtils_h___ */
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -32,20 +32,18 @@
 #include "mozilla/Selection.h"
 #include <algorithm>
 
 // The bidi indicator hangs off the caret to one side, to show which
 // direction the typing is in. It needs to be at least 2x2 to avoid looking like 
 // an insignificant dot
 static const int32_t kMinBidiIndicatorPixels = 2;
 
-#ifdef IBMBIDI
 #include "nsIBidiKeyboard.h"
 #include "nsContentUtils.h"
-#endif //IBMBIDI
 
 using namespace mozilla;
 
 /**
  * Find the first frame in an in-order traversal of the frame subtree rooted
  * at aFrame which is either a text frame logically at the end of a line,
  * or which is aStopAtFrame. Return null if no such frame is found. We don't
  * descend into the children of non-eLineParticipant frames.
@@ -115,20 +113,18 @@ nsCaret::nsCaret()
 : mPresShell(nullptr)
 , mBlinkRate(500)
 , mVisible(false)
 , mDrawn(false)
 , mPendingDraw(false)
 , mReadOnly(false)
 , mShowDuringSelection(false)
 , mIgnoreUserModify(true)
-#ifdef IBMBIDI
 , mKeyboardRTL(false)
 , mLastBidiLevel(0)
-#endif
 , mLastContentOffset(0)
 , mLastHint(nsFrameSelection::HINTLEFT)
 {
 }
 
 //-----------------------------------------------------------------------------
 nsCaret::~nsCaret()
 {
@@ -175,19 +171,17 @@ nsresult nsCaret::Init(nsIPresShell *inP
     privateSelection->AddSelectionListener(this);
   mDomSelectionWeak = do_GetWeakReference(domSelection);
   
   // set up the blink timer
   if (mVisible)
   {
     StartBlinking();
   }
-#ifdef IBMBIDI
   mBidiUI = Preferences::GetBool("bidi.browser.ui");
-#endif
 
   return NS_OK;
 }
 
 static bool
 DrawCJKCaret(nsIFrame* aFrame, int32_t aOffset)
 {
   nsIContent* content = aFrame->GetContent();
@@ -1045,17 +1039,16 @@ nsCaret::UpdateCaretRects(nsIFrame* aFra
     return false;
   }
 
   // on RTL frames the right edge of mCaretRect must be equal to framePos
   const nsStyleVisibility* vis = aFrame->StyleVisibility();
   if (NS_STYLE_DIRECTION_RTL == vis->mDirection)
     mCaretRect.x -= mCaretRect.width;
 
-#ifdef IBMBIDI
   mHookRect.SetEmpty();
 
   // Simon -- make a hook to draw to the left or right of the caret to show keyboard language direction
   bool isCaretRTL = false;
   nsIBidiKeyboard* bidiKeyboard = nsContentUtils::GetBidiKeyboard();
   // if bidiKeyboard->IsLangRTL() fails, there is no way to tell the
   // keyboard direction, or the user has no right-to-left keyboard
   // installed, so we never draw the hook.
@@ -1081,17 +1074,16 @@ nsCaret::UpdateCaretRects(nsIFrame* aFra
     // rectangle.
     mHookRect.SetRect(mCaretRect.x + ((isCaretRTL) ?
                       bidiIndicatorSize * -1 :
                       mCaretRect.width),
                       mCaretRect.y + bidiIndicatorSize,
                       bidiIndicatorSize,
                       mCaretRect.width);
   }
-#endif //IBMBIDI
   return true;
 }
 
 //-----------------------------------------------------------------------------
 /* static */
 void nsCaret::CaretBlinkCallback(nsITimer *aTimer, void *aClosure)
 {
   nsCaret   *theCaret = reinterpret_cast<nsCaret*>(aClosure);
--- a/layout/base/nsCaret.h
+++ b/layout/base/nsCaret.h
@@ -196,21 +196,17 @@ protected:
     // it shouldn't be.
     bool          MustDrawCaret(bool aIgnoreDrawnState);
 
     void          DrawCaret(bool aInvalidate);
     void          DrawCaretAfterBriefDelay();
     bool          UpdateCaretRects(nsIFrame* aFrame, int32_t aFrameOffset);
     nsRect        GetHookRect()
     {
-#ifdef IBMBIDI
       return mHookRect;
-#else
-      return nsRect();
-#endif
     }
     void          ToggleDrawnStatus() { mDrawn = !mDrawn; }
 
     nsFrameSelection* GetFrameSelection();
 
     // Returns true if we should not draw the caret because of XUL menu popups.
     // The caret should be hidden if:
     // 1. An open popup contains the caret, but a menu popup exists before the
@@ -239,22 +235,20 @@ protected:
     bool                  mDrawn;             // Denotes when the caret is physically drawn on the screen.
     bool                  mPendingDraw;       // True when the last on-state draw was suppressed.
 
     bool                  mReadOnly;          // it the caret in readonly state (draws differently)      
     bool                  mShowDuringSelection; // show when text is selected
 
     bool                  mIgnoreUserModify;
 
-#ifdef IBMBIDI
     bool                  mKeyboardRTL;       // is the keyboard language right-to-left
     bool                  mBidiUI;            // is bidi UI turned on
     nsRect                mHookRect;          // directional hook on the caret
     uint8_t               mLastBidiLevel;     // saved bidi level of the last draw request, to use when we erase
-#endif
     nsRect                mCaretRect;         // the last caret rect, in the coodinates of the last frame.
 
     nsCOMPtr<nsIContent>  mLastContent;       // store the content the caret was last requested to be drawn
                                               // in (by DrawAtPosition()/DrawCaret()),
                                               // note that this can be different than where it was
                                               // actually drawn (anon <BR> in text control)
     int32_t               mLastContentOffset; // the offset for the last request
 
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2320,28 +2320,36 @@ void nsDisplayBackgroundImage::ComputeIn
   nsRect bounds = GetBounds(aBuilder, &snap);
   nsRect positioningArea = GetPositioningArea();
   if (positioningArea.TopLeft() != geometry->mPositioningArea.TopLeft() ||
       (positioningArea.Size() != geometry->mPositioningArea.Size() &&
        RenderingMightDependOnPositioningAreaSizeChange())) {
     // Positioning area changed in a way that could cause everything to change,
     // so invalidate everything (both old and new painting areas).
     aInvalidRegion->Or(bounds, geometry->mBounds);
+
+    if (positioningArea.Size() != geometry->mPositioningArea.Size()) {
+      NotifyRenderingChanged();
+    }
     return;
   }
   if (aBuilder->ShouldSyncDecodeImages()) {
     if (mBackgroundStyle &&
         !nsCSSRendering::IsBackgroundImageDecodedForStyleContextAndLayer(mBackgroundStyle, mLayer)) {
       aInvalidRegion->Or(*aInvalidRegion, bounds);
+
+      NotifyRenderingChanged();
     }
   }
   if (!bounds.IsEqualInterior(geometry->mBounds)) {
     // Positioning area is unchanged, so invalidate just the change in the
     // painting area.
     aInvalidRegion->Xor(bounds, geometry->mBounds);
+
+    NotifyRenderingChanged();
   }
 }
 
 nsRect
 nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   *aSnap = true;
   return mBounds;
 }
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1022,33 +1022,35 @@ nsLayoutUtils::GetChildListNameFor(nsIFr
 // static
 nsIFrame*
 nsLayoutUtils::GetBeforeFrame(nsIFrame* aFrame)
 {
   NS_PRECONDITION(aFrame, "NULL frame pointer");
   NS_ASSERTION(!aFrame->GetPrevContinuation(),
                "aFrame must be first continuation");
 
-  nsIFrame* firstFrame = GetFirstChildFrame(aFrame, aFrame->GetContent());
+  nsIFrame* cif = aFrame->GetContentInsertionFrame();
+  nsIFrame* firstFrame = GetFirstChildFrame(cif, aFrame->GetContent());
 
   if (firstFrame && IsGeneratedContentFor(nullptr, firstFrame,
                                           nsCSSPseudoElements::before)) {
     return firstFrame;
   }
 
   return nullptr;
 }
 
 // static
 nsIFrame*
 nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame)
 {
   NS_PRECONDITION(aFrame, "NULL frame pointer");
 
-  nsIFrame* lastFrame = GetLastChildFrame(aFrame, aFrame->GetContent());
+  nsIFrame* cif = aFrame->GetContentInsertionFrame();
+  nsIFrame* lastFrame = GetLastChildFrame(cif, aFrame->GetContent());
 
   if (lastFrame && IsGeneratedContentFor(nullptr, lastFrame,
                                          nsCSSPseudoElements::after)) {
     return lastFrame;
   }
 
   return nullptr;
 }
@@ -4282,50 +4284,46 @@ nsLayoutUtils::GetSnappedBaselineY(nsIFr
 void
 nsLayoutUtils::DrawString(const nsIFrame*       aFrame,
                           nsRenderingContext*   aContext,
                           const char16_t*      aString,
                           int32_t               aLength,
                           nsPoint               aPoint,
                           nsStyleContext*       aStyleContext)
 {
-#ifdef IBMBIDI
   nsresult rv = NS_ERROR_FAILURE;
   nsPresContext* presContext = aFrame->PresContext();
   if (presContext->BidiEnabled()) {
     nsBidiLevel level =
       nsBidiPresUtils::BidiLevelFromStyle(aStyleContext ?
                                           aStyleContext : aFrame->StyleContext());
     rv = nsBidiPresUtils::RenderText(aString, aLength, level,
                                      presContext, *aContext, *aContext,
                                      aPoint.x, aPoint.y);
   }
   if (NS_FAILED(rv))
-#endif // IBMBIDI
   {
     aContext->SetTextRunRTL(false);
     aContext->DrawString(aString, aLength, aPoint.x, aPoint.y);
   }
 }
 
 nscoord
 nsLayoutUtils::GetStringWidth(const nsIFrame*      aFrame,
                               nsRenderingContext* aContext,
                               const char16_t*     aString,
                               int32_t              aLength)
 {
-#ifdef IBMBIDI
   nsPresContext* presContext = aFrame->PresContext();
   if (presContext->BidiEnabled()) {
     nsBidiLevel level =
       nsBidiPresUtils::BidiLevelFromStyle(aFrame->StyleContext());
     return nsBidiPresUtils::MeasureTextWidth(aString, aLength,
                                              level, presContext, *aContext);
   }
-#endif // IBMBIDI
   aContext->SetTextRunRTL(false);
   return aContext->GetWidth(aString, aLength);
 }
 
 /* static */ void
 nsLayoutUtils::PaintTextShadow(const nsIFrame* aFrame,
                                nsRenderingContext* aContext,
                                const nsRect& aTextRect,
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -160,29 +160,27 @@ void
 nsPresContext::PrefChangedUpdateTimerCallback(nsITimer *aTimer, void *aClosure)
 {
   nsPresContext*  presContext = (nsPresContext*)aClosure;
   NS_ASSERTION(presContext != nullptr, "bad instance data");
   if (presContext)
     presContext->UpdateAfterPreferencesChanged();
 }
 
-#ifdef IBMBIDI
 static bool
 IsVisualCharset(const nsCString& aCharset)
 {
   if (aCharset.LowerCaseEqualsLiteral("ibm862")             // Hebrew
       || aCharset.LowerCaseEqualsLiteral("iso-8859-8") ) {  // Hebrew
     return true; // visual text type
   }
   else {
     return false; // logical text type
   }
 }
-#endif // IBMBIDI
 
   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
   // bother initializing members to 0.
 
 nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
   : mType(aType), mDocument(aDocument), mBaseMinFontSize(0),
     mTextZoom(1.0), mFullZoom(1.0), mLastFontInflationScreenWidth(-1.0),
     mPageSize(-1, -1), mPPScale(1.0f),
@@ -289,21 +287,19 @@ nsPresContext::~nsPresContext()
                                   "browser.active_color",
                                   this);
   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
                                   "browser.visited_color",
                                   this);
   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
                                   "image.animation_mode",
                                   this);
-#ifdef IBMBIDI
   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
                                   "bidi.",
                                   this);
-#endif // IBMBIDI
   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
                                   "dom.send_after_paint_to_content",
                                   this);
   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
                                   "gfx.font_rendering.",
                                   this);
   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
                                   "layout.css.dpi",
@@ -1023,21 +1019,19 @@ nsPresContext::Init(nsDeviceContext* aDe
                                 "browser.active_color",
                                 this);
   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
                                 "browser.visited_color",
                                 this);
   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
                                 "image.animation_mode",
                                 this);
-#ifdef IBMBIDI
   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
                                 "bidi.",
                                 this);
-#endif
   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
                                 "dom.send_after_paint_to_content",
                                 this);
   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
                                 "gfx.font_rendering.",
                                 this);
   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
                                 "layout.css.dpi",
@@ -1159,34 +1153,31 @@ nsPresContext::UpdateCharSet(const nsCSt
     // this will be a language group (or script) code rather than a true language code
 
     // bug 39570: moved from nsLanguageAtomService::LookupCharSet()
     if (mLanguage == nsGkAtoms::Unicode) {
       mLanguage = mLangService->GetLocaleLanguage();
     }
     ResetCachedFontPrefs();
   }
-#ifdef IBMBIDI
-  //ahmed
 
   switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
 
     case IBMBIDI_TEXTTYPE_LOGICAL:
       SetVisualMode(false);
       break;
 
     case IBMBIDI_TEXTTYPE_VISUAL:
       SetVisualMode(true);
       break;
 
     case IBMBIDI_TEXTTYPE_CHARSET:
     default:
       SetVisualMode(IsVisualCharset(aCharSet));
   }
-#endif // IBMBIDI
 }
 
 NS_IMETHODIMP
 nsPresContext::Observe(nsISupports* aSubject,
                         const char* aTopic,
                         const char16_t* aData)
 {
   if (!nsCRT::strcmp(aTopic, "charset")) {
@@ -1568,17 +1559,16 @@ nsPresContext::StyleUpdateForAllAnimatio
 }
 
 void
 nsPresContext::TickLastStyleUpdateForAllAnimations()
 {
   mLastStyleUpdateForAllAnimations = mRefreshDriver->MostRecentRefresh();
 }
 
-#ifdef IBMBIDI
 bool
 nsPresContext::BidiEnabledExternal() const
 {
   return BidiEnabledInternal();
 }
 
 bool
 nsPresContext::BidiEnabledInternal() const
@@ -1634,18 +1624,16 @@ nsPresContext::SetBidi(uint32_t aSource,
 }
 
 uint32_t
 nsPresContext::GetBidi() const
 {
   return Document()->GetBidiOptions();
 }
 
-#endif //IBMBIDI
-
 bool
 nsPresContext::IsTopLevelWindowInactive()
 {
   nsCOMPtr<nsIDocShellTreeItem> treeItem(mContainer);
   if (!treeItem)
     return false;
 
   nsCOMPtr<nsIDocShellTreeItem> rootItem;
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -32,20 +32,17 @@
 #include "nsAutoPtr.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/AppUnits.h"
 #include "prclist.h"
 #include "nsThreadUtils.h"
 #include "ScrollbarStyles.h"
 
-#ifdef IBMBIDI
 class nsBidiPresUtils;
-#endif // IBMBIDI
-
 class nsAString;
 class nsIPrintSettings;
 class nsDocShell;
 class nsIDocShell;
 class nsIDocument;
 class nsILanguageAtomService;
 class nsITheme;
 class nsIContent;
@@ -687,17 +684,16 @@ public:
    */
   bool ThrottledTransitionStyleIsUpToDate() const;
   void TickLastUpdateThrottledTransitionStyle();
   bool ThrottledAnimationStyleIsUpToDate() const;
   void TickLastUpdateThrottledAnimationStyle();
   bool StyleUpdateForAllAnimationsIsUpToDate();
   void TickLastStyleUpdateForAllAnimations();
 
-#ifdef IBMBIDI
   /**
    *  Check if bidi enabled (set depending on the presence of RTL
    *  characters or when default directionality is RTL).
    *  If enabled, we should apply the Unicode Bidi Algorithm
    *
    *  @lina 07/12/2000
    */
 #ifdef MOZILLA_INTERNAL_API
@@ -750,17 +746,16 @@ public:
                            bool aForceRestyle = false);
 
   /**
    * Get the Bidi options for the presentation context
    * Not inline so consumers of nsPresContext are not forced to
    * include nsIDocument.
    */
   NS_HIDDEN_(uint32_t) GetBidi() const;
-#endif // IBMBIDI
 
   /**
    * Render only Selection
    */
   void SetIsRenderingOnlySelection(bool aResult)
   {
     mIsRenderingOnlySelection = aResult;
   }
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -464,8 +464,9 @@ skip-if = true || (toolkit == 'android')
 [test_getBoxQuads_convertPointRectQuad.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 948948
 [test_bug687297.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 948948
 support-files =
   bug687297_a.html
   bug687297_b.html
   bug687297_c.html
+[test_bug990340.html]
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/test_bug990340.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=990340
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 990340</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 990340 **/
+
+  function testbug990340() {
+    ok(document.querySelector('#bug990340 span').clientHeight < 100,
+       "'height' is in transition")
+    SimpleTest.finish();
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=990340">Mozilla Bug 990340</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<style type="text/css">
+
+#bug990340::before {
+    content: ":before";
+}
+
+#bug990340 span {
+    display: inline-block;
+    border:1px solid blue;
+    height: 20px;
+    transition: height 30s;
+}
+
+#bug990340.s span {
+    height: 100px;
+}
+</style>
+<div id="bug990340" style="overflow:scroll">
+    <span>Transition height</span>
+</div>
+</pre>
+
+<script>
+document.body.offsetHeight;
+document.querySelector('#bug990340').className='s';
+testbug990340()
+</script>
+
+</body>
+</html>
--- a/layout/forms/nsLegendFrame.cpp
+++ b/layout/forms/nsLegendFrame.cpp
@@ -61,21 +61,19 @@ nsLegendFrame::Reflow(nsPresContext*    
   return nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
 }
 
 // REVIEW: We don't need to override BuildDisplayList, nsBlockFrame will honour
 // our visibility setting
 int32_t nsLegendFrame::GetAlign()
 {
   int32_t intValue = NS_STYLE_TEXT_ALIGN_LEFT;
-#ifdef IBMBIDI
   if (mParent && NS_STYLE_DIRECTION_RTL == mParent->StyleVisibility()->mDirection) {
     intValue = NS_STYLE_TEXT_ALIGN_RIGHT;
   }
-#endif // IBMBIDI
 
   nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
 
   if (content) {
     const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::align);
     if (attr && attr->Type() == nsAttrValue::eEnum) {
       intValue = attr->GetEnumValue();
     }
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -44,19 +44,17 @@
 #include "nsLayoutUtils.h"
 #include "nsDisplayList.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsRenderingContext.h"
 #include "TextOverflow.h"
 #include "nsIFrameInlines.h"
 
-#ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
-#endif // IBMBIDI
 
 static const int MIN_LINES_NEEDING_CURSOR = 20;
 
 static const char16_t kDiscCharacter = 0x2022;
 static const char16_t kCircleCharacter = 0x25e6;
 static const char16_t kSquareCharacter = 0x25aa;
 
 #define DISABLE_FLOAT_BREAKING_IN_COLUMNS
@@ -1018,20 +1016,18 @@ nsBlockFrame::Reflow(nsPresContext*     
   IsMarginRoot(&topMarginRoot, &bottomMarginRoot);
 
   // Cache the consumed height in the block reflow state so that we don't have
   // to continually recompute it.
   nsBlockReflowState state(*reflowState, aPresContext, this,
                            topMarginRoot, bottomMarginRoot, needFloatManager,
                            consumedHeight);
 
-#ifdef IBMBIDI
   if (GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION)
     static_cast<nsBlockFrame*>(FirstContinuation())->ResolveBidi();
-#endif // IBMBIDI
 
   if (RenumberLists(aPresContext)) {
     AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   }
 
   nsresult rv = NS_OK;
 
   // ALWAYS drain overflow. We never want to leave the previnflow's
@@ -4759,20 +4755,17 @@ nsBlockFrame::InsertFrames(ChildListID a
   if (aListID != kPrincipalList) {
     if (kAbsoluteList == aListID) {
       return nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
     }
     else if (kFloatList == aListID) {
       mFloats.InsertFrames(this, aPrevFrame, aFrameList);
       return NS_OK;
     }
-#ifdef IBMBIDI
-    else if (kNoReflowPrincipalList == aListID) {}
-#endif // IBMBIDI
-    else {
+    else if (kNoReflowPrincipalList != aListID) {
       NS_ERROR("unexpected child list");
       return NS_ERROR_INVALID_ARG;
     }
   }
 
 #ifdef NOISY_REFLOW_REASON
   ListTag(stdout);
   printf(": insert ");
@@ -4781,19 +4774,17 @@ nsBlockFrame::InsertFrames(ChildListID a
     printf(" after ");
     nsFrame::ListTag(stdout, aPrevFrame);
   }
   printf("\n");
 #endif
 
   AddFrames(aFrameList, aPrevFrame);
 
-#ifdef IBMBIDI
   if (aListID != kNoReflowPrincipalList)
-#endif // IBMBIDI
     PresContext()->PresShell()->
       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                        NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
   return NS_OK;
 }
 
 static bool
 ShouldPutNextSiblingOnNewLine(nsIFrame* aLastFrame)
@@ -5066,22 +5057,20 @@ nsBlockFrame::RemoveFrame(ChildListID aL
                  "RemoveFrame should not be called on pushed floats.");
     for (nsIFrame* f = aOldFrame;
          f && !(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
          f = f->GetNextContinuation()) {
       MarkSameFloatManagerLinesDirty(static_cast<nsBlockFrame*>(f->GetParent()));
     }
     DoRemoveOutOfFlowFrame(aOldFrame);
   }
-#ifdef IBMBIDI
   else if (kNoReflowPrincipalList == aListID) {
     // Skip the call to |FrameNeedsReflow| below by returning now.
     return DoRemoveFrame(aOldFrame, REMOVE_FIXED_CONTINUATIONS);
   }
-#endif // IBMBIDI
   else {
     NS_ERROR("unexpected child list");
     rv = NS_ERROR_INVALID_ARG;
   }
 
   if (NS_SUCCEEDED(rv)) {
     PresContext()->PresShell()->
       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
@@ -7145,31 +7134,29 @@ nsBlockFrame::ComputeFinalHeight(const n
                                  aContentHeight);
       NS_FRAME_SET_INCOMPLETE(*aStatus);
       if (!GetNextInFlow())
         *aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
     }
   }
 }
 
-#ifdef IBMBIDI
 nsresult
 nsBlockFrame::ResolveBidi()
 {
   NS_ASSERTION(!GetPrevInFlow(),
                "ResolveBidi called on non-first continuation");
 
   nsPresContext* presContext = PresContext();
   if (!presContext->BidiEnabled()) {
     return NS_OK;
   }
 
   return nsBidiPresUtils::Resolve(this);
 }
-#endif
 
 #ifdef DEBUG
 void
 nsBlockFrame::VerifyLines(bool aFinalCheckOK)
 {
   if (!gVerifyLines) {
     return;
   }
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -429,32 +429,30 @@ protected:
    * This block thinks in terms of lines, but the frame construction code
    * knows nothing about lines at all so we need to find the line that
    * contains aPrevSibling and add aFrameList after aPrevSibling on that line.
    * New lines are created as necessary to handle block data in aFrameList.
    * This function will clear aFrameList.
    */
   void AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling);
 
-#ifdef IBMBIDI
   /**
    * Perform Bidi resolution on this frame
    */
   nsresult ResolveBidi();
 
   /**
    * Test whether the frame is a form control in a visual Bidi page.
    * This is necessary for backwards-compatibility, because most visual
    * pages use logical order for form controls so that they will
    * display correctly on native widgets in OSs with Bidi support
    * @param aPresContext the pres context
    * @return whether the frame is a BIDI form control
    */
   bool IsVisualFormControl(nsPresContext* aPresContext);
-#endif
 
 public:
   /**
    * Does all the real work for removing aDeletedFrame
    * -- finds the line containing aDeletedFrame
    * -- removes all aDeletedFrame next-in-flows (or all continuations,
    * if REMOVE_FIXED_CONTINUATIONS is given)
    * -- marks lines dirty as needed
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -165,22 +165,16 @@ public:
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion* aInvalidRegion) MOZ_OVERRIDE
   {
     const nsDisplayItemBoundsGeometry* geometry = static_cast<const nsDisplayItemBoundsGeometry*>(aGeometry);
     ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion);
   }
 
-  virtual void NotifyRenderingChanged() MOZ_OVERRIDE
-  {
-    mFrame->Properties().Delete(nsIFrame::CachedBackgroundImage());
-    mFrame->Properties().Delete(nsIFrame::CachedBackgroundImageDT());
-  }
-
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
 
   void SetExtraBackgroundColor(nscolor aColor)
   {
     mColor = aColor;
   }
 
@@ -194,16 +188,22 @@ class nsDisplayCanvasBackgroundImage : p
 public:
   nsDisplayCanvasBackgroundImage(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                                  uint32_t aLayer, const nsStyleBackground* aBg)
     : nsDisplayBackgroundImage(aBuilder, aFrame, aLayer, aBg)
   {}
 
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
 
+  virtual void NotifyRenderingChanged() MOZ_OVERRIDE
+  {
+    mFrame->Properties().Delete(nsIFrame::CachedBackgroundImage());
+    mFrame->Properties().Delete(nsIFrame::CachedBackgroundImageDT());
+  }
+
   virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
   {
     // Put background-attachment:fixed canvas background images in their own
     // compositing layer. Since we know their background painting area can't
     // change (unless the viewport size itself changes), async scrolling
     // will work well.
     return mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
            !mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty();
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -91,31 +91,27 @@ nsContainerFrame::SetInitialChildList(Ch
   return result;
 }
 
 nsresult
 nsContainerFrame::AppendFrames(ChildListID  aListID,
                                nsFrameList& aFrameList)
 {
   if (aListID != kPrincipalList) {
-#ifdef IBMBIDI
     if (aListID != kNoReflowPrincipalList)
-#endif
     {
       NS_ERROR("unexpected child list");
       return NS_ERROR_INVALID_ARG;
     }
   }
   if (aFrameList.NotEmpty()) {
     mFrames.AppendFrames(this, aFrameList);
 
     // Ask the parent frame to reflow me.
-#ifdef IBMBIDI
     if (aListID == kPrincipalList)
-#endif
     {
       PresContext()->PresShell()->
         FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                          NS_FRAME_HAS_DIRTY_CHILDREN);
     }
   }
   return NS_OK;
 }
@@ -124,63 +120,55 @@ nsresult
 nsContainerFrame::InsertFrames(ChildListID aListID,
                                nsIFrame* aPrevFrame,
                                nsFrameList& aFrameList)
 {
   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
                "inserting after sibling frame with different parent");
 
   if (aListID != kPrincipalList) {
-#ifdef IBMBIDI
     if (aListID != kNoReflowPrincipalList)
-#endif
     {
       NS_ERROR("unexpected child list");
       return NS_ERROR_INVALID_ARG;
     }
   }
   if (aFrameList.NotEmpty()) {
     // Insert frames after aPrevFrame
     mFrames.InsertFrames(this, aPrevFrame, aFrameList);
 
-#ifdef IBMBIDI
     if (aListID == kPrincipalList)
-#endif
     {
       PresContext()->PresShell()->
         FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                          NS_FRAME_HAS_DIRTY_CHILDREN);
     }
   }
   return NS_OK;
 }
 
 nsresult
 nsContainerFrame::RemoveFrame(ChildListID aListID,
                               nsIFrame* aOldFrame)
 {
   if (aListID != kPrincipalList) {
-#ifdef IBMBIDI
     if (kNoReflowPrincipalList != aListID)
-#endif
     {
       NS_ERROR("unexpected child list");
       return NS_ERROR_INVALID_ARG;
     }
   }
 
   // Loop and destroy aOldFrame and all of its continuations.
   // Request a reflow on the parent frames involved unless we were explicitly
   // told not to (kNoReflowPrincipalList).
   bool generateReflowCommand = true;
-#ifdef IBMBIDI
   if (kNoReflowPrincipalList == aListID) {
     generateReflowCommand = false;
   }
-#endif
   nsIPresShell* shell = PresContext()->PresShell();
   nsContainerFrame* lastParent = nullptr;
   while (aOldFrame) {
     //XXXfr probably should use StealFrame here. I'm not sure if we need to
     //      check the overflow lists atm, but we'll need a prescontext lookup
     //      for overflow containers once we can split abspos elements with
     //      inline containing blocks.
     nsIFrame* oldFrameNextContinuation = aOldFrame->GetNextContinuation();
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -43,19 +43,17 @@
 #include "nsFrameTraversal.h"
 #include "nsRange.h"
 #include "nsITextControlFrame.h"
 #include "nsNameSpaceManager.h"
 #include "nsIPercentHeightObserver.h"
 #include "nsStyleStructInlines.h"
 #include <algorithm>
 
-#ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
-#endif
 
 // For triple-click pref
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "nsError.h"
 #include "nsContainerFrame.h"
 #include "nsBoxLayoutState.h"
 #include "nsBlockFrame.h"
@@ -6546,34 +6544,31 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct*
       NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
 
       int32_t lineFrameCount;
       nsIFrame *firstFrame;
       nsRect usedRect;
       uint32_t lineFlags;
       nsIFrame* baseFrame = nullptr;
       bool endOfLine = (eSelectEndLine == aPos->mAmount);
-      
-#ifdef IBMBIDI
+
       if (aPos->mVisual && PresContext()->BidiEnabled()) {
         bool lineIsRTL = it->GetDirection();
         bool isReordered;
         nsIFrame *lastFrame;
         result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
         baseFrame = endOfLine ? lastFrame : firstFrame;
         if (baseFrame) {
           nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(baseFrame);
           // If the direction of the frame on the edge is opposite to that of the line,
           // we'll need to drill down to its opposite end, so reverse endOfLine.
           if ((embeddingLevel & 1) == !lineIsRTL)
             endOfLine = !endOfLine;
         }
-      } else
-#endif
-      {
+      } else {
         it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect, &lineFlags);
 
         nsIFrame* frame = firstFrame;
         for (int32_t count = lineFrameCount; count;
              --count, frame = frame->GetNextSibling()) {
           if (!frame->IsGeneratedContentFrame()) {
             baseFrame = frame;
             if (!endOfLine)
@@ -6775,17 +6770,16 @@ nsIFrame::GetFrameFromDirection(nsDirect
       return NS_ERROR_FAILURE;
 
     nsAutoLineIterator it = blockFrame->GetLineIterator();
     NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
 
     bool atLineEdge;
     nsIFrame *firstFrame;
     nsIFrame *lastFrame;
-#ifdef IBMBIDI
     if (aVisual && presContext->BidiEnabled()) {
       bool lineIsRTL = it->GetDirection();
       bool isReordered;
       result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
       nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame;
       if (*framePtr) {
         nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(*framePtr);
         if ((((embeddingLevel & 1) && lineIsRTL) || (!(embeddingLevel & 1) && !lineIsRTL)) ==
@@ -6793,19 +6787,17 @@ nsIFrame::GetFrameFromDirection(nsDirect
           nsFrame::GetFirstLeaf(presContext, framePtr);
         } else {
           nsFrame::GetLastLeaf(presContext, framePtr);
         }
         atLineEdge = *framePtr == traversedFrame;
       } else {
         atLineEdge = true;
       }
-    } else
-#endif
-    {
+    } else {
       nsRect  nonUsedRect;
       int32_t lineFrameCount;
       uint32_t lineFlags;
       result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,nonUsedRect,
                            &lineFlags);
       if (NS_FAILED(result))
         return result;
 
@@ -6851,24 +6843,22 @@ nsIFrame::GetFrameFromDirection(nsDirect
     traversedFrame = frameTraversal->CurrentItem();
     if (!traversedFrame)
       return NS_ERROR_FAILURE;
     traversedFrame->IsSelectable(&selectable, nullptr);
   } // while (!selectable)
 
   *aOutOffset = (aDirection == eDirNext) ? 0 : -1;
 
-#ifdef IBMBIDI
   if (aVisual) {
     uint8_t newLevel = NS_GET_EMBEDDING_LEVEL(traversedFrame);
     uint8_t newBaseLevel = NS_GET_BASE_LEVEL(traversedFrame);
     if ((newLevel & 1) != (newBaseLevel & 1)) // The new frame is reverse-direction, go to the other end
       *aOutOffset = -1 - *aOutOffset;
   }
-#endif
   *aOutFrame = traversedFrame;
   return NS_OK;
 }
 
 nsView* nsIFrame::GetClosestView(nsPoint* aOffset) const
 {
   nsPoint offset(0,0);
   for (const nsIFrame *f = this; f; f = f->GetParent()) {
--- a/layout/generic/nsFrameList.cpp
+++ b/layout/generic/nsFrameList.cpp
@@ -4,21 +4,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsFrameList.h"
 #include "nsIFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 
-#ifdef IBMBIDI
 #include "nsGkAtoms.h"
 #include "nsILineIterator.h"
 #include "nsBidiPresUtils.h"
-#endif // IBMBIDI
 
 namespace mozilla {
 namespace layout {
 namespace detail {
 const AlignedFrameListBytes gEmptyFrameListBytes = { 0 };
 }
 }
 }
@@ -339,17 +337,16 @@ nsFrameList::List(FILE* out) const
   for (nsIFrame* frame = mFirstChild; frame;
        frame = frame->GetNextSibling()) {
     frame->List(out, "  ");
   }
   fprintf_stderr(out, ">\n");
 }
 #endif
 
-#ifdef IBMBIDI
 nsIFrame*
 nsFrameList::GetPrevVisualFor(nsIFrame* aFrame) const
 {
   if (!mFirstChild)
     return nullptr;
   
   nsIFrame* parent = mFirstChild->GetParent();
   if (!parent)
@@ -488,17 +485,16 @@ nsFrameList::GetNextVisualFor(nsIFrame* 
     if (baseLevel == NSBIDI_LTR) {
       frame = nsBidiPresUtils::GetFrameToRightOf(nullptr, firstFrameOnLine, numFramesOnLine);
     } else { // RTL
       frame = nsBidiPresUtils::GetFrameToLeftOf(nullptr, firstFrameOnLine, numFramesOnLine);
     }
   }
   return frame;
 }
-#endif
 
 #ifdef DEBUG_FRAME_LIST
 void
 nsFrameList::VerifyList() const
 {
   NS_ASSERTION((mFirstChild == nullptr) == (mLastChild == nullptr),
                "bad list state");
 
--- a/layout/generic/nsFrameList.h
+++ b/layout/generic/nsFrameList.h
@@ -264,29 +264,27 @@ public:
   /**
    * If this frame list is non-empty then append it to aLists as the
    * aListID child list.
    * (this method is implemented in FrameChildList.h for dependency reasons)
    */
   inline void AppendIfNonempty(nsTArray<mozilla::layout::FrameChildList>* aLists,
                                mozilla::layout::FrameChildListID aListID) const;
 
-#ifdef IBMBIDI
   /**
    * Return the frame before this frame in visual order (after Bidi reordering).
    * If aFrame is null, return the last frame in visual order.
    */
   nsIFrame* GetPrevVisualFor(nsIFrame* aFrame) const;
 
   /**
    * Return the frame after this frame in visual order (after Bidi reordering).
    * If aFrame is null, return the first frame in visual order.
    */
   nsIFrame* GetNextVisualFor(nsIFrame* aFrame) const;
-#endif // IBMBIDI
 
 #ifdef DEBUG_FRAME_DUMP
   void List(FILE* out) const;
 #endif
 
   static inline const nsFrameList& EmptyList();
 
   class Enumerator;
--- a/layout/generic/nsFrameSelection.h
+++ b/layout/generic/nsFrameSelection.h
@@ -19,19 +19,17 @@
 class nsTableOuterFrame;
 
 // IID for the nsFrameSelection interface
 // 3c6ae2d0-4cf1-44a1-9e9d-2411867f19c6
 #define NS_FRAME_SELECTION_IID      \
 { 0x3c6ae2d0, 0x4cf1, 0x44a1, \
   { 0x9e, 0x9d, 0x24, 0x11, 0x86, 0x7f, 0x19, 0xc6 } }
 
-#ifdef IBMBIDI // Constant for Set/Get CaretBidiLevel
 #define BIDI_LEVEL_UNDEFINED 0x80
-#endif
 
 //----------------------------------------------------------------------
 
 // Selection interface
 
 struct SelectionDetails
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
@@ -406,32 +404,30 @@ public:
    */
   /*unsafe*/
   void CommonPageMove(bool aForward,
                       bool aExtend,
                       nsIScrollableFrame* aScrollableFrame);
 
   void SetHint(HINT aHintRight) { mHint = aHintRight; }
   HINT GetHint() const { return mHint; }
-  
-#ifdef IBMBIDI
+
   /** SetCaretBidiLevel sets the caret bidi level
    *  @param aLevel the caret bidi level
    *  This method is virtual since it gets called from outside of layout.
    */
   virtual void SetCaretBidiLevel (uint8_t aLevel);
   /** GetCaretBidiLevel gets the caret bidi level
    *  This method is virtual since it gets called from outside of layout.
    */
   virtual uint8_t GetCaretBidiLevel() const;
   /** UndefineCaretBidiLevel sets the caret bidi level to "undefined"
    *  This method is virtual since it gets called from outside of layout.
    */
   virtual void UndefineCaretBidiLevel();
-#endif
 
   /** CharacterMove will generally be called from the nsiselectioncontroller implementations.
    *  the effect being the selection will move one character left or right.
    * @param aForward move forward in document.
    * @param aExtend continue selection
    */
   /*unsafe*/
   nsresult CharacterMove(bool aForward, bool aExtend);
@@ -700,19 +696,17 @@ private:
   nsCOMPtr<nsIContent> mAncestorLimiter;
 
   nsIPresShell *mShell;
 
   int16_t mSelectionChangeReason; // reason for notifications of selection changing
   int16_t mDisplaySelection; //for visual display purposes.
 
   HINT  mHint;   //hint to tell if the selection is at the end of this line or beginning of next
-#ifdef IBMBIDI
   uint8_t mCaretBidiLevel;
-#endif
 
   int32_t mDesiredX;
   uint32_t mDelayedMouseEventClickCount;
   bool mDelayedMouseEventIsShift;
   bool mDelayedMouseEventValid;
 
   bool mChangesDuringBatching;
   bool mNotifyFrames;
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -143,21 +143,19 @@ FRAME_STATE_BIT(Generic, 15, NS_FRAME_PA
 
 // If this bit is set, then transforms (e.g. CSS or SVG transforms) are allowed
 // to affect the frame, and a transform may currently be in affect. If this bit
 // is not set, then any transforms on the frame will be ignored.
 // This is used primarily in GetTransformMatrix to optimize for the
 // common case.
 FRAME_STATE_BIT(Generic, 16, NS_FRAME_MAY_BE_TRANSFORMED)
 
-#ifdef IBMBIDI
 // If this bit is set, the frame itself is a bidi continuation,
 // or is incomplete (its next sibling is a bidi continuation)
 FRAME_STATE_BIT(Generic, 17, NS_FRAME_IS_BIDI)
-#endif
 
 // If this bit is set the frame has descendant with a view
 FRAME_STATE_BIT(Generic, 18, NS_FRAME_HAS_CHILD_WITH_VIEW)
 
 // If this bit is set, then reflow may be dispatched from the current
 // frame instead of the root frame.
 FRAME_STATE_BIT(Generic, 19, NS_FRAME_REFLOW_ROOT)
 
--- a/layout/generic/nsILineIterator.h
+++ b/layout/generic/nsILineIterator.h
@@ -88,24 +88,22 @@ public:
                          nsIFrame** aFrameFound,
                          bool* aXIsBeforeFirstFrame,
                          bool* aXIsAfterLastFrame) = 0;
 
   // Give the line iterator implementor a chance todo something more complicated than
   // nsIFrame::GetNextSibling()
   NS_IMETHOD GetNextSiblingOnLine(nsIFrame*& aFrame, int32_t aLineNumber) = 0;
 
-#ifdef IBMBIDI
   // Check whether visual and logical order of frames within a line are identical.
   //  If not, return the first and last visual frames
   NS_IMETHOD CheckLineOrder(int32_t                  aLine,
                             bool                     *aIsReordered,
                             nsIFrame                 **aFirstVisual,
                             nsIFrame                 **aLastVisual) = 0;
-#endif
 };
 
 class nsAutoLineIterator
 {
 public:
   nsAutoLineIterator() : mRawPtr(nullptr) { }
   nsAutoLineIterator(nsILineIterator *i) : mRawPtr(i) { }
 
--- a/layout/generic/nsLineBox.cpp
+++ b/layout/generic/nsLineBox.cpp
@@ -5,19 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* representation of one line within a block frame, a CSS line box */
 
 #include "nsLineBox.h"
 #include "prprf.h"
 #include "nsFrame.h"
 #include "nsPresArena.h"
-#ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
-#endif
 #include "nsIFrameInlines.h"
 #include "WritingModes.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Likely.h"
 #include "nsPrintfCString.h"
 
 #ifdef DEBUG
 static int32_t ctorCount;
@@ -679,17 +677,16 @@ nsLineIterator::FindLineContaining(nsIFr
     if (line->Contains(aFrame)) {
       return lineNumber;
     }
     ++lineNumber;
   }
   return -1;
 }
 
-#ifdef IBMBIDI
 NS_IMETHODIMP
 nsLineIterator::CheckLineOrder(int32_t                  aLine,
                                bool                     *aIsReordered,
                                nsIFrame                 **aFirstVisual,
                                nsIFrame                 **aLastVisual)
 {
   NS_ASSERTION (aLine >= 0 && aLine < mNumLines, "aLine out of range!");
   nsLineBox* line = mLines[aLine];
@@ -706,17 +703,16 @@ nsLineIterator::CheckLineOrder(int32_t  
   *aIsReordered = nsBidiPresUtils::CheckLineOrder(line->mFirstChild, line->GetChildCount(), &leftmostFrame, &rightmostFrame);
 
   // map leftmost/rightmost to first/last according to paragraph direction
   *aFirstVisual = mRightToLeft ? rightmostFrame : leftmostFrame;
   *aLastVisual = mRightToLeft ? leftmostFrame : rightmostFrame;
 
   return NS_OK;
 }
-#endif // IBMBIDI
 
 NS_IMETHODIMP
 nsLineIterator::FindFrameAt(int32_t aLineNumber,
                             nscoord aX,
                             nsIFrame** aFrameFound,
                             bool* aXIsBeforeFirstFrame,
                             bool* aXIsAfterLastFrame)
 {
--- a/layout/generic/nsLineBox.h
+++ b/layout/generic/nsLineBox.h
@@ -1694,22 +1694,20 @@ public:
   virtual int32_t FindLineContaining(nsIFrame* aFrame, int32_t aStartLine = 0) MOZ_OVERRIDE;
   NS_IMETHOD FindFrameAt(int32_t aLineNumber,
                          nscoord aX,
                          nsIFrame** aFrameFound,
                          bool* aXIsBeforeFirstFrame,
                          bool* aXIsAfterLastFrame) MOZ_OVERRIDE;
 
   NS_IMETHOD GetNextSiblingOnLine(nsIFrame*& aFrame, int32_t aLineNumber) MOZ_OVERRIDE;
-#ifdef IBMBIDI
   NS_IMETHOD CheckLineOrder(int32_t                  aLine,
                             bool                     *aIsReordered,
                             nsIFrame                 **aFirstVisual,
                             nsIFrame                 **aLastVisual) MOZ_OVERRIDE;
-#endif
   nsresult Init(nsLineList& aLines, bool aRightToLeft);
 
 private:
   nsLineBox* PrevLine() {
     if (0 == mIndex) {
       return nullptr;
     }
     return mLines[--mIndex];
--- a/layout/generic/nsPageFrame.cpp
+++ b/layout/generic/nsPageFrame.cpp
@@ -8,19 +8,17 @@
 #include "nsRenderingContext.h"
 #include "nsGkAtoms.h"
 #include "nsIPresShell.h"
 #include "nsPageContentFrame.h"
 #include "nsDisplayList.h"
 #include "nsLayoutUtils.h" // for function BinarySearchForPosition
 #include "nsSimplePageSequenceFrame.h" // for nsSharedPageData
 #include "nsTextFormatter.h" // for page number localization formatting
-#ifdef IBMBIDI
 #include "nsBidiUtils.h"
-#endif
 #include "nsIPrintSettings.h"
 
 #include "prlog.h"
 #ifdef PR_LOGGING 
 extern PRLogModuleInfo *GetLayoutPrintingLog();
 #define PR_PL(_p1)  PR_LOG(GetLayoutPrintingLog(), PR_LOG_DEBUG, _p1)
 #else
 #define PR_PL(_p1)
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -29,17 +29,16 @@
 #include "nsTableCellFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsIContentIterator.h"
 #include "nsIDocumentEncoder.h"
 #include "nsTextFragment.h"
 #include <algorithm>
 
-// for IBMBIDI
 #include "nsGkAtoms.h"
 #include "nsIFrameTraversal.h"
 #include "nsLayoutUtils.h"
 #include "nsLayoutCID.h"
 #include "nsBidiPresUtils.h"
 static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
 #include "nsTextFrame.h"
 
@@ -65,19 +64,17 @@ static NS_DEFINE_CID(kFrameTraversalCID,
 #include "nsIDocument.h"
 
 #include "nsISelectionController.h"//for the enums
 #include "nsAutoCopyListener.h"
 #include "nsCopySupport.h"
 #include "nsIClipboard.h"
 #include "nsIFrameInlines.h"
 
-#ifdef IBMBIDI
 #include "nsIBidiKeyboard.h"
-#endif // IBMBIDI
 
 #include "nsError.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/SelectionBinding.h"
 
 using namespace mozilla;
@@ -326,19 +323,17 @@ nsFrameSelection::nsFrameSelection()
   }
   mBatching = 0;
   mChangesDuringBatching = false;
   mNotifyFrames = true;
   
   mMouseDoubleDownState = false;
   
   mHint = HINTLEFT;
-#ifdef IBMBIDI
   mCaretBidiLevel = BIDI_LEVEL_UNDEFINED;
-#endif
   mDragSelectingCells = false;
   mSelectingTableCellMode = 0;
   mSelectedCellIndex = 0;
 
   // Check to see if the autocopy pref is enabled
   //   and add the autocopy listener if it is
   if (Preferences::GetBool("clipboard.autocopy")) {
     nsAutoCopyListener *autoCopy = nsAutoCopyListener::GetInstance();
@@ -593,17 +588,16 @@ nsFrameSelection::ConstrainFrameAndPoint
   // system used by aRetFrame.
   //
 
   aRetPoint = aPoint + aFrame->GetOffsetTo(*aRetFrame);
 
   return NS_OK;
 }
 
-#ifdef IBMBIDI
 void
 nsFrameSelection::SetCaretBidiLevel(uint8_t aLevel)
 {
   // If the current level is undefined, we have just inserted new text.
   // In this case, we don't want to reset the keyboard language
   mCaretBidiLevel = aLevel;
   return;
 }
@@ -614,18 +608,16 @@ nsFrameSelection::GetCaretBidiLevel() co
   return mCaretBidiLevel;
 }
 
 void
 nsFrameSelection::UndefineCaretBidiLevel()
 {
   mCaretBidiLevel |= BIDI_LEVEL_UNDEFINED;
 }
-#endif
-
 
 #ifdef PRINT_RANGE
 void printRange(nsRange *aDomRange)
 {
   if (!aDomRange)
   {
     printf("NULL nsIDOMRange\n");
   }
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -380,17 +380,17 @@ nsSubDocumentFrame::BuildDisplayList(nsD
     dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame);
     // and convert into the appunits of the subdoc
     dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD);
 
     if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
       // for root content documents we want the base to be the composition bounds
       nsRect displayportBase = presContext->IsRootContentDocument() ?
           nsRect(nsPoint(0,0), nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame)) :
-          dirty;
+          dirty.Intersect(nsRect(nsPoint(0,0), subdocRootFrame->GetSize()));
       nsRect displayPort;
       if (nsLayoutUtils::GetOrMaybeCreateDisplayPort(
             *aBuilder, rootScrollFrame, displayportBase, &displayPort)) {
         haveDisplayPort = true;
         dirty = displayPort;
       }
 
       ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -3967,20 +3967,18 @@ void
 nsContinuingTextFrame::Init(nsIContent* aContent,
                             nsIFrame*   aParent,
                             nsIFrame*   aPrevInFlow)
 {
   NS_ASSERTION(aPrevInFlow, "Must be a continuation!");
   // NOTE: bypassing nsTextFrame::Init!!!
   nsFrame::Init(aContent, aParent, aPrevInFlow);
 
-#ifdef IBMBIDI
   nsTextFrame* nextContinuation =
     static_cast<nsTextFrame*>(aPrevInFlow->GetNextContinuation());
-#endif // IBMBIDI
   // Hook the frame into the flow
   SetPrevInFlow(aPrevInFlow);
   aPrevInFlow->SetNextInFlow(this);
   nsTextFrame* prev = static_cast<nsTextFrame*>(aPrevInFlow);
   mContentOffset = prev->GetContentOffset() + prev->GetContentLengthHint();
   NS_ASSERTION(mContentOffset < int32_t(aContent->GetText()->GetLength()),
                "Creating ContinuingTextFrame, but there is no more content");
   if (prev->StyleContext() != StyleContext()) {
@@ -3994,17 +3992,16 @@ nsContinuingTextFrame::Init(nsIContent* 
     if (inflation != 1.0f) {
       gfxTextRun *uninflatedTextRun =
         prev->GetTextRun(nsTextFrame::eNotInflated);
       if (uninflatedTextRun) {
         SetTextRun(uninflatedTextRun, nsTextFrame::eNotInflated, 1.0f);
       }
     }
   }
-#ifdef IBMBIDI
   if (aPrevInFlow->GetStateBits() & NS_FRAME_IS_BIDI) {
     FramePropertyTable *propTable = PresContext()->PropertyTable();
     // Get all the properties from the prev-in-flow first to take
     // advantage of the propTable's cache and simplify the assertion below
     void* embeddingLevel = propTable->Get(aPrevInFlow, EmbeddingLevelProperty());
     void* baseLevel = propTable->Get(aPrevInFlow, BaseLevelProperty());
     void* paragraphDepth = propTable->Get(aPrevInFlow, ParagraphDepthProperty());
     propTable->Set(this, EmbeddingLevelProperty(), embeddingLevel);
@@ -4023,17 +4020,16 @@ nsContinuingTextFrame::Init(nsIContent* 
           paragraphDepth == propTable->Get(nextContinuation, ParagraphDepthProperty()),
           "stealing text from different type of BIDI continuation");
         nextContinuation->mContentOffset = mContentOffset;
         nextContinuation = static_cast<nsTextFrame*>(nextContinuation->GetNextContinuation());
       }
     }
     mState |= NS_FRAME_IS_BIDI;
   } // prev frame is bidi
-#endif // IBMBIDI
 }
 
 void
 nsContinuingTextFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   ClearFrameOffsetCache();
 
   // The text associated with this frame will become associated with our
--- a/layout/reftests/border-image/reftest.list
+++ b/layout/reftests/border-image/reftest.list
@@ -74,9 +74,9 @@ fuzzy(1,437) fails-if(OSX) == border-ima
 fuzzy(1,1357) fails-if(OSX) == border-image-repeating-radial-gradient-slice-fill-1.html border-image-repeating-radial-gradient-slice-fill-1-ref.html
 fuzzy(1,1058) fails-if(OSX) == border-image-repeating-radial-gradient-slice-fill-2.html border-image-repeating-radial-gradient-slice-fill-2-ref.html
 fuzzy(1,602) fails-if(OSX) == border-image-repeating-radial-gradient-width.html border-image-repeating-radial-gradient-width-ref.html
 fuzzy(3,18000) fails-if(OSX) == border-image-repeating-radial-gradient-slice-width.html border-image-repeating-radial-gradient-slice-width-ref.html
 fails-if(OSX) == border-image-repeating-radial-gradient-repeat-repeat-2.html border-image-repeating-radial-gradient-repeat-repeat-2-ref.html
 fuzzy(1,1054) fails-if(OSX) == border-image-repeating-radial-gradient-repeat-round-2.html border-image-repeating-radial-gradient-repeat-round-2-ref.html
 
 # border-image-source (-moz-)element
-fuzzy(125,5808) == border-image-element.html border-image-element-ref.html
+fuzzy(125,5808) fuzzy-if(B2G,151,5809) == border-image-element.html border-image-element-ref.html
--- a/layout/reftests/xul/reftest.list
+++ b/layout/reftests/xul/reftest.list
@@ -1,9 +1,9 @@
 == menuitem-key.xul menuitem-key-ref.xul
 # these random-if(Android) are due to differences between Android Native & Xul, see bug 732569
 random-if(Android||B2G) == menulist-shrinkwrap-1.xul menulist-shrinkwrap-1-ref.xul
 random-if(Android||B2G) fails-if(winWidget) == menulist-shrinkwrap-2.xul menulist-shrinkwrap-2-ref.xul
 == textbox-overflow-1.xul textbox-overflow-1-ref.xul # for bug 749658
 # accesskeys are not normally displayed on Mac, so skip this test
 skip-if(cocoaWidget) == accesskey.xul accesskey-ref.xul
-fails-if(cocoaWidget) fails-if(B2G) == tree-row-outline-1.xul tree-row-outline-1-ref.xul
+fails-if(cocoaWidget) == tree-row-outline-1.xul tree-row-outline-1-ref.xul
 != tree-row-outline-1.xul tree-row-outline-1-notref.xul
--- a/layout/style/nsStyleAnimation.cpp
+++ b/layout/style/nsStyleAnimation.cpp
@@ -3726,19 +3726,19 @@ nsStyleAnimation::Value::SetAndAdoptCSSR
 }
 
 void
 nsStyleAnimation::Value::SetAndAdoptCSSValueListValue(
                            nsCSSValueList *aValueList, Unit aUnit)
 {
   FreeValue();
   NS_ABORT_IF_FALSE(IsCSSValueListUnit(aUnit), "bad unit");
-  NS_ABORT_IF_FALSE(aUnit != eUnit_Dasharray || aUnit != eUnit_Filter ||
+  NS_ABORT_IF_FALSE(aUnit == eUnit_Shadow || aUnit == eUnit_Filter ||
                     aValueList != nullptr,
-                    "dasharrays and filters may not be null");
+                    "value lists other than shadows and filters may not be null");
   mUnit = aUnit;
   mValue.mCSSValueList = aValueList; // take ownership
 }
 
 void
 nsStyleAnimation::Value::SetTransformValue(nsCSSValueSharedList* aList)
 {
   FreeValue();
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -1706,30 +1706,28 @@ nsTableRowGroupFrame::FindLineContaining
   nsTableRowFrame *rowFrame = do_QueryFrame(aFrame);
   NS_ASSERTION(rowFrame, "RowGroup contains a frame that is not a row");
 
   int32_t rowIndexInGroup = rowFrame->GetRowIndex() - GetStartRowIndex();
 
   return rowIndexInGroup >= aStartLine ? rowIndexInGroup : -1;
 }
 
-#ifdef IBMBIDI
 NS_IMETHODIMP
 nsTableRowGroupFrame::CheckLineOrder(int32_t                  aLine,
                                      bool                     *aIsReordered,
                                      nsIFrame                 **aFirstVisual,
                                      nsIFrame                 **aLastVisual)
 {
   *aIsReordered = false;
   *aFirstVisual = nullptr;
   *aLastVisual = nullptr;
   return NS_OK;
 }
-#endif // IBMBIDI
-  
+
 NS_IMETHODIMP
 nsTableRowGroupFrame::FindFrameAt(int32_t    aLineNumber, 
                                   nscoord    aX, 
                                   nsIFrame** aFrameFound,
                                   bool*    aXIsBeforeFirstFrame, 
                                   bool*    aXIsAfterLastFrame)
 {
    nsTableFrame* table = nsTableFrame::GetTableFrame(this);
--- a/layout/tables/nsTableRowGroupFrame.h
+++ b/layout/tables/nsTableRowGroupFrame.h
@@ -240,30 +240,28 @@ public:
     *                               cellframe
     */
   NS_IMETHOD FindFrameAt(int32_t aLineNumber,
                          nscoord aX,
                          nsIFrame** aFrameFound,
                          bool* aXIsBeforeFirstFrame,
                          bool* aXIsAfterLastFrame) MOZ_OVERRIDE;
 
-#ifdef IBMBIDI
    /** Check whether visual and logical order of cell frames within a line are
      * identical. As the layout will reorder them this is always the case
      * @param aLine        - the index of the row relative to the table
      * @param aIsReordered - returns false
      * @param aFirstVisual - if the table is rtl first originating cell frame
      * @param aLastVisual  - if the table is rtl last originating cell frame
      */
 
   NS_IMETHOD CheckLineOrder(int32_t                  aLine,
                             bool                     *aIsReordered,
                             nsIFrame                 **aFirstVisual,
                             nsIFrame                 **aLastVisual) MOZ_OVERRIDE;
-#endif
 
   /** Find the next originating cell frame that originates in the row.    
     * @param aFrame      - cell frame to start with, will return the next cell
     *                      originating in a row
     * @param aLineNumber - the index of the row relative to the table
     */  
   NS_IMETHOD GetNextSiblingOnLine(nsIFrame*& aFrame, int32_t aLineNumber) MOZ_OVERRIDE;
 
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -31,20 +31,18 @@
 #include "mozilla/Preferences.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/Attributes.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
-#ifdef IBMBIDI
 #include "nsBidiUtils.h"
 #include "nsBidiPresUtils.h"
-#endif // IBMBIDI
 
 using namespace mozilla;
 
 class nsAccessKeyInfo
 {
 public:
     int32_t mAccesskeyIndex;
     nscoord mBeforeWidth, mAccessWidth, mAccessUnderlineSize, mAccessOffset;
@@ -503,17 +501,16 @@ nsTextBoxFrame::DrawText(nsRenderingCont
 
     aRenderingContext.SetFont(fontMet);
     refContext->SetFont(fontMet);
 
     CalculateUnderline(*refContext);
 
     aRenderingContext.SetColor(aOverrideColor ? *aOverrideColor : StyleColor()->mColor);
 
-#ifdef IBMBIDI
     nsresult rv = NS_ERROR_FAILURE;
 
     if (mState & NS_FRAME_IS_BIDI) {
       presContext->SetBidiEnabled();
       nsBidiLevel level = nsBidiPresUtils::BidiLevelFromStyle(StyleContext());
       if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
           // We let the RenderText function calculate the mnemonic's
           // underline position for us.
@@ -531,19 +528,17 @@ nsTextBoxFrame::DrawText(nsRenderingCont
       else
       {
           rv = nsBidiPresUtils::RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), level,
                                            presContext, aRenderingContext,
                                            *refContext,
                                            aTextRect.x, baseline);
       }
     }
-    if (NS_FAILED(rv) )
-#endif // IBMBIDI
-    {
+    if (NS_FAILED(rv)) {
        aRenderingContext.SetTextRunRTL(false);
 
        if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
            // In the simple (non-BiDi) case, we calculate the mnemonic's
            // underline position by getting the text metric.
            // XXX are attribute values always two byte?
            if (mAccessKeyInfo->mAccesskeyIndex > 0)
                mAccessKeyInfo->mBeforeWidth =
@@ -614,21 +609,19 @@ nsTextBoxFrame::CalculateTitleForWidth(n
     aRenderingContext.SetFont(fm);
 
     // see if the text will completely fit in the width given
     nscoord titleWidth = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
                                                        mTitle.get(), mTitle.Length());
 
     if (titleWidth <= aWidth) {
         mCroppedTitle = mTitle;
-#ifdef IBMBIDI
         if (HasRTLChars(mTitle)) {
             mState |= NS_FRAME_IS_BIDI;
         }
-#endif // IBMBIDI
         return titleWidth;  // fits, done.
     }
 
     const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
     // start with an ellipsis
     mCroppedTitle.Assign(kEllipsis);
 
     // see if the width is even smaller than the ellipsis
@@ -662,21 +655,19 @@ nsTextBoxFrame::CalculateTitleForWidth(n
             for (i = 0; i < length; ++i) {
                 char16_t ch = mTitle.CharAt(i);
                 // still in LTR mode
                 cwidth = aRenderingContext.GetWidth(ch);
                 if (twidth + cwidth > aWidth)
                     break;
 
                 twidth += cwidth;
-#ifdef IBMBIDI
                 if (UCS2_CHAR_IS_BIDI(ch) ) {
                   mState |= NS_FRAME_IS_BIDI;
                 }
-#endif // IBMBIDI
             }
 
             if (i == 0)
                 return titleWidth;
 
             // insert what character we can in.
             nsAutoString title( mTitle );
             title.Truncate(i);
@@ -692,21 +683,19 @@ nsTextBoxFrame::CalculateTitleForWidth(n
             int i;
             for (i=length-1; i >= 0; --i) {
                 char16_t ch = mTitle.CharAt(i);
                 cwidth = aRenderingContext.GetWidth(ch);
                 if (twidth + cwidth > aWidth)
                     break;
 
                 twidth += cwidth;
-#ifdef IBMBIDI
                 if (UCS2_CHAR_IS_BIDI(ch) ) {
                   mState |= NS_FRAME_IS_BIDI;
                 }
-#endif // IBMBIDI
             }
 
             if (i == length-1)
                 return titleWidth;
 
             nsAutoString copy;
             mTitle.Right(copy, length-1-i);
             mCroppedTitle += copy;
@@ -738,36 +727,32 @@ nsTextBoxFrame::CalculateTitleForWidth(n
                 ch = mTitle.CharAt(leftPos);
                 charWidth = aRenderingContext.GetWidth(ch);
                 totalWidth += charWidth;
                 if (totalWidth > aWidth)
                     // greater than the allowable width
                     break;
                 leftString.Insert(ch, leftString.Length());
 
-#ifdef IBMBIDI
                 if (UCS2_CHAR_IS_BIDI(ch))
                     mState |= NS_FRAME_IS_BIDI;
-#endif
 
                 // look at the next character on the right end
                 if (rightPos > leftPos) {
                     // haven't looked at this character yet
                     ch = mTitle.CharAt(rightPos);
                     charWidth = aRenderingContext.GetWidth(ch);
                     totalWidth += charWidth;
                     if (totalWidth > aWidth)
                         // greater than the allowable width
                         break;
                     rightString.Insert(ch, 0);
 
-#ifdef IBMBIDI
                     if (UCS2_CHAR_IS_BIDI(ch))
                         mState |= NS_FRAME_IS_BIDI;
-#endif
                 }
 
                 // look at the next two characters
                 leftPos++;
                 rightPos--;
             }
 
             mCroppedTitle = leftString + kEllipsis + rightString;
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -61,19 +61,17 @@
 #include "nsIScriptableRegion.h"
 #include <algorithm>
 #include "ScrollbarActivity.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #include "nsIWritablePropertyBag2.h"
 #endif
-#ifdef IBMBIDI
 #include "nsBidiUtils.h"
-#endif
 
 using namespace mozilla;
 using namespace mozilla::layout;
 
 // Enumeration function that cancels all the image requests in our cache
 static PLDHashOperator
 CancelImageRequest(const nsAString& aKey,
                    nsTreeImageCacheEntry aEntry, void* aData)
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1712,20 +1712,16 @@ pref("profile.migration_directory", "");
 // if -1, we never think your profile is defunct
 // and users will never see the remigrate UI.
 pref("profile.seconds_until_defunct", -1);
 // We can show it anytime from menus
 pref("profile.manage_only_at_launch", false);
 
 pref("prefs.converted-to-utf8",false);
 
-// --------------------------------------------------
-// IBMBIDI
-// --------------------------------------------------
-//
 // ------------------
 //  Text Direction
 // ------------------
 // 1 = directionLTRBidi *
 // 2 = directionRTLBidi
 pref("bidi.direction", 1);
 // ------------------
 //  Text Type
--- a/testing/mozbase/mozversion/setup.py
+++ b/testing/mozbase/mozversion/setup.py
@@ -1,15 +1,15 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from setuptools import setup
 
-PACKAGE_VERSION = '0.3'
+PACKAGE_VERSION = '0.4'
 
 dependencies = ['mozdevice >= 0.29',
                 'mozfile >= 1.0',
                 'mozlog >= 1.5']
 
 setup(name='mozversion',
       version=PACKAGE_VERSION,
       description='Library to get version information for applications',
--- a/toolkit/components/downloads/ApplicationReputation.cpp
+++ b/toolkit/components/downloads/ApplicationReputation.cpp
@@ -24,16 +24,17 @@
 #include "nsIX509Cert.h"
 #include "nsIX509CertDB.h"
 #include "nsIX509CertList.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
+#include "mozilla/LoadContext.h"
 
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsNetCID.h"
 #include "nsReadableUtils.h"
 #include "nsServiceManagerUtils.h"
@@ -762,16 +763,23 @@ PendingLookup::SendRemoteQueryInternal()
   nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = uploadChannel->ExplicitSetUploadStream(sstream,
     NS_LITERAL_CSTRING("application/octet-stream"), serialized.size(),
     NS_LITERAL_CSTRING("POST"), false);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // Set the Safebrowsing cookie jar, so that the regular Google cookie is not
+  // sent with this request. See bug 897516.
+  nsCOMPtr<nsIInterfaceRequestor> loadContext =
+    new mozilla::LoadContext(NECKO_SAFEBROWSING_APP_ID);
+  rv = channel->SetNotificationCallbacks(loadContext);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   rv = channel->AsyncOpen(this, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsIStreamListener
--- a/toolkit/components/downloads/moz.build
+++ b/toolkit/components/downloads/moz.build
@@ -32,17 +32,19 @@ SOURCES += [
 
 if CONFIG['MOZ_URL_CLASSIFIER']:
     UNIFIED_SOURCES += [
         'ApplicationReputation.cpp',
         'csd.pb.cc'
     ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
-    UNIFIED_SOURCES += [
+    # Can't build unified because we need CreateEvent which some IPC code
+    # included in LoadContext ends up undefining.
+    SOURCES += [
         'nsDownloadScanner.cpp',
     ]
 
 # XXX - Until Suite builds off XULRunner we can't guarantee our implementation
 # of nsIDownloadManagerUI overrides toolkit's.
 if not CONFIG['MOZ_SUITE']:
     EXTRA_COMPONENTS += [
         'nsDownloadManagerUI.js',
@@ -50,11 +52,12 @@ if not CONFIG['MOZ_SUITE']:
     ]
 
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'toolkitcomps'
 
 LOCAL_INCLUDES += [
     '../protobuf',
+    '/ipc/chromium/src'
 ]
 
 DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True
--- a/widget/windows/nsDragService.cpp
+++ b/widget/windows/nsDragService.cpp
@@ -586,13 +586,20 @@ nsDragService::IsCollectionObject(IDataO
 //
 // Override the default to make sure that we release the data object
 // when the drag ends. It seems that OLE doesn't like to let apps quit
 // w/out crashing when we're still holding onto their data
 //
 NS_IMETHODIMP
 nsDragService::EndDragSession(bool aDoneDrag)
 {
+  // Bug 100180: If we've got mouse events captured, make sure we release it -
+  // that way, if we happen to call EndDragSession before diving into a nested
+  // event loop, we can still respond to mouse events.
+  if (::GetCapture()) {
+    ::ReleaseCapture();
+  }
+
   nsBaseDragService::EndDragSession(aDoneDrag);
   NS_IF_RELEASE(mDataObject);
 
   return NS_OK;
 }