summaryrefslogtreecommitdiffstats
path: root/win8/metro_driver/ime/text_store.h
blob: 3af5bf20991dc368f7f2d39cebf366514771e749 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef WIN8_METRO_DRIVER_IME_TEXT_STORE_H_
#define WIN8_METRO_DRIVER_IME_TEXT_STORE_H_

#include <atlbase.h>
#include <atlcom.h>
#include <initguid.h>
#include <inputscope.h>
#include <msctf.h>

#include <deque>
#include <vector>

#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "base/win/scoped_comptr.h"
#include "ui/metro_viewer/ime_types.h"

namespace metro_driver {

class TextStoreDelegate;

// TextStore is used to interact with the input method via TSF manager.
// TextStore have a string buffer which is manipulated by TSF manager through
// ITextStoreACP interface methods such as SetText().
// When the input method updates the composition, TextStore calls
// TextInputClient::SetCompositionText(). And when the input method finishes the
// composition, TextStore calls TextInputClient::InsertText() and clears the
// buffer.
//
// How TextStore works:
//  - The user enters "a".
//    - The input method set composition as "a".
//    - TSF manager calls TextStore::RequestLock().
//    - TextStore callbacks ITextStoreACPSink::OnLockGranted().
//    - In OnLockGranted(), TSF manager calls
//      - TextStore::OnStartComposition()
//      - TextStore::SetText()
//        The string buffer is set as "a".
//      - TextStore::OnUpdateComposition()
//      - TextStore::OnEndEdit()
//        TextStore can get the composition information such as underlines.
//   - TextStore calls TextInputClient::SetCompositionText().
//     "a" is shown with an underline as composition string.
// - The user enters <space>.
//    - The input method set composition as "A".
//    - TSF manager calls TextStore::RequestLock().
//    - TextStore callbacks ITextStoreACPSink::OnLockGranted().
//    - In OnLockGranted(), TSF manager calls
//      - TextStore::SetText()
//        The string buffer is set as "A".
//      - TextStore::OnUpdateComposition()
//      - TextStore::OnEndEdit()
//   - TextStore calls TextInputClient::SetCompositionText().
//     "A" is shown with an underline as composition string.
// - The user enters <enter>.
//    - The input method commits "A".
//    - TSF manager calls TextStore::RequestLock().
//    - TextStore callbacks ITextStoreACPSink::OnLockGranted().
//    - In OnLockGranted(), TSF manager calls
//      - TextStore::OnEndComposition()
//      - TextStore::OnEndEdit()
//        TextStore knows "A" is committed.
//   - TextStore calls TextInputClient::InsertText().
//     "A" is shown as committed string.
//   - TextStore clears the string buffer.
//   - TextStore calls OnSelectionChange(), OnLayoutChange() and
//     OnTextChange() of ITextStoreACPSink to let TSF manager know that the
//     string buffer has been changed.
//
// About the locking scheme:
// When TSF manager manipulates the string buffer it calls RequestLock() to get
// the lock of the document. If TextStore can grant the lock request, it
// callbacks ITextStoreACPSink::OnLockGranted().
// RequestLock() is called from only one thread, but called recursively in
// OnLockGranted() or OnSelectionChange() or OnLayoutChange() or OnTextChange().
// If the document is locked and the lock request is asynchronous, TextStore
// queues the request. The queued requests will be handled after the current
// lock is removed.
// More information about document locks can be found here:
//   http://msdn.microsoft.com/en-us/library/ms538064
//
// More information about TSF can be found here:
//   http://msdn.microsoft.com/en-us/library/ms629032
class ATL_NO_VTABLE TextStore
    : public CComObjectRootEx<CComMultiThreadModel>,
      public ITextStoreACP,
      public ITfContextOwnerCompositionSink,
      public ITfTextEditSink {
 public:
  virtual ~TextStore();

  BEGIN_COM_MAP(TextStore)
    COM_INTERFACE_ENTRY(ITextStoreACP)
    COM_INTERFACE_ENTRY(ITfContextOwnerCompositionSink)
    COM_INTERFACE_ENTRY(ITfTextEditSink)
  END_COM_MAP()

  // ITextStoreACP:
  STDMETHOD(AdviseSink)(REFIID iid, IUnknown* unknown, DWORD mask) override;
  STDMETHOD(FindNextAttrTransition)(LONG acp_start,
                                    LONG acp_halt,
                                    ULONG num_filter_attributes,
                                    const TS_ATTRID* filter_attributes,
                                    DWORD flags,
                                    LONG* acp_next,
                                    BOOL* found,
                                    LONG* found_offset) override;
  STDMETHOD(GetACPFromPoint)(TsViewCookie view_cookie,
                             const POINT* point,
                             DWORD flags,
                             LONG* acp) override;
  STDMETHOD(GetActiveView)(TsViewCookie* view_cookie) override;
  STDMETHOD(GetEmbedded)(LONG acp_pos,
                         REFGUID service,
                         REFIID iid,
                         IUnknown** unknown) override;
  STDMETHOD(GetEndACP)(LONG* acp) override;
  STDMETHOD(GetFormattedText)(LONG acp_start,
                              LONG acp_end,
                              IDataObject** data_object) override;
  STDMETHOD(GetScreenExt)(TsViewCookie view_cookie, RECT* rect) override;
  STDMETHOD(GetSelection)(ULONG selection_index,
                          ULONG selection_buffer_size,
                          TS_SELECTION_ACP* selection_buffer,
                          ULONG* fetched_count) override;
  STDMETHOD(GetStatus)(TS_STATUS* pdcs) override;
  STDMETHOD(GetText)(LONG acp_start,
                     LONG acp_end,
                     wchar_t* text_buffer,
                     ULONG text_buffer_size,
                     ULONG* text_buffer_copied,
                     TS_RUNINFO* run_info_buffer,
                     ULONG run_info_buffer_size,
                     ULONG* run_info_buffer_copied,
                     LONG* next_acp) override;
  STDMETHOD(GetTextExt)(TsViewCookie view_cookie,
                        LONG acp_start,
                        LONG acp_end,
                        RECT* rect,
                        BOOL* clipped) override;
  STDMETHOD(GetWnd)(TsViewCookie view_cookie, HWND* window_handle) override;
  STDMETHOD(InsertEmbedded)(DWORD flags,
                            LONG acp_start,
                            LONG acp_end,
                            IDataObject* data_object,
                            TS_TEXTCHANGE* change) override;
  STDMETHOD(InsertEmbeddedAtSelection)(DWORD flags,
                                       IDataObject* data_object,
                                       LONG* acp_start,
                                       LONG* acp_end,
                                       TS_TEXTCHANGE* change) override;
  STDMETHOD(InsertTextAtSelection)(DWORD flags,
                                   const wchar_t* text_buffer,
                                   ULONG text_buffer_size,
                                   LONG* acp_start,
                                   LONG* acp_end,
                                   TS_TEXTCHANGE* text_change) override;
  STDMETHOD(QueryInsert)(LONG acp_test_start,
                         LONG acp_test_end,
                         ULONG text_size,
                         LONG* acp_result_start,
                         LONG* acp_result_end) override;
  STDMETHOD(QueryInsertEmbedded)(const GUID* service,
                                 const FORMATETC* format,
                                 BOOL* insertable) override;
  STDMETHOD(RequestAttrsAtPosition)(LONG acp_pos,
                                    ULONG attribute_buffer_size,
                                    const TS_ATTRID* attribute_buffer,
                                    DWORD flags) override;
  STDMETHOD(RequestAttrsTransitioningAtPosition)(
      LONG acp_pos,
      ULONG attribute_buffer_size,
      const TS_ATTRID* attribute_buffer,
      DWORD flags) override;
  STDMETHOD(RequestLock)(DWORD lock_flags, HRESULT* result) override;
  STDMETHOD(RequestSupportedAttrs)(DWORD flags,
                                   ULONG attribute_buffer_size,
                                   const TS_ATTRID* attribute_buffer) override;
  STDMETHOD(RetrieveRequestedAttrs)(ULONG attribute_buffer_size,
                                    TS_ATTRVAL* attribute_buffer,
                                    ULONG* attribute_buffer_copied) override;
  STDMETHOD(SetSelection)(ULONG selection_buffer_size,
                          const TS_SELECTION_ACP* selection_buffer) override;
  STDMETHOD(SetText)(DWORD flags,
                     LONG acp_start,
                     LONG acp_end,
                     const wchar_t* text_buffer,
                     ULONG text_buffer_size,
                     TS_TEXTCHANGE* text_change) override;
  STDMETHOD(UnadviseSink)(IUnknown* unknown) override;

  // ITfContextOwnerCompositionSink:
  STDMETHOD(OnStartComposition)(ITfCompositionView* composition_view,
                                BOOL* ok) override;
  STDMETHOD(OnUpdateComposition)(ITfCompositionView* composition_view,
                                 ITfRange* range) override;
  STDMETHOD(OnEndComposition)(ITfCompositionView* composition_view) override;

  // ITfTextEditSink:
  STDMETHOD(OnEndEdit)(ITfContext* context, TfEditCookie read_only_edit_cookie,
                       ITfEditRecord* edit_record) override;

  // Cancels the ongoing composition if exists.
  bool CancelComposition();

  // Confirms the ongoing composition if exists.
  bool ConfirmComposition();

  // Sends OnLayoutChange() via |text_store_acp_sink_|.
  void SendOnLayoutChange();

  // Creates an instance of TextStore. Returns NULL if fails.
  static scoped_refptr<TextStore> Create(
      HWND window_handle,
      const std::vector<InputScope>& input_scopes,
      TextStoreDelegate* delegate);

 private:
  friend CComObject<TextStore>;
  TextStore();

  void Initialize(HWND window_handle,
                  ITfCategoryMgr* category_manager,
                  ITfDisplayAttributeMgr* display_attribute_manager,
                  ITfInputScope* input_scope,
                  TextStoreDelegate* delegate);

  // Checks if the document has a read-only lock.
  bool HasReadLock() const;

  // Checks if the document has a read and write lock.
  bool HasReadWriteLock() const;

  // Gets the display attribute structure.
  bool GetDisplayAttribute(TfGuidAtom guid_atom,
                           TF_DISPLAYATTRIBUTE* attribute);

  // Gets the committed string size and underline information of the context.
  bool GetCompositionStatus(
      ITfContext* context,
      const TfEditCookie read_only_edit_cookie,
      uint32* committed_size,
      std::vector<metro_viewer::UnderlineInfo>* undelines);

  // A pointer of ITextStoreACPSink, this instance is given in AdviseSink.
  base::win::ScopedComPtr<ITextStoreACPSink> text_store_acp_sink_;

  // The current mask of |text_store_acp_sink_|.
  DWORD text_store_acp_sink_mask_;

  // HWND of the attached window.
  HWND window_handle_;

  //  |string_buffer_| contains committed string and composition string.
  //  Example: "aoi" is committed, and "umi" is under composition.
  //    |string_buffer_|: "aoiumi"
  //    |committed_size_|: 3
  base::string16 string_buffer_;
  uint32 committed_size_;

  //  |selection_start_| and |selection_end_| indicates the selection range.
  //  Example: "iue" is selected
  //    |string_buffer_|: "aiueo"
  //    |selection_start_|: 1
  //    |selection_end_|: 4
  uint32 selection_start_;
  uint32 selection_end_;

  //  |start_offset| and |end_offset| of |composition_undelines_| indicates
  //  the offsets in |string_buffer_|.
  //  Example: "aoi" is committed. There are two underlines in "umi" and "no".
  //    |string_buffer_|: "aoiumino"
  //    |committed_size_|: 3
  //    underlines_[0].start_offset: 3
  //    underlines_[0].end_offset: 6
  //    underlines_[1].start_offset: 6
  //    underlines_[1].end_offset: 8
  std::vector<metro_viewer::UnderlineInfo> underlines_;

  // |edit_flag_| indicates that the status is edited during
  // ITextStoreACPSink::OnLockGranted().
  bool edit_flag_;

  // The type of current lock.
  //   0: No lock.
  //   TS_LF_READ: read-only lock.
  //   TS_LF_READWRITE: read/write lock.
  DWORD current_lock_type_;

  // Queue of the lock request used in RequestLock().
  std::deque<DWORD> lock_queue_;

  // Category manager and Display attribute manager are used to obtain the
  // attributes of the composition string.
  base::win::ScopedComPtr<ITfCategoryMgr> category_manager_;
  base::win::ScopedComPtr<ITfDisplayAttributeMgr> display_attribute_manager_;

  // Represents the context information of this text.
  base::win::ScopedComPtr<ITfInputScope> input_scope_;

  // The delegate attached to this text store.
  TextStoreDelegate* delegate_;

  DISALLOW_COPY_AND_ASSIGN(TextStore);
};

}  // namespace metro_driver

#endif  // WIN8_METRO_DRIVER_IME_TEXT_STORE_H_