Bug 693555 - Update inline spellchecker underlining for multiprocess(e10s).r=ehsan, mrbkap
authorAllison Naaktgeboren <ally@mozilla.com>
Tue, 01 Jul 2014 15:24:27 -0700
changeset 216010 d5d67c4fe497bd6dc0a41960d1e9641ad935a4b3
parent 216009 420209cd2a0a7d7cffa9ee7a496fc8cc334e808f
child 216011 4f035fc0bd3bd496cf0012dd6512c207b59ff748
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan, mrbkap
bugs693555
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 693555 - Update inline spellchecker underlining for multiprocess(e10s).r=ehsan, mrbkap
browser/base/content/browser-context.inc
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
editor/composer/nsEditorSpellCheck.cpp
extensions/spellcheck/hunspell/src/PRemoteSpellcheckEngine.ipdl
extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineChild.cpp
extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineChild.h
extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineParent.cpp
extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineParent.h
extensions/spellcheck/hunspell/src/moz.build
extensions/spellcheck/src/moz.build
extensions/spellcheck/src/mozSpellChecker.cpp
extensions/spellcheck/src/mozSpellChecker.h
toolkit/content/widgets/textbox.xml
toolkit/modules/InlineSpellChecker.jsm
--- a/browser/base/content/browser-context.inc
+++ b/browser/base/content/browser-context.inc
@@ -371,17 +371,17 @@
                 label="&viewPageInfoCmd.label;"
                 accesskey="&viewPageInfoCmd.accesskey;"
                 oncommand="gContextMenu.viewInfo();"/>
       <menuseparator id="spell-separator"/>
       <menuitem id="spell-check-enabled"
                 label="&spellCheckToggle.label;"
                 type="checkbox"
                 accesskey="&spellCheckToggle.accesskey;"
-                oncommand="InlineSpellCheckerUI.toggleEnabled();"/>
+                oncommand="InlineSpellCheckerUI.toggleEnabled(window);"/>
       <menuitem id="spell-add-dictionaries-main"
                 label="&spellAddDictionaries.label;"
                 accesskey="&spellAddDictionaries.accesskey;"
                 oncommand="gContextMenu.addDictionaries();"/>
       <menu id="spell-dictionaries"
             label="&spellDictionaries.label;"
             accesskey="&spellDictionaries.accesskey;">
           <menupopup id="spell-dictionaries-menu">
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -146,16 +146,17 @@
 #include "nsIPrincipal.h"
 #include "nsDeviceStorage.h"
 #include "AudioChannelService.h"
 #include "JavaScriptChild.h"
 #include "mozilla/dom/DataStoreService.h"
 #include "mozilla/dom/telephony/PTelephonyChild.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
 #include "mozilla/net/NeckoMessageUtils.h"
+#include "mozilla/RemoteSpellCheckEngineChild.h"
 
 using namespace base;
 using namespace mozilla;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::ipc;
 using namespace mozilla::dom::mobilemessage;
@@ -1047,16 +1048,30 @@ ContentChild::DeallocPBrowserChild(PBrow
 }
 
 PBlobChild*
 ContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
 {
     return nsIContentChild::AllocPBlobChild(aParams);
 }
 
+mozilla::PRemoteSpellcheckEngineChild *
+ContentChild::AllocPRemoteSpellcheckEngineChild()
+{
+    NS_NOTREACHED("Default Constructor for PRemoteSpellcheckEngineChilf should never be called");
+    return nullptr;
+}
+
+bool
+ContentChild::DeallocPRemoteSpellcheckEngineChild(PRemoteSpellcheckEngineChild *child)
+{
+    delete child;
+    return true;
+}
+
 bool
 ContentChild::DeallocPBlobChild(PBlobChild* aActor)
 {
     return nsIContentChild::DeallocPBlobChild(aActor);
 }
 
 PBlobChild*
 ContentChild::SendPBlobConstructor(PBlobChild* aActor,
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -21,16 +21,17 @@
 
 struct ChromePackage;
 class nsIDOMBlob;
 class nsIObserver;
 struct ResourceMapping;
 struct OverrideMapping;
 
 namespace mozilla {
+class RemoteSpellcheckEngineChild;
 
 namespace ipc {
 class OptionalURIParams;
 class URIParams;
 }// namespace ipc
 
 namespace jsipc {
 class JavaScriptChild;
@@ -232,16 +233,18 @@ public:
 
     virtual bool RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages,
                                     const InfallibleTArray<ResourceMapping>& resources,
                                     const InfallibleTArray<OverrideMapping>& overrides,
                                     const nsCString& locale) MOZ_OVERRIDE;
 
     virtual mozilla::jsipc::PJavaScriptChild* AllocPJavaScriptChild() MOZ_OVERRIDE;
     virtual bool DeallocPJavaScriptChild(mozilla::jsipc::PJavaScriptChild*) MOZ_OVERRIDE;
+    virtual PRemoteSpellcheckEngineChild* AllocPRemoteSpellcheckEngineChild() MOZ_OVERRIDE;
+    virtual bool DeallocPRemoteSpellcheckEngineChild(PRemoteSpellcheckEngineChild*) MOZ_OVERRIDE;
 
     virtual bool RecvSetOffline(const bool& offline) MOZ_OVERRIDE;
 
     virtual bool RecvSpeakerManagerNotify() MOZ_OVERRIDE;
 
     virtual bool RecvNotifyVisited(const URIParams& aURI) MOZ_OVERRIDE;
     // auto remove when alertfinished is received.
     nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -152,16 +152,18 @@ using namespace mozilla::system;
 
 #ifdef MOZ_B2G_BT
 #include "BluetoothParent.h"
 #include "BluetoothService.h"
 #endif
 
 #include "JavaScriptParent.h"
 
+#include "mozilla/RemoteSpellCheckEngineParent.h"
+
 #ifdef MOZ_B2G_FM
 #include "mozilla/dom/FMRadioParent.h"
 #endif
 
 #include "Crypto.h"
 
 #ifdef MOZ_WEBSPEECH
 #include "mozilla/dom/SpeechSynthesisParent.h"
@@ -2688,16 +2690,30 @@ ContentParent::AllocPBlobParent(const Bl
 
 bool
 ContentParent::DeallocPBlobParent(PBlobParent* aActor)
 {
     delete aActor;
     return true;
 }
 
+mozilla::PRemoteSpellcheckEngineParent *
+ContentParent::AllocPRemoteSpellcheckEngineParent()
+{
+    mozilla::RemoteSpellcheckEngineParent *parent = new mozilla::RemoteSpellcheckEngineParent();
+    return parent;
+}
+
+bool
+ContentParent::DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent *parent)
+{
+    delete parent;
+    return true;
+}
+
 void
 ContentParent::KillHard()
 {
     // On Windows, calling KillHard multiple times causes problems - the
     // process handle becomes invalid on the first call, causing a second call
     // to crash our process - more details in bug 890840.
     if (mCalledKillHard) {
         return;
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -31,16 +31,17 @@ class mozIApplication;
 class nsConsoleService;
 class nsICycleCollectorLogSink;
 class nsIDOMBlob;
 class nsIDumpGCAndCCLogsCallback;
 class nsIMemoryReporter;
 class ParentIdleListener;
 
 namespace mozilla {
+class PRemoteSpellcheckEngineParent;
 
 namespace ipc {
 class OptionalURIParams;
 class URIParams;
 class TestShellParent;
 } // namespace ipc
 
 namespace jsipc {
@@ -241,16 +242,17 @@ public:
     }
 
     virtual PJavaScriptParent*
     AllocPJavaScriptParent() MOZ_OVERRIDE;
     virtual bool
     RecvPJavaScriptConstructor(PJavaScriptParent* aActor) MOZ_OVERRIDE {
         return PContentParent::RecvPJavaScriptConstructor(aActor);
     }
+    virtual PRemoteSpellcheckEngineParent* AllocPRemoteSpellcheckEngineParent() MOZ_OVERRIDE;
 
     virtual bool RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
                                            const nsString& aPageURL,
                                            const bool& aIsAudio,
                                            const bool& aIsVideo) MOZ_OVERRIDE;
 
     bool CycleCollectWithLogs(bool aDumpAllTraces,
                               nsICycleCollectorLogSink* aSink,
@@ -384,16 +386,17 @@ private:
 
     virtual bool RecvGetProcessAttributes(uint64_t* aId,
                                           bool* aIsForApp,
                                           bool* aIsForBrowser) MOZ_OVERRIDE;
     virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline) MOZ_OVERRIDE;
 
     virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*) MOZ_OVERRIDE;
 
+    virtual bool DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent*) MOZ_OVERRIDE;
     virtual PBrowserParent* AllocPBrowserParent(const IPCTabContext& aContext,
                                                 const uint32_t& aChromeFlags,
                                                 const uint64_t& aId,
                                                 const bool& aIsForApp,
                                                 const bool& aIsForBrowser) MOZ_OVERRIDE;
     virtual bool DeallocPBrowserParent(PBrowserParent* frame) MOZ_OVERRIDE;
 
     virtual PDeviceStorageRequestParent*
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -25,16 +25,17 @@ include protocol PMemoryReportRequest;
 include protocol PNecko;
 include protocol PSharedBufferManager;
 include protocol PSms;
 include protocol PSpeechSynthesis;
 include protocol PStorage;
 include protocol PTelephony;
 include protocol PTestShell;
 include protocol PJavaScript;
+include protocol PRemoteSpellcheckEngine;
 include DOMTypes;
 include JavaScriptTypes;
 include InputStreamParams;
 include PTabContext;
 include URIParams;
 include ProtocolTypes;
 
 using GeoPosition from "nsGeoPositionIPCSerialiser.h";
@@ -304,16 +305,17 @@ intr protocol PContent
     manages PMemoryReportRequest;
     manages PNecko;
     manages PSms;
     manages PSpeechSynthesis;
     manages PStorage;
     manages PTelephony;
     manages PTestShell;
     manages PJavaScript;
+    manages PRemoteSpellcheckEngine;
 
 both:
     // Depending on exactly how the new browser is being created, it might be
     // created from either the child or parent process!
     //
     // The child creates the PBrowser as part of
     // TabChild::BrowserFrameProvideWindow (which happens when the child's
     // content calls window.open()), and the parent creates the PBrowser as part
@@ -457,16 +459,17 @@ parent:
 
     sync CreateChildProcess(IPCTabContext context,
                             ProcessPriority priority)
         returns (uint64_t id, bool isForApp, bool isForBrowser);
     intr BridgeToChildProcess(uint64_t id);
 
     async PJavaScript();
 
+    sync PRemoteSpellcheckEngine();
     PDeviceStorageRequest(DeviceStorageParams params);
 
     PFileSystemRequest(FileSystemParams params);
 
     sync PCrashReporter(NativeThreadId tid, uint32_t processType);
 
     sync GetRandomValues(uint32_t length)
         returns (uint8_t[] randomValues);
--- a/editor/composer/nsEditorSpellCheck.cpp
+++ b/editor/composer/nsEditorSpellCheck.cpp
@@ -37,16 +37,17 @@
 #include "nsIVariant.h"                 // for nsIWritableVariant, etc
 #include "nsLiteralString.h"            // for NS_LITERAL_STRING, etc
 #include "nsMemory.h"                   // for nsMemory
 #include "nsReadableUtils.h"            // for ToNewUnicode, EmptyString, etc
 #include "nsServiceManagerUtils.h"      // for do_GetService
 #include "nsString.h"                   // for nsAutoString, nsString, etc
 #include "nsStringFwd.h"                // for nsAFlatString
 #include "nsStyleUtil.h"                // for nsStyleUtil
+#include "nsXULAppAPI.h"                // for XRE_GetProcessType
 
 using namespace mozilla;
 
 class UpdateDictionnaryHolder {
   private:
     nsEditorSpellCheck* mSpellCheck;
   public:
     UpdateDictionnaryHolder(nsEditorSpellCheck* esc): mSpellCheck(esc) {
@@ -700,18 +701,26 @@ nsEditorSpellCheck::UpdateCurrentDiction
 
   DictionaryFetcher* fetcher = new DictionaryFetcher(this, aCallback,
                                                      mDictionaryFetcherGroup);
   rootContent->GetLang(fetcher->mRootContentLang);
   nsCOMPtr<nsIDocument> doc = rootContent->GetCurrentDoc();
   NS_ENSURE_STATE(doc);
   doc->GetContentLanguage(fetcher->mRootDocContentLang);
 
-  rv = fetcher->Fetch(mEditor);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    // Content prefs don't work in E10S (Bug 1027898) pretend that we
+    // didn't have any & trigger the asynchrous completion.
+    nsCOMPtr<nsIRunnable> runnable =
+      NS_NewRunnableMethodWithArg<uint16_t>(fetcher, &DictionaryFetcher::HandleCompletion, 0);
+    NS_DispatchToMainThread(runnable);
+  } else {
+    rv = fetcher->Fetch(mEditor);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   return NS_OK;
 }
 
 nsresult
 nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
 {
   nsRefPtr<nsEditorSpellCheck> kungFuDeathGrip = this;
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/src/PRemoteSpellcheckEngine.ipdl
@@ -0,0 +1,20 @@
+/* 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 PContent;
+
+namespace mozilla {
+
+sync protocol PRemoteSpellcheckEngine {
+  manager PContent;
+
+parent:
+  __delete__();
+
+  sync CheckForMisspelling(nsString aWord) returns (bool isMisspelled);
+
+  sync SetDictionary(nsString aDictionary) returns (bool success);
+};
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineChild.cpp
@@ -0,0 +1,21 @@
+/* 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 "RemoteSpellCheckEngineChild.h"
+
+namespace mozilla {
+RemoteSpellcheckEngineChild::RemoteSpellcheckEngineChild(mozSpellChecker *aOwner)
+  :mOwner(aOwner)
+{
+}
+
+RemoteSpellcheckEngineChild::~RemoteSpellcheckEngineChild()
+{
+  // null out the owner's SpellcheckEngineChild to prevent state corruption
+  // during shutdown
+  mOwner->DeleteRemoteEngine();
+
+}
+
+} //namespace mozilla
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineChild.h
@@ -0,0 +1,26 @@
+/* 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 RemoteSpellcheckEngineChild_h_
+#define RemoteSpellcheckEngineChild_h_
+
+#include "mozilla/PRemoteSpellcheckEngineChild.h"
+#include "mozSpellChecker.h"
+
+class mozSpellChecker;
+
+namespace mozilla {
+class RemoteSpellcheckEngineChild : public mozilla::PRemoteSpellcheckEngineChild
+{
+public:
+  RemoteSpellcheckEngineChild(mozSpellChecker *aOwner);
+  ~RemoteSpellcheckEngineChild();
+
+private:
+  mozSpellChecker *mOwner;
+};
+
+} //namespace mozilla
+
+#endif // RemoteSpellcheckEngineChild_h_
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineParent.cpp
@@ -0,0 +1,49 @@
+/* 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 "RemoteSpellCheckEngineParent.h"
+#include "mozISpellCheckingEngine.h"
+#include "nsServiceManagerUtils.h"
+
+#define DEFAULT_SPELL_CHECKER "@mozilla.org/spellchecker/engine;1"
+
+namespace mozilla {
+
+RemoteSpellcheckEngineParent::RemoteSpellcheckEngineParent()
+{
+  mEngine = do_GetService(DEFAULT_SPELL_CHECKER);
+}
+
+RemoteSpellcheckEngineParent::~RemoteSpellcheckEngineParent()
+{
+}
+
+bool
+RemoteSpellcheckEngineParent::RecvSetDictionary(
+  const nsString& aDictionary,
+  bool* success)
+{
+  nsresult rv = mEngine->SetDictionary(aDictionary.get());
+  *success = NS_SUCCEEDED(rv);
+  return true;
+}
+
+bool
+RemoteSpellcheckEngineParent::RecvCheckForMisspelling(
+  const nsString& aWord,
+  bool* isMisspelled)
+{
+  bool isCorrect = false;
+  mEngine->Check(aWord.get(), &isCorrect);
+  *isMisspelled = !isCorrect;
+  return true;
+}
+
+void
+RemoteSpellcheckEngineParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+}
+
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineParent.h
@@ -0,0 +1,31 @@
+/* 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 RemoteSpellcheckEngineParent_h_
+#define RemoteSpellcheckEngineParent_h_
+
+#include "mozISpellCheckingEngine.h"
+#include "mozilla/PRemoteSpellcheckEngineParent.h"
+#include "nsCOMPtr.h"
+
+namespace mozilla {
+
+class RemoteSpellcheckEngineParent : public mozilla::PRemoteSpellcheckEngineParent {
+
+public:
+  RemoteSpellcheckEngineParent();
+
+  ~RemoteSpellcheckEngineParent();
+
+  virtual void ActorDestroy(ActorDestroyReason aWhy);
+
+  bool RecvSetDictionary(const nsString& aDictionary, bool* success);
+
+  bool RecvCheckForMisspelling( const nsString& aWord, bool* isMisspelled);
+
+private:
+  nsCOMPtr<mozISpellCheckingEngine> mEngine;
+};
+
+}
+#endif
--- a/extensions/spellcheck/hunspell/src/moz.build
+++ b/extensions/spellcheck/hunspell/src/moz.build
@@ -1,17 +1,19 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-UNIFIED_SOURCES += [
+SOURCES += [
     'mozHunspell.cpp',
     'mozHunspellDirProvider.cpp',
+    'RemoteSpellCheckEngineChild.cpp',
+    'RemoteSpellCheckEngineParent.cpp',
 ]
 
 if not CONFIG['MOZ_NATIVE_HUNSPELL']:
     SOURCES += [
         'affentry.cxx',
         'affixmgr.cxx',
         'csutil.cxx',
         'dictmgr.cxx',
@@ -35,8 +37,19 @@ LOCAL_INCLUDES += [
 
 LOCAL_INCLUDES += [
     '/editor/libeditor/base',
 ]
 
 # Suppress warnings in third-party code.
 if CONFIG['CLANG_CXX']:
     CXXFLAGS += ['-Wno-unused-private-field']
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+IPDL_SOURCES = [
+    'PRemoteSpellcheckEngine.ipdl',
+]
+
+EXPORTS.mozilla += [
+     'RemoteSpellCheckEngineChild.h',
+     'RemoteSpellCheckEngineParent.h',
+]
--- a/extensions/spellcheck/src/moz.build
+++ b/extensions/spellcheck/src/moz.build
@@ -1,15 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-UNIFIED_SOURCES += [
+include('/ipc/chromium/chromium-config.mozbuild')
+SOURCES += [
     'mozEnglishWordUtils.cpp',
     'mozGenericWordUtils.cpp',
     'mozInlineSpellChecker.cpp',
     'mozInlineSpellWordUtil.cpp',
     'mozPersonalDictionary.cpp',
     'mozSpellChecker.cpp',
     'mozSpellCheckerFactory.cpp',
     'mozSpellI18NManager.cpp',
@@ -19,10 +20,13 @@ LIBRARY_NAME = 'spellchecker'
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '../hunspell/src',
     '/content/base/src',
     '/editor/libeditor/base',
 ]
+EXPORTS.mozilla += [
+     'mozSpellChecker.h',
+]
 
 FAIL_ON_WARNINGS = True
--- a/extensions/spellcheck/src/mozSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozSpellChecker.cpp
@@ -5,16 +5,23 @@
 
 #include "mozSpellChecker.h"
 #include "nsIServiceManager.h"
 #include "mozISpellI18NManager.h"
 #include "nsIStringEnumerator.h"
 #include "nsICategoryManager.h"
 #include "nsISupportsPrimitives.h"
 #include "nsISimpleEnumerator.h"
+#include "mozilla/PRemoteSpellcheckEngineChild.h"
+#include "mozilla/dom/ContentChild.h"
+#include "nsXULAppAPI.h"
+
+using mozilla::dom::ContentChild;
+using mozilla::PRemoteSpellcheckEngineChild;
+using mozilla::RemoteSpellcheckEngineChild;
 
 #define DEFAULT_SPELL_CHECKER "@mozilla.org/spellchecker/engine;1"
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozSpellChecker)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozSpellChecker)
 
 NS_INTERFACE_MAP_BEGIN(mozSpellChecker)
   NS_INTERFACE_MAP_ENTRY(nsISpellChecker)
@@ -33,24 +40,34 @@ mozSpellChecker::mozSpellChecker()
 mozSpellChecker::~mozSpellChecker()
 {
   if(mPersonalDictionary){
     //    mPersonalDictionary->Save();
     mPersonalDictionary->EndSession();
   }
   mSpellCheckingEngine = nullptr;
   mPersonalDictionary = nullptr;
+
+  if(XRE_GetProcessType() == GeckoProcessType_Content) {
+    mEngine->Send__delete__(mEngine);
+  }
 }
 
 nsresult 
 mozSpellChecker::Init()
 {
   mPersonalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1");
   
   mSpellCheckingEngine = nullptr;
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    mozilla::dom::ContentChild* contentChild = mozilla::dom::ContentChild::GetSingleton();
+    MOZ_ASSERT(contentChild);
+    mEngine = new RemoteSpellcheckEngineChild(this);
+    contentChild->SendPRemoteSpellcheckEngineConstructor(mEngine);
+  }
 
   return NS_OK;
 } 
 
 NS_IMETHODIMP 
 mozSpellChecker::SetDocument(nsITextServicesDocument *aDoc, bool aFromStartofDoc)
 {
   mTsDoc = aDoc;
@@ -103,19 +120,26 @@ mozSpellChecker::NextMisspelledWord(nsAS
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 mozSpellChecker::CheckWord(const nsAString &aWord, bool *aIsMisspelled, nsTArray<nsString> *aSuggestions)
 {
   nsresult result;
   bool correct;
-  if(!mSpellCheckingEngine)
+
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    nsString wordwrapped = nsString(aWord);
+    bool rv = mEngine->SendCheckForMisspelling(wordwrapped, aIsMisspelled);
+    return rv ? NS_OK : NS_ERROR_NOT_AVAILABLE;
+  }
+
+  if(!mSpellCheckingEngine) {
     return NS_ERROR_NULL_POINTER;
-
+  }
   *aIsMisspelled = false;
   result = mSpellCheckingEngine->Check(PromiseFlatString(aWord).get(), &correct);
   NS_ENSURE_SUCCESS(result, result);
   if(!correct){
     if(aSuggestions){
       uint32_t count,i;
       char16_t **words;
       
@@ -327,16 +351,23 @@ mozSpellChecker::GetCurrentDictionary(ns
   mSpellCheckingEngine->GetDictionary(getter_Copies(dictname));
   aDictionary = dictname;
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary)
 {
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    nsString wrappedDict = nsString(aDictionary);
+    bool isSuccess;
+    mEngine->SendSetDictionary(wrappedDict, &isSuccess);
+    return isSuccess ? NS_OK : NS_ERROR_NOT_AVAILABLE;
+  }
+
   // Calls to mozISpellCheckingEngine::SetDictionary might destroy us
   nsRefPtr<mozSpellChecker> kungFuDeathGrip = this;
 
   mSpellCheckingEngine = nullptr;
 
   if (aDictionary.IsEmpty()) {
     return NS_OK;
   }
@@ -523,8 +554,12 @@ mozSpellChecker::GetEngineList(nsCOMArra
     // Fail if not succeeded to load HunSpell. Ignore errors
     // for external spellcheck engines.
     return rv;
   }
   aSpellCheckingEngines->AppendObject(engine);
 
   return NS_OK;
 }
+
+void mozSpellChecker::DeleteRemoteEngine() {
+  mEngine = nullptr;
+}
\ No newline at end of file
--- a/extensions/spellcheck/src/mozSpellChecker.h
+++ b/extensions/spellcheck/src/mozSpellChecker.h
@@ -12,16 +12,22 @@
 #include "nsString.h"
 #include "nsITextServicesDocument.h"
 #include "mozIPersonalDictionary.h"
 #include "mozISpellCheckingEngine.h"
 #include "nsClassHashtable.h"
 #include "nsTArray.h"
 #include "mozISpellI18NUtil.h"
 #include "nsCycleCollectionParticipant.h"
+#include "RemoteSpellCheckEngineChild.h"
+
+namespace mozilla {
+class PRemoteSpellcheckEngineChild;
+class RemoteSpellcheckEngineChild;
+}
 
 class mozSpellChecker : public nsISpellChecker
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(mozSpellChecker)
 
   mozSpellChecker();
@@ -38,26 +44,29 @@ public:
   NS_IMETHOD AddWordToPersonalDictionary(const nsAString &aWord);
   NS_IMETHOD RemoveWordFromPersonalDictionary(const nsAString &aWord);
   NS_IMETHOD GetPersonalDictionary(nsTArray<nsString> *aWordList);
 
   NS_IMETHOD GetDictionaryList(nsTArray<nsString> *aDictionaryList);
   NS_IMETHOD GetCurrentDictionary(nsAString &aDictionary);
   NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary);
   NS_IMETHOD CheckCurrentDictionary();
+  void DeleteRemoteEngine();
 
 protected:
   virtual ~mozSpellChecker();
 
   nsCOMPtr<mozISpellI18NUtil> mConverter;
   nsCOMPtr<nsITextServicesDocument> mTsDoc;
   nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary;
 
   nsCOMPtr<mozISpellCheckingEngine>  mSpellCheckingEngine;
   bool mFromStart;
 
   nsresult SetupDoc(int32_t *outBlockOffset);
 
   nsresult GetCurrentBlockIndex(nsITextServicesDocument *aDoc, int32_t *outBlockIndex);
 
   nsresult GetEngineList(nsCOMArray<mozISpellCheckingEngine> *aDictionaryList);
+
+  mozilla::PRemoteSpellcheckEngineChild *mEngine;
 };
 #endif // mozSpellChecker_h__
--- a/toolkit/content/widgets/textbox.xml
+++ b/toolkit/content/widgets/textbox.xml
@@ -536,17 +536,17 @@
         <xul:menuitem label="&cutCmd.label;" accesskey="&cutCmd.accesskey;" cmd="cmd_cut"/>
         <xul:menuitem label="&copyCmd.label;" accesskey="&copyCmd.accesskey;" cmd="cmd_copy"/>
         <xul:menuitem label="&pasteCmd.label;" accesskey="&pasteCmd.accesskey;" cmd="cmd_paste"/>
         <xul:menuitem label="&deleteCmd.label;" accesskey="&deleteCmd.accesskey;" cmd="cmd_delete"/>
         <xul:menuseparator/>
         <xul:menuitem label="&selectAllCmd.label;" accesskey="&selectAllCmd.accesskey;" cmd="cmd_selectAll"/>
         <xul:menuseparator anonid="spell-check-separator"/>
         <xul:menuitem label="&spellCheckToggle.label;" type="checkbox" accesskey="&spellCheckToggle.accesskey;" anonid="spell-check-enabled"
-                      oncommand="this.parentNode.parentNode.spellCheckerUI.toggleEnabled();"/>
+                      oncommand="this.parentNode.parentNode.spellCheckerUI.toggleEnabled(window);"/>
         <xul:menu label="&spellDictionaries.label;" accesskey="&spellDictionaries.accesskey;" anonid="spell-dictionaries">
           <xul:menupopup anonid="spell-dictionaries-menu"
                          onpopupshowing="event.stopPropagation();"
                          onpopuphiding="event.stopPropagation();"/>
         </xul:menu>
       </xul:menupopup>
     </content>
 
--- a/toolkit/modules/InlineSpellChecker.jsm
+++ b/toolkit/modules/InlineSpellChecker.jsm
@@ -186,17 +186,17 @@ InlineSpellChecker.prototype = {
       var item = menu.ownerDocument.createElement("menuitem");
       item.setAttribute("id", "spell-check-dictionary-" + sortedList[i].id);
       item.setAttribute("label", sortedList[i].label);
       item.setAttribute("type", "radio");
       this.mDictionaryItems.push(item);
       if (curlang == sortedList[i].id) {
         item.setAttribute("checked", "true");
       } else {
-        var callback = function(me, val) { return function(evt) { me.selectDictionary(val); } };
+        var callback = function(me, val) { return function(evt) { me.selectDictionary(val, me.menu.ownerDocument.defaultView); } };
         item.addEventListener("command", callback(this, i), true);
       }
       if (insertBefore)
         menu.insertBefore(item, insertBefore);
       else
         menu.appendChild(item);
     }
     return list.length;
@@ -267,18 +267,30 @@ InlineSpellChecker.prototype = {
   {
     for (var i = 0; i < this.mDictionaryItems.length; i ++) {
       this.mDictionaryMenu.removeChild(this.mDictionaryItems[i]);
     }
     this.mDictionaryItems = [];
   },
 
   // callback for selecting a dictionary
-  selectDictionary: function(index)
+  selectDictionary: function(index, aWindow)
   {
+    // Avoid a crash in multiprocess until Bug 1030451 lands
+    // Remove aWindow parameter at that time
+    const Ci = Components.interfaces;
+    let chromeFlags = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
+                                  getInterface(Ci.nsIWebNavigation).
+                                  QueryInterface(Ci.nsIDocShellTreeItem).treeOwner.
+                                  QueryInterface(Ci.nsIInterfaceRequestor).
+                                  getInterface(Ci.nsIXULWindow).chromeFlags;
+    let chromeRemoteWindow = Ci.nsIWebBrowserChrome.CHROME_REMOTE_WINDOW;
+    if (chromeFlags & chromeRemoteWindow) {
+      return;
+    }
     if (! this.mInlineSpellChecker || index < 0 || index >= this.mDictionaryNames.length)
       return;
     var spellchecker = this.mInlineSpellChecker.spellChecker;
     spellchecker.SetCurrentDictionary(this.mDictionaryNames[index]);
     this.mInlineSpellChecker.spellCheckRange(null); // causes recheck
   },
 
   // callback for selecting a suggesteed replacement
@@ -288,18 +300,30 @@ InlineSpellChecker.prototype = {
       return;
     if (index < 0 || index >= this.mSpellSuggestions.length)
       return;
     this.mInlineSpellChecker.replaceWord(this.mWordNode, this.mWordOffset,
                                          this.mSpellSuggestions[index]);
   },
 
   // callback for enabling or disabling spellchecking
-  toggleEnabled: function()
+  toggleEnabled: function(aWindow)
   {
+    // Avoid a crash in multiprocess until Bug 1030451 lands
+    // Remove aWindow parameter at that time
+    const Ci = Components.interfaces;
+    let chromeFlags = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
+                                  getInterface(Ci.nsIWebNavigation).
+                                  QueryInterface(Ci.nsIDocShellTreeItem).treeOwner.
+                                  QueryInterface(Ci.nsIInterfaceRequestor).
+                                  getInterface(Ci.nsIXULWindow).chromeFlags;
+    let chromeRemoteWindow = Ci.nsIWebBrowserChrome.CHROME_REMOTE_WINDOW;
+    if (chromeFlags & chromeRemoteWindow) {
+      return;
+    }
     this.mEditor.setSpellcheckUserOverride(!this.mInlineSpellChecker.enableRealTimeSpell);
   },
 
   // callback for adding the current misspelling to the user-defined dictionary
   addToDictionary: function()
   {
     // Prevent the undo stack from growing over the max depth
     if (this.mAddedWordStack.length == MAX_UNDO_STACK_DEPTH)