widget/tests/TestWinTSF.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:57002741b74c
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 &currentSel, &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 }

mercurial