merge mozilla-inbound to mozilla-central
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 24 Apr 2014 11:38:32 +0200
changeset 198335 6965a913e858b6feb2944649940a646f40eb4037
parent 198301 a0e703ba2ae6ac7c9db9df1ff1531732e28882a9 (current diff)
parent 198334 6ea4ce828d069fa99f3e1526f40eaeb193de17a3 (diff)
child 198349 c8055a00235db1ddadfdd74e1d8181537117c23c
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge 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;
 }