widget/tests/TestWinTSF.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial