Bug 968647 - Part 3. TSF should use postion change notification instead of nsITimer. r=masayuki
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Fri, 28 Feb 2014 16:45:16 +0900
changeset 171764 2275e85c9ad070c25bba736fa4ea3ed3afb2bf5e
parent 171763 d3ce99c9b61ee2c18c5a44e80726ac3057918fcc
child 171765 c66cd5bf1aadd254aefa2078ef3d3f319e006a53
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersmasayuki
bugs968647
milestone30.0a1
Bug 968647 - Part 3. TSF should use postion change notification instead of nsITimer. r=masayuki
modules/libpref/src/init/all.js
widget/windows/WinIMEHandler.cpp
widget/windows/nsTextStore.cpp
widget/windows/nsTextStore.h
widget/windows/winrt/MetroWidget.cpp
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -2580,20 +2580,16 @@ pref("intl.keyboard.per_window_layout", 
 
 #ifdef NS_ENABLE_TSF
 // Enable/Disable TSF support
 pref("intl.tsf.enable", false);
 
 // Support IMEs implemented with IMM in TSF mode.
 pref("intl.tsf.support_imm", true);
 
-// We need to notify the layout change to TSF, but we cannot check the actual
-// change now, therefore, we always notify it by this fequency.
-pref("intl.tsf.on_layout_change_interval", 100);
-
 // Enables/Disables hack for specific TIP.
 
 // Whether creates native caret for ATOK or not.
 pref("intl.tsf.hack.atok.create_native_caret", true);
 #endif
 
 // See bug 448927, on topmost panel, some IMEs are not usable on Windows.
 pref("ui.panel.default_level_parent", false);
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -178,16 +178,18 @@ IMEHandler::NotifyIME(nsWindow* aWindow,
           nsTextStore::CommitComposition(false);
         }
         return NS_OK;
       case REQUEST_TO_CANCEL_COMPOSITION:
         if (nsTextStore::IsComposingOn(aWindow)) {
           nsTextStore::CommitComposition(true);
         }
         return NS_OK;
+      case NOTIFY_IME_OF_POSITION_CHANGE:
+        return nsTextStore::OnLayoutChange();
       default:
         return NS_ERROR_NOT_IMPLEMENTED;
     }
   }
 #endif //NS_ENABLE_TSF
 
   switch (aIMENotification.mMessage) {
     case REQUEST_TO_COMMIT_COMPOSITION:
--- a/widget/windows/nsTextStore.cpp
+++ b/widget/windows/nsTextStore.cpp
@@ -24,18 +24,16 @@
 
 #define INPUTSCOPE_INIT_GUID
 #include "nsTextStore.h"
 
 using namespace mozilla;
 using namespace mozilla::widget;
 
 static const char* kPrefNameTSFEnabled = "intl.tsf.enable";
-static const char* kPrefNameLayoutChangeInternal =
-                     "intl.tsf.on_layout_change_interval";
 
 static const char* kLegacyPrefNameTSFEnabled = "intl.enable_tsf_support";
 
 #ifdef PR_LOGGING
 /**
  * TSF related code should log its behavior even on release build especially
  * in the interface methods.
  *
@@ -631,18 +629,16 @@ nsTextStore::~nsTextStore()
       if (FAILED(hr)) {
         PR_LOG(sTextStoreLog, PR_LOG_ERROR,
           ("TSF: 0x%p   ~nsTextStore FAILED to uninstall "
            "ITfActiveLanguageProfileNotifySink (0x%08X)",
            this, hr));
       }
     }
   }
-
-  mComposition.EnsureLayoutChangeTimerStopped();
 }
 
 bool
 nsTextStore::Create(nsWindowBase* aWidget)
 {
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
     ("TSF: 0x%p nsTextStore::Create(aWidget=0x%p)",
      this, aWidget));
@@ -1042,17 +1038,16 @@ nsTextStore::FlushPendingActions()
                 "dispatching compositionstart event...", this));
         WidgetCompositionEvent compositionStart(true, NS_COMPOSITION_START,
                                                 mWidget);
         mWidget->InitEvent(compositionStart);
         mWidget->DispatchWindowEvent(&compositionStart);
         if (!mWidget || mWidget->Destroyed()) {
           break;
         }
-        mComposition.StartLayoutChangeTimer(this);
         break;
       }
       case PendingAction::COMPOSITION_UPDATE: {
         PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
                ("TSF: 0x%p   nsTextStore::FlushPendingActions() "
                 "flushing COMPOSITION_UPDATE={ mData=\"%s\", "
                 "mRanges.Length()=%d }",
                 this, NS_ConvertUTF16toUTF8(action.mData).get(),
@@ -1132,18 +1127,16 @@ nsTextStore::FlushPendingActions()
         break;
       }
       case PendingAction::COMPOSITION_END: {
         PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
                ("TSF: 0x%p   nsTextStore::FlushPendingActions() "
                 "flushing COMPOSITION_END={ mData=\"%s\" }",
                 this, NS_ConvertUTF16toUTF8(action.mData).get()));
 
-        mComposition.EnsureLayoutChangeTimerStopped();
-
         action.mData.ReplaceSubstring(NS_LITERAL_STRING("\r\n"),
                                       NS_LITERAL_STRING("\n"));
         if (action.mData != mComposition.mLastData) {
           PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
                  ("TSF: 0x%p   nsTextStore::FlushPendingActions(), "
                   "dispatching compositionupdate event...", this));
           WidgetCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE,
                                                    mWidget);
@@ -1202,18 +1195,16 @@ nsTextStore::FlushPendingActions()
       default:
         MOZ_CRASH("unexpected action type");
     }
 
     if (mWidget && !mWidget->Destroyed()) {
       continue;
     }
 
-    mComposition.EnsureLayoutChangeTimerStopped();
-
     PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
            ("TSF: 0x%p   nsTextStore::FlushPendingActions(), "
             "qutting since the mWidget has gone", this));
     break;
   }
   mPendingActions.Clear();
 }
 
@@ -3173,16 +3164,17 @@ nsTextStore::GetIMEUpdatePreference()
 {
   if (sTsfThreadMgr && sTsfTextStore && sTsfTextStore->mDocumentMgr) {
     nsRefPtr<ITfDocumentMgr> docMgr;
     sTsfThreadMgr->GetFocus(getter_AddRefs(docMgr));
     if (docMgr == sTsfTextStore->mDocumentMgr) {
       nsIMEUpdatePreference updatePreference(
         nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE |
         nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE |
+        nsIMEUpdatePreference::NOTIFY_POSITION_CHANGE |
         nsIMEUpdatePreference::NOTIFY_DURING_DEACTIVE);
       // nsTextStore shouldn't notify TSF of selection change and text change
       // which are caused by composition.
       updatePreference.DontNotifyChangesCausedByComposition();
       return updatePreference;
     }
   }
   return nsIMEUpdatePreference();
@@ -3294,27 +3286,23 @@ nsTextStore::OnSelectionChangeInternal(v
            ("TSF: 0x%p   nsTextStore::OnSelectionChangeInternal(), pending "
             "a call of mSink->OnSelectionChange()...", this));
     mPendingOnSelectionChange = true;
   }
   return NS_OK;
 }
 
 nsresult
-nsTextStore::OnLayoutChange()
+nsTextStore::OnLayoutChangeInternal()
 {
   NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE);
   NS_ENSURE_TRUE(mSink, NS_ERROR_FAILURE);
 
-  // XXXmnakano We always call OnLayoutChange for now, but this might use CPU
-  // power when the focused editor has very long text. Ideally, we should call
-  // this only when the composition string screen position is changed by window
-  // moving, resizing. And also reflowing and scrolling the contents.
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: 0x%p   nsTextStore::OnLayoutChange(), calling "
+         ("TSF: 0x%p   nsTextStore::OnLayoutChangeInternal(), calling "
           "mSink->OnLayoutChange()...", this));
   HRESULT hr = mSink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW);
   NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
 void
@@ -3987,57 +3975,16 @@ nsTextStore::Composition::Start(ITfCompo
 
 void
 nsTextStore::Composition::End()
 {
   mView = nullptr;
   mString.Truncate();
 }
 
-void
-nsTextStore::Composition::StartLayoutChangeTimer(nsTextStore* aTextStore)
-{
-  MOZ_ASSERT(!mLayoutChangeTimer);
-  mLayoutChangeTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
-  mLayoutChangeTimer->InitWithFuncCallback(TimerCallback, aTextStore,
-    GetLayoutChangeIntervalTime(), nsITimer::TYPE_REPEATING_SLACK);
-}
-
-void
-nsTextStore::Composition::EnsureLayoutChangeTimerStopped()
-{
-  if (!mLayoutChangeTimer) {
-    return;
-  }
-  mLayoutChangeTimer->Cancel();
-  mLayoutChangeTimer = nullptr;
-}
-
-// static
-void
-nsTextStore::Composition::TimerCallback(nsITimer* aTimer, void* aClosure)
-{
-  nsTextStore *ts = static_cast<nsTextStore*>(aClosure);
-  ts->OnLayoutChange();
-}
-
-// static
-uint32_t
-nsTextStore::Composition::GetLayoutChangeIntervalTime()
-{
-  static int32_t sTime = -1;
-  if (sTime > 0) {
-    return static_cast<uint32_t>(sTime);
-  }
-
-  sTime = std::max(10,
-    Preferences::GetInt(kPrefNameLayoutChangeInternal, 100));
-  return static_cast<uint32_t>(sTime);
-}
-
 /******************************************************************************
  *  nsTextStore::Content
  *****************************************************************************/
 
 const nsDependentSubstring
 nsTextStore::Content::GetSelectedText() const
 {
   MOZ_ASSERT(mInitialized);
--- a/widget/windows/nsTextStore.h
+++ b/widget/windows/nsTextStore.h
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NSTEXTSTORE_H_
 #define NSTEXTSTORE_H_
 
 #include "nsAutoPtr.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
-#include "nsITimer.h"
 #include "nsIWidget.h"
 #include "nsWindowBase.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/TextRange.h"
 #include "mozilla/WindowsVersion.h"
 
 #include <msctf.h>
 #include <textstor.h>
@@ -143,16 +142,22 @@ public:
   }
 
   static nsresult OnSelectionChange(void)
   {
     NS_ENSURE_TRUE(sTsfTextStore, NS_ERROR_NOT_AVAILABLE);
     return sTsfTextStore->OnSelectionChangeInternal();
   }
 
+  static nsresult OnLayoutChange()
+  {
+    NS_ENSURE_TRUE(sTsfTextStore, NS_ERROR_NOT_AVAILABLE);
+    return sTsfTextStore->OnLayoutChangeInternal();
+  }
+
   static nsIMEUpdatePreference GetIMEUpdatePreference();
 
   // Returns the address of the pointer so that the TSF automatic test can
   // replace the system object with a custom implementation for testing.
   static void* GetNativeData(uint32_t aDataType)
   {
     switch (aDataType) {
       case NS_NATIVE_TSF_THREAD_MGR:
@@ -271,17 +276,17 @@ protected:
                                         bool aPreserveSelection);
   HRESULT  RecordCompositionUpdateAction();
   HRESULT  RecordCompositionEndAction();
 
   // FlushPendingActions() performs pending actions recorded in mPendingActions
   // and clear it.
   void     FlushPendingActions();
 
-  nsresult OnLayoutChange();
+  nsresult OnLayoutChangeInternal();
   HRESULT  ProcessScopeRequest(DWORD dwFlags,
                                ULONG cFilterAttrs,
                                const TS_ATTRID *paFilterAttrs);
   void     SetInputScope(const nsString& aHTMLInputType);
 
   // Creates native caret over our caret.  This method only works on desktop
   // application.  Otherwise, this does nothing.
   void     CreateNativeCaret();
@@ -345,27 +350,16 @@ protected:
 
     // Start() and End() updates the members for emulating the latest state.
     // Unless flush the pending actions, this data never matches the actual
     // content.
     void Start(ITfCompositionView* aCompositionView,
                LONG aCompositionStartOffset,
                const nsAString& aCompositionString);
     void End();
-
-    void StartLayoutChangeTimer(nsTextStore* aTextStore);
-    void EnsureLayoutChangeTimerStopped();
-
-  private:
-    // Timer for calling ITextStoreACPSink::OnLayoutChange(). This is only used
-    // during composing.
-    nsCOMPtr<nsITimer> mLayoutChangeTimer;
-
-    static void TimerCallback(nsITimer* aTimer, void *aClosure);
-    static uint32_t GetLayoutChangeIntervalTime();
   };
   // While the document is locked, we cannot dispatch any events which cause
   // DOM events since the DOM events' handlers may modify the locked document.
   // However, even while the document is locked, TSF may queries us.
   // For that, nsTextStore modifies mComposition even while the document is
   // locked.  With mComposition, query methods can returns the text content
   // information.
   Composition mComposition;
--- a/widget/windows/winrt/MetroWidget.cpp
+++ b/widget/windows/winrt/MetroWidget.cpp
@@ -1599,16 +1599,18 @@ MetroWidget::NotifyIME(const IMENotifica
                                         mInputContext.mIMEState.mEnabled);
     case NOTIFY_IME_OF_BLUR:
       return nsTextStore::OnFocusChange(false, this,
                                         mInputContext.mIMEState.mEnabled);
     case NOTIFY_IME_OF_SELECTION_CHANGE:
       return nsTextStore::OnSelectionChange();
     case NOTIFY_IME_OF_TEXT_CHANGE:
       return nsTextStore::OnTextChange(aIMENotification);
+    case NOTIFY_IME_OF_POSITION_CHANGE:
+      return nsTextStore::OnLayoutChange();
     default:
       return NS_ERROR_NOT_IMPLEMENTED;
   }
 }
 
 NS_IMETHODIMP
 MetroWidget::GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState)
 {