Merge m-i to m-c
authorPhil Ringnalda <philringnalda@gmail.com>
Mon, 17 Feb 2014 20:50:51 -0800
changeset 169579 463618fae4cc8e07217f9b080b56cc9617a5b9bd
parent 169578 318c0d6e24c54c0563b8b33894bc8fd8514ba03c (current diff)
parent 169565 5775ed3239faed055c5605d1b002538a811f3800 (diff)
child 169586 6e3ec93efe1d4154cb3e12d999b4730bac0b93bf
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Merge m-i to m-c
gfx/layers/basic/TextureHostX11.cpp
gfx/layers/basic/TextureHostX11.h
netwerk/wifi/wlanapi.h
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -78,18 +78,18 @@ static void Output(const char *fmt, ... 
                       _countof(wide_msg));
 #if MOZ_WINCONSOLE
   fwprintf_s(stderr, wide_msg);
 #else
   // Linking user32 at load-time interferes with the DLL blocklist (bug 932100).
   // This is a rare codepath, so we can load user32 at run-time instead.
   HMODULE user32 = LoadLibraryW(L"user32.dll");
   if (user32) {
-    typedef int (WINAPI * MessageBoxWFn)(HWND, LPCWSTR, LPCWSTR, UINT);
-    MessageBoxWFn messageBoxW = (MessageBoxWFn)GetProcAddress(user32, "MessageBoxW");
+    decltype(MessageBoxW)* messageBoxW =
+      (decltype(MessageBoxW)*) GetProcAddress(user32, "MessageBoxW");
     if (messageBoxW) {
       messageBoxW(nullptr, wide_msg, L"Firefox", MB_OK
                                                | MB_ICONERROR
                                                | MB_SETFOREGROUND);
     }
     FreeLibrary(user32);
   }
 #endif
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -601,29 +601,26 @@ nsWindowsShellService::GetCanSetDesktopB
 {
   *aResult = true;
   return NS_OK;
 }
 
 static nsresult
 DynSHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo)
 {
-  typedef HRESULT (WINAPI * SHOpenWithDialogPtr)(HWND hwndParent,
-                                                 const OPENASINFO *poainfo);
-  
   // shell32.dll is in the knownDLLs list so will always be loaded from the
   // system32 directory.
   static const wchar_t kSehllLibraryName[] =  L"shell32.dll";
   HMODULE shellDLL = ::LoadLibraryW(kSehllLibraryName);
   if (!shellDLL) {
     return NS_ERROR_FAILURE;
   }
 
-  SHOpenWithDialogPtr SHOpenWithDialogFn =
-    (SHOpenWithDialogPtr)GetProcAddress(shellDLL, "SHOpenWithDialog");
+  decltype(SHOpenWithDialog)* SHOpenWithDialogFn =
+    (decltype(SHOpenWithDialog)*) GetProcAddress(shellDLL, "SHOpenWithDialog");
 
   if (!SHOpenWithDialogFn) {
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv = 
     SUCCEEDED(SHOpenWithDialogFn(hwndParent, poainfo)) ? NS_OK :
                                                          NS_ERROR_FAILURE;
--- a/browser/metro/shell/commandexecutehandler/CEHHelper.cpp
+++ b/browser/metro/shell/commandexecutehandler/CEHHelper.cpp
@@ -11,21 +11,16 @@
 #endif
 
 HANDLE sCon;
 LPCWSTR metroDX10Available = L"MetroD3DAvailable";
 LPCWSTR metroLastAHE = L"MetroLastAHE";
 LPCWSTR cehDumpDebugStrings = L"CEHDump";
 extern const WCHAR* kFirefoxExe;
 
-typedef HRESULT (WINAPI*D3D10CreateDevice1Func)
-  (IDXGIAdapter *, D3D10_DRIVER_TYPE, HMODULE, UINT,
-   D3D10_FEATURE_LEVEL1, UINT, ID3D10Device1 **);
-typedef HRESULT(WINAPI*CreateDXGIFactory1Func)(REFIID , void **);
-
 void
 Log(const wchar_t *fmt, ...)
 {
 #if !defined(SHOW_CONSOLE)
   DWORD dwRes = 0;
   if (!GetDWORDRegKey(cehDumpDebugStrings, dwRes) || !dwRes) {
     return;
   }
@@ -65,20 +60,19 @@ SetupConsole()
 bool
 IsImmersiveProcessDynamic(HANDLE process)
 {
   HMODULE user32DLL = LoadLibraryW(L"user32.dll");
   if (!user32DLL) {
     return false;
   }
 
-  typedef BOOL (WINAPI* IsImmersiveProcessFunc)(HANDLE process);
-  IsImmersiveProcessFunc IsImmersiveProcessPtr =
-    (IsImmersiveProcessFunc)GetProcAddress(user32DLL,
-                                           "IsImmersiveProcess");
+  decltype(IsImmersiveProcess)* IsImmersiveProcessPtr =
+    (decltype(IsImmersiveProcess)*) GetProcAddress(user32DLL,
+                                                   "IsImmersiveProcess");
   if (!IsImmersiveProcessPtr) {
     FreeLibrary(user32DLL);
     return false;
   }
 
   BOOL bImmersiveProcess = IsImmersiveProcessPtr(process);
   FreeLibrary(user32DLL);
   return bImmersiveProcess;
@@ -146,31 +140,31 @@ IsDX10Available()
     return isDX10Available;
   }
 
   HMODULE dxgiModule = LoadLibraryA("dxgi.dll");
   if (!dxgiModule) {
     SetDWORDRegKey(metroDX10Available, 0);
     return false;
   }
-  CreateDXGIFactory1Func createDXGIFactory1 =
-    (CreateDXGIFactory1Func) GetProcAddress(dxgiModule, "CreateDXGIFactory1");
+  decltype(CreateDXGIFactory1)* createDXGIFactory1 =
+    (decltype(CreateDXGIFactory1)*) GetProcAddress(dxgiModule, "CreateDXGIFactory1");
   if (!createDXGIFactory1) {
     SetDWORDRegKey(metroDX10Available, 0);
     return false;
   }
 
   HMODULE d3d10module = LoadLibraryA("d3d10_1.dll");
   if (!d3d10module) {
     SetDWORDRegKey(metroDX10Available, 0);
     return false;
   }
-  D3D10CreateDevice1Func createD3DDevice =
-    (D3D10CreateDevice1Func) GetProcAddress(d3d10module,
-                                            "D3D10CreateDevice1");
+  decltype(D3D10CreateDevice1)* createD3DDevice =
+    (decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module,
+                                                   "D3D10CreateDevice1");
   if (!createD3DDevice) {
     SetDWORDRegKey(metroDX10Available, 0);
     return false;
   }
 
   CComPtr<IDXGIFactory1> factory1;
   if (FAILED(createDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory1))) {
     SetDWORDRegKey(metroDX10Available, 0);
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -1018,16 +1018,22 @@ UploadLastDir::FetchDirectoryAndDisplayP
 
   nsIURI* docURI = aDoc->GetDocumentURI();
   NS_PRECONDITION(docURI, "docURI is null");
 
   nsCOMPtr<nsILoadContext> loadContext = aDoc->GetLoadContext();
   nsCOMPtr<nsIContentPrefCallback2> prefCallback = 
     new UploadLastDir::ContentPrefCallback(aFilePicker, aFpCallback);
 
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    // FIXME (bug 949666): Run this code in the parent process.
+    prefCallback->HandleCompletion(nsIContentPrefCallback2::COMPLETE_ERROR);
+    return NS_OK;
+  }
+
   // Attempt to get the CPS, if it's not present we'll fallback to use the Desktop folder
   nsCOMPtr<nsIContentPrefService2> contentPrefService =
     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
   if (!contentPrefService) {
     prefCallback->HandleCompletion(nsIContentPrefCallback2::COMPLETE_ERROR);
     return NS_OK;
   }
 
@@ -1042,16 +1048,21 @@ UploadLastDir::FetchDirectoryAndDisplayP
 nsresult
 UploadLastDir::StoreLastUsedDirectory(nsIDocument* aDoc, nsIFile* aDir)
 {
   NS_PRECONDITION(aDoc, "aDoc is null");
   if (!aDir) {
     return NS_OK;
   }
 
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    // FIXME (bug 949666): Run this code in the parent process.
+    return NS_OK;
+  }
+
   nsCOMPtr<nsIURI> docURI = aDoc->GetDocumentURI();
   NS_PRECONDITION(docURI, "docURI is null");
 
   // Attempt to get the CPS, if it's not present we'll just return
   nsCOMPtr<nsIContentPrefService2> contentPrefService =
     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
   if (!contentPrefService)
     return NS_ERROR_NOT_AVAILABLE;
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -1477,17 +1477,17 @@ void MediaDecoder::MoveLoadsToBackground
 void MediaDecoder::UpdatePlaybackOffset(int64_t aOffset)
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mPlaybackPosition = std::max(aOffset, mPlaybackPosition);
 }
 
 bool MediaDecoder::OnStateMachineThread() const
 {
-  return IsCurrentThread(MediaDecoderStateMachine::GetStateMachineThread());
+  return mDecoderStateMachine->OnStateMachineThread();
 }
 
 void MediaDecoder::NotifyAudioAvailableListener()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mDecoderStateMachine) {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
     mDecoderStateMachine->NotifyAudioAvailableListener();
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -3,17 +3,17 @@
  * 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 XP_WIN
 // Include Windows headers required for enabling high precision timers.
 #include "windows.h"
 #include "mmsystem.h"
 #endif
- 
+
 #include "mozilla/DebugOnly.h"
 #include <stdint.h>
 
 #include "MediaDecoderStateMachine.h"
 #include "AudioStream.h"
 #include "nsTArray.h"
 #include "MediaDecoder.h"
 #include "MediaDecoderReader.h"
@@ -23,17 +23,19 @@
 #include "nsDeque.h"
 #include "AudioSegment.h"
 #include "VideoSegment.h"
 #include "ImageContainer.h"
 #include "nsComponentManagerUtils.h"
 #include "nsITimer.h"
 #include "nsContentUtils.h"
 #include "MediaShutdownManager.h"
-
+#include "SharedThreadPool.h"
+#include "MediaTaskQueue.h"
+#include "nsIEventTarget.h"
 #include "prenv.h"
 #include "mozilla/Preferences.h"
 #include "gfx2DGlue.h"
 
 #include <algorithm>
 
 namespace mozilla {
 
@@ -141,246 +143,16 @@ static const int64_t ESTIMATED_DURATION_
 static TimeDuration UsecsToDuration(int64_t aUsecs) {
   return TimeDuration::FromMilliseconds(static_cast<double>(aUsecs) / USECS_PER_MS);
 }
 
 static int64_t DurationToUsecs(TimeDuration aDuration) {
   return static_cast<int64_t>(aDuration.ToSeconds() * USECS_PER_S);
 }
 
-// Owns the global state machine thread and counts of
-// state machine and decoder threads. There should
-// only be one instance of this class.
-class StateMachineTracker
-{
-private:
-  StateMachineTracker() :
-    mMonitor("media.statemachinetracker"),
-    mStateMachineCount(0),
-    mDecodeThreadCount(0),
-    mStateMachineThread(nullptr)
-  {
-     MOZ_COUNT_CTOR(StateMachineTracker);
-     NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-  }
-
-  ~StateMachineTracker()
-  {
-    NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-
-    MOZ_COUNT_DTOR(StateMachineTracker);
-  }
-
-public:
-  // Access singleton instance. This is initially called on the main
-  // thread in the MediaDecoderStateMachine constructor resulting
-  // in the global object being created lazily. Non-main thread
-  // access always occurs after this and uses the monitor to
-  // safely access the decode thread counts.
-  static StateMachineTracker& Instance();
-
-  // Instantiate the global state machine thread if required.
-  // Call on main thread only.
-  void EnsureGlobalStateMachine();
-
-  // Destroy global state machine thread if required.
-  // Call on main thread only.
-  void CleanupGlobalStateMachine();
-
-  // Return the global state machine thread. Call from any thread.
-  nsIThread* GetGlobalStateMachineThread()
-  {
-    ReentrantMonitorAutoEnter mon(mMonitor);
-    NS_ASSERTION(mStateMachineThread, "Should have non-null state machine thread!");
-    return mStateMachineThread->GetThread();
-  }
-
-  // Requests that a decode thread be created for aStateMachine. The thread
-  // may be created immediately, or after some delay, once a thread becomes
-  // available. The request can be cancelled using CancelCreateDecodeThread().
-  // It's the callers responsibility to not call this more than once for any
-  // given state machine.
-  nsresult RequestCreateDecodeThread(MediaDecoderStateMachine* aStateMachine);
-
-  // Cancels a request made by RequestCreateDecodeThread to create a decode
-  // thread for aStateMachine.
-  nsresult CancelCreateDecodeThread(MediaDecoderStateMachine* aStateMachine);
-
-  // Maximum number of active decode threads allowed. When more
-  // than this number are active the thread creation will fail.
-  static const uint32_t MAX_DECODE_THREADS = 25;
-
-  // Returns the number of active decode threads.
-  // Call on any thread. Holds the internal monitor so don't
-  // call with any other monitor held to avoid deadlock.
-  uint32_t GetDecodeThreadCount();
-
-  // Keep track of the fact that a decode thread was destroyed.
-  // Call on any thread. Holds the internal monitor so don't
-  // call with any other monitor held to avoid deadlock.
-  void NoteDecodeThreadDestroyed();
-
-#ifdef DEBUG
-  // Returns true if aStateMachine has a pending request for a
-  // decode thread.
-  bool IsQueued(MediaDecoderStateMachine* aStateMachine);
-#endif
-
-private:
-  // Holds global instance of StateMachineTracker.
-  // Writable on main thread only.
-  static StateMachineTracker* sInstance;
-
-  // Reentrant monitor that must be obtained to access
-  // the decode thread count member and methods.
-  ReentrantMonitor mMonitor;
-
-  // Number of instances of MediaDecoderStateMachine
-  // that are currently instantiated. Access on the
-  // main thread only.
-  uint32_t mStateMachineCount;
-
-  // Number of instances of decoder threads that are
-  // currently instantiated. Access only with the
-  // mMonitor lock held. Can be used from any thread.
-  uint32_t mDecodeThreadCount;
-
-  // Global state machine thread. Write on the main thread
-  // only, read from the decoder threads. Synchronized via
-  // the mMonitor.
-  nsRefPtr<StateMachineThread> mStateMachineThread;
-
-  // Queue of state machines waiting for decode threads. Entries at the front
-  // get their threads first.
-  nsDeque mPending;
-};
-
-StateMachineTracker* StateMachineTracker::sInstance = nullptr;
-
-StateMachineTracker& StateMachineTracker::Instance()
-{
-  if (!sInstance) {
-    NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-    sInstance = new StateMachineTracker();
-  }
-  return *sInstance;
-}
-
-void StateMachineTracker::EnsureGlobalStateMachine()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-  ReentrantMonitorAutoEnter mon(mMonitor);
-  if (mStateMachineCount == 0) {
-    NS_ASSERTION(!mStateMachineThread, "Should have null state machine thread!");
-    mStateMachineThread = new StateMachineThread();
-    DebugOnly<nsresult> rv = mStateMachineThread->Init();
-    NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Can't create media state machine thread");
-  }
-  mStateMachineCount++;
-}
-
-#ifdef DEBUG
-bool StateMachineTracker::IsQueued(MediaDecoderStateMachine* aStateMachine)
-{
-  ReentrantMonitorAutoEnter mon(mMonitor);
-  int32_t size = mPending.GetSize();
-  for (int i = 0; i < size; ++i) {
-    MediaDecoderStateMachine* m =
-      static_cast<MediaDecoderStateMachine*>(mPending.ObjectAt(i));
-    if (m == aStateMachine) {
-      return true;
-    }
-  }
-  return false;
-}
-#endif
-
-void StateMachineTracker::CleanupGlobalStateMachine()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-  NS_ABORT_IF_FALSE(mStateMachineCount > 0,
-    "State machine ref count must be > 0");
-  mStateMachineCount--;
-  if (mStateMachineCount == 0) {
-    DECODER_LOG(PR_LOG_DEBUG, ("Destroying media state machine thread"));
-    NS_ASSERTION(mPending.GetSize() == 0, "Shouldn't all requests be handled by now?");
-    {
-      ReentrantMonitorAutoEnter mon(mMonitor);
-      mStateMachineThread->Shutdown();
-      mStateMachineThread = nullptr;
-      NS_ASSERTION(mDecodeThreadCount == 0, "Decode thread count must be zero.");
-      sInstance = nullptr;
-    }
-    delete this;
-  }
-}
-
-void StateMachineTracker::NoteDecodeThreadDestroyed()
-{
-  ReentrantMonitorAutoEnter mon(mMonitor);
-  --mDecodeThreadCount;
-  while (mDecodeThreadCount < MAX_DECODE_THREADS && mPending.GetSize() > 0) {
-    MediaDecoderStateMachine* m =
-      static_cast<MediaDecoderStateMachine*>(mPending.PopFront());
-    nsresult rv;
-    {
-      ReentrantMonitorAutoExit exitMon(mMonitor);
-      rv = m->StartDecodeThread();
-    }
-    if (NS_SUCCEEDED(rv)) {
-      ++mDecodeThreadCount;
-    }
-  }
-}
-
-uint32_t StateMachineTracker::GetDecodeThreadCount()
-{
-  ReentrantMonitorAutoEnter mon(mMonitor);
-  return mDecodeThreadCount;
-}
-
-nsresult StateMachineTracker::CancelCreateDecodeThread(MediaDecoderStateMachine* aStateMachine) {
-  ReentrantMonitorAutoEnter mon(mMonitor);
-  int32_t size = mPending.GetSize();
-  for (int32_t i = 0; i < size; ++i) {
-    void* m = static_cast<MediaDecoderStateMachine*>(mPending.ObjectAt(i));
-    if (m == aStateMachine) {
-      mPending.RemoveObjectAt(i);
-      break;
-    }
-  }
-  NS_ASSERTION(!IsQueued(aStateMachine), "State machine should no longer have queued request.");
-  return NS_OK;
-}
-
-nsresult StateMachineTracker::RequestCreateDecodeThread(MediaDecoderStateMachine* aStateMachine)
-{
-  NS_ENSURE_STATE(aStateMachine);
-  ReentrantMonitorAutoEnter mon(mMonitor);
-  if (mPending.GetSize() > 0 || mDecodeThreadCount + 1 >= MAX_DECODE_THREADS) {
-    // If there's already state machines in the queue, or we've exceeded the
-    // limit, append the state machine to the queue of state machines waiting
-    // for a decode thread. This ensures state machines already waiting get
-    // their threads first.
-    mPending.Push(aStateMachine);
-    return NS_OK;
-  }
-  nsresult rv;
-  {
-    ReentrantMonitorAutoExit exitMon(mMonitor);
-    rv = aStateMachine->StartDecodeThread();
-  }
-  if (NS_SUCCEEDED(rv)) {
-    ++mDecodeThreadCount;
-  }
-  NS_ASSERTION(mDecodeThreadCount <= MAX_DECODE_THREADS,
-                "Should keep to thread limit!");
-  return NS_OK;
-}
-
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                                    MediaDecoderReader* aReader,
                                                    bool aRealTime) :
   mDecoder(aDecoder),
   mState(DECODER_STATE_DECODING_METADATA),
   mSyncPointInMediaStream(-1),
   mSyncPointInDecodedStream(-1),
   mResetPlayStartTime(false),
@@ -400,35 +172,32 @@ MediaDecoderStateMachine::MediaDecoderSt
   mBasePosition(0),
   mAudioCaptured(false),
   mTransportSeekable(true),
   mMediaSeekable(true),
   mPositionChangeQueued(false),
   mAudioCompleted(false),
   mGotDurationFromMetaData(false),
   mStopDecodeThread(true),
-  mDecodeThreadIdle(false),
+  mDispatchedEventToDecode(false),
   mStopAudioThread(true),
   mQuickBuffering(false),
   mIsRunning(false),
   mRunAgain(false),
   mDispatchedRunEvent(false),
   mDecodeThreadWaiting(false),
   mRealTime(aRealTime),
   mDidThrottleAudioDecoding(false),
   mDidThrottleVideoDecoding(false),
-  mRequestedNewDecodeThread(false),
   mEventManager(aDecoder),
   mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED)
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
-  StateMachineTracker::Instance().EnsureGlobalStateMachine();
-
   // only enable realtime mode when "media.realtime_decoder.enabled" is true.
   if (Preferences::GetBool("media.realtime_decoder.enabled", false) == false)
     mRealTime = false;
 
   mBufferingWait = mRealTime ? 0 : BUFFERING_WAIT_S;
   mLowDataThresholdUsecs = mRealTime ? 0 : LOW_DATA_THRESHOLD_USECS;
 
   // If we've got more than mAmpleVideoFrames decoded video frames waiting in
@@ -454,30 +223,32 @@ MediaDecoderStateMachine::MediaDecoderSt
   // function per-process is OK, provided each call is matched by a corresponding
   // timeEndPeriod() call.
   timeBeginPeriod(1);
 #endif
 }
 
 MediaDecoderStateMachine::~MediaDecoderStateMachine()
 {
-  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread.");
   MOZ_COUNT_DTOR(MediaDecoderStateMachine);
   NS_ASSERTION(!mPendingWakeDecoder.get(),
                "WakeDecoder should have been revoked already");
-  NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
-    "Should not have a pending request for a new decode thread");
-  NS_ASSERTION(!mRequestedNewDecodeThread,
-    "Should not have (or flagged) a pending request for a new decode thread");
-  if (mTimer)
+
+  if (mDecodeTaskQueue) {
+    mDecodeTaskQueue->Shutdown();
+    mDecodeTaskQueue = nullptr;
+  }
+
+  if (mTimer) {
     mTimer->Cancel();
+  }
   mTimer = nullptr;
   mReader = nullptr;
 
-  StateMachineTracker::Instance().CleanupGlobalStateMachine();
 #ifdef XP_WIN
   timeEndPeriod(1);
 #endif
 }
 
 bool MediaDecoderStateMachine::HasFutureAudio() const {
   AssertCurrentThreadInMonitor();
   NS_ASSERTION(HasAudio(), "Should only call HasFutureAudio() when we have audio");
@@ -503,61 +274,63 @@ int64_t MediaDecoderStateMachine::GetDec
   if (mAudioEndTime != -1) {
     audioDecoded += mAudioEndTime - GetMediaTime();
   }
   return audioDecoded;
 }
 
 void MediaDecoderStateMachine::DecodeThreadRun()
 {
-  NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
-  mReader->OnDecodeThreadStart();
-
-  {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
-    if (mState == DECODER_STATE_DECODING_METADATA &&
-        NS_FAILED(DecodeMetadata())) {
-      NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
-                   "Should be in shutdown state if metadata loading fails.");
-      DECODER_LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
-    }
+  if (mReader) {
+    mReader->OnDecodeThreadStart();
+  }
 
-    while (mState != DECODER_STATE_SHUTDOWN &&
-           mState != DECODER_STATE_COMPLETED &&
-           mState != DECODER_STATE_DORMANT &&
-           !mStopDecodeThread)
-    {
-      if (mState == DECODER_STATE_DECODING || mState == DECODER_STATE_BUFFERING) {
-        DecodeLoop();
-      } else if (mState == DECODER_STATE_SEEKING) {
-        DecodeSeek();
-      } else if (mState == DECODER_STATE_DECODING_METADATA) {
-        if (NS_FAILED(DecodeMetadata())) {
-          NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
-                       "Should be in shutdown state if metadata loading fails.");
-          DECODER_LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
-        }
-      } else if (mState == DECODER_STATE_WAIT_FOR_RESOURCES) {
-        mDecoder->GetReentrantMonitor().Wait();
-
-        if (!mReader->IsWaitingMediaResources()) {
-          // change state to DECODER_STATE_WAIT_FOR_RESOURCES
-          StartDecodeMetadata();
-        }
-      } else if (mState == DECODER_STATE_DORMANT) {
-        mDecoder->GetReentrantMonitor().Wait();
-      }
-    }
-
-    mDecodeThreadIdle = true;
-    DECODER_LOG(PR_LOG_DEBUG, ("%p Decode thread finished", mDecoder.get()));
+  if (mState == DECODER_STATE_DECODING_METADATA &&
+      NS_FAILED(DecodeMetadata())) {
+    NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
+                  "Should be in shutdown state if metadata loading fails.");
+    DECODER_LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
   }
 
-  mReader->OnDecodeThreadFinish();
+  while (mState != DECODER_STATE_SHUTDOWN &&
+         mState != DECODER_STATE_COMPLETED &&
+         mState != DECODER_STATE_DORMANT &&
+         !mStopDecodeThread)
+  {
+    if (mState == DECODER_STATE_DECODING || mState == DECODER_STATE_BUFFERING) {
+      DecodeLoop();
+    } else if (mState == DECODER_STATE_SEEKING) {
+      DecodeSeek();
+    } else if (mState == DECODER_STATE_DECODING_METADATA) {
+      if (NS_FAILED(DecodeMetadata())) {
+        NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
+                      "Should be in shutdown state if metadata loading fails.");
+        DECODER_LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
+      }
+    } else if (mState == DECODER_STATE_WAIT_FOR_RESOURCES) {
+      mDecoder->GetReentrantMonitor().Wait();
+
+      if (!mReader->IsWaitingMediaResources()) {
+        // change state to DECODER_STATE_WAIT_FOR_RESOURCES
+        StartDecodeMetadata();
+      }
+    } else if (mState == DECODER_STATE_DORMANT) {
+      mDecoder->GetReentrantMonitor().Wait();
+    }
+  }
+
+  if (mReader) {
+    mReader->OnDecodeThreadFinish();
+  }
+
+  DECODER_LOG(PR_LOG_DEBUG, ("%p Decode thread finished", mDecoder.get()));
+  mDispatchedEventToDecode = false;
+  mon.NotifyAll();
 }
 
 void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
                                                DecodedStreamData* aStream,
                                                AudioSegment* aOutput)
 {
   NS_ASSERTION(OnDecodeThread() ||
                OnStateMachineThread(), "Should be on decode thread or state machine thread");
@@ -1307,20 +1080,37 @@ uint32_t MediaDecoderStateMachine::PlayF
   if (offset != -1) {
     mDecoder->UpdatePlaybackOffset(offset);
   }
   return frames;
 }
 
 nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RefPtr<SharedThreadPool> decodePool(
+    SharedThreadPool::Get(NS_LITERAL_CSTRING("Media Decode"),
+                          Preferences::GetUint("media.num-decode-threads", 25)));
+  NS_ENSURE_TRUE(decodePool, NS_ERROR_FAILURE);
+
+  RefPtr<SharedThreadPool> stateMachinePool(
+    SharedThreadPool::Get(NS_LITERAL_CSTRING("Media State Machine"), 1));
+  NS_ENSURE_TRUE(stateMachinePool, NS_ERROR_FAILURE);
+
+  mDecodeTaskQueue = new MediaTaskQueue(decodePool.forget());
+  NS_ENSURE_TRUE(mDecodeTaskQueue, NS_ERROR_FAILURE);
+
   MediaDecoderReader* cloneReader = nullptr;
   if (aCloneDonor) {
     cloneReader = static_cast<MediaDecoderStateMachine*>(aCloneDonor)->mReader;
   }
+
+  mStateMachineThreadPool = stateMachinePool;
+
   return mReader->Init(cloneReader);
 }
 
 void MediaDecoderStateMachine::StopPlayback()
 {
   DECODER_LOG(PR_LOG_DEBUG, ("%p StopPlayback()", mDecoder.get()));
 
   AssertCurrentThreadInMonitor();
@@ -1701,40 +1491,18 @@ void MediaDecoderStateMachine::Seek(doub
   }
   ScheduleStateMachine();
 }
 
 void MediaDecoderStateMachine::StopDecodeThread()
 {
   NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
   AssertCurrentThreadInMonitor();
-  if (mRequestedNewDecodeThread) {
-    // We've requested that the decode be created, but it hasn't been yet.
-    // Cancel that request.
-    NS_ASSERTION(!mDecodeThread,
-      "Shouldn't have a decode thread until after request processed");
-    StateMachineTracker::Instance().CancelCreateDecodeThread(this);
-    mRequestedNewDecodeThread = false;
-  }
   mStopDecodeThread = true;
   mDecoder->GetReentrantMonitor().NotifyAll();
-  if (mDecodeThread) {
-    DECODER_LOG(PR_LOG_DEBUG, ("%p Shutdown decode thread", mDecoder.get()));
-    {
-      ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
-      mDecodeThread->Shutdown();
-      StateMachineTracker::Instance().NoteDecodeThreadDestroyed();
-    }
-    mDecodeThread = nullptr;
-    mDecodeThreadIdle = false;
-  }
-  NS_ASSERTION(!mRequestedNewDecodeThread,
-    "Any pending requests for decode threads must be canceled and unflagged");
-  NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
-    "Any pending requests for decode threads must be canceled");
 }
 
 void MediaDecoderStateMachine::StopAudioThread()
 {
   NS_ASSERTION(OnDecodeThread() ||
                OnStateMachineThread(), "Should be on decode thread or state machine thread");
   AssertCurrentThreadInMonitor();
 
@@ -1763,74 +1531,26 @@ MediaDecoderStateMachine::ScheduleDecode
 {
   NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
   AssertCurrentThreadInMonitor();
 
   mStopDecodeThread = false;
   if (mState >= DECODER_STATE_COMPLETED) {
     return NS_OK;
   }
-  if (mDecodeThread) {
-    NS_ASSERTION(!mRequestedNewDecodeThread,
-      "Shouldn't have requested new decode thread when we have a decode thread");
-    // We already have a decode thread...
-    if (mDecodeThreadIdle) {
-      // ... and it's not been shutdown yet, wake it up.
-      nsCOMPtr<nsIRunnable> event =
-        NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeThreadRun);
-      mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
-      mDecodeThreadIdle = false;
-    }
-    return NS_OK;
-  } else if (!mRequestedNewDecodeThread) {
-  // We don't already have a decode thread, request a new one.
-    mRequestedNewDecodeThread = true;
-    ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
-    StateMachineTracker::Instance().RequestCreateDecodeThread(this);
+  if (!mDispatchedEventToDecode) {
+    nsresult rv = mDecodeTaskQueue->Dispatch(
+      NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeThreadRun));
+    NS_ENSURE_SUCCESS(rv, rv);
+    mDispatchedEventToDecode = true;
   }
   return NS_OK;
 }
 
 nsresult
-MediaDecoderStateMachine::StartDecodeThread()
-{
-  NS_ASSERTION(StateMachineTracker::Instance().GetDecodeThreadCount() <
-               StateMachineTracker::MAX_DECODE_THREADS,
-               "Should not have reached decode thread limit");
-
-  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
-    "Should not already have a pending request for a new decode thread.");
-  NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
-  NS_ASSERTION(!mDecodeThread, "Should not have decode thread yet");
-  NS_ASSERTION(mRequestedNewDecodeThread, "Should have requested this...");
-
-  mRequestedNewDecodeThread = false;
-
-  nsresult rv = NS_NewNamedThread("Media Decode",
-                                  getter_AddRefs(mDecodeThread),
-                                  nullptr,
-                                  MEDIA_THREAD_STACK_SIZE);
-  if (NS_FAILED(rv)) {
-    // Give up, report error to media element.
-    nsCOMPtr<nsIRunnable> event =
-      NS_NewRunnableMethod(mDecoder, &MediaDecoder::DecodeError);
-    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
-    return rv;
-  }
-
-  nsCOMPtr<nsIRunnable> event =
-    NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeThreadRun);
-  mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
-  mDecodeThreadIdle = false;
-
-  return NS_OK;
-}
-
-nsresult
 MediaDecoderStateMachine::StartAudioThread()
 {
   NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
                "Should be on state machine or decode thread.");
   AssertCurrentThreadInMonitor();
   if (mAudioCaptured) {
     NS_ASSERTION(mStopAudioThread, "mStopAudioThread must always be true if audio is captured");
     return NS_OK;
@@ -2201,53 +1921,60 @@ nsresult MediaDecoderStateMachine::RunSt
       // running in a nested event loop waiting for Shutdown() on
       // mAudioThread to complete.  Return to the event loop and let it
       // finish processing before continuing with shutdown.
       if (mAudioThread) {
         MOZ_ASSERT(mStopAudioThread);
         return NS_OK;
       }
       StopDecodeThread();
+
+      {
+        ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
+        // Wait for the thread decoding to exit.
+        mDecodeTaskQueue->Shutdown();
+        mReader->ReleaseMediaResources();
+      }
       // Now that those threads are stopped, there's no possibility of
       // mPendingWakeDecoder being needed again. Revoke it.
       mPendingWakeDecoder = nullptr;
-      {
-        ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
-        mReader->ReleaseMediaResources();
-      }
+
       NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
                    "How did we escape from the shutdown state?");
       // We must daisy-chain these events to destroy the decoder. We must
       // destroy the decoder on the main thread, but we can't destroy the
       // decoder while this thread holds the decoder monitor. We can't
       // dispatch an event to the main thread to destroy the decoder from
       // here, as the event may run before the dispatch returns, and we
       // hold the decoder monitor here. We also want to guarantee that the
       // state machine is destroyed on the main thread, and so the
       // event runner running this function (which holds a reference to the
       // state machine) needs to finish and be released in order to allow
       // that. So we dispatch an event to run after this event runner has
       // finished and released its monitor/references. That event then will
       // dispatch an event to the main thread to release the decoder and
       // state machine.
-      NS_DispatchToCurrentThread(new nsDispatchDisposeEvent(mDecoder, this));
+      GetStateMachineThread()->Dispatch(
+        new nsDispatchDisposeEvent(mDecoder, this), NS_DISPATCH_NORMAL);
       return NS_OK;
     }
 
     case DECODER_STATE_DORMANT: {
       if (IsPlaying()) {
         StopPlayback();
       }
       StopAudioThread();
       StopDecodeThread();
       // Now that those threads are stopped, there's no possibility of
       // mPendingWakeDecoder being needed again. Revoke it.
       mPendingWakeDecoder = nullptr;
       {
         ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
+        // Wait for the thread decoding, if any, to exit.
+        mDecodeTaskQueue->AwaitIdle();
         mReader->ReleaseMediaResources();
       }
       return NS_OK;
     }
 
     case DECODER_STATE_WAIT_FOR_RESOURCES: {
       return NS_OK;
     }
@@ -2802,17 +2529,17 @@ nsresult MediaDecoderStateMachine::CallR
   mTimeout = TimeStamp();
 
   mIsRunning = true;
   nsresult res = RunStateMachine();
   mIsRunning = false;
 
   if (mRunAgain && !mDispatchedRunEvent) {
     mDispatchedRunEvent = true;
-    return NS_DispatchToCurrentThread(this);
+    return GetStateMachineThread()->Dispatch(this, NS_DISPATCH_NORMAL);
   }
 
   return res;
 }
 
 static void TimeoutExpired(nsITimer *aTimer, void *aClosure) {
   MediaDecoderStateMachine *machine =
     static_cast<MediaDecoderStateMachine*>(aClosure);
@@ -2898,24 +2625,31 @@ nsresult MediaDecoderStateMachine::Sched
 
   res = mTimer->InitWithFuncCallback(mozilla::TimeoutExpired,
                                      this,
                                      ms,
                                      nsITimer::TYPE_ONE_SHOT);
   return res;
 }
 
+bool MediaDecoderStateMachine::OnDecodeThread() const
+{
+  return mDecodeTaskQueue->IsCurrentThreadIn();
+}
+
 bool MediaDecoderStateMachine::OnStateMachineThread() const
 {
-    return IsCurrentThread(GetStateMachineThread());
+  bool rv = false;
+  mStateMachineThreadPool->IsOnCurrentThread(&rv);
+  return rv;
 }
 
-nsIThread* MediaDecoderStateMachine::GetStateMachineThread()
+nsIEventTarget* MediaDecoderStateMachine::GetStateMachineThread()
 {
-  return StateMachineTracker::Instance().GetGlobalStateMachineThread();
+  return mStateMachineThreadPool->GetEventTarget();
 }
 
 void MediaDecoderStateMachine::NotifyAudioAvailableListener()
 {
   AssertCurrentThreadInMonitor();
   mEventManager.NotifyAudioAvailableListener();
 }
 
--- a/content/media/MediaDecoderStateMachine.h
+++ b/content/media/MediaDecoderStateMachine.h
@@ -86,16 +86,18 @@ hardware (via AudioStream).
 #include "MediaMetadataManager.h"
 
 class nsITimer;
 
 namespace mozilla {
 
 class AudioSegment;
 class VideoSegment;
+class MediaTaskQueue;
+class SharedThreadPool;
 
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount() and conflicts with MediaDecoderStateMachine::GetCurrentTime
 // implementation.
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 
@@ -115,17 +117,16 @@ class MediaDecoderStateMachine : public 
 {
 public:
   typedef MediaDecoder::DecodedStreamData DecodedStreamData;
   MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                MediaDecoderReader* aReader,
                                bool aRealTime = false);
   ~MediaDecoderStateMachine();
 
-  // nsDecoderStateMachine interface
   nsresult Init(MediaDecoderStateMachine* aCloneDonor);
 
   // Enumeration for the valid decoding states
   enum State {
     DECODER_STATE_DECODING_METADATA,
     DECODER_STATE_WAIT_FOR_RESOURCES,
     DECODER_STATE_DORMANT,
     DECODER_STATE_DECODING,
@@ -171,19 +172,17 @@ public:
   // The duration is only changed if its significantly different than the
   // the current duration, as the incoming duration is an estimate and so
   // often is unstable as more data is read and the estimate is updated.
   // Can result in a durationchangeevent. aDuration is in microseconds.
   void UpdateEstimatedDuration(int64_t aDuration);
 
   // Functions used by assertions to ensure we're calling things
   // on the appropriate threads.
-  bool OnDecodeThread() const {
-    return IsCurrentThread(mDecodeThread);
-  }
+  bool OnDecodeThread() const;
   bool OnStateMachineThread() const;
   bool OnAudioThread() const {
     return IsCurrentThread(mAudioThread);
   }
 
   MediaDecoderOwner::NextFrameStatus GetNextFrameStatus();
 
   // Cause state transitions. These methods obtain the decoder monitor
@@ -298,33 +297,27 @@ public:
     return mMediaSeekable;
   }
 
   // Sets the current frame buffer length for the MozAudioAvailable event.
   // Accessed on the main and state machine threads.
   void SetFrameBufferLength(uint32_t aLength);
 
   // Returns the shared state machine thread.
-  static nsIThread* GetStateMachineThread();
+  nsIEventTarget* GetStateMachineThread();
 
   // Calls ScheduleStateMachine() after taking the decoder lock. Also
   // notifies the decoder thread in case it's waiting on the decoder lock.
   void ScheduleStateMachineWithLockAndWakeDecoder();
 
   // Schedules the shared state machine thread to run the state machine
   // in aUsecs microseconds from now, if it's not already scheduled to run
   // earlier, in which case the request is discarded.
   nsresult ScheduleStateMachine(int64_t aUsecs = 0);
 
-  // Creates and starts a new decode thread. Don't call this directly,
-  // request a new decode thread by calling
-  // StateMachineTracker::RequestCreateDecodeThread().
-  // The decoder monitor must not be held. Called on the state machine thread.
-  nsresult StartDecodeThread();
-
   // Timer function to implement ScheduleStateMachine(aUsecs).
   void TimeoutExpired();
 
   // Set the media fragment end time. aEndTime is in microseconds.
   void SetFragmentEndTime(int64_t aEndTime);
 
   // Drop reference to decoder.  Only called during shutdown dance.
   void ReleaseDecoder() {
@@ -612,18 +605,22 @@ private:
   // that interested threads can wake up and alter behaviour if appropriate
   // Accessed on state machine, audio, main, and AV thread.
   State mState;
 
   // Thread for pushing audio onto the audio hardware.
   // The "audio push thread".
   nsCOMPtr<nsIThread> mAudioThread;
 
-  // Thread for decoding video in background. The "decode thread".
-  nsCOMPtr<nsIThread> mDecodeThread;
+  // The task queue in which we run decode tasks. This is referred to as
+  // the "decode thread", though in practise tasks can run on a different
+  // thread every time they're called.
+  RefPtr<MediaTaskQueue> mDecodeTaskQueue;
+
+  RefPtr<SharedThreadPool> mStateMachineThreadPool;
 
   // Timer to call the state machine Run() method. Used by
   // ScheduleStateMachine(). Access protected by decoder monitor.
   nsCOMPtr<nsITimer> mTimer;
 
   // Timestamp at which the next state machine Run() method will be called.
   // If this is non-null, a call to Run() is scheduled, either by a timer,
   // or via an event. Access protected by decoder monitor.
@@ -775,22 +772,20 @@ private:
   // True if mDuration has a value obtained from an HTTP header, or from
   // the media index/metadata. Accessed on the state machine thread.
   bool mGotDurationFromMetaData;
 
   // False while decode thread should be running. Accessed state machine
   // and decode threads. Syncrhonised by decoder monitor.
   bool mStopDecodeThread;
 
-  // True when the decode thread run function has finished, but the thread
-  // has not necessarily been shut down yet. This can happen if we switch
-  // from COMPLETED state to SEEKING before the state machine has a chance
-  // to run in the COMPLETED state and shutdown the decode thread.
-  // Synchronised by the decoder monitor.
-  bool mDecodeThreadIdle;
+  // True if we've dispatched an event to the decode task queue to call
+  // DecodeThreadRun(). We use this flag to prevent us from dispatching
+  // unneccessary runnables, since the decode thread runs in a loop.
+  bool mDispatchedEventToDecode;
 
   // False while audio thread should be running. Accessed state machine
   // and audio threads. Syncrhonised by decoder monitor.
   bool mStopAudioThread;
 
   // If this is true while we're in buffering mode, we can exit early,
   // as it's likely we may be able to playback. This happens when we enter
   // buffering mode soon after the decode starts, because the decode-ahead
@@ -822,20 +817,16 @@ private:
   bool mRealTime;
 
   // Record whether audio and video decoding were throttled during the
   // previous iteration of DecodeLooop. When we transition from
   // throttled to not-throttled we need to pump decoding.
   bool mDidThrottleAudioDecoding;
   bool mDidThrottleVideoDecoding;
 
-  // True if we've requested a new decode thread, but it has not yet been
-  // created. Synchronized by the decoder monitor.
-  bool mRequestedNewDecodeThread;
-
   // Manager for queuing and dispatching MozAudioAvailable events.  The
   // event manager is accessed from the state machine and audio threads,
   // and takes care of synchronizing access to its internal queue.
   AudioAvailableEventManager mEventManager;
 
   // Stores presentation info required for playback. The decoder monitor
   // must be held when accessing this.
   MediaInfo mInfo;
--- a/content/media/MediaShutdownManager.cpp
+++ b/content/media/MediaShutdownManager.cpp
@@ -2,85 +2,28 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "MediaShutdownManager.h"
 #include "nsContentUtils.h"
 #include "mozilla/StaticPtr.h"
-#include "mozilla/ClearOnShutdown.h"
 #include "MediaDecoder.h"
+#include "SharedThreadPool.h"
+#include "prlog.h"
 
 namespace mozilla {
 
-StateMachineThread::StateMachineThread()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_COUNT_CTOR(StateMachineThread);
-}
-
-StateMachineThread::~StateMachineThread()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_COUNT_DTOR(StateMachineThread);
-}
-
-void
-StateMachineThread::Shutdown()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mThread);
-  if (mThread) {
-    nsCOMPtr<nsIRunnable> event =
-      NS_NewRunnableMethod(this, &StateMachineThread::ShutdownThread);
-    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
-  }
-}
-
-void
-StateMachineThread::ShutdownThread()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mThread);
-  mThread->Shutdown();
-  mThread = nullptr;
-  MediaShutdownManager::Instance().Unregister(this);
-}
-
-nsresult
-StateMachineThread::Init()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  nsresult rv = NS_NewNamedThread("Media State", getter_AddRefs(mThread));
-  NS_ENSURE_SUCCESS(rv, rv);
-  MediaShutdownManager::Instance().Register(this);
-  return NS_OK;
-}
-
-nsIThread*
-StateMachineThread::GetThread()
-{
-  MOZ_ASSERT(mThread);
-  return mThread;
-}
-
-void
-StateMachineThread::SpinUntilShutdownComplete()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  while (mThread) {
-    bool processed = false;
-    nsresult rv = NS_GetCurrentThread()->ProcessNextEvent(true, &processed);
-    if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to spin main thread while awaiting media shutdown");
-      break;
-    }
-  }
-}
+#ifdef PR_LOGGING
+extern PRLogModuleInfo* gMediaDecoderLog;
+#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
+#else
+#define DECODER_LOG(type, msg)
+#endif
 
 NS_IMPL_ISUPPORTS1(MediaShutdownManager, nsIObserver)
 
 MediaShutdownManager::MediaShutdownManager()
   : mIsObservingShutdown(false),
     mIsDoingXPCOMShutDown(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -106,18 +49,17 @@ MediaShutdownManager::Instance()
   }
   return *sInstance;
 }
 
 void
 MediaShutdownManager::EnsureCorrectShutdownObserverState()
 {
   MOZ_ASSERT(!mIsDoingXPCOMShutDown);
-  bool needShutdownObserver = (mDecoders.Count() > 0) ||
-                              (mStateMachineThreads.Count() > 0);
+  bool needShutdownObserver = mDecoders.Count() > 0;
   if (needShutdownObserver != mIsObservingShutdown) {
     mIsObservingShutdown = needShutdownObserver;
     if (mIsObservingShutdown) {
       nsContentUtils::RegisterShutdownObserver(this);
     } else {
       nsContentUtils::UnregisterShutdownObserver(this);
       // Clear our singleton reference. This will probably delete
       // this instance, so don't deref |this| clearing sInstance.
@@ -157,82 +99,51 @@ MediaShutdownManager::Observe(nsISupport
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
     Shutdown();
   }
   return NS_OK;
 }
 
-void
-MediaShutdownManager::Register(StateMachineThread* aThread)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!mStateMachineThreads.Contains(aThread));
-  mStateMachineThreads.PutEntry(aThread);
-  MOZ_ASSERT(mStateMachineThreads.Contains(aThread));
-  MOZ_ASSERT(mStateMachineThreads.Count() > 0);
-  EnsureCorrectShutdownObserverState();
-}
-
-void
-MediaShutdownManager::Unregister(StateMachineThread* aThread)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mStateMachineThreads.Contains(aThread));
-  if (!mIsDoingXPCOMShutDown) {
-    mStateMachineThreads.RemoveEntry(aThread);
-    EnsureCorrectShutdownObserverState();
-  }
-}
-
 static PLDHashOperator
 ShutdownMediaDecoder(nsRefPtrHashKey<MediaDecoder>* aEntry, void*)
 {
   aEntry->GetKey()->Shutdown();
   return PL_DHASH_REMOVE;
 }
 
-static PLDHashOperator
-JoinStateMachineThreads(nsRefPtrHashKey<StateMachineThread>* aEntry, void*)
-{
-  // Hold a strong reference to the StateMachineThread, so that if it
-  // is Unregistered() and the hashtable's owning reference is cleared,
-  // it won't be destroyed while we're spinning here.
-  RefPtr<StateMachineThread> thread = aEntry->GetKey();
-  thread->SpinUntilShutdownComplete();
-  return PL_DHASH_REMOVE;
-}
-
 void
 MediaShutdownManager::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(sInstance);
 
+  DECODER_LOG(PR_LOG_DEBUG, ("MediaShutdownManager::Shutdown() start..."));
+
   // Mark that we're shutting down, so that Unregister(*) calls don't remove
   // hashtable entries. If Unregsiter(*) was to remove from the hash table,
   // the iterations over the hashtables below would be disrupted.
   mIsDoingXPCOMShutDown = true;
 
   // Iterate over the decoders and shut them down, and remove them from the
   // hashtable.
   mDecoders.EnumerateEntries(ShutdownMediaDecoder, nullptr);
- 
-  // Iterate over the StateMachineThreads and wait for them to have finished
-  // shutting down, and remove them from the hashtable. Once all the decoders
-  // have shutdown the active state machine thread will naturally shutdown
-  // asynchronously. We may also have another state machine thread active,
-  // if construction and shutdown of the state machine thread has interleaved.
-  mStateMachineThreads.EnumerateEntries(JoinStateMachineThreads, nullptr);
- 
+
+  // Ensure all media shared thread pools are shutdown. This joins with all
+  // threads in the state machine thread pool, the decoder thread pool, and
+  // any others.
+  SharedThreadPool::SpinUntilShutdown();
+
   // Remove the MediaShutdownManager instance from the shutdown observer
   // list.
   nsContentUtils::UnregisterShutdownObserver(this);
 
   // Clear the singleton instance. The only remaining reference should be the
   // reference that the observer service used to call us with. The
   // MediaShutdownManager will be deleted once the observer service cleans
   // up after it finishes its notifications.
   sInstance = nullptr;
+
+  DECODER_LOG(PR_LOG_DEBUG, ("MediaShutdownManager::Shutdown() end."));
 }
 
 } // namespace mozilla
--- a/content/media/MediaShutdownManager.h
+++ b/content/media/MediaShutdownManager.h
@@ -27,31 +27,29 @@ class StateMachineThread;
 // there are a number of moving parts that must be shutdown in a particular
 // order. Additionally the xpcom-shutdown observer *must* block until all
 // threads are shutdown, which is tricky since we have a number of threads
 // here and their shutdown is asynchronous. We can't have each element of
 // our pipeline listening for xpcom-shutdown, as if each observer blocks
 // waiting for its threads to shutdown it will block other xpcom-shutdown
 // notifications from firing, and shutdown of one part of the media pipeline
 // (say the State Machine thread) may depend another part to be shutdown
-// first (the MediaDecoder threads). Additionally we need to not interfere
-// with shutdown in the the non-xpcom-shutdown case, where we need to be able
-// to recreate the State Machine thread after it's been destroyed without
-// affecting the shutdown of the old State Machine thread. The
-// MediaShutdownManager encapsulates all these dependencies, and provides
-// a single xpcom-shutdown listener for the MediaDecoder infrastructure, to
-// ensure that no shutdown order dependencies leak out of the MediaDecoder
-// stack. The MediaShutdownManager is a singleton.
+// first (the MediaDecoder threads). The MediaShutdownManager encapsulates
+// all these dependencies, and provides a single xpcom-shutdown listener
+// for the MediaDecoder infrastructure, to ensure that no shutdown order
+// dependencies leak out of the MediaDecoder stack. The MediaShutdownManager
+// is a singleton.
 //
 // The MediaShutdownManager ensures that the MediaDecoder stack is shutdown
 // before returning from its xpcom-shutdown observer by keeping track of all
 // the active MediaDecoders, and upon xpcom-shutdown calling Shutdown() on
-// every MediaDecoder and then spinning the main thread event loop until the
-// State Machine thread has shutdown. Once the State Machine thread has been
-// shutdown, the xpcom-shutdown observer returns.
+// every MediaDecoder and then spinning the main thread event loop until all
+// SharedThreadPools have shutdown. Once the SharedThreadPools are shutdown,
+// all the state machines and their threads have been shutdown, the
+// xpcom-shutdown observer returns.
 //
 // Note that calling the Unregister() functions may result in the singleton
 // being deleted, so don't store references to the singleton, always use the
 // singleton by derefing the referenced returned by
 // MediaShutdownManager::Instance(), which ensures that the singleton is
 // created when needed.
 // i.e. like this:
 //    MediaShutdownManager::Instance()::Unregister(someDecoder);
@@ -73,28 +71,16 @@ public:
   // of this MediaDecoder.
   void Register(MediaDecoder* aDecoder);
 
   // Notifies the MediaShutdownManager that a MediaDecoder that it was
   // tracking has shutdown, and it no longer needs to be shutdown in the
   // xpcom-shutdown listener.
   void Unregister(MediaDecoder* aDecoder);
 
-  // Notifies the MediaShutdownManager of a state machine thread that
-  // must be tracked. Note that we track State Machine threads individually
-  // as their shutdown and the construction of a new state machine thread
-  // can interleave. This stores a strong ref to the state machine.
-  void Register(StateMachineThread* aThread);
-
-  // Notifies the MediaShutdownManager that a StateMachineThread that it was
-  // tracking has shutdown, and it no longer needs to be shutdown in the
-  // xpcom-shutdown listener. This drops the strong reference to the
-  // StateMachineThread, which may destroy it.
-  void Unregister(StateMachineThread* aThread);
-
 private:
 
   MediaShutdownManager();
   virtual ~MediaShutdownManager();
 
   void Shutdown();
 
   // Ensures we have a shutdown listener if we need one, and removes the
@@ -103,67 +89,17 @@ private:
 
   static StaticRefPtr<MediaShutdownManager> sInstance;
 
   // References to the MediaDecoder. The decoders unregister themselves
   // in their Shutdown() method, so we'll drop the reference naturally when
   // we're shutting down (in the non xpcom-shutdown case).
   nsTHashtable<nsRefPtrHashKey<MediaDecoder>> mDecoders;
 
-  // References to the state machine threads that we're tracking shutdown
-  // of. Note that although there is supposed to be a single state machine,
-  // the construction and shutdown of these can interleave, so we must track
-  // individual instances of the state machine threads.
-  // These are strong references.
-  nsTHashtable<nsRefPtrHashKey<StateMachineThread>> mStateMachineThreads;
-
   // True if we have an XPCOM shutdown observer.
   bool mIsObservingShutdown;
 
   bool mIsDoingXPCOMShutDown;
 };
 
-// A wrapper for the state machine thread. We must wrap this so that the
-// state machine threads can shutdown independently from the
-// StateMachineTracker, under the control of the MediaShutdownManager.
-// The state machine thread is shutdown naturally when all decoders
-// complete their shutdown. So if a new decoder is created just as the
-// old state machine thread has shutdown, we need to be able to shutdown
-// the old state machine thread independently of the StateMachineTracker
-// creating a new state machine thread. Also if this happens we need to
-// be able to force both state machine threads to shutdown in the
-// MediaShutdownManager, which is why we maintain a set of state machine
-// threads, even though there's supposed to only be one alive at once.
-// This class does not enforce its own thread safety, the StateMachineTracker
-// ensures thread safety when it uses the StateMachineThread.
-class StateMachineThread {
-public:
-  StateMachineThread();
-  ~StateMachineThread();
-
-  NS_INLINE_DECL_REFCOUNTING(StateMachineThread);
-
-  // Creates the wrapped thread.
-  nsresult Init();
-
-  // Returns a reference to the underlying thread. Don't shut this down
-  // directly, use StateMachineThread::Shutdown() instead.
-  nsIThread* GetThread();
-
-  // Dispatches an event to the main thread to shutdown the wrapped thread.
-  // The owner's (StateMachineTracker's) reference to the StateMachineThread
-  // can be dropped, the StateMachineThread will shutdown itself
-  // asynchronously.
-  void Shutdown();
-
-  // Processes events on the main thread event loop until this thread
-  // has been shutdown. Use this to block until the asynchronous shutdown
-  // has complete.
-  void SpinUntilShutdownComplete();
-
-private:
-  void ShutdownThread();
-  nsCOMPtr<nsIThread> mThread;
-};
-
 } // namespace mozilla
 
 #endif
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -235,17 +235,17 @@ MediaStreamGraphImpl::UpdateBufferSuffic
       data->mHaveEnough = track->GetEndTimeRoundDown() >= desiredEnd;
       if (!data->mHaveEnough) {
         runnables.MoveElementsFrom(data->mDispatchWhenNotEnough);
       }
     }
   }
 
   for (uint32_t i = 0; i < runnables.Length(); ++i) {
-    runnables[i].mThread->Dispatch(runnables[i].mRunnable, 0);
+    runnables[i].mTarget->Dispatch(runnables[i].mRunnable, 0);
   }
 }
 
 StreamTime
 MediaStreamGraphImpl::GraphTimeToStreamTime(MediaStream* aStream,
                                             GraphTime aTime)
 {
   NS_ASSERTION(aTime <= mStateComputedTime,
@@ -2185,17 +2185,17 @@ SourceMediaStream::HaveEnoughBuffered(Tr
   if (track) {
     return track->mHaveEnough;
   }
   return false;
 }
 
 void
 SourceMediaStream::DispatchWhenNotEnoughBuffered(TrackID aID,
-    nsIThread* aSignalThread, nsIRunnable* aSignalRunnable)
+    nsIEventTarget* aSignalThread, nsIRunnable* aSignalRunnable)
 {
   MutexAutoLock lock(mMutex);
   TrackData* data = FindDataForTrack(aID);
   if (!data) {
     aSignalThread->Dispatch(aSignalRunnable, 0);
     return;
   }
 
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -670,17 +670,17 @@ public:
   bool HaveEnoughBuffered(TrackID aID);
   /**
    * Ensures that aSignalRunnable will be dispatched to aSignalThread
    * when we don't have enough buffered data in the track (which could be
    * immediately). Will dispatch the runnable immediately if the track
    * does not exist. No op if a runnable is already present for this track.
    */
   void DispatchWhenNotEnoughBuffered(TrackID aID,
-      nsIThread* aSignalThread, nsIRunnable* aSignalRunnable);
+      nsIEventTarget* aSignalThread, nsIRunnable* aSignalRunnable);
   /**
    * Indicate that a track has ended. Do not do any more API calls
    * affecting this track.
    * Ignored if the track does not exist.
    */
   void EndTrack(TrackID aID);
   /**
    * Indicate that no tracks will be added starting before time aKnownTime.
@@ -723,23 +723,23 @@ public:
    */
   TrackTicks GetBufferedTicks(TrackID aID);
 
   // XXX need a Reset API
 
   friend class MediaStreamGraphImpl;
 
   struct ThreadAndRunnable {
-    void Init(nsIThread* aThread, nsIRunnable* aRunnable)
+    void Init(nsIEventTarget* aTarget, nsIRunnable* aRunnable)
     {
-      mThread = aThread;
+      mTarget = aTarget;
       mRunnable = aRunnable;
     }
 
-    nsCOMPtr<nsIThread> mThread;
+    nsCOMPtr<nsIEventTarget> mTarget;
     nsCOMPtr<nsIRunnable> mRunnable;
   };
   enum TrackCommands {
     TRACK_CREATE = MediaStreamListener::TRACK_EVENT_CREATED,
     TRACK_END = MediaStreamListener::TRACK_EVENT_ENDED
   };
   /**
    * Data for each track that hasn't ended.
--- a/content/media/MediaTaskQueue.cpp
+++ b/content/media/MediaTaskQueue.cpp
@@ -85,23 +85,35 @@ MediaTaskQueue::Flush()
 
 bool
 MediaTaskQueue::IsEmpty()
 {
   MonitorAutoLock mon(mQueueMonitor);
   return mTasks.empty();
 }
 
+bool
+MediaTaskQueue::IsCurrentThreadIn()
+{
+#ifdef DEBUG
+  MonitorAutoLock mon(mQueueMonitor);
+  return NS_GetCurrentThread() == mRunningThread;
+#else
+  return false;
+#endif
+}
+
 nsresult
 MediaTaskQueue::Runner::Run()
 {
   RefPtr<nsIRunnable> event;
   {
     MonitorAutoLock mon(mQueue->mQueueMonitor);
     MOZ_ASSERT(mQueue->mIsRunning);
+    mQueue->mRunningThread = NS_GetCurrentThread();
     if (mQueue->mTasks.size() == 0) {
       mQueue->mIsRunning = false;
       mon.NotifyAll();
       return NS_OK;
     }
     event = mQueue->mTasks.front();
     mQueue->mTasks.pop();
   }
@@ -109,36 +121,51 @@ MediaTaskQueue::Runner::Run()
 
   // Note that dropping the queue monitor before running the task, and
   // taking the monitor again after the task has run ensures we have memory
   // fences enforced. This means that if the object we're calling wasn't
   // designed to be threadsafe, it will be, provided we're only calling it
   // in this task queue.
   event->Run();
 
+  // Drop the reference to event. The event will hold a reference to the
+  // object it's calling, and we don't want to keep it alive, it may be
+  // making assumptions what holds references to it. This is especially
+  // the case if the object is waiting for us to shutdown, so that it
+  // can shutdown (like in the MediaDecoderStateMachine's SHUTDOWN case).
+  event = nullptr;
+
   {
     MonitorAutoLock mon(mQueue->mQueueMonitor);
     if (mQueue->mTasks.size() == 0) {
       // No more events to run. Exit the task runner.
       mQueue->mIsRunning = false;
       mon.NotifyAll();
+      mQueue->mRunningThread = nullptr;
       return NS_OK;
     }
   }
 
   // There's at least one more event that we can run. Dispatch this Runner
   // to the thread pool again to ensure it runs again. Note that we don't just
   // run in a loop here so that we don't hog the thread pool. This means we may
   // run on another thread next time, but we rely on the memory fences from
   // mQueueMonitor for thread safety of non-threadsafe tasks.
-  nsresult rv = mQueue->mPool->Dispatch(this, NS_DISPATCH_NORMAL);
-  if (NS_FAILED(rv)) {
-    // Failed to dispatch, shutdown!
+  {
     MonitorAutoLock mon(mQueue->mQueueMonitor);
-    mQueue->mIsRunning = false;
-    mQueue->mIsShutdown = true;
-    mon.NotifyAll();
+    // Note: Hold the monitor *before* we dispatch, in case we context switch
+    // to another thread pool in the queue immediately and take the lock in the
+    // other thread; mRunningThread could be set to the new thread's value and
+    // then incorrectly anulled below in that case.
+    nsresult rv = mQueue->mPool->Dispatch(this, NS_DISPATCH_NORMAL);
+    if (NS_FAILED(rv)) {
+      // Failed to dispatch, shutdown!
+      mQueue->mIsRunning = false;
+      mQueue->mIsShutdown = true;
+      mon.NotifyAll();
+    }
+    mQueue->mRunningThread = nullptr;
   }
 
   return NS_OK;
 }
 
 } // namespace mozilla
--- a/content/media/MediaTaskQueue.h
+++ b/content/media/MediaTaskQueue.h
@@ -38,31 +38,40 @@ public:
   // and exits.
   void Shutdown();
 
   // Blocks until all task finish executing.
   void AwaitIdle();
 
   bool IsEmpty();
 
+  // Returns true if the current thread is currently running a Runnable in
+  // the task queue. This is for debugging/validation purposes only.
+  bool IsCurrentThreadIn();
+
 private:
 
   // Blocks until all task finish executing. Called internally by methods
   // that need to wait until the task queue is idle.
   // mQueueMonitor must be held.
   void AwaitIdleLocked();
 
   RefPtr<SharedThreadPool> mPool;
 
   // Monitor that protects the queue and mIsRunning;
   Monitor mQueueMonitor;
 
   // Queue of tasks to run.
   std::queue<RefPtr<nsIRunnable>> mTasks;
 
+  // The thread currently running the task queue. We store a reference
+  // to this so that IsCurrentThreadIn() can tell if the current thread
+  // is the thread currently running in the task queue.
+  RefPtr<nsIThread> mRunningThread;
+
   // True if we've dispatched an event to the pool to execute events from
   // the queue.
   bool mIsRunning;
 
   // True if we've started our shutdown process.
   bool mIsShutdown;
 
   class Runner : public nsRunnable {
--- a/content/media/SharedThreadPool.cpp
+++ b/content/media/SharedThreadPool.cpp
@@ -6,17 +6,16 @@
 
 #include "SharedThreadPool.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/StaticPtr.h"
 #include "nsDataHashtable.h"
 #include "VideoUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsComponentManagerUtils.h"
-#include "mozilla/Preferences.h"
 
 #ifdef XP_WIN
 // Required to init MSCOM by MSCOMInitThreadPoolListener.
 #include <objbase.h>
 #endif
 
 namespace mozilla {
 
@@ -64,30 +63,61 @@ DestroySharedThreadPoolHashTable()
     // Note we don't need to lock sMonitor, since we only modify the
     // hash table on the main thread, and if the hash table is empty
     // there are no external references into its contents.
     sPools = nullptr;
     sMonitor = nullptr;
   }
 }
 
+/* static */
+void
+SharedThreadPool::SpinUntilShutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // Wait until the ShutdownPoolsEvent has been run and shutdown the pool.
+  while (sPools) {
+    if (!NS_ProcessNextEvent(NS_GetCurrentThread(), true)) {
+      break;
+    }
+  }
+  MOZ_ASSERT(!sPools);
+  MOZ_ASSERT(!sMonitor);
+}
+
 TemporaryRef<SharedThreadPool>
-SharedThreadPool::Get(const nsCString& aName)
+SharedThreadPool::Get(const nsCString& aName, uint32_t aThreadLimit)
 {
   MOZ_ASSERT(NS_IsMainThread());
   EnsureInitialized();
   MOZ_ASSERT(sMonitor);
   ReentrantMonitorAutoEnter mon(*sMonitor);
   SharedThreadPool* pool = nullptr;
+  nsresult rv;
   if (!sPools->Get(aName, &pool)) {
     nsCOMPtr<nsIThreadPool> threadPool(CreateThreadPool(aName));
     NS_ENSURE_TRUE(threadPool, nullptr);
     pool = new SharedThreadPool(aName, threadPool);
+
+    // Set the thread and idle limits. Note that we don't rely on the
+    // EnsureThreadLimitIsAtLeast() call below, as the default thread limit
+    // is 4, and if aThreadLimit is less than 4 we'll end up with a pool
+    // with 4 threads rather than what we expected; so we'll have unexpected
+    // behaviour.
+    rv = pool->SetThreadLimit(aThreadLimit);
+    NS_ENSURE_SUCCESS(rv, nullptr);
+
+    rv = pool->SetIdleThreadLimit(aThreadLimit);
+    NS_ENSURE_SUCCESS(rv, nullptr);
+
     sPools->Put(aName, pool);
+  } else if (NS_FAILED(pool->EnsureThreadLimitIsAtLeast(aThreadLimit))) {
+    NS_WARNING("Failed to set limits on thread pool");
   }
+
   MOZ_ASSERT(pool);
   RefPtr<SharedThreadPool> instance(pool);
   return instance.forget();
 }
 
 NS_IMETHODIMP_(nsrefcnt) SharedThreadPool::AddRef(void)
 {
   MOZ_ASSERT(sMonitor);
@@ -135,29 +165,31 @@ NS_IMETHODIMP_(nsrefcnt) SharedThreadPoo
     // Ensure that we only run on the main thread.
     // Do this in an event so that if something holds the monitor we won't
     // be deleting the monitor while it's held.
     NS_DispatchToMainThread(new ShutdownPoolsEvent(), NS_DISPATCH_NORMAL);
   }
   return 0;
 }
 
-NS_IMPL_QUERY_INTERFACE1(SharedThreadPool, nsIThreadPool)
+NS_IMPL_QUERY_INTERFACE2(SharedThreadPool, nsIThreadPool, nsIEventTarget)
 
 SharedThreadPool::SharedThreadPool(const nsCString& aName,
                                    nsIThreadPool* aPool)
   : mName(aName)
   , mPool(aPool)
   , mRefCnt(0)
 {
+  MOZ_COUNT_CTOR(SharedThreadPool);
   mEventTarget = do_QueryInterface(aPool);
 }
 
 SharedThreadPool::~SharedThreadPool()
 {
+  MOZ_COUNT_DTOR(SharedThreadPool);
 }
 
 #ifdef XP_WIN
 
 // Thread pool listener which ensures that MSCOM is initialized and
 // deinitialized on the thread pool thread. We may call into WMF or
 // DirectShow on this thread, so we need MSCOM working.
 class MSCOMInitThreadPoolListener MOZ_FINAL : public nsIThreadPoolListener {
@@ -182,41 +214,59 @@ NS_IMETHODIMP
 MSCOMInitThreadPoolListener::OnThreadShuttingDown()
 {
   CoUninitialize();
   return NS_OK;
 }
 
 #endif // XP_WIN
 
+nsresult
+SharedThreadPool::EnsureThreadLimitIsAtLeast(uint32_t aLimit)
+{
+  // We limit the number of threads that we use for media. Note that we
+  // set the thread limit to the same as the idle limit so that we're not
+  // constantly creating and destroying threads (see Bug 881954). When the
+  // thread pool threads shutdown they dispatch an event to the main thread
+  // to call nsIThread::Shutdown(), and if we're very busy that can take a
+  // while to run, and we end up with dozens of extra threads. Note that
+  // threads that are idle for 60 seconds are shutdown naturally.
+  uint32_t existingLimit = 0;
+  nsresult rv;
+
+  rv = mPool->GetThreadLimit(&existingLimit);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (aLimit > existingLimit) {
+    rv = mPool->SetThreadLimit(aLimit);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  rv = mPool->GetIdleThreadLimit(&existingLimit);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (aLimit > existingLimit) {
+    rv = mPool->SetIdleThreadLimit(aLimit);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
 static already_AddRefed<nsIThreadPool>
 CreateThreadPool(const nsCString& aName)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsresult rv;
   nsCOMPtr<nsIThreadPool> pool = do_CreateInstance(NS_THREADPOOL_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   rv = pool->SetName(aName);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
-  // We limit the number of threads that we use for media. Note that the
-  // default thread limit is the same as the idle limit so that we're not
-  // constantly creating and destroying threads (see Bug 881954). When the
-  // thread pool threads shutdown they dispatch an event to the main thread
-  // to call nsIThread::Shutdown(), and if we're very busy that can take a
-  // while to run, and we end up with dozens of extra threads. Note that
-  // threads that are idle for 60 seconds are shutdown naturally.
-  rv = pool->SetThreadLimit(
-    Preferences::GetUint("media.thread-pool.thread-limit", 4));
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
-  rv = pool->SetIdleThreadLimit(
-    Preferences::GetUint("media.thread-pool.idle-thread-limit", 4));
+  rv = pool->SetThreadStackSize(MEDIA_THREAD_STACK_SIZE);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
 #ifdef XP_WIN
   // Ensure MSCOM is initialized on the thread pools threads.
   nsCOMPtr<nsIThreadPoolListener> listener = new MSCOMInitThreadPoolListener();
   rv = pool->SetListener(listener);
   NS_ENSURE_SUCCESS(rv, nullptr);
 #endif
--- a/content/media/SharedThreadPool.h
+++ b/content/media/SharedThreadPool.h
@@ -20,48 +20,61 @@ namespace mozilla {
 // Wrapper that makes an nsIThreadPool a singleton, and provides a
 // consistent threadsafe interface to get instances. Callers simply get a
 // SharedThreadPool by the name of its nsIThreadPool. All get requests of
 // the same name get the same SharedThreadPool. Users must store a reference
 // to the pool, and when the last reference to a SharedThreadPool is dropped
 // the pool is shutdown and deleted. Users aren't required to manually
 // shutdown the pool, and can release references on any thread. On Windows
 // all threads in the pool have MSCOM initialized with COINIT_MULTITHREADED.
-class SharedThreadPool : public nsIThreadPool {
+class SharedThreadPool : public nsIThreadPool
+{
 public:
 
   // Gets (possibly creating) the shared thread pool singleton instance with
   // thread pool named aName.
   // *Must* be called on the main thread.
-  static TemporaryRef<SharedThreadPool> Get(const nsCString& aName);
+  static TemporaryRef<SharedThreadPool> Get(const nsCString& aName,
+                                            uint32_t aThreadLimit = 4);
+
+  // Spins the event loop until all thread pools are shutdown.
+  // *Must* be called on the main thread.
+  static void SpinUntilShutdown();
 
   // We implement custom threadsafe AddRef/Release pair, that destroys the
   // the shared pool singleton when the refcount drops to 0. The addref/release
   // are implemented using locking, so it's not recommended that you use them
   // in a tight loop.
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
   NS_IMETHOD_(nsrefcnt) AddRef(void);
   NS_IMETHOD_(nsrefcnt) Release(void);
 
   // Forward behaviour to wrapped thread pool implementation.
   NS_FORWARD_SAFE_NSITHREADPOOL(mPool);
-  NS_FORWARD_SAFE_NSIEVENTTARGET(mEventTarget);
+  NS_FORWARD_SAFE_NSIEVENTTARGET(GetEventTarget());
+
+  nsIEventTarget* GetEventTarget() {
+    return mEventTarget;
+  }
 
 private:
 
   // Creates necessary statics.
   // Main thread only.
   static void EnsureInitialized();
 
   // Creates a singleton SharedThreadPool wrapper around aPool.
   // aName is the name of the aPool, and is used to lookup the
   // SharedThreadPool in the hash table of all created pools.
-  SharedThreadPool(const nsCString& aName, nsIThreadPool* aPool);
+  SharedThreadPool(const nsCString& aName,
+                   nsIThreadPool* aPool);
   virtual ~SharedThreadPool();
 
+  nsresult EnsureThreadLimitIsAtLeast(uint32_t aThreadLimit);
+
   // Name of mPool.
   const nsCString mName;
 
   // Thread pool being wrapped.
   nsCOMPtr<nsIThreadPool> mPool;
 
   // Refcount. We implement custom ref counting so that the thread pool is
   // shutdown in a threadsafe manner and singletonness is preserved.
--- a/content/media/gstreamer/GStreamerReader.cpp
+++ b/content/media/gstreamer/GStreamerReader.cpp
@@ -332,40 +332,50 @@ nsresult GStreamerReader::ReadMetadata(M
        */
       GstCaps* filterCaps = gst_caps_new_simple ("skip", nullptr, nullptr);
       g_object_set(filter, "caps", filterCaps, nullptr);
       gst_caps_unref(filterCaps);
       gst_object_unref(filter);
     }
 
     LOG(PR_LOG_DEBUG, ("starting metadata pipeline"));
-    gst_element_set_state(mPlayBin, GST_STATE_PAUSED);
+    if (gst_element_set_state(mPlayBin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
+      LOG(PR_LOG_DEBUG, ("metadata pipeline state change failed"));
+      ret = NS_ERROR_FAILURE;
+      continue;
+    }
 
     /* Wait for ASYNC_DONE, which is emitted when the pipeline is built,
      * prerolled and ready to play. Also watch for errors.
      */
     message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE,
-                 (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR));
-    if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) {
-      GError* error;
-      gchar* debug;
-
-      gst_message_parse_error(message, &error, &debug);
-      LOG(PR_LOG_ERROR, ("read metadata error: %s: %s", error->message,
-                         debug));
-      g_error_free(error);
-      g_free(debug);
-      gst_element_set_state(mPlayBin, GST_STATE_NULL);
-      gst_message_unref(message);
-      ret = NS_ERROR_FAILURE;
-    } else {
+                 (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR | GST_MESSAGE_EOS));
+    if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ASYNC_DONE) {
       LOG(PR_LOG_DEBUG, ("read metadata pipeline prerolled"));
       gst_message_unref(message);
       ret = NS_OK;
       break;
+    } else {
+      LOG(PR_LOG_DEBUG, ("read metadata pipeline failed to preroll: %s",
+            gst_message_type_get_name (GST_MESSAGE_TYPE (message))));
+
+      if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) {
+        GError* error;
+        gchar* debug;
+        gst_message_parse_error(message, &error, &debug);
+        LOG(PR_LOG_ERROR, ("read metadata error: %s: %s", error->message,
+                           debug));
+        g_error_free(error);
+        g_free(debug);
+      }
+      /* Unexpected stream close/EOS or other error. We'll give up if all
+       * streams are in error/eos. */
+      gst_element_set_state(mPlayBin, GST_STATE_NULL);
+      gst_message_unref(message);
+      ret = NS_ERROR_FAILURE;
     }
   }
 
   if (NS_SUCCEEDED(ret))
     ret = CheckSupportedFormats();
 
   if (NS_FAILED(ret))
     /* we couldn't get this to play */
@@ -374,22 +384,25 @@ nsresult GStreamerReader::ReadMetadata(M
   /* FIXME: workaround for a bug in matroskademux. This seek makes matroskademux
    * parse the index */
   LOG(PR_LOG_DEBUG, ("doing matroskademux seek hack"));
   if (gst_element_seek_simple(mPlayBin, GST_FORMAT_TIME,
         GST_SEEK_FLAG_FLUSH, 0)) {
     /* after a seek we need to wait again for ASYNC_DONE */
     message = gst_bus_timed_pop_filtered(mBus, 5 * GST_SECOND,
        (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR));
-    LOG(PR_LOG_DEBUG, ("matroskademux seek hack done"));
-    if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_ASYNC_DONE) {
+    if (message == NULL || GST_MESSAGE_TYPE(message) != GST_MESSAGE_ASYNC_DONE) {
+      LOG(PR_LOG_DEBUG, ("matroskademux seek hack failed: %p", message));
       gst_element_set_state(mPlayBin, GST_STATE_NULL);
-      gst_message_unref(message);
+      if (message) {
+        gst_message_unref(message);
+      }
       return NS_ERROR_FAILURE;
     }
+    LOG(PR_LOG_DEBUG, ("matroskademux seek hack completed"));
   } else {
     LOG(PR_LOG_DEBUG, ("matroskademux seek hack failed (non fatal)"));
   }
 
   bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
   if (isMP3) {
     ParseMP3Headers();
   }
--- a/content/media/mediasource/MediaSourceDecoder.cpp
+++ b/content/media/mediasource/MediaSourceDecoder.cpp
@@ -40,17 +40,20 @@ class MediaSourceReader : public MediaDe
 public:
   MediaSourceReader(MediaSourceDecoder* aDecoder)
     : MediaDecoderReader(aDecoder)
   {
   }
 
   nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE
   {
-    return NS_ERROR_NOT_IMPLEMENTED;
+    // Although we technically don't implement anything here, we return NS_OK
+    // so that when the state machine initializes and calls this function
+    // we don't return an error code back to the media element.
+    return NS_OK;
   }
 
   bool DecodeAudioData() MOZ_OVERRIDE
   {
     if (GetAudioReader()) {
       return GetAudioReader()->DecodeAudioData();
     }
     return false;
@@ -143,17 +146,24 @@ MediaDecoderStateMachine*
 MediaSourceDecoder::CreateStateMachine()
 {
   return new MediaDecoderStateMachine(this, new MediaSourceReader(this));
 }
 
 nsresult
 MediaSourceDecoder::Load(nsIStreamListener**, MediaDecoder*)
 {
-  return NS_OK;
+  MOZ_ASSERT(!mDecoderStateMachine);
+  mDecoderStateMachine = CreateStateMachine();
+  if (!mDecoderStateMachine) {
+    NS_WARNING("Failed to create state machine!");
+    return NS_ERROR_FAILURE;
+  }
+
+  return mDecoderStateMachine->Init(nullptr);
 }
 
 nsresult
 MediaSourceDecoder::GetSeekable(dom::TimeRanges* aSeekable)
 {
   double duration = mMediaSource->Duration();
   if (IsNaN(duration)) {
     // Return empty range.
@@ -167,17 +177,16 @@ MediaSourceDecoder::GetSeekable(dom::Tim
   return NS_OK;
 }
 
 void
 MediaSourceDecoder::AttachMediaSource(dom::MediaSource* aMediaSource)
 {
   MOZ_ASSERT(!mMediaSource && !mDecoderStateMachine);
   mMediaSource = aMediaSource;
-  mDecoderStateMachine = CreateStateMachine();
 }
 
 void
 MediaSourceDecoder::DetachMediaSource()
 {
   mMediaSource = nullptr;
 }
 
--- a/content/media/wmf/DXVA2Manager.cpp
+++ b/content/media/wmf/DXVA2Manager.cpp
@@ -55,28 +55,26 @@ D3D9DXVA2Manager::~D3D9DXVA2Manager()
 
 IUnknown*
 D3D9DXVA2Manager::GetDXVADeviceManager()
 {
   MutexAutoLock lock(mLock);
   return mDeviceManager;
 }
 
-typedef HRESULT (WINAPI*Direct3DCreate9Func)(UINT SDKVersion, IDirect3D9Ex**);
-
 HRESULT
 D3D9DXVA2Manager::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Create D3D9Ex.
   HMODULE d3d9lib = LoadLibraryW(L"d3d9.dll");
   NS_ENSURE_TRUE(d3d9lib, E_FAIL);
-  Direct3DCreate9Func d3d9Create =
-    (Direct3DCreate9Func)GetProcAddress(d3d9lib, "Direct3DCreate9Ex");
+  decltype(Direct3DCreate9Ex)* d3d9Create =
+    (decltype(Direct3DCreate9Ex)*) GetProcAddress(d3d9lib, "Direct3DCreate9Ex");
   nsRefPtr<IDirect3D9Ex> d3d9Ex;
   HRESULT hr = d3d9Create(D3D_SDK_VERSION, getter_AddRefs(d3d9Ex));
   if (!d3d9Ex) {
     NS_WARNING("Direct3DCreate9 failed");
     return E_FAIL;
   }
 
   // Ensure we can do the YCbCr->RGB conversion in StretchRect.
--- a/content/media/wmf/WMFByteStream.cpp
+++ b/content/media/wmf/WMFByteStream.cpp
@@ -58,17 +58,17 @@ WMFByteStream::~WMFByteStream()
   WMF_BS_LOG("[%p] WMFByteStream DTOR", this);
 }
 
 nsresult
 WMFByteStream::Init()
 {
   NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
 
-  mThreadPool = SharedThreadPool::Get(NS_LITERAL_CSTRING("WMFByteStream IO"));
+  mThreadPool = SharedThreadPool::Get(NS_LITERAL_CSTRING("WMFByteStream IO"), 4);
   NS_ENSURE_TRUE(mThreadPool, NS_ERROR_FAILURE);
 
   NS_ConvertUTF8toUTF16 contentTypeUTF16(mResource->GetContentType());
   if (!contentTypeUTF16.IsEmpty()) {
     HRESULT hr = wmf::MFCreateAttributes(byRef(mAttributes), 1);
     NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
 
     hr = mAttributes->SetString(MF_BYTESTREAM_CONTENT_TYPE,
--- a/content/media/wmf/WMFUtils.cpp
+++ b/content/media/wmf/WMFUtils.cpp
@@ -484,205 +484,197 @@ UnloadDLLs()
       FreeLibrary(sDLLs[i].handle);
       sDLLs[i].handle = nullptr;
     }
     sDLLsLoaded = false;
   }
   return S_OK;
 }
 
-#define ENSURE_FUNCTION_PTR(FunctionName, DLL) \
-  static FunctionName##Ptr_t FunctionName##Ptr = nullptr; \
+#define ENSURE_FUNCTION_PTR_HELPER(FunctionType, FunctionName, DLL) \
+  static FunctionType FunctionName##Ptr = nullptr; \
   if (!FunctionName##Ptr) { \
-    FunctionName##Ptr = (FunctionName##Ptr_t)GetProcAddress(GetModuleHandle( #DLL ), #FunctionName ); \
+    FunctionName##Ptr = (FunctionType) GetProcAddress(GetModuleHandle(#DLL), #FunctionName); \
     if (!FunctionName##Ptr) { \
-      NS_WARNING("Failed to get GetProcAddress of " #FunctionName " from " #DLL ); \
+      NS_WARNING("Failed to get GetProcAddress of " #FunctionName " from " #DLL); \
       return E_FAIL; \
     } \
   }
 
+#define ENSURE_FUNCTION_PTR(FunctionName, DLL) \
+  ENSURE_FUNCTION_PTR_HELPER(decltype(::FunctionName)*, FunctionName, DLL) \
+
+#define ENSURE_FUNCTION_PTR_(FunctionName, DLL) \
+  ENSURE_FUNCTION_PTR_HELPER(FunctionName##Ptr_t, FunctionName, DLL) \
+
 #define DECL_FUNCTION_PTR(FunctionName, ...) \
   typedef HRESULT (STDMETHODCALLTYPE * FunctionName##Ptr_t)(__VA_ARGS__)
 
 HRESULT
 MFStartup()
 {
   const int MF_VISTA_VERSION = (0x0001 << 16 | MF_API_VERSION);
   const int MF_WIN7_VERSION = (0x0002 << 16 | MF_API_VERSION);
 
+  // decltype is unusable for functions having default parameters
   DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD);
-  ENSURE_FUNCTION_PTR(MFStartup, Mfplat.dll)
+  ENSURE_FUNCTION_PTR_(MFStartup, Mfplat.dll)
   if (!IsWin7OrLater())
     return MFStartupPtr(MF_VISTA_VERSION, MFSTARTUP_FULL);
   else
     return MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL);
 }
 
 HRESULT
 MFShutdown()
 {
-  DECL_FUNCTION_PTR(MFShutdown);
   ENSURE_FUNCTION_PTR(MFShutdown, Mfplat.dll)
   return (MFShutdownPtr)();
 }
 
 HRESULT
 MFCreateAsyncResult(IUnknown *aUnkObject,
                     IMFAsyncCallback *aCallback,
                     IUnknown *aUnkState,
                     IMFAsyncResult **aOutAsyncResult)
 {
-  DECL_FUNCTION_PTR(MFCreateAsyncResult, IUnknown*, IMFAsyncCallback*, IUnknown*, IMFAsyncResult**);
   ENSURE_FUNCTION_PTR(MFCreateAsyncResult, Mfplat.dll)
   return (MFCreateAsyncResultPtr)(aUnkObject, aCallback, aUnkState, aOutAsyncResult);
 }
 
 HRESULT
 MFInvokeCallback(IMFAsyncResult *aAsyncResult)
 {
-  DECL_FUNCTION_PTR(MFInvokeCallback, IMFAsyncResult*);
   ENSURE_FUNCTION_PTR(MFInvokeCallback, Mfplat.dll);
   return (MFInvokeCallbackPtr)(aAsyncResult);
 }
 
 HRESULT
 MFCreateMediaType(IMFMediaType **aOutMFType)
 {
-  DECL_FUNCTION_PTR(MFCreateMediaType, IMFMediaType**);
   ENSURE_FUNCTION_PTR(MFCreateMediaType, Mfplat.dll)
   return (MFCreateMediaTypePtr)(aOutMFType);
 }
 
 HRESULT
 MFCreateSourceReaderFromByteStream(IMFByteStream *aByteStream,
                                    IMFAttributes *aAttributes,
                                    IMFSourceReader **aOutSourceReader)
 {
-  DECL_FUNCTION_PTR(MFCreateSourceReaderFromByteStream, IMFByteStream*, IMFAttributes*, IMFSourceReader**);
   ENSURE_FUNCTION_PTR(MFCreateSourceReaderFromByteStream, Mfreadwrite.dll)
   return (MFCreateSourceReaderFromByteStreamPtr)(aByteStream,
                                                  aAttributes,
                                                  aOutSourceReader);
 }
 
 HRESULT
 PropVariantToUInt32(REFPROPVARIANT aPropvar, ULONG *aOutUL)
 {
+  // decltype is unusable for overloaded functions
   DECL_FUNCTION_PTR(PropVariantToUInt32, REFPROPVARIANT, ULONG *);
-  ENSURE_FUNCTION_PTR(PropVariantToUInt32, Propsys.dll)
+  ENSURE_FUNCTION_PTR_(PropVariantToUInt32, Propsys.dll)
   return (PropVariantToUInt32Ptr)(aPropvar, aOutUL);
 }
 
 HRESULT PropVariantToInt64(REFPROPVARIANT aPropVar, LONGLONG *aOutLL)
 {
-  DECL_FUNCTION_PTR(PropVariantToInt64, REFPROPVARIANT, LONGLONG *);
   ENSURE_FUNCTION_PTR(PropVariantToInt64, Propsys.dll)
   return (PropVariantToInt64Ptr)(aPropVar, aOutLL);
 }
 
 HRESULT
 MFTGetInfo(CLSID aClsidMFT,
            LPWSTR *aOutName,
            MFT_REGISTER_TYPE_INFO **aOutInputTypes,
            UINT32 *aOutNumInputTypes,
            MFT_REGISTER_TYPE_INFO **aOutOutputTypes,
            UINT32 *aOutNumOutputTypes,
            IMFAttributes **aOutAttributes)
 {
-  DECL_FUNCTION_PTR(MFTGetInfo, CLSID, LPWSTR*, MFT_REGISTER_TYPE_INFO**, UINT32*, MFT_REGISTER_TYPE_INFO**, UINT32*, IMFAttributes**);
   ENSURE_FUNCTION_PTR(MFTGetInfo, Mfplat.dll)
   return (MFTGetInfoPtr)(aClsidMFT,
                          aOutName,
                          aOutInputTypes,
                          aOutNumInputTypes,
                          aOutOutputTypes,
                          aOutNumOutputTypes,
                          aOutAttributes);
 }
 
 HRESULT
 MFGetStrideForBitmapInfoHeader(DWORD aFormat,
                                DWORD aWidth,
                                LONG *aOutStride)
 {
-  DECL_FUNCTION_PTR(MFGetStrideForBitmapInfoHeader, DWORD, DWORD, LONG*);
   ENSURE_FUNCTION_PTR(MFGetStrideForBitmapInfoHeader, Mfplat.dll)
   return (MFGetStrideForBitmapInfoHeaderPtr)(aFormat, aWidth, aOutStride);
 }
 
 HRESULT
 MFCreateSourceReaderFromURL(LPCWSTR aURL,
                             IMFAttributes *aAttributes,
                             IMFSourceReader **aSourceReader)
 {
-  DECL_FUNCTION_PTR(MFCreateSourceReaderFromURL, LPCWSTR, IMFAttributes*, IMFSourceReader**);
   ENSURE_FUNCTION_PTR(MFCreateSourceReaderFromURL, Mfreadwrite.dll)
   return (MFCreateSourceReaderFromURLPtr)(aURL, aAttributes, aSourceReader);
 }
 
 HRESULT
 MFCreateAttributes(IMFAttributes **ppMFAttributes, UINT32 cInitialSize)
 {
-  DECL_FUNCTION_PTR(MFCreateAttributes, IMFAttributes**, UINT32);
   ENSURE_FUNCTION_PTR(MFCreateAttributes, mfplat.dll)
   return (MFCreateAttributesPtr)(ppMFAttributes, cInitialSize);
 }
 
 HRESULT
 MFGetPluginControl(IMFPluginControl **aOutPluginControl)
 {
-  DECL_FUNCTION_PTR(MFGetPluginControl, IMFPluginControl **);
   ENSURE_FUNCTION_PTR(MFGetPluginControl, mfplat.dll)
   return (MFGetPluginControlPtr)(aOutPluginControl);
 }
 
 HRESULT
 MFTEnumEx(GUID guidCategory,
           UINT32 Flags,
           const MFT_REGISTER_TYPE_INFO *pInputType,
           const MFT_REGISTER_TYPE_INFO *pOutputType,
           IMFActivate ***pppMFTActivate,
           UINT32 *pcMFTActivate)
 {
-  DECL_FUNCTION_PTR(MFTEnumEx, GUID, UINT32, const MFT_REGISTER_TYPE_INFO *, const MFT_REGISTER_TYPE_INFO *, IMFActivate ***, UINT32 *);
   ENSURE_FUNCTION_PTR(MFTEnumEx, mfplat.dll)
   return (MFTEnumExPtr)(guidCategory, Flags, pInputType, pOutputType, pppMFTActivate, pcMFTActivate);
 }
 
 HRESULT MFGetService(IUnknown *punkObject,
                      REFGUID guidService,
                      REFIID riid,
                      LPVOID *ppvObject)
 {
-  DECL_FUNCTION_PTR(MFGetService, IUnknown*, REFGUID, REFIID, LPVOID *);
   ENSURE_FUNCTION_PTR(MFGetService, mf.dll)
   return (MFGetServicePtr)(punkObject, guidService, riid, ppvObject);
 }
 
 HRESULT
 DXVA2CreateDirect3DDeviceManager9(UINT *pResetToken,
                                   IDirect3DDeviceManager9 **ppDXVAManager)
 {
-  DECL_FUNCTION_PTR(DXVA2CreateDirect3DDeviceManager9, UINT*, IDirect3DDeviceManager9 **);
   ENSURE_FUNCTION_PTR(DXVA2CreateDirect3DDeviceManager9, dxva2.dll)
   return (DXVA2CreateDirect3DDeviceManager9Ptr)(pResetToken, ppDXVAManager);
 }
 
 HRESULT
 MFCreateSample(IMFSample **ppIMFSample)
 {
-  DECL_FUNCTION_PTR(MFCreateSample, IMFSample **);
   ENSURE_FUNCTION_PTR(MFCreateSample, mfplat.dll)
   return (MFCreateSamplePtr)(ppIMFSample);
 }
 
 HRESULT
 MFCreateAlignedMemoryBuffer(DWORD cbMaxLength,
                             DWORD fAlignmentFlags,
                             IMFMediaBuffer **ppBuffer)
 {
-  DECL_FUNCTION_PTR(MFCreateAlignedMemoryBuffer, DWORD, DWORD, IMFMediaBuffer**);
   ENSURE_FUNCTION_PTR(MFCreateAlignedMemoryBuffer, mfplat.dll)
   return (MFCreateAlignedMemoryBufferPtr)(cbMaxLength, fAlignmentFlags, ppBuffer);
 }
 
 } // end namespace wmf
 } // end namespace mozilla
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -11,16 +11,18 @@
 #include "nsIContent.h"
 #include "nsIEditor.h"
 #include "nsIMEStateManager.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/TextEvents.h"
 
+using namespace mozilla::widget;
+
 namespace mozilla {
 
 /******************************************************************************
  * TextComposition
  ******************************************************************************/
 
 TextComposition::TextComposition(nsPresContext* aPresContext,
                                  nsINode* aNode,
@@ -103,17 +105,17 @@ TextComposition::NotityUpdateComposition
       if (range.mRangeType == NS_TEXTRANGE_SELECTEDRAWTEXT ||
           range.mRangeType == NS_TEXTRANGE_SELECTEDCONVERTEDTEXT) {
         mCompositionTargetOffset += range.mStartOffset;
         break;
       }
     }
   }
 
-  NotifyIME(widget::NotificationToIME::NOTIFY_IME_OF_COMPOSITION_UPDATE);
+  NotifyIME(NOTIFY_IME_OF_COMPOSITION_UPDATE);
 }
 
 void
 TextComposition::DispatchCompsotionEventRunnable(uint32_t aEventMessage,
                                                  const nsAString& aData)
 {
   nsContentUtils::AddScriptRunner(
     new CompositionEventDispatcher(mPresContext, mNode,
@@ -128,20 +130,20 @@ TextComposition::SynthesizeCommit(bool a
   if (mLastData != data) {
     DispatchCompsotionEventRunnable(NS_COMPOSITION_UPDATE, data);
     DispatchCompsotionEventRunnable(NS_TEXT_TEXT, data);
   }
   DispatchCompsotionEventRunnable(NS_COMPOSITION_END, data);
 }
 
 nsresult
-TextComposition::NotifyIME(widget::NotificationToIME aNotification)
+TextComposition::NotifyIME(IMEMessage aMessage)
 {
   NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
-  return nsIMEStateManager::NotifyIME(aNotification, mPresContext);
+  return nsIMEStateManager::NotifyIME(aMessage, mPresContext);
 }
 
 void
 TextComposition::EditorWillHandleTextEvent(const WidgetTextEvent* aTextEvent)
 {
   mIsComposing = aTextEvent->IsComposing();
 
   MOZ_ASSERT(mLastData == aTextEvent->theText,
--- a/dom/events/TextComposition.h
+++ b/dom/events/TextComposition.h
@@ -69,17 +69,17 @@ public:
    * @param aDiscard true when committing with empty string.  Otherwise, false.
    */
   void SynthesizeCommit(bool aDiscard);
 
   /**
    * Send a notification to IME.  It depends on the IME or platform spec what
    * will occur (or not occur).
    */
-  nsresult NotifyIME(widget::NotificationToIME aNotification);
+  nsresult NotifyIME(widget::IMEMessage aMessage);
 
   /**
    * the offset of first selected clause or start of of compositon
    */
   uint32_t OffsetOfTargetClause() const { return mCompositionTargetOffset; }
 
   /**
    * Returns true if there is non-empty composition string and it's not fixed.
--- a/dom/events/nsIMEStateManager.cpp
+++ b/dom/events/nsIMEStateManager.cpp
@@ -581,44 +581,45 @@ nsIMEStateManager::DispatchCompositionEv
     if (i != TextCompositionArray::NoIndex) {
       sTextCompositions->RemoveElementAt(i);
     }
   }
 }
 
 // static
 nsresult
-nsIMEStateManager::NotifyIME(NotificationToIME aNotification,
+nsIMEStateManager::NotifyIME(IMEMessage aMessage,
                              nsIWidget* aWidget)
 {
   NS_ENSURE_TRUE(aWidget, NS_ERROR_INVALID_ARG);
 
   nsRefPtr<TextComposition> composition;
   if (sTextCompositions) {
     composition = sTextCompositions->GetCompositionFor(aWidget);
   }
   if (!composition || !composition->IsSynthesizedForTests()) {
-    switch (aNotification) {
+    switch (aMessage) {
       case NOTIFY_IME_OF_CURSOR_POS_CHANGED:
-        return aWidget->NotifyIME(aNotification);
+        return aWidget->NotifyIME(IMENotification(aMessage));
       case REQUEST_TO_COMMIT_COMPOSITION:
       case REQUEST_TO_CANCEL_COMPOSITION:
       case NOTIFY_IME_OF_COMPOSITION_UPDATE:
-        return composition ? aWidget->NotifyIME(aNotification) : NS_OK;
+        return composition ?
+          aWidget->NotifyIME(IMENotification(aMessage)) : NS_OK;
       default:
         MOZ_CRASH("Unsupported notification");
     }
     MOZ_CRASH(
       "Failed to handle the notification for non-synthesized composition");
   }
 
   // If the composition is synthesized events for automated tests, we should
   // dispatch composition events for emulating the native composition behavior.
   // NOTE: The dispatched events are discarded if it's not safe to run script.
-  switch (aNotification) {
+  switch (aMessage) {
     case REQUEST_TO_COMMIT_COMPOSITION: {
       nsCOMPtr<nsIWidget> widget(aWidget);
       nsEventStatus status = nsEventStatus_eIgnore;
       if (!composition->LastData().IsEmpty()) {
         WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget);
         textEvent.theText = composition->LastData();
         textEvent.mFlags.mIsSynthesizedForTests = true;
         widget->DispatchEvent(&textEvent, status);
@@ -667,26 +668,26 @@ nsIMEStateManager::NotifyIME(Notificatio
     }
     default:
       return NS_OK;
   }
 }
 
 // static
 nsresult
-nsIMEStateManager::NotifyIME(NotificationToIME aNotification,
+nsIMEStateManager::NotifyIME(IMEMessage aMessage,
                              nsPresContext* aPresContext)
 {
   NS_ENSURE_TRUE(aPresContext, NS_ERROR_INVALID_ARG);
 
   nsIWidget* widget = aPresContext->GetRootWidget();
   if (!widget) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-  return NotifyIME(aNotification, widget);
+  return NotifyIME(aMessage, widget);
 }
 
 void
 nsTextStateManager::Init(nsIWidget* aWidget,
                          nsPresContext* aPresContext,
                          nsIContent* aContent)
 {
   mWidget = aWidget;
@@ -735,17 +736,17 @@ nsTextStateManager::Init(nsIWidget* aWid
   NS_ENSURE_TRUE_VOID(mRootContent);
 
   if (nsIMEStateManager::sIsTestingIME) {
     nsIDocument* doc = aPresContext->Document();
     (new nsAsyncDOMEvent(doc, NS_LITERAL_STRING("MozIMEFocusIn"),
                          false, false))->RunDOMEventWhenSafe();
   }
 
-  aWidget->NotifyIME(NOTIFY_IME_OF_FOCUS);
+  aWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS));
 
   // NOTIFY_IME_OF_FOCUS might cause recreating nsTextStateManager
   // instance via nsIMEStateManager::UpdateIMEState().  So, this
   // instance might already have been destroyed, check it.
   if (!mRootContent) {
     return;
   }
 
@@ -772,24 +773,24 @@ nsTextStateManager::ObserveEditableNode(
     mRootContent->AddMutationObserver(this);
   }
 }
 
 void
 nsTextStateManager::Destroy(void)
 {
   // If CreateTextStateManager failed, mRootContent will be null,
-  // and we should not call NotifyIME(NOTIFY_IME_OF_BLUR)
+  // and we should not call NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR))
   if (mRootContent) {
     if (nsIMEStateManager::sIsTestingIME && mEditableNode) {
       nsIDocument* doc = mEditableNode->OwnerDoc();
       (new nsAsyncDOMEvent(doc, NS_LITERAL_STRING("MozIMEFocusOut"),
                            false, false))->RunDOMEventWhenSafe();
     }
-    mWidget->NotifyIME(NOTIFY_IME_OF_BLUR);
+    mWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
   }
   // Even if there are some pending notification, it'll never notify the widget.
   mWidget = nullptr;
   if ((mObserving & nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE) && mSel) {
     nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSel));
     if (selPrivate)
       selPrivate->RemoveSelectionListener(this);
   }
@@ -826,17 +827,18 @@ public:
   SelectionChangeEvent(nsTextStateManager *aDispatcher)
     : mDispatcher(aDispatcher)
   {
     MOZ_ASSERT(mDispatcher);
   }
 
   NS_IMETHOD Run() {
     if (mDispatcher->mWidget) {
-      mDispatcher->mWidget->NotifyIME(NOTIFY_IME_OF_SELECTION_CHANGE);
+      mDispatcher->mWidget->NotifyIME(
+        IMENotification(NOTIFY_IME_OF_SELECTION_CHANGE));
     }
     return NS_OK;
   }
 
 private:
   nsRefPtr<nsTextStateManager> mDispatcher;
 };
 
@@ -864,17 +866,21 @@ public:
     , mOldEnd(oldEnd)
     , mNewEnd(newEnd)
   {
     MOZ_ASSERT(mDispatcher);
   }
 
   NS_IMETHOD Run() {
     if (mDispatcher->mWidget) {
-      mDispatcher->mWidget->NotifyIMEOfTextChange(mStart, mOldEnd, mNewEnd);
+      IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE);
+      notification.mTextChangeData.mStartOffset = mStart;
+      notification.mTextChangeData.mOldEndOffset = mOldEnd;
+      notification.mTextChangeData.mNewEndOffset = mNewEnd;
+      mDispatcher->mWidget->NotifyIME(notification);
     }
     return NS_OK;
   }
 
 private:
   nsRefPtr<nsTextStateManager> mDispatcher;
   uint32_t mStart, mOldEnd, mNewEnd;
 };
--- a/dom/events/nsIMEStateManager.h
+++ b/dom/events/nsIMEStateManager.h
@@ -26,16 +26,17 @@ class TextComposition;
 /*
  * IME state manager
  */
 
 class nsIMEStateManager
 {
   friend class nsTextStateManager;
 protected:
+  typedef mozilla::widget::IMEMessage IMEMessage;
   typedef mozilla::widget::IMEState IMEState;
   typedef mozilla::widget::InputContext InputContext;
   typedef mozilla::widget::InputContextAction InputContextAction;
 
 public:
   static void Shutdown();
 
   static nsresult OnDestroyPresContext(nsPresContext* aPresContext);
@@ -109,20 +110,18 @@ public:
    */
   static already_AddRefed<mozilla::TextComposition>
     GetTextCompositionFor(mozilla::WidgetGUIEvent* aEvent);
 
   /**
    * Send a notification to IME.  It depends on the IME or platform spec what
    * will occur (or not occur).
    */
-  static nsresult NotifyIME(mozilla::widget::NotificationToIME aNotification,
-                            nsIWidget* aWidget);
-  static nsresult NotifyIME(mozilla::widget::NotificationToIME aNotification,
-                            nsPresContext* aPresContext);
+  static nsresult NotifyIME(IMEMessage aMessage, nsIWidget* aWidget);
+  static nsresult NotifyIME(IMEMessage aMessage, nsPresContext* aPresContext);
 
 protected:
   static nsresult OnChangeFocusInternal(nsPresContext* aPresContext,
                                         nsIContent* aContent,
                                         InputContextAction aAction);
   static void SetIMEState(const IMEState &aState,
                           nsIContent* aContent,
                           nsIWidget* aWidget,
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -62,17 +62,16 @@
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
 #include "nsIAppsService.h"
 #include "nsIClipboard.h"
 #include "nsIDOMGeoGeolocation.h"
 #include "mozilla/dom/WakeLock.h"
 #include "nsIDOMWindow.h"
 #include "nsIExternalProtocolService.h"
-#include "nsIFilePicker.h"
 #include "nsIGfxInfo.h"
 #include "nsIIdleService.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsIRemoteBlob.h"
@@ -2656,91 +2655,16 @@ ContentParent::RecvSetURITitle(const URI
     nsCOMPtr<IHistory> history = services::GetHistoryService();
     if (history) {
         history->SetURITitle(ourURI, title);
     }
     return true;
 }
 
 bool
-ContentParent::RecvShowFilePicker(const int16_t& mode,
-                                  const int16_t& selectedType,
-                                  const bool& addToRecentDocs,
-                                  const nsString& title,
-                                  const nsString& defaultFile,
-                                  const nsString& defaultExtension,
-                                  const InfallibleTArray<nsString>& filters,
-                                  const InfallibleTArray<nsString>& filterNames,
-                                  InfallibleTArray<nsString>* files,
-                                  int16_t* retValue,
-                                  nsresult* result)
-{
-    nsCOMPtr<nsIFilePicker> filePicker = do_CreateInstance("@mozilla.org/filepicker;1");
-    if (!filePicker) {
-        *result = NS_ERROR_NOT_AVAILABLE;
-        return true;
-    }
-
-    // as the parent given to the content process would be meaningless in this
-    // process, always use active window as the parent
-    nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
-    nsCOMPtr<nsIDOMWindow> window;
-    ww->GetActiveWindow(getter_AddRefs(window));
-
-    // initialize the "real" picker with all data given
-    *result = filePicker->Init(window, title, mode);
-    if (NS_FAILED(*result))
-        return true;
-
-    filePicker->SetAddToRecentDocs(addToRecentDocs);
-
-    uint32_t count = filters.Length();
-    for (uint32_t i = 0; i < count; ++i) {
-        filePicker->AppendFilter(filterNames[i], filters[i]);
-    }
-
-    filePicker->SetDefaultString(defaultFile);
-    filePicker->SetDefaultExtension(defaultExtension);
-    filePicker->SetFilterIndex(selectedType);
-
-    // and finally open the dialog
-    *result = filePicker->Show(retValue);
-    if (NS_FAILED(*result))
-        return true;
-
-    if (mode == nsIFilePicker::modeOpenMultiple) {
-        nsCOMPtr<nsISimpleEnumerator> fileIter;
-        *result = filePicker->GetFiles(getter_AddRefs(fileIter));
-
-        nsCOMPtr<nsIFile> singleFile;
-        bool loop = true;
-        while (NS_SUCCEEDED(fileIter->HasMoreElements(&loop)) && loop) {
-            fileIter->GetNext(getter_AddRefs(singleFile));
-            if (singleFile) {
-                nsAutoString filePath;
-                singleFile->GetPath(filePath);
-                files->AppendElement(filePath);
-            }
-        }
-        return true;
-    }
-    nsCOMPtr<nsIFile> file;
-    filePicker->GetFile(getter_AddRefs(file));
-
-    // Even with NS_OK file can be null if nothing was selected.
-    if (file) {
-        nsAutoString filePath;
-        file->GetPath(filePath);
-        files->AppendElement(filePath);
-    }
-
-    return true;
-}
-
-bool
 ContentParent::RecvGetRandomValues(const uint32_t& length,
                                    InfallibleTArray<uint8_t>* randomValues)
 {
     uint8_t* buf = Crypto::GetRandomValues(length);
     if (!buf) {
         return true;
     }
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -424,28 +424,16 @@ private:
 
     virtual bool RecvVisitURI(const URIParams& uri,
                               const OptionalURIParams& referrer,
                               const uint32_t& flags) MOZ_OVERRIDE;
 
     virtual bool RecvSetURITitle(const URIParams& uri,
                                  const nsString& title) MOZ_OVERRIDE;
 
-    virtual bool RecvShowFilePicker(const int16_t& mode,
-                                    const int16_t& selectedType,
-                                    const bool& addToRecentDocs,
-                                    const nsString& title,
-                                    const nsString& defaultFile,
-                                    const nsString& defaultExtension,
-                                    const InfallibleTArray<nsString>& filters,
-                                    const InfallibleTArray<nsString>& filterNames,
-                                    InfallibleTArray<nsString>* files,
-                                    int16_t* retValue,
-                                    nsresult* result) MOZ_OVERRIDE;
-
     virtual bool RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
                                            const nsString& aText, const bool& aTextClickable,
                                            const nsString& aCookie, const nsString& aName,
                                            const nsString& aBidi, const nsString& aLang,
                                            const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
 
     virtual bool RecvCloseAlert(const nsString& aName,
                                 const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
new file mode 100644
--- /dev/null
+++ b/dom/ipc/FilePickerParent.cpp
@@ -0,0 +1,133 @@
+/* -*- 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 "FilePickerParent.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIDocument.h"
+#include "nsIDOMWindow.h"
+#include "nsIFile.h"
+#include "nsISimpleEnumerator.h"
+#include "mozilla/unused.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/TabParent.h"
+
+using mozilla::unused;
+using namespace mozilla::dom;
+
+NS_IMPL_ISUPPORTS1(FilePickerParent::FilePickerShownCallback,
+                   nsIFilePickerShownCallback);
+
+NS_IMETHODIMP
+FilePickerParent::FilePickerShownCallback::Done(int16_t aResult)
+{
+  if (mFilePickerParent) {
+    mFilePickerParent->Done(aResult);
+  }
+  return NS_OK;
+}
+
+void
+FilePickerParent::FilePickerShownCallback::Destroy()
+{
+  mFilePickerParent = nullptr;
+}
+
+FilePickerParent::~FilePickerParent()
+{
+}
+
+void
+FilePickerParent::Done(int16_t aResult)
+{
+  InfallibleTArray<nsString> files;
+
+  if (mMode == nsIFilePicker::modeOpenMultiple) {
+    nsCOMPtr<nsISimpleEnumerator> iter;
+    NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
+
+    nsCOMPtr<nsIFile> file;
+    bool loop = true;
+    while (NS_SUCCEEDED(iter->HasMoreElements(&loop)) && loop) {
+      iter->GetNext(getter_AddRefs(file));
+      if (file) {
+        nsAutoString path;
+        if (NS_SUCCEEDED(file->GetPath(path))) {
+          files.AppendElement(path);
+        }
+      }
+    }
+  } else {
+    nsCOMPtr<nsIFile> file;
+    mFilePicker->GetFile(getter_AddRefs(file));
+
+    if (file) {
+      nsAutoString path;
+      if (NS_SUCCEEDED(file->GetPath(path))) {
+        files.AppendElement(path);
+      }
+    }
+  }
+
+  unused << Send__delete__(this, InputFiles(files), aResult);
+}
+
+bool
+FilePickerParent::CreateFilePicker()
+{
+  mFilePicker = do_CreateInstance("@mozilla.org/filepicker;1");
+  if (!mFilePicker) {
+    return false;
+  }
+
+  Element* element = static_cast<TabParent*>(Manager())->GetOwnerElement();
+  if (!element) {
+    return false;
+  }
+
+  nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(element->OwnerDoc()->GetWindow());
+  if (!window) {
+    return false;
+  }
+
+  return NS_SUCCEEDED(mFilePicker->Init(window, mTitle, mMode));
+}
+
+bool
+FilePickerParent::RecvOpen(const int16_t& aSelectedType,
+                           const bool& aAddToRecentDocs,
+                           const nsString& aDefaultFile,
+                           const nsString& aDefaultExtension,
+                           const InfallibleTArray<nsString>& aFilters,
+                           const InfallibleTArray<nsString>& aFilterNames)
+{
+  if (!CreateFilePicker()) {
+    unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
+    return true;
+  }
+
+  mFilePicker->SetAddToRecentDocs(aAddToRecentDocs);
+
+  for (uint32_t i = 0; i < aFilters.Length(); ++i) {
+    mFilePicker->AppendFilter(aFilterNames[i], aFilters[i]);
+  }
+
+  mFilePicker->SetDefaultString(aDefaultFile);
+  mFilePicker->SetDefaultExtension(aDefaultExtension);
+  mFilePicker->SetFilterIndex(aSelectedType);
+
+  mCallback = new FilePickerShownCallback(this);
+
+  mFilePicker->Open(mCallback);
+  return true;
+}
+
+void
+FilePickerParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  if (mCallback) {
+    mCallback->Destroy();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/FilePickerParent.h
@@ -0,0 +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/. */
+
+#ifndef mozilla_dom_FilePickerParent_h
+#define mozilla_dom_FilePickerParent_h
+
+#include "nsIFilePicker.h"
+#include "mozilla/dom/PFilePickerParent.h"
+
+namespace mozilla {
+namespace dom {
+
+class FilePickerParent : public PFilePickerParent
+{
+ public:
+  FilePickerParent(const nsString& aTitle,
+                   const int16_t& aMode)
+  : mTitle(aTitle)
+  , mMode(aMode)
+  {}
+
+  virtual ~FilePickerParent();
+
+  void Done(int16_t aResult);
+
+  virtual bool RecvOpen(const int16_t& aSelectedType,
+                        const bool& aAddToRecentDocs,
+                        const nsString& aDefaultFile,
+                        const nsString& aDefaultExtension,
+                        const InfallibleTArray<nsString>& aFilters,
+                        const InfallibleTArray<nsString>& aFilterNames) MOZ_OVERRIDE;
+
+  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  class FilePickerShownCallback : public nsIFilePickerShownCallback
+  {
+  public:
+    FilePickerShownCallback(FilePickerParent* aFilePickerParent)
+      : mFilePickerParent(aFilePickerParent)
+    { }
+    virtual ~FilePickerShownCallback() {}
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIFILEPICKERSHOWNCALLBACK
+
+    void Destroy();
+
+  private:
+    FilePickerParent* mFilePickerParent;
+  };
+
+ private:
+  bool CreateFilePicker();
+
+  nsRefPtr<FilePickerShownCallback> mCallback;
+  nsCOMPtr<nsIFilePicker> mFilePicker;
+
+  nsString mTitle;
+  int16_t mMode;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -5,16 +5,17 @@
  * 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 protocol PBlob;
 include protocol PContent;
 include protocol PContentDialog;
 include protocol PDocumentRenderer;
 include protocol PContentPermissionRequest;
+include protocol PFilePicker;
 include protocol PRenderFrame;
 include protocol POfflineCacheUpdate;
 include protocol PIndexedDB;
 include DOMTypes;
 include JavaScriptTypes;
 include URIParams;
 include PContentPermission;
 
@@ -54,16 +55,17 @@ namespace dom {
 
 intr protocol PBrowser
 {
     manager PContent;
 
     manages PContentDialog;
     manages PDocumentRenderer;
     manages PContentPermissionRequest;
+    manages PFilePicker;
     manages PRenderFrame;
     manages POfflineCacheUpdate;
     manages PIndexedDB;
 
 both:
     AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows,
                  Principal aPrincipal);
 
@@ -232,16 +234,18 @@ parent:
      *       principals that can live in the content process should
      *       provided.
      */
     PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal);
 
     PContentDialog(uint32_t aType, nsCString aName, nsCString aFeatures,
                    int32_t[] aIntParams, nsString[] aStringParams);
 
+    PFilePicker(nsString aTitle, int16_t aMode);
+
     /**
      * Create a layout frame (encapsulating a remote layer tree) for
      * the page that is currently loaded in the <browser>.
      */
     sync PRenderFrame();
 
     sync InitRenderFrame(PRenderFrame aFrame)
         returns (ScrollingBehavior scrolling,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -383,22 +383,16 @@ parent:
 
     PAsmJSCacheEntry(OpenMode openMode, WriteParams write, Principal principal);
 
     // Services remoting
 
     async StartVisitedQuery(URIParams uri);
     async VisitURI(URIParams uri, OptionalURIParams referrer, uint32_t flags);
     async SetURITitle(URIParams uri, nsString title);
-    
-    // filepicker remoting
-    sync ShowFilePicker(int16_t mode, int16_t selectedType, bool addToRecentDocs,
-                        nsString title, nsString defaultFile, nsString defaultExtension,
-                        nsString[] filters, nsString[] filterNames)
-        returns (nsString[] files, int16_t retValue, nsresult result);
 
     async LoadURIExternal(URIParams uri);
 
     // PrefService message
     sync ReadPrefsArray() returns (PrefSetting[] prefs);
 
     sync ReadFontList() returns (FontListEntry[] retValue);
 
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PFilePicker.ipdl
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+/* 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 protocol PBrowser;
+
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+
+namespace mozilla {
+namespace dom {
+
+struct InputFiles
+{
+  nsString[] files;
+};
+
+union MaybeInputFiles
+{
+  InputFiles;
+  void_t;
+};
+
+protocol PFilePicker
+{
+  manager PBrowser;
+
+parent:
+    Open(int16_t selectedType, bool addToRecentDocs, nsString defaultFile,
+         nsString defaultExtension, nsString[] filters, nsString[] filterNames);
+
+child:
+    __delete__(MaybeInputFiles files, int16_t result);
+};
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -33,16 +33,17 @@
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsEmbedCID.h"
 #include "nsEventListenerManager.h"
 #include <algorithm>
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
+#include "nsFilePickerProxy.h"
 #include "mozilla/dom/Element.h"
 #include "nsIBaseWindow.h"
 #include "nsICachedFileDescriptorListener.h"
 #include "nsIDialogParamBlock.h"
 #include "nsIDocumentInlines.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMWindow.h"
@@ -2097,16 +2098,31 @@ TabChild::DeallocPContentPermissionReque
         static_cast<PCOMContentPermissionRequestChild*>(actor);
 #ifdef DEBUG
     child->mIPCOpen = false;
 #endif /* DEBUG */
     child->IPDLRelease();
     return true;
 }
 
+PFilePickerChild*
+TabChild::AllocPFilePickerChild(const nsString&, const int16_t&)
+{
+  NS_RUNTIMEABORT("unused");
+  return nullptr;
+}
+
+bool
+TabChild::DeallocPFilePickerChild(PFilePickerChild* actor)
+{
+  nsFilePickerProxy* filePicker = static_cast<nsFilePickerProxy*>(actor);
+  NS_RELEASE(filePicker);
+  return true;
+}
+
 bool
 TabChild::RecvActivateFrameEvent(const nsString& aType, const bool& capture)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
   NS_ENSURE_TRUE(window, true);
   nsCOMPtr<EventTarget> chromeHandler =
     do_QueryInterface(window->GetChromeEventHandler());
   NS_ENSURE_TRUE(chromeHandler, true);
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -300,16 +300,21 @@ public:
 #endif /* DEBUG */
 
     virtual PContentPermissionRequestChild*
     AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
                                         const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
     virtual bool
     DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor) MOZ_OVERRIDE;
 
+    virtual PFilePickerChild*
+    AllocPFilePickerChild(const nsString& aTitle, const int16_t& aMode) MOZ_OVERRIDE;
+    virtual bool
+    DeallocPFilePickerChild(PFilePickerChild* actor) MOZ_OVERRIDE;
+
     virtual POfflineCacheUpdateChild* AllocPOfflineCacheUpdateChild(
             const URIParams& manifestURI,
             const URIParams& documentURI,
             const bool& stickDocument) MOZ_OVERRIDE;
     virtual bool
     DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* offlineCacheUpdate) MOZ_OVERRIDE;
 
     nsIWebNavigation* WebNavigation() { return mWebNav; }
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -51,16 +51,17 @@
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "private/pprio.h"
 #include "PermissionMessageUtils.h"
 #include "StructuredCloneUtils.h"
 #include "JavaScriptParent.h"
+#include "FilePickerParent.h"
 #include "TabChild.h"
 #include "LoadContext.h"
 #include "nsNetCID.h"
 #include <algorithm>
 
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
@@ -632,16 +633,29 @@ TabParent::AllocPContentPermissionReques
 
 bool
 TabParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor)
 {
   delete actor;
   return true;
 }
 
+PFilePickerParent*
+TabParent::AllocPFilePickerParent(const nsString& aTitle, const int16_t& aMode)
+{
+  return new FilePickerParent(aTitle, aMode);
+}
+
+bool
+TabParent::DeallocPFilePickerParent(PFilePickerParent* actor)
+{
+  delete actor;
+  return true;
+}
+
 void
 TabParent::SendMouseEvent(const nsAString& aType, float aX, float aY,
                           int32_t aButton, int32_t aClickCount,
                           int32_t aModifiers, bool aIgnoreRootScrollFrame)
 {
   if (!mIsDestroyed) {
     unused << PBrowserParent::SendMouseEvent(nsString(aType), aX, aY,
                                              aButton, aClickCount,
@@ -1039,17 +1053,18 @@ TabParent::RecvNotifyIMEFocus(const bool
     aPreference->mWantUpdates = nsIMEUpdatePreference::NOTIFY_NOTHING;
     return true;
   }
 
   *aSeqno = mIMESeqno;
   mIMETabParent = aFocus ? this : nullptr;
   mIMESelectionAnchor = 0;
   mIMESelectionFocus = 0;
-  widget->NotifyIME(aFocus ? NOTIFY_IME_OF_FOCUS : NOTIFY_IME_OF_BLUR);
+  widget->NotifyIME(IMENotification(aFocus ? NOTIFY_IME_OF_FOCUS :
+                                             NOTIFY_IME_OF_BLUR));
 
   if (aFocus) {
     *aPreference = widget->GetIMEUpdatePreference();
   } else {
     mIMECacheText.Truncate(0);
   }
   return true;
 }
@@ -1061,17 +1076,21 @@ TabParent::RecvNotifyIMETextChange(const
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return true;
 
   NS_ASSERTION(widget->GetIMEUpdatePreference().WantTextChange(),
                "Don't call Send/RecvNotifyIMETextChange without NOTIFY_TEXT_CHANGE");
 
-  widget->NotifyIMEOfTextChange(aStart, aEnd, aNewEnd);
+  IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE);
+  notification.mTextChangeData.mStartOffset = aStart;
+  notification.mTextChangeData.mOldEndOffset = aEnd;
+  notification.mTextChangeData.mNewEndOffset = aNewEnd;
+  widget->NotifyIME(notification);
   return true;
 }
 
 bool
 TabParent::RecvNotifyIMESelectedCompositionRect(const uint32_t& aOffset,
                                                 const nsIntRect& aRect,
                                                 const nsIntRect& aCaretRect)
 {
@@ -1079,34 +1098,34 @@ TabParent::RecvNotifyIMESelectedComposit
   mIMECompositionRectOffset = aOffset;
   mIMECompositionRect = aRect;
   mIMECaretRect = aCaretRect;
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
-  widget->NotifyIME(NOTIFY_IME_OF_COMPOSITION_UPDATE);
+  widget->NotifyIME(IMENotification(NOTIFY_IME_OF_COMPOSITION_UPDATE));
   return true;
 }
 
 bool
 TabParent::RecvNotifyIMESelection(const uint32_t& aSeqno,
                                   const uint32_t& aAnchor,
                                   const uint32_t& aFocus)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return true;
 
   if (aSeqno == mIMESeqno) {
     mIMESelectionAnchor = aAnchor;
     mIMESelectionFocus = aFocus;
     if (widget->GetIMEUpdatePreference().WantSelectionChange()) {
-      widget->NotifyIME(NOTIFY_IME_OF_SELECTION_CHANGE);
+      widget->NotifyIME(IMENotification(NOTIFY_IME_OF_SELECTION_CHANGE));
     }
   }
   return true;
 }
 
 bool
 TabParent::RecvNotifyIMETextHint(const nsString& aText)
 {
@@ -1353,18 +1372,18 @@ TabParent::RecvEndIMEComposition(const b
                                  nsString* aComposition)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return true;
 
   mIMECompositionEnding = true;
 
-  widget->NotifyIME(aCancel ? REQUEST_TO_CANCEL_COMPOSITION :
-                              REQUEST_TO_COMMIT_COMPOSITION);
+  widget->NotifyIME(IMENotification(aCancel ? REQUEST_TO_CANCEL_COMPOSITION :
+                                              REQUEST_TO_COMMIT_COMPOSITION));
 
   mIMECompositionEnding = false;
   *aComposition = mIMECompositionText;
   mIMECompositionText.Truncate(0);  
   return true;
 }
 
 bool
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_tabs_TabParent_h
 #define mozilla_tabs_TabParent_h
 
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/PContentDialogParent.h"
+#include "mozilla/dom/PFilePickerParent.h"
 #include "mozilla/dom/TabContext.h"
 #include "nsCOMPtr.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsIDialogParamBlock.h"
 #include "nsISecureBrowserUI.h"
 #include "nsITabParent.h"
 #include "nsIXULBrowserWindow.h"
@@ -253,16 +254,21 @@ public:
     virtual bool DeallocPDocumentRendererParent(PDocumentRendererParent* actor) MOZ_OVERRIDE;
 
     virtual PContentPermissionRequestParent*
     AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
                                          const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
     virtual bool
     DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor) MOZ_OVERRIDE;
 
+    virtual PFilePickerParent*
+    AllocPFilePickerParent(const nsString& aTitle,
+                           const int16_t& aMode) MOZ_OVERRIDE;
+    virtual bool DeallocPFilePickerParent(PFilePickerParent* actor) MOZ_OVERRIDE;
+
     virtual POfflineCacheUpdateParent*
     AllocPOfflineCacheUpdateParent(const URIParams& aManifestURI,
                                    const URIParams& aDocumentURI,
                                    const bool& aStickDocument) MOZ_OVERRIDE;
     virtual bool
     RecvPOfflineCacheUpdateConstructor(POfflineCacheUpdateParent* aActor,
                                        const URIParams& aManifestURI,
                                        const URIParams& aDocumentURI,
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -18,16 +18,17 @@ EXPORTS.mozilla.dom.ipc += [
 ]
 
 EXPORTS.mozilla.dom += [
     'ContentChild.h',
     'ContentParent.h',
     'ContentProcess.h',
     'CrashReporterChild.h',
     'CrashReporterParent.h',
+    'FilePickerParent.h',
     'PermissionMessageUtils.h',
     'StructuredCloneUtils.h',
     'TabChild.h',
     'TabContext.h',
     'TabMessageUtils.h',
     'TabParent.h',
 ]
 
@@ -38,16 +39,17 @@ EXPORTS.mozilla += [
 ]
 
 UNIFIED_SOURCES += [
     'AppProcessChecker.cpp',
     'ContentChild.cpp',
     'ContentParent.cpp',
     'ContentProcess.cpp',
     'CrashReporterParent.cpp',
+    'FilePickerParent.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
     'ProcessPriorityManager.cpp',
     'StructuredCloneUtils.cpp',
     'TabChild.cpp',
     'TabContext.cpp',
     'TabMessageUtils.cpp',
     'TabParent.cpp',
@@ -67,16 +69,17 @@ IPDL_SOURCES += [
     'PBlobStream.ipdl',
     'PBrowser.ipdl',
     'PContent.ipdl',
     'PContentDialog.ipdl',
     'PContentPermission.ipdlh',
     'PContentPermissionRequest.ipdl',
     'PCrashReporter.ipdl',
     'PDocumentRenderer.ipdl',
+    'PFilePicker.ipdl',
     'PMemoryReportRequest.ipdl',
     'PTabContext.ipdlh',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/dom/plugins/test/testplugin/nptest_windows.cpp
+++ b/dom/plugins/test/testplugin/nptest_windows.cpp
@@ -35,32 +35,17 @@
 #include "nptest_platform.h"
 
 #include <windows.h>
 #include <windowsx.h>
 #include <stdio.h>
 
 #include <d3d10_1.h>
 
-typedef HRESULT (WINAPI*D3D10CreateDevice1Func)(
-  IDXGIAdapter *pAdapter,
-  D3D10_DRIVER_TYPE DriverType,
-  HMODULE Software,
-  UINT Flags,
-  D3D10_FEATURE_LEVEL1 HardwareLevel,
-  UINT SDKVersion,
-  ID3D10Device1 **ppDevice
-);
-
-typedef HRESULT(WINAPI*CreateDXGIFactory1Func)(
-  REFIID riid,
-  void **ppFactory
-);
-
- using namespace std;
+using namespace std;
 
 void SetSubclass(HWND hWnd, InstanceData* instanceData);
 void ClearSubclass(HWND hWnd);
 LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
 struct _PlatformData {
   HWND childWindow;
   ID3D10Device1 *device;
@@ -121,23 +106,25 @@ pluginInstanceShutdown(InstanceData* ins
 }
 
 static ID3D10Device1*
 getD3D10Device()
 {
   ID3D10Device1 *device;
     
   HMODULE d3d10module = LoadLibraryA("d3d10_1.dll");
-  D3D10CreateDevice1Func createD3DDevice = (D3D10CreateDevice1Func)
-      GetProcAddress(d3d10module, "D3D10CreateDevice1");
+  decltype(D3D10CreateDevice1)* createD3DDevice =
+      (decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module,
+                                                     "D3D10CreateDevice1");
 
   if (createD3DDevice) {
     HMODULE dxgiModule = LoadLibraryA("dxgi.dll");
-    CreateDXGIFactory1Func createDXGIFactory1 = (CreateDXGIFactory1Func)
-        GetProcAddress(dxgiModule, "CreateDXGIFactory1");
+    decltype(CreateDXGIFactory1)* createDXGIFactory1 =
+        (decltype(CreateDXGIFactory1)*) GetProcAddress(dxgiModule,
+                                                       "CreateDXGIFactory1");
 
     HRESULT hr;
 
     // Try to use a DXGI 1.1 adapter in order to share resources
     // across processes.
     IDXGIAdapter1 *adapter1;
     if (createDXGIFactory1) {
       IDXGIFactory1 *factory1;
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -18,38 +18,24 @@
 #include "FilterNodeSoftware.h"
 
 #ifdef USE_D2D1_1
 #include "FilterNodeD2D1.h"
 #endif
 
 #include <dwrite.h>
 
+// decltype is not usable for overloaded functions.
 typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
     D2D1_FACTORY_TYPE factoryType,
     REFIID iid,
     CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
     void **factory
 );
 
-typedef HRESULT (WINAPI*D3D10CreateEffectFromMemoryFunc)(
-    void *pData,
-    SIZE_T DataLength,
-    UINT FXFlags,
-    ID3D10Device *pDevice,
-    ID3D10EffectPool *pEffectPool,
-    ID3D10Effect **ppEffect
-);
-
-typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)(
-  DWRITE_FACTORY_TYPE factoryType,
-  REFIID iid,
-  IUnknown **factory
-);
-
 using namespace std;
 
 namespace mozilla {
 namespace gfx {
 
 struct Vertex {
   float x;
   float y;
@@ -1383,19 +1369,19 @@ DrawTargetD2D::InitD3D10Data()
   hr = mDevice->GetPrivateData(sPrivateDataD2D, &privateDataSize, &mPrivateData);
 
   if (SUCCEEDED(hr)) {
       return true;
   }
 
   mPrivateData = new PrivateD3D10DataD2D;
 
-  D3D10CreateEffectFromMemoryFunc createD3DEffect;
+  decltype(D3D10CreateEffectFromMemory)* createD3DEffect;
   HMODULE d3dModule = LoadLibraryW(L"d3d10_1.dll");
-  createD3DEffect = (D3D10CreateEffectFromMemoryFunc)
+  createD3DEffect = (decltype(D3D10CreateEffectFromMemory)*)
       GetProcAddress(d3dModule, "D3D10CreateEffectFromMemory");
 
   hr = createD3DEffect((void*)d2deffect, sizeof(d2deffect), 0, mDevice, nullptr, byRef(mPrivateData->mEffect));
 
   if (FAILED(hr)) {
     gfxWarning() << "Failed to initialize Direct2D required effects. Code: " << hr;
     return false;
   }
@@ -2653,19 +2639,19 @@ DrawTargetD2D::CleanupD2D()
 
 IDWriteFactory*
 DrawTargetD2D::GetDWriteFactory()
 {
   if (mDWriteFactory) {
     return mDWriteFactory;
   }
 
-  DWriteCreateFactoryFunc createDWriteFactory;
+  decltype(DWriteCreateFactory)* createDWriteFactory;
   HMODULE dwriteModule = LoadLibraryW(L"dwrite.dll");
-  createDWriteFactory = (DWriteCreateFactoryFunc)
+  createDWriteFactory = (decltype(DWriteCreateFactory)*)
     GetProcAddress(dwriteModule, "DWriteCreateFactory");
 
   if (!createDWriteFactory) {
     gfxWarning() << "Failed to locate DWriteCreateFactory function.";
     return nullptr;
   }
 
   HRESULT hr = createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -384,16 +384,17 @@ public:
                        const gfx::Rect& aClipRect,
                        const gfx::Matrix4x4& transform);
 
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const = 0;
 #endif // MOZ_DUMP_PAINTING
 
+  virtual LayersBackend GetBackendType() const = 0;
 
   /**
    * Each Compositor has a unique ID.
    * This ID is used to keep references to each Compositor in a map accessed
    * from the compositor thread only, so that async compositables can find
    * the right compositor parent and schedule compositing even if the compositor
    * changed.
    */
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -111,16 +111,20 @@ public:
 
   virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) { }
 
   virtual void PrepareViewport(const gfx::IntSize& aSize,
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE { }
 
   virtual const char* Name() const { return "Basic"; }
 
+  virtual LayersBackend GetBackendType() const MOZ_OVERRIDE {
+    return LayersBackend::LAYERS_BASIC;
+  }
+
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   gfx::DrawTarget *GetDrawTarget() { return mDrawTarget; }
 
 private:
   // Widget associated with this compositor
   nsIWidget *mWidget;
   nsIntSize mWidgetSize;
--- a/gfx/layers/basic/TextureHostBasic.cpp
+++ b/gfx/layers/basic/TextureHostBasic.cpp
@@ -1,17 +1,14 @@
 /* -*- Mode: C++; tab-width: 20; 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/. */
 
 #include "TextureHostBasic.h"
-#ifdef MOZ_X11
-#include "TextureHostX11.h"
-#endif
 #include "MacIOSurfaceTextureHostBasic.h"
 
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
@@ -23,21 +20,13 @@ CreateTextureHostBasic(const SurfaceDesc
 #ifdef XP_MACOSX
   if (aDesc.type() == SurfaceDescriptor::TSurfaceDescriptorMacIOSurface) {
     const SurfaceDescriptorMacIOSurface& desc =
       aDesc.get_SurfaceDescriptorMacIOSurface();
     RefPtr<TextureHost> result = new MacIOSurfaceTextureHostBasic(aFlags, desc);
     return result;
   }
 #endif
-#ifdef MOZ_X11
-  if (aDesc.type() == SurfaceDescriptor::TSurfaceDescriptorX11) {
-    const SurfaceDescriptorX11& desc = aDesc.get_SurfaceDescriptorX11();
-    RefPtr<TextureHost> result = new TextureHostX11(aFlags, desc);
-    return result;
-  }
-#endif
-
   return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
 }
 
 } // namespace layers
 } // namespace gfx
rename from gfx/layers/basic/TextureHostX11.cpp
rename to gfx/layers/basic/X11TextureSourceBasic.cpp
--- a/gfx/layers/basic/TextureHostX11.cpp
+++ b/gfx/layers/basic/X11TextureSourceBasic.cpp
@@ -1,111 +1,65 @@
 /* -*- Mode: C++; tab-width: 20; 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/. */
 
-#include "TextureHostX11.h"
+#include "X11TextureSourceBasic.h"
 #include "mozilla/layers/BasicCompositor.h"
 #include "gfxXlibSurface.h"
 #include "gfx2DGlue.h"
 
 using namespace mozilla;
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
-static inline SurfaceFormat
-ContentTypeToSurfaceFormat(gfxContentType type)
+X11TextureSourceBasic::X11TextureSourceBasic(BasicCompositor* aCompositor, gfxXlibSurface* aSurface)
+  : mCompositor(aCompositor),
+    mSurface(aSurface)
+{
+}
+
+IntSize
+X11TextureSourceBasic::GetSize() const
+{
+  return ToIntSize(mSurface->GetSize());
+}
+
+SurfaceFormat
+X11TextureSourceBasic::GetFormat() const
 {
-  switch (type) {
+  gfxContentType type = mSurface->GetContentType();
+  return X11TextureSourceBasic::ContentTypeToSurfaceFormat(type);
+}
+
+SourceSurface*
+X11TextureSourceBasic::GetSurface()
+{
+  if (!mSourceSurface) {
+    mSourceSurface =
+      Factory::CreateSourceSurfaceForCairoSurface(mSurface->CairoSurface(), GetFormat());
+  }
+  return mSourceSurface;
+}
+
+void
+X11TextureSourceBasic::SetCompositor(Compositor* aCompositor)
+{
+  MOZ_ASSERT(aCompositor->GetBackendType() == LayersBackend::LAYERS_BASIC);
+  BasicCompositor* compositor = static_cast<BasicCompositor*>(aCompositor);
+  mCompositor = compositor;
+}
+
+SurfaceFormat
+X11TextureSourceBasic::ContentTypeToSurfaceFormat(gfxContentType aType)
+{
+  switch (aType) {
     case gfxContentType::COLOR:
       return SurfaceFormat::B8G8R8X8;
     case gfxContentType::ALPHA:
       return SurfaceFormat::A8;
     case gfxContentType::COLOR_ALPHA:
       return SurfaceFormat::B8G8R8A8;
     default:
       return SurfaceFormat::UNKNOWN;
   }
-}
-
-TextureSourceX11::TextureSourceX11(BasicCompositor* aCompositor, gfxXlibSurface* aSurface)
-  : mCompositor(aCompositor),
-    mSurface(aSurface)
-{
-}
-
-IntSize
-TextureSourceX11::GetSize() const
-{
-  return ToIntSize(mSurface->GetSize());
-}
-
-SurfaceFormat
-TextureSourceX11::GetFormat() const
-{
-  return ContentTypeToSurfaceFormat(mSurface->GetContentType());
-}
-
-SourceSurface*
-TextureSourceX11::GetSurface()
-{
-  if (!mSourceSurface) {
-    mSourceSurface =
-      Factory::CreateSourceSurfaceForCairoSurface(mSurface->CairoSurface(), GetFormat());
-  }
-  return mSourceSurface;
-}
-
-void
-TextureSourceX11::SetCompositor(Compositor* aCompositor)
-{
-  BasicCompositor* compositor = static_cast<BasicCompositor*>(aCompositor);
-  mCompositor = compositor;
-}
-
-TextureHostX11::TextureHostX11(TextureFlags aFlags,
-                               const SurfaceDescriptorX11& aDescriptor)
- : TextureHost(aFlags)
-{
-  nsRefPtr<gfxXlibSurface> surface = aDescriptor.OpenForeign();
-  mSurface = surface.get();
-
-  // The host always frees the pixmap.
-  MOZ_ASSERT(!(aFlags & TEXTURE_DEALLOCATE_CLIENT));
-  mSurface->TakePixmap();
-}
-
-bool
-TextureHostX11::Lock()
-{
-  if (!mCompositor) {
-    return false;
-  }
-
-  if (!mTextureSource) {
-    mTextureSource = new TextureSourceX11(mCompositor, mSurface);
-  }
-
-  return true;
-}
-
-void
-TextureHostX11::SetCompositor(Compositor* aCompositor)
-{
-  BasicCompositor* compositor = static_cast<BasicCompositor*>(aCompositor);
-  mCompositor = compositor;
-  if (mTextureSource) {
-    mTextureSource->SetCompositor(compositor);
-  }
-}
-
-SurfaceFormat
-TextureHostX11::GetFormat() const
-{
-  return ContentTypeToSurfaceFormat(mSurface->GetContentType());
-}
-
-IntSize
-TextureHostX11::GetSize() const
-{
-  return ToIntSize(mSurface->GetSize());
-}
+}
\ No newline at end of file
rename from gfx/layers/basic/TextureHostX11.h
rename to gfx/layers/basic/X11TextureSourceBasic.h
--- a/gfx/layers/basic/TextureHostX11.h
+++ b/gfx/layers/basic/X11TextureSourceBasic.h
@@ -1,76 +1,46 @@
 /* -*- Mode: C++; tab-width: 20; 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/. */
 
-#ifndef MOZILLA_GFX_TEXTUREHOSTX11__H
-#define MOZILLA_GFX_TEXTUREHOSTX11__H
+#ifndef MOZILLA_GFX_X11TEXTURESOURCEBASIC__H
+#define MOZILLA_GFX_X11TEXTURESOURCEBASIC__H
 
 #include "mozilla/layers/TextureHostBasic.h"
 #include "mozilla/gfx/2D.h"
 
 namespace mozilla {
 namespace layers {
 
 class BasicCompositor;
 
 // TextureSource for Xlib-backed surfaces.
-class TextureSourceX11
+class X11TextureSourceBasic
   : public TextureSourceBasic,
     public NewTextureSource
 {
 public:
-  TextureSourceX11(BasicCompositor* aCompositor, gfxXlibSurface* aSurface);
+  X11TextureSourceBasic(BasicCompositor* aCompositor, gfxXlibSurface* aSurface);
 
-  virtual TextureSourceX11* AsSourceBasic() MOZ_OVERRIDE { return this; }
+  virtual X11TextureSourceBasic* AsSourceBasic() MOZ_OVERRIDE { return this; }
 
   virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
   virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
   virtual gfx::SourceSurface* GetSurface() MOZ_OVERRIDE;
 
   virtual void DeallocateDeviceData() MOZ_OVERRIDE { }
 
   virtual void SetCompositor(Compositor* aCompositor);
 
+  static gfx::SurfaceFormat ContentTypeToSurfaceFormat(gfxContentType aType);
+
 protected:
   BasicCompositor* mCompositor;
   RefPtr<gfxXlibSurface> mSurface;
   RefPtr<gfx::SourceSurface> mSourceSurface;
 };
 
-// TextureSource for Xlib-backed TextureSources.
-class TextureHostX11 : public TextureHost
-{
-public:
-  TextureHostX11(TextureFlags aFlags,
-                 const SurfaceDescriptorX11& aDescriptor);
-
-  virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
-  virtual bool Lock() MOZ_OVERRIDE;
-  virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
-  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
-
-  virtual NewTextureSource* GetTextureSources() MOZ_OVERRIDE
-  {
-    return mTextureSource;
-  }
-
-  virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE
-  {
-    return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
-  }
-
-#ifdef MOZ_LAYERS_HAVE_LOG
-  virtual const char* Name() { return "TextureHostX11"; }
-#endif
-
-protected:
-  BasicCompositor* mCompositor;
-  RefPtr<TextureSourceX11> mTextureSource;
-  RefPtr<gfxXlibSurface> mSurface;
-};
-
 } // namespace layers
 } // namespace mozilla
 
-#endif // MOZILLA_GFX_TEXTUREHOSTX11__H
+#endif // MOZILLA_GFX_X11TEXTURESOURCEBASIC__H
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -14,16 +14,19 @@
 #ifdef XP_WIN
 #include "mozilla/layers/TextureD3D9.h"
 #include "mozilla/layers/TextureD3D11.h"
 #include "gfxWindowsPlatform.h"
 #include "gfx2DGlue.h"
 #endif
 #ifdef MOZ_X11
 #include "mozilla/layers/TextureClientX11.h"
+#ifdef GL_PROVIDER_GLX
+#include "GLXLibrary.h"
+#endif
 #endif
 #ifdef MOZ_WIDGET_GONK
 #include <cutils/properties.h>
 #include "mozilla/layers/GrallocTextureClient.h"
 #endif
 
 using namespace mozilla::gfx;
 
@@ -249,22 +252,35 @@ CompositableClient::CreateTextureClientF
     } else {
       result = new CairoTextureClientD3D9(aFormat, aTextureFlags);
     }
   }
 #endif
 
 #ifdef MOZ_X11
   LayersBackend parentBackend = GetForwarder()->GetCompositorBackendType();
+  gfxSurfaceType type =
+    gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
+
   if (parentBackend == LayersBackend::LAYERS_BASIC &&
-      gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType() == gfxSurfaceType::Xlib &&
+      type == gfxSurfaceType::Xlib &&
       !(aTextureFlags & TEXTURE_ALLOC_FALLBACK))
   {
     result = new TextureClientX11(aFormat, aTextureFlags);
   }
+#ifdef GL_PROVIDER_GLX
+  if (parentBackend == LayersBackend::LAYERS_OPENGL &&
+      type == gfxSurfaceType::Xlib &&
+      !(aTextureFlags & TEXTURE_ALLOC_FALLBACK) &&
+      aFormat != SurfaceFormat::A8 &&
+      gl::sGLXLibrary.UseTextureFromPixmap())
+  {
+    result = new TextureClientX11(aFormat, aTextureFlags);
+  }
+#endif
 #endif
 
 #ifdef MOZ_WIDGET_GONK
   if (!DisableGralloc(aFormat)) {
     result = new GrallocTextureClientOGL(this, aFormat, aTextureFlags);
   }
 #endif
 
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -9,16 +9,19 @@
 #include "gfx2DGlue.h"                  // for ToIntSize
 #include "gfxImageSurface.h"            // for gfxImageSurface
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
+#ifdef MOZ_X11
+#include "mozilla/layers/X11TextureHost.h"
+#endif
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "mozilla/layers/PTextureParent.h"
 
 struct nsIntPoint;
 
@@ -178,18 +181,21 @@ TextureHost::Create(const SurfaceDescrip
       return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
     case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface:
       if (Compositor::GetBackend() == LayersBackend::LAYERS_OPENGL) {
         return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
       } else {
         return CreateTextureHostBasic(aDesc, aDeallocator, aFlags);
       }
 #ifdef MOZ_X11
-    case SurfaceDescriptor::TSurfaceDescriptorX11:
-      return CreateTextureHostBasic(aDesc, aDeallocator, aFlags);
+    case SurfaceDescriptor::TSurfaceDescriptorX11: {
+      const SurfaceDescriptorX11& desc = aDesc.get_SurfaceDescriptorX11();
+      RefPtr<TextureHost> result = new X11TextureHost(aFlags, desc);
+      return result;
+    }
 #endif
 #ifdef XP_WIN
     case SurfaceDescriptor::TSurfaceDescriptorD3D9:
     case SurfaceDescriptor::TSurfaceDescriptorDIB:
       return CreateTextureHostD3D9(aDesc, aDeallocator, aFlags);
     case SurfaceDescriptor::TSurfaceDescriptorD3D10:
       return CreateTextureHostD3D11(aDesc, aDeallocator, aFlags);
 #endif
copy from gfx/layers/basic/TextureHostX11.cpp
copy to gfx/layers/composite/X11TextureHost.cpp
--- a/gfx/layers/basic/TextureHostX11.cpp
+++ b/gfx/layers/composite/X11TextureHost.cpp
@@ -1,111 +1,86 @@
 /* -*- Mode: C++; tab-width: 20; 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/. */
 
-#include "TextureHostX11.h"
+#include "X11TextureHost.h"
 #include "mozilla/layers/BasicCompositor.h"
+#include "mozilla/layers/X11TextureSourceBasic.h"
+#ifdef GL_PROVIDER_GLX
+#include "mozilla/layers/CompositorOGL.h"
+#include "mozilla/layers/X11TextureSourceOGL.h"
+#endif
 #include "gfxXlibSurface.h"
 #include "gfx2DGlue.h"
 
 using namespace mozilla;
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
-static inline SurfaceFormat
-ContentTypeToSurfaceFormat(gfxContentType type)
-{
-  switch (type) {
-    case gfxContentType::COLOR:
-      return SurfaceFormat::B8G8R8X8;
-    case gfxContentType::ALPHA:
-      return SurfaceFormat::A8;
-    case gfxContentType::COLOR_ALPHA:
-      return SurfaceFormat::B8G8R8A8;
-    default:
-      return SurfaceFormat::UNKNOWN;
-  }
-}
-
-TextureSourceX11::TextureSourceX11(BasicCompositor* aCompositor, gfxXlibSurface* aSurface)
-  : mCompositor(aCompositor),
-    mSurface(aSurface)
-{
-}
-
-IntSize
-TextureSourceX11::GetSize() const
-{
-  return ToIntSize(mSurface->GetSize());
-}
-
-SurfaceFormat
-TextureSourceX11::GetFormat() const
-{
-  return ContentTypeToSurfaceFormat(mSurface->GetContentType());
-}
-
-SourceSurface*
-TextureSourceX11::GetSurface()
-{
-  if (!mSourceSurface) {
-    mSourceSurface =
-      Factory::CreateSourceSurfaceForCairoSurface(mSurface->CairoSurface(), GetFormat());
-  }
-  return mSourceSurface;
-}
-
-void
-TextureSourceX11::SetCompositor(Compositor* aCompositor)
-{
-  BasicCompositor* compositor = static_cast<BasicCompositor*>(aCompositor);
-  mCompositor = compositor;
-}
-
-TextureHostX11::TextureHostX11(TextureFlags aFlags,
+X11TextureHost::X11TextureHost(TextureFlags aFlags,
                                const SurfaceDescriptorX11& aDescriptor)
  : TextureHost(aFlags)
 {
   nsRefPtr<gfxXlibSurface> surface = aDescriptor.OpenForeign();
   mSurface = surface.get();
 
   // The host always frees the pixmap.
   MOZ_ASSERT(!(aFlags & TEXTURE_DEALLOCATE_CLIENT));
   mSurface->TakePixmap();
 }
 
 bool
-TextureHostX11::Lock()
+X11TextureHost::Lock()
 {
   if (!mCompositor) {
     return false;
   }
 
   if (!mTextureSource) {
-    mTextureSource = new TextureSourceX11(mCompositor, mSurface);
+    switch (mCompositor->GetBackendType()) {
+      case LayersBackend::LAYERS_BASIC:
+        mTextureSource =
+          new X11TextureSourceBasic(static_cast<BasicCompositor*>(mCompositor),
+                                    mSurface);
+        break;
+#ifdef GL_PROVIDER_GLX
+      case LayersBackend::LAYERS_OPENGL:
+        mTextureSource =
+          new X11TextureSourceOGL(static_cast<CompositorOGL*>(mCompositor),
+                                  mSurface);
+        break;
+#endif
+      default:
+        return false;
+    }
   }
 
   return true;
 }
 
 void
-TextureHostX11::SetCompositor(Compositor* aCompositor)
+X11TextureHost::SetCompositor(Compositor* aCompositor)
 {
-  BasicCompositor* compositor = static_cast<BasicCompositor*>(aCompositor);
-  mCompositor = compositor;
+  mCompositor = aCompositor;
   if (mTextureSource) {
-    mTextureSource->SetCompositor(compositor);
+    mTextureSource->SetCompositor(aCompositor);
   }
 }
 
 SurfaceFormat
-TextureHostX11::GetFormat() const
+X11TextureHost::GetFormat() const
 {
-  return ContentTypeToSurfaceFormat(mSurface->GetContentType());
+  gfxContentType type = mSurface->GetContentType();
+#ifdef GL_PROVIDER_GLX
+  if (mCompositor->GetBackendType() == LayersBackend::LAYERS_OPENGL) {
+    return X11TextureSourceOGL::ContentTypeToSurfaceFormat(type);
+  }
+#endif
+  return X11TextureSourceBasic::ContentTypeToSurfaceFormat(type);
 }
 
 IntSize
-TextureHostX11::GetSize() const
+X11TextureHost::GetSize() const
 {
   return ToIntSize(mSurface->GetSize());
 }
copy from gfx/layers/basic/TextureHostX11.h
copy to gfx/layers/composite/X11TextureHost.h
--- a/gfx/layers/basic/TextureHostX11.h
+++ b/gfx/layers/composite/X11TextureHost.h
@@ -1,53 +1,30 @@
 /* -*- Mode: C++; tab-width: 20; 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/. */
 
-#ifndef MOZILLA_GFX_TEXTUREHOSTX11__H
-#define MOZILLA_GFX_TEXTUREHOSTX11__H
+#ifndef MOZILLA_GFX_X11TEXTUREHOST__H
+#define MOZILLA_GFX_X11TEXTUREHOST__H
 
-#include "mozilla/layers/TextureHostBasic.h"
+#include "mozilla/layers/TextureHost.h"
+#include "mozilla/layers/LayersSurfaces.h"
 #include "mozilla/gfx/2D.h"
 
+class gfxXlibSurface;
+
 namespace mozilla {
 namespace layers {
 
-class BasicCompositor;
-
-// TextureSource for Xlib-backed surfaces.
-class TextureSourceX11
-  : public TextureSourceBasic,
-    public NewTextureSource
+// TextureSource for Xlib-backed TextureSources.
+class X11TextureHost : public TextureHost
 {
 public:
-  TextureSourceX11(BasicCompositor* aCompositor, gfxXlibSurface* aSurface);
-
-  virtual TextureSourceX11* AsSourceBasic() MOZ_OVERRIDE { return this; }
-
-  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
-  virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
-  virtual gfx::SourceSurface* GetSurface() MOZ_OVERRIDE;
-
-  virtual void DeallocateDeviceData() MOZ_OVERRIDE { }
-
-  virtual void SetCompositor(Compositor* aCompositor);
-
-protected:
-  BasicCompositor* mCompositor;
-  RefPtr<gfxXlibSurface> mSurface;
-  RefPtr<gfx::SourceSurface> mSourceSurface;
-};
-
-// TextureSource for Xlib-backed TextureSources.
-class TextureHostX11 : public TextureHost
-{
-public:
-  TextureHostX11(TextureFlags aFlags,
+  X11TextureHost(TextureFlags aFlags,
                  const SurfaceDescriptorX11& aDescriptor);
 
   virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
   virtual bool Lock() MOZ_OVERRIDE;
   virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
   virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
 
   virtual NewTextureSource* GetTextureSources() MOZ_OVERRIDE
@@ -56,21 +33,21 @@ public:
   }
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE
   {
     return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
   }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
-  virtual const char* Name() { return "TextureHostX11"; }
+  virtual const char* Name() { return "X11TextureHost"; }
 #endif
 
 protected:
-  BasicCompositor* mCompositor;
-  RefPtr<TextureSourceX11> mTextureSource;
+  Compositor* mCompositor;
+  RefPtr<NewTextureSource> mTextureSource;
   RefPtr<gfxXlibSurface> mSurface;
 };
 
 } // namespace layers
 } // namespace mozilla
 
-#endif // MOZILLA_GFX_TEXTUREHOSTX11__H
+#endif // MOZILLA_GFX_X11TEXTUREHOST__H
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp
+++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp
@@ -33,25 +33,16 @@
 
 using namespace std;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
-typedef HRESULT (WINAPI*D3D10CreateEffectFromMemoryFunc)(
-    void *pData,
-    SIZE_T DataLength,
-    UINT FXFlags,
-    ID3D10Device *pDevice, 
-    ID3D10EffectPool *pEffectPool,
-    ID3D10Effect **ppEffect
-);
-
 struct Vertex
 {
     float position[2];
 };
 
 // {592BF306-0EED-4F76-9D03-A0846450F472}
 static const GUID sDeviceAttachments = 
 { 0x592bf306, 0xeed, 0x4f76, { 0x9d, 0x3, 0xa0, 0x84, 0x64, 0x50, 0xf4, 0x72 } };
@@ -154,18 +145,19 @@ LayerManagerD3D10::Initialize(bool force
 
   DeviceAttachments *attachments;
   size = sizeof(DeviceAttachments*);
   if (FAILED(mDevice->GetPrivateData(sDeviceAttachments, &size, &attachments))) {
     attachments = new DeviceAttachments;
     mDevice->SetPrivateData(sDeviceAttachments, sizeof(attachments), &attachments);
 
     SetLastError(0);
-    D3D10CreateEffectFromMemoryFunc createEffect = (D3D10CreateEffectFromMemoryFunc)
-      GetProcAddress(LoadLibraryA("d3d10_1.dll"), "D3D10CreateEffectFromMemory");
+    decltype(D3D10CreateEffectFromMemory)* createEffect =
+      (decltype(D3D10CreateEffectFromMemory)*)
+        GetProcAddress(LoadLibraryA("d3d10_1.dll"), "D3D10CreateEffectFromMemory");
     if (!createEffect) {
       SetHRESULT(aHresultPtr, HRESULT_FROM_WIN32(GetLastError()));
       return false;
     }
 
     hr = createEffect((void*)g_main,
                       sizeof(g_main),
                       D3D10_EFFECT_SINGLE_THREADED,
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -131,16 +131,20 @@ public:
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE { return true; }
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "Direct3D 11"; }
 #endif
 
+  virtual LayersBackend GetBackendType() const MOZ_OVERRIDE {
+    return LayersBackend::LAYERS_D3D11;
+  }
+
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   ID3D11Device* GetDevice() { return mDevice; }
 
 private:
   // ensure mSize is up to date with respect to mWidget
   void EnsureSize();
   void VerifyBufferSize();
--- a/gfx/layers/d3d9/CompositorD3D9.h
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -78,16 +78,20 @@ public:
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE{ return true; }
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "Direct3D9"; }
 #endif
 
+  virtual LayersBackend GetBackendType() const MOZ_OVERRIDE {
+    return LayersBackend::LAYERS_D3D9;
+  }
+
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   IDirect3DDevice9* device() const
   {
     return mDeviceManager
            ? mDeviceManager->device()
            : nullptr;
   }
--- a/gfx/layers/d3d9/DeviceManagerD3D9.cpp
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.cpp
@@ -22,25 +22,16 @@ using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 const LPCWSTR kClassName       = L"D3D9WindowClass";
 
 #define USE_D3D9EX
 
-typedef IDirect3D9* (WINAPI*Direct3DCreate9Func)(
-  UINT SDKVersion
-);
-
-typedef HRESULT (WINAPI*Direct3DCreate9ExFunc)(
-  UINT SDKVersion,
-  IDirect3D9Ex **ppD3D
-);
-
 struct vertex {
   float x, y;
 };
 
 SwapChainD3D9::SwapChainD3D9(DeviceManagerD3D9 *aDeviceManager)
   : mDeviceManager(aDeviceManager)
   , mWnd(0)
 {
@@ -219,21 +210,21 @@ DeviceManagerD3D9::Init()
   } 
 
   /* Initialize the Nv3DVUtils object */ 
   if (mNv3DVUtils) { 
     mNv3DVUtils->Initialize(); 
   } 
 
   HMODULE d3d9 = LoadLibraryW(L"d3d9.dll");
-  Direct3DCreate9Func d3d9Create = (Direct3DCreate9Func)
+  decltype(Direct3DCreate9)* d3d9Create = (decltype(Direct3DCreate9)*)
     GetProcAddress(d3d9, "Direct3DCreate9");
-  Direct3DCreate9ExFunc d3d9CreateEx = (Direct3DCreate9ExFunc)
+  decltype(Direct3DCreate9Ex)* d3d9CreateEx = (decltype(Direct3DCreate9Ex)*)
     GetProcAddress(d3d9, "Direct3DCreate9Ex");
-  
+
 #ifdef USE_D3D9EX
   if (d3d9CreateEx) {
     hr = d3d9CreateEx(D3D_SDK_VERSION, getter_AddRefs(mD3D9Ex));
     if (SUCCEEDED(hr)) {
       mD3D9 = mD3D9Ex;
     }
   }
 #endif
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -153,23 +153,27 @@ EXPORTS.mozilla.layers += [
     'opengl/TextureHostOGL.h',
     'RenderTrace.h',
     'YCbCrImageDataSerializer.h',
 ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS.mozilla.layers += [
         'basic/TextureClientX11.h',
-        'basic/TextureHostX11.h',
+        'basic/X11TextureSourceBasic.h',
+        'composite/X11TextureHost.h',
         'ipc/ShadowLayerUtilsX11.h',
+        'opengl/X11TextureSourceOGL.h',
     ]
     SOURCES += [
         'basic/TextureClientX11.cpp',
-        'basic/TextureHostX11.cpp',
-        'ipc/ShadowLayerUtilsX11.cpp'
+        'basic/X11TextureSourceBasic.cpp',
+        'composite/X11TextureHost.cpp',
+        'ipc/ShadowLayerUtilsX11.cpp',
+        'opengl/X11TextureSourceOGL.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     EXPORTS.mozilla.layers += [
         'opengl/GLManager.h',
     ]
     EXPORTS += [
         'MacIOSurfaceImage.h',
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -145,16 +145,20 @@ public:
   virtual void PrepareViewport(const gfx::IntSize& aSize,
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE;
 
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "OGL"; }
 #endif // MOZ_DUMP_PAINTING
 
+  virtual LayersBackend GetBackendType() const MOZ_OVERRIDE {
+    return LayersBackend::LAYERS_OPENGL;
+  }
+
   virtual void Pause() MOZ_OVERRIDE;
   virtual bool Resume() MOZ_OVERRIDE;
 
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   GLContext* gl() const { return mGLContext; }
   ShaderProgramType GetFBOLayerProgramType() const {
     return mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB ?
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
@@ -6,16 +6,65 @@
 #include "MacIOSurfaceTextureHostOGL.h"
 #include "mozilla/gfx/MacIOSurface.h"
 #include "mozilla/layers/CompositorOGL.h"
 #include "GLContextCGL.h"
 
 namespace mozilla {
 namespace layers {
 
+MacIOSurfaceTextureHostOGL::MacIOSurfaceTextureHostOGL(TextureFlags aFlags,
+                                                       const SurfaceDescriptorMacIOSurface& aDescriptor)
+  : TextureHost(aFlags)
+{
+  mSurface = MacIOSurface::LookupSurface(aDescriptor.surface(),
+                                         aDescriptor.scaleFactor(),
+                                         aDescriptor.hasAlpha());
+}
+
+bool
+MacIOSurfaceTextureHostOGL::Lock()
+{
+  if (!mCompositor || !mSurface) {
+    return false;
+  }
+
+  if (!mTextureSource) {
+    mTextureSource = new MacIOSurfaceTextureSourceOGL(mCompositor, mSurface);
+  }
+  return true;
+}
+
+void
+MacIOSurfaceTextureHostOGL::SetCompositor(Compositor* aCompositor)
+{
+  CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
+  mCompositor = glCompositor;
+  if (mTextureSource) {
+    mTextureSource->SetCompositor(glCompositor);
+  }
+}
+
+gfx::SurfaceFormat
+MacIOSurfaceTextureHostOGL::GetFormat() const {
+  if (!mSurface) {
+    return gfx::SurfaceFormat::UNKNOWN;
+  }
+  return mSurface->HasAlpha() ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::B8G8R8X8;
+}
+
+gfx::IntSize
+MacIOSurfaceTextureHostOGL::GetSize() const {
+  if (!mSurface) {
+    return gfx::IntSize();
+  }
+  return gfx::IntSize(mSurface->GetDevicePixelWidth(),
+                      mSurface->GetDevicePixelHeight());
+}
+
 MacIOSurfaceTextureSourceOGL::MacIOSurfaceTextureSourceOGL(
                                 CompositorOGL* aCompositor,
                                 MacIOSurface* aSurface)
   : mCompositor(aCompositor)
   , mSurface(aSurface)
 {}
 
 MacIOSurfaceTextureSourceOGL::~MacIOSurfaceTextureSourceOGL()
@@ -29,48 +78,16 @@ MacIOSurfaceTextureSourceOGL::GetSize() 
 }
 
 gfx::SurfaceFormat
 MacIOSurfaceTextureSourceOGL::GetFormat() const
 {
   return mSurface->HasAlpha() ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::B8G8R8X8;
 }
 
-MacIOSurfaceTextureHostOGL::MacIOSurfaceTextureHostOGL(TextureFlags aFlags,
-                                                       const SurfaceDescriptorMacIOSurface& aDescriptor)
-  : TextureHost(aFlags)
-{
-  mSurface = MacIOSurface::LookupSurface(aDescriptor.surface(),
-                                         aDescriptor.scaleFactor(),
-                                         aDescriptor.hasAlpha());
-}
-
-bool
-MacIOSurfaceTextureHostOGL::Lock()
-{
-  if (!mCompositor) {
-    return false;
-  }
-
-  if (!mTextureSource) {
-    mTextureSource = new MacIOSurfaceTextureSourceOGL(mCompositor, mSurface);
-  }
-  return true;
-}
-
-void
-MacIOSurfaceTextureHostOGL::SetCompositor(Compositor* aCompositor)
-{
-  CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
-  mCompositor = glCompositor;
-  if (mTextureSource) {
-    mTextureSource->SetCompositor(glCompositor);
-  }
-}
-
 void
 MacIOSurfaceTextureSourceOGL::BindTexture(GLenum aTextureUnit)
 {
   if (!gl()) {
     NS_WARNING("Trying to bind a texture without a GLContext");
     return;
   }
   GLuint tex = mCompositor->GetTemporaryTexture(aTextureUnit);
@@ -88,21 +105,10 @@ MacIOSurfaceTextureSourceOGL::SetComposi
 }
 
 gl::GLContext*
 MacIOSurfaceTextureSourceOGL::gl() const
 {
   return mCompositor ? mCompositor->gl() : nullptr;
 }
 
-gfx::SurfaceFormat
-MacIOSurfaceTextureHostOGL::GetFormat() const {
-  return mSurface->HasAlpha() ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::B8G8R8X8;
-}
-
-gfx::IntSize
-MacIOSurfaceTextureHostOGL::GetSize() const {
-  return gfx::IntSize(mSurface->GetDevicePixelWidth(),
-                      mSurface->GetDevicePixelHeight());
-}
-
 }
 }
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/X11TextureSourceOGL.cpp
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 20; 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 GL_PROVIDER_GLX
+
+#include "X11TextureSourceOGL.h"
+#include "mozilla/layers/CompositorOGL.h"
+#include "gfxXlibSurface.h"
+#include "gfx2DGlue.h"
+
+using namespace mozilla;
+using namespace mozilla::layers;
+using namespace mozilla::gfx;
+
+X11TextureSourceOGL::X11TextureSourceOGL(CompositorOGL* aCompositor, gfxXlibSurface* aSurface)
+  : mCompositor(aCompositor),
+    mSurface(aSurface)
+{
+}
+
+void
+X11TextureSourceOGL::BindTexture(GLenum aTextureUnit)
+{
+  GLuint tex = mCompositor->GetTemporaryTexture(aTextureUnit);
+
+  gl()->fActiveTexture(aTextureUnit);
+  gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, tex);
+
+  gl::sGLXLibrary.xBindTexImage(mSurface->XDisplay(), mSurface->GetGLXPixmap(),
+                                LOCAL_GLX_FRONT_LEFT_EXT, NULL);
+
+  gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
+  gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
+
+  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+}
+
+IntSize
+X11TextureSourceOGL::GetSize() const
+{
+  return ToIntSize(mSurface->GetSize());
+}
+
+SurfaceFormat
+X11TextureSourceOGL::GetFormat() const {
+  gfxContentType type = mSurface->GetContentType();
+  return X11TextureSourceOGL::ContentTypeToSurfaceFormat(type);
+}
+
+void
+X11TextureSourceOGL::SetCompositor(Compositor* aCompositor)
+{
+  MOZ_ASSERT(aCompositor->GetBackendType() == LayersBackend::LAYERS_OPENGL);
+  mCompositor = static_cast<CompositorOGL*>(aCompositor);
+}
+
+gl::GLContext*
+X11TextureSourceOGL::gl() const
+{
+  return mCompositor ? mCompositor->gl() : nullptr;
+}
+
+SurfaceFormat
+X11TextureSourceOGL::ContentTypeToSurfaceFormat(gfxContentType aType)
+{
+  // X11 uses a switched format and the OGL compositor
+  // doesn't support ALPHA / A8.
+  switch (aType) {
+    case gfxContentType::COLOR:
+      return SurfaceFormat::R8G8B8X8;
+    case gfxContentType::COLOR_ALPHA:
+      return SurfaceFormat::R8G8B8A8;
+    default:
+      return SurfaceFormat::UNKNOWN;
+  }
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/X11TextureSourceOGL.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 20; 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/. */
+
+#ifndef MOZILLA_GFX_X11TEXTURESOURCEOGL__H
+#define MOZILLA_GFX_X11TEXTURESOURCEOGL__H
+
+#ifdef GL_PROVIDER_GLX
+
+#include "mozilla/layers/TextureHostOGL.h"
+#include "mozilla/gfx/2D.h"
+
+namespace mozilla {
+namespace layers {
+
+// TextureSource for Xlib-backed surfaces.
+class X11TextureSourceOGL
+  : public TextureSourceOGL,
+    public NewTextureSource
+{
+public:
+  X11TextureSourceOGL(CompositorOGL* aCompositor, gfxXlibSurface* aSurface);
+
+  virtual X11TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE { return this; }
+
+  virtual bool IsValid() const MOZ_OVERRIDE { return !!gl(); } ;
+  virtual void BindTexture(GLenum aTextureUnit) MOZ_OVERRIDE;
+  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
+  virtual GLenum GetTextureTarget() const MOZ_OVERRIDE {
+    return LOCAL_GL_TEXTURE_2D;
+  }
+  virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
+  virtual GLenum GetWrapMode() const MOZ_OVERRIDE {
+     return LOCAL_GL_CLAMP_TO_EDGE;
+  }
+
+  virtual void DeallocateDeviceData() MOZ_OVERRIDE { }
+
+  virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
+
+  gl::GLContext* gl() const;
+  static gfx::SurfaceFormat ContentTypeToSurfaceFormat(gfxContentType aType);
+
+protected:
+  CompositorOGL* mCompositor;
+  RefPtr<gfxXlibSurface> mSurface;
+  RefPtr<gfx::SourceSurface> mSourceSurface;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
+
+#endif // MOZILLA_GFX_X11TEXTURESOURCEOGL__H
\ No newline at end of file
--- a/gfx/thebes/gfxFT2Utils.cpp
+++ b/gfx/thebes/gfxFT2Utils.cpp
@@ -89,25 +89,25 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
         //
         // FT_Size_Metrics::y_scale is in 16.16 fixed point format.  Its
         // (fractional) value is a factor that converts vertical metrics from
         // design units to units of 1/64 pixels, so that the result may be
         // interpreted as pixels in 26.6 fixed point format.
         yScale = FLOAT_FROM_26_6(FLOAT_FROM_16_16(ftMetrics.y_scale));
         emHeight = mFace->units_per_EM * yScale;
     } else { // Not scalable.
+        emHeight = ftMetrics.y_ppem;
         // FT_Face doc says units_per_EM and a bunch of following fields
         // are "only relevant to scalable outlines". If it's an sfnt,
         // we can get units_per_EM from the 'head' table instead; otherwise,
         // we don't have a unitsPerEm value so we can't compute/use yScale.
         const TT_Header* head =
             static_cast<TT_Header*>(FT_Get_Sfnt_Table(mFace, ft_sfnt_head));
         if (head) {
             gfxFloat emUnit = head->Units_Per_EM;
-            emHeight = ftMetrics.y_ppem;
             yScale = emHeight / emUnit;
         }
     }
 
     TT_OS2 *os2 =
         static_cast<TT_OS2*>(FT_Get_Sfnt_Table(mFace, ft_sfnt_os2));
 
     aMetrics->maxAscent = FLOAT_FROM_26_6(ftMetrics.ascender);
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -168,56 +168,16 @@ NS_IMPL_ISUPPORTS1(GfxD2DVramReporter, n
 
 #define GFX_CLEARTYPE_PARAMS           "gfx.font_rendering.cleartype_params."
 #define GFX_CLEARTYPE_PARAMS_GAMMA     "gfx.font_rendering.cleartype_params.gamma"
 #define GFX_CLEARTYPE_PARAMS_CONTRAST  "gfx.font_rendering.cleartype_params.enhanced_contrast"
 #define GFX_CLEARTYPE_PARAMS_LEVEL     "gfx.font_rendering.cleartype_params.cleartype_level"
 #define GFX_CLEARTYPE_PARAMS_STRUCTURE "gfx.font_rendering.cleartype_params.pixel_structure"
 #define GFX_CLEARTYPE_PARAMS_MODE      "gfx.font_rendering.cleartype_params.rendering_mode"
 
-#ifdef CAIRO_HAS_DWRITE_FONT
-// DirectWrite is not available on all platforms, we need to use the function
-// pointer.
-typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)(
-  DWRITE_FACTORY_TYPE factoryType,
-  REFIID iid,
-  IUnknown **factory
-);
-#endif
-
-#ifdef CAIRO_HAS_D2D_SURFACE
-typedef HRESULT (WINAPI*D3D10CreateDevice1Func)(
-  IDXGIAdapter *pAdapter,
-  D3D10_DRIVER_TYPE DriverType,
-  HMODULE Software,
-  UINT Flags,
-  D3D10_FEATURE_LEVEL1 HardwareLevel,
-  UINT SDKVersion,
-  ID3D10Device1 **ppDevice
-);
-#endif
-
-typedef HRESULT(WINAPI*CreateDXGIFactory1Func)(
-  REFIID riid,
-  void **ppFactory
-);
-
-typedef HRESULT (WINAPI*D3D11CreateDeviceFunc)(
-  IDXGIAdapter *pAdapter,
-  D3D_DRIVER_TYPE DriverType,
-  HMODULE Software,
-  UINT Flags,
-  D3D_FEATURE_LEVEL *pFeatureLevels,
-  UINT FeatureLevels,
-  UINT SDKVersion,
-  ID3D11Device **ppDevice,
-  D3D_FEATURE_LEVEL *pFeatureLevel,
-  ID3D11DeviceContext *ppImmediateContext
-);
-
 class GPUAdapterReporter : public nsIMemoryReporter
 {
     // Callers must Release the DXGIAdapter after use or risk mem-leak
     static bool GetDXGIAdapter(IDXGIAdapter **DXGIAdapter)
     {
         ID3D10Device1 *D2D10Device;
         IDXGIDevice *DXGIDevice;
         bool result = false;
@@ -461,17 +421,17 @@ gfxWindowsPlatform::UpdateRenderMode()
     }
 #endif
 
 #ifdef CAIRO_HAS_DWRITE_FONT
     // Enable when it's preffed on -and- we're using Vista or higher. Or when
     // we're going to use D2D.
     if (!mDWriteFactory && (mUseDirectWrite && isVistaOrHigher)) {
         mozilla::ScopedGfxFeatureReporter reporter("DWrite");
-        DWriteCreateFactoryFunc createDWriteFactory = (DWriteCreateFactoryFunc)
+        decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
             GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory");
 
         if (createDWriteFactory) {
             /**
              * I need a direct pointer to be able to cast to IUnknown**, I also
              * need to remember to release this because the nsRefPtr will
              * AddRef it.
              */
@@ -513,18 +473,18 @@ gfxWindowsPlatform::UpdateRenderMode()
 #ifdef CAIRO_HAS_D2D_SURFACE
 HRESULT
 gfxWindowsPlatform::CreateDevice(nsRefPtr<IDXGIAdapter1> &adapter1,
                                  int featureLevelIndex)
 {
   nsModuleHandle d3d10module(LoadLibrarySystem32(L"d3d10_1.dll"));
   if (!d3d10module)
     return E_FAIL;
-  D3D10CreateDevice1Func createD3DDevice =
-    (D3D10CreateDevice1Func)GetProcAddress(d3d10module, "D3D10CreateDevice1");
+  decltype(D3D10CreateDevice1)* createD3DDevice =
+    (decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module, "D3D10CreateDevice1");
   if (!createD3DDevice)
     return E_FAIL;
 
   nsRefPtr<ID3D10Device1> device;
   HRESULT hr =
     createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
                     D3D10_CREATE_DEVICE_BGRA_SUPPORT |
                     D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
@@ -1455,17 +1415,17 @@ gfxWindowsPlatform::GetD3D11Device()
 {
   if (mD3D11DeviceInitialized) {
     return mD3D11Device;
   }
 
   mD3D11DeviceInitialized = true;
 
   nsModuleHandle d3d11Module(LoadLibrarySystem32(L"d3d11.dll"));
-  D3D11CreateDeviceFunc d3d11CreateDevice = (D3D11CreateDeviceFunc)
+  decltype(D3D11CreateDevice)* d3d11CreateDevice = (decltype(D3D11CreateDevice)*)
     GetProcAddress(d3d11Module, "D3D11CreateDevice");
 
   if (!d3d11CreateDevice) {
     return nullptr;
   }
 
   nsTArray<D3D_FEATURE_LEVEL> featureLevels;
   if (IsWin8OrLater()) {
@@ -1523,17 +1483,17 @@ gfxWindowsPlatform::GetScreenDepth() con
 IDXGIAdapter1*
 gfxWindowsPlatform::GetDXGIAdapter()
 {
   if (mAdapter) {
     return mAdapter;
   }
 
   nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll"));
-  CreateDXGIFactory1Func createDXGIFactory1 = (CreateDXGIFactory1Func)
+  decltype(CreateDXGIFactory1)* createDXGIFactory1 = (decltype(CreateDXGIFactory1)*)
     GetProcAddress(dxgiModule, "CreateDXGIFactory1");
 
   // Try to use a DXGI 1.1 adapter in order to share resources
   // across processes.
   if (createDXGIFactory1) {
     nsRefPtr<IDXGIFactory1> factory1;
     HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1),
                                     getter_AddRefs(factory1));
--- a/hal/windows/WindowsBattery.cpp
+++ b/hal/windows/WindowsBattery.cpp
@@ -16,20 +16,18 @@
 using namespace mozilla::dom::battery;
 
 namespace mozilla {
 namespace hal_impl {
 
 static nsCOMPtr<nsITimer> sUpdateTimer;
 
 /* Power Event API is Vista or later */
-typedef HPOWERNOTIFY (WINAPI *REGISTERPOWERSETTINGNOTIFICATION) (HANDLE, LPCGUID, DWORD);
-typedef BOOL (WINAPI *UNREGISTERPOWERSETTINGNOTIFICATION) (HPOWERNOTIFY);
-static REGISTERPOWERSETTINGNOTIFICATION sRegisterPowerSettingNotification = nullptr;
-static UNREGISTERPOWERSETTINGNOTIFICATION sUnregisterPowerSettingNotification = nullptr;
+static decltype(RegisterPowerSettingNotification)* sRegisterPowerSettingNotification = nullptr;
+static decltype(UnregisterPowerSettingNotification)* sUnregisterPowerSettingNotification = nullptr;
 static HPOWERNOTIFY sPowerHandle = nullptr;
 static HPOWERNOTIFY sCapacityHandle = nullptr;
 static HWND sHWnd = nullptr;
 
 static void
 UpdateHandler(nsITimer* aTimer, void* aClosure) {
   NS_ASSERTION(!IsVistaOrLater(),
                "We shouldn't call this function for Vista or later version!");
@@ -65,20 +63,20 @@ BatteryWindowProc(HWND hwnd, UINT msg, W
 void
 EnableBatteryNotifications()
 {
   if (IsVistaOrLater()) {
     // RegisterPowerSettingNotification is from Vista or later.
     // Use this API if available.
     HMODULE hUser32 = GetModuleHandleW(L"USER32.DLL");
     if (!sRegisterPowerSettingNotification)
-      sRegisterPowerSettingNotification = (REGISTERPOWERSETTINGNOTIFICATION)
+      sRegisterPowerSettingNotification = (decltype(RegisterPowerSettingNotification)*)
         GetProcAddress(hUser32, "RegisterPowerSettingNotification");
     if (!sUnregisterPowerSettingNotification)
-      sUnregisterPowerSettingNotification = (UNREGISTERPOWERSETTINGNOTIFICATION)
+      sUnregisterPowerSettingNotification = (decltype(UnregisterPowerSettingNotification)*)
         GetProcAddress(hUser32, "UnregisterPowerSettingNotification");
 
     if (!sRegisterPowerSettingNotification ||
         !sUnregisterPowerSettingNotification) {
       NS_ASSERTION(false, "Canot find PowerSettingNotification functions.");
       return;
     }
 
--- a/image/decoders/icon/win/nsIconChannel.cpp
+++ b/image/decoders/icon/win/nsIconChannel.cpp
@@ -50,18 +50,16 @@ struct ICONENTRY {
   uint8_t ieColors;
   uint8_t ieReserved;
   uint16_t iePlanes;
   uint16_t ieBitCount;
   uint32_t ieSizeImage;
   uint32_t ieFileOffset;
 };
 
-typedef HRESULT (WINAPI*SHGetStockIconInfoPtr) (SHSTOCKICONID siid, UINT uFlags, SHSTOCKICONINFO *psii);
-
 // Match stock icons with names
 static SHSTOCKICONID GetStockIconIDForName(const nsACString &aStockName)
 {
   // UAC shield icon
   if (aStockName == NS_LITERAL_CSTRING("uac-shield"))
     return SIID_SHIELD;
 
   return SIID_INVALID;
@@ -344,18 +342,18 @@ nsresult nsIconChannel::GetHIconFromFile
 }
 
 nsresult nsIconChannel::GetStockHIcon(nsIMozIconURI *aIconURI, HICON *hIcon)
 {
   nsresult rv = NS_OK;
 
   // We can only do this on Vista or above
   HMODULE hShellDLL = ::LoadLibraryW(L"shell32.dll");
-  SHGetStockIconInfoPtr pSHGetStockIconInfo =
-    (SHGetStockIconInfoPtr) ::GetProcAddress(hShellDLL, "SHGetStockIconInfo");
+  decltype(SHGetStockIconInfo)* pSHGetStockIconInfo =
+    (decltype(SHGetStockIconInfo)*) ::GetProcAddress(hShellDLL, "SHGetStockIconInfo");
 
   if (pSHGetStockIconInfo)
   {
     uint32_t desiredImageSize;
     aIconURI->GetImageSize(&desiredImageSize);
     nsAutoCString stockIcon;
     aIconURI->GetStockIcon(stockIcon);
 
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -141,21 +141,23 @@ class JS_FRIEND_API(BaseProxyHandler)
      * may still decide to squelch the error).
      *
      * We make these OR-able so that assertEnteredPolicy can pass a union of them.
      * For example, get{,Own}PropertyDescriptor is invoked by both calls to ::get()
      * and ::set() (since we need to look up the accessor), so its
      * assertEnteredPolicy would pass GET | SET.
      */
     typedef uint32_t Action;
-    static const Action NONE = 0x00;
-    static const Action GET  = 0x01;
-    static const Action SET  = 0x02;
-    static const Action CALL = 0x04;
-    static const Action ENUMERATE = 0x08;
+    enum {
+        NONE      = 0x00,
+        GET       = 0x01,
+        SET       = 0x02,
+        CALL      = 0x04,
+        ENUMERATE = 0x08
+    };
 
     virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act,
                        bool *bp);
 
     /* ES5 Harmony fundamental proxy traps. */
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy) = 0;
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc,
--- a/js/src/tests/lib/jittests.py
+++ b/js/src/tests/lib/jittests.py
@@ -366,37 +366,42 @@ def check_output(out, err, rc, test):
         # 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:
-    # TEST-PASS | /foo/bar/baz.js | --ion-eager
-    # TEST-UNEXPECTED-FAIL | /foo/bar/baz.js | --no-ion: Assertion failure: ...
+    # TEST-RESULT | filename.js | Failure description (code N, args "--foobar")
+    #
+    # Example:
+    # TEST-PASS | foo/bar/baz.js | (code 0, args "--ion-eager")
+    # TEST-UNEXPECTED-FAIL | foo/bar/baz.js | TypeError: or something (code -9, args "--no-ion")
     # INFO exit-status     : 3
     # INFO timed-out       : False
     # INFO stdout          > foo
     # INFO stdout          > bar
     # INFO stdout          > baz
     # INFO stderr         2> TypeError: or something
     # TEST-UNEXPECTED-FAIL | jit_test.py: Test execution interrupted by user
-    label = "TEST-PASS" if ok else "TEST-UNEXPECTED-FAIL"
+    result = "TEST-PASS" if ok else "TEST-UNEXPECTED-FAIL"
+    message = "Success" if ok else res.describe_failure()
     jitflags = " ".join(res.test.jitflags)
-    print("%s | %s | %s" % (label, res.test.relpath_top, jitflags))
+    print("{} | {} | {} (code {}, args \"{}\")".format(
+          result, res.test.relpath_top, message, res.rc, jitflags))
+
+    # For failed tests, print as much information as we have, to aid debugging.
     if ok:
         return
-
-    # For failed tests, print as much information as we have, to aid debugging.
     print("INFO exit-status     : {}".format(res.rc))
     print("INFO timed-out       : {}".format(res.timed_out))
-    for line in res.out.split('\n'):
+    for line in res.out.splitlines():
         print("INFO stdout          > " + line.strip())
-    for line in res.err.split('\n'):
+    for line in res.err.splitlines():
         print("INFO stderr         2> " + line.strip())
 
 def wrap_parallel_run_test(test, prefix, resultQueue, options):
     # Ignore SIGINT in the child
     signal.signal(signal.SIGINT, signal.SIG_IGN)
     result = run_test(test, prefix, options)
     resultQueue.put(result)
     return result
--- a/js/src/tests/lib/results.py
+++ b/js/src/tests/lib/results.py
@@ -12,16 +12,26 @@ class TestOutput:
         self.test = test   # Test
         self.cmd = cmd     # str:   command line of test
         self.out = out     # str:   stdout
         self.err = err     # str:   stderr
         self.rc = rc       # int:   return code
         self.dt = dt       # float: run time
         self.timed_out = timed_out # bool: did the test time out
 
+    def describe_failure(self):
+        if self.timed_out:
+            return "Timeout"
+        lines = self.err.splitlines()
+        for line in lines:
+            # Skip the asm.js compilation success message.
+            if "Successfully compiled asm.js code" not in line:
+                return line
+        return "Unknown"
+
 class NullTestOutput:
     """Variant of TestOutput that indicates a test was not run."""
     def __init__(self, test):
         self.test = test
         self.cmd = ''
         self.out = ''
         self.err = ''
         self.rc = 0
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -10097,24 +10097,30 @@ nsCSSFrameConstructor::RemoveFloatingFir
   // Remove placeholder frame and the float
   RemoveFrame(kPrincipalList, placeholderFrame);
 
   // Now that the old frames are gone, we can start pointing to our
   // new primary frame.
   textContent->SetPrimaryFrame(newTextFrame);
 
   // Wallpaper bug 822910.
-  if (prevSibling && prevSibling->GetType() == nsGkAtoms::textFrame) {
-    prevSibling->AddStateBits(NS_FRAME_IS_DIRTY);
+  bool offsetsNeedFixing =
+    prevSibling && prevSibling->GetType() == nsGkAtoms::textFrame;
+  if (offsetsNeedFixing) {
+    prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
   }
 
   // Insert text frame in its place
   nsFrameList textList(newTextFrame, newTextFrame);
   InsertFrames(parentFrame, kPrincipalList, prevSibling, textList);
 
+  if (offsetsNeedFixing) {
+    prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
+  }
+
   return NS_OK;
 }
 
 nsresult
 nsCSSFrameConstructor::RemoveFirstLetterFrames(nsPresContext* aPresContext,
                                                nsIPresShell* aPresShell,
                                                nsIFrame* aFrame,
                                                nsIFrame* aBlockFrame,
@@ -10148,24 +10154,30 @@ nsCSSFrameConstructor::RemoveFirstLetter
       // Next rip out the kid and replace it with the text frame
       RemoveFrame(kPrincipalList, kid);
 
       // Now that the old frames are gone, we can start pointing to our
       // new primary frame.
       textContent->SetPrimaryFrame(textFrame);
 
       // Wallpaper bug 822910.
-      if (prevSibling && prevSibling->GetType() == nsGkAtoms::textFrame) {
-        prevSibling->AddStateBits(NS_FRAME_IS_DIRTY);
+      bool offsetsNeedFixing =
+        prevSibling && prevSibling->GetType() == nsGkAtoms::textFrame;
+      if (offsetsNeedFixing) {
+        prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
       }
 
       // Insert text frame in its place
       nsFrameList textList(textFrame, textFrame);
       InsertFrames(aFrame, kPrincipalList, prevSibling, textList);
 
+      if (offsetsNeedFixing) {
+        prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
+      }
+
       *aStopLooking = true;
       NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
                    "should have the first continuation here");
       aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
       break;
     }
     else if (IsInlineFrame(kid)) {
       // Look inside child inline frame for the letter frame
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -4772,19 +4772,19 @@ nsBlockFrame::InsertFrames(ChildListID a
 
 static bool
 ShouldPutNextSiblingOnNewLine(nsIFrame* aLastFrame)
 {
   nsIAtom* type = aLastFrame->GetType();
   if (type == nsGkAtoms::brFrame) {
     return true;
   }
-  // XXX the IS_DIRTY check is a wallpaper for bug 822910.
+  // XXX the TEXT_OFFSETS_NEED_FIXING check is a wallpaper for bug 822910.
   if (type == nsGkAtoms::textFrame &&
-      !(aLastFrame->GetStateBits() & NS_FRAME_IS_DIRTY)) {
+      !(aLastFrame->GetStateBits() & TEXT_OFFSETS_NEED_FIXING)) {
     return aLastFrame->HasSignificantTerminalNewline();
   }
   return false;
 }
 
 void
 nsBlockFrame::AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling)
 {
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -375,16 +375,20 @@ FRAME_STATE_BIT(Text, 27, TEXT_IS_ONLY_W
 // Set this bit if the textframe is known to be not only collapsible whitespace.
 FRAME_STATE_BIT(Text, 28, TEXT_ISNOT_ONLY_WHITESPACE)
 
 // -- Other state bits --------------------------------------------------------
 
 // Set when this text frame is mentioned in the userdata for mTextRun
 FRAME_STATE_BIT(Text, 29, TEXT_IN_TEXTRUN_USER_DATA)
 
+// This state bit is set on frames whose character data offsets need to be
+// fixed up
+FRAME_STATE_BIT(Text, 30, TEXT_OFFSETS_NEED_FIXING)
+
 // This state bit is set on frames that have some non-collapsed characters after
 // reflow
 FRAME_STATE_BIT(Text, 31, TEXT_HAS_NONCOLLAPSED_CHARACTERS)
 
 // This state bit is set on children of token MathML elements.
 // NOTE: TEXT_IS_IN_TOKEN_MATHML has a global state bit value that is shared
 //       with NS_FRAME_IS_PUSHED_FLOAT.
 FRAME_STATE_BIT(Text, 32, TEXT_IS_IN_TOKEN_MATHML)
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/966510-1-ref.html
@@ -0,0 +1,11 @@
+<html reftest-displayport-x="0" reftest-displayport-y="0"
+      reftest-displayport-w="800" reftest-displayport-h="1000"
+      reftest-displayport-element="scrollframe">
+<body>
+  <div id="scrollframe" style="overflow: scroll; position: absolute; top: 0; left: 0; bottom: 0; right: 0; z-index: 3;">
+    <div style="background: purple; height: 50px;"></div>
+  </div>
+  <div style="width: 50px; height: 50px; background: url('solidblue.png'); position: absolute; top: 100px; left: 50px; z-index: 4;">
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/966510-1.html
@@ -0,0 +1,11 @@
+<html reftest-displayport-x="0" reftest-displayport-y="0"
+      reftest-displayport-w="800" reftest-displayport-h="1000"
+      reftest-displayport-element="scrollframe">
+<body>
+  <div id="scrollframe" style="overflow: scroll; position: absolute; top: 0; left: 0; bottom: 0; right: 0; z-index: 3;">
+    <div style="background: purple; height: 50px;"></div>
+  </div>
+  <div style="width: 50px; height: 50px; background: url('solidblue.png'); position: absolute; top: 100px; left: 50px; z-index: 2;">
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/966510-2-ref.html
@@ -0,0 +1,9 @@
+<html>
+<body>
+  <div style="width: 50px; height: 50px; background: url('solidblue.png'); position: absolute; top: 100px; left: 50px;">
+  </div>
+  <div id="scrollframe" style="overflow: scroll; position: absolute; top: 0; left: 0; bottom: 0; right: 0;">
+    <div style="background: purple; height: 50px;"></div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/966510-2.html
@@ -0,0 +1,11 @@
+<html reftest-displayport-x="0" reftest-displayport-y="0"
+      reftest-displayport-w="800" reftest-displayport-h="1000"
+      reftest-displayport-element="scrollframe">
+<body>
+  <div style="width: 50px; height: 50px; background: url('solidblue.png'); position: absolute; top: 100px; left: 50px;">
+  </div>
+  <div id="scrollframe" style="overflow: scroll; position: absolute; top: 0; left: 0; bottom: 0; right: 0;">
+    <div style="background: purple; height: 50px;"></div>
+  </div>
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1791,8 +1791,10 @@ fuzzy-if(OSX==10.6,2,30) == 933264-1.htm
 == 941940-1.html 941940-1-ref.html
 == 942017.html 942017-ref.html
 == 942672-1.html 942672-1-ref.html
 == 953334-win32-clipping.html 953334-win32-clipping-ref.html
 == 956513-1.svg 956513-1-ref.svg
 == 944291-1.html 944291-1-ref.html
 == 957770-1.svg 957770-1-ref.svg
 == 960277-1.html 960277-1-ref.html
+skip-if(Android) == 966510-1.html 966510-1-ref.html # scrollable elements other than the root probably won't work well on android until bug 776030 is fixed
+skip-if(Android) == 966510-2.html 966510-2-ref.html # same as above
--- a/layout/tools/reftest/reftest-content.js
+++ b/layout/tools/reftest/reftest-content.js
@@ -199,19 +199,23 @@ function setupDisplayport(contentRootEle
         windowUtils().setCSSViewport(vw, vh);
     }
 
     // XXX support displayPortX/Y when needed
     var dpw = attrOrDefault("reftest-displayport-w", 0);
     var dph = attrOrDefault("reftest-displayport-h", 0);
     var dpx = attrOrDefault("reftest-displayport-x", 0);
     var dpy = attrOrDefault("reftest-displayport-y", 0);
+    var elementID = attrOrDefault("reftest-displayport-element", null);
     if (dpw !== 0 || dph !== 0) {
-        LogInfo("Setting displayport to <x="+ dpx +", y="+ dpy +", w="+ dpw +", h="+ dph +">");
-        windowUtils().setDisplayPortForElement(dpx, dpy, dpw, dph, content.document.documentElement);
+        var element = elementID ? content.document.getElementById(elementID) : null;
+        LogInfo("Setting displayport to <x="+ dpx +", y="+ dpy +", w="+ dpw +", h="+ dph +">" +
+                (element ? (" on element with id " + elementID) : " on document element"));
+        windowUtils().setDisplayPortForElement(dpx, dpy, dpw, dph,
+            element ? element : content.document.documentElement);
     }
     var asyncScroll = attrOrDefault("reftest-async-scroll", false);
     if (asyncScroll) {
       SendEnableAsyncScroll();
     }
 
     // XXX support resolution when needed
 
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -165,16 +165,19 @@ class RefTest(object):
 
     for v in options.extraPrefs:
       thispref = v.split('=')
       if len(thispref) < 2:
         print "Error: syntax error in --setpref=" + v
         sys.exit(1)
       prefs[thispref[0]] = mozprofile.Preferences.cast(thispref[1].strip())
 
+    # We need to set this here, see bug 972099
+    prefs['gfx.color_management.force_srgb'] = True
+
     # install the reftest extension bits into the profile
     addons = []
     addons.append(os.path.join(SCRIPT_DIRECTORY, "reftest"))
 
     # I would prefer to use "--install-extension reftest/specialpowers", but that requires tight coordination with
     # release engineering and landing on multiple branches at once.
     if special_powers and (manifest.endswith('crashtests.list') or manifest.endswith('jstests.list')):
       addons.append(os.path.join(SCRIPT_DIRECTORY, 'specialpowers'))
new file mode 100644
--- /dev/null
+++ b/media/libspeex_resampler/reset.patch
@@ -0,0 +1,35 @@
+# HG changeset patch
+# Parent b65da7e13aaee4756135be04016e081a95e86855
+# User Karl Tomlinson <karlt+@karlt.net>
+b=973374 complete speex_resampler_reset_mem r=jmspeex
+
+sample_frac_num is the array most likely to be non-zero after resampling a
+previous stream, but the other arrays can also be left at non-zero values
+in other situations.
+
+diff --git a/media/libspeex_resampler/src/resample.c b/media/libspeex_resampler/src/resample.c
+--- a/media/libspeex_resampler/src/resample.c
++++ b/media/libspeex_resampler/src/resample.c
+@@ -1141,16 +1141,22 @@ SPX_RESAMPLE_EXPORT int speex_resampler_
+    for (i=0;i<st->nb_channels;i++)
+       st->last_sample[i] = st->filt_len/2;
+    return RESAMPLER_ERR_SUCCESS;
+ }
+ 
+ SPX_RESAMPLE_EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
+ {
+    spx_uint32_t i;
++   for (i=0;i<st->nb_channels;i++)
++   {
++      st->last_sample[i] = 0;
++      st->magic_samples[i] = 0;
++      st->samp_frac_num[i] = 0;
++   }
+    for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
+       st->mem[i] = 0;
+    return RESAMPLER_ERR_SUCCESS;
+ }
+ 
+ SPX_RESAMPLE_EXPORT const char *speex_resampler_strerror(int err)
+ {
+    switch (err)
--- a/media/libspeex_resampler/src/resample.c
+++ b/media/libspeex_resampler/src/resample.c
@@ -1141,16 +1141,22 @@ SPX_RESAMPLE_EXPORT int speex_resampler_
    for (i=0;i<st->nb_channels;i++)
       st->last_sample[i] = st->filt_len/2;
    return RESAMPLER_ERR_SUCCESS;
 }
 
 SPX_RESAMPLE_EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
 {
    spx_uint32_t i;
+   for (i=0;i<st->nb_channels;i++)
+   {
+      st->last_sample[i] = 0;
+      st->magic_samples[i] = 0;
+      st->samp_frac_num[i] = 0;
+   }
    for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
       st->mem[i] = 0;
    return RESAMPLER_ERR_SUCCESS;
 }
 
 SPX_RESAMPLE_EXPORT const char *speex_resampler_strerror(int err)
 {
    switch (err)
--- a/media/libspeex_resampler/update.sh
+++ b/media/libspeex_resampler/update.sh
@@ -14,8 +14,9 @@ cp $1/src/resample_sse.h src
 cp $1/src/arch.h src
 cp $1/src/stack_alloc.h src
 cp $1/src/speex_resampler.h src
 cp $1/AUTHORS .
 cp $1/COPYING .
 
 # apply outstanding local patches
 patch -p1 < sse-detect-runtime.patch
+patch -p3 < reset.patch
--- a/netwerk/system/win32/nsNotifyAddrListener.cpp
+++ b/netwerk/system/win32/nsNotifyAddrListener.cpp
@@ -21,27 +21,25 @@
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "mozilla/Services.h"
 #include "nsCRT.h"
 
 #include <iptypes.h>
 #include <iphlpapi.h>
 
-typedef void (WINAPI *NcFreeNetconPropertiesFunc)(NETCON_PROPERTIES*);
-
 static HMODULE sNetshell;
-static NcFreeNetconPropertiesFunc sNcFreeNetconProperties;
+static decltype(NcFreeNetconProperties)* sNcFreeNetconProperties;
 
 static void InitNetshellLibrary(void)
 {
     if (!sNetshell) {
         sNetshell = LoadLibraryW(L"Netshell.dll");
         if (sNetshell) {
-            sNcFreeNetconProperties = (NcFreeNetconPropertiesFunc)
+            sNcFreeNetconProperties = (decltype(NcFreeNetconProperties)*)
                 GetProcAddress(sNetshell, "NcFreeNetconProperties");
         }
     }
 }
 
 static void FreeDynamicLibraries(void)
 {
     if (sNetshell) {
--- a/netwerk/wifi/nsWifiScannerWin.cpp
+++ b/netwerk/wifi/nsWifiScannerWin.cpp
@@ -10,30 +10,32 @@
 
 #include "nsWifiMonitor.h"
 #include "nsWifiAccessPoint.h"
 
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIMutableArray.h"
 
+#define DOT11_BSS_TYPE_UNUSED static_cast<DOT11_BSS_TYPE>(0)
+
 using namespace mozilla;
 
 nsresult
 nsWifiMonitor::DoScan()
 {
     HINSTANCE wlan_library = LoadLibrary("Wlanapi.dll");
     if (!wlan_library)
       return NS_ERROR_NOT_AVAILABLE;
 
-    WlanOpenHandleFunction WlanOpenHandle = (WlanOpenHandleFunction) GetProcAddress(wlan_library, "WlanOpenHandle");
-    WlanEnumInterfacesFunction WlanEnumInterfaces = (WlanEnumInterfacesFunction) GetProcAddress(wlan_library, "WlanEnumInterfaces");
-    WlanGetNetworkBssListFunction WlanGetNetworkBssList = (WlanGetNetworkBssListFunction) GetProcAddress(wlan_library, "WlanGetNetworkBssList");
-    WlanFreeMemoryFunction WlanFreeMemory = (WlanFreeMemoryFunction) GetProcAddress(wlan_library, "WlanFreeMemory");
-    WlanCloseHandleFunction WlanCloseHandle = (WlanCloseHandleFunction) GetProcAddress(wlan_library, "WlanCloseHandle");
+    decltype(::WlanOpenHandle)* WlanOpenHandle = (decltype(::WlanOpenHandle)*) GetProcAddress(wlan_library, "WlanOpenHandle");
+    decltype(::WlanEnumInterfaces)* WlanEnumInterfaces = (decltype(::WlanEnumInterfaces)*) GetProcAddress(wlan_library, "WlanEnumInterfaces");
+    decltype(::WlanGetNetworkBssList)* WlanGetNetworkBssList = (decltype(::WlanGetNetworkBssList)*) GetProcAddress(wlan_library, "WlanGetNetworkBssList");
+    decltype(::WlanFreeMemory)* WlanFreeMemory = (decltype(::WlanFreeMemory)*) GetProcAddress(wlan_library, "WlanFreeMemory");
+    decltype(::WlanCloseHandle)* WlanCloseHandle = (decltype(::WlanCloseHandle)*) GetProcAddress(wlan_library, "WlanCloseHandle");
 
     if (!WlanOpenHandle ||
         !WlanEnumInterfaces ||
         !WlanGetNetworkBssList ||
         !WlanFreeMemory ||
         !WlanCloseHandle)
       return NS_ERROR_FAILURE;
 
deleted file mode 100644
--- a/netwerk/wifi/wlanapi.h
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2008, Google Inc.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-//  1. Redistributions of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//  2. Redistributions in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//  3. Neither the name of Google Inc. nor the names of its contributors may be
-//     used to endorse or promote products derived from this software without
-//     specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Replicates missing wlanapi.h. Taken from
-// http://msdn.microsoft.com/en-us/library/bb204766.aspx.
-
-// TODO(steveblock): Change naming convention to follow correct style.
-
-
-// WlanOpenHandle
-
-typedef DWORD (WINAPI *WlanOpenHandleFunction)(DWORD dwClientVersion,
-                                               PVOID pReserved,
-                                               PDWORD pdwNegotiatedVersion,
-                                               PHANDLE phClientHandle);
-
-// WlanEnumInterfaces
-
-typedef enum _WLAN_INTERFACE_STATE {
-  WLAN_INTERFACE_STATE_UNUSED
-} WLAN_INTERFACE_STATE;
-
-typedef struct _WLAN_INTERFACE_INFO {
-  GUID InterfaceGuid;
-  WCHAR strInterfaceDescription[256];
-  WLAN_INTERFACE_STATE isState;
-} WLAN_INTERFACE_INFO, *PWLAN_INTERFACE_INFO;
-
-typedef struct _WLAN_INTERFACE_INFO_LIST {
-  DWORD dwNumberOfItems;
-  DWORD dwIndex;
-  WLAN_INTERFACE_INFO InterfaceInfo[1];
-} WLAN_INTERFACE_INFO_LIST, *PWLAN_INTERFACE_INFO_LIST;
-
-typedef DWORD (WINAPI *WlanEnumInterfacesFunction)(
-    HANDLE hClientHandle,
-    PVOID pReserved,
-    PWLAN_INTERFACE_INFO_LIST *ppInterfaceList);
-
-// WlanGetNetworkBssList
-
-#define DOT11_SSID_MAX_LENGTH 32
-
-typedef struct _DOT11_SSID {
-  ULONG uSSIDLength;
-  UCHAR ucSSID[DOT11_SSID_MAX_LENGTH];
-} DOT11_SSID, *PDOT11_SSID;
-
-typedef UCHAR DOT11_MAC_ADDRESS[6];
-
-typedef enum _DOT11_BSS_TYPE {
-  DOT11_BSS_TYPE_UNUSED
-} DOT11_BSS_TYPE;
-
-typedef enum _DOT11_PHY_TYPE {
-  DOT11_PHY_TYPE_UNUSED
-} DOT11_PHY_TYPE;
-
-#define DOT11_RATE_SET_MAX_LENGTH (126)
-
-typedef struct _WLAN_RATE_SET {
-  ULONG uRateSetLength;
-  USHORT usRateSet[DOT11_RATE_SET_MAX_LENGTH];
-} WLAN_RATE_SET, *PWLAN_RATE_SET;
-
-typedef struct _WLAN_BSS_ENTRY {
-  DOT11_SSID dot11Ssid;
-  ULONG uPhyId;
-  DOT11_MAC_ADDRESS dot11Bssid;
-  DOT11_BSS_TYPE dot11BssType;
-  DOT11_PHY_TYPE dot11BssPhyType;
-  LONG lRssi;
-  ULONG uLinkQuality;
-  BOOLEAN bInRegDomain;
-  USHORT usBeaconPeriod;
-  ULONGLONG ullTimestamp;
-  ULONGLONG ullHostTimestamp;
-  USHORT usCapabilityInformation;
-  ULONG ulChCenterFrequency;
-  WLAN_RATE_SET wlanRateSet;
-  ULONG ulIeOffset;
-  ULONG ulIeSize;
-} WLAN_BSS_ENTRY, *PWLAN_BSS_ENTRY;
-
-typedef struct _WLAN_BSS_LIST {
-  DWORD dwTotalSize;
-  DWORD dwNumberOfItems;
-  // Following data is an array of WLAN_BSS_ENTRY objects of length
-  // dwNumberOfItems.
-  WLAN_BSS_ENTRY wlanBssEntries[1];
-} WLAN_BSS_LIST, *PWLAN_BSS_LIST;
-
-typedef DWORD (WINAPI *WlanGetNetworkBssListFunction)(
-    HANDLE hClientHandle,
-    const GUID *pInterfaceGuid,
-    const  PDOT11_SSID pDot11Ssid,
-    DOT11_BSS_TYPE dot11BssType,
-    BOOL bSecurityEnabled,
-    PVOID pReserved,
-    PWLAN_BSS_LIST *ppWlanBssList
-);
-
-// WlanFreeMemory
-
-typedef VOID (WINAPI *WlanFreeMemoryFunction)(PVOID pMemory);
-
-// WlanCloseHandle
-
-typedef DWORD (WINAPI *WlanCloseHandleFunction)(HANDLE hClientHandle,
-                                                PVOID pReserved);
-
-
--- a/toolkit/components/parentalcontrols/nsParentalControlsServiceWin.cpp
+++ b/toolkit/components/parentalcontrols/nsParentalControlsServiceWin.cpp
@@ -16,34 +16,19 @@
 
 static const CLSID CLSID_WinParentalControls = {0xE77CC89B,0x7401,0x4C04,{0x8C,0xED,0x14,0x9D,0xB3,0x5A,0xDD,0x04}};
 static const IID IID_IWinParentalControls  = {0x28B4D88B,0xE072,0x49E6,{0x80,0x4D,0x26,0xED,0xBE,0x21,0xA7,0xB9}};
 
 NS_IMPL_ISUPPORTS1(nsParentalControlsServiceWin, nsIParentalControlsService)
 
 static HINSTANCE gAdvAPIDLLInst = nullptr;
 
-typedef ULONG (STDMETHODCALLTYPE *MyEventWrite)(
-  REGHANDLE RegHandle,
-  PCEVENT_DESCRIPTOR EventDescriptor,
-  ULONG UserDataCount,
-  PEVENT_DATA_DESCRIPTOR UserData);
-
-typedef ULONG (STDMETHODCALLTYPE *MyEventRegister)(
-  LPCGUID ProviderId,
-  PENABLECALLBACK EnableCallback,
-  PVOID CallbackContext,
-  PREGHANDLE RegHandle);
-
-typedef ULONG (STDMETHODCALLTYPE *MyEventUnregister)(
-  REGHANDLE RegHandle);
-
-MyEventWrite gEventWrite = nullptr;
-MyEventRegister gEventRegister = nullptr;
-MyEventUnregister gEventUnregister = nullptr;
+decltype(EventWrite)* gEventWrite = nullptr;
+decltype(EventRegister)* gEventRegister = nullptr;
+decltype(EventUnregister)* gEventUnregister = nullptr;
 
 nsParentalControlsServiceWin::nsParentalControlsServiceWin() :
   mEnabled(false)
 , mProvider(0)
 , mPC(nullptr)
 {
   HRESULT hr;
   CoInitialize(nullptr);
@@ -62,19 +47,19 @@ nsParentalControlsServiceWin::nsParental
 
   DWORD settings = 0;
   wpcs->GetRestrictions(&settings);
   
   if (settings) { // WPCFLAG_NO_RESTRICTION = 0
     gAdvAPIDLLInst = ::LoadLibrary("Advapi32.dll");
     if(gAdvAPIDLLInst)
     {
-      gEventWrite = (MyEventWrite) GetProcAddress(gAdvAPIDLLInst, "EventWrite");
-      gEventRegister = (MyEventRegister) GetProcAddress(gAdvAPIDLLInst, "EventRegister");
-      gEventUnregister = (MyEventUnregister) GetProcAddress(gAdvAPIDLLInst, "EventUnregister");
+      gEventWrite = (decltype(EventWrite)*) GetProcAddress(gAdvAPIDLLInst, "EventWrite");
+      gEventRegister = (decltype(EventRegister)*) GetProcAddress(gAdvAPIDLLInst, "EventRegister");
+      gEventUnregister = (decltype(EventUnregister)*) GetProcAddress(gAdvAPIDLLInst, "EventUnregister");
     }
     mEnabled = true;
   }
 }
 
 nsParentalControlsServiceWin::~nsParentalControlsServiceWin()
 {
   if (mPC)
--- a/toolkit/content/license.html
+++ b/toolkit/content/license.html
@@ -2285,53 +2285,16 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTI
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 </pre>
 
 
     <hr>
 
-    <h1><a id="gears"></a>Google Gears License</h1>
-
-    <p>This license applies to the file
-    <span class="path">netwerk/wifi/wlanapi.h</span>.</p>
-
-<pre>
-Copyright 2008, Google Inc.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
-    this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright notice,
-    this list of conditions and the following disclaimer in the documentation
-    and/or other materials provided with the distribution.
- 3. Neither the name of Google Inc. nor the names of its contributors may be
-    used to endorse or promote products derived from this software without
-    specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-</pre>
-
-
-
-
-    <hr>
-
     <h1><a id="vp8"></a>Google VP8 License</h1>
 
     <p>This license applies to certain files in the directory
     <span class="path">media/libvpx</span>.</p>
 <pre>
 Copyright (c) 2010, Google, Inc.
 
 All rights reserved.
--- a/toolkit/mozapps/update/common/uachelper.cpp
+++ b/toolkit/mozapps/update/common/uachelper.cpp
@@ -1,18 +1,17 @@
 /* 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 <windows.h>
+#include <wtsapi32.h>
 #include "uachelper.h"
 #include "updatelogging.h"
 
-typedef BOOL (WINAPI *LPWTSQueryUserToken)(ULONG, PHANDLE);
-
 // See the MSDN documentation with title: Privilege Constants
 // At the time of this writing, this documentation is located at: 
 // http://msdn.microsoft.com/en-us/library/windows/desktop/bb530716%28v=vs.85%29.aspx
 LPCTSTR UACHelper::PrivsToDisable[] = { 
   SE_ASSIGNPRIMARYTOKEN_NAME,
   SE_AUDIT_NAME,
   SE_BACKUP_NAME,
   // CreateProcess will succeed but the app will fail to launch on some WinXP 
@@ -62,18 +61,18 @@ LPCTSTR UACHelper::PrivsToDisable[] = {
  * @return A handle to the token to obtain which will be primary if enough
  *         permissions exist.  Caller should close the handle.
  */
 HANDLE
 UACHelper::OpenUserToken(DWORD sessionID)
 {
   HMODULE module = LoadLibraryW(L"wtsapi32.dll");
   HANDLE token = nullptr;
-  LPWTSQueryUserToken wtsQueryUserToken = 
-    (LPWTSQueryUserToken)GetProcAddress(module, "WTSQueryUserToken");
+  decltype(WTSQueryUserToken)* wtsQueryUserToken = 
+    (decltype(WTSQueryUserToken)*) GetProcAddress(module, "WTSQueryUserToken");
   if (wtsQueryUserToken) {
     wtsQueryUserToken(sessionID, &token);
   }
   FreeLibrary(module);
   return token;
 }
 
 /**
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -2620,22 +2620,16 @@ static void MOZ_gdk_display_close(GdkDis
  * improve startup performance.
  */
 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE;
 
 #ifdef CAIRO_HAS_DWRITE_FONT
 
 #include <dwrite.h>
 
-typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)(
-  DWRITE_FACTORY_TYPE factoryType,
-  REFIID iid,
-  IUnknown **factory
-);
-
 #ifdef DEBUG_DWRITE_STARTUP
 
 #define LOGREGISTRY(msg) LogRegistryEvent(msg)
 
 // for use when monitoring process
 static void LogRegistryEvent(const wchar_t *msg)
 {
   HKEY dummyKey;
@@ -2655,17 +2649,17 @@ static void LogRegistryEvent(const wchar
 #endif
 
 static DWORD InitDwriteBG(LPVOID lpdwThreadParam)
 {
   SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
   LOGREGISTRY(L"loading dwrite.dll");
   HMODULE dwdll = LoadLibraryW(L"dwrite.dll");
   if (dwdll) {
-    DWriteCreateFactoryFunc createDWriteFactory = (DWriteCreateFactoryFunc)
+    decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
       GetProcAddress(dwdll, "DWriteCreateFactory");
     if (createDWriteFactory) {
       LOGREGISTRY(L"creating dwrite factory");
       IDWriteFactory *factory;
       HRESULT hr = createDWriteFactory(
         DWRITE_FACTORY_TYPE_SHARED,
         __uuidof(IDWriteFactory),
         reinterpret_cast<IUnknown**>(&factory));
--- a/tools/trace-malloc/lib/nsDebugHelpWin32.cpp
+++ b/tools/trace-malloc/lib/nsDebugHelpWin32.cpp
@@ -20,17 +20,17 @@
 
 
 
 /***************************************************************************/
 
 
 PRLock*           DHWImportHooker::gLock  = nullptr;
 DHWImportHooker*  DHWImportHooker::gHooks = nullptr;
-GETPROCADDRESS    DHWImportHooker::gRealGetProcAddress = nullptr;
+decltype(GetProcAddress)* DHWImportHooker::gRealGetProcAddress = nullptr;
 
 
 static bool
 dhwEnsureImageHlpInitialized()
 {
   static bool gInitialized = false;
   static bool gTried       = false;
 
@@ -42,17 +42,17 @@ dhwEnsureImageHlpInitialized()
       printf("DumpStack Error: DBGHELP.DLL wasn't found. GetLastError() returned 0x%8.8X\n"
              "                 This DLL is needed for succeessfully implementing trace-malloc.\n"
              "                 This dll ships by default on Win2k. Disabling trace-malloc functionality.\n"
              , dw);
       return false;
     }
 
 #define INIT_PROC(typename_, name_) \
-    dhw##name_ = (typename_) ::GetProcAddress(module, #name_); \
+    dhw##name_ = (decltype(name_)*) ::GetProcAddress(module, #name_); \
     if(!dhw##name_) return false;
 
 #ifdef _WIN64
     INIT_PROC(ENUMERATELOADEDMODULES64, EnumerateLoadedModules64);
 #else
     INIT_PROC(ENUMERATELOADEDMODULES, EnumerateLoadedModules);
 #endif
     INIT_PROC(IMAGEDIRECTORYENTRYTODATA, ImageDirectoryEntryToData);
@@ -307,53 +307,48 @@ DHWImportHooker::ModuleLoaded(HMODULE aM
     return true;
 }
 
 // static 
 HMODULE WINAPI 
 DHWImportHooker::LoadLibraryW(PCWSTR path)
 {
     //wprintf(L"LoadLibraryW %s\n",path);
-    DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYW_, (PCWSTR));
-    HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYW_, getLoadLibraryWHooker())(path);
+    HMODULE hmod = DHW_ORIGINAL(::LoadLibraryW, getLoadLibraryWHooker())(path);
     ModuleLoaded(hmod, 0);
     return hmod;
 }
 
 
 // static 
 HMODULE WINAPI 
 DHWImportHooker::LoadLibraryExW(PCWSTR path, HANDLE file, DWORD flags)
 {
     //wprintf(L"LoadLibraryExW %s\n",path);
-    DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYEXW_, (PCWSTR, HANDLE, DWORD));
-    HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYEXW_, getLoadLibraryExWHooker())(path, file, flags);
+    HMODULE hmod = DHW_ORIGINAL(::LoadLibraryExW, getLoadLibraryExWHooker())(path, file, flags);
     ModuleLoaded(hmod, flags);
     return hmod;
 }    
 
 // static 
 HMODULE WINAPI 
 DHWImportHooker::LoadLibraryA(PCSTR path)
 {
     //printf("LoadLibraryA %s\n",path);
-
-    DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYA_, (PCSTR));
-    HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYA_, getLoadLibraryAHooker())(path);
+    HMODULE hmod = DHW_ORIGINAL(::LoadLibraryA, getLoadLibraryAHooker())(path);
     ModuleLoaded(hmod, 0);
     return hmod;
 }
 
 // static 
 HMODULE WINAPI 
 DHWImportHooker::LoadLibraryExA(PCSTR path, HANDLE file, DWORD flags)
 {
     //printf("LoadLibraryExA %s\n",path);
-    DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYEXA_, (PCSTR, HANDLE, DWORD));
-    HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYEXA_, getLoadLibraryExAHooker())(path, file, flags);
+    HMODULE hmod = DHW_ORIGINAL(::LoadLibraryExA, getLoadLibraryExAHooker())(path, file, flags);
     ModuleLoaded(hmod, flags);
     return hmod;
 }     
 // static 
 FARPROC WINAPI 
 DHWImportHooker::GetProcAddress(HMODULE aModule, PCSTR aFunctionName)
 {
     FARPROC pfn = gRealGetProcAddress(aModule, aFunctionName);
--- a/tools/trace-malloc/lib/nsDebugHelpWin32.h
+++ b/tools/trace-malloc/lib/nsDebugHelpWin32.h
@@ -21,134 +21,47 @@
 
 // XXX temporary hack...
 //#include "hacky_defines.h"
 
 
 /***************************************************************************/
 // useful macros...
 
-#define DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_) \
-    typedef retval_ ( conv_ * typename_ ) args_ ;
-
 #ifdef DHW_IMPLEMENT_GLOBALS
-#define DHW_DECLARE_FUN_GLOBAL(typename_, name_) typename_ dhw##name_
+#define DHW_DECLARE_FUN_GLOBAL(name_) decltype(name_)* dhw##name_
 #else
-#define DHW_DECLARE_FUN_GLOBAL(typename_, name_) extern typename_ dhw##name_
+#define DHW_DECLARE_FUN_GLOBAL(name_) extern decltype(name_)* dhw##name_
 #endif
 
-#define DHW_DECLARE_FUN_PROTO(retval_, conv_, name_, args_) \
-    retval_ conv_ name_ args_
-
-#define DHW_DECLARE_FUN_STATIC_PROTO(retval_, name_, args_) \
-    static retval_ conv_ name_ args_
-
-#define DHW_DECLARE_FUN_TYPE_AND_PROTO(name_, retval_, conv_, typename_, args_) \
-    DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_); \
-    DHW_DECLARE_FUN_PROTO(retval_, conv_, name_, args_)
-
-#define DHW_DECLARE_FUN_TYPE_AND_STATIC_PROTO(name_, retval_, conv_, typename_, args_) \
-    DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_); \
-    DHW_DECLARE_FUN_STATIC_PROTO(retval_, conv_, name_, args_)
-
-#define DHW_DECLARE_FUN_TYPE_AND_GLOBAL(typename_, name_, retval_, conv_, args_) \
-    DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_); \
-    DHW_DECLARE_FUN_GLOBAL(typename_, name_)
-
 
 /**********************************************************/
-// These are used to get 'original' function addresses from DHWImportHooker.
-
-#define DHW_DECLARE_ORIGINAL(type_, name_, hooker_) \
-    type_ name_ = (type_) hooker_ . GetOriginalFunction()
+// This is used to get 'original' function addresses from DHWImportHooker.
 
-#define DHW_DECLARE_ORIGINAL_PTR(type_, name_, hooker_) \
-    type_ name_ = (type_) hooker_ -> GetOriginalFunction()
-
-#define DHW_ORIGINAL(type_, hooker_) \
-    ((type_) hooker_ . GetOriginalFunction())
-
-#define DHW_ORIGINAL_PTR(type_, hooker_) \
-    ((type_) hooker_ -> GetOriginalFunction())
+#define DHW_ORIGINAL(name_, hooker_) \
+    ((decltype(name_)*) hooker_ . GetOriginalFunction())
 
 /***************************************************************************/
 // Global declarations of entry points into ImgHelp functions
-#if 0
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMINITIALIZEPROC, SymInitialize, \
-                                BOOL, __stdcall, (HANDLE, LPSTR, BOOL));
-
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMSETOPTIONS, SymSetOptions, \
-                                DWORD, __stdcall, (DWORD));
-
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETOPTIONS, SymGetOptions, \
-                                DWORD, __stdcall, ());
-
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETMODULEINFO, SymGetModuleInfo, \
-                                BOOL, __stdcall, (HANDLE, DWORD, PIMAGEHLP_MODULE));
-
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETSYMFROMADDRPROC, SymGetSymFromAddr, \
-                                BOOL, __stdcall, (HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL));
-
-#endif
 
 #ifndef _WIN64
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(ENUMERATELOADEDMODULES, EnumerateLoadedModules, \
-                                BOOL, __stdcall, (HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID));
+DHW_DECLARE_FUN_GLOBAL(EnumerateLoadedModules);
 #else
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(ENUMERATELOADEDMODULES64, EnumerateLoadedModules64, \
-                                BOOL, __stdcall, (HANDLE, PENUMLOADED_MODULES_CALLBACK64, PVOID));
+DHW_DECLARE_FUN_GLOBAL(EnumerateLoadedModules64);
 #endif
 
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(IMAGEDIRECTORYENTRYTODATA, ImageDirectoryEntryToData, \
-                                PVOID, __stdcall, (PVOID, BOOL, USHORT, PULONG));
-
-// We aren't using any of the below yet...
-
-/*
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMCLEANUPPROC, SymCleanup, \
-                                BOOL, __stdcall, (HANDLE));
-
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(STACKWALKPROC, StackWalk, \
-                                BOOL, 
-                                __stdcall, 
-                                (DWORD, HANDLE, HANDLE, LPSTACKFRAME, LPVOID, \
-                                       PREAD_PROCESS_MEMORY_ROUTINE, \
-                                       PFUNCTION_TABLE_ACCESS_ROUTINE, \
-                                       PGET_MODULE_BASE_ROUTINE, \
-                                       PTRANSLATE_ADDRESS_ROUTINE));
-
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMFUNCTIONTABLEACCESSPROC, SymFunctionTableAccess, \
-                                LPVOID, __stdcall, (HANDLE, DWORD));
-
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETMODULEBASEPROC, SymGetModuleBase, \
-                                DWORD, __stdcall, (HANDLE, DWORD));
-
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMLOADMODULE, SymLoadModule, \
-                                DWORD, __stdcall, (HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD));
-
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(UNDECORATESYMBOLNAME, _UnDecorateSymbolName, \
-                                DWORD, __stdcall, (LPCSTR, LPSTR, DWORD, DWORD));
-
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMUNDNAME, SymUnDName, \
-                                BOOL, __stdcall, (PIMAGEHLP_SYMBOL, LPSTR, DWORD));
-
-DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETLINEFROMADDR, SymGetLineFromAddr, \
-                                BOOL, __stdcall, (HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE));
-
-*/
+DHW_DECLARE_FUN_GLOBAL(ImageDirectoryEntryToData);
 
 /***************************************************************************/
 
 extern bool
 dhwEnsureImageHlpInitialized();
 
 /***************************************************************************/
 
-DHW_DECLARE_FUN_TYPE(FARPROC, __stdcall, GETPROCADDRESS, (HMODULE, PCSTR));
-
 class DHWImportHooker
 {
 public: 
 
     DHWImportHooker(const char* aModuleName,
                     const char* aFunctionName,
                     PROC aHook,
                     bool aExcludeOurModule = false);
@@ -182,17 +95,17 @@ private:
     PROC             mOriginal;
     PROC             mHook;
     HMODULE          mIgnoreModule;
     bool             mHooking;
 
 private:
     static PRLock* gLock;
     static DHWImportHooker* gHooks;
-    static GETPROCADDRESS gRealGetProcAddress;
+    static decltype(GetProcAddress)* gRealGetProcAddress;
     
     static HMODULE WINAPI LoadLibraryW(PCWSTR path);
     static HMODULE WINAPI LoadLibraryExW(PCWSTR path, HANDLE file, DWORD flags);
     static HMODULE WINAPI LoadLibraryExA(PCSTR path, HANDLE file, DWORD flags);
 
     static FARPROC WINAPI GetProcAddress(HMODULE aModule, PCSTR aFunctionName);
 };
 
--- a/tools/trace-malloc/lib/nsWinTraceMalloc.cpp
+++ b/tools/trace-malloc/lib/nsWinTraceMalloc.cpp
@@ -32,169 +32,169 @@
 #elif _MSC_VER == 1700
 #define NS_DEBUG_CRT "msvcr110d.dll"
 #elif _MSC_VER == 1800
 #define NS_DEBUG_CRT "msvcr120d.dll"
 #else
 #error "Don't know filename of MSVC debug library."
 #endif
 
-DHW_DECLARE_FUN_TYPE_AND_PROTO(dhw_malloc, void*, __cdecl, MALLOC_, (size_t));
+decltype(malloc) dhw_malloc;
 
 DHWImportHooker &getMallocHooker()
 {
   static DHWImportHooker gMallocHooker(NS_DEBUG_CRT, "malloc", (PROC) dhw_malloc);
   return gMallocHooker;
 }
 
 void * __cdecl dhw_malloc( size_t size )
 {
     tm_thread *t = tm_get_thread();
     ++t->suppress_tracing;
     uint32_t start = PR_IntervalNow();
-    void* result = DHW_ORIGINAL(MALLOC_, getMallocHooker())(size);
+    void* result = DHW_ORIGINAL(malloc, getMallocHooker())(size);
     uint32_t end = PR_IntervalNow();
     --t->suppress_tracing;
     MallocCallback(result, size, start, end, t);
     return result;    
 }
 
-DHW_DECLARE_FUN_TYPE_AND_PROTO(dhw_calloc, void*, __cdecl, CALLOC_, (size_t,size_t));
+decltype(calloc) dhw_calloc;
 
 DHWImportHooker &getCallocHooker()
 {
   static DHWImportHooker gCallocHooker(NS_DEBUG_CRT, "calloc", (PROC) dhw_calloc);
   return gCallocHooker;
 }
 
 void * __cdecl dhw_calloc( size_t count, size_t size )
 {
     tm_thread *t = tm_get_thread();
     ++t->suppress_tracing;
     uint32_t start = PR_IntervalNow();
-    void* result = DHW_ORIGINAL(CALLOC_, getCallocHooker())(count,size);
+    void* result = DHW_ORIGINAL(calloc, getCallocHooker())(count,size);
     uint32_t end = PR_IntervalNow();
     --t->suppress_tracing;
     CallocCallback(result, count, size, start, end, t);
     return result;    
 }
 
-DHW_DECLARE_FUN_TYPE_AND_PROTO(dhw_free, void, __cdecl, FREE_, (void*));
+decltype(free) dhw_free;
 DHWImportHooker &getFreeHooker()
 {
   static DHWImportHooker gFreeHooker(NS_DEBUG_CRT, "free", (PROC) dhw_free);
   return gFreeHooker;
 }
 
 void __cdecl dhw_free( void* p )
 {
     tm_thread *t = tm_get_thread();
     ++t->suppress_tracing;
     uint32_t start = PR_IntervalNow();
-    DHW_ORIGINAL(FREE_, getFreeHooker())(p);
+    DHW_ORIGINAL(free, getFreeHooker())(p);
     uint32_t end = PR_IntervalNow();
     --t->suppress_tracing;
     /* FIXME bug 392008: We could race with reallocation of p. */
     FreeCallback(p, start, end, t);
 }
 
 
-DHW_DECLARE_FUN_TYPE_AND_PROTO(dhw_realloc, void*, __cdecl, REALLOC_, (void*, size_t));
+decltype(realloc) dhw_realloc;
 DHWImportHooker &getReallocHooker()
 {
   static DHWImportHooker gReallocHooker(NS_DEBUG_CRT, "realloc", (PROC) dhw_realloc);
   return gReallocHooker;
 }
 
 void * __cdecl dhw_realloc(void * pin, size_t size)
 {
     tm_thread *t = tm_get_thread();
     ++t->suppress_tracing;
     uint32_t start = PR_IntervalNow();
-    void* pout = DHW_ORIGINAL(REALLOC_, getReallocHooker())(pin, size);
+    void* pout = DHW_ORIGINAL(realloc, getReallocHooker())(pin, size);
     uint32_t end = PR_IntervalNow();
     --t->suppress_tracing;
     /* FIXME bug 392008: We could race with reallocation of pin. */
     ReallocCallback(pin, pout, size, start, end, t);
     return pout;
 }
 
 // Note the mangled name!
-DHW_DECLARE_FUN_TYPE_AND_PROTO(dhw_new, void*, __cdecl, NEW_, (size_t));
+void * __cdecl dhw_new(size_t size);
 DHWImportHooker &getNewHooker()
 {
   static DHWImportHooker gNewHooker(NS_DEBUG_CRT, "??2@YAPAXI@Z", (PROC) dhw_new);
   return gNewHooker;
 }
 
 void * __cdecl dhw_new(size_t size)
 {
     tm_thread *t = tm_get_thread();
     ++t->suppress_tracing;
     uint32_t start = PR_IntervalNow();
-    void* result = DHW_ORIGINAL(NEW_, getNewHooker())(size);
+    void* result = DHW_ORIGINAL(dhw_new, getNewHooker())(size);
     uint32_t end = PR_IntervalNow();
     --t->suppress_tracing;
     MallocCallback(result, size, start, end, t);//do we need a different one for new?
     return result;
 }
 
 // Note the mangled name!
-DHW_DECLARE_FUN_TYPE_AND_PROTO(dhw_delete, void, __cdecl, DELETE_, (void*));
+void __cdecl dhw_delete(void* p);
 DHWImportHooker &getDeleteHooker()
 {
   static DHWImportHooker gDeleteHooker(NS_DEBUG_CRT, "??3@YAXPAX@Z", (PROC) dhw_delete);
   return gDeleteHooker;
 }
 
 void __cdecl dhw_delete(void* p)
 {
     tm_thread *t = tm_get_thread();
     ++t->suppress_tracing;
     uint32_t start = PR_IntervalNow();
-    DHW_ORIGINAL(DELETE_, getDeleteHooker())(p);
+    DHW_ORIGINAL(dhw_delete, getDeleteHooker())(p);
     uint32_t end = PR_IntervalNow();
     --t->suppress_tracing;
     FreeCallback(p, start, end, t);
 }
 
 // Note the mangled name!
-DHW_DECLARE_FUN_TYPE_AND_PROTO(dhw_vec_new, void*, __cdecl, VEC_NEW_, (size_t));
+void * __cdecl dhw_vec_new(size_t size);
 DHWImportHooker &getVecNewHooker()
 {
   static DHWImportHooker gVecNewHooker(NS_DEBUG_CRT, "??_U@YAPAXI@Z", (PROC) dhw_vec_new);
   return gVecNewHooker;
 }
 
 void * __cdecl dhw_vec_new(size_t size)
 {
     tm_thread *t = tm_get_thread();
     ++t->suppress_tracing; // need to suppress since new[] calls new
     uint32_t start = PR_IntervalNow();
-    void* result = DHW_ORIGINAL(VEC_NEW_, getVecNewHooker())(size);
+    void* result = DHW_ORIGINAL(dhw_vec_new, getVecNewHooker())(size);
     uint32_t end = PR_IntervalNow();
     --t->suppress_tracing;
     MallocCallback(result, size, start, end, t);//do we need a different one for new[]?
     return result;
 }
 
 // Note the mangled name!
-DHW_DECLARE_FUN_TYPE_AND_PROTO(dhw_vec_delete, void, __cdecl, VEC_DELETE_, (void*));
+void __cdecl dhw_vec_delete(void* p);
 DHWImportHooker &getVecDeleteHooker()
 {
   static DHWImportHooker gVecDeleteHooker(NS_DEBUG_CRT, "??_V@YAXPAX@Z", (PROC) dhw_vec_delete);
   return gVecDeleteHooker;
 }
 
 void __cdecl dhw_vec_delete(void* p)
 {
     tm_thread *t = tm_get_thread();
     ++t->suppress_tracing;
     uint32_t start = PR_IntervalNow();
-    DHW_ORIGINAL(VEC_DELETE_, getVecDeleteHooker())(p);
+    DHW_ORIGINAL(dhw_vec_delete, getVecDeleteHooker())(p);
     uint32_t end = PR_IntervalNow();
     --t->suppress_tracing;
     FreeCallback(p, start, end, t);
 }
 
 /*C Callbacks*/
 PR_IMPLEMENT(void)
 StartupHooker()
@@ -225,28 +225,28 @@ extern "C" {
   void* dhw_orig_calloc(size_t, size_t);
   void* dhw_orig_realloc(void*, size_t);
   void dhw_orig_free(void*);
 }
 
 void*
 dhw_orig_malloc(size_t size)
 {
-    return DHW_ORIGINAL(MALLOC_, getMallocHooker())(size);
+    return DHW_ORIGINAL(malloc, getMallocHooker())(size);
 }
 
 void*
 dhw_orig_calloc(size_t count, size_t size)
 {
-    return DHW_ORIGINAL(CALLOC_, getCallocHooker())(count,size);
+    return DHW_ORIGINAL(calloc, getCallocHooker())(count,size);
 }
 
 void*
 dhw_orig_realloc(void* pin, size_t size)
 {
-    return DHW_ORIGINAL(REALLOC_, getReallocHooker())(pin, size);
+    return DHW_ORIGINAL(realloc, getReallocHooker())(pin, size);
 }
 
 void
 dhw_orig_free(void* p)
 {
-    DHW_ORIGINAL(FREE_, getFreeHooker())(p);
+    DHW_ORIGINAL(free, getFreeHooker())(p);
 }
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -119,17 +119,17 @@ private:
 };
 
 
 class AndroidBridge MOZ_FINAL : public mozilla::layers::GeckoContentController
 {
 public:
     enum {
         // Values for NotifyIME, in addition to values from the Gecko
-        // NotificationToIME enum; use negative values here to prevent conflict
+        // IMEMessage enum; use negative values here to prevent conflict
         NOTIFY_IME_OPEN_VKB = -2,
         NOTIFY_IME_REPLY_EVENT = -1,
     };
 
     enum {
         LAYER_CLIENT_TYPE_NONE = 0,
         LAYER_CLIENT_TYPE_GL = 2            // AndroidGeckoGLLayerClient
     };
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -1831,17 +1831,20 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *
             // The focusing handshake sequence is complete, and Java is waiting
             // on Gecko. Now we can notify Java of the newly focused content
             mIMETextChanges.Clear();
             mIMESelectionChanged = false;
             // NotifyIMEOfTextChange also notifies selection
             // Use 'INT32_MAX / 2' here because subsequent text changes might
             // combine with this text change, and overflow might occur if
             // we just use INT32_MAX
-            NotifyIMEOfTextChange(0, INT32_MAX / 2, INT32_MAX / 2);
+            IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE);
+            notification.mTextChangeData.mOldEndOffset =
+                notification.mTextChangeData.mNewEndOffset = INT32_MAX / 2;
+            NotifyIMEOfTextChange(notification);
             FlushIMEChanges();
         }
         GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT);
         return;
     } else if (ae->Action() == AndroidGeckoEvent::IME_UPDATE_CONTEXT) {
         GeckoAppShell::NotifyIMEContext(mInputContext.mIMEState.mEnabled,
                                         mInputContext.mHTMLInputType,
                                         mInputContext.mHTMLInputInputmode,
@@ -2089,19 +2092,19 @@ nsWindow::UserActivity()
   }
 
   if (mIdleService) {
     mIdleService->ResetIdleTimeOut(0);
   }
 }
 
 NS_IMETHODIMP
-nsWindow::NotifyIME(NotificationToIME aNotification)
+nsWindow::NotifyIME(const IMENotification& aIMENotification)
 {
-    switch (aNotification) {
+    switch (aIMENotification.mMessage) {
         case REQUEST_TO_COMMIT_COMPOSITION:
             //ALOGIME("IME: REQUEST_TO_COMMIT_COMPOSITION: s=%d", aState);
             RemoveIMEComposition();
             GeckoAppShell::NotifyIME(REQUEST_TO_COMMIT_COMPOSITION);
             return NS_OK;
         case REQUEST_TO_CANCEL_COMPOSITION:
             ALOGIME("IME: REQUEST_TO_CANCEL_COMPOSITION");
 
@@ -2142,16 +2145,18 @@ nsWindow::NotifyIME(NotificationToIME aN
                 return NS_OK;
             }
 
             ALOGIME("IME: NOTIFY_IME_OF_SELECTION_CHANGE");
 
             PostFlushIMEChanges();
             mIMESelectionChanged = true;
             return NS_OK;
+        case NOTIFY_IME_OF_TEXT_CHANGE:
+            return NotifyIMEOfTextChange(aIMENotification);
         default:
             return NS_ERROR_NOT_IMPLEMENTED;
     }
 }
 
 NS_IMETHODIMP_(void)
 nsWindow::SetInputContext(const InputContext& aContext,
                           const InputContextAction& aAction)
@@ -2268,41 +2273,46 @@ nsWindow::FlushIMEChanges()
 
         GeckoAppShell::NotifyIMEChange(EmptyString(),
                              (int32_t) event.GetSelectionStart(),
                              (int32_t) event.GetSelectionEnd(), -1);
         mIMESelectionChanged = false;
     }
 }
 
-NS_IMETHODIMP
-nsWindow::NotifyIMEOfTextChange(uint32_t aStart,
-                                uint32_t aOldEnd,
-                                uint32_t aNewEnd)
+nsresult
+nsWindow::NotifyIMEOfTextChange(const IMENotification& aIMENotification)
 {
+    MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE,
+               "NotifyIMEOfTextChange() is called with invaild notification");
+
     if (mIMEMaskTextUpdate)
         return NS_OK;
 
     ALOGIME("IME: NotifyIMEOfTextChange: s=%d, oe=%d, ne=%d",
-            aStart, aOldEnd, aNewEnd);
+            aIMENotification.mTextChangeData.mStartOffset,
+            aIMENotification.mTextChangeData.mOldEndOffset,
+            aIMENotification.mTextChangeData.mNewEndOffset);
 
     /* Make sure Java's selection is up-to-date */
     mIMESelectionChanged = false;
     NotifyIME(NOTIFY_IME_OF_SELECTION_CHANGE);
     PostFlushIMEChanges();
 
-    mIMETextChanges.AppendElement(IMEChange(aStart, aOldEnd, aNewEnd));
+    mIMETextChanges.AppendElement(IMEChange(aIMENotification));
     // Now that we added a new range we need to go back and
     // update all the ranges before that.
     // Ranges that have offsets which follow this new range
     // need to be updated to reflect new offsets
-    int32_t delta = (int32_t)(aNewEnd - aOldEnd);
+    int32_t delta = aIMENotification.mTextChangeData.AdditionalLength();
     for (int32_t i = mIMETextChanges.Length() - 2; i >= 0; i--) {
         IMEChange &previousChange = mIMETextChanges[i];
-        if (previousChange.mStart > (int32_t)aOldEnd) {
+        if (previousChange.mStart >
+                static_cast<int32_t>(
+                    aIMENotification.mTextChangeData.mOldEndOffset)) {
             previousChange.mStart += delta;
             previousChange.mOldEnd += delta;
             previousChange.mNewEnd += delta;
         }
     }
 
     // Now go through all ranges to merge any ranges that are connected
     // srcIndex is the index of the range to merge from
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -130,24 +130,22 @@ public:
     NS_IMETHOD GetAttention(int32_t aCycleCount) { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD BeginResizeDrag(mozilla::WidgetGUIEvent* aEvent,
                                int32_t aHorizontal,
                                int32_t aVertical)
     {
         return NS_ERROR_NOT_IMPLEMENTED;
     }
 
-    NS_IMETHOD NotifyIME(NotificationToIME aNotification) MOZ_OVERRIDE;
+    NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
     NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                       const InputContextAction& aAction);
     NS_IMETHOD_(InputContext) GetInputContext();
 
-    NS_IMETHOD NotifyIMEOfTextChange(uint32_t aStart,
-                                     uint32_t aOldEnd,
-                                     uint32_t aNewEnd) MOZ_OVERRIDE;
+    nsresult NotifyIMEOfTextChange(const IMENotification& aIMENotification);
     virtual nsIMEUpdatePreference GetIMEUpdatePreference();
 
     LayerManager* GetLayerManager (PLayerTransactionChild* aShadowManager = nullptr,
                                    LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                                    LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                    bool* aAllowRetaining = nullptr);
 
     NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
@@ -205,19 +203,26 @@ protected:
 
     struct IMEChange {
         int32_t mStart, mOldEnd, mNewEnd;
 
         IMEChange() :
             mStart(-1), mOldEnd(-1), mNewEnd(-1)
         {
         }
-        IMEChange(int32_t start, int32_t oldEnd, int32_t newEnd) :
-            mStart(start), mOldEnd(oldEnd), mNewEnd(newEnd)
+        IMEChange(const IMENotification& aIMENotification)
+            : mStart(aIMENotification.mTextChangeData.mStartOffset)
+            , mOldEnd(aIMENotification.mTextChangeData.mOldEndOffset)
+            , mNewEnd(aIMENotification.mTextChangeData.mNewEndOffset)
         {
+            MOZ_ASSERT(aIMENotification.mMessage ==
+                           mozilla::widget::NOTIFY_IME_OF_TEXT_CHANGE,
+                       "IMEChange initialized with wrong notification");
+            MOZ_ASSERT(aIMENotification.mTextChangeData.IsInInt32Range(),
+                       "The text change notification is out of range");
         }
         bool IsEmpty()
         {
             return mStart < 0;
         }
     };
     nsAutoTArray<IMEChange, 4> mIMETextChanges;
     bool mIMESelectionChanged;
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -512,17 +512,17 @@ public:
 
   NS_IMETHOD        GetAttention(int32_t aCycleCount);
 
   virtual bool HasPendingInputEvent();
 
   NS_IMETHOD        ActivateNativeMenuItemAt(const nsAString& indexString);
   NS_IMETHOD        ForceUpdateNativeMenuAt(const nsAString& indexString);
 
-  NS_IMETHOD        NotifyIME(NotificationToIME aNotification) MOZ_OVERRIDE;
+  NS_IMETHOD        NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
   NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                     const InputContextAction& aAction);
   NS_IMETHOD_(InputContext) GetInputContext();
   virtual nsIMEUpdatePreference GetIMEUpdatePreference() MOZ_OVERRIDE;
   NS_IMETHOD        GetToggledKeyState(uint32_t aKeyCode,
                                        bool* aLEDState);
 
   // nsIPluginWidget
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -1853,19 +1853,19 @@ void nsChildView::UpdateCurrentInputEven
 bool nsChildView::HasPendingInputEvent()
 {
   return DoHasPendingInputEvent();
 }
 
 #pragma mark -
 
 NS_IMETHODIMP
-nsChildView::NotifyIME(NotificationToIME aNotification)
-{
-  switch (aNotification) {
+nsChildView::NotifyIME(const IMENotification& aIMENotification)
+{
+  switch (aIMENotification.mMessage) {
     case REQUEST_TO_COMMIT_COMPOSITION:
       NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
       mTextInputHandler->CommitIMEComposition();
       return NS_OK;
     case REQUEST_TO_CANCEL_COMPOSITION:
       NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
       mTextInputHandler->CancelIMEComposition();
       return NS_OK;
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -321,17 +321,17 @@ public:
     virtual bool DragEvent(unsigned int aMessage, Point aMouseGlobal, UInt16 aKeyModifiers);
 
     bool HasModalDescendents() { return mNumModalDescendents > 0; }
     NSWindow *GetCocoaWindow() { return mWindow; }
 
     void SetMenuBar(nsMenuBarX* aMenuBar);
     nsMenuBarX *GetMenuBar();
 
-    NS_IMETHOD NotifyIME(NotificationToIME aNotification) MOZ_OVERRIDE;
+    NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
     NS_IMETHOD_(void) SetInputContext(
                         const InputContext& aContext,
                         const InputContextAction& aAction) MOZ_OVERRIDE;
     NS_IMETHOD_(InputContext) GetInputContext()
     {
       NSView* view = mWindow ? [mWindow contentView] : nil;
       if (view) {
         mInputContext.mNativeIMEContext = [view inputContext];
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -2115,19 +2115,19 @@ bool nsCocoaWindow::ShouldFocusPlugin()
 {
   if (!mWindow || IsChildInFailingLeftClickThrough([mWindow contentView]))
     return false;
 
   return true;
 }
 
 NS_IMETHODIMP
-nsCocoaWindow::NotifyIME(NotificationToIME aNotification)
+nsCocoaWindow::NotifyIME(const IMENotification& aIMENotification)
 {
-  switch (aNotification) {
+  switch (aIMENotification.mMessage) {
     case NOTIFY_IME_OF_FOCUS:
       if (mInputContext.IsPasswordEditor()) {
         TextInputHandler::EnableSecureEventInput();
       }
       return NS_OK;
     case NOTIFY_IME_OF_BLUR:
       // When we're going to be deactive, we must disable the secure event input
       // mode, see the Carbon Event Manager Reference.
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -5860,31 +5860,31 @@ nsChildWindow::nsChildWindow()
 {
 }
 
 nsChildWindow::~nsChildWindow()
 {
 }
 
 NS_IMETHODIMP
-nsWindow::NotifyIME(NotificationToIME aNotification)
+nsWindow::NotifyIME(const IMENotification& aIMENotification)
 {
     if (MOZ_UNLIKELY(!mIMModule)) {
-        switch (aNotification) {
+        switch (aIMENotification.mMessage) {
             case NOTIFY_IME_OF_CURSOR_POS_CHANGED:
             case REQUEST_TO_COMMIT_COMPOSITION:
             case REQUEST_TO_CANCEL_COMPOSITION:
             case NOTIFY_IME_OF_FOCUS:
             case NOTIFY_IME_OF_BLUR:
               return NS_ERROR_NOT_AVAILABLE;
             default:
               break;
         }
     }
-    switch (aNotification) {
+    switch (aIMENotification.mMessage) {
         // TODO: We should replace NOTIFY_IME_OF_CURSOR_POS_CHANGED with
         //       NOTIFY_IME_OF_SELECTION_CHANGE.  The required behavior is
         //       really different from committing composition.
         case NOTIFY_IME_OF_CURSOR_POS_CHANGED:
         case REQUEST_TO_COMMIT_COMPOSITION:
             return mIMModule->CommitIMEComposition(this);
         case REQUEST_TO_CANCEL_COMPOSITION:
             return mIMModule->CancelIMEComposition(this);
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -258,17 +258,17 @@ public:
                                          guint aTime);
     static void        UpdateDragStatus (GdkDragContext *aDragContext,
                                          nsIDragService *aDragService);
     // If this dispatched the keydown event actually, this returns TRUE,
     // otherwise, FALSE.
     bool               DispatchKeyDownEvent(GdkEventKey *aEvent,
                                             bool *aIsCancelled);
 
-    NS_IMETHOD NotifyIME(NotificationToIME aNotification) MOZ_OVERRIDE;
+    NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
     NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                       const InputContextAction& aAction);
     NS_IMETHOD_(InputContext) GetInputContext();
     NS_IMETHOD GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState);
 
     // These methods are for toplevel windows only.
     void               ResizeTransparencyBitmap();
     void               ApplyTransparencyBitmap();
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -95,18 +95,18 @@ typedef void* nsNativeWidget;
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #define NS_NATIVE_ICOREWINDOW          103 // winrt specific
 #endif
 
 #define NS_IWIDGET_IID \
-{ 0x67da44c4, 0xe21b, 0x4742, \
-  { 0x9c, 0x2b, 0x26, 0xc7, 0x70, 0x21, 0xde, 0x87 } }
+{ 0xb979c607, 0xf0aa, 0x4fee, \
+  { 0xb2, 0x7b, 0xd4, 0x46, 0xa2, 0xe, 0x8b, 0x27 } }
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
@@ -202,22 +202,22 @@ enum nsTopLevelWidgetZPlacement { // for
  * notified.
  */
 #define NS_WIDGET_RESUME_PROCESS_OBSERVER_TOPIC "resume_process_notification"
 
 /**
  * Preference for receiving IME updates
  *
  * If mWantUpdates is not NOTIFY_NOTHING, nsTextStateManager will observe text
- * change and/or selection change and call nsIWidget::NotifyIMEOfTextChange()
- * and/or nsIWidget::NotifyIME(NOTIFY_IME_OF_SELECTION_CHANGE).
+ * change and/or selection change and call nsIWidget::NotifyIME() with
+ * NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE.
  * Please note that the text change observing cost is very expensive especially
  * on an HTML editor has focus.
  * If the IME implementation on a particular platform doesn't care about
- * NotifyIMEOfTextChange() and/or NotifyIME(NOTIFY_IME_OF_SELECTION_CHANGE),
+ * NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE,
  * they should set mWantUpdates to NOTIFY_NOTHING to avoid the cost.
  * If the IME implementation needs notifications even while our process is
  * deactive, it should also set NOTIFY_DURING_DEACTIVE.
  */
 struct nsIMEUpdatePreference {
 
   typedef uint8_t Notifications;
 
@@ -443,31 +443,85 @@ struct SizeConstraints {
     mMaxSize(aMaxSize)
   {
   }
 
   nsIntSize mMinSize;
   nsIntSize mMaxSize;
 };
 
-// NotificationToIME is shared by nsIMEStateManager and TextComposition.
-enum NotificationToIME {
+// IMEMessage is shared by nsIMEStateManager and TextComposition.
+// XXX Negative values are used in Android...
+enum IMEMessage MOZ_ENUM_TYPE(int8_t)
+{
   // XXX We should replace NOTIFY_IME_OF_CURSOR_POS_CHANGED with
   //     NOTIFY_IME_OF_SELECTION_CHANGE later.
   NOTIFY_IME_OF_CURSOR_POS_CHANGED,
   // An editable content is getting focus
   NOTIFY_IME_OF_FOCUS,
   // An editable content is losing focus
   NOTIFY_IME_OF_BLUR,
   // Selection in the focused editable content is changed
   NOTIFY_IME_OF_SELECTION_CHANGE,
+  // Text in the focused editable content is changed
+  NOTIFY_IME_OF_TEXT_CHANGE,
+  // Composition string has been updated
+  NOTIFY_IME_OF_COMPOSITION_UPDATE,
+  // Request to commit current composition to IME
+  // (some platforms may not support)
   REQUEST_TO_COMMIT_COMPOSITION,
-  REQUEST_TO_CANCEL_COMPOSITION,
-  // Composition string has been updated
-  NOTIFY_IME_OF_COMPOSITION_UPDATE
+  // Request to cancel current composition to IME
+  // (some platforms may not support)
+  REQUEST_TO_CANCEL_COMPOSITION
+};
+
+struct IMENotification
+{
+  IMENotification(IMEMessage aMessage)
+    : mMessage(aMessage)
+  {
+    switch (aMessage) {
+      case NOTIFY_IME_OF_TEXT_CHANGE:
+        mTextChangeData.mStartOffset = 0;
+        mTextChangeData.mOldEndOffset = 0;
+        mTextChangeData.mNewEndOffset = 0;
+        break;
+      default:
+        break;
+    }
+  }
+
+  IMEMessage mMessage;
+
+  union
+  {
+    // NOTIFY_IME_OF_TEXT_CHANGE specific data
+    struct
+    {
+      uint32_t mStartOffset;
+      uint32_t mOldEndOffset;
+      uint32_t mNewEndOffset;
+
+      uint32_t OldLength() const { return mOldEndOffset - mStartOffset; }
+      uint32_t NewLength() const { return mNewEndOffset - mStartOffset; }
+      int32_t AdditionalLength() const
+      {
+        return static_cast<int32_t>(mNewEndOffset - mOldEndOffset);
+      }
+      bool IsInInt32Range() const
+      {
+        return mStartOffset <= INT32_MAX &&
+               mOldEndOffset <= INT32_MAX &&
+               mNewEndOffset <= INT32_MAX;
+      }
+    } mTextChangeData;
+  };
+
+private:
+  IMENotification();
 };
 
 } // namespace widget
 } // namespace mozilla
 
 /**
  * The base class for all the widgets. It provides the interface for
  * all basic and necessary functionality.
@@ -478,17 +532,18 @@ class nsIWidget : public nsISupports {
 
   public:
     typedef mozilla::layers::Composer2D Composer2D;
     typedef mozilla::layers::CompositorChild CompositorChild;
     typedef mozilla::layers::LayerManager LayerManager;
     typedef mozilla::layers::LayerManagerComposite LayerManagerComposite;
     typedef mozilla::layers::LayersBackend LayersBackend;
     typedef mozilla::layers::PLayerTransactionChild PLayerTransactionChild;
-    typedef mozilla::widget::NotificationToIME NotificationToIME;
+    typedef mozilla::widget::IMEMessage IMEMessage;
+    typedef mozilla::widget::IMENotification IMENotification;
     typedef mozilla::widget::IMEState IMEState;
     typedef mozilla::widget::InputContext InputContext;
     typedef mozilla::widget::InputContextAction InputContextAction;
     typedef mozilla::widget::SizeConstraints SizeConstraints;
 
     // Used in UpdateThemeGeometries.
     struct ThemeGeometry {
       // The -moz-appearance value for the themed widget
@@ -1700,17 +1755,17 @@ public:
      * If this is called with an empty string it forces a full reload of the
      * menu system.
      */
     virtual nsresult ForceUpdateNativeMenuAt(const nsAString& indexString) = 0;
 
     /**
      * Notify IME of the specified notification.
      */
-    NS_IMETHOD NotifyIME(NotificationToIME aNotification) = 0;
+    NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) = 0;
 
     /*
      * Notifies the input context changes.
      */
     NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                       const InputContextAction& aAction) = 0;
 
     /*
@@ -1730,26 +1785,16 @@ public:
      * aLEDState is the result for current LED state of the key.
      * If the LED is 'ON', it returns TRUE, otherwise, FALSE.
      * If the platform doesn't support the LED state (or we cannot get the
      * state), this method returns NS_ERROR_NOT_IMPLEMENTED.
      */
     NS_IMETHOD GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState) = 0;
 
     /*
-     * Text content of the focused node has changed
-     * aStart is the starting offset of the change
-     * aOldEnd is the ending offset of the change
-     * aNewEnd is the caret offset after the change
-     */
-    NS_IMETHOD NotifyIMEOfTextChange(uint32_t aStart,
-                                     uint32_t aOldEnd,
-                                     uint32_t aNewEnd) = 0;
-
-    /*
      * Retrieves preference for IME updates
      */
     virtual nsIMEUpdatePreference GetIMEUpdatePreference() = 0;
 
     /*
      * Call this method when a dialog is opened which has a default button.
      * The button's rectangle should be supplied in aButtonRect.
      */ 
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -22,17 +22,17 @@ namespace widget {
 /******************************************************************************
  * IMEHandler
  ******************************************************************************/
 
 #ifdef NS_ENABLE_TSF
 bool IMEHandler::sIsInTSFMode = false;
 bool IMEHandler::sIsIMMEnabled = true;
 bool IMEHandler::sPluginHasFocus = false;
-IMEHandler::SetInputScopesFunc IMEHandler::sSetInputScopes = nullptr;
+decltype(SetInputScopes)* IMEHandler::sSetInputScopes = nullptr;
 #endif // #ifdef NS_ENABLE_TSF
 
 // static
 void
 IMEHandler::Initialize()
 {
 #ifdef NS_ENABLE_TSF
   nsTextStore::Initialize();
@@ -41,17 +41,17 @@ IMEHandler::Initialize()
     !sIsInTSFMode || Preferences::GetBool("intl.tsf.support_imm", true);
   if (!sIsInTSFMode) {
     // When full nsTextStore is not available, try to use SetInputScopes API
     // to enable at least InputScope. Use GET_MODULE_HANDLE_EX_FLAG_PIN to
     // ensure that msctf.dll will not be unloaded.
     HMODULE module = nullptr;
     if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, L"msctf.dll",
                            &module)) {
-      sSetInputScopes = reinterpret_cast<SetInputScopesFunc>(
+      sSetInputScopes = reinterpret_cast<decltype(SetInputScopes)*>(
         GetProcAddress(module, "SetInputScopes"));
     }
   }
 #endif // #ifdef NS_ENABLE_TSF
 
   nsIMM32Handler::Initialize();
 }
 
@@ -153,23 +153,25 @@ IMEHandler::IsComposingOn(nsWindow* aWin
 #endif // #ifdef NS_ENABLE_TSF
 
   return nsIMM32Handler::IsComposingOn(aWindow);
 }
 
 // static
 nsresult
 IMEHandler::NotifyIME(nsWindow* aWindow,
-                      NotificationToIME aNotification)
+                      const IMENotification& aIMENotification)
 {
 #ifdef NS_ENABLE_TSF
   if (IsTSFAvailable()) {
-    switch (aNotification) {
+    switch (aIMENotification.mMessage) {
       case NOTIFY_IME_OF_SELECTION_CHANGE:
         return nsTextStore::OnSelectionChange();
+      case NOTIFY_IME_OF_TEXT_CHANGE:
+        return nsTextStore::OnTextChange(aIMENotification);
       case NOTIFY_IME_OF_FOCUS:
         return nsTextStore::OnFocusChange(true, aWindow,
                  aWindow->GetInputContext().mIMEState.mEnabled);
       case NOTIFY_IME_OF_BLUR:
         return nsTextStore::OnFocusChange(false, aWindow,
                  aWindow->GetInputContext().mIMEState.mEnabled);
       case REQUEST_TO_COMMIT_COMPOSITION:
         if (nsTextStore::IsComposingOn(aWindow)) {
@@ -182,17 +184,17 @@ IMEHandler::NotifyIME(nsWindow* aWindow,
         }
         return NS_OK;
       default:
         return NS_ERROR_NOT_IMPLEMENTED;
     }
   }
 #endif //NS_ENABLE_TSF
 
-  switch (aNotification) {
+  switch (aIMENotification.mMessage) {
     case REQUEST_TO_COMMIT_COMPOSITION:
       nsIMM32Handler::CommitComposition(aWindow);
       return NS_OK;
     case REQUEST_TO_CANCEL_COMPOSITION:
       nsIMM32Handler::CancelComposition(aWindow);
       return NS_OK;
     case NOTIFY_IME_OF_COMPOSITION_UPDATE:
       nsIMM32Handler::OnUpdateComposition(aWindow);
@@ -208,31 +210,16 @@ IMEHandler::NotifyIME(nsWindow* aWindow,
       return NS_ERROR_NOT_IMPLEMENTED;
 #endif //NS_ENABLE_TSF
     default:
       return NS_ERROR_NOT_IMPLEMENTED;
   }
 }
 
 // static
-nsresult
-IMEHandler::NotifyIMEOfTextChange(uint32_t aStart,
-                                  uint32_t aOldEnd,
-                                  uint32_t aNewEnd)
-{
-#ifdef NS_ENABLE_TSF
-  if (IsTSFAvailable()) {
-    return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
-  }
-#endif //NS_ENABLE_TSF
-
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-// static
 nsIMEUpdatePreference
 IMEHandler::GetUpdatePreference()
 {
 #ifdef NS_ENABLE_TSF
   if (IsTSFAvailable()) {
     return nsTextStore::GetIMEUpdatePreference();
   }
 #endif //NS_ENABLE_TSF
@@ -272,17 +259,17 @@ IMEHandler::OnDestroyWindow(nsWindow* aW
 
 // static
 void
 IMEHandler::SetInputContext(nsWindow* aWindow,
                             InputContext& aInputContext,
                             const InputContextAction& aAction)
 {
   // FYI: If there is no composition, this call will do nothing.
-  NotifyIME(aWindow, REQUEST_TO_COMMIT_COMPOSITION);
+  NotifyIME(aWindow, IMENotification(REQUEST_TO_COMMIT_COMPOSITION));
 
   const InputContext& oldInputContext = aWindow->GetInputContext();
 
   // Assume that SetInputContext() is called only when aWindow has focus.
   sPluginHasFocus = (aInputContext.mIMEState.mEnabled == IMEState::PLUGIN);
 
   bool enable = WinUtils::IsIMEEnabled(aInputContext);
   bool adjustOpenState = (enable &&
--- a/widget/windows/WinIMEHandler.h
+++ b/widget/windows/WinIMEHandler.h
@@ -63,24 +63,17 @@ public:
    * Otherwise, false.
    */
   static bool IsComposingOn(nsWindow* aWindow);
 
   /**
    * Notifies IME of the notification (a request or an event).
    */
   static nsresult NotifyIME(nsWindow* aWindow,
-                            NotificationToIME aNotification);
-
-  /**
-   * Notifies IME of text change in the focused editable content.
-   */
-  static nsresult NotifyIMEOfTextChange(uint32_t aStart,
-                                        uint32_t aOldEnd,
-                                        uint32_t aNewEnd);
+                            const IMENotification& aIMENotification);
 
   /**
    * Returns update preferences.
    */
   static nsIMEUpdatePreference GetUpdatePreference();
 
   /**
    * Returns IME open state on the window.
@@ -114,24 +107,17 @@ public:
   /**
    * Returns true when current keyboard layout has IME.  Otherwise, false.
    */
   static bool CurrentKeyboardLayoutHasIME();
 #endif // #ifdef DEBUG
 
 private:
 #ifdef NS_ENABLE_TSF
-  typedef HRESULT (WINAPI *SetInputScopesFunc)(HWND windowHandle,
-                                               const InputScope *inputScopes,
-                                               UINT numInputScopes,
-                                               wchar_t **phrase_list,
-                                               UINT numPhraseList,
-                                               wchar_t *regExp,
-                                               wchar_t *srgs);
-  static SetInputScopesFunc sSetInputScopes;
+  static decltype(SetInputScopes)* sSetInputScopes;
   static void SetInputScopeForIMM32(nsWindow* aWindow,
                                     const nsAString& aHTMLInputType);
   static bool sIsInTSFMode;
   // If sIMMEnabled is false, any IME messages are not handled in TSF mode.
   // Additionally, IME context is always disassociated from focused window.
   static bool sIsIMMEnabled;
   static bool sPluginHasFocus;
 
--- a/widget/windows/nsTextStore.cpp
+++ b/widget/windows/nsTextStore.cpp
@@ -3181,39 +3181,41 @@ nsTextStore::GetIMEUpdatePreference()
                        nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE |
                        nsIMEUpdatePreference::NOTIFY_DURING_DEACTIVE);
     }
   }
   return nsIMEUpdatePreference(notifications);
 }
 
 nsresult
-nsTextStore::OnTextChangeInternal(uint32_t aStart,
-                                  uint32_t aOldEnd,
-                                  uint32_t aNewEnd)
+nsTextStore::OnTextChangeInternal(const IMENotification& aIMENotification)
 {
   PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
-         ("TSF: 0x%p   nsTextStore::OnTextChangeInternal(aStart=%lu, "
-          "aOldEnd=%lu, aNewEnd=%lu), mSink=0x%p, mSinkMask=%s, "
+         ("TSF: 0x%p   nsTextStore::OnTextChangeInternal(aIMENotification={ "
+          "mMessage=0x%08X, mTextChangeData={ mStartOffset=%lu, "
+          "mOldEndOffset=%lu, mNewEndOffset=%lu}), mSink=0x%p, mSinkMask=%s, "
           "mComposition.IsComposing()=%s",
-          this, aStart, aOldEnd, aNewEnd, mSink.get(),
+          this, aIMENotification.mMessage,
+          aIMENotification.mTextChangeData.mStartOffset,
+          aIMENotification.mTextChangeData.mOldEndOffset,
+          aIMENotification.mTextChangeData.mNewEndOffset, mSink.get(),
           GetSinkMaskNameStr(mSinkMask).get(),
           GetBoolName(mComposition.IsComposing())));
 
   if (IsReadLocked()) {
     return NS_OK;
   }
 
   mSelection.MarkDirty();
 
   if (!mSink || !(mSinkMask & TS_AS_TEXT_CHANGE)) {
     return NS_OK;
   }
 
-  if (aStart >= INT32_MAX || aOldEnd >= INT32_MAX || aNewEnd >= INT32_MAX) {
+  if (!aIMENotification.mTextChangeData.IsInInt32Range()) {
     PR_LOG(sTextStoreLog, PR_LOG_ERROR,
            ("TSF: 0x%p   nsTextStore::OnTextChangeInternal() FAILED due to "
             "offset is too big for calling mSink->OnTextChange()...",
             this));
     return NS_OK;
   }
 
   // Some TIPs are confused by text change notification during composition.
@@ -3224,22 +3226,25 @@ nsTextStore::OnTextChangeInternal(uint32
            ("TSF: 0x%p   nsTextStore::OnTextChangeInternal(), "
             "committing the composition for avoiding making TIP confused...",
             this));
     CommitCompositionInternal(false);
     return NS_OK;
   }
 
   TS_TEXTCHANGE textChange;
-  textChange.acpStart = static_cast<LONG>(aStart);
-  textChange.acpOldEnd = static_cast<LONG>(aOldEnd);
-  textChange.acpNewEnd = static_cast<LONG>(aNewEnd);
+  textChange.acpStart =
+    static_cast<LONG>(aIMENotification.mTextChangeData.mStartOffset);
+  textChange.acpOldEnd =
+    static_cast<LONG>(aIMENotification.mTextChangeData.mOldEndOffset);
+  textChange.acpNewEnd =
+    static_cast<LONG>(aIMENotification.mTextChangeData.mNewEndOffset);
 
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: 0x%p   nsTextStore::OnTextChangeInternal(), calling"
+         ("TSF: 0x%p   nsTextStore::OnTextChangeInternal(), calling "
           "mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, "
           "acpNewEnd=%ld })...", this, textChange.acpStart,
           textChange.acpOldEnd, textChange.acpNewEnd));
   mSink->OnTextChange(0, &textChange);
 
   return NS_OK;
 }
 
--- a/widget/windows/nsTextStore.h
+++ b/widget/windows/nsTextStore.h
@@ -100,16 +100,17 @@ public: /*ITfActiveLanguageProfileNotify
   STDMETHODIMP OnActivated(REFCLSID clsid, REFGUID guidProfile,
                            BOOL fActivated);
 
 public: /*ITfInputProcessorProfileActivationSink*/
   STDMETHODIMP OnActivated(DWORD, LANGID, REFCLSID, REFGUID, REFGUID,
                            HKL, DWORD);
 
 protected:
+  typedef mozilla::widget::IMENotification IMENotification;
   typedef mozilla::widget::IMEState IMEState;
   typedef mozilla::widget::InputContext InputContext;
   typedef mozilla::widget::InputContextAction InputContextAction;
 
 public:
   static void     Initialize(void);
   static void     Terminate(void);
 
@@ -130,22 +131,20 @@ public:
 
   static void SetInputContext(nsWindowBase* aWidget,
                               const InputContext& aContext,
                               const InputContextAction& aAction);
 
   static nsresult OnFocusChange(bool aGotFocus,
                                 nsWindowBase* aFocusedWidget,
                                 IMEState::Enabled aIMEEnabled);
-  static nsresult OnTextChange(uint32_t aStart,
-                               uint32_t aOldEnd,
-                               uint32_t aNewEnd)
+  static nsresult OnTextChange(const IMENotification& aIMENotification)
   {
     NS_ENSURE_TRUE(sTsfTextStore, NS_ERROR_NOT_AVAILABLE);
-    return sTsfTextStore->OnTextChangeInternal(aStart, aOldEnd, aNewEnd);
+    return sTsfTextStore->OnTextChangeInternal(aIMENotification);
   }
 
   static nsresult OnSelectionChange(void)
   {
     NS_ENSURE_TRUE(sTsfTextStore, NS_ERROR_NOT_AVAILABLE);
     return sTsfTextStore->OnSelectionChangeInternal();
   }
 
@@ -253,17 +252,17 @@ protected:
   // this is called during IME composing.  aDispatchTextEvent should be true
   // only when this is called from SetSelection.  Because otherwise, the text
   // event should not be sent from here.
   HRESULT  SetSelectionInternal(const TS_SELECTION_ACP*,
                                 bool aDispatchTextEvent = false);
   bool     InsertTextAtSelectionInternal(const nsAString &aInsertStr,
                                          TS_TEXTCHANGE* aTextChange);
   void     CommitCompositionInternal(bool);
-  nsresult OnTextChangeInternal(uint32_t, uint32_t, uint32_t);
+  nsresult OnTextChangeInternal(const IMENotification& aIMENotification);
   nsresult OnSelectionChangeInternal(void);
   HRESULT  GetDisplayAttribute(ITfProperty* aProperty,
                                ITfRange* aRange,
                                TF_DISPLAYATTRIBUTE* aResult);
   HRESULT  RestartCompositionIfNecessary(ITfRange* pRangeNew = nullptr);
 
   // Following methods record composing action(s) to mPendingActions.
   // They will be flushed FlushPendingActions().
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -6609,19 +6609,19 @@ nsWindow::OnSysColorChanged()
  ** BLOCK: IME management and accessibility
  **
  ** Handles managing IME input and accessibility.
  **
  **************************************************************
  **************************************************************/
 
 NS_IMETHODIMP
-nsWindow::NotifyIME(NotificationToIME aNotification)
-{
-  return IMEHandler::NotifyIME(this, aNotification);
+nsWindow::NotifyIME(const IMENotification& aIMENotification)
+{
+  return IMEHandler::NotifyIME(this, aIMENotification);
 }
 
 NS_IMETHODIMP_(void)
 nsWindow::SetInputContext(const InputContext& aContext,
                           const InputContextAction& aAction)
 {
   InputContext newInputContext = aContext;
   IMEHandler::SetInputContext(this, newInputContext, aAction);
@@ -6646,24 +6646,16 @@ nsWindow::GetToggledKeyState(uint32_t aK
 #ifdef DEBUG_KBSTATE
   PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("GetToggledKeyState\n"));
 #endif 
   NS_ENSURE_ARG_POINTER(aLEDState);
   *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsWindow::NotifyIMEOfTextChange(uint32_t aStart,
-                                uint32_t aOldEnd,
-                                uint32_t aNewEnd)
-{
-  return IMEHandler::NotifyIMEOfTextChange(aStart, aOldEnd, aNewEnd);
-}
-
 nsIMEUpdatePreference
 nsWindow::GetIMEUpdatePreference()
 {
   return IMEHandler::GetUpdatePreference();
 }
 
 #ifdef ACCESSIBILITY
 #ifdef DEBUG
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -172,31 +172,28 @@ public:
 
   virtual nsresult        SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint,
                                                            uint32_t aNativeMessage,
                                                            double aDeltaX,
                                                            double aDeltaY,
                                                            double aDeltaZ,
                                                            uint32_t aModifierFlags,
                                                            uint32_t aAdditionalFlags);
-  NS_IMETHOD              NotifyIME(NotificationToIME aNotification) MOZ_OVERRIDE;
+  NS_IMETHOD              NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
   NS_IMETHOD_(void)       SetInputContext(const InputContext& aContext,
                                           const InputContextAction& aAction);
   NS_IMETHOD_(InputContext) GetInputContext();
   NS_IMETHOD              GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState);
   NS_IMETHOD              RegisterTouchWindow();
   NS_IMETHOD              UnregisterTouchWindow();
 #ifdef MOZ_XUL
   virtual void            SetTransparencyMode(nsTransparencyMode aMode);
   virtual nsTransparencyMode GetTransparencyMode();
   virtual void            UpdateOpaqueRegion(const nsIntRegion& aOpaqueRegion);
 #endif // MOZ_XUL
-  NS_IMETHOD              NotifyIMEOfTextChange(uint32_t aStart,
-                                                uint32_t aOldEnd,
-                                                uint32_t aNewEnd) MOZ_OVERRIDE;
   virtual nsIMEUpdatePreference GetIMEUpdatePreference();
   NS_IMETHOD              GetNonClientMargins(nsIntMargin &margins);
   NS_IMETHOD              SetNonClientMargins(nsIntMargin &margins);
   void                    SetDrawsInTitlebar(bool aState);
   mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing() MOZ_OVERRIDE;
   virtual void            EndRemoteDrawing() MOZ_OVERRIDE;
 
   /**
--- a/widget/windows/winrt/MetroWidget.cpp
+++ b/widget/windows/winrt/MetroWidget.cpp
@@ -1581,54 +1581,48 @@ MetroWidget::SetInputContext(const Input
 
 NS_IMETHODIMP_(nsIWidget::InputContext)
 MetroWidget::GetInputContext()
 {
   return mInputContext;
 }
 
 NS_IMETHODIMP
-MetroWidget::NotifyIME(NotificationToIME aNotification)
+MetroWidget::NotifyIME(const IMENotification& aIMENotification)
 {
-  switch (aNotification) {
+  switch (aIMENotification.mMessage) {
     case REQUEST_TO_COMMIT_COMPOSITION:
       nsTextStore::CommitComposition(false);
       return NS_OK;
     case REQUEST_TO_CANCEL_COMPOSITION:
       nsTextStore::CommitComposition(true);
       return NS_OK;
     case NOTIFY_IME_OF_FOCUS:
       return nsTextStore::OnFocusChange(true, this,
                                         mInputContext.mIMEState.mEnabled);
     case NOTIFY_IME_OF_BLUR:
       return nsTextStore::OnFocusChange(false, this,
                                         mInputContext.mIMEState.mEnabled);
     case NOTIFY_IME_OF_SELECTION_CHANGE:
       return nsTextStore::OnSelectionChange();
+    case NOTIFY_IME_OF_TEXT_CHANGE:
+      return nsTextStore::OnTextChange(aIMENotification);
     default:
       return NS_ERROR_NOT_IMPLEMENTED;
   }
 }
 
 NS_IMETHODIMP
 MetroWidget::GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState)
 {
   NS_ENSURE_ARG_POINTER(aLEDState);
   *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-MetroWidget::NotifyIMEOfTextChange(uint32_t aStart,
-                                   uint32_t aOldEnd,
-                                   uint32_t aNewEnd)
-{
-  return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
-}
-
 nsIMEUpdatePreference
 MetroWidget::GetIMEUpdatePreference()
 {
   return nsTextStore::GetIMEUpdatePreference();
 }
 
 NS_IMETHODIMP
 MetroWidget::ReparentNativeWidget(nsIWidget* aNewParent)
--- a/widget/windows/winrt/MetroWidget.h
+++ b/widget/windows/winrt/MetroWidget.h
@@ -155,21 +155,18 @@ public:
                                         LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                         bool* aAllowRetaining = nullptr);
   virtual void GetPreferredCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aHints) { aHints.AppendElement(mozilla::layers::LayersBackend::LAYERS_D3D11); }
 
   // IME related interfaces
   NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                     const InputContextAction& aAction);
   NS_IMETHOD_(nsIWidget::InputContext) GetInputContext();
-  NS_IMETHOD    NotifyIME(NotificationToIME aNotification) MOZ_OVERRIDE;
+  NS_IMETHOD    NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
   NS_IMETHOD    GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState);
-  NS_IMETHOD    NotifyIMEOfTextChange(uint32_t aStart,
-                                      uint32_t aOldEnd,
-                                      uint32_t aNewEnd) MOZ_OVERRIDE;
   virtual nsIMEUpdatePreference GetIMEUpdatePreference() MOZ_OVERRIDE;
 
   // FrameworkView helpers
   void SizeModeChanged();
   void Activated(bool aActiveated);
   void Paint(const nsIntRegion& aInvalidRegion);
 
   MetroWidget* MetroWidget::GetTopLevelWindow(bool aStopOnDialogOrPopup) { return this; }
--- a/widget/xpwidgets/PuppetWidget.cpp
+++ b/widget/xpwidgets/PuppetWidget.cpp
@@ -372,30 +372,32 @@ PuppetWidget::IMEEndComposition(bool aCa
   WidgetCompositionEvent compEvent(true, NS_COMPOSITION_END, this);
   InitEvent(compEvent, nullptr);
   compEvent.mSeqno = mIMELastReceivedSeqno;
   DispatchEvent(&compEvent, status);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PuppetWidget::NotifyIME(NotificationToIME aNotification)
+PuppetWidget::NotifyIME(const IMENotification& aIMENotification)
 {
-  switch (aNotification) {
+  switch (aIMENotification.mMessage) {
     case NOTIFY_IME_OF_CURSOR_POS_CHANGED:
     case REQUEST_TO_COMMIT_COMPOSITION:
       return IMEEndComposition(false);
     case REQUEST_TO_CANCEL_COMPOSITION:
       return IMEEndComposition(true);
     case NOTIFY_IME_OF_FOCUS:
       return NotifyIMEOfFocusChange(true);
     case NOTIFY_IME_OF_BLUR:
       return NotifyIMEOfFocusChange(false);
     case NOTIFY_IME_OF_SELECTION_CHANGE:
       return NotifyIMEOfSelectionChange();
+    case NOTIFY_IME_OF_TEXT_CHANGE:
+      return NotifyIMEOfTextChange(aIMENotification);
     case NOTIFY_IME_OF_COMPOSITION_UPDATE:
       return NotifyIMEOfUpdateComposition();
     default:
       return NS_ERROR_NOT_IMPLEMENTED;
   }
 }
 
 NS_IMETHODIMP_(void)
@@ -521,20 +523,18 @@ PuppetWidget::GetIMEUpdatePreference()
                                nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE |
                                nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE);
 #else
   // B2G doesn't handle IME as widget-level.
   return nsIMEUpdatePreference();
 #endif
 }
 
-NS_IMETHODIMP
-PuppetWidget::NotifyIMEOfTextChange(uint32_t aStart,
-                                    uint32_t aEnd,
-                                    uint32_t aNewEnd)
+nsresult
+PuppetWidget::NotifyIMEOfTextChange(const IMENotification& aIMENotification)
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
 
   if (!mTabChild)
     return NS_ERROR_FAILURE;
 
@@ -546,17 +546,20 @@ PuppetWidget::NotifyIMEOfTextChange(uint
 
   if (queryEvent.mSucceeded) {
     mTabChild->SendNotifyIMETextHint(queryEvent.mReply.mString);
   }
 
   // TabParent doesn't this this to cache.  we don't send the notification
   // if parent process doesn't request NOTIFY_TEXT_CHANGE.
   if (mIMEPreferenceOfParent.WantTextChange()) {
-    mTabChild->SendNotifyIMETextChange(aStart, aEnd, aNewEnd);
+    mTabChild->SendNotifyIMETextChange(
+      aIMENotification.mTextChangeData.mStartOffset,
+      aIMENotification.mTextChangeData.mOldEndOffset,
+      aIMENotification.mTextChangeData.mNewEndOffset);
   }
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::NotifyIMEOfSelectionChange()
 {
 #ifndef MOZ_CROSS_PROCESS_IME
--- a/widget/xpwidgets/PuppetWidget.h
+++ b/widget/xpwidgets/PuppetWidget.h
@@ -144,22 +144,20 @@ public:
 
   virtual LayerManager*
   GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                   LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                   LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                   bool* aAllowRetaining = nullptr);
   virtual gfxASurface*      GetThebesSurface();
 
-  NS_IMETHOD NotifyIME(NotificationToIME aNotification) MOZ_OVERRIDE;
+  NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
   NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                     const InputContextAction& aAction);
   NS_IMETHOD_(InputContext) GetInputContext();
-  NS_IMETHOD NotifyIMEOfTextChange(uint32_t aOffset, uint32_t aEnd,
-                                   uint32_t aNewEnd) MOZ_OVERRIDE;
   virtual nsIMEUpdatePreference GetIMEUpdatePreference() MOZ_OVERRIDE;
 
   NS_IMETHOD SetCursor(nsCursor aCursor);
   NS_IMETHOD SetCursor(imgIContainer* aCursor,
                        uint32_t aHotspotX, uint32_t aHotspotY)
   {
     return nsBaseWidget::SetCursor(aCursor, aHotspotX, aHotspotY);
   }
@@ -179,16 +177,17 @@ private:
   nsresult Paint();
 
   void SetChild(PuppetWidget* aChild);
 
   nsresult IMEEndComposition(bool aCancel);
   nsresult NotifyIMEOfFocusChange(bool aFocus);
   nsresult NotifyIMEOfSelectionChange();
   nsresult NotifyIMEOfUpdateComposition();
+  nsresult NotifyIMEOfTextChange(const IMENotification& aIMENotification);
 
   class PaintTask : public nsRunnable {
   public:
     NS_DECL_NSIRUNNABLE
     PaintTask(PuppetWidget* widget) : mWidget(widget) {}
     void Revoke() { mWidget = nullptr; }
   private:
     PuppetWidget* mWidget;
--- a/widget/xpwidgets/nsBaseWidget.h
+++ b/widget/xpwidgets/nsBaseWidget.h
@@ -181,22 +181,21 @@ public:
   virtual bool            ShowsResizeIndicator(nsIntRect* aResizerRect);
   virtual void            FreeNativeData(void * data, uint32_t aDataType) {}
   NS_IMETHOD              BeginResizeDrag(mozilla::WidgetGUIEvent* aEvent,
                                           int32_t aHorizontal,
                                           int32_t aVertical);
   NS_IMETHOD              BeginMoveDrag(mozilla::WidgetMouseEvent* aEvent);
   virtual nsresult        ActivateNativeMenuItemAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult        ForceUpdateNativeMenuAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
-  NS_IMETHOD              NotifyIME(NotificationToIME aNotification) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
+  NS_IMETHOD              NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              SetLayersAcceleration(bool aEnabled);
   virtual bool            GetLayersAcceleration() { return mUseLayersAcceleration; }
   virtual bool            ComputeShouldAccelerate(bool aDefault);
   NS_IMETHOD              GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState) { return NS_ERROR_NOT_IMPLEMENTED; }
-  NS_IMETHOD              NotifyIMEOfTextChange(uint32_t aStart, uint32_t aOldEnd, uint32_t aNewEnd) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsIMEUpdatePreference GetIMEUpdatePreference() MOZ_OVERRIDE { return nsIMEUpdatePreference(); }
   NS_IMETHOD              OnDefaultButtonLoaded(const nsIntRect &aButtonRect) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              OverrideSystemMouseScrollSpeed(double aOriginalDeltaX,
                                                          double aOriginalDeltaY,
                                                          double& aOverriddenDeltaX,
                                                          double& aOverriddenDeltaY);
   virtual already_AddRefed<nsIWidget>
   CreateChild(const nsIntRect  &aRect,
--- a/widget/xpwidgets/nsFilePickerProxy.cpp
+++ b/widget/xpwidgets/nsFilePickerProxy.cpp
@@ -1,170 +1,176 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 4; 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/. */
 
-#include "mozilla/dom/ContentChild.h"
 #include "nsFilePickerProxy.h"
+#include "nsComponentManagerUtils.h"
 #include "nsNetUtil.h"
+#include "nsIFile.h"
+#include "mozilla/dom/TabChild.h"
 
+using namespace mozilla::dom;
 
 NS_IMPL_ISUPPORTS1(nsFilePickerProxy, nsIFilePicker)
 
 nsFilePickerProxy::nsFilePickerProxy()
-{ 
+{
 }
 
 nsFilePickerProxy::~nsFilePickerProxy()
 {
 }
 
 NS_IMETHODIMP
-nsFilePickerProxy::Init(nsIDOMWindow* /*aParent*/, const nsAString& aTitle,
+nsFilePickerProxy::Init(nsIDOMWindow* aParent, const nsAString& aTitle,
                         int16_t aMode)
 {
-    mTitle = aTitle;
-    mMode = aMode;
+  TabChild* tabChild = TabChild::GetFrom(aParent);
+  if (!tabChild) {
+    return NS_ERROR_FAILURE;
+  }
 
-    return NS_OK;
+  mMode = aMode;
+
+  NS_ADDREF_THIS();
+  tabChild->SendPFilePickerConstructor(this, nsString(aTitle), aMode);
+  return NS_OK;
 }
 
-void nsFilePickerProxy::InitNative(nsIWidget* aParent, const nsAString& aTitle)
+void
+nsFilePickerProxy::InitNative(nsIWidget* aParent, const nsAString& aTitle)
 {
 }
 
-
 NS_IMETHODIMP
 nsFilePickerProxy::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
 {
-    mFilters.AppendElement(aFilter);
-    mFilterNames.AppendElement(aTitle);  
-    return NS_OK;
+  mFilterNames.AppendElement(aTitle);
+  mFilters.AppendElement(aFilter);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::GetDefaultString(nsAString& aDefaultString)
 {
-    aDefaultString = mDefault;
-    return NS_OK;
+  aDefaultString = mDefault;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::SetDefaultString(const nsAString& aDefaultString)
 {
-    mDefault = aDefaultString;
-    return NS_OK;
+  mDefault = aDefaultString;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::GetDefaultExtension(nsAString& aDefaultExtension)
 {
-    aDefaultExtension = mDefaultExtension;
-    return NS_OK;
+  aDefaultExtension = mDefaultExtension;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::SetDefaultExtension(const nsAString& aDefaultExtension)
 {
-    mDefaultExtension = aDefaultExtension;
-    return NS_OK;
+  mDefaultExtension = aDefaultExtension;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::GetFilterIndex(int32_t* aFilterIndex)
 {
-    *aFilterIndex = mSelectedType;
-    return NS_OK;
+  *aFilterIndex = mSelectedType;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFilePickerProxy::SetFilterIndex(int32_t aFilterIndex)
 {
-    mSelectedType = aFilterIndex;
-    return NS_OK;
+  mSelectedType = aFilterIndex;
+  return NS_OK;
 }
 
 /* readonly attribute nsIFile file; */
 NS_IMETHODIMP
 nsFilePickerProxy::GetFile(nsIFile** aFile)
 {
-    NS_ENSURE_ARG_POINTER(aFile);
-
-    *aFile = nullptr;
-    if (mFile.IsEmpty()) {
-        return NS_OK;
-    }
+  NS_ENSURE_ARG_POINTER(aFile);
 
-    nsCOMPtr<nsIFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
-    NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
+  *aFile = nullptr;
+  if (mFiles.IsEmpty()) {
+      return NS_OK;
+  }
 
-    file->InitWithPath(mFile);
-
-    file.forget(aFile);
-
-    return NS_OK;
+  nsCOMPtr<nsIFile> file = mFiles[0];
+  file.forget(aFile);
+  return NS_OK;
 }
 
 /* readonly attribute nsIFileURL fileURL; */
 NS_IMETHODIMP
 nsFilePickerProxy::GetFileURL(nsIURI** aFileURL)
 {
-    nsCOMPtr<nsIFile> file;
-    GetFile(getter_AddRefs(file));
+  nsCOMPtr<nsIFile> file;
+  GetFile(getter_AddRefs(file));
 
-    nsCOMPtr<nsIURI> uri;
-    NS_NewFileURI(getter_AddRefs(uri), file);
-    NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIURI> uri;
+  NS_NewFileURI(getter_AddRefs(uri), file);
+  NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
 
-    return CallQueryInterface(uri, aFileURL);
+  return CallQueryInterface(uri, aFileURL);
 }
 
 /* readonly attribute nsISimpleEnumerator files; */
 NS_IMETHODIMP
 nsFilePickerProxy::GetFiles(nsISimpleEnumerator** aFiles)
 {
-    NS_ENSURE_ARG_POINTER(aFiles);
+  NS_ENSURE_ARG_POINTER(aFiles);
+
+  if (mMode == nsIFilePicker::modeOpenMultiple) {
+    return NS_NewArrayEnumerator(aFiles, mFiles);
+  }
 
-    if (mMode == nsIFilePicker::modeOpenMultiple) {
-        return NS_NewArrayEnumerator(aFiles, mFiles);
-    }
+  return NS_ERROR_FAILURE;
+}
 
-    return NS_ERROR_FAILURE;
+NS_IMETHODIMP
+nsFilePickerProxy::Show(int16_t* aReturn)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-NS_IMETHODIMP nsFilePickerProxy::Show(int16_t* aReturn)
+NS_IMETHODIMP
+nsFilePickerProxy::Open(nsIFilePickerShownCallback* aCallback)
 {
-    mozilla::dom::ContentChild *cc = mozilla::dom::ContentChild::GetSingleton();
-    NS_ASSERTION(cc, "Content Protocol is NULL!");
-    
-    InfallibleTArray<nsString> filePaths;
-    
-    nsresult rv;
-    cc->SendShowFilePicker(mMode, mSelectedType,
-                           mAddToRecentDocs, mTitle,
-                           mDefault, mDefaultExtension,
-                           mFilters, mFilterNames,
-                           &filePaths, aReturn, &rv);
+  mCallback = aCallback;
 
-    NS_ENSURE_SUCCESS(rv, rv);
+  SendOpen(mSelectedType, mAddToRecentDocs, mDefault,
+           mDefaultExtension, mFilters, mFilterNames);
+
+  return NS_OK;
+}
 
-    uint32_t count = filePaths.Length();
-    
-    if (mMode == nsIFilePicker::modeOpenMultiple) {
-        for (uint32_t i = 0; i < count; ++i) {
-            nsCOMPtr<nsIFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
-            NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
+bool
+nsFilePickerProxy::Recv__delete__(const MaybeInputFiles& aFiles,
+                                  const int16_t& aResult)
+{
+  if (aFiles.type() == MaybeInputFiles::TInputFiles) {
+    const InfallibleTArray<nsString>& files = aFiles.get_InputFiles().files();
+    for (uint32_t i = 0; i < files.Length(); ++i) {
+      nsCOMPtr<nsIFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
+      NS_ENSURE_TRUE(file, true);
+      file->InitWithPath(files[i]);
+      mFiles.AppendObject(file);
+    }
+  }
 
-            file->InitWithPath(filePaths[i]);
-            mFiles.AppendObject(file);
-        }
-        return NS_OK;
-    }
+  if (mCallback) {
+    mCallback->Done(aResult);
+    mCallback = nullptr;
+  }
 
-    NS_ASSERTION(count == 1 || count == 0, "we should only have 1 or 0 files");
-
-    if (count == 1)
-        mFile = filePaths[0];
-    
-    return NS_OK;
+  return true;
 }
--- a/widget/xpwidgets/nsFilePickerProxy.h
+++ b/widget/xpwidgets/nsFilePickerProxy.h
@@ -7,55 +7,63 @@
 #define NSFILEPICKERPROXY_H
 
 #include "nsBaseFilePicker.h"
 #include "nsString.h"
 #include "nsIURI.h"
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 
+#include "mozilla/dom/PFilePickerChild.h"
+
 class nsIWidget;
 class nsIFile;
 
 /**
   This class creates a proxy file picker to be used in content processes.
   The file picker just collects the initialization data and when Show() is
   called, remotes everything to the chrome process which in turn can show a
   platform specific file picker.
 */
-class nsFilePickerProxy : public nsBaseFilePicker
+class nsFilePickerProxy : public nsBaseFilePicker,
+                          public mozilla::dom::PFilePickerChild
 {
 public:
     nsFilePickerProxy();
 
     NS_DECL_ISUPPORTS
 
     // nsIFilePicker (less what's in nsBaseFilePicker)
-    NS_IMETHODIMP Init(nsIDOMWindow* parent, const nsAString& title, int16_t mode);
+    NS_IMETHODIMP Init(nsIDOMWindow* aParent, const nsAString& aTitle, int16_t aMode);
     NS_IMETHODIMP AppendFilter(const nsAString& aTitle, const nsAString& aFilter);
     NS_IMETHODIMP GetDefaultString(nsAString& aDefaultString);
     NS_IMETHODIMP SetDefaultString(const nsAString& aDefaultString);
     NS_IMETHODIMP GetDefaultExtension(nsAString& aDefaultExtension);
     NS_IMETHODIMP SetDefaultExtension(const nsAString& aDefaultExtension);
     NS_IMETHODIMP GetFilterIndex(int32_t* aFilterIndex);
     NS_IMETHODIMP SetFilterIndex(int32_t aFilterIndex);
     NS_IMETHODIMP GetFile(nsIFile** aFile);
     NS_IMETHODIMP GetFileURL(nsIURI** aFileURL);
     NS_IMETHODIMP GetFiles(nsISimpleEnumerator** aFiles);
     NS_IMETHODIMP Show(int16_t* aReturn);
+    NS_IMETHODIMP Open(nsIFilePickerShownCallback* aCallback);
+
+    // PFilePickerChild
+    virtual bool
+    Recv__delete__(const MaybeInputFiles& aFiles, const int16_t& aResult);
 
 private:
     ~nsFilePickerProxy();
     void InitNative(nsIWidget*, const nsAString&);
 
     nsCOMArray<nsIFile> mFiles;
+    nsCOMPtr<nsIFilePickerShownCallback> mCallback;
 
     int16_t   mSelectedType;
     nsString  mFile;
-    nsString  mTitle;
     nsString  mDefault;
     nsString  mDefaultExtension;
 
     InfallibleTArray<nsString> mFilters;
     InfallibleTArray<nsString> mFilterNames;
 };
 
 #endif // NSFILEPICKERPROXY_H
--- a/xpcom/threads/nsIThreadPool.idl
+++ b/xpcom/threads/nsIThreadPool.idl
@@ -22,47 +22,53 @@ interface nsIThreadPoolListener : nsISup
   void onThreadShuttingDown();
 };
 
 /**
  * An interface to a thread pool.  A thread pool creates a limited number of
  * anonymous (unnamed) worker threads.  An event dispatched to the thread pool
  * will be run on the next available worker thread.
  */
-[scriptable, uuid(ba9a466b-8d4a-4b33-ae5c-6ed751068c90)]
+[scriptable, uuid(53675068-cb3a-40e5-a026-1be5a97c9b23)]
 interface nsIThreadPool : nsIEventTarget
 {
   /**
    * Shutdown the thread pool.  This method may not be executed from any thread
    * in the thread pool.  Instead, it is meant to be executed from another
    * thread (usually the thread that created this thread pool).  When this
    * function returns, the thread pool and all of its threads will be shutdown,
    * and it will no longer be possible to dispatch tasks to the thread pool.
    *
    * As a side effect, events on the current thread will be processed.
    */
   void shutdown();
 
   /**
    * Get/set the maximum number of threads allowed at one time in this pool.
-   */ 
+   */
   attribute unsigned long threadLimit;
 
   /**
    * Get/set the maximum number of idle threads kept alive.
    */
   attribute unsigned long idleThreadLimit;
 
   /**
    * Get/set the amount of time in milliseconds before an idle thread is
    * destroyed.
    */
   attribute unsigned long idleThreadTimeout;
 
   /**
+   * Get/set the number of bytes reserved for the stack of all threads in
+   * the pool. By default this is nsIThreadManager::DEFAULT_STACK_SIZE.
+   */
+  attribute unsigned long threadStackSize;
+
+  /**
    * An optional listener that will be notified when a thread is created or
    * destroyed in the course of the thread pool's operation.
    *
    * A listener will only receive notifications about threads created after the
    * listener is set so it is recommended that the consumer set the listener
    * before dispatching the first event. A listener that receives an
    * onThreadCreated() notification is guaranteed to always receive the
    * corresponding onThreadShuttingDown() notification.
--- a/xpcom/threads/nsThreadPool.cpp
+++ b/xpcom/threads/nsThreadPool.cpp
@@ -47,55 +47,58 @@ NS_IMPL_CLASSINFO(nsThreadPool, nullptr,
 NS_IMPL_QUERY_INTERFACE3_CI(nsThreadPool, nsIThreadPool, nsIEventTarget,
                             nsIRunnable)
 NS_IMPL_CI_INTERFACE_GETTER2(nsThreadPool, nsIThreadPool, nsIEventTarget)
 
 nsThreadPool::nsThreadPool()
   : mThreadLimit(DEFAULT_THREAD_LIMIT)
   , mIdleThreadLimit(DEFAULT_IDLE_THREAD_LIMIT)
   , mIdleThreadTimeout(DEFAULT_IDLE_THREAD_TIMEOUT)
+  , mStackSize(nsIThreadManager::DEFAULT_STACK_SIZE)
   , mIdleCount(0)
   , mShutdown(false)
 {
 }
 
 nsThreadPool::~nsThreadPool()
 {
   // Threads keep a reference to the nsThreadPool until they return from Run()
   // after removing themselves from mThreads.
   MOZ_ASSERT(mThreads.IsEmpty());
 }
 
 nsresult
 nsThreadPool::PutEvent(nsIRunnable *event)
 {
   // Avoid spawning a new thread while holding the event queue lock...
- 
+
   bool spawnThread = false;
+  uint32_t stackSize = 0;
   {
     ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
 
     LOG(("THRD-P(%p) put [%d %d %d]\n", this, mIdleCount, mThreads.Count(),
          mThreadLimit));
     MOZ_ASSERT(mIdleCount <= (uint32_t) mThreads.Count(), "oops");
 
     // Make sure we have a thread to service this event.
     if (mIdleCount == 0 && mThreads.Count() < (int32_t) mThreadLimit)
       spawnThread = true;
 
     mEvents.PutEvent(event);
+    stackSize = mStackSize;
   }
 
   LOG(("THRD-P(%p) put [spawn=%d]\n", this, spawnThread));
   if (!spawnThread)
     return NS_OK;
 
   nsCOMPtr<nsIThread> thread;
   nsThreadManager::get()->NewThread(0,
-                                    nsIThreadManager::DEFAULT_STACK_SIZE,
+                                    stackSize,
                                     getter_AddRefs(thread));
   if (NS_WARN_IF(!thread))
     return NS_ERROR_UNEXPECTED;
 
   bool killThread = false;
   {
     ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
     if (mThreads.Count() < (int32_t) mThreadLimit) {
@@ -246,20 +249,24 @@ nsThreadPool::Dispatch(nsIRunnable *even
     PutEvent(event);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsThreadPool::IsOnCurrentThread(bool *result)
 {
-  // No one should be calling this method.  If this assertion gets hit, then we
-  // need to think carefully about what this method should be returning.
-  NS_NOTREACHED("implement me");
-
+  ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
+  nsIThread* thread = NS_GetCurrentThread();
+  for (uint32_t i = 0; i < mThreads.Count(); ++i) {
+    if (mThreads[i] == thread) {
+      *result = true;
+      return NS_OK;
+    }
+  }
   *result = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsThreadPool::Shutdown()
 {
   nsCOMArray<nsIThread> threads;
@@ -347,16 +354,32 @@ nsThreadPool::SetIdleThreadTimeout(uint3
   // Do we need to notify any idle threads that their sleep time has shortened?
   if (mIdleThreadTimeout < oldTimeout && mIdleCount > 0) {
     mon.NotifyAll();  // wake up threads so they observe this change
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsThreadPool::GetThreadStackSize(uint32_t* value)
+{
+  ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
+  *value = mStackSize;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsThreadPool::SetThreadStackSize(uint32_t value)
+{
+  ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
+  mStackSize = value;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsThreadPool::GetListener(nsIThreadPoolListener** aListener)
 {
   ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
   NS_IF_ADDREF(*aListener = mListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/xpcom/threads/nsThreadPool.h
+++ b/xpcom/threads/nsThreadPool.h
@@ -34,16 +34,17 @@ private:
   nsresult PutEvent(nsIRunnable *event);
 
   nsCOMArray<nsIThread> mThreads;
   nsEventQueue          mEvents;
   uint32_t              mThreadLimit;
   uint32_t              mIdleThreadLimit;
   uint32_t              mIdleThreadTimeout;
   uint32_t              mIdleCount;
+  uint32_t              mStackSize;
   nsCOMPtr<nsIThreadPoolListener> mListener;
   bool                  mShutdown;
   nsCString             mName;
   nsThreadPoolNaming    mThreadNaming;
 };
 
 #define NS_THREADPOOL_CID                          \
 { /* 547ec2a8-315e-4ec4-888e-6e4264fe90eb */       \