| 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 |