Backed out changeset 5dc41a3d8d77 (bug 968647)
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Mon, 03 Mar 2014 11:53:27 +0900
changeset 171753 753007aca755d52a3bd968825494197b6d0d077c
parent 171752 5dc41a3d8d7775ecb056f0199dbfebe64bd44bd8
child 171754 4a48bf9197d8132385ad443e9b7e656e463d2e8a
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
bugs968647
milestone30.0a1
backs out5dc41a3d8d7775ecb056f0199dbfebe64bd44bd8
Backed out changeset 5dc41a3d8d77 (bug 968647)
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,16 +2580,20 @@ 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,18 +178,16 @@ 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,16 +24,18 @@
 
 #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.
  *
@@ -629,16 +631,18 @@ 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));
@@ -1038,16 +1042,17 @@ 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(),
@@ -1127,16 +1132,18 @@ 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);
@@ -1195,16 +1202,18 @@ 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();
 }
 
@@ -3164,17 +3173,16 @@ 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();
@@ -3286,23 +3294,27 @@ nsTextStore::OnSelectionChangeInternal(v
            ("TSF: 0x%p   nsTextStore::OnSelectionChangeInternal(), pending "
             "a call of mSink->OnSelectionChange()...", this));
     mPendingOnSelectionChange = true;
   }
   return NS_OK;
 }
 
 nsresult
-nsTextStore::OnLayoutChangeInternal()
+nsTextStore::OnLayoutChange()
 {
   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::OnLayoutChangeInternal(), calling "
+         ("TSF: 0x%p   nsTextStore::OnLayoutChange(), 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
@@ -3975,16 +3987,57 @@ 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,16 +4,17 @@
  * 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>
@@ -142,22 +143,16 @@ 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:
@@ -276,17 +271,17 @@ protected:
                                         bool aPreserveSelection);
   HRESULT  RecordCompositionUpdateAction();
   HRESULT  RecordCompositionEndAction();
 
   // FlushPendingActions() performs pending actions recorded in mPendingActions
   // and clear it.
   void     FlushPendingActions();
 
-  nsresult OnLayoutChangeInternal();
+  nsresult OnLayoutChange();
   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();
@@ -350,16 +345,27 @@ 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,18 +1599,16 @@ 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)
 {