Home | History | Annotate | Download | only in ime
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef WIN8_METRO_DRIVER_IME_TEXT_STORE_H_
      6 #define WIN8_METRO_DRIVER_IME_TEXT_STORE_H_
      7 
      8 #include <atlbase.h>
      9 #include <atlcom.h>
     10 #include <initguid.h>
     11 #include <inputscope.h>
     12 #include <msctf.h>
     13 
     14 #include <deque>
     15 #include <vector>
     16 
     17 #include "base/basictypes.h"
     18 #include "base/compiler_specific.h"
     19 #include "base/memory/ref_counted.h"
     20 #include "base/strings/string16.h"
     21 #include "base/win/scoped_comptr.h"
     22 #include "ui/metro_viewer/ime_types.h"
     23 
     24 namespace metro_driver {
     25 
     26 class TextStoreDelegate;
     27 
     28 // TextStore is used to interact with the input method via TSF manager.
     29 // TextStore have a string buffer which is manipulated by TSF manager through
     30 // ITextStoreACP interface methods such as SetText().
     31 // When the input method updates the composition, TextStore calls
     32 // TextInputClient::SetCompositionText(). And when the input method finishes the
     33 // composition, TextStore calls TextInputClient::InsertText() and clears the
     34 // buffer.
     35 //
     36 // How TextStore works:
     37 //  - The user enters "a".
     38 //    - The input method set composition as "a".
     39 //    - TSF manager calls TextStore::RequestLock().
     40 //    - TextStore callbacks ITextStoreACPSink::OnLockGranted().
     41 //    - In OnLockGranted(), TSF manager calls
     42 //      - TextStore::OnStartComposition()
     43 //      - TextStore::SetText()
     44 //        The string buffer is set as "a".
     45 //      - TextStore::OnUpdateComposition()
     46 //      - TextStore::OnEndEdit()
     47 //        TextStore can get the composition information such as underlines.
     48 //   - TextStore calls TextInputClient::SetCompositionText().
     49 //     "a" is shown with an underline as composition string.
     50 // - The user enters <space>.
     51 //    - The input method set composition as "A".
     52 //    - TSF manager calls TextStore::RequestLock().
     53 //    - TextStore callbacks ITextStoreACPSink::OnLockGranted().
     54 //    - In OnLockGranted(), TSF manager calls
     55 //      - TextStore::SetText()
     56 //        The string buffer is set as "A".
     57 //      - TextStore::OnUpdateComposition()
     58 //      - TextStore::OnEndEdit()
     59 //   - TextStore calls TextInputClient::SetCompositionText().
     60 //     "A" is shown with an underline as composition string.
     61 // - The user enters <enter>.
     62 //    - The input method commits "A".
     63 //    - TSF manager calls TextStore::RequestLock().
     64 //    - TextStore callbacks ITextStoreACPSink::OnLockGranted().
     65 //    - In OnLockGranted(), TSF manager calls
     66 //      - TextStore::OnEndComposition()
     67 //      - TextStore::OnEndEdit()
     68 //        TextStore knows "A" is committed.
     69 //   - TextStore calls TextInputClient::InsertText().
     70 //     "A" is shown as committed string.
     71 //   - TextStore clears the string buffer.
     72 //   - TextStore calls OnSelectionChange(), OnLayoutChange() and
     73 //     OnTextChange() of ITextStoreACPSink to let TSF manager know that the
     74 //     string buffer has been changed.
     75 //
     76 // About the locking scheme:
     77 // When TSF manager manipulates the string buffer it calls RequestLock() to get
     78 // the lock of the document. If TextStore can grant the lock request, it
     79 // callbacks ITextStoreACPSink::OnLockGranted().
     80 // RequestLock() is called from only one thread, but called recursively in
     81 // OnLockGranted() or OnSelectionChange() or OnLayoutChange() or OnTextChange().
     82 // If the document is locked and the lock request is asynchronous, TextStore
     83 // queues the request. The queued requests will be handled after the current
     84 // lock is removed.
     85 // More information about document locks can be found here:
     86 //   http://msdn.microsoft.com/en-us/library/ms538064
     87 //
     88 // More information about TSF can be found here:
     89 //   http://msdn.microsoft.com/en-us/library/ms629032
     90 class ATL_NO_VTABLE TextStore
     91     : public CComObjectRootEx<CComMultiThreadModel>,
     92       public ITextStoreACP,
     93       public ITfContextOwnerCompositionSink,
     94       public ITfTextEditSink {
     95  public:
     96   virtual ~TextStore();
     97 
     98   BEGIN_COM_MAP(TextStore)
     99     COM_INTERFACE_ENTRY(ITextStoreACP)
    100     COM_INTERFACE_ENTRY(ITfContextOwnerCompositionSink)
    101     COM_INTERFACE_ENTRY(ITfTextEditSink)
    102   END_COM_MAP()
    103 
    104   // ITextStoreACP:
    105   STDMETHOD(AdviseSink)(REFIID iid, IUnknown* unknown, DWORD mask) OVERRIDE;
    106   STDMETHOD(FindNextAttrTransition)(LONG acp_start,
    107                                     LONG acp_halt,
    108                                     ULONG num_filter_attributes,
    109                                     const TS_ATTRID* filter_attributes,
    110                                     DWORD flags,
    111                                     LONG* acp_next,
    112                                     BOOL* found,
    113                                     LONG* found_offset) OVERRIDE;
    114   STDMETHOD(GetACPFromPoint)(TsViewCookie view_cookie,
    115                              const POINT* point,
    116                              DWORD flags,
    117                              LONG* acp) OVERRIDE;
    118   STDMETHOD(GetActiveView)(TsViewCookie* view_cookie) OVERRIDE;
    119   STDMETHOD(GetEmbedded)(LONG acp_pos,
    120                          REFGUID service,
    121                          REFIID iid,
    122                          IUnknown** unknown) OVERRIDE;
    123   STDMETHOD(GetEndACP)(LONG* acp) OVERRIDE;
    124   STDMETHOD(GetFormattedText)(LONG acp_start,
    125                               LONG acp_end,
    126                               IDataObject** data_object) OVERRIDE;
    127   STDMETHOD(GetScreenExt)(TsViewCookie view_cookie, RECT* rect) OVERRIDE;
    128   STDMETHOD(GetSelection)(ULONG selection_index,
    129                           ULONG selection_buffer_size,
    130                           TS_SELECTION_ACP* selection_buffer,
    131                           ULONG* fetched_count) OVERRIDE;
    132   STDMETHOD(GetStatus)(TS_STATUS* pdcs) OVERRIDE;
    133   STDMETHOD(GetText)(LONG acp_start,
    134                      LONG acp_end,
    135                      wchar_t* text_buffer,
    136                      ULONG text_buffer_size,
    137                      ULONG* text_buffer_copied,
    138                      TS_RUNINFO* run_info_buffer,
    139                      ULONG run_info_buffer_size,
    140                      ULONG* run_info_buffer_copied,
    141                      LONG* next_acp) OVERRIDE;
    142   STDMETHOD(GetTextExt)(TsViewCookie view_cookie,
    143                         LONG acp_start,
    144                         LONG acp_end,
    145                         RECT* rect,
    146                         BOOL* clipped) OVERRIDE;
    147   STDMETHOD(GetWnd)(TsViewCookie view_cookie, HWND* window_handle) OVERRIDE;
    148   STDMETHOD(InsertEmbedded)(DWORD flags,
    149                             LONG acp_start,
    150                             LONG acp_end,
    151                             IDataObject* data_object,
    152                             TS_TEXTCHANGE* change) OVERRIDE;
    153   STDMETHOD(InsertEmbeddedAtSelection)(DWORD flags,
    154                                        IDataObject* data_object,
    155                                        LONG* acp_start,
    156                                        LONG* acp_end,
    157                                        TS_TEXTCHANGE* change) OVERRIDE;
    158   STDMETHOD(InsertTextAtSelection)(DWORD flags,
    159                                    const wchar_t* text_buffer,
    160                                    ULONG text_buffer_size,
    161                                    LONG* acp_start,
    162                                    LONG* acp_end,
    163                                    TS_TEXTCHANGE* text_change) OVERRIDE;
    164   STDMETHOD(QueryInsert)(LONG acp_test_start,
    165                          LONG acp_test_end,
    166                          ULONG text_size,
    167                          LONG* acp_result_start,
    168                          LONG* acp_result_end) OVERRIDE;
    169   STDMETHOD(QueryInsertEmbedded)(const GUID* service,
    170                                  const FORMATETC* format,
    171                                  BOOL* insertable) OVERRIDE;
    172   STDMETHOD(RequestAttrsAtPosition)(LONG acp_pos,
    173                                     ULONG attribute_buffer_size,
    174                                     const TS_ATTRID* attribute_buffer,
    175                                     DWORD flags) OVERRIDE;
    176   STDMETHOD(RequestAttrsTransitioningAtPosition)(
    177       LONG acp_pos,
    178       ULONG attribute_buffer_size,
    179       const TS_ATTRID* attribute_buffer,
    180       DWORD flags) OVERRIDE;
    181   STDMETHOD(RequestLock)(DWORD lock_flags, HRESULT* result) OVERRIDE;
    182   STDMETHOD(RequestSupportedAttrs)(DWORD flags,
    183                                    ULONG attribute_buffer_size,
    184                                    const TS_ATTRID* attribute_buffer) OVERRIDE;
    185   STDMETHOD(RetrieveRequestedAttrs)(ULONG attribute_buffer_size,
    186                                     TS_ATTRVAL* attribute_buffer,
    187                                     ULONG* attribute_buffer_copied) OVERRIDE;
    188   STDMETHOD(SetSelection)(ULONG selection_buffer_size,
    189                           const TS_SELECTION_ACP* selection_buffer) OVERRIDE;
    190   STDMETHOD(SetText)(DWORD flags,
    191                      LONG acp_start,
    192                      LONG acp_end,
    193                      const wchar_t* text_buffer,
    194                      ULONG text_buffer_size,
    195                      TS_TEXTCHANGE* text_change) OVERRIDE;
    196   STDMETHOD(UnadviseSink)(IUnknown* unknown) OVERRIDE;
    197 
    198   // ITfContextOwnerCompositionSink:
    199   STDMETHOD(OnStartComposition)(ITfCompositionView* composition_view,
    200                                 BOOL* ok) OVERRIDE;
    201   STDMETHOD(OnUpdateComposition)(ITfCompositionView* composition_view,
    202                                  ITfRange* range) OVERRIDE;
    203   STDMETHOD(OnEndComposition)(ITfCompositionView* composition_view) OVERRIDE;
    204 
    205   // ITfTextEditSink:
    206   STDMETHOD(OnEndEdit)(ITfContext* context, TfEditCookie read_only_edit_cookie,
    207                        ITfEditRecord* edit_record) OVERRIDE;
    208 
    209   // Cancels the ongoing composition if exists.
    210   bool CancelComposition();
    211 
    212   // Confirms the ongoing composition if exists.
    213   bool ConfirmComposition();
    214 
    215   // Sends OnLayoutChange() via |text_store_acp_sink_|.
    216   void SendOnLayoutChange();
    217 
    218   // Creates an instance of TextStore. Returns NULL if fails.
    219   static scoped_refptr<TextStore> Create(
    220       HWND window_handle,
    221       const std::vector<InputScope>& input_scopes,
    222       TextStoreDelegate* delegate);
    223 
    224  private:
    225   friend CComObject<TextStore>;
    226   TextStore();
    227 
    228   void Initialize(HWND window_handle,
    229                   ITfCategoryMgr* category_manager,
    230                   ITfDisplayAttributeMgr* display_attribute_manager,
    231                   ITfInputScope* input_scope,
    232                   TextStoreDelegate* delegate);
    233 
    234   // Checks if the document has a read-only lock.
    235   bool HasReadLock() const;
    236 
    237   // Checks if the document has a read and write lock.
    238   bool HasReadWriteLock() const;
    239 
    240   // Gets the display attribute structure.
    241   bool GetDisplayAttribute(TfGuidAtom guid_atom,
    242                            TF_DISPLAYATTRIBUTE* attribute);
    243 
    244   // Gets the committed string size and underline information of the context.
    245   bool GetCompositionStatus(
    246       ITfContext* context,
    247       const TfEditCookie read_only_edit_cookie,
    248       uint32* committed_size,
    249       std::vector<metro_viewer::UnderlineInfo>* undelines);
    250 
    251   // A pointer of ITextStoreACPSink, this instance is given in AdviseSink.
    252   base::win::ScopedComPtr<ITextStoreACPSink> text_store_acp_sink_;
    253 
    254   // The current mask of |text_store_acp_sink_|.
    255   DWORD text_store_acp_sink_mask_;
    256 
    257   // HWND of the attached window.
    258   HWND window_handle_;
    259 
    260   //  |string_buffer_| contains committed string and composition string.
    261   //  Example: "aoi" is committed, and "umi" is under composition.
    262   //    |string_buffer_|: "aoiumi"
    263   //    |committed_size_|: 3
    264   base::string16 string_buffer_;
    265   uint32 committed_size_;
    266 
    267   //  |selection_start_| and |selection_end_| indicates the selection range.
    268   //  Example: "iue" is selected
    269   //    |string_buffer_|: "aiueo"
    270   //    |selection_start_|: 1
    271   //    |selection_end_|: 4
    272   uint32 selection_start_;
    273   uint32 selection_end_;
    274 
    275   //  |start_offset| and |end_offset| of |composition_undelines_| indicates
    276   //  the offsets in |string_buffer_|.
    277   //  Example: "aoi" is committed. There are two underlines in "umi" and "no".
    278   //    |string_buffer_|: "aoiumino"
    279   //    |committed_size_|: 3
    280   //    underlines_[0].start_offset: 3
    281   //    underlines_[0].end_offset: 6
    282   //    underlines_[1].start_offset: 6
    283   //    underlines_[1].end_offset: 8
    284   std::vector<metro_viewer::UnderlineInfo> underlines_;
    285 
    286   // |edit_flag_| indicates that the status is edited during
    287   // ITextStoreACPSink::OnLockGranted().
    288   bool edit_flag_;
    289 
    290   // The type of current lock.
    291   //   0: No lock.
    292   //   TS_LF_READ: read-only lock.
    293   //   TS_LF_READWRITE: read/write lock.
    294   DWORD current_lock_type_;
    295 
    296   // Queue of the lock request used in RequestLock().
    297   std::deque<DWORD> lock_queue_;
    298 
    299   // Category manager and Display attribute manager are used to obtain the
    300   // attributes of the composition string.
    301   base::win::ScopedComPtr<ITfCategoryMgr> category_manager_;
    302   base::win::ScopedComPtr<ITfDisplayAttributeMgr> display_attribute_manager_;
    303 
    304   // Represents the context information of this text.
    305   base::win::ScopedComPtr<ITfInputScope> input_scope_;
    306 
    307   // The delegate attached to this text store.
    308   TextStoreDelegate* delegate_;
    309 
    310   DISALLOW_COPY_AND_ASSIGN(TextStore);
    311 };
    312 
    313 }  // namespace metro_driver
    314 
    315 #endif  // WIN8_METRO_DRIVER_IME_TEXT_STORE_H_
    316