"Fossies" - the Fresh Open Source Software Archive

Member "firefox-67.0.4/widget/windows/IMMHandler.h" (20 Jun 2019, 17774 Bytes) of package /linux/www/firefox-67.0.4.source.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
    2 /* This Source Code Form is subject to the terms of the Mozilla Public
    3  * License, v. 2.0. If a copy of the MPL was not distributed with this
    4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    5 
    6 #ifndef IMMHandler_h_
    7 #define IMMHandler_h_
    8 
    9 #include "nscore.h"
   10 #include <windows.h>
   11 #include "nsCOMPtr.h"
   12 #include "nsString.h"
   13 #include "nsTArray.h"
   14 #include "nsIWidget.h"
   15 #include "mozilla/EventForwards.h"
   16 #include "mozilla/TextEventDispatcher.h"
   17 #include "nsRect.h"
   18 #include "WritingModes.h"
   19 #include "npapi.h"
   20 
   21 class nsWindow;
   22 class nsWindowBase;
   23 
   24 namespace mozilla {
   25 namespace widget {
   26 
   27 struct MSGResult;
   28 
   29 class IMEContext final {
   30  public:
   31   IMEContext() : mWnd(nullptr), mIMC(nullptr) {}
   32 
   33   explicit IMEContext(HWND aWnd);
   34   explicit IMEContext(nsWindowBase* aWindowBase);
   35 
   36   ~IMEContext() { Clear(); }
   37 
   38   HIMC get() const { return mIMC; }
   39 
   40   void Init(HWND aWnd);
   41   void Init(nsWindowBase* aWindowBase);
   42   void Clear();
   43 
   44   bool IsValid() const { return !!mIMC; }
   45 
   46   void SetOpenState(bool aOpen) const {
   47     if (!mIMC) {
   48       return;
   49     }
   50     ::ImmSetOpenStatus(mIMC, aOpen);
   51   }
   52 
   53   bool GetOpenState() const {
   54     if (!mIMC) {
   55       return false;
   56     }
   57     return (::ImmGetOpenStatus(mIMC) != FALSE);
   58   }
   59 
   60   bool AssociateDefaultContext() {
   61     // We assume that there is only default IMC, no new IMC has been created.
   62     if (mIMC) {
   63       return false;
   64     }
   65     if (!::ImmAssociateContextEx(mWnd, nullptr, IACE_DEFAULT)) {
   66       return false;
   67     }
   68     mIMC = ::ImmGetContext(mWnd);
   69     return (mIMC != nullptr);
   70   }
   71 
   72   bool Disassociate() {
   73     if (!mIMC) {
   74       return false;
   75     }
   76     if (!::ImmAssociateContextEx(mWnd, nullptr, 0)) {
   77       return false;
   78     }
   79     ::ImmReleaseContext(mWnd, mIMC);
   80     mIMC = nullptr;
   81     return true;
   82   }
   83 
   84  protected:
   85   IMEContext(const IMEContext& aOther) { MOZ_CRASH("Don't copy IMEContext"); }
   86 
   87   HWND mWnd;
   88   HIMC mIMC;
   89 };
   90 
   91 class IMMHandler final {
   92  public:
   93   static void Initialize();
   94   static void Terminate();
   95 
   96   // If Process*() returns true, the caller shouldn't do anything anymore.
   97   static bool ProcessMessage(nsWindow* aWindow, UINT msg, WPARAM& wParam,
   98                              LPARAM& lParam, MSGResult& aResult);
   99   static bool IsComposing() { return IsComposingOnOurEditor(); }
  100   static bool IsComposingOn(nsWindow* aWindow) {
  101     return IsComposing() && IsComposingWindow(aWindow);
  102   }
  103 
  104 #ifdef DEBUG
  105   /**
  106    * IsIMEAvailable() returns TRUE when current keyboard layout has IME.
  107    * Otherwise, FALSE.
  108    */
  109   static bool IsIMEAvailable() { return !!::ImmIsIME(::GetKeyboardLayout(0)); }
  110 #endif
  111 
  112   // If aForce is TRUE, these methods doesn't check whether we have composition
  113   // or not.  If you don't set it to TRUE, these method doesn't commit/cancel
  114   // the composition on uexpected window.
  115   static void CommitComposition(nsWindow* aWindow, bool aForce = false);
  116   static void CancelComposition(nsWindow* aWindow, bool aForce = false);
  117   static void OnFocusChange(bool aFocus, nsWindow* aWindow);
  118   static void OnUpdateComposition(nsWindow* aWindow);
  119   static void OnSelectionChange(nsWindow* aWindow,
  120                                 const IMENotification& aIMENotification,
  121                                 bool aIsIMMActive);
  122 
  123   static IMENotificationRequests GetIMENotificationRequests();
  124 
  125   // Returns NS_SUCCESS_EVENT_CONSUMED if the mouse button event is consumed by
  126   // IME.  Otherwise, NS_OK.
  127   static nsresult OnMouseButtonEvent(nsWindow* aWindow,
  128                                      const IMENotification& aIMENotification);
  129   static void SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm);
  130   static void DefaultProcOfPluginEvent(nsWindow* aWindow,
  131                                        const NPEvent* aEvent);
  132 
  133 #define DECL_IS_IME_ACTIVE(aReadableName) \
  134   static bool Is##aReadableName##Active();
  135 
  136   // Japanese IMEs
  137   DECL_IS_IME_ACTIVE(ATOK2006)
  138   DECL_IS_IME_ACTIVE(ATOK2007)
  139   DECL_IS_IME_ACTIVE(ATOK2008)
  140   DECL_IS_IME_ACTIVE(ATOK2009)
  141   DECL_IS_IME_ACTIVE(ATOK2010)
  142   DECL_IS_IME_ACTIVE(GoogleJapaneseInput)
  143   DECL_IS_IME_ACTIVE(Japanist2003)
  144 
  145 #undef DECL_IS_IME_ACTIVE
  146 
  147   /**
  148    * IsActiveIMEInBlockList() returns true if we know active keyboard layout's
  149    * IME has some crash bugs or something which make some damage to us.  When
  150    * this returns true, IMC shouldn't be associated with any windows.
  151    */
  152   static bool IsActiveIMEInBlockList();
  153 
  154  protected:
  155   static void EnsureHandlerInstance();
  156 
  157   static bool IsComposingOnOurEditor();
  158   static bool IsComposingOnPlugin();
  159   static bool IsComposingWindow(nsWindow* aWindow);
  160 
  161   static bool ShouldDrawCompositionStringOurselves();
  162   static bool IsVerticalWritingSupported();
  163   // aWindow can be nullptr if it's called without receiving WM_INPUTLANGCHANGE.
  164   static void InitKeyboardLayout(nsWindow* aWindow, HKL aKeyboardLayout);
  165   static UINT GetKeyboardCodePage();
  166 
  167   /**
  168    * Checks whether the window is top level window of the composing window.
  169    * In this method, the top level window means in all windows, not only in all
  170    * OUR windows.  I.e., if the aWindow is embedded, this always returns FALSE.
  171    */
  172   static bool IsTopLevelWindowOfComposition(nsWindow* aWindow);
  173 
  174   static bool ProcessInputLangChangeMessage(nsWindow* aWindow, WPARAM wParam,
  175                                             LPARAM lParam, MSGResult& aResult);
  176   static bool ProcessMessageForPlugin(nsWindow* aWindow, UINT msg,
  177                                       WPARAM& wParam, LPARAM& lParam,
  178                                       bool& aRet, MSGResult& aResult);
  179 
  180   IMMHandler();
  181   ~IMMHandler();
  182 
  183   // On*() methods return true if the caller of message handler shouldn't do
  184   // anything anymore.  Otherwise, false.
  185   static bool OnKeyDownEvent(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
  186                              MSGResult& aResult);
  187 
  188   bool OnIMEStartComposition(nsWindow* aWindow, MSGResult& aResult);
  189   void OnIMEStartCompositionOnPlugin(nsWindow* aWindow, WPARAM wParam,
  190                                      LPARAM lParam);
  191   bool OnIMEComposition(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
  192                         MSGResult& aResult);
  193   void OnIMECompositionOnPlugin(nsWindow* aWindow, WPARAM wParam,
  194                                 LPARAM lParam);
  195   bool OnIMEEndComposition(nsWindow* aWindow, MSGResult& aResult);
  196   void OnIMEEndCompositionOnPlugin(nsWindow* aWindow, WPARAM wParam,
  197                                    LPARAM lParam);
  198   bool OnIMERequest(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
  199                     MSGResult& aResult);
  200   bool OnIMECharOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
  201                          MSGResult& aResult);
  202   bool OnChar(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
  203               MSGResult& aResult);
  204   bool OnCharOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
  205                       MSGResult& aResult);
  206   void OnInputLangChange(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
  207                          MSGResult& aResult);
  208 
  209   // These message handlers don't use instance members, we should not create
  210   // the instance by the messages.  So, they should be static.
  211   static bool OnIMEChar(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
  212                         MSGResult& aResult);
  213   static bool OnIMESetContext(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
  214                               MSGResult& aResult);
  215   static bool OnIMESetContextOnPlugin(nsWindow* aWindow, WPARAM wParam,
  216                                       LPARAM lParam, MSGResult& aResult);
  217   static bool OnIMECompositionFull(nsWindow* aWindow, MSGResult& aResult);
  218   static bool OnIMENotify(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
  219                           MSGResult& aResult);
  220   static bool OnIMESelect(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
  221                           MSGResult& aResult);
  222 
  223   // The result of Handle* method mean "Processed" when it's TRUE.
  224   void HandleStartComposition(nsWindow* aWindow, const IMEContext& aContext);
  225   bool HandleComposition(nsWindow* aWindow, const IMEContext& aContext,
  226                          LPARAM lParam);
  227   // If aCommitString is null, this commits composition with the latest
  228   // dispatched data.  Otherwise, commits composition with the value.
  229   void HandleEndComposition(nsWindow* aWindow,
  230                             const nsAString* aCommitString = nullptr);
  231   bool HandleReconvert(nsWindow* aWindow, LPARAM lParam, LRESULT* oResult);
  232   bool HandleQueryCharPosition(nsWindow* aWindow, LPARAM lParam,
  233                                LRESULT* oResult);
  234   bool HandleDocumentFeed(nsWindow* aWindow, LPARAM lParam, LRESULT* oResult);
  235 
  236   /**
  237    *  When a window's IME context is activating but we have composition on
  238    *  another window, we should commit our composition because IME context is
  239    *  shared by all our windows (including plug-ins).
  240    *  @param aWindow is a new activated window.
  241    *  If aWindow is our composing window, this method does nothing.
  242    *  Otherwise, this commits the composition on the previous window.
  243    *  If this method did commit a composition, this returns TRUE.
  244    */
  245   bool CommitCompositionOnPreviousWindow(nsWindow* aWindow);
  246 
  247   /**
  248    *  ResolveIMECaretPos
  249    *  Convert the caret rect of a composition event to another widget's
  250    *  coordinate system.
  251    *
  252    *  @param aReferenceWidget The origin widget of aCursorRect.
  253    *                          Typically, this is mReferenceWidget of the
  254    *                          composing events. If the aCursorRect is in screen
  255    *                          coordinates, set nullptr.
  256    *  @param aCursorRect      The cursor rect.
  257    *  @param aNewOriginWidget aOutRect will be in this widget's coordinates. If
  258    *                          this is nullptr, aOutRect will be in screen
  259    *                          coordinates.
  260    *  @param aOutRect         The converted cursor rect.
  261    */
  262   void ResolveIMECaretPos(nsIWidget* aReferenceWidget,
  263                           mozilla::LayoutDeviceIntRect& aCursorRect,
  264                           nsIWidget* aNewOriginWidget,
  265                           mozilla::LayoutDeviceIntRect& aOutRect);
  266 
  267   bool ConvertToANSIString(const nsString& aStr, UINT aCodePage,
  268                            nsACString& aANSIStr);
  269 
  270   bool SetIMERelatedWindowsPos(nsWindow* aWindow, const IMEContext& aContext);
  271   void SetIMERelatedWindowsPosOnPlugin(nsWindow* aWindow,
  272                                        const IMEContext& aContext);
  273   /**
  274    * GetCharacterRectOfSelectedTextAt() returns character rect of the offset
  275    * from the selection start or the start of composition string if there is
  276    * a composition.
  277    *
  278    * @param aWindow         The window which has focus.
  279    * @param aOffset         Offset from the selection start or the start of
  280    *                        composition string when there is a composition.
  281    *                        This must be in the selection range or
  282    *                        the composition string.
  283    * @param aCharRect       The result.
  284    * @param aWritingMode    The writing mode of current selection.  When this
  285    *                        is nullptr, this assumes that the selection is in
  286    *                        horizontal writing mode.
  287    * @return                true if this succeeded to retrieve the rect.
  288    *                        Otherwise, false.
  289    */
  290   bool GetCharacterRectOfSelectedTextAt(
  291       nsWindow* aWindow, uint32_t aOffset,
  292       mozilla::LayoutDeviceIntRect& aCharRect,
  293       mozilla::WritingMode* aWritingMode = nullptr);
  294   /**
  295    * GetCaretRect() returns caret rect at current selection start.
  296    *
  297    * @param aWindow         The window which has focus.
  298    * @param aCaretRect      The result.
  299    * @param aWritingMode    The writing mode of current selection.  When this
  300    *                        is nullptr, this assumes that the selection is in
  301    *                        horizontal writing mode.
  302    * @return                true if this succeeded to retrieve the rect.
  303    *                        Otherwise, false.
  304    */
  305   bool GetCaretRect(nsWindow* aWindow, mozilla::LayoutDeviceIntRect& aCaretRect,
  306                     mozilla::WritingMode* aWritingMode = nullptr);
  307   void GetCompositionString(const IMEContext& aContext, DWORD aIndex,
  308                             nsAString& aCompositionString) const;
  309 
  310   /**
  311    * AdjustCompositionFont() makes IME vertical writing mode if it's supported.
  312    * If aForceUpdate is true, it will update composition font even if writing
  313    * mode isn't being changed.
  314    */
  315   void AdjustCompositionFont(nsWindow* aWindow, const IMEContext& aContext,
  316                              const mozilla::WritingMode& aWritingMode,
  317                              bool aForceUpdate = false);
  318 
  319   /**
  320    * MaybeAdjustCompositionFont() calls AdjustCompositionFont() when the
  321    * locale of active IME is CJK.  Note that this creates an instance even
  322    * when there is no composition but the locale is CJK.
  323    */
  324   static void MaybeAdjustCompositionFont(
  325       nsWindow* aWindow, const mozilla::WritingMode& aWritingMode,
  326       bool aForceUpdate = false);
  327 
  328   /**
  329    *  Get the current target clause of composition string.
  330    *  If there are one or more characters whose attribute is ATTR_TARGET_*,
  331    *  this returns the first character's offset and its length.
  332    *  Otherwise, e.g., the all characters are ATTR_INPUT, this returns
  333    *  the composition string range because the all is the current target.
  334    *
  335    *  aLength can be null (default), but aOffset must not be null.
  336    *
  337    *  The aOffset value is offset in the contents.  So, when you need offset
  338    *  in the composition string, you need to subtract mCompositionStart from it.
  339    */
  340   bool GetTargetClauseRange(uint32_t* aOffset, uint32_t* aLength = nullptr);
  341 
  342   /**
  343    * DispatchEvent() dispatches aEvent if aWidget hasn't been destroyed yet.
  344    */
  345   static void DispatchEvent(nsWindow* aWindow, WidgetGUIEvent& aEvent);
  346 
  347   /**
  348    * DispatchCompositionChangeEvent() dispatches eCompositionChange event
  349    * with clause information (it'll be retrieved by CreateTextRangeArray()).
  350    * I.e., this should be called only during composing.  If a composition is
  351    * being committed, only HandleCompositionEnd() should be called.
  352    *
  353    * @param aWindow     The window which has the composition.
  354    * @param aContext    Native IME context which has the composition.
  355    */
  356   void DispatchCompositionChangeEvent(nsWindow* aWindow,
  357                                       const IMEContext& aContext);
  358 
  359   nsresult EnsureClauseArray(int32_t aCount);
  360   nsresult EnsureAttributeArray(int32_t aCount);
  361 
  362   /**
  363    * When WM_IME_CHAR is received and passed to DefWindowProc, we need to
  364    * record the messages.  In other words, we should record the messages
  365    * when we receive WM_IME_CHAR on windowless plug-in (if we have focus,
  366    * we always eat them).  When focus is moved from a windowless plug-in to
  367    * our window during composition, WM_IME_CHAR messages were received when
  368    * the plug-in has focus.  However, WM_CHAR messages are received after the
  369    * plug-in lost focus.  So, we need to ignore the WM_CHAR messages because
  370    * they make unexpected text input events on us.
  371    */
  372   nsTArray<MSG> mPassedIMEChar;
  373 
  374   bool IsIMECharRecordsEmpty() { return mPassedIMEChar.IsEmpty(); }
  375   void ResetIMECharRecords() { mPassedIMEChar.Clear(); }
  376   void DequeueIMECharRecords(WPARAM& wParam, LPARAM& lParam) {
  377     MSG msg = mPassedIMEChar.ElementAt(0);
  378     wParam = msg.wParam;
  379     lParam = msg.lParam;
  380     mPassedIMEChar.RemoveElementAt(0);
  381   }
  382   void EnqueueIMECharRecords(WPARAM wParam, LPARAM lParam) {
  383     MSG msg;
  384     msg.wParam = wParam;
  385     msg.lParam = lParam;
  386     mPassedIMEChar.AppendElement(msg);
  387   }
  388 
  389   TextEventDispatcher* GetTextEventDispatcherFor(nsWindow* aWindow);
  390 
  391   nsWindow* mComposingWindow;
  392   RefPtr<TextEventDispatcher> mDispatcher;
  393   nsString mCompositionString;
  394   InfallibleTArray<uint32_t> mClauseArray;
  395   InfallibleTArray<uint8_t> mAttributeArray;
  396 
  397   int32_t mCursorPosition;
  398   uint32_t mCompositionStart;
  399 
  400   struct Selection {
  401     nsString mString;
  402     uint32_t mOffset;
  403     mozilla::WritingMode mWritingMode;
  404     bool mIsValid;
  405 
  406     Selection() : mOffset(UINT32_MAX), mIsValid(false) {}
  407 
  408     void Clear() {
  409       mOffset = UINT32_MAX;
  410       mIsValid = false;
  411     }
  412     uint32_t Length() const { return mString.Length(); }
  413     bool Collapsed() const { return !Length(); }
  414 
  415     bool IsValid() const;
  416     bool Update(const IMENotification& aIMENotification);
  417     bool Init(nsWindow* aWindow);
  418     bool EnsureValidSelection(nsWindow* aWindow);
  419 
  420    private:
  421     Selection(const Selection& aOther) = delete;
  422     void operator=(const Selection& aOther) = delete;
  423   };
  424   // mSelection stores the latest selection data only when sHasFocus is true.
  425   // Don't access mSelection directly.  You should use GetSelection() for
  426   // getting proper state.
  427   Selection mSelection;
  428 
  429   Selection& GetSelection() {
  430     // When IME has focus, mSelection is automatically updated by
  431     // NOTIFY_IME_OF_SELECTION_CHANGE.
  432     if (sHasFocus) {
  433       return mSelection;
  434     }
  435     // Otherwise, i.e., While IME doesn't have focus, we cannot observe
  436     // selection changes.  So, in such case, we need to query selection
  437     // when it's necessary.
  438     static Selection sTempSelection;
  439     sTempSelection.Clear();
  440     return sTempSelection;
  441   }
  442 
  443   bool mIsComposing;
  444   bool mIsComposingOnPlugin;
  445 
  446   static mozilla::WritingMode sWritingModeOfCompositionFont;
  447   static nsString sIMEName;
  448   static UINT sCodePage;
  449   static DWORD sIMEProperty;
  450   static DWORD sIMEUIProperty;
  451   static bool sAssumeVerticalWritingModeNotSupported;
  452   static bool sHasFocus;
  453 };
  454 
  455 }  // namespace widget
  456 }  // namespace mozilla
  457 
  458 #endif  // IMMHandler_h_