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