Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: win8/metro_driver/ime/text_store.cc

Issue 53553003: WIP: Ash IME support (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « win8/metro_driver/ime/text_store.h ('k') | win8/metro_driver/ime/text_store_delegate.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #define INITGUID // required for GUID_PROP_INPUTSCOPE 5 #define INITGUID // required for GUID_PROP_INPUTSCOPE
6 #include "ui/base/ime/win/tsf_text_store.h" 6 #include "win8/metro_driver/ime/text_store.h"
7 7
8 #include <InputScope.h> 8 #include <InputScope.h>
9 #include <OleCtl.h> 9 #include <OleCtl.h>
10 10
11 #include <algorithm> 11 #include <algorithm>
12 12
13 #include "base/win/scoped_variant.h" 13 #include "base/win/scoped_variant.h"
14 #include "ui/base/ime/text_input_client.h" 14 #include "win8/metro_driver/ime/input_scope.h"
15 #include "ui/base/ime/win/tsf_input_scope.h" 15 #include "win8/metro_driver/ime/text_store_delegate.h"
16 #include "ui/gfx/rect.h"
17 16
18 namespace ui { 17 namespace metro_driver {
19 namespace { 18 namespace {
20 19
21 // We support only one view. 20 // We support only one view.
22 const TsViewCookie kViewCookie = 1; 21 const TsViewCookie kViewCookie = 1;
23 22
24 } // namespace 23 } // namespace
25 24
26 TSFTextStore::TSFTextStore() 25 TextStore::TextStore(HWND window_handle,
26 const std::vector<InputScope>& input_scopes,
27 TextStoreDelegate* delegate)
27 : ref_count_(0), 28 : ref_count_(0),
28 text_store_acp_sink_mask_(0), 29 text_store_acp_sink_mask_(0),
29 window_handle_(NULL), 30 window_handle_(window_handle),
30 text_input_client_(NULL), 31 delegate_(delegate),
31 committed_size_(0), 32 committed_size_(0),
33 selection_start_(0),
34 selection_end_(0),
32 edit_flag_(false), 35 edit_flag_(false),
33 current_lock_type_(0) { 36 current_lock_type_(0) {
34 if (FAILED(category_manager_.CreateInstance(CLSID_TF_CategoryMgr))) { 37 if (FAILED(category_manager_.CreateInstance(CLSID_TF_CategoryMgr))) {
35 LOG(FATAL) << "Failed to initialize CategoryMgr."; 38 LOG(FATAL) << "Failed to initialize CategoryMgr.";
36 return; 39 return;
37 } 40 }
38 if (FAILED(display_attribute_manager_.CreateInstance( 41 if (FAILED(display_attribute_manager_.CreateInstance(
39 CLSID_TF_DisplayAttributeMgr))) { 42 CLSID_TF_DisplayAttributeMgr))) {
40 LOG(FATAL) << "Failed to initialize DisplayAttributeMgr."; 43 LOG(FATAL) << "Failed to initialize DisplayAttributeMgr.";
41 return; 44 return;
42 } 45 }
46 input_scope_ = CreteInputScope(input_scopes);
43 } 47 }
44 48
45 TSFTextStore::~TSFTextStore() { 49 TextStore::~TextStore() {
46 } 50 }
47 51
48 ULONG STDMETHODCALLTYPE TSFTextStore::AddRef() { 52 ULONG STDMETHODCALLTYPE TextStore::AddRef() {
49 return InterlockedIncrement(&ref_count_); 53 return InterlockedIncrement(&ref_count_);
50 } 54 }
51 55
52 ULONG STDMETHODCALLTYPE TSFTextStore::Release() { 56 ULONG STDMETHODCALLTYPE TextStore::Release() {
53 const LONG count = InterlockedDecrement(&ref_count_); 57 const LONG count = InterlockedDecrement(&ref_count_);
54 if (!count) { 58 if (!count) {
55 delete this; 59 delete this;
56 return 0; 60 return 0;
57 } 61 }
58 return static_cast<ULONG>(count); 62 return static_cast<ULONG>(count);
59 } 63 }
60 64
61 STDMETHODIMP TSFTextStore::QueryInterface(REFIID iid, void** result) { 65 STDMETHODIMP TextStore::QueryInterface(REFIID iid, void** result) {
62 if (iid == IID_IUnknown || iid == IID_ITextStoreACP) { 66 if (iid == IID_IUnknown || iid == IID_ITextStoreACP) {
63 *result = static_cast<ITextStoreACP*>(this); 67 *result = static_cast<ITextStoreACP*>(this);
64 } else if (iid == IID_ITfContextOwnerCompositionSink) { 68 } else if (iid == IID_ITfContextOwnerCompositionSink) {
65 *result = static_cast<ITfContextOwnerCompositionSink*>(this); 69 *result = static_cast<ITfContextOwnerCompositionSink*>(this);
66 } else if (iid == IID_ITfTextEditSink) { 70 } else if (iid == IID_ITfTextEditSink) {
67 *result = static_cast<ITfTextEditSink*>(this); 71 *result = static_cast<ITfTextEditSink*>(this);
68 } else { 72 } else {
69 *result = NULL; 73 *result = NULL;
70 return E_NOINTERFACE; 74 return E_NOINTERFACE;
71 } 75 }
72 AddRef(); 76 AddRef();
73 return S_OK; 77 return S_OK;
74 } 78 }
75 79
76 STDMETHODIMP TSFTextStore::AdviseSink(REFIID iid, 80 STDMETHODIMP TextStore::AdviseSink(REFIID iid,
77 IUnknown* unknown, 81 IUnknown* unknown,
78 DWORD mask) { 82 DWORD mask) {
79 if (!IsEqualGUID(iid, IID_ITextStoreACPSink)) 83 if (!IsEqualGUID(iid, IID_ITextStoreACPSink))
80 return E_INVALIDARG; 84 return E_INVALIDARG;
81 if (text_store_acp_sink_) { 85 if (text_store_acp_sink_) {
82 if (text_store_acp_sink_.IsSameObject(unknown)) { 86 if (text_store_acp_sink_.IsSameObject(unknown)) {
83 text_store_acp_sink_mask_ = mask; 87 text_store_acp_sink_mask_ = mask;
84 return S_OK; 88 return S_OK;
85 } else { 89 } else {
86 return CONNECT_E_ADVISELIMIT; 90 return CONNECT_E_ADVISELIMIT;
87 } 91 }
88 } 92 }
89 if (FAILED(text_store_acp_sink_.QueryFrom(unknown))) 93 if (FAILED(text_store_acp_sink_.QueryFrom(unknown)))
90 return E_UNEXPECTED; 94 return E_UNEXPECTED;
91 text_store_acp_sink_mask_ = mask; 95 text_store_acp_sink_mask_ = mask;
92 96
93 return S_OK; 97 return S_OK;
94 } 98 }
95 99
96 STDMETHODIMP TSFTextStore::FindNextAttrTransition( 100 STDMETHODIMP TextStore::FindNextAttrTransition(
97 LONG acp_start, 101 LONG acp_start,
98 LONG acp_halt, 102 LONG acp_halt,
99 ULONG num_filter_attributes, 103 ULONG num_filter_attributes,
100 const TS_ATTRID* filter_attributes, 104 const TS_ATTRID* filter_attributes,
101 DWORD flags, 105 DWORD flags,
102 LONG* acp_next, 106 LONG* acp_next,
103 BOOL* found, 107 BOOL* found,
104 LONG* found_offset) { 108 LONG* found_offset) {
105 if (!acp_next || !found || !found_offset) 109 if (!acp_next || !found || !found_offset)
106 return E_INVALIDARG; 110 return E_INVALIDARG;
107 // We don't support any attributes. 111 // We don't support any attributes.
108 // So we always return "not found". 112 // So we always return "not found".
109 *acp_next = 0; 113 *acp_next = 0;
110 *found = FALSE; 114 *found = FALSE;
111 *found_offset = 0; 115 *found_offset = 0;
112 return S_OK; 116 return S_OK;
113 } 117 }
114 118
115 STDMETHODIMP TSFTextStore::GetACPFromPoint(TsViewCookie view_cookie, 119 STDMETHODIMP TextStore::GetACPFromPoint(TsViewCookie view_cookie,
116 const POINT* point, 120 const POINT* point,
117 DWORD flags, 121 DWORD flags,
118 LONG* acp) { 122 LONG* acp) {
119 NOTIMPLEMENTED(); 123 NOTIMPLEMENTED();
120 if (view_cookie != kViewCookie) 124 if (view_cookie != kViewCookie)
121 return E_INVALIDARG; 125 return E_INVALIDARG;
122 return E_NOTIMPL; 126 return E_NOTIMPL;
123 } 127 }
124 128
125 STDMETHODIMP TSFTextStore::GetActiveView(TsViewCookie* view_cookie) { 129 STDMETHODIMP TextStore::GetActiveView(TsViewCookie* view_cookie) {
126 if (!view_cookie) 130 if (!view_cookie)
127 return E_INVALIDARG; 131 return E_INVALIDARG;
128 // We support only one view. 132 // We support only one view.
129 *view_cookie = kViewCookie; 133 *view_cookie = kViewCookie;
130 return S_OK; 134 return S_OK;
131 } 135 }
132 136
133 STDMETHODIMP TSFTextStore::GetEmbedded(LONG acp_pos, 137 STDMETHODIMP TextStore::GetEmbedded(LONG acp_pos,
134 REFGUID service, 138 REFGUID service,
135 REFIID iid, 139 REFIID iid,
136 IUnknown** unknown) { 140 IUnknown** unknown) {
137 // We don't support any embedded objects. 141 // We don't support any embedded objects.
138 NOTIMPLEMENTED(); 142 NOTIMPLEMENTED();
139 if (!unknown) 143 if (!unknown)
140 return E_INVALIDARG; 144 return E_INVALIDARG;
141 *unknown = NULL; 145 *unknown = NULL;
142 return E_NOTIMPL; 146 return E_NOTIMPL;
143 } 147 }
144 148
145 STDMETHODIMP TSFTextStore::GetEndACP(LONG* acp) { 149 STDMETHODIMP TextStore::GetEndACP(LONG* acp) {
146 if (!acp) 150 if (!acp)
147 return E_INVALIDARG; 151 return E_INVALIDARG;
148 if (!HasReadLock()) 152 if (!HasReadLock())
149 return TS_E_NOLOCK; 153 return TS_E_NOLOCK;
150 *acp = string_buffer_.size(); 154 *acp = string_buffer_.size();
151 return S_OK; 155 return S_OK;
152 } 156 }
153 157
154 STDMETHODIMP TSFTextStore::GetFormattedText(LONG acp_start, LONG acp_end, 158 STDMETHODIMP TextStore::GetFormattedText(LONG acp_start, LONG acp_end,
155 IDataObject** data_object) { 159 IDataObject** data_object) {
156 NOTIMPLEMENTED(); 160 NOTIMPLEMENTED();
157 return E_NOTIMPL; 161 return E_NOTIMPL;
158 } 162 }
159 163
160 STDMETHODIMP TSFTextStore::GetScreenExt(TsViewCookie view_cookie, RECT* rect) { 164 STDMETHODIMP TextStore::GetScreenExt(TsViewCookie view_cookie, RECT* rect) {
161 if (view_cookie != kViewCookie) 165 if (view_cookie != kViewCookie)
162 return E_INVALIDARG; 166 return E_INVALIDARG;
163 if (!rect) 167 if (!rect)
164 return E_INVALIDARG; 168 return E_INVALIDARG;
165 169
166 // {0, 0, 0, 0} means that the document rect is not currently displayed. 170 // {0, 0, 0, 0} means that the document rect is not currently displayed.
167 SetRect(rect, 0, 0, 0, 0); 171 SetRect(rect, 0, 0, 0, 0);
168 172
169 if (!IsWindow(window_handle_))
170 return E_FAIL;
171
172 // Currently ui::TextInputClient does not expose the document rect. So use
173 // the Win32 client rectangle instead.
174 // TODO(yukawa): Upgrade TextInputClient so that the client can retrieve the
175 // document rectangle.
176 RECT client_rect = {}; 173 RECT client_rect = {};
177 if (!GetClientRect(window_handle_, &client_rect)) 174 if (!GetClientRect(window_handle_, &client_rect))
178 return E_FAIL; 175 return E_FAIL;
179 POINT left_top = {client_rect.left, client_rect.top}; 176 POINT left_top = {client_rect.left, client_rect.top};
180 POINT right_bottom = {client_rect.right, client_rect.bottom}; 177 POINT right_bottom = {client_rect.right, client_rect.bottom};
181 if (!ClientToScreen(window_handle_, &left_top)) 178 if (!ClientToScreen(window_handle_, &left_top))
182 return E_FAIL; 179 return E_FAIL;
183 if (!ClientToScreen(window_handle_, &right_bottom)) 180 if (!ClientToScreen(window_handle_, &right_bottom))
184 return E_FAIL; 181 return E_FAIL;
185 182
186 rect->left = left_top.x; 183 rect->left = left_top.x;
187 rect->top = left_top.y; 184 rect->top = left_top.y;
188 rect->right = right_bottom.x; 185 rect->right = right_bottom.x;
189 rect->bottom = right_bottom.y; 186 rect->bottom = right_bottom.y;
190 return S_OK; 187 return S_OK;
191 } 188 }
192 189
193 STDMETHODIMP TSFTextStore::GetSelection(ULONG selection_index, 190 STDMETHODIMP TextStore::GetSelection(ULONG selection_index,
194 ULONG selection_buffer_size, 191 ULONG selection_buffer_size,
195 TS_SELECTION_ACP* selection_buffer, 192 TS_SELECTION_ACP* selection_buffer,
196 ULONG* fetched_count) { 193 ULONG* fetched_count) {
197 if (!selection_buffer) 194 if (!selection_buffer)
198 return E_INVALIDARG; 195 return E_INVALIDARG;
199 if (!fetched_count) 196 if (!fetched_count)
200 return E_INVALIDARG; 197 return E_INVALIDARG;
201 if (!HasReadLock()) 198 if (!HasReadLock())
202 return TS_E_NOLOCK; 199 return TS_E_NOLOCK;
203 *fetched_count = 0; 200 *fetched_count = 0;
204 if ((selection_buffer_size > 0) && 201 if ((selection_buffer_size > 0) &&
205 ((selection_index == 0) || (selection_index == TS_DEFAULT_SELECTION))) { 202 ((selection_index == 0) || (selection_index == TS_DEFAULT_SELECTION))) {
206 selection_buffer[0].acpStart = selection_.start(); 203 selection_buffer[0].acpStart = selection_start_;
207 selection_buffer[0].acpEnd = selection_.end(); 204 selection_buffer[0].acpEnd = selection_end_;
208 selection_buffer[0].style.ase = TS_AE_END; 205 selection_buffer[0].style.ase = TS_AE_END;
209 selection_buffer[0].style.fInterimChar = FALSE; 206 selection_buffer[0].style.fInterimChar = FALSE;
210 *fetched_count = 1; 207 *fetched_count = 1;
211 } 208 }
212 return S_OK; 209 return S_OK;
213 } 210 }
214 211
215 STDMETHODIMP TSFTextStore::GetStatus(TS_STATUS* status) { 212 STDMETHODIMP TextStore::GetStatus(TS_STATUS* status) {
216 if (!status) 213 if (!status)
217 return E_INVALIDARG; 214 return E_INVALIDARG;
218 215
219 status->dwDynamicFlags = 0; 216 status->dwDynamicFlags = 0;
220 // We use transitory contexts and we don't support hidden text. 217 // We use transitory contexts and we don't support hidden text.
221 status->dwStaticFlags = TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT; 218 status->dwStaticFlags = TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT;
222 219
223 return S_OK; 220 return S_OK;
224 } 221 }
225 222
226 STDMETHODIMP TSFTextStore::GetText(LONG acp_start, 223 STDMETHODIMP TextStore::GetText(LONG acp_start,
227 LONG acp_end, 224 LONG acp_end,
228 wchar_t* text_buffer, 225 wchar_t* text_buffer,
229 ULONG text_buffer_size, 226 ULONG text_buffer_size,
230 ULONG* text_buffer_copied, 227 ULONG* text_buffer_copied,
231 TS_RUNINFO* run_info_buffer, 228 TS_RUNINFO* run_info_buffer,
232 ULONG run_info_buffer_size, 229 ULONG run_info_buffer_size,
233 ULONG* run_info_buffer_copied, 230 ULONG* run_info_buffer_copied,
234 LONG* next_acp) { 231 LONG* next_acp) {
235 if (!text_buffer_copied || !run_info_buffer_copied) 232 if (!text_buffer_copied || !run_info_buffer_copied)
236 return E_INVALIDARG; 233 return E_INVALIDARG;
237 if (!text_buffer && text_buffer_size != 0) 234 if (!text_buffer && text_buffer_size != 0)
238 return E_INVALIDARG; 235 return E_INVALIDARG;
239 if (!run_info_buffer && run_info_buffer_size != 0) 236 if (!run_info_buffer && run_info_buffer_size != 0)
240 return E_INVALIDARG; 237 return E_INVALIDARG;
241 if (!next_acp) 238 if (!next_acp)
242 return E_INVALIDARG; 239 return E_INVALIDARG;
243 if (!HasReadLock()) 240 if (!HasReadLock())
244 return TF_E_NOLOCK; 241 return TF_E_NOLOCK;
(...skipping 17 matching lines...) Expand all
262 if (run_info_buffer_size) { 259 if (run_info_buffer_size) {
263 run_info_buffer[0].uCount = *text_buffer_copied; 260 run_info_buffer[0].uCount = *text_buffer_copied;
264 run_info_buffer[0].type = TS_RT_PLAIN; 261 run_info_buffer[0].type = TS_RT_PLAIN;
265 *run_info_buffer_copied = 1; 262 *run_info_buffer_copied = 1;
266 } 263 }
267 264
268 *next_acp = acp_end; 265 *next_acp = acp_end;
269 return S_OK; 266 return S_OK;
270 } 267 }
271 268
272 STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie, 269 STDMETHODIMP TextStore::GetTextExt(TsViewCookie view_cookie,
273 LONG acp_start, 270 LONG acp_start,
274 LONG acp_end, 271 LONG acp_end,
275 RECT* rect, 272 RECT* rect,
276 BOOL* clipped) { 273 BOOL* clipped) {
277 if (!rect || !clipped) 274 if (!rect || !clipped)
278 return E_INVALIDARG; 275 return E_INVALIDARG;
279 if (!text_input_client_)
280 return E_UNEXPECTED;
281 if (view_cookie != kViewCookie) 276 if (view_cookie != kViewCookie)
282 return E_INVALIDARG; 277 return E_INVALIDARG;
283 if (!HasReadLock()) 278 if (!HasReadLock())
284 return TS_E_NOLOCK; 279 return TS_E_NOLOCK;
285 if (!((static_cast<LONG>(committed_size_) <= acp_start) && 280 if (!((static_cast<LONG>(committed_size_) <= acp_start) &&
286 (acp_start <= acp_end) && 281 (acp_start <= acp_end) &&
287 (acp_end <= static_cast<LONG>(string_buffer_.size())))) { 282 (acp_end <= static_cast<LONG>(string_buffer_.size())))) {
288 return TS_E_INVALIDPOS; 283 return TS_E_INVALIDPOS;
289 } 284 }
290 285
291 // According to a behavior of notepad.exe and wordpad.exe, top left corner of 286 // According to a behavior of notepad.exe and wordpad.exe, top left corner of
292 // rect indicates a first character's one, and bottom right corner of rect 287 // rect indicates a first character's one, and bottom right corner of rect
293 // indicates a last character's one. 288 // indicates a last character's one.
294 // We use RECT instead of gfx::Rect since left position may be bigger than 289 // We use RECT instead of gfx::Rect since left position may be bigger than
295 // right position when composition has multiple lines. 290 // right position when composition has multiple lines.
296 RECT result; 291 RECT result = {};
297 gfx::Rect tmp_rect; 292 RECT tmp_rect = {};
298 const uint32 start_pos = acp_start - committed_size_; 293 const uint32 start_pos = acp_start - committed_size_;
299 const uint32 end_pos = acp_end - committed_size_; 294 const uint32 end_pos = acp_end - committed_size_;
300 295
301 if (start_pos == end_pos) { 296 if (start_pos == end_pos) {
302 // According to MSDN document, if |acp_start| and |acp_end| are equal it is 297 // According to MSDN document, if |acp_start| and |acp_end| are equal it is
303 // OK to just return E_INVALIDARG. 298 // OK to just return E_INVALIDARG.
304 // http://msdn.microsoft.com/en-us/library/ms538435 299 // http://msdn.microsoft.com/en-us/library/ms538435
305 // But when using Pinin IME of Windows 8, this method is called with the 300 // But when using Pinin IME of Windows 8, this method is called with the
306 // equal values of |acp_start| and |acp_end|. So we handle this condition. 301 // equal values of |acp_start| and |acp_end|. So we handle this condition.
307 if (start_pos == 0) { 302 if (start_pos == 0) {
308 if (text_input_client_->GetCompositionCharacterBounds(0, &tmp_rect)) { 303 if (delegate_->GetCompositionCharacterBounds(0, &tmp_rect)) {
309 tmp_rect.set_width(0); 304 tmp_rect.right = tmp_rect.right;
310 result = tmp_rect.ToRECT(); 305 result = tmp_rect;
311 } else if (string_buffer_.size() == committed_size_) { 306 } else if (string_buffer_.size() == committed_size_) {
312 result = text_input_client_->GetCaretBounds().ToRECT(); 307 result = delegate_->GetCaretBounds();
313 } else { 308 } else {
314 return TS_E_NOLAYOUT; 309 return TS_E_NOLAYOUT;
315 } 310 }
316 } else if (text_input_client_->GetCompositionCharacterBounds(start_pos - 1, 311 } else if (delegate_->GetCompositionCharacterBounds(start_pos - 1,
317 &tmp_rect)) { 312 &tmp_rect)) {
318 result.left = tmp_rect.right(); 313 tmp_rect.left = tmp_rect.right;
319 result.right = tmp_rect.right(); 314 result = tmp_rect;
320 result.top = tmp_rect.y();
321 result.bottom = tmp_rect.bottom();
322 } else { 315 } else {
323 return TS_E_NOLAYOUT; 316 return TS_E_NOLAYOUT;
324 } 317 }
325 } else { 318 } else {
326 if (text_input_client_->GetCompositionCharacterBounds(start_pos, 319 if (delegate_->GetCompositionCharacterBounds(start_pos, &tmp_rect)) {
327 &tmp_rect)) { 320 result = tmp_rect;
328 result.left = tmp_rect.x(); 321 if (delegate_->GetCompositionCharacterBounds(end_pos - 1, &tmp_rect)) {
329 result.top = tmp_rect.y(); 322 result.right = tmp_rect.right;
330 result.right = tmp_rect.right(); 323 result.bottom = tmp_rect.bottom;
331 result.bottom = tmp_rect.bottom();
332 if (text_input_client_->GetCompositionCharacterBounds(end_pos - 1,
333 &tmp_rect)) {
334 result.right = tmp_rect.right();
335 result.bottom = tmp_rect.bottom();
336 } else { 324 } else {
337 // We may not be able to get the last character bounds, so we use the 325 // We may not be able to get the last character bounds, so we use the
338 // first character bounds instead of returning TS_E_NOLAYOUT. 326 // first character bounds instead of returning TS_E_NOLAYOUT.
339 } 327 }
340 } else { 328 } else {
341 // Hack for PPAPI flash. PPAPI flash does not support GetCaretBounds, so 329 // Hack for PPAPI flash. PPAPI flash does not support GetCaretBounds, so
342 // it's better to return previous caret rectangle instead. 330 // it's better to return previous caret rectangle instead.
343 // TODO(nona, kinaba): Remove this hack. 331 // TODO(nona, kinaba): Remove this hack.
344 if (start_pos == 0) { 332 if (start_pos == 0) {
345 result = text_input_client_->GetCaretBounds().ToRECT(); 333 result = delegate_->GetCaretBounds();
346 } else { 334 } else {
347 return TS_E_NOLAYOUT; 335 return TS_E_NOLAYOUT;
348 } 336 }
349 } 337 }
350 } 338 }
351 339
352 *rect = result; 340 *rect = result;
353 *clipped = FALSE; 341 *clipped = FALSE;
354 return S_OK; 342 return S_OK;
355 } 343 }
356 344
357 STDMETHODIMP TSFTextStore::GetWnd(TsViewCookie view_cookie, 345 STDMETHODIMP TextStore::GetWnd(TsViewCookie view_cookie,
358 HWND* window_handle) { 346 HWND* window_handle) {
359 if (!window_handle) 347 if (!window_handle)
360 return E_INVALIDARG; 348 return E_INVALIDARG;
361 if (view_cookie != kViewCookie) 349 if (view_cookie != kViewCookie)
362 return E_INVALIDARG; 350 return E_INVALIDARG;
363 *window_handle = window_handle_; 351 *window_handle = window_handle_;
364 return S_OK; 352 return S_OK;
365 } 353 }
366 354
367 STDMETHODIMP TSFTextStore::InsertEmbedded(DWORD flags, 355 STDMETHODIMP TextStore::InsertEmbedded(DWORD flags,
368 LONG acp_start, 356 LONG acp_start,
369 LONG acp_end, 357 LONG acp_end,
370 IDataObject* data_object, 358 IDataObject* data_object,
371 TS_TEXTCHANGE* change) { 359 TS_TEXTCHANGE* change) {
372 // We don't support any embedded objects. 360 // We don't support any embedded objects.
373 NOTIMPLEMENTED(); 361 NOTIMPLEMENTED();
374 return E_NOTIMPL; 362 return E_NOTIMPL;
375 } 363 }
376 364
377 STDMETHODIMP TSFTextStore::InsertEmbeddedAtSelection(DWORD flags, 365 STDMETHODIMP TextStore::InsertEmbeddedAtSelection(DWORD flags,
378 IDataObject* data_object, 366 IDataObject* data_object,
379 LONG* acp_start, 367 LONG* acp_start,
380 LONG* acp_end, 368 LONG* acp_end,
381 TS_TEXTCHANGE* change) { 369 TS_TEXTCHANGE* change) {
382 // We don't support any embedded objects. 370 // We don't support any embedded objects.
383 NOTIMPLEMENTED(); 371 NOTIMPLEMENTED();
384 return E_NOTIMPL; 372 return E_NOTIMPL;
385 } 373 }
386 374
387 STDMETHODIMP TSFTextStore::InsertTextAtSelection(DWORD flags, 375 STDMETHODIMP TextStore::InsertTextAtSelection(DWORD flags,
388 const wchar_t* text_buffer, 376 const wchar_t* text_buffer,
389 ULONG text_buffer_size, 377 ULONG text_buffer_size,
390 LONG* acp_start, 378 LONG* acp_start,
391 LONG* acp_end, 379 LONG* acp_end,
392 TS_TEXTCHANGE* text_change) { 380 TS_TEXTCHANGE* text_change) {
393 const LONG start_pos = selection_.start(); 381 const LONG start_pos = selection_start_;
394 const LONG end_pos = selection_.end(); 382 const LONG end_pos = selection_end_;
395 const LONG new_end_pos = start_pos + text_buffer_size; 383 const LONG new_end_pos = start_pos + text_buffer_size;
396 384
397 if (flags & TS_IAS_QUERYONLY) { 385 if (flags & TS_IAS_QUERYONLY) {
398 if (!HasReadLock()) 386 if (!HasReadLock())
399 return TS_E_NOLOCK; 387 return TS_E_NOLOCK;
400 if (acp_start) 388 if (acp_start)
401 *acp_start = start_pos; 389 *acp_start = start_pos;
402 if (acp_end) { 390 if (acp_end)
403 *acp_end = end_pos; 391 *acp_end = end_pos;
404 }
405 return S_OK; 392 return S_OK;
406 } 393 }
407 394
408 if (!HasReadWriteLock()) 395 if (!HasReadWriteLock())
409 return TS_E_NOLOCK; 396 return TS_E_NOLOCK;
410 if (!text_buffer) 397 if (!text_buffer)
411 return E_INVALIDARG; 398 return E_INVALIDARG;
412 399
413 DCHECK_LE(start_pos, end_pos); 400 DCHECK_LE(start_pos, end_pos);
414 string_buffer_ = string_buffer_.substr(0, start_pos) + 401 string_buffer_ = string_buffer_.substr(0, start_pos) +
415 string16(text_buffer, text_buffer + text_buffer_size) + 402 string16(text_buffer, text_buffer + text_buffer_size) +
416 string_buffer_.substr(end_pos); 403 string_buffer_.substr(end_pos);
417 if (acp_start) 404 if (acp_start)
418 *acp_start = start_pos; 405 *acp_start = start_pos;
419 if (acp_end) 406 if (acp_end)
420 *acp_end = new_end_pos; 407 *acp_end = new_end_pos;
421 if (text_change) { 408 if (text_change) {
422 text_change->acpStart = start_pos; 409 text_change->acpStart = start_pos;
423 text_change->acpOldEnd = end_pos; 410 text_change->acpOldEnd = end_pos;
424 text_change->acpNewEnd = new_end_pos; 411 text_change->acpNewEnd = new_end_pos;
425 } 412 }
426 selection_.set_start(start_pos); 413 selection_start_ = start_pos;
427 selection_.set_end(new_end_pos); 414 selection_end_ = new_end_pos;
428 return S_OK; 415 return S_OK;
429 } 416 }
430 417
431 STDMETHODIMP TSFTextStore::QueryInsert( 418 STDMETHODIMP TextStore::QueryInsert(
432 LONG acp_test_start, 419 LONG acp_test_start,
433 LONG acp_test_end, 420 LONG acp_test_end,
434 ULONG text_size, 421 ULONG text_size,
435 LONG* acp_result_start, 422 LONG* acp_result_start,
436 LONG* acp_result_end) { 423 LONG* acp_result_end) {
437 if (!acp_result_start || !acp_result_end || acp_test_start > acp_test_end) 424 if (!acp_result_start || !acp_result_end || acp_test_start > acp_test_end)
438 return E_INVALIDARG; 425 return E_INVALIDARG;
439 const LONG committed_size = static_cast<LONG>(committed_size_); 426 const LONG committed_size = static_cast<LONG>(committed_size_);
440 const LONG buffer_size = static_cast<LONG>(string_buffer_.size()); 427 const LONG buffer_size = static_cast<LONG>(string_buffer_.size());
441 *acp_result_start = std::min(std::max(committed_size, acp_test_start), 428 *acp_result_start = std::min(std::max(committed_size, acp_test_start),
442 buffer_size); 429 buffer_size);
443 *acp_result_end = std::min(std::max(committed_size, acp_test_end), 430 *acp_result_end = std::min(std::max(committed_size, acp_test_end),
444 buffer_size); 431 buffer_size);
445 return S_OK; 432 return S_OK;
446 } 433 }
447 434
448 STDMETHODIMP TSFTextStore::QueryInsertEmbedded(const GUID* service, 435 STDMETHODIMP TextStore::QueryInsertEmbedded(const GUID* service,
449 const FORMATETC* format, 436 const FORMATETC* format,
450 BOOL* insertable) { 437 BOOL* insertable) {
451 if (!format) 438 if (!format)
452 return E_INVALIDARG; 439 return E_INVALIDARG;
453 // We don't support any embedded objects. 440 // We don't support any embedded objects.
454 if (insertable) 441 if (insertable)
455 *insertable = FALSE; 442 *insertable = FALSE;
456 return S_OK; 443 return S_OK;
457 } 444 }
458 445
459 STDMETHODIMP TSFTextStore::RequestAttrsAtPosition( 446 STDMETHODIMP TextStore::RequestAttrsAtPosition(
460 LONG acp_pos, 447 LONG acp_pos,
461 ULONG attribute_buffer_size, 448 ULONG attribute_buffer_size,
462 const TS_ATTRID* attribute_buffer, 449 const TS_ATTRID* attribute_buffer,
463 DWORD flags) { 450 DWORD flags) {
464 // We don't support any document attributes. 451 // We don't support any document attributes.
465 // This method just returns S_OK, and the subsequently called 452 // This method just returns S_OK, and the subsequently called
466 // RetrieveRequestedAttrs() returns 0 as the number of supported attributes. 453 // RetrieveRequestedAttrs() returns 0 as the number of supported attributes.
467 return S_OK; 454 return S_OK;
468 } 455 }
469 456
470 STDMETHODIMP TSFTextStore::RequestAttrsTransitioningAtPosition( 457 STDMETHODIMP TextStore::RequestAttrsTransitioningAtPosition(
471 LONG acp_pos, 458 LONG acp_pos,
472 ULONG attribute_buffer_size, 459 ULONG attribute_buffer_size,
473 const TS_ATTRID* attribute_buffer, 460 const TS_ATTRID* attribute_buffer,
474 DWORD flags) { 461 DWORD flags) {
475 // We don't support any document attributes. 462 // We don't support any document attributes.
476 // This method just returns S_OK, and the subsequently called 463 // This method just returns S_OK, and the subsequently called
477 // RetrieveRequestedAttrs() returns 0 as the number of supported attributes. 464 // RetrieveRequestedAttrs() returns 0 as the number of supported attributes.
478 return S_OK; 465 return S_OK;
479 } 466 }
480 467
481 STDMETHODIMP TSFTextStore::RequestLock(DWORD lock_flags, HRESULT* result) { 468 STDMETHODIMP TextStore::RequestLock(DWORD lock_flags, HRESULT* result) {
482 if (!text_store_acp_sink_.get()) 469 if (!text_store_acp_sink_.get())
483 return E_FAIL; 470 return E_FAIL;
484 if (!result) 471 if (!result)
485 return E_INVALIDARG; 472 return E_INVALIDARG;
486 473
487 if (current_lock_type_ != 0) { 474 if (current_lock_type_ != 0) {
488 if (lock_flags & TS_LF_SYNC) { 475 if (lock_flags & TS_LF_SYNC) {
489 // Can't lock synchronously. 476 // Can't lock synchronously.
490 *result = TS_E_SYNCHRONOUS; 477 *result = TS_E_SYNCHRONOUS;
491 return S_OK; 478 return S_OK;
(...skipping 17 matching lines...) Expand all
509 current_lock_type_ = 0; 496 current_lock_type_ = 0;
510 497
511 // Handles the pending lock requests. 498 // Handles the pending lock requests.
512 while (!lock_queue_.empty()) { 499 while (!lock_queue_.empty()) {
513 current_lock_type_ = lock_queue_.front(); 500 current_lock_type_ = lock_queue_.front();
514 lock_queue_.pop_front(); 501 lock_queue_.pop_front();
515 text_store_acp_sink_->OnLockGranted(current_lock_type_); 502 text_store_acp_sink_->OnLockGranted(current_lock_type_);
516 current_lock_type_ = 0; 503 current_lock_type_ = 0;
517 } 504 }
518 505
519 if (!edit_flag_) { 506 if (!edit_flag_)
520 return S_OK; 507 return S_OK;
521 }
522 508
523 // If the text store is edited in OnLockGranted(), we may need to call 509 // If the text store is edited in OnLockGranted(), we may need to call
524 // TextInputClient::InsertText() or TextInputClient::SetCompositionText(). 510 // TextStoreDelegate::ConfirmComposition() or
511 // TextStoreDelegate::SetComposition().
525 const size_t new_committed_size = committed_size_; 512 const size_t new_committed_size = committed_size_;
526 const string16& new_committed_string = 513 const string16& new_committed_string =
527 string_buffer_.substr(last_committed_size, 514 string_buffer_.substr(last_committed_size,
528 new_committed_size - last_committed_size); 515 new_committed_size - last_committed_size);
529 const string16& composition_string = 516 const string16& composition_string =
530 string_buffer_.substr(new_committed_size); 517 string_buffer_.substr(new_committed_size);
531 518
532 // If there is new committed string, calls TextInputClient::InsertText(). 519 if (delegate_) {
533 if ((!new_committed_string.empty()) && text_input_client_) { 520 // If there is new committed string, calls
534 text_input_client_->InsertText(new_committed_string); 521 // TextStoreDelegate::ConfirmComposition().
522 if ((!new_committed_string.empty()))
523 delegate_->OnTextCommitted(new_committed_string);
524
525 // Calls TextInputClient::SetCompositionText().
526 std::vector<metro_viewer::UnderlineInfo> underlines = underlines_;
527 // Adjusts the offset.
528 for (size_t i = 0; i < underlines_.size(); ++i) {
529 underlines[i].start_offset -= new_committed_size;
530 underlines[i].end_offset -= new_committed_size;
531 }
532 int32 selection_start = 0;
533 int32 selection_end = 0;
534 if (selection_start_ >= new_committed_size)
535 selection_start = selection_start_ - new_committed_size;
536 if (selection_end_ >= new_committed_size)
537 selection_end = selection_end_ - new_committed_size;
538 delegate_->OnCompositionChanged(
539 composition_string, selection_start, selection_end, underlines);
535 } 540 }
536 541
537 // Calls TextInputClient::SetCompositionText().
538 CompositionText composition_text;
539 composition_text.text = composition_string;
540 composition_text.underlines = composition_undelines_;
541 // Adjusts the offset.
542 for (size_t i = 0; i < composition_text.underlines.size(); ++i) {
543 composition_text.underlines[i].start_offset -= new_committed_size;
544 composition_text.underlines[i].end_offset -= new_committed_size;
545 }
546 if (selection_.start() < new_committed_size) {
547 composition_text.selection.set_start(0);
548 } else {
549 composition_text.selection.set_start(
550 selection_.start() - new_committed_size);
551 }
552 if (selection_.end() < new_committed_size) {
553 composition_text.selection.set_end(0);
554 } else {
555 composition_text.selection.set_end(selection_.end() - new_committed_size);
556 }
557 if (text_input_client_)
558 text_input_client_->SetCompositionText(composition_text);
559
560 // If there is no composition string, clear the text store status. 542 // If there is no composition string, clear the text store status.
561 // And call OnSelectionChange(), OnLayoutChange(), and OnTextChange(). 543 // And call OnSelectionChange(), OnLayoutChange(), and OnTextChange().
562 if ((composition_string.empty()) && (new_committed_size != 0)) { 544 if ((composition_string.empty()) && (new_committed_size != 0)) {
563 string_buffer_.clear(); 545 string_buffer_.clear();
564 committed_size_ = 0; 546 committed_size_ = 0;
565 selection_.set_start(0); 547 selection_start_ = 0;
566 selection_.set_end(0); 548 selection_end_ = 0;
567 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE) 549 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE)
568 text_store_acp_sink_->OnSelectionChange(); 550 text_store_acp_sink_->OnSelectionChange();
569 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE) 551 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)
570 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); 552 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
571 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) { 553 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) {
572 TS_TEXTCHANGE textChange; 554 TS_TEXTCHANGE textChange = {};
573 textChange.acpStart = 0; 555 textChange.acpStart = 0;
574 textChange.acpOldEnd = new_committed_size; 556 textChange.acpOldEnd = new_committed_size;
575 textChange.acpNewEnd = 0; 557 textChange.acpNewEnd = 0;
576 text_store_acp_sink_->OnTextChange(0, &textChange); 558 text_store_acp_sink_->OnTextChange(0, &textChange);
577 } 559 }
578 } 560 }
579 561
580 return S_OK; 562 return S_OK;
581 } 563 }
582 564
583 STDMETHODIMP TSFTextStore::RequestSupportedAttrs( 565 STDMETHODIMP TextStore::RequestSupportedAttrs(
584 DWORD /* flags */, // Seems that we should ignore this. 566 DWORD /* flags */, // Seems that we should ignore this.
585 ULONG attribute_buffer_size, 567 ULONG attribute_buffer_size,
586 const TS_ATTRID* attribute_buffer) { 568 const TS_ATTRID* attribute_buffer) {
587 if (!attribute_buffer) 569 if (!attribute_buffer)
588 return E_INVALIDARG; 570 return E_INVALIDARG;
589 if (!text_input_client_) 571 if (!input_scope_)
590 return E_FAIL; 572 return E_FAIL;
591 // We support only input scope attribute. 573 // We support only input scope attribute.
592 for (size_t i = 0; i < attribute_buffer_size; ++i) { 574 for (size_t i = 0; i < attribute_buffer_size; ++i) {
593 if (IsEqualGUID(GUID_PROP_INPUTSCOPE, attribute_buffer[i])) 575 if (IsEqualGUID(GUID_PROP_INPUTSCOPE, attribute_buffer[i]))
594 return S_OK; 576 return S_OK;
595 } 577 }
596 return E_FAIL; 578 return E_FAIL;
597 } 579 }
598 580
599 STDMETHODIMP TSFTextStore::RetrieveRequestedAttrs( 581 STDMETHODIMP TextStore::RetrieveRequestedAttrs(
600 ULONG attribute_buffer_size, 582 ULONG attribute_buffer_size,
601 TS_ATTRVAL* attribute_buffer, 583 TS_ATTRVAL* attribute_buffer,
602 ULONG* attribute_buffer_copied) { 584 ULONG* attribute_buffer_copied) {
603 if (!attribute_buffer_copied) 585 if (!attribute_buffer_copied)
604 return E_INVALIDARG; 586 return E_INVALIDARG;
587 *attribute_buffer_copied = 0;
605 if (!attribute_buffer) 588 if (!attribute_buffer)
606 return E_INVALIDARG; 589 return E_INVALIDARG;
607 if (!text_input_client_) 590 if (!input_scope_)
608 return E_UNEXPECTED; 591 return E_FAIL;
609 // We support only input scope attribute. 592 // We support only input scope attribute.
610 *attribute_buffer_copied = 0;
611 if (attribute_buffer_size == 0) 593 if (attribute_buffer_size == 0)
612 return S_OK; 594 return S_OK;
613 595
614 attribute_buffer[0].dwOverlapId = 0; 596 attribute_buffer[0].dwOverlapId = 0;
615 attribute_buffer[0].idAttr = GUID_PROP_INPUTSCOPE; 597 attribute_buffer[0].idAttr = GUID_PROP_INPUTSCOPE;
616 attribute_buffer[0].varValue.vt = VT_UNKNOWN; 598 attribute_buffer[0].varValue.vt = VT_UNKNOWN;
617 attribute_buffer[0].varValue.punkVal = tsf_inputscope::CreateInputScope( 599 attribute_buffer[0].varValue.punkVal = input_scope_;
618 text_input_client_->GetTextInputType(),
619 text_input_client_->GetTextInputMode());
620 attribute_buffer[0].varValue.punkVal->AddRef(); 600 attribute_buffer[0].varValue.punkVal->AddRef();
621 *attribute_buffer_copied = 1; 601 *attribute_buffer_copied = 1;
602
622 return S_OK; 603 return S_OK;
623 } 604 }
624 605
625 STDMETHODIMP TSFTextStore::SetSelection( 606 STDMETHODIMP TextStore::SetSelection(
626 ULONG selection_buffer_size, 607 ULONG selection_buffer_size,
627 const TS_SELECTION_ACP* selection_buffer) { 608 const TS_SELECTION_ACP* selection_buffer) {
628 if (!HasReadWriteLock()) 609 if (!HasReadWriteLock())
629 return TF_E_NOLOCK; 610 return TF_E_NOLOCK;
630 if (selection_buffer_size > 0) { 611 if (selection_buffer_size > 0) {
631 const LONG start_pos = selection_buffer[0].acpStart; 612 const LONG start_pos = selection_buffer[0].acpStart;
632 const LONG end_pos = selection_buffer[0].acpEnd; 613 const LONG end_pos = selection_buffer[0].acpEnd;
633 if (!((static_cast<LONG>(committed_size_) <= start_pos) && 614 if (!((static_cast<LONG>(committed_size_) <= start_pos) &&
634 (start_pos <= end_pos) && 615 (start_pos <= end_pos) &&
635 (end_pos <= static_cast<LONG>(string_buffer_.size())))) { 616 (end_pos <= static_cast<LONG>(string_buffer_.size())))) {
636 return TF_E_INVALIDPOS; 617 return TF_E_INVALIDPOS;
637 } 618 }
638 selection_.set_start(start_pos); 619 selection_start_ = start_pos;
639 selection_.set_end(end_pos); 620 selection_end_ = end_pos;
640 } 621 }
641 return S_OK; 622 return S_OK;
642 } 623 }
643 624
644 STDMETHODIMP TSFTextStore::SetText(DWORD flags, 625 STDMETHODIMP TextStore::SetText(DWORD flags,
645 LONG acp_start, 626 LONG acp_start,
646 LONG acp_end, 627 LONG acp_end,
647 const wchar_t* text_buffer, 628 const wchar_t* text_buffer,
648 ULONG text_buffer_size, 629 ULONG text_buffer_size,
649 TS_TEXTCHANGE* text_change) { 630 TS_TEXTCHANGE* text_change) {
650 if (!HasReadWriteLock()) 631 if (!HasReadWriteLock())
651 return TS_E_NOLOCK; 632 return TS_E_NOLOCK;
652 if (!((static_cast<LONG>(committed_size_) <= acp_start) && 633 if (!((static_cast<LONG>(committed_size_) <= acp_start) &&
653 (acp_start <= acp_end) && 634 (acp_start <= acp_end) &&
654 (acp_end <= static_cast<LONG>(string_buffer_.size())))) { 635 (acp_end <= static_cast<LONG>(string_buffer_.size())))) {
655 return TS_E_INVALIDPOS; 636 return TS_E_INVALIDPOS;
656 } 637 }
657 638
658 TS_SELECTION_ACP selection; 639 TS_SELECTION_ACP selection = {};
659 selection.acpStart = acp_start; 640 selection.acpStart = acp_start;
660 selection.acpEnd = acp_end; 641 selection.acpEnd = acp_end;
661 selection.style.ase = TS_AE_NONE; 642 selection.style.ase = TS_AE_NONE;
662 selection.style.fInterimChar = 0; 643 selection.style.fInterimChar = 0;
663 644
664 HRESULT ret; 645 HRESULT ret = SetSelection(1, &selection);
665 ret = SetSelection(1, &selection);
666 if (ret != S_OK) 646 if (ret != S_OK)
667 return ret; 647 return ret;
668 648
669 TS_TEXTCHANGE change; 649 TS_TEXTCHANGE change;
670 ret = InsertTextAtSelection(0, text_buffer, text_buffer_size, 650 ret = InsertTextAtSelection(
671 &acp_start, &acp_end, &change); 651 0, text_buffer, text_buffer_size, &acp_start, &acp_end, &change);
672 if (ret != S_OK) 652 if (ret != S_OK)
673 return ret; 653 return ret;
674 654
675 if (text_change) 655 if (text_change)
676 *text_change = change; 656 *text_change = change;
677 657
678 return S_OK; 658 return S_OK;
679 } 659 }
680 660
681 STDMETHODIMP TSFTextStore::UnadviseSink(IUnknown* unknown) { 661 STDMETHODIMP TextStore::UnadviseSink(IUnknown* unknown) {
682 if (!text_store_acp_sink_.IsSameObject(unknown)) 662 if (!text_store_acp_sink_.IsSameObject(unknown))
683 return CONNECT_E_NOCONNECTION; 663 return CONNECT_E_NOCONNECTION;
684 text_store_acp_sink_.Release(); 664 text_store_acp_sink_.Release();
685 text_store_acp_sink_mask_ = 0; 665 text_store_acp_sink_mask_ = 0;
686 return S_OK; 666 return S_OK;
687 } 667 }
688 668
689 STDMETHODIMP TSFTextStore::OnStartComposition( 669 STDMETHODIMP TextStore::OnStartComposition(
690 ITfCompositionView* composition_view, 670 ITfCompositionView* composition_view,
691 BOOL* ok) { 671 BOOL* ok) {
692 if (ok) 672 if (ok)
693 *ok = TRUE; 673 *ok = TRUE;
694 return S_OK; 674 return S_OK;
695 } 675 }
696 676
697 STDMETHODIMP TSFTextStore::OnUpdateComposition( 677 STDMETHODIMP TextStore::OnUpdateComposition(
698 ITfCompositionView* composition_view, 678 ITfCompositionView* composition_view,
699 ITfRange* range) { 679 ITfRange* range) {
700 return S_OK; 680 return S_OK;
701 } 681 }
702 682
703 STDMETHODIMP TSFTextStore::OnEndComposition( 683 STDMETHODIMP TextStore::OnEndComposition(
704 ITfCompositionView* composition_view) { 684 ITfCompositionView* composition_view) {
705 return S_OK; 685 return S_OK;
706 } 686 }
707 687
708 STDMETHODIMP TSFTextStore::OnEndEdit(ITfContext* context, 688 STDMETHODIMP TextStore::OnEndEdit(ITfContext* context,
709 TfEditCookie read_only_edit_cookie, 689 TfEditCookie read_only_edit_cookie,
710 ITfEditRecord* edit_record) { 690 ITfEditRecord* edit_record) {
711 if (!context || !edit_record) 691 if (!context || !edit_record)
712 return E_INVALIDARG; 692 return E_INVALIDARG;
713 693 if (!GetCompositionStatus(context, read_only_edit_cookie, &committed_size_,
714 size_t committed_size; 694 &underlines_)) {
715 CompositionUnderlines undelines; 695 // TODO(yukawa): Error handling.
716 if (!GetCompositionStatus(context, read_only_edit_cookie, &committed_size,
717 &undelines)) {
718 return S_OK; 696 return S_OK;
719 } 697 }
720 composition_undelines_ = undelines;
721 committed_size_ = committed_size;
722 edit_flag_ = true; 698 edit_flag_ = true;
723 return S_OK; 699 return S_OK;
724 } 700 }
725 701
726 bool TSFTextStore::GetDisplayAttribute(TfGuidAtom guid_atom, 702 bool TextStore::GetDisplayAttribute(TfGuidAtom guid_atom,
727 TF_DISPLAYATTRIBUTE* attribute) { 703 TF_DISPLAYATTRIBUTE* attribute) {
728 GUID guid; 704 GUID guid;
729 if (FAILED(category_manager_->GetGUID(guid_atom, &guid))) 705 if (FAILED(category_manager_->GetGUID(guid_atom, &guid)))
730 return false; 706 return false;
731 707
732 base::win::ScopedComPtr<ITfDisplayAttributeInfo> display_attribute_info; 708 base::win::ScopedComPtr<ITfDisplayAttributeInfo> display_attribute_info;
733 if (FAILED(display_attribute_manager_->GetDisplayAttributeInfo( 709 if (FAILED(display_attribute_manager_->GetDisplayAttributeInfo(
734 guid, display_attribute_info.Receive(), NULL))) { 710 guid, display_attribute_info.Receive(), NULL))) {
735 return false; 711 return false;
736 } 712 }
737 return SUCCEEDED(display_attribute_info->GetAttributeInfo(attribute)); 713 return SUCCEEDED(display_attribute_info->GetAttributeInfo(attribute));
738 } 714 }
739 715
740 bool TSFTextStore::GetCompositionStatus( 716 bool TextStore::GetCompositionStatus(
741 ITfContext* context, 717 ITfContext* context,
742 const TfEditCookie read_only_edit_cookie, 718 const TfEditCookie read_only_edit_cookie,
743 size_t* committed_size, 719 size_t* committed_size,
744 CompositionUnderlines* undelines) { 720 std::vector<metro_viewer::UnderlineInfo>* undelines) {
745 DCHECK(context); 721 DCHECK(context);
746 DCHECK(committed_size); 722 DCHECK(committed_size);
747 DCHECK(undelines); 723 DCHECK(undelines);
748 const GUID* rgGuids[2] = {&GUID_PROP_COMPOSING, &GUID_PROP_ATTRIBUTE}; 724 const GUID* kTargetGuids[2] = {&GUID_PROP_COMPOSING, &GUID_PROP_ATTRIBUTE};
749 base::win::ScopedComPtr<ITfReadOnlyProperty> track_property; 725 base::win::ScopedComPtr<ITfReadOnlyProperty> track_property;
750 if (FAILED(context->TrackProperties(rgGuids, 2, NULL, 0, 726 if (FAILED(context->TrackProperties(kTargetGuids, 2, NULL, 0,
751 track_property.Receive()))) { 727 track_property.Receive()))) {
752 return false; 728 return false;
753 } 729 }
754 730
755 *committed_size = 0; 731 *committed_size = 0;
756 undelines->clear(); 732 undelines->clear();
757 base::win::ScopedComPtr<ITfRange> start_to_end_range; 733 base::win::ScopedComPtr<ITfRange> start_to_end_range;
758 base::win::ScopedComPtr<ITfRange> end_range; 734 base::win::ScopedComPtr<ITfRange> end_range;
759 if (FAILED(context->GetStart(read_only_edit_cookie, 735 if (FAILED(context->GetStart(read_only_edit_cookie,
760 start_to_end_range.Receive()))) { 736 start_to_end_range.Receive()))) {
(...skipping 18 matching lines...) Expand all
779 break; 755 break;
780 base::win::ScopedVariant value; 756 base::win::ScopedVariant value;
781 base::win::ScopedComPtr<IEnumTfPropertyValue> enum_prop_value; 757 base::win::ScopedComPtr<IEnumTfPropertyValue> enum_prop_value;
782 if (FAILED(track_property->GetValue(read_only_edit_cookie, range, 758 if (FAILED(track_property->GetValue(read_only_edit_cookie, range,
783 value.Receive()))) { 759 value.Receive()))) {
784 return false; 760 return false;
785 } 761 }
786 if (FAILED(enum_prop_value.QueryFrom(value.AsInput()->punkVal))) 762 if (FAILED(enum_prop_value.QueryFrom(value.AsInput()->punkVal)))
787 return false; 763 return false;
788 764
789 TF_PROPERTYVAL property_value; 765 TF_PROPERTYVAL property_value = {};
790 bool is_composition = false; 766 bool is_composition = false;
791 bool has_display_attribute = false; 767 bool has_display_attribute = false;
792 TF_DISPLAYATTRIBUTE display_attribute; 768 TF_DISPLAYATTRIBUTE display_attribute;
793 while (enum_prop_value->Next(1, &property_value, NULL) == S_OK) { 769 while (enum_prop_value->Next(1, &property_value, NULL) == S_OK) {
794 if (IsEqualGUID(property_value.guidId, GUID_PROP_COMPOSING)) { 770 if (IsEqualGUID(property_value.guidId, GUID_PROP_COMPOSING)) {
795 is_composition = (property_value.varValue.lVal == TRUE); 771 is_composition = (property_value.varValue.lVal == TRUE);
796 } else if (IsEqualGUID(property_value.guidId, GUID_PROP_ATTRIBUTE)) { 772 } else if (IsEqualGUID(property_value.guidId, GUID_PROP_ATTRIBUTE)) {
797 TfGuidAtom guid_atom = 773 TfGuidAtom guid_atom =
798 static_cast<TfGuidAtom>(property_value.varValue.lVal); 774 static_cast<TfGuidAtom>(property_value.varValue.lVal);
799 if (GetDisplayAttribute(guid_atom, &display_attribute)) 775 if (GetDisplayAttribute(guid_atom, &display_attribute))
800 has_display_attribute = true; 776 has_display_attribute = true;
801 } 777 }
802 VariantClear(&property_value.varValue); 778 VariantClear(&property_value.varValue);
803 } 779 }
804 780
805 base::win::ScopedComPtr<ITfRangeACP> range_acp; 781 base::win::ScopedComPtr<ITfRangeACP> range_acp;
806 range_acp.QueryFrom(range); 782 range_acp.QueryFrom(range);
807 LONG start_pos, length; 783 LONG start_pos, length;
808 range_acp->GetExtent(&start_pos, &length); 784 range_acp->GetExtent(&start_pos, &length);
809 if (!is_composition) { 785 if (!is_composition) {
810 if (*committed_size < static_cast<size_t>(start_pos + length)) 786 if (*committed_size < static_cast<size_t>(start_pos + length))
811 *committed_size = start_pos + length; 787 *committed_size = start_pos + length;
812 } else { 788 } else {
813 CompositionUnderline underline; 789 metro_viewer::UnderlineInfo underline;
814 underline.start_offset = start_pos; 790 underline.start_offset = start_pos;
815 underline.end_offset = start_pos + length; 791 underline.end_offset = start_pos + length;
816 underline.color = SK_ColorBLACK; 792 underline.thick = !!display_attribute.fBoldLine;
817 if (has_display_attribute)
818 underline.thick = !!display_attribute.fBoldLine;
819 undelines->push_back(underline); 793 undelines->push_back(underline);
820 } 794 }
821 } 795 }
822 return true; 796 return true;
823 } 797 }
824 798
825 void TSFTextStore::SetFocusedTextInputClient( 799 bool TextStore::CancelComposition() {
826 HWND focused_window,
827 TextInputClient* text_input_client) {
828 window_handle_ = focused_window;
829 text_input_client_ = text_input_client;
830 }
831
832 void TSFTextStore::RemoveFocusedTextInputClient(
833 TextInputClient* text_input_client) {
834 if (text_input_client_ == text_input_client) {
835 window_handle_ = NULL;
836 text_input_client_ = NULL;
837 }
838 }
839
840 bool TSFTextStore::CancelComposition() {
841 // If there is an on-going document lock, we must not edit the text. 800 // If there is an on-going document lock, we must not edit the text.
842 if (edit_flag_) 801 if (edit_flag_)
843 return false; 802 return false;
844 803
845 if (string_buffer_.empty()) 804 if (string_buffer_.empty())
846 return true; 805 return true;
847 806
848 // Unlike ImmNotifyIME(NI_COMPOSITIONSTR, CPS_CANCEL, 0) in IMM32, TSF does 807 // Unlike ImmNotifyIME(NI_COMPOSITIONSTR, CPS_CANCEL, 0) in IMM32, TSF does
849 // not have a dedicated method to cancel composition. However, CUAS actually 808 // not have a dedicated method to cancel composition. However, CUAS actually
850 // has a protocol conversion from CPS_CANCEL into TSF operations. According 809 // has a protocol conversion from CPS_CANCEL into TSF operations. According
851 // to the observations on Windows 7, TIPs are expected to cancel composition 810 // to the observations on Windows 7, TIPs are expected to cancel composition
852 // when an on-going composition text is replaced with an empty string. So 811 // when an on-going composition text is replaced with an empty string. So
853 // we use the same operation to cancel composition here to minimize the risk 812 // we use the same operation to cancel composition here to minimize the risk
854 // of potential compatibility issues. 813 // of potential compatibility issues.
855 814
856 const size_t previous_buffer_size = string_buffer_.size(); 815 const size_t previous_buffer_size = string_buffer_.size();
857 string_buffer_.clear(); 816 string_buffer_.clear();
858 committed_size_ = 0; 817 committed_size_ = 0;
859 selection_.set_start(0); 818 selection_start_ = 0;
860 selection_.set_end(0); 819 selection_end_ = 0;
861 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE) 820 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE)
862 text_store_acp_sink_->OnSelectionChange(); 821 text_store_acp_sink_->OnSelectionChange();
863 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE) 822 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)
864 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); 823 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
865 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) { 824 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) {
866 TS_TEXTCHANGE textChange = {}; 825 TS_TEXTCHANGE textChange = {};
867 textChange.acpStart = 0; 826 textChange.acpStart = 0;
868 textChange.acpOldEnd = previous_buffer_size; 827 textChange.acpOldEnd = previous_buffer_size;
869 textChange.acpNewEnd = 0; 828 textChange.acpNewEnd = 0;
870 text_store_acp_sink_->OnTextChange(0, &textChange); 829 text_store_acp_sink_->OnTextChange(0, &textChange);
871 } 830 }
872 return true; 831 return true;
873 } 832 }
874 833
875 bool TSFTextStore::ConfirmComposition() { 834 bool TextStore::ConfirmComposition() {
876 // If there is an on-going document lock, we must not edit the text. 835 // If there is an on-going document lock, we must not edit the text.
877 if (edit_flag_) 836 if (edit_flag_)
878 return false; 837 return false;
879 838
880 if (string_buffer_.empty()) 839 if (string_buffer_.empty())
881 return true; 840 return true;
882 841
883 // See the comment in TSFTextStore::CancelComposition. 842 // See the comment in TextStore::CancelComposition.
884 // This logic is based on the observation about how to emulate 843 // This logic is based on the observation about how to emulate
885 // ImmNotifyIME(NI_COMPOSITIONSTR, CPS_COMPLETE, 0) by CUAS. 844 // ImmNotifyIME(NI_COMPOSITIONSTR, CPS_COMPLETE, 0) by CUAS.
886 845
887 const string16& composition_text = string_buffer_.substr(committed_size_); 846 const string16& composition_text = string_buffer_.substr(committed_size_);
888 if (!composition_text.empty()) 847 if (!composition_text.empty())
889 text_input_client_->InsertText(composition_text); 848 delegate_->OnTextCommitted(composition_text);
890 849
891 const size_t previous_buffer_size = string_buffer_.size(); 850 const size_t previous_buffer_size = string_buffer_.size();
892 string_buffer_.clear(); 851 string_buffer_.clear();
893 committed_size_ = 0; 852 committed_size_ = 0;
894 selection_.set_start(0); 853 selection_start_ = 0;
895 selection_.set_end(0); 854 selection_end_ = 0;
896 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE) 855 if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE)
897 text_store_acp_sink_->OnSelectionChange(); 856 text_store_acp_sink_->OnSelectionChange();
898 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE) 857 if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)
899 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); 858 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
900 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) { 859 if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) {
901 TS_TEXTCHANGE textChange = {}; 860 TS_TEXTCHANGE textChange = {};
902 textChange.acpStart = 0; 861 textChange.acpStart = 0;
903 textChange.acpOldEnd = previous_buffer_size; 862 textChange.acpOldEnd = previous_buffer_size;
904 textChange.acpNewEnd = 0; 863 textChange.acpNewEnd = 0;
905 text_store_acp_sink_->OnTextChange(0, &textChange); 864 text_store_acp_sink_->OnTextChange(0, &textChange);
906 } 865 }
907 return true; 866 return true;
908 } 867 }
909 868
910 void TSFTextStore::SendOnLayoutChange() { 869 void TextStore::SendOnLayoutChange() {
911 if (text_store_acp_sink_ && (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)) 870 if (text_store_acp_sink_ && (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE))
912 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); 871 text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
913 } 872 }
914 873
915 bool TSFTextStore::HasReadLock() const { 874 bool TextStore::HasReadLock() const {
916 return (current_lock_type_ & TS_LF_READ) == TS_LF_READ; 875 return (current_lock_type_ & TS_LF_READ) == TS_LF_READ;
917 } 876 }
918 877
919 bool TSFTextStore::HasReadWriteLock() const { 878 bool TextStore::HasReadWriteLock() const {
920 return (current_lock_type_ & TS_LF_READWRITE) == TS_LF_READWRITE; 879 return (current_lock_type_ & TS_LF_READWRITE) == TS_LF_READWRITE;
921 } 880 }
922 881
923 } // namespace ui 882 } // namespace metro_driver
OLDNEW
« no previous file with comments | « win8/metro_driver/ime/text_store.h ('k') | win8/metro_driver/ime/text_store_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698