Bug 477911 [TSF] crash after committing long IME transaction string at losing focus r=VYV03354, sr=roc
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 09 Mar 2009 11:38:12 +0900
changeset 25857 7a6071857512c5d3556022734b4efd6991389a96
parent 25856 5c293c84dc070d2501fa4b0903a38facf048d3a2
child 25858 33ab278e0a35116bc7c60f8621488ca0fe9087b7
push id5784
push usermasayuki@d-toybox.com
push dateMon, 09 Mar 2009 02:38:45 +0000
treeherdermozilla-central@7a6071857512 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersVYV03354, roc
bugs477911
milestone1.9.2a1pre
Bug 477911 [TSF] crash after committing long IME transaction string at losing focus r=VYV03354, sr=roc
widget/src/windows/nsTextStore.cpp
widget/src/windows/nsTextStore.h
widget/tests/TestWinTSF.cpp
--- a/widget/src/windows/nsTextStore.cpp
+++ b/widget/src/windows/nsTextStore.cpp
@@ -111,17 +111,16 @@ nsTextStore::Create(nsWindow* aWindow,
     mDocumentMgr = NULL;
   }
   return PR_FALSE;
 }
 
 PRBool
 nsTextStore::Destroy(void)
 {
-  Blur();
   if (mWindow) {
     // When blurred, Tablet Input Panel posts "blur" messages
     // and try to insert text when the message is retrieved later.
     // But by that time the text store is already destroyed,
     // so try to get the message early
     MSG msg;
     if (::PeekMessageW(&msg, mWindow->GetWindowHandle(),
                        sFlushTIPInputMessage, sFlushTIPInputMessage,
@@ -136,35 +135,16 @@ nsTextStore::Destroy(void)
   }
   mSink = NULL;
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
          ("TSF: Destroyed, window=%08x\n", mWindow));
   mWindow = NULL;
   return PR_TRUE;
 }
 
-PRBool
-nsTextStore::Focus(void)
-{
-  HRESULT hr = sTsfThreadMgr->SetFocus(mDocumentMgr);
-  NS_ENSURE_TRUE(SUCCEEDED(hr), PR_FALSE);
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: Focused\n"));
-  return PR_TRUE;
-}
-
-PRBool
-nsTextStore::Blur(void)
-{
-  sTsfThreadMgr->SetFocus(NULL);
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: Blurred\n"));
-  return PR_TRUE;
-}
-
 STDMETHODIMP
 nsTextStore::QueryInterface(REFIID riid,
                             void** ppv)
 {
   *ppv=NULL;
   if ( (IID_IUnknown == riid) || (IID_ITextStoreACP == riid) ) {
     *ppv = static_cast<ITextStoreACP*>(this);
   } else if (IID_ITfContextOwnerCompositionSink == riid) {
@@ -1369,18 +1349,21 @@ nsTextStore::OnFocusChange(PRBool aFocus
                            nsWindow* aWindow,
                            PRUint32 aIMEEnabled)
 {
   // no change notifications if TSF is disabled
   if (!sTsfThreadMgr || !sTsfTextStore)
     return NS_ERROR_NOT_AVAILABLE;
 
   if (aFocus) {
-    if (sTsfTextStore->Create(aWindow, aIMEEnabled))
-      sTsfTextStore->Focus();
+    PRBool bRet = sTsfTextStore->Create(aWindow, aIMEEnabled);
+    NS_ENSURE_TRUE(bRet, NS_ERROR_FAILURE);
+    NS_ENSURE_TRUE(sTsfTextStore->mDocumentMgr, NS_ERROR_FAILURE);
+    HRESULT hr = sTsfThreadMgr->SetFocus(sTsfTextStore->mDocumentMgr);
+    NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
   } else {
     sTsfTextStore->Destroy();
   }
   return NS_OK;
 }
 
 nsresult
 nsTextStore::OnTextChangeInternal(PRUint32 aStart,
--- a/widget/src/windows/nsTextStore.h
+++ b/widget/src/windows/nsTextStore.h
@@ -176,18 +176,16 @@ public:
   }
 
 protected:
   nsTextStore();
   ~nsTextStore();
 
   PRBool   Create(nsWindow*, PRUint32);
   PRBool   Destroy(void);
-  PRBool   Focus(void);
-  PRBool   Blur(void);
 
   // If aDispatchTextEvent is true, this method will dispatch text event if
   // 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*,
                                 PRBool aDispatchTextEvent = PR_FALSE);
   HRESULT  OnStartCompositionInternal(ITfCompositionView*, ITfRange*, PRBool);
--- a/widget/tests/TestWinTSF.cpp
+++ b/widget/tests/TestWinTSF.cpp
@@ -91,17 +91,19 @@ class nsAFlatCString;
 
 #ifndef MOZILLA_INTERNAL_API
 #undef nsString_h___
 #undef nsAString_h___
 #endif
 
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
-class TSFImpl;
+class TSFMgrImpl;
+class TSFDocumentMgrImpl;
+class TSFContextImpl;
 class TSFRangeImpl;
 class TSFEnumRangeImpl;
 class TSFAttrPropImpl;
 
 class TestApp : public nsIWebProgressListener, public nsSupportsWeakReference
 {
 public:
   NS_DECL_ISUPPORTS
@@ -141,17 +143,17 @@ protected:
                                     const nsAString& aCharacter,
                                     LONG aStart,
                                     LONG aOldEnd,
                                     LONG aNewEnd);
   nsresult GetSelCon(nsISelectionController** aSelCon);
 
   PRBool mFailed;
   nsString mTestString;
-  nsRefPtr<TSFImpl> mImpl;
+  nsRefPtr<TSFMgrImpl> mMgr;
   nsCOMPtr<nsIAppShell> mAppShell;
   nsCOMPtr<nsIXULWindow> mWindow;
   nsCOMPtr<nsIDOMNode> mCurrentNode;
   nsCOMPtr<nsIDOMHTMLInputElement> mInput;
   nsCOMPtr<nsIDOMHTMLTextAreaElement> mTextArea;
   nsCOMPtr<nsIDOMHTMLInputElement> mButton;
 };
 
@@ -747,79 +749,58 @@ public: // ITfReadOnlyProperty
 
   STDMETHODIMP GetContext(ITfContext **ppContext)
   {
     NS_NOTREACHED("ITfReadOnlyProperty::GetContext");
     return E_NOTIMPL;
   }
 };
 
-// Simple TSF manager implementation for testing
-// Most methods are not implemented, but the ones used by Mozilla are
-//
-// XXX Implement appropriate methods here as the Mozilla TSF code changes
-//
-class TSFImpl : public ITfThreadMgr, public ITfDocumentMgr, public ITfContext,
-                public ITfCompositionView, public ITextStoreACPSink,
-                public ITfDisplayAttributeMgr, public ITfCategoryMgr
+/******************************************************************************
+ * TSFContextImpl
+ ******************************************************************************/
+
+class TSFContextImpl : public ITfContext,
+                       public ITfCompositionView, public ITextStoreACPSink
 {
 private:
   ULONG mRefCnt;
-  nsRefPtr<TestApp> mTestApp;
 
 public:
-  TestApp::test_type mTest;
-  TestApp::test_type mOnFocus;
-  TestApp::test_type mOnBlur;
-  nsRefPtr<ITextStoreACP> mStore;
   nsRefPtr<TSFAttrPropImpl> mAttrProp;
-  PRBool mFocused;
-  PRBool mContextPushed;
-  PRBool mDeactivated;
-  PRUint32 mFocusCount;
-  PRUint32 mBlurCount;
+  nsRefPtr<TSFDocumentMgrImpl> mDocMgr;
   PRBool mTextChanged;
   PRBool mSelChanged;
   TS_TEXTCHANGE mTextChangeData;
 
 public:
-  TSFImpl(TestApp* test) : mTestApp(test), mTest(nsnull),
-      mRefCnt(0), mFocused(PR_FALSE), mDeactivated(PR_FALSE),
-      mFocusCount(0), mBlurCount(0), mContextPushed(PR_FALSE),
-      mOnFocus(nsnull), mOnBlur(nsnull), mTextChanged(PR_FALSE),
+  TSFContextImpl(TSFDocumentMgrImpl* aDocMgr) :
+      mDocMgr(aDocMgr), mRefCnt(0), mTextChanged(PR_FALSE),
       mSelChanged(PR_FALSE)
   {
     mAttrProp = new TSFAttrPropImpl();
     if (!mAttrProp) {
-      NS_NOTREACHED("TSFImpl::TSFImpl (OOM)");
+      NS_NOTREACHED("TSFContextImpl::TSFContextImpl (OOM)");
       return;
     }
   }
 
-  ~TSFImpl()
+  ~TSFContextImpl()
   {
   }
 
 public: // IUnknown
 
   STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk)
   {
     *ppUnk = NULL;
-    if (IID_IUnknown == riid || IID_ITfThreadMgr == riid)
-      *ppUnk = static_cast<ITfThreadMgr*>(this);
-    else if (IID_ITfDocumentMgr == riid)
-      *ppUnk = static_cast<ITfDocumentMgr*>(this);
-    else if (IID_ITfContext == riid)
+    if (IID_IUnknown == riid || IID_ITfContext == riid)
       *ppUnk = static_cast<ITfContext*>(this);
     else if (IID_ITextStoreACPSink == riid)
       *ppUnk = static_cast<ITextStoreACPSink*>(this);
-    else if (IID_ITfDisplayAttributeMgr == riid)
-      *ppUnk = static_cast<ITfDisplayAttributeMgr*>(this);
-    else if (IID_ITfCategoryMgr == riid)
-      *ppUnk = static_cast<ITfCategoryMgr*>(this);
     if (*ppUnk)
       AddRef();
     return *ppUnk ? S_OK : E_NOINTERFACE;
   }
 
   STDMETHODIMP_(ULONG) AddRef(void)
   {
     return ++mRefCnt;
@@ -827,272 +808,16 @@ public: // IUnknown
 
   STDMETHODIMP_(ULONG) Release(void)
   {
     if (--mRefCnt) return mRefCnt;
     delete this;
     return 0;
   }
 
-public: // ITfThreadMgr
-
-  STDMETHODIMP Activate(TfClientId *ptid)
-  {
-    *ptid = 1;
-    return S_OK;
-  }
-
-  STDMETHODIMP Deactivate(void)
-  {
-    SetFocus(NULL);
-    mDeactivated = PR_TRUE;
-    return S_OK;
-  }
-
-  STDMETHODIMP CreateDocumentMgr(ITfDocumentMgr **ppdim)
-  {
-    (*ppdim) = this;
-    (*ppdim)->AddRef();
-    return S_OK;
-  }
-
-  STDMETHODIMP EnumDocumentMgrs(IEnumTfDocumentMgrs **ppEnum)
-  {
-    NS_NOTREACHED("ITfThreadMgr::EnumDocumentMgrs");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP GetFocus(ITfDocumentMgr **ppdimFocus)
-  {
-    (*ppdimFocus) = mFocused ? this : NULL;
-    if (*ppdimFocus) (*ppdimFocus)->AddRef();
-    return S_OK;
-  }
-
-  STDMETHODIMP SetFocus(ITfDocumentMgr *pdimFocus)
-  {
-    mFocused = pdimFocus != NULL;
-    if (mFocused) {
-      ++mFocusCount;
-      if (mOnFocus) (mTestApp->*mOnFocus)();
-    } else {
-      ++mBlurCount;
-      if (mOnBlur) (mTestApp->*mOnBlur)();
-    }
-    return S_OK;
-  }
-
-  STDMETHODIMP AssociateFocus(HWND hwnd, ITfDocumentMgr *pdimNew,
-                           ITfDocumentMgr **ppdimPrev)
-  {
-    NS_NOTREACHED("ITfThreadMgr::AssociateFocus");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP IsThreadFocus(BOOL *pfThreadFocus)
-  {
-    *pfThreadFocus = TRUE;
-    return S_OK;
-  }
-
-  STDMETHODIMP GetFunctionProvider(REFCLSID clsid,
-                                ITfFunctionProvider **ppFuncProv)
-  {
-    NS_NOTREACHED("ITfThreadMgr::GetFunctionProvider");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP EnumFunctionProviders(IEnumTfFunctionProviders **ppEnum)
-  {
-    NS_NOTREACHED("ITfThreadMgr::EnumFunctionProviders");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP GetGlobalCompartment(ITfCompartmentMgr **ppCompMgr)
-  {
-    NS_NOTREACHED("ITfThreadMgr::GetGlobalCompartment");
-    return E_NOTIMPL;
-  }
-
-public: // ITfDocumentMgr
-
-  STDMETHODIMP CreateContext(TfClientId tidOwner, DWORD dwFlags,
-                             IUnknown *punk, ITfContext **ppic,
-                             TfEditCookie *pecTextStore)
-  {
-    punk->QueryInterface(IID_ITextStoreACP, getter_AddRefs(mStore));
-    NS_ENSURE_TRUE(mStore, E_FAIL);
-    HRESULT hr = mStore->AdviseSink(IID_ITextStoreACPSink,
-                                    static_cast<ITextStoreACPSink*>(this),
-                                    TS_AS_ALL_SINKS);
-    if (FAILED(hr)) mStore = NULL;
-    NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL);
-    (*ppic) = this;
-    (*ppic)->AddRef();
-    *pecTextStore = 1;
-    return S_OK;
-  }
-
-  STDMETHODIMP Push(ITfContext *pic)
-  {
-    mContextPushed = PR_TRUE;
-    return S_OK;
-  }
-
-  STDMETHODIMP Pop(DWORD dwFlags)
-  {
-    if (!mStore || dwFlags != TF_POPF_ALL) return E_FAIL;
-    mStore->UnadviseSink(static_cast<ITextStoreACPSink*>(this));
-    mStore = NULL;
-    mContextPushed = PR_FALSE;
-    return S_OK;
-  }
-
-  STDMETHODIMP GetTop(ITfContext **ppic)
-  {
-    (*ppic) = mContextPushed ? this : NULL;
-    if (*ppic) (*ppic)->AddRef();
-    return S_OK;
-  }
-
-  STDMETHODIMP GetBase(ITfContext **ppic)
-  {
-    (*ppic) = mContextPushed ? this : NULL;
-    if (*ppic) (*ppic)->AddRef();
-    return S_OK;
-  }
-
-  STDMETHODIMP EnumContexts(IEnumTfContexts **ppEnum)
-  {
-    NS_NOTREACHED("ITfDocumentMgr::EnumContexts");
-    return E_NOTIMPL;
-  }
-
-public: // ITfCategoryMgr
-
-  STDMETHODIMP RegisterCategory(REFCLSID rclsid, REFGUID rcatid, REFGUID rguid)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::RegisterCategory");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP UnregisterCategory(REFCLSID rclsid, REFGUID rcatid, REFGUID rguid)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::UnregisterCategory");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP EnumCategoriesInItem(REFGUID rguid, IEnumGUID **ppEnum)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::EnumCategoriesInItem");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP EnumItemsInCategory(REFGUID rcatid, IEnumGUID **ppEnum)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::EnumItemsInCategory");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP FindClosestCategory(REFGUID rguid, GUID *pcatid,
-                                   const GUID **ppcatidList, ULONG ulCount)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::FindClosestCategory");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP RegisterGUIDDescription(REFCLSID rclsid, REFGUID rguid,
-                                       const WCHAR *pchDesc, ULONG cch)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::RegisterGUIDDescription");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP UnregisterGUIDDescription(REFCLSID rclsid, REFGUID rguid)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::UnregisterGUIDDescription");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP GetGUIDDescription(REFGUID rguid, BSTR *pbstrDesc)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::GetGUIDDescription");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP RegisterGUIDDWORD(REFCLSID rclsid, REFGUID rguid, DWORD dw)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::RegisterGUIDDWORD");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP UnregisterGUIDDWORD(REFCLSID rclsid, REFGUID rguid)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::UnregisterGUIDDWORD");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP GetGUIDDWORD(REFGUID rguid, DWORD *pdw)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::GetGUIDDWORD");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP RegisterGUID(REFGUID rguid, TfGuidAtom *pguidatom)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::RegisterGUID");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP GetGUID(TfGuidAtom guidatom, GUID *pguid)
-  {
-    if (guidatom == GUID_ATOM_COMPOSING_SELECTION_ATTR) {
-      *pguid = GUID_COMPOSING_SELECTION_ATTR;
-      return S_OK;
-    }
-    NS_NOTREACHED("ITfCategoryMgr::GetGUID");
-    return E_FAIL;
-  }
-
-  STDMETHODIMP IsEqualTfGuidAtom(TfGuidAtom guidatom, REFGUID rguid,
-                                 BOOL *pfEqual)
-  {
-    NS_NOTREACHED("ITfCategoryMgr::IsEqualTfGuidAtom");
-    return E_NOTIMPL;
-  }
-
-public: // ITfDisplayAttributeMgr
-
-  STDMETHODIMP OnUpdateInfo()
-  {
-    NS_NOTREACHED("ITfDisplayAttributeMgr::OnUpdateInfo");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP EnumDisplayAttributeInfo(IEnumTfDisplayAttributeInfo **ppEnum)
-  {
-    NS_NOTREACHED("ITfDisplayAttributeMgr::EnumDisplayAttributeInfo");
-    return E_NOTIMPL;
-  }
-
-  STDMETHODIMP GetDisplayAttributeInfo(REFGUID guid,
-                                       ITfDisplayAttributeInfo **ppInfo,
-                                       CLSID *pclsidOwner)
-  {
-    NS_ENSURE_TRUE(ppInfo, E_INVALIDARG);
-    NS_ENSURE_TRUE(!pclsidOwner, E_INVALIDARG);
-    if (guid == GUID_COMPOSING_SELECTION_ATTR) {
-      (*ppInfo) = new TSFDispAttrInfoImpl(guid);
-      (*ppInfo)->AddRef();
-      return S_OK;
-    }
-    NS_NOTREACHED("ITfDisplayAttributeMgr::GetDisplayAttributeInfo");
-    return E_FAIL;
-  }
-
 public: // ITfContext
 
   STDMETHODIMP RequestEditSession(TfClientId tid, ITfEditSession *pes,
                                   DWORD dwFlags, HRESULT *phrSession)
   {
     NS_NOTREACHED("ITfContext::RequestEditSession");
     return E_NOTIMPL;
   }
@@ -1247,35 +972,465 @@ public: // ITextStoreACPSink
   }
 
   STDMETHODIMP OnAttrsChange(LONG acpStart, LONG acpEnd, ULONG cAttrs,
                           const TS_ATTRID *paAttrs)
   {
     return S_OK;
   }
 
-  STDMETHODIMP OnLockGranted(DWORD dwLockFlags)
-  {
-    // If we have a test, run it
-    if (mTest && !(mTestApp->*mTest)())
-      return S_FALSE;
-    return S_OK;
-  }
+  STDMETHODIMP OnLockGranted(DWORD dwLockFlags);
 
   STDMETHODIMP OnStartEditTransaction(void)
   {
     return S_OK;
   }
 
   STDMETHODIMP OnEndEditTransaction(void)
   {
     return S_OK;
   }
 };
 
+/******************************************************************************
+ * TSFDocumentMgrImpl
+ ******************************************************************************/
+
+class TSFDocumentMgrImpl : public ITfDocumentMgr
+{
+private:
+  ULONG mRefCnt;
+
+public:
+  nsRefPtr<TSFMgrImpl> mMgr;
+  nsRefPtr<ITextStoreACP> mStore;
+  nsRefPtr<TSFContextImpl> mContextBase;
+  nsRefPtr<TSFContextImpl> mContextTop; // XXX currently, we don't support this.
+
+public:
+  TSFDocumentMgrImpl(TSFMgrImpl* aMgr) :
+      mRefCnt(0), mMgr(aMgr)
+  {
+  }
+
+  ~TSFDocumentMgrImpl()
+  {
+  }
+
+public: // IUnknown
+
+  STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk)
+  {
+    *ppUnk = NULL;
+    if (IID_IUnknown == riid || IID_ITfDocumentMgr == riid)
+      *ppUnk = static_cast<ITfDocumentMgr*>(this);
+    if (*ppUnk)
+      AddRef();
+    return *ppUnk ? S_OK : E_NOINTERFACE;
+  }
+
+  STDMETHODIMP_(ULONG) AddRef(void)
+  {
+    return ++mRefCnt;
+  }
+
+  STDMETHODIMP_(ULONG) Release(void);
+
+public: // ITfDocumentMgr
+
+  STDMETHODIMP CreateContext(TfClientId tidOwner, DWORD dwFlags,
+                             IUnknown *punk, ITfContext **ppic,
+                             TfEditCookie *pecTextStore)
+  {
+    nsRefPtr<TSFContextImpl> context = new TSFContextImpl(this);
+    punk->QueryInterface(IID_ITextStoreACP, getter_AddRefs(mStore));
+    NS_ENSURE_TRUE(mStore, E_FAIL);
+    HRESULT hr =
+      mStore->AdviseSink(IID_ITextStoreACPSink,
+                         static_cast<ITextStoreACPSink*>(context.get()),
+                         TS_AS_ALL_SINKS);
+    if (FAILED(hr)) mStore = NULL;
+    NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL);
+    (*ppic) = context;
+    (*ppic)->AddRef();
+    *pecTextStore = 1;
+    return S_OK;
+  }
+
+  STDMETHODIMP Push(ITfContext *pic)
+  {
+    if (mContextTop) {
+      NS_NOTREACHED("TSFDocumentMgrImpl::Push stack is already full");
+      return E_FAIL;
+    }
+    if (mContextBase) {
+      NS_WARNING("TSFDocumentMgrImpl::Push additional context is pushed, but we don't support that yet.");
+      if (mContextBase == pic) {
+        NS_NOTREACHED("TSFDocumentMgrImpl::Push same context is pused again");
+        return E_FAIL;
+      }
+      mContextTop = static_cast<TSFContextImpl*>(pic);
+      return S_OK;
+    }
+    mContextBase = static_cast<TSFContextImpl*>(pic);
+    return S_OK;
+  }
+
+  STDMETHODIMP Pop(DWORD dwFlags)
+  {
+    if (!mStore)
+      return E_FAIL;
+    if (dwFlags == TF_POPF_ALL) {
+      NS_ENSURE_TRUE(mContextBase, E_FAIL);
+      mStore->UnadviseSink(static_cast<ITextStoreACPSink*>(mContextBase.get()));
+      mStore = NULL;
+      mContextBase = nsnull;
+      mContextTop = nsnull;
+      return S_OK;
+    }
+    if (dwFlags == 0) {
+      if (!mContextTop) {
+        NS_NOTREACHED("TSFDocumentMgrImpl::Pop there is non-base context");
+        return E_FAIL;
+      }
+      mContextTop = nsnull;
+      return S_OK;
+    }
+    NS_NOTREACHED("TSFDocumentMgrImpl::Pop invalid flag");
+    return E_FAIL;
+  }
+
+  STDMETHODIMP GetTop(ITfContext **ppic)
+  {
+    (*ppic) = mContextTop ? mContextTop : mContextBase;
+    if (*ppic) (*ppic)->AddRef();
+    return S_OK;
+  }
+
+  STDMETHODIMP GetBase(ITfContext **ppic)
+  {
+    (*ppic) = mContextBase;
+    if (*ppic) (*ppic)->AddRef();
+    return S_OK;
+  }
+
+  STDMETHODIMP EnumContexts(IEnumTfContexts **ppEnum)
+  {
+    NS_NOTREACHED("ITfDocumentMgr::EnumContexts");
+    return E_NOTIMPL;
+  }
+
+};
+
+/******************************************************************************
+ * TSFMgrImpl
+ ******************************************************************************/
+
+class TSFMgrImpl : public ITfThreadMgr,
+                   public ITfDisplayAttributeMgr, public ITfCategoryMgr
+{
+private:
+  ULONG mRefCnt;
+
+public:
+  nsRefPtr<TestApp> mTestApp;
+  TestApp::test_type mTest;
+  PRBool mDeactivated;
+  TSFDocumentMgrImpl* mFocusedDocument; // Must be raw pointer, but strong.
+  PRInt32 mFocusCount;
+
+  TSFMgrImpl(TestApp* test) : mTestApp(test), mTest(nsnull), mRefCnt(0),
+    mDeactivated(PR_FALSE), mFocusCount(0)
+  {
+  }
+
+  ~TSFMgrImpl()
+  {
+  }
+
+public: // IUnknown
+
+  STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk)
+  {
+    *ppUnk = NULL;
+    if (IID_IUnknown == riid || IID_ITfThreadMgr == riid)
+      *ppUnk = static_cast<ITfThreadMgr*>(this);
+    else if (IID_ITfDisplayAttributeMgr == riid)
+      *ppUnk = static_cast<ITfDisplayAttributeMgr*>(this);
+    else if (IID_ITfCategoryMgr == riid)
+      *ppUnk = static_cast<ITfCategoryMgr*>(this);
+    if (*ppUnk)
+      AddRef();
+    return *ppUnk ? S_OK : E_NOINTERFACE;
+  }
+
+  STDMETHODIMP_(ULONG) AddRef(void)
+  {
+    return ++mRefCnt;
+  }
+
+  STDMETHODIMP_(ULONG) Release(void)
+  {
+    if (--mRefCnt) return mRefCnt;
+    delete this;
+    return 0;
+  }
+
+public: // ITfThreadMgr
+
+  STDMETHODIMP Activate(TfClientId *ptid)
+  {
+    *ptid = 1;
+    return S_OK;
+  }
+
+  STDMETHODIMP Deactivate(void)
+  {
+    mDeactivated = PR_TRUE;
+    return S_OK;
+  }
+
+  STDMETHODIMP CreateDocumentMgr(ITfDocumentMgr **ppdim)
+  {
+    nsRefPtr<TSFDocumentMgrImpl> docMgr = new TSFDocumentMgrImpl(this);
+    if (!docMgr) {
+      NS_NOTREACHED("TSFMgrImpl::CreateDocumentMgr (OOM)");
+      return E_OUTOFMEMORY;
+    }
+    (*ppdim) = docMgr;
+    (*ppdim)->AddRef();
+    return S_OK;
+  }
+
+  STDMETHODIMP EnumDocumentMgrs(IEnumTfDocumentMgrs **ppEnum)
+  {
+    NS_NOTREACHED("ITfThreadMgr::EnumDocumentMgrs");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP GetFocus(ITfDocumentMgr **ppdimFocus)
+  {
+    (*ppdimFocus) = mFocusedDocument;
+    if (*ppdimFocus) (*ppdimFocus)->AddRef();
+    return S_OK;
+  }
+
+  STDMETHODIMP SetFocus(ITfDocumentMgr *pdimFocus)
+  {
+    if (!pdimFocus) {
+      NS_NOTREACHED("ITfThreadMgr::SetFocus must not be called with NULL");
+      return E_FAIL;
+    }
+    mFocusCount++;
+    if (mFocusedDocument == pdimFocus) {
+      return S_OK;
+    }
+    mFocusedDocument = static_cast<TSFDocumentMgrImpl*>(pdimFocus);
+    mFocusedDocument->AddRef();
+    return S_OK;
+  }
+
+  STDMETHODIMP AssociateFocus(HWND hwnd, ITfDocumentMgr *pdimNew,
+                           ITfDocumentMgr **ppdimPrev)
+  {
+    NS_NOTREACHED("ITfThreadMgr::AssociateFocus");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP IsThreadFocus(BOOL *pfThreadFocus)
+  {
+    *pfThreadFocus = TRUE;
+    return S_OK;
+  }
+
+  STDMETHODIMP GetFunctionProvider(REFCLSID clsid,
+                                ITfFunctionProvider **ppFuncProv)
+  {
+    NS_NOTREACHED("ITfThreadMgr::GetFunctionProvider");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP EnumFunctionProviders(IEnumTfFunctionProviders **ppEnum)
+  {
+    NS_NOTREACHED("ITfThreadMgr::EnumFunctionProviders");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP GetGlobalCompartment(ITfCompartmentMgr **ppCompMgr)
+  {
+    NS_NOTREACHED("ITfThreadMgr::GetGlobalCompartment");
+    return E_NOTIMPL;
+  }
+
+public: // ITfCategoryMgr
+
+  STDMETHODIMP RegisterCategory(REFCLSID rclsid, REFGUID rcatid, REFGUID rguid)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::RegisterCategory");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP UnregisterCategory(REFCLSID rclsid, REFGUID rcatid, REFGUID rguid)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::UnregisterCategory");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP EnumCategoriesInItem(REFGUID rguid, IEnumGUID **ppEnum)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::EnumCategoriesInItem");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP EnumItemsInCategory(REFGUID rcatid, IEnumGUID **ppEnum)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::EnumItemsInCategory");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP FindClosestCategory(REFGUID rguid, GUID *pcatid,
+                                   const GUID **ppcatidList, ULONG ulCount)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::FindClosestCategory");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP RegisterGUIDDescription(REFCLSID rclsid, REFGUID rguid,
+                                       const WCHAR *pchDesc, ULONG cch)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::RegisterGUIDDescription");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP UnregisterGUIDDescription(REFCLSID rclsid, REFGUID rguid)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::UnregisterGUIDDescription");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP GetGUIDDescription(REFGUID rguid, BSTR *pbstrDesc)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::GetGUIDDescription");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP RegisterGUIDDWORD(REFCLSID rclsid, REFGUID rguid, DWORD dw)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::RegisterGUIDDWORD");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP UnregisterGUIDDWORD(REFCLSID rclsid, REFGUID rguid)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::UnregisterGUIDDWORD");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP GetGUIDDWORD(REFGUID rguid, DWORD *pdw)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::GetGUIDDWORD");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP RegisterGUID(REFGUID rguid, TfGuidAtom *pguidatom)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::RegisterGUID");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP GetGUID(TfGuidAtom guidatom, GUID *pguid)
+  {
+    if (guidatom == GUID_ATOM_COMPOSING_SELECTION_ATTR) {
+      *pguid = GUID_COMPOSING_SELECTION_ATTR;
+      return S_OK;
+    }
+    NS_NOTREACHED("ITfCategoryMgr::GetGUID");
+    return E_FAIL;
+  }
+
+  STDMETHODIMP IsEqualTfGuidAtom(TfGuidAtom guidatom, REFGUID rguid,
+                                 BOOL *pfEqual)
+  {
+    NS_NOTREACHED("ITfCategoryMgr::IsEqualTfGuidAtom");
+    return E_NOTIMPL;
+  }
+
+public: // ITfDisplayAttributeMgr
+
+  STDMETHODIMP OnUpdateInfo()
+  {
+    NS_NOTREACHED("ITfDisplayAttributeMgr::OnUpdateInfo");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP EnumDisplayAttributeInfo(IEnumTfDisplayAttributeInfo **ppEnum)
+  {
+    NS_NOTREACHED("ITfDisplayAttributeMgr::EnumDisplayAttributeInfo");
+    return E_NOTIMPL;
+  }
+
+  STDMETHODIMP GetDisplayAttributeInfo(REFGUID guid,
+                                       ITfDisplayAttributeInfo **ppInfo,
+                                       CLSID *pclsidOwner)
+  {
+    NS_ENSURE_TRUE(ppInfo, E_INVALIDARG);
+    NS_ENSURE_TRUE(!pclsidOwner, E_INVALIDARG);
+    if (guid == GUID_COMPOSING_SELECTION_ATTR) {
+      (*ppInfo) = new TSFDispAttrInfoImpl(guid);
+      (*ppInfo)->AddRef();
+      return S_OK;
+    }
+    NS_NOTREACHED("ITfDisplayAttributeMgr::GetDisplayAttributeInfo");
+    return E_FAIL;
+  }
+
+public:
+
+  ITextStoreACP* GetFocusedStore()
+  {
+    return mFocusedDocument ? mFocusedDocument->mStore : nsnull;
+  }
+
+  TSFContextImpl* GetFocusedContext()
+  {
+    return mFocusedDocument ? mFocusedDocument->mContextBase : nsnull;
+  }
+
+  TSFAttrPropImpl* GetFocusedAttrProp()
+  {
+    TSFContextImpl* context = GetFocusedContext();
+    return context ? context->mAttrProp : nsnull;
+  }
+
+};
+
+STDMETHODIMP
+TSFContextImpl::OnLockGranted(DWORD dwLockFlags)
+{
+  // If we have a test, run it
+  if (mDocMgr->mMgr->mTest &&
+     !(mDocMgr->mMgr->mTestApp->*(mDocMgr->mMgr->mTest))())
+    return S_FALSE;
+  return S_OK;
+}
+
+
+STDMETHODIMP_(ULONG)
+TSFDocumentMgrImpl::Release(void)
+{
+  --mRefCnt;
+  if (mRefCnt == 1 && mMgr->mFocusedDocument == this) {
+    mMgr->mFocusedDocument = nsnull;
+    --mRefCnt;
+  }
+  if (mRefCnt) return mRefCnt;
+  delete this;
+  return 0;
+}
+
 NS_IMPL_ISUPPORTS2(TestApp, nsIWebProgressListener,
                             nsISupportsWeakReference)
 
 nsresult
 TestApp::Run(void)
 {
   // Create a test window
   // We need a full-fledged window to test for TSF functionality
@@ -1311,21 +1466,21 @@ TestApp::Run(void)
   mAppShell->Run();
   return NS_OK;
 }
 
 PRBool
 TestApp::CheckFailed(void)
 {
   // All windows should be closed by now
-  if (mImpl && !mImpl->mDeactivated) {
+  if (mMgr && !mMgr->mDeactivated) {
     fail("TSF not terminated properly");
     mFailed = PR_TRUE;
   }
-  mImpl = nsnull;
+  mMgr = nsnull;
   return mFailed;
 }
 
 nsresult
 TestApp::Init(void)
 {
   // Replace TSF manager pointer, category manager pointer and display
   // attribute manager pointer.
@@ -1358,25 +1513,25 @@ TestApp::Init(void)
   }
   ITfDisplayAttributeMgr **daMgr = reinterpret_cast<ITfDisplayAttributeMgr**>(
       widget->GetNativeData(NS_NATIVE_TSF_DISPLAY_ATTR_MGR));
   if (*daMgr) {
     (*daMgr)->Release();
     (*daMgr) = NULL;
   }
 
-  mImpl = new TSFImpl(this);
-  if (!mImpl) {
+  mMgr = new TSFMgrImpl(this);
+  if (!mMgr) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
-  (*threadMgr) = mImpl;
+  (*threadMgr) = mMgr;
   (*threadMgr)->AddRef();
-  (*catMgr) = mImpl;
+  (*catMgr) = mMgr;
   (*catMgr)->AddRef();
-  (*daMgr) = mImpl;
+  (*daMgr) = mMgr;
   (*daMgr)->AddRef();
 
   // Apply the change
   reinterpret_cast<ITfThreadMgr**>(
       widget->GetNativeData(NS_NATIVE_TSF_THREAD_MGR));
 
   // Create a couple of text boxes for testing
   nsCOMPtr<nsIDOMWindowInternal> win(do_GetInterface(mWindow));
@@ -1461,20 +1616,20 @@ TestApp::Term(void)
   mAppShell = nsnull;
   return NS_OK;
 }
 
 PRBool
 TestApp::RunTest(test_type aTest, PRBool aLock)
 {
   PRBool succeeded;
-  if (aLock && mImpl->mStore) {
-    mImpl->mTest = aTest;
+  if (aLock && mMgr && mMgr->GetFocusedStore()) {
+    mMgr->mTest = aTest;
     HRESULT hr = E_FAIL;
-    mImpl->mStore->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &hr);
+    mMgr->GetFocusedStore()->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &hr);
     succeeded = hr == S_OK;
   } else {
     succeeded = (this->*aTest)();
   }
   mFailed |= !succeeded;
   return succeeded;
 }
 
@@ -1487,31 +1642,31 @@ TestApp::OnStateChange(nsIWebProgress *a
   NS_ASSERTION(aStateFlags & nsIWebProgressListener::STATE_IS_WINDOW &&
               aStateFlags & nsIWebProgressListener::STATE_STOP, "wrong state");
   if (NS_SUCCEEDED(Init())) {
     if (RunTest(&TestApp::TestFocus, PR_FALSE))
       passed("TestFocus");
 
     mCurrentNode = mInput;
     mInput->Focus();
-    if (mImpl->mStore) {
+    if (mMgr->GetFocusedStore()) {
       if (RunTest(&TestApp::TestClustering))
         passed("TestClustering");
     } else {
       fail("no text store (clustering)");
       mFailed = PR_TRUE;
     }
 
     printf("Testing TSF support in text input element...\n");
     mCurrentNode = mInput;
     mTestString = NS_LITERAL_STRING(
       "This is a test of the Text Services Framework implementation.");
     mInput->SetValue(mTestString);
     mInput->Focus();
-    if (mImpl->mStore) {
+    if (mMgr->GetFocusedStore()) {
       if (RunTest(&TestApp::TestSelection))
         passed("TestSelection (input)");
       if (RunTest(&TestApp::TestText))
         passed("TestText (input)");
       if (RunTest(&TestApp::TestExtents))
         passed("TestExtents (input)");
       if (RunTest(&TestApp::TestComposition))
         passed("TestComposition (input)");
@@ -1523,17 +1678,17 @@ TestApp::OnStateChange(nsIWebProgress *a
     }
 
     printf("Testing TSF support in textarea element...\n");
     mCurrentNode = mTextArea;
     mTestString = NS_LITERAL_STRING(
       "This is a test of the\r\nText Services Framework\r\nimplementation.");
     mTextArea->SetValue(mTestString);
     mTextArea->Focus();
-    if (mImpl->mStore) {
+    if (mMgr->GetFocusedStore()) {
       if (RunTest(&TestApp::TestSelection))
         passed("TestSelection (textarea)");
       if (RunTest(&TestApp::TestText))
         passed("TestText (textarea)");
       if (RunTest(&TestApp::TestExtents))
         passed("TestExtents (textarea)");
       if (RunTest(&TestApp::TestComposition))
         passed("TestComposition (textarea)");
@@ -1549,113 +1704,134 @@ TestApp::OnStateChange(nsIWebProgress *a
   }
   Term();
   return NS_OK;
 }
 
 PRBool
 TestApp::TestFocus(void)
 {
-  PRUint32 focus = mImpl->mFocusCount, blur = mImpl->mBlurCount;
+  PRUint32 focus = mMgr->mFocusCount;
   nsresult rv;
 
   /* If these fail the cause is probably one or more of:
    * - nsIMEStateManager::OnTextStateFocus not called by nsEventStateManager
    * - nsIMEStateManager::OnTextStateBlur not called by nsEventStateManager
    * - nsWindow::OnIMEFocusChange (nsIWidget) not called by nsIMEStateManager
    * - nsTextStore::Create/Focus/Destroy not called by nsWindow
    * - ITfThreadMgr::CreateDocumentMgr/SetFocus not called by nsTextStore
    * - ITfDocumentMgr::CreateContext/Push not called by nsTextStore
    */
 
   rv = mInput->Focus();
   if (!(NS_SUCCEEDED(rv) &&
-        mImpl->mFocused &&
-        mImpl->mStore &&
-        mImpl->mFocusCount - focus == 1 &&
-        mImpl->mBlurCount - blur == 0 &&
-        mImpl->mStore)) {
+        mMgr->mFocusedDocument &&
+        mMgr->mFocusCount - focus == 1 &&
+        mMgr->GetFocusedStore())) {
     fail("TestFocus: document focus was not set");
     return PR_FALSE;
   }
 
   rv = mTextArea->Focus();
   if (!(NS_SUCCEEDED(rv) &&
-        mImpl->mFocused &&
-        mImpl->mStore &&
-        mImpl->mFocusCount - focus == 2 &&
-        mImpl->mBlurCount - blur == 1 &&
-        mImpl->mStore)) {
+        mMgr->mFocusedDocument &&
+        mMgr->mFocusCount - focus == 2 &&
+        mMgr->GetFocusedStore())) {
     fail("TestFocus: document focus was not changed");
     return PR_FALSE;
   }
 
   rv = mButton->Focus();
   if (!(NS_SUCCEEDED(rv) &&
-        !mImpl->mFocused &&
-        !mImpl->mStore &&
-        mImpl->mFocusCount - focus == 2 &&
-        mImpl->mBlurCount - blur == 2 &&
-        !mImpl->mStore)) {
-    fail("TestFocus: document was not blurred");
+        !mMgr->mFocusedDocument &&
+        mMgr->mFocusCount - focus == 2 &&
+        !mMgr->GetFocusedStore())) {
+    fail("TestFocus: document focus was changed");
     return PR_FALSE;
   }
   return PR_TRUE;
 }
 
 PRBool
 TestApp::TestClustering(void)
 {
   // Text for testing
   const PRUint32 STRING_LENGTH = 2;
   PRUnichar string[3];
   string[0] = 'e';
   string[1] = 0x0301; // U+0301 'acute accent'
   string[2] = nsnull;
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestClustering: GetFocusedStore returns null #1");
+    return PR_FALSE;
+  }
+
   // Replace entire string with our string
   TS_TEXTCHANGE textChange;
-  HRESULT hr = mImpl->mStore->SetText(0, 0, -1, string, STRING_LENGTH,
-                                      &textChange);
+  HRESULT hr =
+    mMgr->GetFocusedStore()->SetText(0, 0, -1, string, STRING_LENGTH,
+                                     &textChange);
   if (!(SUCCEEDED(hr) &&
         0 == textChange.acpStart &&
         STRING_LENGTH == textChange.acpNewEnd)) {
     fail("TestClustering: SetText");
     return PR_FALSE;
   }
 
   TsViewCookie view;
   RECT rectLetter, rectAccent, rectWhole, rectCombined;
   BOOL clipped, nonEmpty;
 
-  hr = mImpl->mStore->GetActiveView(&view);
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestClustering: GetFocusedStore returns null #2");
+    return PR_FALSE;
+  }
+
+  hr = mMgr->GetFocusedStore()->GetActiveView(&view);
   if (!(SUCCEEDED(hr))) {
     fail("TestClustering: GetActiveView");
     return PR_FALSE;
   }
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestClustering: GetFocusedStore returns null #3");
+    return PR_FALSE;
+  }
+
   // Get rect of first char (the letter)
-  hr = mImpl->mStore->GetTextExt(view, 0, STRING_LENGTH / 2,
-                                 &rectLetter, &clipped);
+  hr = mMgr->GetFocusedStore()->GetTextExt(view, 0, STRING_LENGTH / 2,
+                                           &rectLetter, &clipped);
   if (!(SUCCEEDED(hr))) {
     fail("TestClustering: GetTextExt (letter)");
     return PR_FALSE;
   }
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestClustering: GetFocusedStore returns null #4");
+    return PR_FALSE;
+  }
+
   // Get rect of second char (the accent)
-  hr = mImpl->mStore->GetTextExt(view, STRING_LENGTH / 2, STRING_LENGTH,
-                                 &rectAccent, &clipped);
+  hr = mMgr->GetFocusedStore()->GetTextExt(view, STRING_LENGTH / 2,
+                                           STRING_LENGTH,
+                                           &rectAccent, &clipped);
   if (!(SUCCEEDED(hr))) {
     fail("TestClustering: GetTextExt (accent)");
     return PR_FALSE;
   }
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestClustering: GetFocusedStore returns null #5");
+    return PR_FALSE;
+  }
+
   // Get rect of combined char
-  hr = mImpl->mStore->GetTextExt(view, 0, STRING_LENGTH,
-                                 &rectWhole, &clipped);
+  hr = mMgr->GetFocusedStore()->GetTextExt(view, 0, STRING_LENGTH,
+                                           &rectWhole, &clipped);
   if (!(SUCCEEDED(hr))) {
     fail("TestClustering: GetTextExt (whole)");
     return PR_FALSE;
   }
 
   nonEmpty = ::UnionRect(&rectCombined, &rectLetter, &rectAccent);
   if (!(nonEmpty &&
         ::EqualRect(&rectCombined, &rectWhole))) {
@@ -1670,29 +1846,39 @@ TestApp::TestSelectionInternal(char* aTe
                                LONG aStart,
                                LONG aEnd,
                                TsActiveSelEnd aSelEnd)
 {
   PRBool succeeded = PR_TRUE, continueTest = PR_TRUE;
   TS_SELECTION_ACP sel, testSel;
   ULONG selFetched;
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestSelectionInternal: GetFocusedStore returns null #1");
+    return PR_FALSE;
+  }
+
   sel.acpStart = aStart;
   sel.acpEnd = aEnd;
   sel.style.ase = aSelEnd;
   sel.style.fInterimChar = FALSE;
-  HRESULT hr = mImpl->mStore->SetSelection(1, &sel);
+  HRESULT hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
   if (!(SUCCEEDED(hr))) {
     fail("TestSelection: SetSelection (%s)", aTestName);
     continueTest = succeeded = PR_FALSE;
   }
 
   if (continueTest) {
-    hr = mImpl->mStore->GetSelection(TS_DEFAULT_SELECTION, 1,
-                                     &testSel, &selFetched);
+    if (!mMgr->GetFocusedStore()) {
+      fail("TestSelectionInternal: GetFocusedStore returns null #2");
+      return PR_FALSE;
+    }
+
+    hr = mMgr->GetFocusedStore()->GetSelection(TS_DEFAULT_SELECTION, 1,
+                                               &testSel, &selFetched);
     if (!(SUCCEEDED(hr) &&
           selFetched == 1 &&
           !memcmp(&sel, &testSel, sizeof(sel)))) {
       fail("TestSelection: unexpected GetSelection result (%s)", aTestName);
       succeeded = PR_FALSE;
     }
   }
   return succeeded;
@@ -1710,17 +1896,23 @@ TestApp::TestSelection(void)
    * nsTextStore::SetSelection not sending NS_SELECTION_SET
    * NS_SELECTION_SET not handled by nsContentEventHandler
    * Bug in NS_SELECTION_SET handler
    */
 
   TS_SELECTION_ACP testSel;
   ULONG selFetched;
 
-  HRESULT hr = mImpl->mStore->GetSelection(0, 1, &testSel, &selFetched);
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestSelection: GetFocusedStore returns null");
+    return PR_FALSE;
+  }
+
+  HRESULT hr =
+    mMgr->GetFocusedStore()->GetSelection(0, 1, &testSel, &selFetched);
   if (!(SUCCEEDED(hr) &&
         selFetched == 1)) {
     fail("TestSelection: GetSelection");
     succeeded = PR_FALSE;
   }
 
   const LONG SELECTION1_START            = 0;
   const LONG SELECTION1_END              = mTestString.Length();
@@ -1775,76 +1967,99 @@ TestApp::TestText(void)
    * nsTextStore::GetText not sending NS_QUERY_TEXT_CONTENT
    * NS_QUERY_TEXT_CONTENT not handled by nsContentEventHandler
    * Bug in NS_QUERY_TEXT_CONTENT handler
    * nsTextStore::SetText not calling SetSelection or InsertTextAtSelection
    * Bug in SetSelection or InsertTextAtSelection
    *  NS_SELECTION_SET bug or NS_COMPOSITION_* / NS_TEXT_TEXT bug
    */
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestText: GetFocusedStore returns null #1");
+    return PR_FALSE;
+  }
+
   // Get all text
-  hr = mImpl->mStore->GetText(0, -1, buffer, BUFFER_SIZE, &bufferRet,
-      runInfo, RUNINFO_SIZE, &runInfoRet, &acpRet);
+  hr = mMgr->GetFocusedStore()->GetText(0, -1, buffer, BUFFER_SIZE, &bufferRet,
+                                        runInfo, RUNINFO_SIZE, &runInfoRet,
+                                        &acpRet);
   if (!(SUCCEEDED(hr) &&
         bufferRet <= mTestString.Length() &&
         !wcsncmp(mTestString.get(), buffer, bufferRet) &&
         acpRet == LONG(bufferRet) &&
         runInfoRet > 0)) {
     fail("TestText: GetText 1");
     succeeded = PR_FALSE;
   }
 
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestText: GetFocusedStore returns null #2");
+    return PR_FALSE;
+  }
+
   // Get text from GETTEXT2_START to GETTEXT2_END
   const PRUint32 GETTEXT2_START       = (18);
   const PRUint32 GETTEXT2_END         = (mTestString.Length() - 16);
   const PRUint32 GETTEXT2_BUFFER_SIZE = (0x10);
 
-  hr = mImpl->mStore->GetText(GETTEXT2_START, GETTEXT2_END,
-      buffer, GETTEXT2_BUFFER_SIZE, &bufferRet,
-      runInfo, RUNINFO_SIZE, &runInfoRet, &acpRet);
+  hr = mMgr->GetFocusedStore()->GetText(GETTEXT2_START, GETTEXT2_END,
+                                        buffer, GETTEXT2_BUFFER_SIZE,
+                                        &bufferRet, runInfo, RUNINFO_SIZE,
+                                        &runInfoRet, &acpRet);
   if (!(SUCCEEDED(hr) &&
         bufferRet <= GETTEXT2_BUFFER_SIZE &&
         !wcsncmp(mTestString.get() + GETTEXT2_START, buffer, bufferRet) &&
         acpRet == LONG(bufferRet) + GETTEXT2_START &&
         runInfoRet > 0)) {
     fail("TestText: GetText 2");
     succeeded = PR_FALSE;
   }
 
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestText: GetFocusedStore returns null #3");
+    return PR_FALSE;
+  }
+
   // Replace text from SETTEXT1_START to SETTEXT1_END with insertString
   const PRUint32 SETTEXT1_START        = (8);
   const PRUint32 SETTEXT1_TAIL_LENGTH  = (40);
   const PRUint32 SETTEXT1_END          = (mTestString.Length() -
                                           SETTEXT1_TAIL_LENGTH);
   NS_NAMED_LITERAL_STRING(insertString, "(Inserted string)");
 
   continueTest = PR_TRUE;
-  hr = mImpl->mStore->SetText(0, SETTEXT1_START, SETTEXT1_END,
-      insertString.get(), insertString.Length(), &textChange);
+  hr = mMgr->GetFocusedStore()->SetText(0, SETTEXT1_START, SETTEXT1_END,
+                                        insertString.get(),
+                                        insertString.Length(), &textChange);
   if (!(SUCCEEDED(hr) &&
         textChange.acpStart == SETTEXT1_START &&
         textChange.acpOldEnd == LONG(SETTEXT1_END) &&
         textChange.acpNewEnd == LONG(SETTEXT1_START +
                                 insertString.Length()))) {
     fail("TestText: SetText 1");
     continueTest = succeeded = PR_FALSE;
   }
 
   const PRUint32 SETTEXT1_FINAL_LENGTH = (SETTEXT1_START +
                                           SETTEXT1_TAIL_LENGTH +
                                           insertString.Length());
 
   if (continueTest) {
     acpCurrent = 0;
     while (acpCurrent < LONG(SETTEXT1_FINAL_LENGTH)) {
-      hr = mImpl->mStore->GetText(acpCurrent, -1, &buffer[acpCurrent],
-                                  BUFFER_SIZE, &bufferRet, runInfo,
-                                  RUNINFO_SIZE, &runInfoRet, &acpRet);
+      if (!mMgr->GetFocusedStore()) {
+        fail("TestText: GetFocusedStore returns null #4");
+        return PR_FALSE;
+      }
+
+      hr = mMgr->GetFocusedStore()->GetText(acpCurrent, -1, &buffer[acpCurrent],
+                                            BUFFER_SIZE, &bufferRet, runInfo,
+                                            RUNINFO_SIZE, &runInfoRet, &acpRet);
       if (!(SUCCEEDED(hr) &&
             acpRet > acpCurrent &&
             bufferRet <= SETTEXT1_FINAL_LENGTH &&
             runInfoRet > 0)) {
         fail("TestText: GetText failed after SetTest 1");
         continueTest = succeeded = PR_FALSE;
         break;
       }
@@ -1860,33 +2075,44 @@ TestApp::TestText(void)
           !wcsncmp(&buffer[SETTEXT1_START + insertString.Length()],
                    mTestString.get() + SETTEXT1_END, SETTEXT1_TAIL_LENGTH))) {
       fail("TestText: unexpected GetText result after SetText 1");
       succeeded = PR_FALSE;
     }
   }
 
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestText: GetFocusedStore returns null #5");
+    return PR_FALSE;
+  }
+
   // Restore entire text to original text (mTestString)
   continueTest = PR_TRUE;
-  hr = mImpl->mStore->SetText(0, 0, -1, mTestString.get(),
-      mTestString.Length(), &textChange);
+  hr = mMgr->GetFocusedStore()->SetText(0, 0, -1, mTestString.get(),
+                                        mTestString.Length(), &textChange);
   if (!(SUCCEEDED(hr) &&
         textChange.acpStart == 0 &&
         textChange.acpOldEnd == LONG(SETTEXT1_FINAL_LENGTH) &&
         textChange.acpNewEnd == LONG(mTestString.Length()))) {
     fail("TestText: SetText 2");
     continueTest = succeeded = PR_FALSE;
   }
 
   if (continueTest) {
     acpCurrent = 0;
     while (acpCurrent < LONG(mTestString.Length())) {
-      hr = mImpl->mStore->GetText(acpCurrent, -1, &buffer[acpCurrent],
-          BUFFER_SIZE, &bufferRet, runInfo, RUNINFO_SIZE, &runInfoRet, &acpRet);
+      if (!mMgr->GetFocusedStore()) {
+        fail("TestText: GetFocusedStore returns null #6");
+        return PR_FALSE;
+      }
+
+      hr = mMgr->GetFocusedStore()->GetText(acpCurrent, -1, &buffer[acpCurrent],
+                                            BUFFER_SIZE, &bufferRet, runInfo,
+                                            RUNINFO_SIZE, &runInfoRet, &acpRet);
       if (!(SUCCEEDED(hr) &&
             acpRet > acpCurrent &&
             bufferRet <= mTestString.Length() &&
             runInfoRet > 0)) {
         fail("TestText: GetText failed after SetText 2");
         continueTest = succeeded = PR_FALSE;
         break;
       }
@@ -1902,22 +2128,27 @@ TestApp::TestText(void)
     }
   }
   return succeeded;
 }
 
 PRBool
 TestApp::TestExtents(void)
 {
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestExtents: GetFocusedStore returns null #1");
+    return PR_FALSE;
+  }
+
   TS_SELECTION_ACP sel;
   sel.acpStart = 0;
   sel.acpEnd = 0;
   sel.style.ase = TS_AE_END;
   sel.style.fInterimChar = FALSE;
-  mImpl->mStore->SetSelection(1, &sel);
+  mMgr->GetFocusedStore()->SetSelection(1, &sel);
 
   nsCOMPtr<nsISelectionController> selCon;
   if (!(NS_SUCCEEDED(GetSelCon(getter_AddRefs(selCon))) && selCon)) {
     fail("TestExtents: get nsISelectionController");
     return PR_FALSE;
   }
   selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
               nsISelectionController::SELECTION_FOCUS_REGION, PR_TRUE);
@@ -1941,68 +2172,98 @@ TestApp::TestExtents(void)
   windowRect.right = windowRect.left + val;
   nsr |= window->GetOuterHeight(&val);
   windowRect.bottom = windowRect.top + val;
   if (!(NS_SUCCEEDED(nsr))) {
     fail("TestExtents: get window rect failed");
     return PR_FALSE;
   }
 
-  hr = mImpl->mStore->GetActiveView(&view);
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestExtents: GetFocusedStore returns null #2");
+    return PR_FALSE;
+  }
+
+  hr = mMgr->GetFocusedStore()->GetActiveView(&view);
   if (!(SUCCEEDED(hr))) {
     fail("TestExtents: GetActiveView");
     return PR_FALSE;
   }
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestExtents: GetFocusedStore returns null #3");
+    return PR_FALSE;
+  }
+
   PRBool succeeded = PR_TRUE;
   HWND hwnd;
-  hr = mImpl->mStore->GetWnd(view, &hwnd);
+  hr = mMgr->GetFocusedStore()->GetWnd(view, &hwnd);
   if (!(SUCCEEDED(hr) &&
         ::IsWindow(hwnd))) {
     fail("TestExtents: GetWnd");
     succeeded = PR_FALSE;
   }
 
   ::SetRectEmpty(&screenRect);
-  hr = mImpl->mStore->GetScreenExt(view, &screenRect);
+
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestExtents: GetFocusedStore returns null #4");
+    return PR_FALSE;
+  }
+
+  hr = mMgr->GetFocusedStore()->GetScreenExt(view, &screenRect);
   if (!(SUCCEEDED(hr) &&
         screenRect.left > windowRect.left &&
         screenRect.top > windowRect.top &&
         screenRect.right > screenRect.left &&
         screenRect.bottom > screenRect.top &&
         screenRect.right < windowRect.right &&
         screenRect.bottom < windowRect.bottom)) {
     fail("TestExtents: GetScreenExt");
     succeeded = PR_FALSE;
   }
 
   const LONG GETTEXTEXT1_START = 0;
   const LONG GETTEXTEXT1_END   = 0;
 
   ::SetRectEmpty(&textRect1);
-  hr = mImpl->mStore->GetTextExt(view, GETTEXTEXT1_START, GETTEXTEXT1_END,
-      &textRect1, &clipped);
+
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestExtents: GetFocusedStore returns null #5");
+    return PR_FALSE;
+  }
+
+  hr = mMgr->GetFocusedStore()->GetTextExt(view, GETTEXTEXT1_START,
+                                           GETTEXTEXT1_END, &textRect1,
+                                           &clipped);
   if (!(SUCCEEDED(hr) &&
         textRect1.left >= screenRect.left &&
         textRect1.top >= screenRect.top &&
         textRect1.right < screenRect.right &&
         textRect1.bottom <= screenRect.bottom &&
         textRect1.right >= textRect1.left &&
         textRect1.bottom > textRect1.top)) {
     fail("TestExtents: GetTextExt (offset %ld to %ld)",
          GETTEXTEXT1_START, GETTEXTEXT1_END);
     succeeded = PR_FALSE;
   }
 
   const LONG GETTEXTEXT2_START = 10;
   const LONG GETTEXTEXT2_END   = 25;
 
   ::SetRectEmpty(&textRect2);
-  hr = mImpl->mStore->GetTextExt(view, GETTEXTEXT2_START, GETTEXTEXT2_END,
-      &textRect2, &clipped);
+
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestExtents: GetFocusedStore returns null #6");
+    return PR_FALSE;
+  }
+
+  hr = mMgr->GetFocusedStore()->GetTextExt(view, GETTEXTEXT2_START,
+                                           GETTEXTEXT2_END, &textRect2,
+                                           &clipped);
   if (!(SUCCEEDED(hr) &&
         textRect2.left >= screenRect.left &&
         textRect2.top >= screenRect.top &&
         textRect2.right <= screenRect.right &&
         textRect2.bottom <= screenRect.bottom &&
         textRect2.right > textRect2.left &&
         textRect2.bottom > textRect2.top)) {
     fail("TestExtents: GetTextExt (offset %ld to %ld)",
@@ -2010,18 +2271,25 @@ TestApp::TestExtents(void)
     succeeded = PR_FALSE;
   }
 
   // Offsets must be between GETTEXTEXT2_START and GETTEXTEXT2_END
   const LONG GETTEXTEXT3_START = 23;
   const LONG GETTEXTEXT3_END   = 23;
 
   ::SetRectEmpty(&textRect1);
-  hr = mImpl->mStore->GetTextExt(view, GETTEXTEXT3_START, GETTEXTEXT3_END,
-        &textRect1, &clipped);
+
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestExtents: GetFocusedStore returns null #7");
+    return PR_FALSE;
+  }
+
+  hr = mMgr->GetFocusedStore()->GetTextExt(view, GETTEXTEXT3_START,
+                                           GETTEXTEXT3_END, &textRect1,
+                                           &clipped);
   // Rectangle must be entirely inside the previous rectangle,
   // since GETTEXTEXT3_START and GETTEXTEXT3_END are between
   // GETTEXTEXT2_START and GETTEXTEXT2_START
   if (!(SUCCEEDED(hr) && ::IsRectEmpty(&textRect1) ||
         (textRect1.left >= textRect2.left &&
         textRect1.top >= textRect2.top &&
         textRect1.right <= textRect2.right &&
         textRect1.bottom <= textRect2.bottom &&
@@ -2035,37 +2303,48 @@ TestApp::TestExtents(void)
 }
 
 PRBool
 TestApp::TestCompositionSelectionAndText(char* aTestName,
                                          LONG aExpectedSelStart,
                                          LONG aExpectedSelEnd,
                                          nsString& aReferenceString)
 {
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestCompositionSelectionAndText: GetFocusedStore returns null #1");
+    return PR_FALSE;
+  }
+
   TS_SELECTION_ACP currentSel;
   ULONG selFetched = 0;
-  HRESULT hr = mImpl->mStore->GetSelection(TF_DEFAULT_SELECTION, 1,
-                                           &currentSel, &selFetched);
+  HRESULT hr = mMgr->GetFocusedStore()->GetSelection(TF_DEFAULT_SELECTION, 1,
+                                                     &currentSel, &selFetched);
   if (!(SUCCEEDED(hr) &&
         1 == selFetched &&
         currentSel.acpStart == aExpectedSelStart &&
         currentSel.acpEnd == aExpectedSelEnd)) {
     fail("TestComposition: GetSelection (%s)", aTestName);
     return PR_FALSE;
   }
 
   const PRUint32 bufferSize = 0x100, runInfoSize = 0x10;
   PRUnichar buffer[bufferSize];
   TS_RUNINFO runInfo[runInfoSize];
   ULONG bufferRet, runInfoRet;
   LONG acpRet, acpCurrent = 0;
   while (acpCurrent < LONG(aReferenceString.Length())) {
-    hr = mImpl->mStore->GetText(acpCurrent, aReferenceString.Length(),
-          &buffer[acpCurrent], bufferSize, &bufferRet, runInfo, runInfoSize,
-          &runInfoRet, &acpRet);
+    if (!mMgr->GetFocusedStore()) {
+      fail("TestCompositionSelectionAndText: GetFocusedStore returns null #2");
+      return PR_FALSE;
+    }
+
+    hr = mMgr->GetFocusedStore()->GetText(acpCurrent, aReferenceString.Length(),
+                                          &buffer[acpCurrent], bufferSize,
+                                          &bufferRet, runInfo, runInfoSize,
+                                          &runInfoRet, &acpRet);
     if (!(SUCCEEDED(hr) &&
           acpRet > acpCurrent &&
           bufferRet <= aReferenceString.Length() &&
           runInfoRet > 0)) {
       fail("TestComposition: GetText (%s)", aTestName);
       return PR_FALSE;
     }
     acpCurrent = acpRet;
@@ -2076,100 +2355,129 @@ TestApp::TestCompositionSelectionAndText
     return PR_FALSE;
   }
   return PR_TRUE;
 }
 
 PRBool
 TestApp::TestComposition(void)
 {
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestComposition: GetFocusedStore returns null #1");
+    return PR_FALSE;
+  }
+
   nsRefPtr<ITfContextOwnerCompositionSink> sink;
-  HRESULT hr = mImpl->mStore->QueryInterface(
-                                  IID_ITfContextOwnerCompositionSink,
-                                  getter_AddRefs(sink));
+  HRESULT hr =
+    mMgr->GetFocusedStore()->QueryInterface(IID_ITfContextOwnerCompositionSink,
+                                            getter_AddRefs(sink));
   if (!(SUCCEEDED(hr))) {
     fail("TestComposition: QueryInterface");
     return PR_FALSE;
   }
 
   const LONG PRECOMPOSITION_SEL_START            = 2;
   const LONG PRECOMPOSITION_SEL_END              = PRECOMPOSITION_SEL_START;
   const TsActiveSelEnd PRECOMPOSITION_SEL_SELEND = TS_AE_END;
 
   TS_SELECTION_ACP sel;
   sel.acpStart = PRECOMPOSITION_SEL_START;
   sel.acpEnd = PRECOMPOSITION_SEL_END;
   sel.style.ase = PRECOMPOSITION_SEL_SELEND;
   sel.style.fInterimChar = FALSE;
-  hr = mImpl->mStore->SetSelection(1, &sel);
+  hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
   if (!(SUCCEEDED(hr))) {
     fail("TestComposition: SetSelection (pre-composition)");
     return PR_FALSE;
   }
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestComposition: GetFocusedStore returns null #2");
+    return PR_FALSE;
+  }
 
   TS_TEXTCHANGE textChange;
   NS_NAMED_LITERAL_STRING(insertString1, "Compo1");
-  hr = mImpl->mStore->InsertTextAtSelection(TF_IAS_NOQUERY,
-                                            insertString1.get(),
-                                            insertString1.Length(),
-                                            NULL, NULL, &textChange);
+  hr = mMgr->GetFocusedStore()->InsertTextAtSelection(TF_IAS_NOQUERY,
+                                                      insertString1.get(),
+                                                      insertString1.Length(),
+                                                      NULL, NULL, &textChange);
   if (!(SUCCEEDED(hr) &&
         sel.acpEnd == textChange.acpStart &&
         sel.acpEnd == textChange.acpOldEnd &&
         sel.acpEnd + insertString1.Length() == textChange.acpNewEnd)) {
     fail("TestComposition: InsertTextAtSelection");
     return PR_FALSE;
   }
   sel.acpEnd = textChange.acpNewEnd;
 
-  mImpl->mAttrProp->mRanges.Clear();
+  if (!mMgr->GetFocusedAttrProp()) {
+    fail("TestComposition: GetFocusedAttrProp returns null #1");
+    return PR_FALSE;
+  }
+  mMgr->GetFocusedAttrProp()->mRanges.Clear();
   nsRefPtr<TSFRangeImpl> range =
     new TSFRangeImpl(textChange.acpStart,
                      textChange.acpNewEnd - textChange.acpOldEnd);
-  mImpl->mAttrProp->mRanges.AppendElement(range);
+  if (!mMgr->GetFocusedAttrProp()) {
+    fail("TestComposition: GetFocusedAttrProp returns null #2");
+    return PR_FALSE;
+  }
+  mMgr->GetFocusedAttrProp()->mRanges.AppendElement(range);
 
   BOOL okay = FALSE;
-  hr = sink->OnStartComposition(mImpl, &okay);
+  hr = sink->OnStartComposition(mMgr->GetFocusedContext(), &okay);
   if (!(SUCCEEDED(hr) &&
         okay)) {
     fail("TestComposition: OnStartComposition");
     return PR_FALSE;
   }
 
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestComposition: GetFocusedStore returns null #3");
+    return PR_FALSE;
+  }
+
   NS_NAMED_LITERAL_STRING(insertString2, "Composition2");
-  hr = mImpl->mStore->SetText(0, range->mStart + range->mLength,
-                              range->mStart + range->mLength,
-                              insertString2.get(), insertString2.Length(),
-                              &textChange);
+  hr = mMgr->GetFocusedStore()->SetText(0, range->mStart + range->mLength,
+                                        range->mStart + range->mLength,
+                                        insertString2.get(),
+                                        insertString2.Length(),
+                                        &textChange);
   if (!(SUCCEEDED(hr) &&
         sel.acpEnd == textChange.acpStart &&
         sel.acpEnd == textChange.acpOldEnd &&
         sel.acpEnd + insertString2.Length() == textChange.acpNewEnd)) {
     fail("TestComposition: SetText 1");
     return PR_FALSE;
   }
   sel.acpEnd = textChange.acpNewEnd;
   range->mLength += textChange.acpNewEnd - textChange.acpOldEnd;
 
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestComposition: GetFocusedStore returns null #4");
+    return PR_FALSE;
+  }
+
   const LONG COMPOSITION3_TEXT_START_OFFSET = -8; // offset 8 from the end
   const LONG COMPOSITION3_TEXT_END_OFFSET   = 4;
 
   const LONG COMPOSITION3_TEXT_START = range->mStart + range->mLength +
                                        COMPOSITION3_TEXT_START_OFFSET;
   const LONG COMPOSITION3_TEXT_END   = COMPOSITION3_TEXT_START +
                                        COMPOSITION3_TEXT_END_OFFSET;
 
   NS_NAMED_LITERAL_STRING(insertString3, "Compo3");
-  hr = mImpl->mStore->SetText(0, COMPOSITION3_TEXT_START,
-                              COMPOSITION3_TEXT_END,
-                              insertString3.get(), insertString3.Length(),
-                              &textChange);
+  hr = mMgr->GetFocusedStore()->SetText(0, COMPOSITION3_TEXT_START,
+                                        COMPOSITION3_TEXT_END,
+                                        insertString3.get(),
+                                        insertString3.Length(),
+                                        &textChange);
   if (!(SUCCEEDED(hr) &&
         sel.acpEnd + COMPOSITION3_TEXT_START_OFFSET == textChange.acpStart &&
         sel.acpEnd + COMPOSITION3_TEXT_START_OFFSET +
             COMPOSITION3_TEXT_END_OFFSET == textChange.acpOldEnd &&
         sel.acpEnd + insertString3.Length() + COMPOSITION3_TEXT_START_OFFSET ==
             textChange.acpNewEnd)) {
     fail("TestComposition: SetText 2");
     return PR_FALSE;
@@ -2190,58 +2498,75 @@ TestApp::TestComposition(void)
       COMPOSITION3_TEXT_END_OFFSET);
 
   if (!TestCompositionSelectionAndText("composition",
            sel.acpEnd, sel.acpEnd,
            referenceString))
     return PR_FALSE;
 
 
+  if (!mMgr->GetFocusedStore()) {
+    fail("TestComposition: GetFocusedStore returns null #5");
+    return PR_FALSE;
+  }
+
   const LONG POSTCOMPOSITION_SEL_START = sel.acpEnd - 8;
   const LONG POSTCOMPOSITION_SEL_END   = POSTCOMPOSITION_SEL_START + 2;
 
   sel.acpStart = POSTCOMPOSITION_SEL_START;
   sel.acpEnd = POSTCOMPOSITION_SEL_END;
-  hr = mImpl->mStore->SetSelection(1, &sel);
+  hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
   if (!(SUCCEEDED(hr))) {
     fail("TestComposition: SetSelection (composition)");
     return PR_FALSE;
   }
 
-  mImpl->mAttrProp->mRanges.Clear();
-
-  hr = sink->OnEndComposition(mImpl);
+  if (!mMgr->GetFocusedAttrProp()) {
+    fail("TestComposition: GetFocusedAttrProp returns null #3");
+    return PR_FALSE;
+  }
+  mMgr->GetFocusedAttrProp()->mRanges.Clear();
+
+  hr = sink->OnEndComposition(mMgr->GetFocusedContext());
   if (!(SUCCEEDED(hr))) {
     fail("TestComposition: OnEndComposition");
     return PR_FALSE;
   }
 
   if (!TestCompositionSelectionAndText("post-composition",
            sel.acpStart, sel.acpEnd,
            referenceString))
     return PR_FALSE;
 
   const LONG EMPTYCOMPOSITION_START  = range->mStart + 2;
   const LONG EMPTYCOMPOSITION_LENGTH = range->mLength - 4;
 
   range->mStart = EMPTYCOMPOSITION_START;
   range->mLength = EMPTYCOMPOSITION_LENGTH;
-  mImpl->mAttrProp->mRanges.AppendElement(range);
+  if (!mMgr->GetFocusedAttrProp()) {
+    fail("TestComposition: GetFocusedAttrProp returns null #4");
+    return PR_FALSE;
+  }
+  mMgr->GetFocusedAttrProp()->mRanges.AppendElement(range);
 
   okay = FALSE;
-  hr = sink->OnStartComposition(mImpl, &okay);
+  hr = sink->OnStartComposition(mMgr->GetFocusedContext(), &okay);
   if (!(SUCCEEDED(hr) &&
         okay)) {
     fail("TestComposition: OnStartComposition (empty composition)");
     return PR_FALSE;
   }
 
-  mImpl->mAttrProp->mRanges.Clear();
-
-  hr = sink->OnEndComposition(mImpl);
+  if (!mMgr->GetFocusedAttrProp()) {
+    fail("TestComposition: GetFocusedAttrProp returns null #5");
+    return PR_FALSE;
+  }
+  mMgr->GetFocusedAttrProp()->mRanges.Clear();
+
+  hr = sink->OnEndComposition(mMgr->GetFocusedContext());
   if (!(SUCCEEDED(hr))) {
     fail("TestComposition: OnEndComposition (empty composition)");
     return PR_FALSE;
   }
 
   if (!TestCompositionSelectionAndText("empty composition",
            range->mStart, range->mStart + range->mLength,
            referenceString))
@@ -2257,27 +2582,31 @@ TestApp::TestNotificationTextChange(nsIW
                                     LONG aStart,
                                     LONG aOldEnd,
                                     LONG aNewEnd)
 {
   MSG msg;
   if (::PeekMessageW(&msg, NULL, WM_USER_TSF_TEXTCHANGE,
                      WM_USER_TSF_TEXTCHANGE, PM_REMOVE))
     ::DispatchMessageW(&msg);
-  mImpl->mTextChanged = PR_FALSE;
+  if (!mMgr->GetFocusedContext()) {
+    fail("TestNotificationTextChange: GetFocusedContext returns null");
+    return PR_FALSE;
+  }
+  mMgr->GetFocusedContext()->mTextChanged = PR_FALSE;
   nsresult nsr = aWidget->SynthesizeNativeKeyEvent(0, aCode, 0,
                               aCharacter, aCharacter);
   if (::PeekMessageW(&msg, NULL, WM_USER_TSF_TEXTCHANGE,
                      WM_USER_TSF_TEXTCHANGE, PM_REMOVE))
     ::DispatchMessageW(&msg);
   return NS_SUCCEEDED(nsr) &&
-         mImpl->mTextChanged &&
-         aStart == mImpl->mTextChangeData.acpStart &&
-         aOldEnd == mImpl->mTextChangeData.acpOldEnd &&
-         aNewEnd == mImpl->mTextChangeData.acpNewEnd;
+         mMgr->GetFocusedContext()->mTextChanged &&
+         aStart == mMgr->GetFocusedContext()->mTextChangeData.acpStart &&
+         aOldEnd == mMgr->GetFocusedContext()->mTextChangeData.acpOldEnd &&
+         aNewEnd == mMgr->GetFocusedContext()->mTextChangeData.acpNewEnd;
 }
 
 PRBool
 TestApp::TestNotification(void)
 {
   nsresult nsr;
   // get selection to test notification support
   nsCOMPtr<nsISelectionController> selCon;
@@ -2287,28 +2616,38 @@ TestApp::TestNotification(void)
   }
 
   nsr = selCon->CompleteMove(PR_FALSE, PR_FALSE);
   if (!(NS_SUCCEEDED(nsr))) {
     fail("TestNotification: CompleteMove");
     return PR_FALSE;
   }
 
-  mImpl->mSelChanged = PR_FALSE;
+  if (!mMgr->GetFocusedContext()) {
+    fail("TestNotification: GetFocusedContext returns null #1");
+    return PR_FALSE;
+  }
+
+  mMgr->GetFocusedContext()->mSelChanged = PR_FALSE;
   nsr = selCon->CharacterMove(PR_TRUE, PR_FALSE);
   if (!(NS_SUCCEEDED(nsr) &&
-        mImpl->mSelChanged)) {
+        mMgr->GetFocusedContext()->mSelChanged)) {
     fail("TestNotification: CharacterMove");
     return PR_FALSE;
   }
 
-  mImpl->mSelChanged = PR_FALSE;
+  if (!mMgr->GetFocusedContext()) {
+    fail("TestNotification: GetFocusedContext returns null #2");
+    return PR_FALSE;
+  }
+
+  mMgr->GetFocusedContext()->mSelChanged = PR_FALSE;
   nsr = selCon->CharacterMove(PR_TRUE, PR_TRUE);
   if (!(NS_SUCCEEDED(nsr) &&
-        mImpl->mSelChanged)) {
+        mMgr->GetFocusedContext()->mSelChanged)) {
     fail("TestNotification: CharacterMove (extend)");
     return PR_FALSE;
   }
 
   nsCOMPtr<nsIWidget> widget;
   nsCOMPtr<nsIDocShell> docShell;
   nsr = mWindow->GetDocShell(getter_AddRefs(docShell));
   if (NS_SUCCEEDED(nsr) && docShell) {