|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 |
|
7 /* This tests Mozilla's Text Services Framework implementation (bug #88831) |
|
8 * |
|
9 * The Mozilla implementation interacts with the TSF system through a |
|
10 * system-provided COM interface, ITfThreadMgr. This tests works by swapping |
|
11 * the system version of the interface with a custom version implemented in |
|
12 * here. This way the Mozilla implementation thinks it's interacting with the |
|
13 * system but in fact is interacting with this test program. This allows the |
|
14 * test program to access and test every aspect of the Mozilla implementation. |
|
15 */ |
|
16 |
|
17 #include <ole2.h> |
|
18 #include <msctf.h> |
|
19 #include <textstor.h> |
|
20 #include <richedit.h> |
|
21 |
|
22 #include "TestHarness.h" |
|
23 #include <algorithm> |
|
24 |
|
25 #define WM_USER_TSF_TEXTCHANGE (WM_USER + 0x100) |
|
26 |
|
27 #ifndef MOZILLA_INTERNAL_API |
|
28 // some of the includes make use of internal string types |
|
29 #define nsAString_h___ |
|
30 #define nsString_h___ |
|
31 #define nsStringFwd_h___ |
|
32 #define nsReadableUtils_h___ |
|
33 class nsACString; |
|
34 class nsAString; |
|
35 class nsAFlatString; |
|
36 class nsAFlatCString; |
|
37 class nsAdoptingString; |
|
38 class nsAdoptingCString; |
|
39 class nsXPIDLString; |
|
40 template<class T> class nsReadingIterator; |
|
41 #endif |
|
42 |
|
43 #include "nscore.h" |
|
44 #include "nsWeakReference.h" |
|
45 #include "nsIAppShell.h" |
|
46 #include "nsWidgetsCID.h" |
|
47 #include "nsIAppShellService.h" |
|
48 #include "nsAppShellCID.h" |
|
49 #include "nsNetUtil.h" |
|
50 #include "nsIWebBrowserChrome.h" |
|
51 #include "nsIXULWindow.h" |
|
52 #include "nsIBaseWindow.h" |
|
53 #include "nsIDOMWindow.h" |
|
54 #include "nsIDocShell.h" |
|
55 #include "nsIWidget.h" |
|
56 #include "nsIPresShell.h" |
|
57 #include "nsPresContext.h" |
|
58 #include "nsIFrame.h" |
|
59 #include "nsIWebProgress.h" |
|
60 #include "nsIWebProgressListener.h" |
|
61 #include "nsIInterfaceRequestorUtils.h" |
|
62 #include "nsIDOMHTMLDocument.h" |
|
63 #include "mozilla/dom/HTMLBodyElement.h" |
|
64 #include "nsIDOMHTMLElement.h" |
|
65 #include "nsIDOMHTMLInputElement.h" |
|
66 #include "nsIDOMHTMLTextAreaElement.h" |
|
67 #include "nsIDOMElement.h" |
|
68 #include "nsISelectionController.h" |
|
69 #include "nsViewManager.h" |
|
70 #include "nsTArray.h" |
|
71 |
|
72 #ifndef MOZILLA_INTERNAL_API |
|
73 #undef nsString_h___ |
|
74 #undef nsAString_h___ |
|
75 #undef nsReadableUtils_h___ |
|
76 #endif |
|
77 |
|
78 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); |
|
79 |
|
80 class TSFMgrImpl; |
|
81 class TSFDocumentMgrImpl; |
|
82 class TSFContextImpl; |
|
83 class TSFRangeImpl; |
|
84 class TSFEnumRangeImpl; |
|
85 class TSFAttrPropImpl; |
|
86 |
|
87 class TestApp : public nsIWebProgressListener, public nsSupportsWeakReference |
|
88 { |
|
89 public: |
|
90 NS_DECL_ISUPPORTS |
|
91 NS_DECL_NSIWEBPROGRESSLISTENER |
|
92 |
|
93 TestApp() : mFailed(false) {} |
|
94 ~TestApp() {} |
|
95 |
|
96 nsresult Run(void); |
|
97 bool CheckFailed(void); |
|
98 |
|
99 typedef bool (TestApp::*test_type)(void); |
|
100 |
|
101 protected: |
|
102 nsresult Init(void); |
|
103 nsresult Term(void); |
|
104 bool RunTest(test_type aTest, bool aLock = true); |
|
105 |
|
106 bool TestFocus(void); |
|
107 bool TestClustering(void); |
|
108 bool TestSelection(void); |
|
109 bool TestText(void); |
|
110 bool TestExtents(void); |
|
111 bool TestComposition(void); |
|
112 bool TestNotification(void); |
|
113 bool TestEditMessages(void); |
|
114 bool TestScrollMessages(void); |
|
115 |
|
116 bool TestSelectionInternal(char* aTestName, |
|
117 LONG aStart, |
|
118 LONG aEnd, |
|
119 TsActiveSelEnd aSelEnd); |
|
120 bool TestCompositionSelectionAndText(char* aTestName, |
|
121 LONG aExpectedSelStart, |
|
122 LONG aExpectedSelEnd, |
|
123 nsString& aReferenceString); |
|
124 bool TestNotificationTextChange(nsIWidget* aWidget, |
|
125 uint32_t aCode, |
|
126 const nsAString& aCharacter, |
|
127 LONG aStart, |
|
128 LONG aOldEnd, |
|
129 LONG aNewEnd); |
|
130 nsresult GetSelCon(nsISelectionController** aSelCon); |
|
131 |
|
132 bool GetWidget(nsIWidget** aWidget); |
|
133 |
|
134 bool mFailed; |
|
135 nsString mTestString; |
|
136 nsRefPtr<TSFMgrImpl> mMgr; |
|
137 nsCOMPtr<nsIAppShell> mAppShell; |
|
138 nsCOMPtr<nsIXULWindow> mWindow; |
|
139 nsCOMPtr<nsIDOMNode> mCurrentNode; |
|
140 nsCOMPtr<nsIDOMHTMLInputElement> mInput; |
|
141 nsCOMPtr<nsIDOMHTMLTextAreaElement> mTextArea; |
|
142 nsCOMPtr<nsIDOMHTMLInputElement> mButton; |
|
143 }; |
|
144 |
|
145 NS_IMETHODIMP |
|
146 TestApp::OnProgressChange(nsIWebProgress *aWebProgress, |
|
147 nsIRequest *aRequest, |
|
148 int32_t aCurSelfProgress, |
|
149 int32_t aMaxSelfProgress, |
|
150 int32_t aCurTotalProgress, |
|
151 int32_t aMaxTotalProgress) |
|
152 { |
|
153 return NS_OK; |
|
154 } |
|
155 |
|
156 NS_IMETHODIMP |
|
157 TestApp::OnLocationChange(nsIWebProgress *aWebProgress, |
|
158 nsIRequest *aRequest, |
|
159 nsIURI *aLocation, |
|
160 uint32_t aFlags) |
|
161 { |
|
162 return NS_OK; |
|
163 } |
|
164 |
|
165 NS_IMETHODIMP |
|
166 TestApp::OnStatusChange(nsIWebProgress *aWebProgress, |
|
167 nsIRequest *aRequest, |
|
168 nsresult aStatus, |
|
169 const char16_t *aMessage) |
|
170 { |
|
171 return NS_OK; |
|
172 } |
|
173 |
|
174 NS_IMETHODIMP |
|
175 TestApp::OnSecurityChange(nsIWebProgress *aWebProgress, |
|
176 nsIRequest *aRequest, |
|
177 uint32_t aState) |
|
178 { |
|
179 return NS_OK; |
|
180 } |
|
181 |
|
182 static HRESULT |
|
183 GetRegularExtent(ITfRange *aRange, LONG &aStart, LONG &aEnd) |
|
184 { |
|
185 NS_ENSURE_TRUE(aRange, E_INVALIDARG); |
|
186 nsRefPtr<ITfRangeACP> rangeACP; |
|
187 HRESULT hr = aRange->QueryInterface(IID_ITfRangeACP, |
|
188 getter_AddRefs(rangeACP)); |
|
189 NS_ENSURE_TRUE(SUCCEEDED(hr) && rangeACP, E_FAIL); |
|
190 |
|
191 LONG start, length; |
|
192 hr = rangeACP->GetExtent(&start, &length); |
|
193 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
194 if (length >= 0) { |
|
195 aStart = start; |
|
196 aEnd = start + length; |
|
197 } else { |
|
198 aEnd = start; |
|
199 aStart = start + length; |
|
200 } |
|
201 return S_OK; |
|
202 } |
|
203 |
|
204 // {3B2DFDF5-2485-4858-8185-5C6B4EFD38F5} |
|
205 static const GUID GUID_COMPOSING_SELECTION_ATTR = |
|
206 { 0x3b2dfdf5, 0x2485, 0x4858, |
|
207 { 0x81, 0x85, 0x5c, 0x6b, 0x4e, 0xfd, 0x38, 0xf5 } }; |
|
208 #define GUID_ATOM_COMPOSING_SELECTION_ATTR \ |
|
209 (static_cast<TfGuidAtom>(0x3b2dfdf5)) |
|
210 |
|
211 /****************************************************************************** |
|
212 * TSFRangeImpl |
|
213 ******************************************************************************/ |
|
214 |
|
215 class TSFRangeImpl : public ITfRangeACP |
|
216 { |
|
217 private: |
|
218 ULONG mRefCnt; |
|
219 |
|
220 public: |
|
221 LONG mStart; |
|
222 LONG mLength; |
|
223 |
|
224 TSFRangeImpl(LONG aStart = 0, LONG aLength = 0) : |
|
225 mRefCnt(0), mStart(aStart), mLength(aLength) |
|
226 { |
|
227 } |
|
228 |
|
229 ~TSFRangeImpl() |
|
230 { |
|
231 } |
|
232 |
|
233 public: // IUnknown |
|
234 |
|
235 STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk) |
|
236 { |
|
237 *ppUnk = nullptr; |
|
238 if (IID_IUnknown == riid || IID_ITfRange == riid || IID_ITfRangeACP == riid) |
|
239 *ppUnk = static_cast<ITfRangeACP*>(this); |
|
240 if (*ppUnk) |
|
241 AddRef(); |
|
242 return *ppUnk ? S_OK : E_NOINTERFACE; |
|
243 } |
|
244 |
|
245 STDMETHODIMP_(ULONG) AddRef(void) |
|
246 { |
|
247 return ++mRefCnt; |
|
248 } |
|
249 |
|
250 STDMETHODIMP_(ULONG) Release(void) |
|
251 { |
|
252 if (--mRefCnt) return mRefCnt; |
|
253 delete this; |
|
254 return 0; |
|
255 } |
|
256 |
|
257 public: // ITfRange |
|
258 |
|
259 STDMETHODIMP GetText(TfEditCookie ec, DWORD dwFlags, WCHAR *pchText, |
|
260 ULONG cchMax, ULONG *pcch) |
|
261 { |
|
262 NS_NOTREACHED("ITfRange::GetText"); |
|
263 return E_NOTIMPL; |
|
264 } |
|
265 |
|
266 STDMETHODIMP SetText(TfEditCookie ec, DWORD dwFlags, const WCHAR *pchText, |
|
267 LONG cch) |
|
268 { |
|
269 NS_NOTREACHED("ITfRange::SetText"); |
|
270 return E_NOTIMPL; |
|
271 } |
|
272 |
|
273 STDMETHODIMP GetFormattedText(TfEditCookie ec, IDataObject **ppDataObject) |
|
274 { |
|
275 NS_NOTREACHED("ITfRange::GetFormattedText"); |
|
276 return E_NOTIMPL; |
|
277 } |
|
278 |
|
279 STDMETHODIMP GetEmbedded(TfEditCookie ec, REFGUID rguidService, REFIID riid, |
|
280 IUnknown **ppunk) |
|
281 { |
|
282 NS_NOTREACHED("ITfRange::GetEmbedded"); |
|
283 return E_NOTIMPL; |
|
284 } |
|
285 |
|
286 STDMETHODIMP InsertEmbedded(TfEditCookie ec, DWORD dwFlags, |
|
287 IDataObject *pDataObject) |
|
288 { |
|
289 NS_NOTREACHED("ITfRange::InsertEmbedded"); |
|
290 return E_NOTIMPL; |
|
291 } |
|
292 |
|
293 STDMETHODIMP ShiftStart(TfEditCookie ec, LONG cchReq, LONG *pcch, |
|
294 const TF_HALTCOND *pHalt) |
|
295 { |
|
296 NS_NOTREACHED("ITfRange::ShiftStart"); |
|
297 return E_NOTIMPL; |
|
298 } |
|
299 |
|
300 STDMETHODIMP ShiftEnd(TfEditCookie ec, LONG cchReq, LONG *pcch, |
|
301 const TF_HALTCOND *pHalt) |
|
302 { |
|
303 NS_NOTREACHED("ITfRange::ShiftEnd"); |
|
304 return E_NOTIMPL; |
|
305 } |
|
306 |
|
307 STDMETHODIMP ShiftStartToRange(TfEditCookie ec, ITfRange *pRange, |
|
308 TfAnchor aPos) |
|
309 { |
|
310 NS_NOTREACHED("ITfRange::ShiftStartToRange"); |
|
311 return E_NOTIMPL; |
|
312 } |
|
313 |
|
314 STDMETHODIMP ShiftEndToRange(TfEditCookie ec, ITfRange *pRange, TfAnchor aPos) |
|
315 { |
|
316 NS_NOTREACHED("ITfRange::ShiftEndToRange"); |
|
317 return E_NOTIMPL; |
|
318 } |
|
319 |
|
320 STDMETHODIMP ShiftStartRegion(TfEditCookie ec, TfShiftDir dir, |
|
321 BOOL *pfNoRegion) |
|
322 { |
|
323 NS_NOTREACHED("ITfRange::ShiftStartRegion"); |
|
324 return E_NOTIMPL; |
|
325 } |
|
326 |
|
327 STDMETHODIMP ShiftEndRegion(TfEditCookie ec, TfShiftDir dir, BOOL *pfNoRegion) |
|
328 { |
|
329 NS_NOTREACHED("ITfRange::ShiftEndRegion"); |
|
330 return E_NOTIMPL; |
|
331 } |
|
332 |
|
333 STDMETHODIMP IsEmpty(TfEditCookie ec, BOOL *pfEmpty) |
|
334 { |
|
335 NS_NOTREACHED("ITfRange::IsEmpty"); |
|
336 return E_NOTIMPL; |
|
337 } |
|
338 |
|
339 STDMETHODIMP Collapse(TfEditCookie ec, TfAnchor aPos) |
|
340 { |
|
341 NS_NOTREACHED("ITfRange::Collapse"); |
|
342 return E_NOTIMPL; |
|
343 } |
|
344 |
|
345 STDMETHODIMP IsEqualStart(TfEditCookie ec, ITfRange *pWith, TfAnchor aPos, |
|
346 BOOL *pfEqual) |
|
347 { |
|
348 NS_NOTREACHED("ITfRange::IsEqualStart"); |
|
349 return E_NOTIMPL; |
|
350 } |
|
351 |
|
352 STDMETHODIMP IsEqualEnd(TfEditCookie ec, ITfRange *pWith, TfAnchor aPos, |
|
353 BOOL *pfEqual) |
|
354 { |
|
355 NS_NOTREACHED("ITfRange::IsEqualEnd"); |
|
356 return E_NOTIMPL; |
|
357 } |
|
358 |
|
359 STDMETHODIMP CompareStart(TfEditCookie ec, ITfRange *pWith, TfAnchor aPos, |
|
360 LONG *plResult) |
|
361 { |
|
362 NS_NOTREACHED("ITfRange::CompareStart"); |
|
363 return E_NOTIMPL; |
|
364 } |
|
365 |
|
366 STDMETHODIMP CompareEnd(TfEditCookie ec, ITfRange *pWith, TfAnchor aPos, |
|
367 LONG *plResult) |
|
368 { |
|
369 NS_NOTREACHED("ITfRange::CompareEnd"); |
|
370 return E_NOTIMPL; |
|
371 } |
|
372 |
|
373 STDMETHODIMP AdjustForInsert(TfEditCookie ec, ULONG cchInsert, |
|
374 BOOL *pfInsertOk) |
|
375 { |
|
376 NS_NOTREACHED("ITfRange::AdjustForInsert"); |
|
377 return E_NOTIMPL; |
|
378 } |
|
379 |
|
380 STDMETHODIMP GetGravity(TfGravity *pgStart, TfGravity *pgEnd) |
|
381 { |
|
382 NS_NOTREACHED("ITfRange::GetGravity"); |
|
383 return E_NOTIMPL; |
|
384 } |
|
385 |
|
386 STDMETHODIMP SetGravity(TfEditCookie ec, TfGravity gStart, TfGravity gEnd) |
|
387 { |
|
388 NS_NOTREACHED("ITfRange::SetGravity"); |
|
389 return E_NOTIMPL; |
|
390 } |
|
391 |
|
392 STDMETHODIMP Clone(ITfRange **ppClone) |
|
393 { |
|
394 NS_NOTREACHED("ITfRange::Clone"); |
|
395 return E_NOTIMPL; |
|
396 } |
|
397 |
|
398 STDMETHODIMP GetContext(ITfContext **ppContext) |
|
399 { |
|
400 NS_NOTREACHED("ITfRange::GetContext"); |
|
401 return E_NOTIMPL; |
|
402 } |
|
403 |
|
404 public: // ITfRangeACP |
|
405 |
|
406 STDMETHODIMP GetExtent(LONG *pacpAnchor, LONG *pcch) |
|
407 { |
|
408 NS_ENSURE_TRUE(pacpAnchor, E_FAIL); |
|
409 NS_ENSURE_TRUE(pcch, E_FAIL); |
|
410 *pacpAnchor = mStart; |
|
411 *pcch = mLength; |
|
412 return S_OK; |
|
413 } |
|
414 |
|
415 STDMETHODIMP SetExtent(LONG acpAnchor, LONG cch) |
|
416 { |
|
417 mStart = acpAnchor; |
|
418 mLength = cch; |
|
419 return S_OK; |
|
420 } |
|
421 }; |
|
422 |
|
423 /****************************************************************************** |
|
424 * TSFEnumRangeImpl |
|
425 ******************************************************************************/ |
|
426 |
|
427 class TSFEnumRangeImpl : public IEnumTfRanges |
|
428 { |
|
429 private: |
|
430 ULONG mRefCnt; |
|
431 uint32_t mCurrentIndex; |
|
432 |
|
433 public: |
|
434 nsTArray<nsRefPtr<TSFRangeImpl> > mRanges; |
|
435 |
|
436 TSFEnumRangeImpl() : |
|
437 mRefCnt(0), mCurrentIndex(0) |
|
438 { |
|
439 } |
|
440 |
|
441 ~TSFEnumRangeImpl() |
|
442 { |
|
443 } |
|
444 |
|
445 public: // IUnknown |
|
446 |
|
447 STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk) |
|
448 { |
|
449 *ppUnk = nullptr; |
|
450 if (IID_IUnknown == riid || IID_IEnumTfRanges == riid) |
|
451 *ppUnk = static_cast<IEnumTfRanges*>(this); |
|
452 if (*ppUnk) |
|
453 AddRef(); |
|
454 return *ppUnk ? S_OK : E_NOINTERFACE; |
|
455 } |
|
456 |
|
457 STDMETHODIMP_(ULONG) AddRef(void) |
|
458 { |
|
459 return ++mRefCnt; |
|
460 } |
|
461 |
|
462 STDMETHODIMP_(ULONG) Release(void) |
|
463 { |
|
464 if (--mRefCnt) return mRefCnt; |
|
465 delete this; |
|
466 return 0; |
|
467 } |
|
468 |
|
469 public: // IEnumTfRanges |
|
470 |
|
471 STDMETHODIMP Clone(IEnumTfRanges **ppEnum) |
|
472 { |
|
473 NS_NOTREACHED("IEnumTfRanges::Clone"); |
|
474 return E_NOTIMPL; |
|
475 } |
|
476 |
|
477 STDMETHODIMP Next(ULONG ulCount, ITfRange **ppRange, ULONG *pcFetched) |
|
478 { |
|
479 NS_ENSURE_TRUE(ppRange, E_FAIL); |
|
480 if (pcFetched) |
|
481 *pcFetched = 0; |
|
482 if (mCurrentIndex + ulCount - 1 >= mRanges.Length()) |
|
483 return E_FAIL; |
|
484 for (uint32_t i = 0; i < ulCount; i++) { |
|
485 ppRange[i] = mRanges[mCurrentIndex++]; |
|
486 ppRange[i]->AddRef(); |
|
487 if (pcFetched) |
|
488 (*pcFetched)++; |
|
489 } |
|
490 return S_OK; |
|
491 } |
|
492 |
|
493 STDMETHODIMP Reset() |
|
494 { |
|
495 mCurrentIndex = 0; |
|
496 return S_OK; |
|
497 } |
|
498 |
|
499 STDMETHODIMP Skip(ULONG ulCount) |
|
500 { |
|
501 mCurrentIndex += ulCount; |
|
502 return S_OK; |
|
503 } |
|
504 }; |
|
505 |
|
506 /****************************************************************************** |
|
507 * TSFDispAttrInfoImpl |
|
508 ******************************************************************************/ |
|
509 |
|
510 class TSFDispAttrInfoImpl : public ITfDisplayAttributeInfo |
|
511 { |
|
512 private: |
|
513 ULONG mRefCnt; |
|
514 TF_DISPLAYATTRIBUTE mAttr; |
|
515 |
|
516 public: |
|
517 |
|
518 TSFDispAttrInfoImpl(REFGUID aGUID) : |
|
519 mRefCnt(0) |
|
520 { |
|
521 if (aGUID == GUID_COMPOSING_SELECTION_ATTR) { |
|
522 mAttr.crText.type = TF_CT_NONE; |
|
523 mAttr.crBk.type = TF_CT_NONE; |
|
524 mAttr.lsStyle = TF_LS_SQUIGGLE; |
|
525 mAttr.fBoldLine = FALSE; |
|
526 mAttr.crLine.type = TF_CT_NONE; |
|
527 mAttr.bAttr = TF_ATTR_INPUT; |
|
528 } else { |
|
529 NS_NOTREACHED("TSFDispAttrInfoImpl::TSFDispAttrInfoImpl"); |
|
530 } |
|
531 } |
|
532 |
|
533 ~TSFDispAttrInfoImpl() |
|
534 { |
|
535 } |
|
536 |
|
537 public: // IUnknown |
|
538 |
|
539 STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk) |
|
540 { |
|
541 *ppUnk = nullptr; |
|
542 if (IID_IUnknown == riid || IID_ITfDisplayAttributeInfo == riid) |
|
543 *ppUnk = static_cast<ITfDisplayAttributeInfo*>(this); |
|
544 if (*ppUnk) |
|
545 AddRef(); |
|
546 return *ppUnk ? S_OK : E_NOINTERFACE; |
|
547 } |
|
548 |
|
549 STDMETHODIMP_(ULONG) AddRef(void) |
|
550 { |
|
551 return ++mRefCnt; |
|
552 } |
|
553 |
|
554 STDMETHODIMP_(ULONG) Release(void) |
|
555 { |
|
556 if (--mRefCnt) return mRefCnt; |
|
557 delete this; |
|
558 return 0; |
|
559 } |
|
560 |
|
561 public: // ITfDisplayAttributeInfo |
|
562 |
|
563 STDMETHODIMP GetGUID(GUID *pguid) |
|
564 { |
|
565 NS_NOTREACHED("ITfDisplayAttributeInfo::GetGUID"); |
|
566 return E_NOTIMPL; |
|
567 } |
|
568 |
|
569 STDMETHODIMP GetDescription(BSTR *pbstrDesc) |
|
570 { |
|
571 NS_NOTREACHED("ITfDisplayAttributeInfo::GetDescription"); |
|
572 return E_NOTIMPL; |
|
573 } |
|
574 |
|
575 STDMETHODIMP GetAttributeInfo(TF_DISPLAYATTRIBUTE *pda) |
|
576 { |
|
577 NS_ENSURE_TRUE(pda, E_INVALIDARG); |
|
578 *pda = mAttr; |
|
579 return S_OK; |
|
580 } |
|
581 |
|
582 STDMETHODIMP SetAttributeInfo(const TF_DISPLAYATTRIBUTE *pda) |
|
583 { |
|
584 NS_NOTREACHED("ITfDisplayAttributeInfo::SetAttributeInfo"); |
|
585 return E_NOTIMPL; |
|
586 } |
|
587 |
|
588 STDMETHODIMP Reset() |
|
589 { |
|
590 NS_NOTREACHED("ITfDisplayAttributeInfo::Reset"); |
|
591 return E_NOTIMPL; |
|
592 } |
|
593 }; |
|
594 |
|
595 /****************************************************************************** |
|
596 * TSFAttrPropImpl |
|
597 ******************************************************************************/ |
|
598 |
|
599 class TSFAttrPropImpl : public ITfProperty |
|
600 { |
|
601 private: |
|
602 ULONG mRefCnt; |
|
603 |
|
604 public: |
|
605 nsTArray<nsRefPtr<TSFRangeImpl> > mRanges; |
|
606 |
|
607 TSFAttrPropImpl() : |
|
608 mRefCnt(0) |
|
609 { |
|
610 } |
|
611 |
|
612 ~TSFAttrPropImpl() |
|
613 { |
|
614 } |
|
615 |
|
616 public: // IUnknown |
|
617 |
|
618 STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk) |
|
619 { |
|
620 *ppUnk = nullptr; |
|
621 if (IID_IUnknown == riid || IID_ITfProperty == riid || |
|
622 IID_ITfReadOnlyProperty == riid) |
|
623 *ppUnk = static_cast<ITfProperty*>(this); |
|
624 if (*ppUnk) |
|
625 AddRef(); |
|
626 return *ppUnk ? S_OK : E_NOINTERFACE; |
|
627 } |
|
628 |
|
629 STDMETHODIMP_(ULONG) AddRef(void) |
|
630 { |
|
631 return ++mRefCnt; |
|
632 } |
|
633 |
|
634 STDMETHODIMP_(ULONG) Release(void) |
|
635 { |
|
636 if (--mRefCnt) return mRefCnt; |
|
637 delete this; |
|
638 return 0; |
|
639 } |
|
640 |
|
641 public: // ITfProperty |
|
642 |
|
643 STDMETHODIMP FindRange(TfEditCookie ec, ITfRange *pRange, ITfRange **ppRange, |
|
644 TfAnchor aPos) |
|
645 { |
|
646 NS_NOTREACHED("ITfProperty::FindRange"); |
|
647 return E_NOTIMPL; |
|
648 } |
|
649 |
|
650 STDMETHODIMP SetValueStore(TfEditCookie ec, ITfRange *pRange, |
|
651 ITfPropertyStore *pPropStore) |
|
652 { |
|
653 NS_NOTREACHED("ITfProperty::SetValueStore"); |
|
654 return E_NOTIMPL; |
|
655 } |
|
656 |
|
657 STDMETHODIMP SetValue(TfEditCookie ec, ITfRange *pRange, |
|
658 const VARIANT *pvarValue) |
|
659 { |
|
660 NS_NOTREACHED("ITfProperty::SetValue"); |
|
661 return E_NOTIMPL; |
|
662 } |
|
663 |
|
664 STDMETHODIMP Clear(TfEditCookie ec, ITfRange *pRange) |
|
665 { |
|
666 NS_NOTREACHED("ITfProperty::Clear"); |
|
667 return E_NOTIMPL; |
|
668 } |
|
669 |
|
670 public: // ITfReadOnlyProperty |
|
671 |
|
672 STDMETHODIMP GetType(GUID *pguid) |
|
673 { |
|
674 NS_NOTREACHED("ITfReadOnlyProperty::GetType"); |
|
675 return E_NOTIMPL; |
|
676 } |
|
677 |
|
678 STDMETHODIMP EnumRanges(TfEditCookie ec, IEnumTfRanges **ppEnum, |
|
679 ITfRange *pTargetRange) |
|
680 { |
|
681 NS_ENSURE_TRUE(ppEnum, E_INVALIDARG); |
|
682 NS_ENSURE_TRUE(pTargetRange, E_INVALIDARG); |
|
683 |
|
684 // XXX ec checking is not implemented yet. |
|
685 |
|
686 LONG targetStart = 0, targetEnd = 0; |
|
687 if (pTargetRange) { |
|
688 HRESULT hr = GetRegularExtent(pTargetRange, targetStart, targetEnd); |
|
689 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
690 } |
|
691 nsRefPtr<TSFEnumRangeImpl> er = new TSFEnumRangeImpl(); |
|
692 NS_ENSURE_TRUE(er, E_OUTOFMEMORY); |
|
693 for (uint32_t i = 0; i < mRanges.Length(); i++) { |
|
694 LONG start, end; |
|
695 HRESULT hr = GetRegularExtent(mRanges[i], start, end); |
|
696 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
697 if (pTargetRange) { |
|
698 // If pTargetRange is not null and the current range is not overlapped |
|
699 // with it, we don't need to add range. |
|
700 if (targetStart > end || targetEnd < start) |
|
701 continue; |
|
702 // Otherwise, shrink to the target range. |
|
703 start = std::max(targetStart, start); |
|
704 end = std::min(targetEnd, end); |
|
705 } |
|
706 nsRefPtr<TSFRangeImpl> range = new TSFRangeImpl(start, end - start); |
|
707 NS_ENSURE_TRUE(range, E_OUTOFMEMORY); |
|
708 er->mRanges.AppendElement(range); |
|
709 } |
|
710 *ppEnum = er; |
|
711 (*ppEnum)->AddRef(); |
|
712 return S_OK; |
|
713 } |
|
714 |
|
715 STDMETHODIMP GetValue(TfEditCookie ec, ITfRange *pRange, VARIANT *pvarValue) |
|
716 { |
|
717 NS_ENSURE_TRUE(pvarValue, E_INVALIDARG); |
|
718 |
|
719 LONG givenStart, givenEnd; |
|
720 HRESULT hr = GetRegularExtent(pRange, givenStart, givenEnd); |
|
721 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
722 for (uint32_t i = 0; i < mRanges.Length(); i++) { |
|
723 LONG start, end; |
|
724 HRESULT hr = GetRegularExtent(mRanges[i], start, end); |
|
725 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
726 // pRange must be same as (or included in) a range of mRanges. |
|
727 if (givenStart > start || givenEnd < end) |
|
728 continue; |
|
729 pvarValue->vt = VT_I4; |
|
730 pvarValue->lVal = static_cast<DWORD>(GUID_ATOM_COMPOSING_SELECTION_ATTR); |
|
731 return S_OK; |
|
732 } |
|
733 return E_FAIL; |
|
734 } |
|
735 |
|
736 STDMETHODIMP GetContext(ITfContext **ppContext) |
|
737 { |
|
738 NS_NOTREACHED("ITfReadOnlyProperty::GetContext"); |
|
739 return E_NOTIMPL; |
|
740 } |
|
741 }; |
|
742 |
|
743 /****************************************************************************** |
|
744 * TSFContextImpl |
|
745 ******************************************************************************/ |
|
746 |
|
747 class TSFContextImpl : public ITfContext, |
|
748 public ITfCompositionView, public ITextStoreACPSink |
|
749 { |
|
750 private: |
|
751 ULONG mRefCnt; |
|
752 |
|
753 public: |
|
754 nsRefPtr<TSFAttrPropImpl> mAttrProp; |
|
755 nsRefPtr<TSFDocumentMgrImpl> mDocMgr; |
|
756 bool mTextChanged; |
|
757 bool mSelChanged; |
|
758 TS_TEXTCHANGE mTextChangeData; |
|
759 |
|
760 public: |
|
761 TSFContextImpl(TSFDocumentMgrImpl* aDocMgr) : |
|
762 mDocMgr(aDocMgr), mRefCnt(0), mTextChanged(false), |
|
763 mSelChanged(false) |
|
764 { |
|
765 mAttrProp = new TSFAttrPropImpl(); |
|
766 if (!mAttrProp) { |
|
767 NS_NOTREACHED("TSFContextImpl::TSFContextImpl (OOM)"); |
|
768 return; |
|
769 } |
|
770 } |
|
771 |
|
772 ~TSFContextImpl() |
|
773 { |
|
774 } |
|
775 |
|
776 public: // IUnknown |
|
777 |
|
778 STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk) |
|
779 { |
|
780 *ppUnk = nullptr; |
|
781 if (IID_IUnknown == riid || IID_ITfContext == riid) |
|
782 *ppUnk = static_cast<ITfContext*>(this); |
|
783 else if (IID_ITextStoreACPSink == riid) |
|
784 *ppUnk = static_cast<ITextStoreACPSink*>(this); |
|
785 if (*ppUnk) |
|
786 AddRef(); |
|
787 return *ppUnk ? S_OK : E_NOINTERFACE; |
|
788 } |
|
789 |
|
790 STDMETHODIMP_(ULONG) AddRef(void) |
|
791 { |
|
792 return ++mRefCnt; |
|
793 } |
|
794 |
|
795 STDMETHODIMP_(ULONG) Release(void) |
|
796 { |
|
797 if (--mRefCnt) return mRefCnt; |
|
798 delete this; |
|
799 return 0; |
|
800 } |
|
801 |
|
802 public: // ITfContext |
|
803 |
|
804 STDMETHODIMP RequestEditSession(TfClientId tid, ITfEditSession *pes, |
|
805 DWORD dwFlags, HRESULT *phrSession) |
|
806 { |
|
807 NS_NOTREACHED("ITfContext::RequestEditSession"); |
|
808 return E_NOTIMPL; |
|
809 } |
|
810 |
|
811 STDMETHODIMP InWriteSession(TfClientId tid, BOOL *pfWriteSession) |
|
812 { |
|
813 NS_NOTREACHED("ITfContext::InWriteSession"); |
|
814 return E_NOTIMPL; |
|
815 } |
|
816 |
|
817 STDMETHODIMP GetSelection(TfEditCookie ec, ULONG ulIndex, ULONG ulCount, |
|
818 TF_SELECTION *pSelection, ULONG *pcFetched) |
|
819 { |
|
820 NS_NOTREACHED("ITfContext::GetSelection"); |
|
821 return E_NOTIMPL; |
|
822 } |
|
823 |
|
824 STDMETHODIMP SetSelection(TfEditCookie ec, ULONG ulCount, |
|
825 const TF_SELECTION *pSelection) |
|
826 { |
|
827 NS_NOTREACHED("ITfContext::SetSelection"); |
|
828 return E_NOTIMPL; |
|
829 } |
|
830 |
|
831 STDMETHODIMP GetStart(TfEditCookie ec, ITfRange **ppStart) |
|
832 { |
|
833 NS_NOTREACHED("ITfContext::GetStart"); |
|
834 return E_NOTIMPL; |
|
835 } |
|
836 |
|
837 STDMETHODIMP GetEnd(TfEditCookie ec, ITfRange **ppEnd) |
|
838 { |
|
839 NS_NOTREACHED("ITfContext::GetEnd"); |
|
840 return E_NOTIMPL; |
|
841 } |
|
842 |
|
843 STDMETHODIMP GetActiveView(ITfContextView **ppView) |
|
844 { |
|
845 NS_NOTREACHED("ITfContext::GetActiveView"); |
|
846 return E_NOTIMPL; |
|
847 } |
|
848 |
|
849 STDMETHODIMP EnumViews(IEnumTfContextViews **ppEnum) |
|
850 { |
|
851 NS_NOTREACHED("ITfContext::EnumViews"); |
|
852 return E_NOTIMPL; |
|
853 } |
|
854 |
|
855 STDMETHODIMP GetStatus(TF_STATUS *pdcs) |
|
856 { |
|
857 NS_NOTREACHED("ITfContext::GetStatus"); |
|
858 return E_NOTIMPL; |
|
859 } |
|
860 |
|
861 STDMETHODIMP GetProperty(REFGUID guidProp, ITfProperty **ppProp) |
|
862 { |
|
863 NS_ENSURE_TRUE(ppProp, E_INVALIDARG); |
|
864 if (guidProp == GUID_PROP_ATTRIBUTE) { |
|
865 (*ppProp) = mAttrProp; |
|
866 (*ppProp)->AddRef(); |
|
867 return S_OK; |
|
868 } |
|
869 NS_NOTREACHED("ITfContext::GetProperty"); |
|
870 return E_NOTIMPL; |
|
871 } |
|
872 |
|
873 STDMETHODIMP GetAppProperty(REFGUID guidProp, ITfReadOnlyProperty **ppProp) |
|
874 { |
|
875 NS_NOTREACHED("ITfContext::GetAppProperty"); |
|
876 return E_NOTIMPL; |
|
877 } |
|
878 |
|
879 STDMETHODIMP TrackProperties(const GUID **prgProp, ULONG cProp, |
|
880 const GUID **prgAppProp, ULONG cAppProp, |
|
881 ITfReadOnlyProperty **ppProperty) |
|
882 { |
|
883 NS_NOTREACHED("ITfContext::TrackProperties"); |
|
884 return E_NOTIMPL; |
|
885 } |
|
886 |
|
887 STDMETHODIMP EnumProperties(IEnumTfProperties **ppEnum) |
|
888 { |
|
889 NS_NOTREACHED("ITfContext::EnumProperties"); |
|
890 return E_NOTIMPL; |
|
891 } |
|
892 |
|
893 STDMETHODIMP GetDocumentMgr(ITfDocumentMgr **ppDm) |
|
894 { |
|
895 NS_NOTREACHED("ITfContext::GetDocumentMgr"); |
|
896 return E_NOTIMPL; |
|
897 } |
|
898 |
|
899 STDMETHODIMP CreateRangeBackup(TfEditCookie ec, ITfRange *pRange, |
|
900 ITfRangeBackup **ppBackup) |
|
901 { |
|
902 NS_NOTREACHED("ITfContext::CreateRangeBackup"); |
|
903 return E_NOTIMPL; |
|
904 } |
|
905 |
|
906 public: // ITfCompositionView |
|
907 |
|
908 STDMETHODIMP GetOwnerClsid(CLSID* pclsid) |
|
909 { |
|
910 NS_NOTREACHED("ITfCompositionView::GetOwnerClsid"); |
|
911 return E_NOTIMPL; |
|
912 } |
|
913 |
|
914 STDMETHODIMP GetRange(ITfRange** ppRange) |
|
915 { |
|
916 NS_ENSURE_TRUE(ppRange, E_INVALIDARG); |
|
917 NS_ENSURE_TRUE(mAttrProp->mRanges.Length() > 0, E_FAIL); |
|
918 LONG start = LONG_MAX, end = 0; |
|
919 for (uint32_t i = 0; i < mAttrProp->mRanges.Length(); i++) { |
|
920 LONG tmpStart, tmpEnd; |
|
921 HRESULT hr = GetRegularExtent(mAttrProp->mRanges[i], tmpStart, tmpEnd); |
|
922 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
923 start = std::min(start, tmpStart); |
|
924 end = std::max(end, tmpEnd); |
|
925 } |
|
926 nsRefPtr<TSFRangeImpl> range = new TSFRangeImpl(); |
|
927 NS_ENSURE_TRUE(range, E_OUTOFMEMORY); |
|
928 HRESULT hr = range->SetExtent(start, end - start); |
|
929 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
930 (*ppRange) = range; |
|
931 (*ppRange)->AddRef(); |
|
932 return S_OK; |
|
933 } |
|
934 |
|
935 public: // ITextStoreACPSink |
|
936 |
|
937 STDMETHODIMP OnTextChange(DWORD dwFlags, const TS_TEXTCHANGE *pChange) |
|
938 { |
|
939 mTextChanged = true; |
|
940 mTextChangeData = *pChange; |
|
941 return S_OK; |
|
942 } |
|
943 |
|
944 STDMETHODIMP OnSelectionChange(void) |
|
945 { |
|
946 mSelChanged = true; |
|
947 return S_OK; |
|
948 } |
|
949 |
|
950 STDMETHODIMP OnLayoutChange(TsLayoutCode lcode, TsViewCookie vcView) |
|
951 { |
|
952 return S_OK; |
|
953 } |
|
954 |
|
955 STDMETHODIMP OnStatusChange(DWORD dwFlags) |
|
956 { |
|
957 return S_OK; |
|
958 } |
|
959 |
|
960 STDMETHODIMP OnAttrsChange(LONG acpStart, LONG acpEnd, ULONG cAttrs, |
|
961 const TS_ATTRID *paAttrs) |
|
962 { |
|
963 return S_OK; |
|
964 } |
|
965 |
|
966 STDMETHODIMP OnLockGranted(DWORD dwLockFlags); |
|
967 |
|
968 STDMETHODIMP OnStartEditTransaction(void) |
|
969 { |
|
970 return S_OK; |
|
971 } |
|
972 |
|
973 STDMETHODIMP OnEndEditTransaction(void) |
|
974 { |
|
975 return S_OK; |
|
976 } |
|
977 }; |
|
978 |
|
979 /****************************************************************************** |
|
980 * TSFDocumentMgrImpl |
|
981 ******************************************************************************/ |
|
982 |
|
983 class TSFDocumentMgrImpl : public ITfDocumentMgr |
|
984 { |
|
985 private: |
|
986 ULONG mRefCnt; |
|
987 |
|
988 public: |
|
989 nsRefPtr<TSFMgrImpl> mMgr; |
|
990 nsRefPtr<ITextStoreACP> mStore; |
|
991 nsRefPtr<TSFContextImpl> mContextBase; |
|
992 nsRefPtr<TSFContextImpl> mContextTop; // XXX currently, we don't support this. |
|
993 |
|
994 public: |
|
995 TSFDocumentMgrImpl(TSFMgrImpl* aMgr) : |
|
996 mRefCnt(0), mMgr(aMgr) |
|
997 { |
|
998 } |
|
999 |
|
1000 ~TSFDocumentMgrImpl() |
|
1001 { |
|
1002 } |
|
1003 |
|
1004 public: // IUnknown |
|
1005 |
|
1006 STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk) |
|
1007 { |
|
1008 *ppUnk = nullptr; |
|
1009 if (IID_IUnknown == riid || IID_ITfDocumentMgr == riid) |
|
1010 *ppUnk = static_cast<ITfDocumentMgr*>(this); |
|
1011 if (*ppUnk) |
|
1012 AddRef(); |
|
1013 return *ppUnk ? S_OK : E_NOINTERFACE; |
|
1014 } |
|
1015 |
|
1016 STDMETHODIMP_(ULONG) AddRef(void) |
|
1017 { |
|
1018 return ++mRefCnt; |
|
1019 } |
|
1020 |
|
1021 STDMETHODIMP_(ULONG) Release(void); |
|
1022 |
|
1023 public: // ITfDocumentMgr |
|
1024 |
|
1025 STDMETHODIMP CreateContext(TfClientId tidOwner, DWORD dwFlags, |
|
1026 IUnknown *punk, ITfContext **ppic, |
|
1027 TfEditCookie *pecTextStore) |
|
1028 { |
|
1029 nsRefPtr<TSFContextImpl> context = new TSFContextImpl(this); |
|
1030 punk->QueryInterface(IID_ITextStoreACP, getter_AddRefs(mStore)); |
|
1031 NS_ENSURE_TRUE(mStore, E_FAIL); |
|
1032 HRESULT hr = |
|
1033 mStore->AdviseSink(IID_ITextStoreACPSink, |
|
1034 static_cast<ITextStoreACPSink*>(context.get()), |
|
1035 TS_AS_ALL_SINKS); |
|
1036 if (FAILED(hr)) mStore = nullptr; |
|
1037 NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); |
|
1038 (*ppic) = context; |
|
1039 (*ppic)->AddRef(); |
|
1040 *pecTextStore = 1; |
|
1041 return S_OK; |
|
1042 } |
|
1043 |
|
1044 STDMETHODIMP Push(ITfContext *pic) |
|
1045 { |
|
1046 if (mContextTop) { |
|
1047 NS_NOTREACHED("TSFDocumentMgrImpl::Push stack is already full"); |
|
1048 return E_FAIL; |
|
1049 } |
|
1050 if (mContextBase) { |
|
1051 NS_WARNING("TSFDocumentMgrImpl::Push additional context is pushed, but we don't support that yet."); |
|
1052 if (mContextBase == pic) { |
|
1053 NS_NOTREACHED("TSFDocumentMgrImpl::Push same context is pused again"); |
|
1054 return E_FAIL; |
|
1055 } |
|
1056 mContextTop = static_cast<TSFContextImpl*>(pic); |
|
1057 return S_OK; |
|
1058 } |
|
1059 mContextBase = static_cast<TSFContextImpl*>(pic); |
|
1060 return S_OK; |
|
1061 } |
|
1062 |
|
1063 STDMETHODIMP Pop(DWORD dwFlags) |
|
1064 { |
|
1065 if (!mStore) |
|
1066 return E_FAIL; |
|
1067 if (dwFlags == TF_POPF_ALL) { |
|
1068 NS_ENSURE_TRUE(mContextBase, E_FAIL); |
|
1069 mStore->UnadviseSink(static_cast<ITextStoreACPSink*>(mContextBase.get())); |
|
1070 mStore = nullptr; |
|
1071 mContextBase = nullptr; |
|
1072 mContextTop = nullptr; |
|
1073 return S_OK; |
|
1074 } |
|
1075 if (dwFlags == 0) { |
|
1076 if (!mContextTop) { |
|
1077 NS_NOTREACHED("TSFDocumentMgrImpl::Pop there is non-base context"); |
|
1078 return E_FAIL; |
|
1079 } |
|
1080 mContextTop = nullptr; |
|
1081 return S_OK; |
|
1082 } |
|
1083 NS_NOTREACHED("TSFDocumentMgrImpl::Pop invalid flag"); |
|
1084 return E_FAIL; |
|
1085 } |
|
1086 |
|
1087 STDMETHODIMP GetTop(ITfContext **ppic) |
|
1088 { |
|
1089 (*ppic) = mContextTop ? mContextTop : mContextBase; |
|
1090 if (*ppic) (*ppic)->AddRef(); |
|
1091 return S_OK; |
|
1092 } |
|
1093 |
|
1094 STDMETHODIMP GetBase(ITfContext **ppic) |
|
1095 { |
|
1096 (*ppic) = mContextBase; |
|
1097 if (*ppic) (*ppic)->AddRef(); |
|
1098 return S_OK; |
|
1099 } |
|
1100 |
|
1101 STDMETHODIMP EnumContexts(IEnumTfContexts **ppEnum) |
|
1102 { |
|
1103 NS_NOTREACHED("ITfDocumentMgr::EnumContexts"); |
|
1104 return E_NOTIMPL; |
|
1105 } |
|
1106 |
|
1107 }; |
|
1108 |
|
1109 /****************************************************************************** |
|
1110 * TSFMgrImpl |
|
1111 ******************************************************************************/ |
|
1112 |
|
1113 class TSFMgrImpl : public ITfThreadMgr, |
|
1114 public ITfDisplayAttributeMgr, public ITfCategoryMgr |
|
1115 { |
|
1116 private: |
|
1117 ULONG mRefCnt; |
|
1118 |
|
1119 public: |
|
1120 nsRefPtr<TestApp> mTestApp; |
|
1121 TestApp::test_type mTest; |
|
1122 bool mDeactivated; |
|
1123 TSFDocumentMgrImpl* mFocusedDocument; // Must be raw pointer, but strong. |
|
1124 int32_t mFocusCount; |
|
1125 |
|
1126 TSFMgrImpl(TestApp* test) : mTestApp(test), mTest(nullptr), mRefCnt(0), |
|
1127 mDeactivated(false), mFocusedDocument(nullptr), mFocusCount(0) |
|
1128 { |
|
1129 } |
|
1130 |
|
1131 ~TSFMgrImpl() |
|
1132 { |
|
1133 } |
|
1134 |
|
1135 public: // IUnknown |
|
1136 |
|
1137 STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk) |
|
1138 { |
|
1139 *ppUnk = nullptr; |
|
1140 if (IID_IUnknown == riid || IID_ITfThreadMgr == riid) |
|
1141 *ppUnk = static_cast<ITfThreadMgr*>(this); |
|
1142 else if (IID_ITfDisplayAttributeMgr == riid) |
|
1143 *ppUnk = static_cast<ITfDisplayAttributeMgr*>(this); |
|
1144 else if (IID_ITfCategoryMgr == riid) |
|
1145 *ppUnk = static_cast<ITfCategoryMgr*>(this); |
|
1146 if (*ppUnk) |
|
1147 AddRef(); |
|
1148 return *ppUnk ? S_OK : E_NOINTERFACE; |
|
1149 } |
|
1150 |
|
1151 STDMETHODIMP_(ULONG) AddRef(void) |
|
1152 { |
|
1153 return ++mRefCnt; |
|
1154 } |
|
1155 |
|
1156 STDMETHODIMP_(ULONG) Release(void) |
|
1157 { |
|
1158 if (--mRefCnt) return mRefCnt; |
|
1159 delete this; |
|
1160 return 0; |
|
1161 } |
|
1162 |
|
1163 public: // ITfThreadMgr |
|
1164 |
|
1165 STDMETHODIMP Activate(TfClientId *ptid) |
|
1166 { |
|
1167 *ptid = 1; |
|
1168 return S_OK; |
|
1169 } |
|
1170 |
|
1171 STDMETHODIMP Deactivate(void) |
|
1172 { |
|
1173 mDeactivated = true; |
|
1174 return S_OK; |
|
1175 } |
|
1176 |
|
1177 STDMETHODIMP CreateDocumentMgr(ITfDocumentMgr **ppdim) |
|
1178 { |
|
1179 nsRefPtr<TSFDocumentMgrImpl> docMgr = new TSFDocumentMgrImpl(this); |
|
1180 if (!docMgr) { |
|
1181 NS_NOTREACHED("TSFMgrImpl::CreateDocumentMgr (OOM)"); |
|
1182 return E_OUTOFMEMORY; |
|
1183 } |
|
1184 (*ppdim) = docMgr; |
|
1185 (*ppdim)->AddRef(); |
|
1186 return S_OK; |
|
1187 } |
|
1188 |
|
1189 STDMETHODIMP EnumDocumentMgrs(IEnumTfDocumentMgrs **ppEnum) |
|
1190 { |
|
1191 NS_NOTREACHED("ITfThreadMgr::EnumDocumentMgrs"); |
|
1192 return E_NOTIMPL; |
|
1193 } |
|
1194 |
|
1195 STDMETHODIMP GetFocus(ITfDocumentMgr **ppdimFocus) |
|
1196 { |
|
1197 (*ppdimFocus) = mFocusedDocument; |
|
1198 if (*ppdimFocus) (*ppdimFocus)->AddRef(); |
|
1199 return S_OK; |
|
1200 } |
|
1201 |
|
1202 STDMETHODIMP SetFocus(ITfDocumentMgr *pdimFocus) |
|
1203 { |
|
1204 if (!pdimFocus) { |
|
1205 NS_NOTREACHED("ITfThreadMgr::SetFocus must not be called with NULL"); |
|
1206 return E_FAIL; |
|
1207 } |
|
1208 mFocusCount++; |
|
1209 if (mFocusedDocument == pdimFocus) { |
|
1210 return S_OK; |
|
1211 } |
|
1212 mFocusedDocument = static_cast<TSFDocumentMgrImpl*>(pdimFocus); |
|
1213 mFocusedDocument->AddRef(); |
|
1214 return S_OK; |
|
1215 } |
|
1216 |
|
1217 STDMETHODIMP AssociateFocus(HWND hwnd, ITfDocumentMgr *pdimNew, |
|
1218 ITfDocumentMgr **ppdimPrev) |
|
1219 { |
|
1220 NS_NOTREACHED("ITfThreadMgr::AssociateFocus"); |
|
1221 return E_NOTIMPL; |
|
1222 } |
|
1223 |
|
1224 STDMETHODIMP IsThreadFocus(BOOL *pfThreadFocus) |
|
1225 { |
|
1226 *pfThreadFocus = TRUE; |
|
1227 return S_OK; |
|
1228 } |
|
1229 |
|
1230 STDMETHODIMP GetFunctionProvider(REFCLSID clsid, |
|
1231 ITfFunctionProvider **ppFuncProv) |
|
1232 { |
|
1233 NS_NOTREACHED("ITfThreadMgr::GetFunctionProvider"); |
|
1234 return E_NOTIMPL; |
|
1235 } |
|
1236 |
|
1237 STDMETHODIMP EnumFunctionProviders(IEnumTfFunctionProviders **ppEnum) |
|
1238 { |
|
1239 NS_NOTREACHED("ITfThreadMgr::EnumFunctionProviders"); |
|
1240 return E_NOTIMPL; |
|
1241 } |
|
1242 |
|
1243 STDMETHODIMP GetGlobalCompartment(ITfCompartmentMgr **ppCompMgr) |
|
1244 { |
|
1245 NS_NOTREACHED("ITfThreadMgr::GetGlobalCompartment"); |
|
1246 return E_NOTIMPL; |
|
1247 } |
|
1248 |
|
1249 public: // ITfCategoryMgr |
|
1250 |
|
1251 STDMETHODIMP RegisterCategory(REFCLSID rclsid, REFGUID rcatid, REFGUID rguid) |
|
1252 { |
|
1253 NS_NOTREACHED("ITfCategoryMgr::RegisterCategory"); |
|
1254 return E_NOTIMPL; |
|
1255 } |
|
1256 |
|
1257 STDMETHODIMP UnregisterCategory(REFCLSID rclsid, REFGUID rcatid, REFGUID rguid) |
|
1258 { |
|
1259 NS_NOTREACHED("ITfCategoryMgr::UnregisterCategory"); |
|
1260 return E_NOTIMPL; |
|
1261 } |
|
1262 |
|
1263 STDMETHODIMP EnumCategoriesInItem(REFGUID rguid, IEnumGUID **ppEnum) |
|
1264 { |
|
1265 NS_NOTREACHED("ITfCategoryMgr::EnumCategoriesInItem"); |
|
1266 return E_NOTIMPL; |
|
1267 } |
|
1268 |
|
1269 STDMETHODIMP EnumItemsInCategory(REFGUID rcatid, IEnumGUID **ppEnum) |
|
1270 { |
|
1271 NS_NOTREACHED("ITfCategoryMgr::EnumItemsInCategory"); |
|
1272 return E_NOTIMPL; |
|
1273 } |
|
1274 |
|
1275 STDMETHODIMP FindClosestCategory(REFGUID rguid, GUID *pcatid, |
|
1276 const GUID **ppcatidList, ULONG ulCount) |
|
1277 { |
|
1278 NS_NOTREACHED("ITfCategoryMgr::FindClosestCategory"); |
|
1279 return E_NOTIMPL; |
|
1280 } |
|
1281 |
|
1282 STDMETHODIMP RegisterGUIDDescription(REFCLSID rclsid, REFGUID rguid, |
|
1283 const WCHAR *pchDesc, ULONG cch) |
|
1284 { |
|
1285 NS_NOTREACHED("ITfCategoryMgr::RegisterGUIDDescription"); |
|
1286 return E_NOTIMPL; |
|
1287 } |
|
1288 |
|
1289 STDMETHODIMP UnregisterGUIDDescription(REFCLSID rclsid, REFGUID rguid) |
|
1290 { |
|
1291 NS_NOTREACHED("ITfCategoryMgr::UnregisterGUIDDescription"); |
|
1292 return E_NOTIMPL; |
|
1293 } |
|
1294 |
|
1295 STDMETHODIMP GetGUIDDescription(REFGUID rguid, BSTR *pbstrDesc) |
|
1296 { |
|
1297 NS_NOTREACHED("ITfCategoryMgr::GetGUIDDescription"); |
|
1298 return E_NOTIMPL; |
|
1299 } |
|
1300 |
|
1301 STDMETHODIMP RegisterGUIDDWORD(REFCLSID rclsid, REFGUID rguid, DWORD dw) |
|
1302 { |
|
1303 NS_NOTREACHED("ITfCategoryMgr::RegisterGUIDDWORD"); |
|
1304 return E_NOTIMPL; |
|
1305 } |
|
1306 |
|
1307 STDMETHODIMP UnregisterGUIDDWORD(REFCLSID rclsid, REFGUID rguid) |
|
1308 { |
|
1309 NS_NOTREACHED("ITfCategoryMgr::UnregisterGUIDDWORD"); |
|
1310 return E_NOTIMPL; |
|
1311 } |
|
1312 |
|
1313 STDMETHODIMP GetGUIDDWORD(REFGUID rguid, DWORD *pdw) |
|
1314 { |
|
1315 NS_NOTREACHED("ITfCategoryMgr::GetGUIDDWORD"); |
|
1316 return E_NOTIMPL; |
|
1317 } |
|
1318 |
|
1319 STDMETHODIMP RegisterGUID(REFGUID rguid, TfGuidAtom *pguidatom) |
|
1320 { |
|
1321 NS_NOTREACHED("ITfCategoryMgr::RegisterGUID"); |
|
1322 return E_NOTIMPL; |
|
1323 } |
|
1324 |
|
1325 STDMETHODIMP GetGUID(TfGuidAtom guidatom, GUID *pguid) |
|
1326 { |
|
1327 if (guidatom == GUID_ATOM_COMPOSING_SELECTION_ATTR) { |
|
1328 *pguid = GUID_COMPOSING_SELECTION_ATTR; |
|
1329 return S_OK; |
|
1330 } |
|
1331 NS_NOTREACHED("ITfCategoryMgr::GetGUID"); |
|
1332 return E_FAIL; |
|
1333 } |
|
1334 |
|
1335 STDMETHODIMP IsEqualTfGuidAtom(TfGuidAtom guidatom, REFGUID rguid, |
|
1336 BOOL *pfEqual) |
|
1337 { |
|
1338 NS_NOTREACHED("ITfCategoryMgr::IsEqualTfGuidAtom"); |
|
1339 return E_NOTIMPL; |
|
1340 } |
|
1341 |
|
1342 public: // ITfDisplayAttributeMgr |
|
1343 |
|
1344 STDMETHODIMP OnUpdateInfo() |
|
1345 { |
|
1346 NS_NOTREACHED("ITfDisplayAttributeMgr::OnUpdateInfo"); |
|
1347 return E_NOTIMPL; |
|
1348 } |
|
1349 |
|
1350 STDMETHODIMP EnumDisplayAttributeInfo(IEnumTfDisplayAttributeInfo **ppEnum) |
|
1351 { |
|
1352 NS_NOTREACHED("ITfDisplayAttributeMgr::EnumDisplayAttributeInfo"); |
|
1353 return E_NOTIMPL; |
|
1354 } |
|
1355 |
|
1356 STDMETHODIMP GetDisplayAttributeInfo(REFGUID guid, |
|
1357 ITfDisplayAttributeInfo **ppInfo, |
|
1358 CLSID *pclsidOwner) |
|
1359 { |
|
1360 NS_ENSURE_TRUE(ppInfo, E_INVALIDARG); |
|
1361 NS_ENSURE_TRUE(!pclsidOwner, E_INVALIDARG); |
|
1362 if (guid == GUID_COMPOSING_SELECTION_ATTR) { |
|
1363 (*ppInfo) = new TSFDispAttrInfoImpl(guid); |
|
1364 (*ppInfo)->AddRef(); |
|
1365 return S_OK; |
|
1366 } |
|
1367 NS_NOTREACHED("ITfDisplayAttributeMgr::GetDisplayAttributeInfo"); |
|
1368 return E_FAIL; |
|
1369 } |
|
1370 |
|
1371 public: |
|
1372 |
|
1373 ITextStoreACP* GetFocusedStore() |
|
1374 { |
|
1375 return mFocusedDocument ? mFocusedDocument->mStore : nullptr; |
|
1376 } |
|
1377 |
|
1378 TSFContextImpl* GetFocusedContext() |
|
1379 { |
|
1380 return mFocusedDocument ? mFocusedDocument->mContextBase : nullptr; |
|
1381 } |
|
1382 |
|
1383 TSFAttrPropImpl* GetFocusedAttrProp() |
|
1384 { |
|
1385 TSFContextImpl* context = GetFocusedContext(); |
|
1386 return context ? context->mAttrProp : nullptr; |
|
1387 } |
|
1388 |
|
1389 }; |
|
1390 |
|
1391 STDMETHODIMP |
|
1392 TSFContextImpl::OnLockGranted(DWORD dwLockFlags) |
|
1393 { |
|
1394 // If we have a test, run it |
|
1395 if (mDocMgr->mMgr->mTest && |
|
1396 !((*mDocMgr->mMgr->mTestApp).*(mDocMgr->mMgr->mTest))()) |
|
1397 return S_FALSE; |
|
1398 return S_OK; |
|
1399 } |
|
1400 |
|
1401 |
|
1402 STDMETHODIMP_(ULONG) |
|
1403 TSFDocumentMgrImpl::Release(void) |
|
1404 { |
|
1405 --mRefCnt; |
|
1406 if (mRefCnt == 1 && mMgr->mFocusedDocument == this) { |
|
1407 mMgr->mFocusedDocument = nullptr; |
|
1408 --mRefCnt; |
|
1409 } |
|
1410 if (mRefCnt) return mRefCnt; |
|
1411 delete this; |
|
1412 return 0; |
|
1413 } |
|
1414 |
|
1415 NS_IMPL_ISUPPORTS(TestApp, nsIWebProgressListener, |
|
1416 nsISupportsWeakReference) |
|
1417 |
|
1418 nsresult |
|
1419 TestApp::Run(void) |
|
1420 { |
|
1421 // Create a test window |
|
1422 // We need a full-fledged window to test for TSF functionality |
|
1423 nsresult rv; |
|
1424 mAppShell = do_GetService(kAppShellCID); |
|
1425 NS_ENSURE_TRUE(mAppShell, NS_ERROR_UNEXPECTED); |
|
1426 |
|
1427 nsCOMPtr<nsIAppShellService> appShellService( |
|
1428 do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); |
|
1429 NS_ENSURE_TRUE(appShellService, NS_ERROR_UNEXPECTED); |
|
1430 |
|
1431 nsCOMPtr<nsIURI> uri; |
|
1432 rv = NS_NewURI(getter_AddRefs(uri), "about:blank", nullptr); |
|
1433 NS_ENSURE_SUCCESS(rv, rv); |
|
1434 |
|
1435 rv = appShellService->CreateTopLevelWindow(nullptr, uri, |
|
1436 nsIWebBrowserChrome::CHROME_DEFAULT, |
|
1437 800 /*nsIAppShellService::SIZE_TO_CONTENT*/, |
|
1438 600 /*nsIAppShellService::SIZE_TO_CONTENT*/, |
|
1439 getter_AddRefs(mWindow)); |
|
1440 NS_ENSURE_SUCCESS(rv, rv); |
|
1441 |
|
1442 nsCOMPtr<nsIDocShell> docShell; |
|
1443 rv = mWindow->GetDocShell(getter_AddRefs(docShell)); |
|
1444 NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED); |
|
1445 nsCOMPtr<nsIWebProgress> progress(do_GetInterface(docShell)); |
|
1446 NS_ENSURE_TRUE(progress, NS_ERROR_UNEXPECTED); |
|
1447 rv = progress->AddProgressListener(this, |
|
1448 nsIWebProgress::NOTIFY_STATE_WINDOW | |
|
1449 nsIWebProgress::NOTIFY_STATUS); |
|
1450 NS_ENSURE_SUCCESS(rv, rv); |
|
1451 |
|
1452 mAppShell->Run(); |
|
1453 return NS_OK; |
|
1454 } |
|
1455 |
|
1456 bool |
|
1457 TestApp::CheckFailed(void) |
|
1458 { |
|
1459 // All windows should be closed by now |
|
1460 if (mMgr && !mMgr->mDeactivated) { |
|
1461 fail("TSF not terminated properly"); |
|
1462 mFailed = true; |
|
1463 } |
|
1464 mMgr = nullptr; |
|
1465 return mFailed; |
|
1466 } |
|
1467 |
|
1468 nsresult |
|
1469 TestApp::Init(void) |
|
1470 { |
|
1471 // Replace TSF manager pointer, category manager pointer and display |
|
1472 // attribute manager pointer. |
|
1473 nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(mWindow)); |
|
1474 NS_ENSURE_TRUE(baseWindow, NS_ERROR_UNEXPECTED); |
|
1475 nsCOMPtr<nsIWidget> widget; |
|
1476 nsresult rv = baseWindow->GetMainWidget(getter_AddRefs(widget)); |
|
1477 NS_ENSURE_TRUE(widget, NS_ERROR_UNEXPECTED); |
|
1478 |
|
1479 ITfThreadMgr **threadMgr = reinterpret_cast<ITfThreadMgr**>( |
|
1480 widget->GetNativeData(NS_NATIVE_TSF_THREAD_MGR)); |
|
1481 if (!threadMgr) { |
|
1482 fail("nsIWidget::GetNativeData(NS_NATIVE_TSF_THREAD_MGR) not supported"); |
|
1483 return NS_ERROR_FAILURE; |
|
1484 } |
|
1485 if (*threadMgr) { |
|
1486 (*threadMgr)->Deactivate(); |
|
1487 (*threadMgr)->Release(); |
|
1488 (*threadMgr) = nullptr; |
|
1489 } else { |
|
1490 // This is only for information. The test does not need TSF to run. |
|
1491 printf("TSF not initialized properly (TSF is not enabled/installed?)\n"); |
|
1492 } |
|
1493 |
|
1494 ITfCategoryMgr **catMgr = reinterpret_cast<ITfCategoryMgr**>( |
|
1495 widget->GetNativeData(NS_NATIVE_TSF_CATEGORY_MGR)); |
|
1496 if (*catMgr) { |
|
1497 (*catMgr)->Release(); |
|
1498 (*catMgr) = nullptr; |
|
1499 } |
|
1500 ITfDisplayAttributeMgr **daMgr = reinterpret_cast<ITfDisplayAttributeMgr**>( |
|
1501 widget->GetNativeData(NS_NATIVE_TSF_DISPLAY_ATTR_MGR)); |
|
1502 if (*daMgr) { |
|
1503 (*daMgr)->Release(); |
|
1504 (*daMgr) = nullptr; |
|
1505 } |
|
1506 |
|
1507 mMgr = new TSFMgrImpl(this); |
|
1508 if (!mMgr) { |
|
1509 return NS_ERROR_OUT_OF_MEMORY; |
|
1510 } |
|
1511 (*threadMgr) = mMgr; |
|
1512 (*threadMgr)->AddRef(); |
|
1513 (*catMgr) = mMgr; |
|
1514 (*catMgr)->AddRef(); |
|
1515 (*daMgr) = mMgr; |
|
1516 (*daMgr)->AddRef(); |
|
1517 |
|
1518 // Apply the change |
|
1519 reinterpret_cast<ITfThreadMgr**>( |
|
1520 widget->GetNativeData(NS_NATIVE_TSF_THREAD_MGR)); |
|
1521 |
|
1522 // Create a couple of text boxes for testing |
|
1523 nsCOMPtr<nsIDOMWindow> win(do_GetInterface(mWindow)); |
|
1524 NS_ENSURE_TRUE(win, NS_ERROR_UNEXPECTED); |
|
1525 nsCOMPtr<nsIDOMDocument> document; |
|
1526 rv = win->GetDocument(getter_AddRefs(document)); |
|
1527 NS_ENSURE_TRUE(document, NS_ERROR_UNEXPECTED); |
|
1528 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(document)); |
|
1529 NS_ENSURE_TRUE(htmlDoc, NS_ERROR_UNEXPECTED); |
|
1530 nsCOMPtr<nsIDOMHTMLElement> htmlBody; |
|
1531 rv = htmlDoc->GetBody(getter_AddRefs(htmlBody)); |
|
1532 NS_ENSURE_TRUE(htmlBody, NS_ERROR_UNEXPECTED); |
|
1533 |
|
1534 nsCOMPtr<nsIDOMElement> form; |
|
1535 rv = htmlDoc->CreateElementNS( |
|
1536 NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"), |
|
1537 NS_LITERAL_STRING("form"), |
|
1538 getter_AddRefs(form)); |
|
1539 nsCOMPtr<nsIDOMElement> elem; |
|
1540 rv = htmlDoc->CreateElementNS( |
|
1541 NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"), |
|
1542 NS_LITERAL_STRING("input"), |
|
1543 getter_AddRefs(elem)); |
|
1544 NS_ENSURE_SUCCESS(rv, rv); |
|
1545 elem->SetAttribute(NS_LITERAL_STRING("type"), |
|
1546 NS_LITERAL_STRING("text")); |
|
1547 mInput = do_QueryInterface(elem); |
|
1548 NS_ENSURE_TRUE(mInput, NS_ERROR_UNEXPECTED); |
|
1549 rv = htmlDoc->CreateElementNS( |
|
1550 NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"), |
|
1551 NS_LITERAL_STRING("textarea"), |
|
1552 getter_AddRefs(elem)); |
|
1553 NS_ENSURE_SUCCESS(rv, rv); |
|
1554 mTextArea = do_QueryInterface(elem); |
|
1555 NS_ENSURE_TRUE(mTextArea, NS_ERROR_UNEXPECTED); |
|
1556 rv = htmlDoc->CreateElementNS( |
|
1557 NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"), |
|
1558 NS_LITERAL_STRING("input"), |
|
1559 getter_AddRefs(elem)); |
|
1560 NS_ENSURE_SUCCESS(rv, rv); |
|
1561 elem->SetAttribute(NS_LITERAL_STRING("type"), |
|
1562 NS_LITERAL_STRING("button")); |
|
1563 mButton = do_QueryInterface(elem); |
|
1564 NS_ENSURE_TRUE(mButton, NS_ERROR_UNEXPECTED); |
|
1565 |
|
1566 nsCOMPtr<nsIDOMNode> node; |
|
1567 rv = form->AppendChild(mInput, getter_AddRefs(node)); |
|
1568 NS_ENSURE_SUCCESS(rv, rv); |
|
1569 rv = form->AppendChild(mTextArea, getter_AddRefs(node)); |
|
1570 NS_ENSURE_SUCCESS(rv, rv); |
|
1571 rv = form->AppendChild(mButton, getter_AddRefs(node)); |
|
1572 NS_ENSURE_SUCCESS(rv, rv); |
|
1573 rv = htmlBody->AppendChild(form, getter_AddRefs(node)); |
|
1574 NS_ENSURE_SUCCESS(rv, rv); |
|
1575 |
|
1576 // set a background color manually, |
|
1577 // otherwise the window might be transparent |
|
1578 static_cast<HTMLBodyElement*>(htmlBody)-> |
|
1579 SetBgColor(NS_LITERAL_STRING("white")); |
|
1580 |
|
1581 widget->Show(true); |
|
1582 widget->SetFocus(); |
|
1583 return NS_OK; |
|
1584 } |
|
1585 |
|
1586 nsresult |
|
1587 TestApp::Term(void) |
|
1588 { |
|
1589 mCurrentNode = nullptr; |
|
1590 mInput = nullptr; |
|
1591 mTextArea = nullptr; |
|
1592 mButton = nullptr; |
|
1593 |
|
1594 nsCOMPtr<nsIDOMWindow> win(do_GetInterface(mWindow)); |
|
1595 if (win) |
|
1596 win->Close(); |
|
1597 win = nullptr; |
|
1598 mWindow = nullptr; |
|
1599 |
|
1600 if (mAppShell) |
|
1601 mAppShell->Exit(); |
|
1602 mAppShell = nullptr; |
|
1603 return NS_OK; |
|
1604 } |
|
1605 |
|
1606 bool |
|
1607 TestApp::RunTest(test_type aTest, bool aLock) |
|
1608 { |
|
1609 bool succeeded; |
|
1610 if (aLock && mMgr && mMgr->GetFocusedStore()) { |
|
1611 mMgr->mTest = aTest; |
|
1612 HRESULT hr = E_FAIL; |
|
1613 mMgr->GetFocusedStore()->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &hr); |
|
1614 succeeded = hr == S_OK; |
|
1615 } else { |
|
1616 succeeded = (this->*aTest)(); |
|
1617 } |
|
1618 mFailed |= !succeeded; |
|
1619 return succeeded; |
|
1620 } |
|
1621 |
|
1622 NS_IMETHODIMP |
|
1623 TestApp::OnStateChange(nsIWebProgress *aWebProgress, |
|
1624 nsIRequest *aRequest, |
|
1625 uint32_t aStateFlags, |
|
1626 nsresult aStatus) |
|
1627 { |
|
1628 NS_ASSERTION(aStateFlags & nsIWebProgressListener::STATE_IS_WINDOW && |
|
1629 aStateFlags & nsIWebProgressListener::STATE_STOP, "wrong state"); |
|
1630 if (NS_SUCCEEDED(Init())) { |
|
1631 mCurrentNode = mTextArea; |
|
1632 mTextArea->Focus(); |
|
1633 |
|
1634 if (RunTest(&TestApp::TestEditMessages)) |
|
1635 passed("TestEditMessages"); |
|
1636 if (RunTest(&TestApp::TestScrollMessages)) |
|
1637 passed("TestScrollMessages"); |
|
1638 |
|
1639 if (RunTest(&TestApp::TestFocus, false)) |
|
1640 passed("TestFocus"); |
|
1641 |
|
1642 mCurrentNode = mInput; |
|
1643 mInput->Focus(); |
|
1644 if (mMgr->GetFocusedStore()) { |
|
1645 if (RunTest(&TestApp::TestClustering)) |
|
1646 passed("TestClustering"); |
|
1647 } else { |
|
1648 fail("no text store (clustering)"); |
|
1649 mFailed = true; |
|
1650 } |
|
1651 |
|
1652 printf("Testing TSF support in text input element...\n"); |
|
1653 mCurrentNode = mInput; |
|
1654 mTestString = NS_LITERAL_STRING( |
|
1655 "This is a test of the Text Services Framework implementation."); |
|
1656 mInput->SetValue(mTestString); |
|
1657 mInput->Focus(); |
|
1658 if (mMgr->GetFocusedStore()) { |
|
1659 if (RunTest(&TestApp::TestSelection)) |
|
1660 passed("TestSelection (input)"); |
|
1661 if (RunTest(&TestApp::TestText)) |
|
1662 passed("TestText (input)"); |
|
1663 if (RunTest(&TestApp::TestExtents)) |
|
1664 passed("TestExtents (input)"); |
|
1665 if (RunTest(&TestApp::TestComposition)) |
|
1666 passed("TestComposition (input)"); |
|
1667 if (RunTest(&TestApp::TestNotification, false)) |
|
1668 passed("TestNotification (input)"); |
|
1669 } else { |
|
1670 fail("no text store (input)"); |
|
1671 mFailed = true; |
|
1672 } |
|
1673 |
|
1674 printf("Testing TSF support in textarea element...\n"); |
|
1675 mCurrentNode = mTextArea; |
|
1676 mTestString = NS_LITERAL_STRING( |
|
1677 "This is a test of the\r\nText Services Framework\r\nimplementation."); |
|
1678 mTextArea->SetValue(mTestString); |
|
1679 mTextArea->Focus(); |
|
1680 if (mMgr->GetFocusedStore()) { |
|
1681 if (RunTest(&TestApp::TestSelection)) |
|
1682 passed("TestSelection (textarea)"); |
|
1683 if (RunTest(&TestApp::TestText)) |
|
1684 passed("TestText (textarea)"); |
|
1685 if (RunTest(&TestApp::TestExtents)) |
|
1686 passed("TestExtents (textarea)"); |
|
1687 if (RunTest(&TestApp::TestComposition)) |
|
1688 passed("TestComposition (textarea)"); |
|
1689 if (RunTest(&TestApp::TestNotification, false)) |
|
1690 passed("TestNotification (textarea)"); |
|
1691 } else { |
|
1692 fail("no text store (textarea)"); |
|
1693 mFailed = true; |
|
1694 } |
|
1695 } else { |
|
1696 fail("initialization"); |
|
1697 mFailed = true; |
|
1698 } |
|
1699 Term(); |
|
1700 return NS_OK; |
|
1701 } |
|
1702 |
|
1703 bool |
|
1704 TestApp::TestFocus(void) |
|
1705 { |
|
1706 uint32_t focus = mMgr->mFocusCount; |
|
1707 nsresult rv; |
|
1708 |
|
1709 /* If these fail the cause is probably one or more of: |
|
1710 * - nsIMEStateManager::OnTextStateFocus not called by nsEventStateManager |
|
1711 * - nsIMEStateManager::OnTextStateBlur not called by nsEventStateManager |
|
1712 * - nsWindow::OnIMEFocusChange (nsIWidget) not called by nsIMEStateManager |
|
1713 * - nsTextStore::Create/Focus/Destroy not called by nsWindow |
|
1714 * - ITfThreadMgr::CreateDocumentMgr/SetFocus not called by nsTextStore |
|
1715 * - ITfDocumentMgr::CreateContext/Push not called by nsTextStore |
|
1716 */ |
|
1717 |
|
1718 rv = mInput->Focus(); |
|
1719 if (!(NS_SUCCEEDED(rv) && |
|
1720 mMgr->mFocusedDocument && |
|
1721 mMgr->mFocusCount - focus == 1 && |
|
1722 mMgr->GetFocusedStore())) { |
|
1723 fail("TestFocus: document focus was not set"); |
|
1724 return false; |
|
1725 } |
|
1726 |
|
1727 rv = mTextArea->Focus(); |
|
1728 if (!(NS_SUCCEEDED(rv) && |
|
1729 mMgr->mFocusedDocument && |
|
1730 mMgr->mFocusCount - focus == 2 && |
|
1731 mMgr->GetFocusedStore())) { |
|
1732 fail("TestFocus: document focus was not changed"); |
|
1733 return false; |
|
1734 } |
|
1735 |
|
1736 rv = mButton->Focus(); |
|
1737 if (!(NS_SUCCEEDED(rv) && |
|
1738 !mMgr->mFocusedDocument && |
|
1739 mMgr->mFocusCount - focus == 2 && |
|
1740 !mMgr->GetFocusedStore())) { |
|
1741 fail("TestFocus: document focus was changed"); |
|
1742 return false; |
|
1743 } |
|
1744 return true; |
|
1745 } |
|
1746 |
|
1747 bool |
|
1748 TestApp::TestClustering(void) |
|
1749 { |
|
1750 // Text for testing |
|
1751 const uint32_t STRING_LENGTH = 2; |
|
1752 char16_t string[3]; |
|
1753 string[0] = 'e'; |
|
1754 string[1] = 0x0301; // U+0301 'acute accent' |
|
1755 string[2] = nullptr; |
|
1756 |
|
1757 if (!mMgr->GetFocusedStore()) { |
|
1758 fail("TestClustering: GetFocusedStore returns null #1"); |
|
1759 return false; |
|
1760 } |
|
1761 |
|
1762 // Replace entire string with our string |
|
1763 TS_TEXTCHANGE textChange; |
|
1764 HRESULT hr = |
|
1765 mMgr->GetFocusedStore()->SetText(0, 0, -1, string, STRING_LENGTH, |
|
1766 &textChange); |
|
1767 if (!(SUCCEEDED(hr) && |
|
1768 0 == textChange.acpStart && |
|
1769 STRING_LENGTH == textChange.acpNewEnd)) { |
|
1770 fail("TestClustering: SetText"); |
|
1771 return false; |
|
1772 } |
|
1773 |
|
1774 TsViewCookie view; |
|
1775 RECT rectLetter, rectAccent, rectWhole, rectCombined; |
|
1776 BOOL clipped, nonEmpty; |
|
1777 |
|
1778 if (!mMgr->GetFocusedStore()) { |
|
1779 fail("TestClustering: GetFocusedStore returns null #2"); |
|
1780 return false; |
|
1781 } |
|
1782 |
|
1783 hr = mMgr->GetFocusedStore()->GetActiveView(&view); |
|
1784 if (!(SUCCEEDED(hr))) { |
|
1785 fail("TestClustering: GetActiveView"); |
|
1786 return false; |
|
1787 } |
|
1788 |
|
1789 if (!mMgr->GetFocusedStore()) { |
|
1790 fail("TestClustering: GetFocusedStore returns null #3"); |
|
1791 return false; |
|
1792 } |
|
1793 |
|
1794 // Get rect of first char (the letter) |
|
1795 hr = mMgr->GetFocusedStore()->GetTextExt(view, 0, STRING_LENGTH / 2, |
|
1796 &rectLetter, &clipped); |
|
1797 if (!(SUCCEEDED(hr))) { |
|
1798 fail("TestClustering: GetTextExt (letter)"); |
|
1799 return false; |
|
1800 } |
|
1801 |
|
1802 if (!mMgr->GetFocusedStore()) { |
|
1803 fail("TestClustering: GetFocusedStore returns null #4"); |
|
1804 return false; |
|
1805 } |
|
1806 |
|
1807 // Get rect of second char (the accent) |
|
1808 hr = mMgr->GetFocusedStore()->GetTextExt(view, STRING_LENGTH / 2, |
|
1809 STRING_LENGTH, |
|
1810 &rectAccent, &clipped); |
|
1811 if (!(SUCCEEDED(hr))) { |
|
1812 fail("TestClustering: GetTextExt (accent)"); |
|
1813 return false; |
|
1814 } |
|
1815 |
|
1816 if (!mMgr->GetFocusedStore()) { |
|
1817 fail("TestClustering: GetFocusedStore returns null #5"); |
|
1818 return false; |
|
1819 } |
|
1820 |
|
1821 // Get rect of combined char |
|
1822 hr = mMgr->GetFocusedStore()->GetTextExt(view, 0, STRING_LENGTH, |
|
1823 &rectWhole, &clipped); |
|
1824 if (!(SUCCEEDED(hr))) { |
|
1825 fail("TestClustering: GetTextExt (whole)"); |
|
1826 return false; |
|
1827 } |
|
1828 |
|
1829 nonEmpty = ::UnionRect(&rectCombined, &rectLetter, &rectAccent); |
|
1830 if (!(nonEmpty && |
|
1831 ::EqualRect(&rectCombined, &rectWhole))) { |
|
1832 fail("TestClustering: unexpected combined rect"); |
|
1833 return false; |
|
1834 } |
|
1835 return true; |
|
1836 } |
|
1837 |
|
1838 bool |
|
1839 TestApp::TestSelectionInternal(char* aTestName, |
|
1840 LONG aStart, |
|
1841 LONG aEnd, |
|
1842 TsActiveSelEnd aSelEnd) |
|
1843 { |
|
1844 bool succeeded = true, continueTest = true; |
|
1845 TS_SELECTION_ACP sel, testSel; |
|
1846 ULONG selFetched; |
|
1847 |
|
1848 if (!mMgr->GetFocusedStore()) { |
|
1849 fail("TestSelectionInternal: GetFocusedStore returns null #1"); |
|
1850 return false; |
|
1851 } |
|
1852 |
|
1853 sel.acpStart = aStart; |
|
1854 sel.acpEnd = aEnd; |
|
1855 sel.style.ase = aSelEnd; |
|
1856 sel.style.fInterimChar = FALSE; |
|
1857 HRESULT hr = mMgr->GetFocusedStore()->SetSelection(1, &sel); |
|
1858 if (!(SUCCEEDED(hr))) { |
|
1859 fail("TestSelection: SetSelection (%s)", aTestName); |
|
1860 continueTest = succeeded = false; |
|
1861 } |
|
1862 |
|
1863 if (continueTest) { |
|
1864 if (!mMgr->GetFocusedStore()) { |
|
1865 fail("TestSelectionInternal: GetFocusedStore returns null #2"); |
|
1866 return false; |
|
1867 } |
|
1868 |
|
1869 hr = mMgr->GetFocusedStore()->GetSelection(TS_DEFAULT_SELECTION, 1, |
|
1870 &testSel, &selFetched); |
|
1871 if (!(SUCCEEDED(hr) && |
|
1872 selFetched == 1 && |
|
1873 !memcmp(&sel, &testSel, sizeof(sel)))) { |
|
1874 fail("TestSelection: unexpected GetSelection result (%s)", aTestName); |
|
1875 succeeded = false; |
|
1876 } |
|
1877 } |
|
1878 return succeeded; |
|
1879 } |
|
1880 |
|
1881 bool |
|
1882 TestApp::TestSelection(void) |
|
1883 { |
|
1884 bool succeeded = true; |
|
1885 |
|
1886 /* If these fail the cause is probably one or more of: |
|
1887 * nsTextStore::GetSelection not sending NS_QUERY_SELECTED_TEXT |
|
1888 * NS_QUERY_SELECTED_TEXT not handled by ContentEventHandler |
|
1889 * Bug in NS_QUERY_SELECTED_TEXT handler |
|
1890 * nsTextStore::SetSelection not sending NS_SELECTION_SET |
|
1891 * NS_SELECTION_SET not handled by ContentEventHandler |
|
1892 * Bug in NS_SELECTION_SET handler |
|
1893 */ |
|
1894 |
|
1895 TS_SELECTION_ACP testSel; |
|
1896 ULONG selFetched; |
|
1897 |
|
1898 if (!mMgr->GetFocusedStore()) { |
|
1899 fail("TestSelection: GetFocusedStore returns null"); |
|
1900 return false; |
|
1901 } |
|
1902 |
|
1903 HRESULT hr = |
|
1904 mMgr->GetFocusedStore()->GetSelection(0, 1, &testSel, &selFetched); |
|
1905 if (!(SUCCEEDED(hr) && |
|
1906 selFetched == 1)) { |
|
1907 fail("TestSelection: GetSelection"); |
|
1908 succeeded = false; |
|
1909 } |
|
1910 |
|
1911 const LONG SELECTION1_START = 0; |
|
1912 const LONG SELECTION1_END = mTestString.Length(); |
|
1913 const TsActiveSelEnd SELECTION1_SELEND = TS_AE_END; |
|
1914 |
|
1915 if (!TestSelectionInternal("normal", |
|
1916 SELECTION1_START, |
|
1917 SELECTION1_END, |
|
1918 SELECTION1_SELEND)) { |
|
1919 succeeded = false; |
|
1920 } |
|
1921 |
|
1922 const LONG SELECTION2_START = mTestString.Length() / 2; |
|
1923 const LONG SELECTION2_END = SELECTION2_START; |
|
1924 const TsActiveSelEnd SELECTION2_SELEND = TS_AE_END; |
|
1925 |
|
1926 if (!TestSelectionInternal("collapsed", |
|
1927 SELECTION2_START, |
|
1928 SELECTION2_END, |
|
1929 SELECTION2_SELEND)) { |
|
1930 succeeded = false; |
|
1931 } |
|
1932 |
|
1933 const LONG SELECTION3_START = 12; |
|
1934 const LONG SELECTION3_END = mTestString.Length() - 20; |
|
1935 const TsActiveSelEnd SELECTION3_SELEND = TS_AE_START; |
|
1936 |
|
1937 if (!TestSelectionInternal("reversed", |
|
1938 SELECTION3_START, |
|
1939 SELECTION3_END, |
|
1940 SELECTION3_SELEND)) { |
|
1941 succeeded = false; |
|
1942 } |
|
1943 return succeeded; |
|
1944 } |
|
1945 |
|
1946 bool |
|
1947 TestApp::TestText(void) |
|
1948 { |
|
1949 const uint32_t BUFFER_SIZE = (0x100); |
|
1950 const uint32_t RUNINFO_SIZE = (0x10); |
|
1951 |
|
1952 bool succeeded = true, continueTest; |
|
1953 char16_t buffer[BUFFER_SIZE]; |
|
1954 TS_RUNINFO runInfo[RUNINFO_SIZE]; |
|
1955 ULONG bufferRet, runInfoRet; |
|
1956 LONG acpRet, acpCurrent; |
|
1957 TS_TEXTCHANGE textChange; |
|
1958 HRESULT hr; |
|
1959 |
|
1960 /* If these fail the cause is probably one or more of: |
|
1961 * nsTextStore::GetText not sending NS_QUERY_TEXT_CONTENT |
|
1962 * NS_QUERY_TEXT_CONTENT not handled by ContentEventHandler |
|
1963 * Bug in NS_QUERY_TEXT_CONTENT handler |
|
1964 * nsTextStore::SetText not calling SetSelection or InsertTextAtSelection |
|
1965 * Bug in SetSelection or InsertTextAtSelection |
|
1966 * NS_SELECTION_SET bug or NS_COMPOSITION_* / NS_TEXT_TEXT bug |
|
1967 */ |
|
1968 |
|
1969 if (!mMgr->GetFocusedStore()) { |
|
1970 fail("TestText: GetFocusedStore returns null #1"); |
|
1971 return false; |
|
1972 } |
|
1973 |
|
1974 // Get all text |
|
1975 hr = mMgr->GetFocusedStore()->GetText(0, -1, buffer, BUFFER_SIZE, &bufferRet, |
|
1976 runInfo, RUNINFO_SIZE, &runInfoRet, |
|
1977 &acpRet); |
|
1978 if (!(SUCCEEDED(hr) && |
|
1979 bufferRet <= mTestString.Length() && |
|
1980 !wcsncmp(mTestString.get(), buffer, bufferRet) && |
|
1981 acpRet == LONG(bufferRet) && |
|
1982 runInfoRet > 0)) { |
|
1983 fail("TestText: GetText 1"); |
|
1984 succeeded = false; |
|
1985 } |
|
1986 |
|
1987 |
|
1988 if (!mMgr->GetFocusedStore()) { |
|
1989 fail("TestText: GetFocusedStore returns null #2"); |
|
1990 return false; |
|
1991 } |
|
1992 |
|
1993 // Get text from GETTEXT2_START to GETTEXT2_END |
|
1994 const uint32_t GETTEXT2_START = (18); |
|
1995 const uint32_t GETTEXT2_END = (mTestString.Length() - 16); |
|
1996 const uint32_t GETTEXT2_BUFFER_SIZE = (0x10); |
|
1997 |
|
1998 hr = mMgr->GetFocusedStore()->GetText(GETTEXT2_START, GETTEXT2_END, |
|
1999 buffer, GETTEXT2_BUFFER_SIZE, |
|
2000 &bufferRet, runInfo, RUNINFO_SIZE, |
|
2001 &runInfoRet, &acpRet); |
|
2002 if (!(SUCCEEDED(hr) && |
|
2003 bufferRet <= GETTEXT2_BUFFER_SIZE && |
|
2004 !wcsncmp(mTestString.get() + GETTEXT2_START, buffer, bufferRet) && |
|
2005 acpRet == LONG(bufferRet) + GETTEXT2_START && |
|
2006 runInfoRet > 0)) { |
|
2007 fail("TestText: GetText 2"); |
|
2008 succeeded = false; |
|
2009 } |
|
2010 |
|
2011 |
|
2012 if (!mMgr->GetFocusedStore()) { |
|
2013 fail("TestText: GetFocusedStore returns null #3"); |
|
2014 return false; |
|
2015 } |
|
2016 |
|
2017 // Replace text from SETTEXT1_START to SETTEXT1_END with insertString |
|
2018 const uint32_t SETTEXT1_START = (8); |
|
2019 const uint32_t SETTEXT1_TAIL_LENGTH = (40); |
|
2020 const uint32_t SETTEXT1_END = (mTestString.Length() - |
|
2021 SETTEXT1_TAIL_LENGTH); |
|
2022 NS_NAMED_LITERAL_STRING(insertString, "(Inserted string)"); |
|
2023 |
|
2024 continueTest = true; |
|
2025 hr = mMgr->GetFocusedStore()->SetText(0, SETTEXT1_START, SETTEXT1_END, |
|
2026 insertString.get(), |
|
2027 insertString.Length(), &textChange); |
|
2028 if (!(SUCCEEDED(hr) && |
|
2029 textChange.acpStart == SETTEXT1_START && |
|
2030 textChange.acpOldEnd == LONG(SETTEXT1_END) && |
|
2031 textChange.acpNewEnd == LONG(SETTEXT1_START + |
|
2032 insertString.Length()))) { |
|
2033 fail("TestText: SetText 1"); |
|
2034 continueTest = succeeded = false; |
|
2035 } |
|
2036 |
|
2037 const uint32_t SETTEXT1_FINAL_LENGTH = (SETTEXT1_START + |
|
2038 SETTEXT1_TAIL_LENGTH + |
|
2039 insertString.Length()); |
|
2040 |
|
2041 if (continueTest) { |
|
2042 acpCurrent = 0; |
|
2043 while (acpCurrent < LONG(SETTEXT1_FINAL_LENGTH)) { |
|
2044 if (!mMgr->GetFocusedStore()) { |
|
2045 fail("TestText: GetFocusedStore returns null #4"); |
|
2046 return false; |
|
2047 } |
|
2048 |
|
2049 hr = mMgr->GetFocusedStore()->GetText(acpCurrent, -1, &buffer[acpCurrent], |
|
2050 BUFFER_SIZE, &bufferRet, runInfo, |
|
2051 RUNINFO_SIZE, &runInfoRet, &acpRet); |
|
2052 if (!(SUCCEEDED(hr) && |
|
2053 acpRet > acpCurrent && |
|
2054 bufferRet <= SETTEXT1_FINAL_LENGTH && |
|
2055 runInfoRet > 0)) { |
|
2056 fail("TestText: GetText failed after SetTest 1"); |
|
2057 continueTest = succeeded = false; |
|
2058 break; |
|
2059 } |
|
2060 acpCurrent = acpRet; |
|
2061 } |
|
2062 } |
|
2063 |
|
2064 if (continueTest) { |
|
2065 if (!(acpCurrent == LONG(SETTEXT1_FINAL_LENGTH) && |
|
2066 !wcsncmp(buffer, mTestString.get(), SETTEXT1_START) && |
|
2067 !wcsncmp(&buffer[SETTEXT1_START], insertString.get(), |
|
2068 insertString.Length()) && |
|
2069 !wcsncmp(&buffer[SETTEXT1_START + insertString.Length()], |
|
2070 mTestString.get() + SETTEXT1_END, SETTEXT1_TAIL_LENGTH))) { |
|
2071 fail("TestText: unexpected GetText result after SetText 1"); |
|
2072 succeeded = false; |
|
2073 } |
|
2074 } |
|
2075 |
|
2076 |
|
2077 if (!mMgr->GetFocusedStore()) { |
|
2078 fail("TestText: GetFocusedStore returns null #5"); |
|
2079 return false; |
|
2080 } |
|
2081 |
|
2082 // Restore entire text to original text (mTestString) |
|
2083 continueTest = true; |
|
2084 hr = mMgr->GetFocusedStore()->SetText(0, 0, -1, mTestString.get(), |
|
2085 mTestString.Length(), &textChange); |
|
2086 if (!(SUCCEEDED(hr) && |
|
2087 textChange.acpStart == 0 && |
|
2088 textChange.acpOldEnd == LONG(SETTEXT1_FINAL_LENGTH) && |
|
2089 textChange.acpNewEnd == LONG(mTestString.Length()))) { |
|
2090 fail("TestText: SetText 2"); |
|
2091 continueTest = succeeded = false; |
|
2092 } |
|
2093 |
|
2094 if (continueTest) { |
|
2095 acpCurrent = 0; |
|
2096 while (acpCurrent < LONG(mTestString.Length())) { |
|
2097 if (!mMgr->GetFocusedStore()) { |
|
2098 fail("TestText: GetFocusedStore returns null #6"); |
|
2099 return false; |
|
2100 } |
|
2101 |
|
2102 hr = mMgr->GetFocusedStore()->GetText(acpCurrent, -1, &buffer[acpCurrent], |
|
2103 BUFFER_SIZE, &bufferRet, runInfo, |
|
2104 RUNINFO_SIZE, &runInfoRet, &acpRet); |
|
2105 if (!(SUCCEEDED(hr) && |
|
2106 acpRet > acpCurrent && |
|
2107 bufferRet <= mTestString.Length() && |
|
2108 runInfoRet > 0)) { |
|
2109 fail("TestText: GetText failed after SetText 2"); |
|
2110 continueTest = succeeded = false; |
|
2111 break; |
|
2112 } |
|
2113 acpCurrent = acpRet; |
|
2114 } |
|
2115 } |
|
2116 |
|
2117 if (continueTest) { |
|
2118 if (!(acpCurrent == LONG(mTestString.Length()) && |
|
2119 !wcsncmp(buffer, mTestString.get(), mTestString.Length()))) { |
|
2120 fail("TestText: unexpected GetText result after SetText 2"); |
|
2121 succeeded = false; |
|
2122 } |
|
2123 } |
|
2124 return succeeded; |
|
2125 } |
|
2126 |
|
2127 bool |
|
2128 TestApp::TestExtents(void) |
|
2129 { |
|
2130 if (!mMgr->GetFocusedStore()) { |
|
2131 fail("TestExtents: GetFocusedStore returns null #1"); |
|
2132 return false; |
|
2133 } |
|
2134 |
|
2135 TS_SELECTION_ACP sel; |
|
2136 sel.acpStart = 0; |
|
2137 sel.acpEnd = 0; |
|
2138 sel.style.ase = TS_AE_END; |
|
2139 sel.style.fInterimChar = FALSE; |
|
2140 mMgr->GetFocusedStore()->SetSelection(1, &sel); |
|
2141 |
|
2142 nsCOMPtr<nsISelectionController> selCon; |
|
2143 if (!(NS_SUCCEEDED(GetSelCon(getter_AddRefs(selCon))) && selCon)) { |
|
2144 fail("TestExtents: get nsISelectionController"); |
|
2145 return false; |
|
2146 } |
|
2147 selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, |
|
2148 nsISelectionController::SELECTION_FOCUS_REGION, true); |
|
2149 |
|
2150 nsCOMPtr<nsIDOMWindow> window(do_GetInterface(mWindow)); |
|
2151 if (!window) { |
|
2152 fail("TestExtents: get nsIDOMWindow"); |
|
2153 return false; |
|
2154 } |
|
2155 RECT windowRect, screenRect, textRect1, textRect2; |
|
2156 BOOL clipped; |
|
2157 int32_t val; |
|
2158 TsViewCookie view; |
|
2159 HRESULT hr; |
|
2160 |
|
2161 nsresult nsr = window->GetScreenX(&val); |
|
2162 windowRect.left = val; |
|
2163 nsr |= window->GetScreenY(&val); |
|
2164 windowRect.top = val; |
|
2165 nsr |= window->GetOuterWidth(&val); |
|
2166 windowRect.right = windowRect.left + val; |
|
2167 nsr |= window->GetOuterHeight(&val); |
|
2168 windowRect.bottom = windowRect.top + val; |
|
2169 if (!(NS_SUCCEEDED(nsr))) { |
|
2170 fail("TestExtents: get window rect failed"); |
|
2171 return false; |
|
2172 } |
|
2173 |
|
2174 if (!mMgr->GetFocusedStore()) { |
|
2175 fail("TestExtents: GetFocusedStore returns null #2"); |
|
2176 return false; |
|
2177 } |
|
2178 |
|
2179 hr = mMgr->GetFocusedStore()->GetActiveView(&view); |
|
2180 if (!(SUCCEEDED(hr))) { |
|
2181 fail("TestExtents: GetActiveView"); |
|
2182 return false; |
|
2183 } |
|
2184 |
|
2185 if (!mMgr->GetFocusedStore()) { |
|
2186 fail("TestExtents: GetFocusedStore returns null #3"); |
|
2187 return false; |
|
2188 } |
|
2189 |
|
2190 bool succeeded = true; |
|
2191 HWND hwnd; |
|
2192 hr = mMgr->GetFocusedStore()->GetWnd(view, &hwnd); |
|
2193 if (!(SUCCEEDED(hr) && |
|
2194 ::IsWindow(hwnd))) { |
|
2195 fail("TestExtents: GetWnd"); |
|
2196 succeeded = false; |
|
2197 } |
|
2198 |
|
2199 ::SetRectEmpty(&screenRect); |
|
2200 |
|
2201 if (!mMgr->GetFocusedStore()) { |
|
2202 fail("TestExtents: GetFocusedStore returns null #4"); |
|
2203 return false; |
|
2204 } |
|
2205 |
|
2206 hr = mMgr->GetFocusedStore()->GetScreenExt(view, &screenRect); |
|
2207 if (!(SUCCEEDED(hr) && |
|
2208 screenRect.left > windowRect.left && |
|
2209 screenRect.top > windowRect.top && |
|
2210 screenRect.right > screenRect.left && |
|
2211 screenRect.bottom > screenRect.top && |
|
2212 screenRect.right < windowRect.right && |
|
2213 screenRect.bottom < windowRect.bottom)) { |
|
2214 fail("TestExtents: GetScreenExt"); |
|
2215 succeeded = false; |
|
2216 } |
|
2217 |
|
2218 const LONG GETTEXTEXT1_START = 0; |
|
2219 const LONG GETTEXTEXT1_END = 0; |
|
2220 |
|
2221 ::SetRectEmpty(&textRect1); |
|
2222 |
|
2223 if (!mMgr->GetFocusedStore()) { |
|
2224 fail("TestExtents: GetFocusedStore returns null #5"); |
|
2225 return false; |
|
2226 } |
|
2227 |
|
2228 hr = mMgr->GetFocusedStore()->GetTextExt(view, GETTEXTEXT1_START, |
|
2229 GETTEXTEXT1_END, &textRect1, |
|
2230 &clipped); |
|
2231 if (!(SUCCEEDED(hr) && |
|
2232 textRect1.left >= screenRect.left && |
|
2233 textRect1.top >= screenRect.top && |
|
2234 textRect1.right < screenRect.right && |
|
2235 textRect1.bottom <= screenRect.bottom && |
|
2236 textRect1.right >= textRect1.left && |
|
2237 textRect1.bottom > textRect1.top)) { |
|
2238 fail("TestExtents: GetTextExt (offset %ld to %ld)", |
|
2239 GETTEXTEXT1_START, GETTEXTEXT1_END); |
|
2240 succeeded = false; |
|
2241 } |
|
2242 |
|
2243 const LONG GETTEXTEXT2_START = 10; |
|
2244 const LONG GETTEXTEXT2_END = 25; |
|
2245 |
|
2246 ::SetRectEmpty(&textRect2); |
|
2247 |
|
2248 if (!mMgr->GetFocusedStore()) { |
|
2249 fail("TestExtents: GetFocusedStore returns null #6"); |
|
2250 return false; |
|
2251 } |
|
2252 |
|
2253 hr = mMgr->GetFocusedStore()->GetTextExt(view, GETTEXTEXT2_START, |
|
2254 GETTEXTEXT2_END, &textRect2, |
|
2255 &clipped); |
|
2256 if (!(SUCCEEDED(hr) && |
|
2257 textRect2.left >= screenRect.left && |
|
2258 textRect2.top >= screenRect.top && |
|
2259 textRect2.right <= screenRect.right && |
|
2260 textRect2.bottom <= screenRect.bottom && |
|
2261 textRect2.right > textRect2.left && |
|
2262 textRect2.bottom > textRect2.top)) { |
|
2263 fail("TestExtents: GetTextExt (offset %ld to %ld)", |
|
2264 GETTEXTEXT2_START, GETTEXTEXT2_END); |
|
2265 succeeded = false; |
|
2266 } |
|
2267 |
|
2268 // Offsets must be between GETTEXTEXT2_START and GETTEXTEXT2_END |
|
2269 const LONG GETTEXTEXT3_START = 23; |
|
2270 const LONG GETTEXTEXT3_END = 23; |
|
2271 |
|
2272 ::SetRectEmpty(&textRect1); |
|
2273 |
|
2274 if (!mMgr->GetFocusedStore()) { |
|
2275 fail("TestExtents: GetFocusedStore returns null #7"); |
|
2276 return false; |
|
2277 } |
|
2278 |
|
2279 hr = mMgr->GetFocusedStore()->GetTextExt(view, GETTEXTEXT3_START, |
|
2280 GETTEXTEXT3_END, &textRect1, |
|
2281 &clipped); |
|
2282 // Rectangle must be entirely inside the previous rectangle, |
|
2283 // since GETTEXTEXT3_START and GETTEXTEXT3_END are between |
|
2284 // GETTEXTEXT2_START and GETTEXTEXT2_START |
|
2285 if (!(SUCCEEDED(hr) && ::IsRectEmpty(&textRect1) || |
|
2286 (textRect1.left >= textRect2.left && |
|
2287 textRect1.top >= textRect2.top && |
|
2288 textRect1.right <= textRect2.right && |
|
2289 textRect1.bottom <= textRect2.bottom && |
|
2290 textRect1.right >= textRect1.left && |
|
2291 textRect1.bottom > textRect1.top))) { |
|
2292 fail("TestExtents: GetTextExt (offset %ld to %ld)", |
|
2293 GETTEXTEXT3_START, GETTEXTEXT3_END); |
|
2294 succeeded = false; |
|
2295 } |
|
2296 return succeeded; |
|
2297 } |
|
2298 |
|
2299 bool |
|
2300 TestApp::TestCompositionSelectionAndText(char* aTestName, |
|
2301 LONG aExpectedSelStart, |
|
2302 LONG aExpectedSelEnd, |
|
2303 nsString& aReferenceString) |
|
2304 { |
|
2305 if (!mMgr->GetFocusedStore()) { |
|
2306 fail("TestCompositionSelectionAndText: GetFocusedStore returns null #1"); |
|
2307 return false; |
|
2308 } |
|
2309 |
|
2310 TS_SELECTION_ACP currentSel; |
|
2311 ULONG selFetched = 0; |
|
2312 HRESULT hr = mMgr->GetFocusedStore()->GetSelection(TF_DEFAULT_SELECTION, 1, |
|
2313 ¤tSel, &selFetched); |
|
2314 if (!(SUCCEEDED(hr) && |
|
2315 1 == selFetched && |
|
2316 currentSel.acpStart == aExpectedSelStart && |
|
2317 currentSel.acpEnd == aExpectedSelEnd)) { |
|
2318 fail("TestComposition: GetSelection (%s)", aTestName); |
|
2319 return false; |
|
2320 } |
|
2321 |
|
2322 const uint32_t bufferSize = 0x100, runInfoSize = 0x10; |
|
2323 char16_t buffer[bufferSize]; |
|
2324 TS_RUNINFO runInfo[runInfoSize]; |
|
2325 ULONG bufferRet, runInfoRet; |
|
2326 LONG acpRet, acpCurrent = 0; |
|
2327 while (acpCurrent < LONG(aReferenceString.Length())) { |
|
2328 if (!mMgr->GetFocusedStore()) { |
|
2329 fail("TestCompositionSelectionAndText: GetFocusedStore returns null #2"); |
|
2330 return false; |
|
2331 } |
|
2332 |
|
2333 hr = mMgr->GetFocusedStore()->GetText(acpCurrent, aReferenceString.Length(), |
|
2334 &buffer[acpCurrent], bufferSize, |
|
2335 &bufferRet, runInfo, runInfoSize, |
|
2336 &runInfoRet, &acpRet); |
|
2337 if (!(SUCCEEDED(hr) && |
|
2338 acpRet > acpCurrent && |
|
2339 bufferRet <= aReferenceString.Length() && |
|
2340 runInfoRet > 0)) { |
|
2341 fail("TestComposition: GetText (%s)", aTestName); |
|
2342 return false; |
|
2343 } |
|
2344 acpCurrent = acpRet; |
|
2345 } |
|
2346 if (!(acpCurrent == aReferenceString.Length() && |
|
2347 !wcsncmp(buffer, aReferenceString.get(), aReferenceString.Length()))) { |
|
2348 fail("TestComposition: unexpected GetText result (%s)", aTestName); |
|
2349 return false; |
|
2350 } |
|
2351 return true; |
|
2352 } |
|
2353 |
|
2354 bool |
|
2355 TestApp::TestComposition(void) |
|
2356 { |
|
2357 if (!mMgr->GetFocusedStore()) { |
|
2358 fail("TestComposition: GetFocusedStore returns null #1"); |
|
2359 return false; |
|
2360 } |
|
2361 |
|
2362 nsRefPtr<ITfContextOwnerCompositionSink> sink; |
|
2363 HRESULT hr = |
|
2364 mMgr->GetFocusedStore()->QueryInterface(IID_ITfContextOwnerCompositionSink, |
|
2365 getter_AddRefs(sink)); |
|
2366 if (!(SUCCEEDED(hr))) { |
|
2367 fail("TestComposition: QueryInterface"); |
|
2368 return false; |
|
2369 } |
|
2370 |
|
2371 const LONG PRECOMPOSITION_SEL_START = 2; |
|
2372 const LONG PRECOMPOSITION_SEL_END = PRECOMPOSITION_SEL_START; |
|
2373 const TsActiveSelEnd PRECOMPOSITION_SEL_SELEND = TS_AE_END; |
|
2374 |
|
2375 TS_SELECTION_ACP sel; |
|
2376 sel.acpStart = PRECOMPOSITION_SEL_START; |
|
2377 sel.acpEnd = PRECOMPOSITION_SEL_END; |
|
2378 sel.style.ase = PRECOMPOSITION_SEL_SELEND; |
|
2379 sel.style.fInterimChar = FALSE; |
|
2380 hr = mMgr->GetFocusedStore()->SetSelection(1, &sel); |
|
2381 if (!(SUCCEEDED(hr))) { |
|
2382 fail("TestComposition: SetSelection (pre-composition)"); |
|
2383 return false; |
|
2384 } |
|
2385 |
|
2386 if (!mMgr->GetFocusedStore()) { |
|
2387 fail("TestComposition: GetFocusedStore returns null #2"); |
|
2388 return false; |
|
2389 } |
|
2390 |
|
2391 TS_TEXTCHANGE textChange; |
|
2392 NS_NAMED_LITERAL_STRING(insertString1, "Compo1"); |
|
2393 hr = mMgr->GetFocusedStore()->InsertTextAtSelection(TF_IAS_NOQUERY, |
|
2394 insertString1.get(), |
|
2395 insertString1.Length(), |
|
2396 nullptr, nullptr, |
|
2397 &textChange); |
|
2398 if (!(SUCCEEDED(hr) && |
|
2399 sel.acpEnd == textChange.acpStart && |
|
2400 sel.acpEnd == textChange.acpOldEnd && |
|
2401 sel.acpEnd + insertString1.Length() == textChange.acpNewEnd)) { |
|
2402 fail("TestComposition: InsertTextAtSelection"); |
|
2403 return false; |
|
2404 } |
|
2405 sel.acpEnd = textChange.acpNewEnd; |
|
2406 |
|
2407 if (!mMgr->GetFocusedAttrProp()) { |
|
2408 fail("TestComposition: GetFocusedAttrProp returns null #1"); |
|
2409 return false; |
|
2410 } |
|
2411 mMgr->GetFocusedAttrProp()->mRanges.Clear(); |
|
2412 nsRefPtr<TSFRangeImpl> range = |
|
2413 new TSFRangeImpl(textChange.acpStart, |
|
2414 textChange.acpNewEnd - textChange.acpOldEnd); |
|
2415 if (!mMgr->GetFocusedAttrProp()) { |
|
2416 fail("TestComposition: GetFocusedAttrProp returns null #2"); |
|
2417 return false; |
|
2418 } |
|
2419 mMgr->GetFocusedAttrProp()->mRanges.AppendElement(range); |
|
2420 |
|
2421 BOOL okay = FALSE; |
|
2422 hr = sink->OnStartComposition(mMgr->GetFocusedContext(), &okay); |
|
2423 if (!(SUCCEEDED(hr) && |
|
2424 okay)) { |
|
2425 fail("TestComposition: OnStartComposition"); |
|
2426 return false; |
|
2427 } |
|
2428 |
|
2429 |
|
2430 if (!mMgr->GetFocusedStore()) { |
|
2431 fail("TestComposition: GetFocusedStore returns null #3"); |
|
2432 return false; |
|
2433 } |
|
2434 |
|
2435 NS_NAMED_LITERAL_STRING(insertString2, "Composition2"); |
|
2436 hr = mMgr->GetFocusedStore()->SetText(0, range->mStart + range->mLength, |
|
2437 range->mStart + range->mLength, |
|
2438 insertString2.get(), |
|
2439 insertString2.Length(), |
|
2440 &textChange); |
|
2441 if (!(SUCCEEDED(hr) && |
|
2442 sel.acpEnd == textChange.acpStart && |
|
2443 sel.acpEnd == textChange.acpOldEnd && |
|
2444 sel.acpEnd + insertString2.Length() == textChange.acpNewEnd)) { |
|
2445 fail("TestComposition: SetText 1"); |
|
2446 return false; |
|
2447 } |
|
2448 sel.acpEnd = textChange.acpNewEnd; |
|
2449 range->mLength += textChange.acpNewEnd - textChange.acpOldEnd; |
|
2450 |
|
2451 |
|
2452 if (!mMgr->GetFocusedStore()) { |
|
2453 fail("TestComposition: GetFocusedStore returns null #4"); |
|
2454 return false; |
|
2455 } |
|
2456 |
|
2457 const LONG COMPOSITION3_TEXT_START_OFFSET = -8; // offset 8 from the end |
|
2458 const LONG COMPOSITION3_TEXT_END_OFFSET = 4; |
|
2459 |
|
2460 const LONG COMPOSITION3_TEXT_START = range->mStart + range->mLength + |
|
2461 COMPOSITION3_TEXT_START_OFFSET; |
|
2462 const LONG COMPOSITION3_TEXT_END = COMPOSITION3_TEXT_START + |
|
2463 COMPOSITION3_TEXT_END_OFFSET; |
|
2464 |
|
2465 NS_NAMED_LITERAL_STRING(insertString3, "Compo3"); |
|
2466 hr = mMgr->GetFocusedStore()->SetText(0, COMPOSITION3_TEXT_START, |
|
2467 COMPOSITION3_TEXT_END, |
|
2468 insertString3.get(), |
|
2469 insertString3.Length(), |
|
2470 &textChange); |
|
2471 if (!(SUCCEEDED(hr) && |
|
2472 sel.acpEnd + COMPOSITION3_TEXT_START_OFFSET == textChange.acpStart && |
|
2473 sel.acpEnd + COMPOSITION3_TEXT_START_OFFSET + |
|
2474 COMPOSITION3_TEXT_END_OFFSET == textChange.acpOldEnd && |
|
2475 sel.acpEnd + insertString3.Length() + COMPOSITION3_TEXT_START_OFFSET == |
|
2476 textChange.acpNewEnd)) { |
|
2477 fail("TestComposition: SetText 2"); |
|
2478 return false; |
|
2479 } |
|
2480 sel.acpEnd = textChange.acpNewEnd; |
|
2481 range->mLength += textChange.acpNewEnd - textChange.acpOldEnd; |
|
2482 |
|
2483 |
|
2484 nsString referenceString; |
|
2485 referenceString.Append(mTestString.get(), sel.acpStart); |
|
2486 referenceString.Append(insertString1); |
|
2487 referenceString.Append(insertString2.get(), |
|
2488 insertString2.Length() + COMPOSITION3_TEXT_START_OFFSET); |
|
2489 referenceString.Append(insertString3); |
|
2490 referenceString.Append(insertString2.get() + insertString2.Length() - |
|
2491 COMPOSITION3_TEXT_END_OFFSET, COMPOSITION3_TEXT_END_OFFSET); |
|
2492 referenceString.Append(mTestString.get() + sel.acpStart, |
|
2493 COMPOSITION3_TEXT_END_OFFSET); |
|
2494 |
|
2495 if (!TestCompositionSelectionAndText("composition", |
|
2496 sel.acpEnd, sel.acpEnd, |
|
2497 referenceString)) |
|
2498 return false; |
|
2499 |
|
2500 |
|
2501 if (!mMgr->GetFocusedStore()) { |
|
2502 fail("TestComposition: GetFocusedStore returns null #5"); |
|
2503 return false; |
|
2504 } |
|
2505 |
|
2506 const LONG POSTCOMPOSITION_SEL_START = sel.acpEnd - 8; |
|
2507 const LONG POSTCOMPOSITION_SEL_END = POSTCOMPOSITION_SEL_START + 2; |
|
2508 |
|
2509 sel.acpStart = POSTCOMPOSITION_SEL_START; |
|
2510 sel.acpEnd = POSTCOMPOSITION_SEL_END; |
|
2511 hr = mMgr->GetFocusedStore()->SetSelection(1, &sel); |
|
2512 if (!(SUCCEEDED(hr))) { |
|
2513 fail("TestComposition: SetSelection (composition)"); |
|
2514 return false; |
|
2515 } |
|
2516 |
|
2517 if (!mMgr->GetFocusedAttrProp()) { |
|
2518 fail("TestComposition: GetFocusedAttrProp returns null #3"); |
|
2519 return false; |
|
2520 } |
|
2521 mMgr->GetFocusedAttrProp()->mRanges.Clear(); |
|
2522 |
|
2523 hr = sink->OnEndComposition(mMgr->GetFocusedContext()); |
|
2524 if (!(SUCCEEDED(hr))) { |
|
2525 fail("TestComposition: OnEndComposition"); |
|
2526 return false; |
|
2527 } |
|
2528 |
|
2529 if (!TestCompositionSelectionAndText("post-composition", |
|
2530 sel.acpStart, sel.acpEnd, |
|
2531 referenceString)) |
|
2532 return false; |
|
2533 |
|
2534 const LONG EMPTYCOMPOSITION_START = range->mStart + 2; |
|
2535 const LONG EMPTYCOMPOSITION_LENGTH = range->mLength - 4; |
|
2536 |
|
2537 range->mStart = EMPTYCOMPOSITION_START; |
|
2538 range->mLength = EMPTYCOMPOSITION_LENGTH; |
|
2539 if (!mMgr->GetFocusedAttrProp()) { |
|
2540 fail("TestComposition: GetFocusedAttrProp returns null #4"); |
|
2541 return false; |
|
2542 } |
|
2543 mMgr->GetFocusedAttrProp()->mRanges.AppendElement(range); |
|
2544 |
|
2545 okay = FALSE; |
|
2546 hr = sink->OnStartComposition(mMgr->GetFocusedContext(), &okay); |
|
2547 if (!(SUCCEEDED(hr) && |
|
2548 okay)) { |
|
2549 fail("TestComposition: OnStartComposition (empty composition)"); |
|
2550 return false; |
|
2551 } |
|
2552 |
|
2553 if (!mMgr->GetFocusedAttrProp()) { |
|
2554 fail("TestComposition: GetFocusedAttrProp returns null #5"); |
|
2555 return false; |
|
2556 } |
|
2557 mMgr->GetFocusedAttrProp()->mRanges.Clear(); |
|
2558 |
|
2559 hr = sink->OnEndComposition(mMgr->GetFocusedContext()); |
|
2560 if (!(SUCCEEDED(hr))) { |
|
2561 fail("TestComposition: OnEndComposition (empty composition)"); |
|
2562 return false; |
|
2563 } |
|
2564 |
|
2565 if (!TestCompositionSelectionAndText("empty composition", |
|
2566 range->mStart, range->mStart + range->mLength, |
|
2567 referenceString)) |
|
2568 return false; |
|
2569 |
|
2570 return true; |
|
2571 } |
|
2572 |
|
2573 bool |
|
2574 TestApp::TestNotificationTextChange(nsIWidget* aWidget, |
|
2575 uint32_t aCode, |
|
2576 const nsAString& aCharacter, |
|
2577 LONG aStart, |
|
2578 LONG aOldEnd, |
|
2579 LONG aNewEnd) |
|
2580 { |
|
2581 MSG msg; |
|
2582 if (::PeekMessageW(&msg, nullptr, WM_USER_TSF_TEXTCHANGE, |
|
2583 WM_USER_TSF_TEXTCHANGE, PM_REMOVE)) |
|
2584 ::DispatchMessageW(&msg); |
|
2585 if (!mMgr->GetFocusedContext()) { |
|
2586 fail("TestNotificationTextChange: GetFocusedContext returns null"); |
|
2587 return false; |
|
2588 } |
|
2589 mMgr->GetFocusedContext()->mTextChanged = false; |
|
2590 nsresult nsr = aWidget->SynthesizeNativeKeyEvent(0, aCode, 0, |
|
2591 aCharacter, aCharacter); |
|
2592 if (::PeekMessageW(&msg, nullptr, WM_USER_TSF_TEXTCHANGE, |
|
2593 WM_USER_TSF_TEXTCHANGE, PM_REMOVE)) |
|
2594 ::DispatchMessageW(&msg); |
|
2595 return NS_SUCCEEDED(nsr) && |
|
2596 mMgr->GetFocusedContext()->mTextChanged && |
|
2597 aStart == mMgr->GetFocusedContext()->mTextChangeData.acpStart && |
|
2598 aOldEnd == mMgr->GetFocusedContext()->mTextChangeData.acpOldEnd && |
|
2599 aNewEnd == mMgr->GetFocusedContext()->mTextChangeData.acpNewEnd; |
|
2600 } |
|
2601 |
|
2602 bool |
|
2603 TestApp::TestNotification(void) |
|
2604 { |
|
2605 nsresult nsr; |
|
2606 // get selection to test notification support |
|
2607 nsCOMPtr<nsISelectionController> selCon; |
|
2608 if (!(NS_SUCCEEDED(GetSelCon(getter_AddRefs(selCon))) && selCon)) { |
|
2609 fail("TestNotification: get nsISelectionController"); |
|
2610 return false; |
|
2611 } |
|
2612 |
|
2613 nsr = selCon->CompleteMove(false, false); |
|
2614 if (!(NS_SUCCEEDED(nsr))) { |
|
2615 fail("TestNotification: CompleteMove"); |
|
2616 return false; |
|
2617 } |
|
2618 |
|
2619 if (!mMgr->GetFocusedContext()) { |
|
2620 fail("TestNotification: GetFocusedContext returns null #1"); |
|
2621 return false; |
|
2622 } |
|
2623 |
|
2624 mMgr->GetFocusedContext()->mSelChanged = false; |
|
2625 nsr = selCon->CharacterMove(true, false); |
|
2626 if (!(NS_SUCCEEDED(nsr) && |
|
2627 mMgr->GetFocusedContext()->mSelChanged)) { |
|
2628 fail("TestNotification: CharacterMove"); |
|
2629 return false; |
|
2630 } |
|
2631 |
|
2632 if (!mMgr->GetFocusedContext()) { |
|
2633 fail("TestNotification: GetFocusedContext returns null #2"); |
|
2634 return false; |
|
2635 } |
|
2636 |
|
2637 mMgr->GetFocusedContext()->mSelChanged = false; |
|
2638 nsr = selCon->CharacterMove(true, true); |
|
2639 if (!(NS_SUCCEEDED(nsr) && |
|
2640 mMgr->GetFocusedContext()->mSelChanged)) { |
|
2641 fail("TestNotification: CharacterMove (extend)"); |
|
2642 return false; |
|
2643 } |
|
2644 |
|
2645 nsCOMPtr<nsIWidget> widget; |
|
2646 if (!GetWidget(getter_AddRefs(widget))) { |
|
2647 fail("TestNotification: get nsIWidget"); |
|
2648 return false; |
|
2649 } |
|
2650 |
|
2651 NS_NAMED_LITERAL_STRING(character, ""); |
|
2652 NS_NAMED_LITERAL_STRING(characterA, "A"); |
|
2653 |
|
2654 // The selection test code above placed the selection at offset 1 to 2 |
|
2655 const LONG TEXTCHANGE1_START = 1; |
|
2656 const LONG TEXTCHANGE1_OLDEND = 2; |
|
2657 const LONG TEXTCHANGE1_NEWEND = 2; |
|
2658 |
|
2659 // replace single selected character with 'A' |
|
2660 if (!TestNotificationTextChange(widget, 'A', characterA, |
|
2661 TEXTCHANGE1_START, TEXTCHANGE1_OLDEND, TEXTCHANGE1_NEWEND)) { |
|
2662 fail("TestNotification: text change 1"); |
|
2663 return false; |
|
2664 } |
|
2665 |
|
2666 const LONG TEXTCHANGE2_START = TEXTCHANGE1_NEWEND; |
|
2667 const LONG TEXTCHANGE2_OLDEND = TEXTCHANGE1_NEWEND; |
|
2668 const LONG TEXTCHANGE2_NEWEND = TEXTCHANGE1_NEWEND + 1; |
|
2669 |
|
2670 // insert 'A' |
|
2671 if (!TestNotificationTextChange(widget, 'A', characterA, |
|
2672 TEXTCHANGE2_START, TEXTCHANGE2_OLDEND, TEXTCHANGE2_NEWEND)) { |
|
2673 fail("TestNotification: text change 2"); |
|
2674 return false; |
|
2675 } |
|
2676 |
|
2677 const LONG TEXTCHANGE3_START = TEXTCHANGE2_NEWEND - 1; |
|
2678 const LONG TEXTCHANGE3_OLDEND = TEXTCHANGE2_NEWEND; |
|
2679 const LONG TEXTCHANGE3_NEWEND = TEXTCHANGE2_NEWEND - 1; |
|
2680 |
|
2681 // backspace |
|
2682 if (!TestNotificationTextChange(widget, '\b', character, |
|
2683 TEXTCHANGE3_START, TEXTCHANGE3_OLDEND, TEXTCHANGE3_NEWEND)) { |
|
2684 fail("TestNotification: text change 3"); |
|
2685 return false; |
|
2686 } |
|
2687 return true; |
|
2688 } |
|
2689 |
|
2690 bool |
|
2691 TestApp::TestEditMessages(void) |
|
2692 { |
|
2693 mTestString = NS_LITERAL_STRING( |
|
2694 "This is a test of\nthe native editing command messages"); |
|
2695 // 0123456789012345678901 2345678901234567890123456789012 |
|
2696 // 0 1 2 3 4 5 |
|
2697 |
|
2698 // The native text string is increased by converting \n to \r\n. |
|
2699 uint32_t testStringLength = mTestString.Length() + 1; |
|
2700 |
|
2701 mTextArea->SetValue(mTestString); |
|
2702 mTextArea->Focus(); |
|
2703 |
|
2704 nsCOMPtr<nsIWidget> widget; |
|
2705 if (!GetWidget(getter_AddRefs(widget))) { |
|
2706 fail("TestEditMessages: get nsIWidget"); |
|
2707 return false; |
|
2708 } |
|
2709 |
|
2710 HWND wnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW); |
|
2711 bool result = true; |
|
2712 |
|
2713 if (!::SendMessage(wnd, EM_CANUNDO, 0, 0)) { |
|
2714 fail("TestEditMessages: EM_CANUNDO"); |
|
2715 return false; |
|
2716 } |
|
2717 |
|
2718 if (::SendMessage(wnd, EM_CANREDO, 0, 0)) { |
|
2719 fail("TestEditMessages: EM_CANREDO #1"); |
|
2720 return false; |
|
2721 } |
|
2722 |
|
2723 |
|
2724 if (!::SendMessage(wnd, EM_UNDO, 0, 0)) { |
|
2725 fail("TestEditMessages: EM_UNDO #1"); |
|
2726 return false; |
|
2727 } |
|
2728 |
|
2729 nsAutoString str; |
|
2730 mTextArea->GetValue(str); |
|
2731 if (str == mTestString) { |
|
2732 fail("TestEditMessage: EM_UNDO #1, failed to execute"); |
|
2733 printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get()); |
|
2734 return false; |
|
2735 } |
|
2736 |
|
2737 if (!::SendMessage(wnd, EM_CANREDO, 0, 0)) { |
|
2738 fail("TestEditMessages: EM_CANREDO #2"); |
|
2739 return false; |
|
2740 } |
|
2741 |
|
2742 if (!::SendMessage(wnd, EM_REDO, 0, 0)) { |
|
2743 fail("TestEditMessages: EM_REDO #1"); |
|
2744 return false; |
|
2745 } |
|
2746 |
|
2747 mTextArea->GetValue(str); |
|
2748 if (str != mTestString) { |
|
2749 fail("TestEditMessage: EM_REDO #1, failed to execute"); |
|
2750 printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get()); |
|
2751 return false; |
|
2752 } |
|
2753 |
|
2754 TS_SELECTION_ACP sel; |
|
2755 HRESULT hr; |
|
2756 |
|
2757 sel.acpStart = 0; |
|
2758 sel.acpEnd = testStringLength; |
|
2759 sel.style.ase = TS_AE_END; |
|
2760 sel.style.fInterimChar = FALSE; |
|
2761 hr = mMgr->GetFocusedStore()->SetSelection(1, &sel); |
|
2762 if (!(SUCCEEDED(hr))) { |
|
2763 fail("TestEditMessages: SetSelection #1"); |
|
2764 return false; |
|
2765 } |
|
2766 |
|
2767 ::SendMessage(wnd, WM_CUT, 0, 0); |
|
2768 mTextArea->GetValue(str); |
|
2769 if (!str.IsEmpty()) { |
|
2770 fail("TestEditMessages: WM_CUT"); |
|
2771 printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get()); |
|
2772 return false; |
|
2773 } |
|
2774 |
|
2775 ::SendMessage(wnd, WM_PASTE, 0, 0); |
|
2776 mTextArea->GetValue(str); |
|
2777 if (str != mTestString) { |
|
2778 fail("TestEditMessages: WM_PASTE #1"); |
|
2779 printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get()); |
|
2780 return false; |
|
2781 } |
|
2782 |
|
2783 ::SendMessage(wnd, WM_PASTE, 0, 0); |
|
2784 mTextArea->GetValue(str); |
|
2785 nsAutoString expectedStr(mTestString); |
|
2786 expectedStr += mTestString; |
|
2787 if (str != expectedStr) { |
|
2788 fail("TestEditMessages: WM_PASTE #2"); |
|
2789 printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get()); |
|
2790 return false; |
|
2791 } |
|
2792 |
|
2793 sel.acpStart = 0; |
|
2794 sel.acpEnd = testStringLength; |
|
2795 hr = mMgr->GetFocusedStore()->SetSelection(1, &sel); |
|
2796 if (!(SUCCEEDED(hr))) { |
|
2797 fail("TestEditMessages: SetSelection #2"); |
|
2798 return false; |
|
2799 } |
|
2800 |
|
2801 ::SendMessage(wnd, WM_CLEAR, 0, 0); |
|
2802 mTextArea->GetValue(str); |
|
2803 if (str != mTestString) { |
|
2804 fail("TestEditMessages: WM_CLEAR #1"); |
|
2805 printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get()); |
|
2806 return false; |
|
2807 } |
|
2808 |
|
2809 sel.acpStart = 4; |
|
2810 sel.acpEnd = testStringLength; |
|
2811 hr = mMgr->GetFocusedStore()->SetSelection(1, &sel); |
|
2812 if (!(SUCCEEDED(hr))) { |
|
2813 fail("TestEditMessages: SetSelection #3"); |
|
2814 return false; |
|
2815 } |
|
2816 |
|
2817 ::SendMessage(wnd, WM_COPY, 0, 0); |
|
2818 mTextArea->GetValue(str); |
|
2819 if (str != mTestString) { |
|
2820 fail("TestEditMessages: WM_COPY"); |
|
2821 printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get()); |
|
2822 return false; |
|
2823 } |
|
2824 |
|
2825 if (!::SendMessage(wnd, EM_CANPASTE, 0, 0)) { |
|
2826 fail("TestEditMessages: EM_CANPASTE #1"); |
|
2827 return false; |
|
2828 } |
|
2829 |
|
2830 if (!::SendMessage(wnd, EM_CANPASTE, CF_TEXT, 0)) { |
|
2831 fail("TestEditMessages: EM_CANPASTE #2"); |
|
2832 return false; |
|
2833 } |
|
2834 |
|
2835 if (!::SendMessage(wnd, EM_CANPASTE, CF_UNICODETEXT, 0)) { |
|
2836 fail("TestEditMessages: EM_CANPASTE #3"); |
|
2837 return false; |
|
2838 } |
|
2839 |
|
2840 ::SendMessage(wnd, WM_PASTE, 0, 0); |
|
2841 mTextArea->GetValue(str); |
|
2842 if (str != mTestString) { |
|
2843 fail("TestEditMessages: WM_PASTE #3"); |
|
2844 printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get()); |
|
2845 return false; |
|
2846 } |
|
2847 |
|
2848 sel.acpStart = 4; |
|
2849 sel.acpEnd = testStringLength; |
|
2850 hr = mMgr->GetFocusedStore()->SetSelection(1, &sel); |
|
2851 if (!(SUCCEEDED(hr))) { |
|
2852 fail("TestEditMessages: SetSelection #3"); |
|
2853 return false; |
|
2854 } |
|
2855 |
|
2856 ::SendMessage(wnd, WM_CLEAR, 0, 0); |
|
2857 mTextArea->GetValue(str); |
|
2858 if (str != NS_LITERAL_STRING("This")) { |
|
2859 fail("TestEditMessages: WM_CLEAR #2"); |
|
2860 printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get()); |
|
2861 return false; |
|
2862 } |
|
2863 |
|
2864 ::SendMessage(wnd, WM_PASTE, 0, 0); |
|
2865 mTextArea->GetValue(str); |
|
2866 if (str != mTestString) { |
|
2867 fail("TestEditMessages: WM_PASTE #4"); |
|
2868 printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get()); |
|
2869 return false; |
|
2870 } |
|
2871 |
|
2872 return true; |
|
2873 } |
|
2874 |
|
2875 bool |
|
2876 TestApp::TestScrollMessages(void) |
|
2877 { |
|
2878 NS_NAMED_LITERAL_STRING(kLine, "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\n"); |
|
2879 mTestString.Truncate(); |
|
2880 for (uint32_t i = 0; i < 30; i++) { |
|
2881 mTestString.Append(kLine); |
|
2882 } |
|
2883 |
|
2884 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), |
|
2885 NS_LITERAL_STRING("width:3em;height:3em;word-wrap:normal;")); |
|
2886 mTextArea->SetValue(mTestString); |
|
2887 mTextArea->Focus(); |
|
2888 |
|
2889 nsCOMPtr<nsIWidget> widget; |
|
2890 if (!GetWidget(getter_AddRefs(widget))) { |
|
2891 fail("TestScrollMessages: get nsIWidget"); |
|
2892 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
2893 return false; |
|
2894 } |
|
2895 |
|
2896 nsCOMPtr<nsIDOMElement> textArea = do_QueryInterface(mTextArea); |
|
2897 if (!textArea) { |
|
2898 fail("TestScrollMessages: get nsIDOMElement"); |
|
2899 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
2900 return false; |
|
2901 } |
|
2902 |
|
2903 #define DO_CHECK(aFailureCondition, aDescription) \ |
|
2904 if (aFailureCondition) { \ |
|
2905 nsAutoCString str(aDescription); \ |
|
2906 str.Append(": "); \ |
|
2907 str.Append(#aFailureCondition); \ |
|
2908 fail(str.get()); \ |
|
2909 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); \ |
|
2910 return false; \ |
|
2911 } |
|
2912 |
|
2913 HWND wnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW); |
|
2914 |
|
2915 textArea->SetScrollTop(0); |
|
2916 textArea->SetScrollLeft(0); |
|
2917 |
|
2918 if (::SendMessage(wnd, WM_VSCROLL, SB_LINEDOWN, 0) != 0) { |
|
2919 fail("TestScrollMessages: SendMessage WM_VSCROLL #1"); |
|
2920 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
2921 return false; |
|
2922 } |
|
2923 |
|
2924 int32_t x, y, prevX, prevY; |
|
2925 textArea->GetScrollTop(&y); |
|
2926 textArea->GetScrollLeft(&x); |
|
2927 |
|
2928 DO_CHECK(x != 0, "TestScrollMessages: SendMessage WM_VSCROLL #1"); |
|
2929 DO_CHECK(y == 0, "TestScrollMessages: SendMessage WM_VSCROLL #1"); |
|
2930 |
|
2931 if (::SendMessage(wnd, WM_HSCROLL, SB_LINERIGHT, 0) != 0) { |
|
2932 fail("TestScrollMessages: SendMessage WM_HSCROLL #1"); |
|
2933 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
2934 return false; |
|
2935 } |
|
2936 |
|
2937 prevX = x; |
|
2938 prevY = y; |
|
2939 textArea->GetScrollTop(&y); |
|
2940 textArea->GetScrollLeft(&x); |
|
2941 |
|
2942 const int32_t kLineWidth = x; |
|
2943 const int32_t kLineHeight = y; |
|
2944 |
|
2945 DO_CHECK(x == 0, "TestScrollMessages: SendMessage WM_HSCROLL #1"); |
|
2946 DO_CHECK(y != prevY, "TestScrollMessages: SendMessage WM_HSCROLL #1"); |
|
2947 |
|
2948 if (::SendMessage(wnd, WM_VSCROLL, SB_LINEUP, 0) != 0) { |
|
2949 fail("TestScrollMessages: SendMessage WM_VSCROLL #2"); |
|
2950 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
2951 return false; |
|
2952 } |
|
2953 |
|
2954 prevX = x; |
|
2955 prevY = y; |
|
2956 textArea->GetScrollTop(&y); |
|
2957 textArea->GetScrollLeft(&x); |
|
2958 |
|
2959 DO_CHECK(x != prevX, "TestScrollMessages: SendMessage WM_VSCROLL #2"); |
|
2960 DO_CHECK(y != 0, "TestScrollMessages: SendMessage WM_VSCROLL #2"); |
|
2961 |
|
2962 if (::SendMessage(wnd, WM_HSCROLL, SB_LINELEFT, 0) != 0) { |
|
2963 fail("TestScrollMessages: SendMessage WM_HSCROLL #2"); |
|
2964 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
2965 return false; |
|
2966 } |
|
2967 |
|
2968 prevX = x; |
|
2969 prevY = y; |
|
2970 textArea->GetScrollTop(&y); |
|
2971 textArea->GetScrollLeft(&x); |
|
2972 |
|
2973 DO_CHECK(x != 0, "TestScrollMessages: SendMessage WM_HSCROLL #2"); |
|
2974 DO_CHECK(y != 0, "TestScrollMessages: SendMessage WM_HSCROLL #2"); |
|
2975 |
|
2976 if (::SendMessage(wnd, WM_VSCROLL, SB_PAGEDOWN, 0) != 0) { |
|
2977 fail("TestScrollMessages: SendMessage WM_VSCROLL #3"); |
|
2978 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
2979 return false; |
|
2980 } |
|
2981 |
|
2982 prevX = x; |
|
2983 prevY = y; |
|
2984 textArea->GetScrollTop(&y); |
|
2985 textArea->GetScrollLeft(&x); |
|
2986 |
|
2987 DO_CHECK(x != 0, "TestScrollMessages: SendMessage WM_VSCROLL #3"); |
|
2988 DO_CHECK(y <= kLineHeight, "TestScrollMessages: SendMessage WM_VSCROLL #3"); |
|
2989 |
|
2990 if (::SendMessage(wnd, WM_HSCROLL, SB_PAGERIGHT, 0) != 0) { |
|
2991 fail("TestScrollMessages: SendMessage WM_HSCROLL #3"); |
|
2992 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
2993 return false; |
|
2994 } |
|
2995 |
|
2996 prevX = x; |
|
2997 prevY = y; |
|
2998 textArea->GetScrollTop(&y); |
|
2999 textArea->GetScrollLeft(&x); |
|
3000 |
|
3001 DO_CHECK(x <= kLineWidth, "TestScrollMessages: SendMessage WM_HSCROLL #3"); |
|
3002 DO_CHECK(y != prevY, "TestScrollMessages: SendMessage WM_HSCROLL #3"); |
|
3003 |
|
3004 const int32_t kPageWidth = x; |
|
3005 const int32_t kPageHeight = y; |
|
3006 |
|
3007 ::SendMessage(wnd, WM_VSCROLL, SB_LINEDOWN, 0); |
|
3008 ::SendMessage(wnd, WM_VSCROLL, SB_LINEUP, 0); |
|
3009 ::SendMessage(wnd, WM_HSCROLL, SB_LINERIGHT, 0); |
|
3010 ::SendMessage(wnd, WM_HSCROLL, SB_LINELEFT, 0); |
|
3011 |
|
3012 prevX = x; |
|
3013 prevY = y; |
|
3014 textArea->GetScrollTop(&y); |
|
3015 textArea->GetScrollLeft(&x); |
|
3016 |
|
3017 DO_CHECK(x != prevX, "TestScrollMessages: SB_LINELEFT scrolled wrong amount"); |
|
3018 DO_CHECK(y != prevY, "TestScrollMessages: SB_LINEUP scrolled wrong amount"); |
|
3019 |
|
3020 if (::SendMessage(wnd, WM_VSCROLL, SB_PAGEUP, 0) != 0) { |
|
3021 fail("TestScrollMessages: SendMessage WM_VSCROLL #4"); |
|
3022 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
3023 return false; |
|
3024 } |
|
3025 |
|
3026 prevX = x; |
|
3027 prevY = y; |
|
3028 textArea->GetScrollTop(&y); |
|
3029 textArea->GetScrollLeft(&x); |
|
3030 |
|
3031 DO_CHECK(x != prevX, "TestScrollMessages: SendMessage WM_VSCROLL #4"); |
|
3032 DO_CHECK(y != 0, "TestScrollMessages: SendMessage WM_VSCROLL #4"); |
|
3033 |
|
3034 if (::SendMessage(wnd, WM_HSCROLL, SB_PAGELEFT, 0) != 0) { |
|
3035 fail("TestScrollMessages: SendMessage WM_HSCROLL #4"); |
|
3036 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
3037 return false; |
|
3038 } |
|
3039 |
|
3040 prevX = x; |
|
3041 prevY = y; |
|
3042 textArea->GetScrollTop(&y); |
|
3043 textArea->GetScrollLeft(&x); |
|
3044 |
|
3045 DO_CHECK(x != 0, "TestScrollMessages: SendMessage WM_HSCROLL #4"); |
|
3046 DO_CHECK(y != 0, "TestScrollMessages: SendMessage WM_HSCROLL #4"); |
|
3047 |
|
3048 if (::SendMessage(wnd, WM_VSCROLL, SB_BOTTOM, 0) != 0) { |
|
3049 fail("TestScrollMessages: SendMessage WM_VSCROLL #5"); |
|
3050 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
3051 return false; |
|
3052 } |
|
3053 |
|
3054 prevX = x; |
|
3055 prevY = y; |
|
3056 textArea->GetScrollTop(&y); |
|
3057 textArea->GetScrollLeft(&x); |
|
3058 |
|
3059 DO_CHECK(x != 0, "TestScrollMessages: SendMessage WM_VSCROLL #5"); |
|
3060 DO_CHECK(y <= kPageHeight, "TestScrollMessages: SendMessage WM_VSCROLL #5"); |
|
3061 |
|
3062 if (::SendMessage(wnd, WM_HSCROLL, SB_RIGHT, 0) != 0) { |
|
3063 fail("TestScrollMessages: SendMessage WM_HSCROLL #6"); |
|
3064 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
3065 return false; |
|
3066 } |
|
3067 |
|
3068 prevX = x; |
|
3069 prevY = y; |
|
3070 textArea->GetScrollTop(&y); |
|
3071 textArea->GetScrollLeft(&x); |
|
3072 |
|
3073 DO_CHECK(x <= kPageWidth, "TestScrollMessages: SendMessage WM_HSCROLL #5"); |
|
3074 DO_CHECK(y != prevY, "TestScrollMessages: SendMessage WM_HSCROLL #5"); |
|
3075 |
|
3076 ::SendMessage(wnd, WM_VSCROLL, SB_LINEDOWN, 0); |
|
3077 ::SendMessage(wnd, WM_HSCROLL, SB_LINERIGHT, 0); |
|
3078 |
|
3079 prevX = x; |
|
3080 prevY = y; |
|
3081 textArea->GetScrollTop(&y); |
|
3082 textArea->GetScrollLeft(&x); |
|
3083 |
|
3084 DO_CHECK(x != prevX, "SB_RIGHT didn't scroll to right most"); |
|
3085 DO_CHECK(y != prevY, "SB_BOTTOM didn't scroll to bottom most"); |
|
3086 |
|
3087 ::SendMessage(wnd, WM_VSCROLL, SB_PAGEUP, 0); |
|
3088 ::SendMessage(wnd, WM_VSCROLL, SB_PAGEDOWN, 0); |
|
3089 ::SendMessage(wnd, WM_HSCROLL, SB_PAGELEFT, 0); |
|
3090 ::SendMessage(wnd, WM_HSCROLL, SB_PAGERIGHT, 0); |
|
3091 |
|
3092 prevX = x; |
|
3093 prevY = y; |
|
3094 textArea->GetScrollTop(&y); |
|
3095 textArea->GetScrollLeft(&x); |
|
3096 |
|
3097 DO_CHECK(x != prevX, "TestScrollMessages: SB_PAGELEFT scrolled wrong amount"); |
|
3098 DO_CHECK(y != prevY, "TestScrollMessages: SB_PAGEUP scrolled wrong amount"); |
|
3099 |
|
3100 if (::SendMessage(wnd, WM_VSCROLL, SB_TOP, 0) != 0) { |
|
3101 fail("TestScrollMessages: SendMessage WM_VSCROLL #6"); |
|
3102 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
3103 return false; |
|
3104 } |
|
3105 |
|
3106 prevX = x; |
|
3107 prevY = y; |
|
3108 textArea->GetScrollTop(&y); |
|
3109 textArea->GetScrollLeft(&x); |
|
3110 |
|
3111 DO_CHECK(x != prevX, "TestScrollMessages: SendMessage WM_VSCROLL #6"); |
|
3112 DO_CHECK(y != 0, "TestScrollMessages: SendMessage WM_VSCROLL #6"); |
|
3113 |
|
3114 if (::SendMessage(wnd, WM_HSCROLL, SB_LEFT, 0) != 0) { |
|
3115 fail("TestScrollMessages: SendMessage WM_HSCROLL #4"); |
|
3116 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
3117 return false; |
|
3118 } |
|
3119 |
|
3120 prevX = x; |
|
3121 prevY = y; |
|
3122 textArea->GetScrollTop(&y); |
|
3123 textArea->GetScrollLeft(&x); |
|
3124 |
|
3125 DO_CHECK(x != 0, "TestScrollMessages: SendMessage WM_HSCROLL #6"); |
|
3126 DO_CHECK(y != 0, "TestScrollMessages: SendMessage WM_HSCROLL #6"); |
|
3127 #undef DO_CHECK |
|
3128 |
|
3129 mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); |
|
3130 return true; |
|
3131 } |
|
3132 |
|
3133 bool |
|
3134 TestApp::GetWidget(nsIWidget** aWidget) |
|
3135 { |
|
3136 nsCOMPtr<nsIDocShell> docShell; |
|
3137 nsresult rv = mWindow->GetDocShell(getter_AddRefs(docShell)); |
|
3138 if (NS_FAILED(rv) || !docShell) { |
|
3139 return false; |
|
3140 } |
|
3141 |
|
3142 nsCOMPtr<nsIPresShell> presShell; |
|
3143 rv = docShell->GetPresShell(getter_AddRefs(presShell)); |
|
3144 if (NS_FAILED(rv) || !presShell) { |
|
3145 return false; |
|
3146 } |
|
3147 |
|
3148 nsRefPtr<nsViewManager> viewManager = presShell->GetViewManager(); |
|
3149 if (!viewManager) { |
|
3150 return false; |
|
3151 } |
|
3152 |
|
3153 rv = viewManager->GetRootWidget(aWidget); |
|
3154 return (NS_SUCCEEDED(rv) && aWidget); |
|
3155 } |
|
3156 |
|
3157 nsresult |
|
3158 TestApp::GetSelCon(nsISelectionController** aSelCon) |
|
3159 { |
|
3160 nsCOMPtr<nsIDocShell> docShell; |
|
3161 nsresult nsr = mWindow->GetDocShell(getter_AddRefs(docShell)); |
|
3162 if (NS_SUCCEEDED(nsr) && docShell) { |
|
3163 nsCOMPtr<nsIPresShell> presShell; |
|
3164 nsr = docShell->GetPresShell(getter_AddRefs(presShell)); |
|
3165 if (NS_SUCCEEDED(nsr) && presShell) { |
|
3166 nsIFrame* frame = |
|
3167 nsCOMPtr<nsIContent>(do_QueryInterface(mCurrentNode))->GetPrimaryFrame(); |
|
3168 if (frame) { |
|
3169 nsPresContext* presContext = presShell->GetPresContext(); |
|
3170 if (presContext) { |
|
3171 nsr = frame->GetSelectionController(presContext, aSelCon); |
|
3172 } |
|
3173 } |
|
3174 } |
|
3175 } |
|
3176 return nsr; |
|
3177 } |
|
3178 |
|
3179 int main(int argc, char** argv) |
|
3180 { |
|
3181 ScopedXPCOM xpcom("TestWinTSF (bug #88831)"); |
|
3182 if (xpcom.failed()) |
|
3183 return 1; |
|
3184 |
|
3185 nsRefPtr<TestApp> tests = new TestApp(); |
|
3186 if (!tests) |
|
3187 return 1; |
|
3188 |
|
3189 if (NS_FAILED(tests->Run())) { |
|
3190 fail("run failed"); |
|
3191 return 1; |
|
3192 } |
|
3193 return int(tests->CheckFailed()); |
|
3194 } |