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