widget/tests/TestWinTSF.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/tests/TestWinTSF.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3194 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +
    1.10 +/* This tests Mozilla's Text Services Framework implementation (bug #88831)
    1.11 + *
    1.12 + * The Mozilla implementation interacts with the TSF system through a
    1.13 + * system-provided COM interface, ITfThreadMgr. This tests works by swapping
    1.14 + * the system version of the interface with a custom version implemented in
    1.15 + * here. This way the Mozilla implementation thinks it's interacting with the
    1.16 + * system but in fact is interacting with this test program. This allows the
    1.17 + * test program to access and test every aspect of the Mozilla implementation.
    1.18 + */
    1.19 +
    1.20 +#include <ole2.h>
    1.21 +#include <msctf.h>
    1.22 +#include <textstor.h>
    1.23 +#include <richedit.h>
    1.24 +
    1.25 +#include "TestHarness.h"
    1.26 +#include <algorithm>
    1.27 +
    1.28 +#define WM_USER_TSF_TEXTCHANGE  (WM_USER + 0x100)
    1.29 +
    1.30 +#ifndef MOZILLA_INTERNAL_API
    1.31 +// some of the includes make use of internal string types
    1.32 +#define nsAString_h___
    1.33 +#define nsString_h___
    1.34 +#define nsStringFwd_h___
    1.35 +#define nsReadableUtils_h___
    1.36 +class nsACString;
    1.37 +class nsAString;
    1.38 +class nsAFlatString;
    1.39 +class nsAFlatCString;
    1.40 +class nsAdoptingString;
    1.41 +class nsAdoptingCString;
    1.42 +class nsXPIDLString;
    1.43 +template<class T> class nsReadingIterator;
    1.44 +#endif
    1.45 +
    1.46 +#include "nscore.h"
    1.47 +#include "nsWeakReference.h"
    1.48 +#include "nsIAppShell.h"
    1.49 +#include "nsWidgetsCID.h"
    1.50 +#include "nsIAppShellService.h"
    1.51 +#include "nsAppShellCID.h"
    1.52 +#include "nsNetUtil.h"
    1.53 +#include "nsIWebBrowserChrome.h"
    1.54 +#include "nsIXULWindow.h"
    1.55 +#include "nsIBaseWindow.h"
    1.56 +#include "nsIDOMWindow.h"
    1.57 +#include "nsIDocShell.h"
    1.58 +#include "nsIWidget.h"
    1.59 +#include "nsIPresShell.h"
    1.60 +#include "nsPresContext.h"
    1.61 +#include "nsIFrame.h"
    1.62 +#include "nsIWebProgress.h"
    1.63 +#include "nsIWebProgressListener.h"
    1.64 +#include "nsIInterfaceRequestorUtils.h"
    1.65 +#include "nsIDOMHTMLDocument.h"
    1.66 +#include "mozilla/dom/HTMLBodyElement.h"
    1.67 +#include "nsIDOMHTMLElement.h"
    1.68 +#include "nsIDOMHTMLInputElement.h"
    1.69 +#include "nsIDOMHTMLTextAreaElement.h"
    1.70 +#include "nsIDOMElement.h"
    1.71 +#include "nsISelectionController.h"
    1.72 +#include "nsViewManager.h"
    1.73 +#include "nsTArray.h"
    1.74 +
    1.75 +#ifndef MOZILLA_INTERNAL_API
    1.76 +#undef nsString_h___
    1.77 +#undef nsAString_h___
    1.78 +#undef nsReadableUtils_h___
    1.79 +#endif
    1.80 +
    1.81 +static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
    1.82 +
    1.83 +class TSFMgrImpl;
    1.84 +class TSFDocumentMgrImpl;
    1.85 +class TSFContextImpl;
    1.86 +class TSFRangeImpl;
    1.87 +class TSFEnumRangeImpl;
    1.88 +class TSFAttrPropImpl;
    1.89 +
    1.90 +class TestApp : public nsIWebProgressListener, public nsSupportsWeakReference
    1.91 +{
    1.92 +public:
    1.93 +  NS_DECL_ISUPPORTS
    1.94 +  NS_DECL_NSIWEBPROGRESSLISTENER
    1.95 +
    1.96 +  TestApp() : mFailed(false) {}
    1.97 +  ~TestApp() {}
    1.98 +
    1.99 +  nsresult Run(void);
   1.100 +  bool CheckFailed(void);
   1.101 +
   1.102 +  typedef bool (TestApp::*test_type)(void);
   1.103 +
   1.104 +protected:
   1.105 +  nsresult Init(void);
   1.106 +  nsresult Term(void);
   1.107 +  bool RunTest(test_type aTest, bool aLock = true);
   1.108 +
   1.109 +  bool TestFocus(void);
   1.110 +  bool TestClustering(void);
   1.111 +  bool TestSelection(void);
   1.112 +  bool TestText(void);
   1.113 +  bool TestExtents(void);
   1.114 +  bool TestComposition(void);
   1.115 +  bool TestNotification(void);
   1.116 +  bool TestEditMessages(void);
   1.117 +  bool TestScrollMessages(void);
   1.118 +
   1.119 +  bool TestSelectionInternal(char* aTestName,
   1.120 +                                        LONG aStart,
   1.121 +                                        LONG aEnd,
   1.122 +                                        TsActiveSelEnd aSelEnd);
   1.123 +  bool TestCompositionSelectionAndText(char* aTestName,
   1.124 +                                         LONG aExpectedSelStart,
   1.125 +                                         LONG aExpectedSelEnd,
   1.126 +                                         nsString& aReferenceString);
   1.127 +  bool TestNotificationTextChange(nsIWidget* aWidget,
   1.128 +                                    uint32_t aCode,
   1.129 +                                    const nsAString& aCharacter,
   1.130 +                                    LONG aStart,
   1.131 +                                    LONG aOldEnd,
   1.132 +                                    LONG aNewEnd);
   1.133 +  nsresult GetSelCon(nsISelectionController** aSelCon);
   1.134 +
   1.135 +  bool GetWidget(nsIWidget** aWidget);
   1.136 +
   1.137 +  bool mFailed;
   1.138 +  nsString mTestString;
   1.139 +  nsRefPtr<TSFMgrImpl> mMgr;
   1.140 +  nsCOMPtr<nsIAppShell> mAppShell;
   1.141 +  nsCOMPtr<nsIXULWindow> mWindow;
   1.142 +  nsCOMPtr<nsIDOMNode> mCurrentNode;
   1.143 +  nsCOMPtr<nsIDOMHTMLInputElement> mInput;
   1.144 +  nsCOMPtr<nsIDOMHTMLTextAreaElement> mTextArea;
   1.145 +  nsCOMPtr<nsIDOMHTMLInputElement> mButton;
   1.146 +};
   1.147 +
   1.148 +NS_IMETHODIMP
   1.149 +TestApp::OnProgressChange(nsIWebProgress *aWebProgress,
   1.150 +                           nsIRequest *aRequest,
   1.151 +                           int32_t aCurSelfProgress,
   1.152 +                           int32_t aMaxSelfProgress,
   1.153 +                           int32_t aCurTotalProgress,
   1.154 +                           int32_t aMaxTotalProgress)
   1.155 +{
   1.156 +  return NS_OK;
   1.157 +}
   1.158 +
   1.159 +NS_IMETHODIMP
   1.160 +TestApp::OnLocationChange(nsIWebProgress *aWebProgress,
   1.161 +                           nsIRequest *aRequest,
   1.162 +                           nsIURI *aLocation,
   1.163 +                           uint32_t aFlags)
   1.164 +{
   1.165 +  return NS_OK;
   1.166 +}
   1.167 +
   1.168 +NS_IMETHODIMP
   1.169 +TestApp::OnStatusChange(nsIWebProgress *aWebProgress,
   1.170 +                         nsIRequest *aRequest,
   1.171 +                         nsresult aStatus,
   1.172 +                         const char16_t *aMessage)
   1.173 +{
   1.174 +  return NS_OK;
   1.175 +}
   1.176 +
   1.177 +NS_IMETHODIMP
   1.178 +TestApp::OnSecurityChange(nsIWebProgress *aWebProgress,
   1.179 +                           nsIRequest *aRequest,
   1.180 +                           uint32_t aState)
   1.181 +{
   1.182 +  return NS_OK;
   1.183 +}
   1.184 +
   1.185 +static HRESULT
   1.186 +GetRegularExtent(ITfRange *aRange, LONG &aStart, LONG &aEnd)
   1.187 +{
   1.188 +  NS_ENSURE_TRUE(aRange, E_INVALIDARG);
   1.189 +  nsRefPtr<ITfRangeACP> rangeACP;
   1.190 +  HRESULT hr = aRange->QueryInterface(IID_ITfRangeACP,
   1.191 +                                      getter_AddRefs(rangeACP));
   1.192 +  NS_ENSURE_TRUE(SUCCEEDED(hr) && rangeACP, E_FAIL);
   1.193 +
   1.194 +  LONG start, length;
   1.195 +  hr = rangeACP->GetExtent(&start, &length);
   1.196 +  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.197 +  if (length >= 0) {
   1.198 +    aStart = start;
   1.199 +    aEnd = start + length;
   1.200 +  } else {
   1.201 +    aEnd = start;
   1.202 +    aStart = start + length;
   1.203 +  }
   1.204 +  return S_OK;
   1.205 +}
   1.206 +
   1.207 +// {3B2DFDF5-2485-4858-8185-5C6B4EFD38F5}
   1.208 +static const GUID GUID_COMPOSING_SELECTION_ATTR = 
   1.209 +  { 0x3b2dfdf5, 0x2485, 0x4858,
   1.210 +    { 0x81, 0x85, 0x5c, 0x6b, 0x4e, 0xfd, 0x38, 0xf5 } };
   1.211 +#define GUID_ATOM_COMPOSING_SELECTION_ATTR \
   1.212 +  (static_cast<TfGuidAtom>(0x3b2dfdf5))
   1.213 +
   1.214 +/******************************************************************************
   1.215 + * TSFRangeImpl
   1.216 + ******************************************************************************/
   1.217 +
   1.218 +class TSFRangeImpl : public ITfRangeACP
   1.219 +{
   1.220 +private:
   1.221 +  ULONG mRefCnt;
   1.222 +
   1.223 +public:
   1.224 +  LONG mStart;
   1.225 +  LONG mLength;
   1.226 +
   1.227 +  TSFRangeImpl(LONG aStart = 0, LONG aLength = 0) :
   1.228 +      mRefCnt(0), mStart(aStart), mLength(aLength)
   1.229 +  {
   1.230 +  }
   1.231 +
   1.232 +  ~TSFRangeImpl()
   1.233 +  {
   1.234 +  }
   1.235 +
   1.236 +public: // IUnknown
   1.237 +
   1.238 +  STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk)
   1.239 +  {
   1.240 +    *ppUnk = nullptr;
   1.241 +    if (IID_IUnknown == riid || IID_ITfRange == riid || IID_ITfRangeACP == riid)
   1.242 +      *ppUnk = static_cast<ITfRangeACP*>(this);
   1.243 +    if (*ppUnk)
   1.244 +      AddRef();
   1.245 +    return *ppUnk ? S_OK : E_NOINTERFACE;
   1.246 +  }
   1.247 +
   1.248 +  STDMETHODIMP_(ULONG) AddRef(void)
   1.249 +  {
   1.250 +    return ++mRefCnt;
   1.251 +  }
   1.252 +
   1.253 +  STDMETHODIMP_(ULONG) Release(void)
   1.254 +  {
   1.255 +    if (--mRefCnt) return mRefCnt;
   1.256 +    delete this;
   1.257 +    return 0;
   1.258 +  }
   1.259 +
   1.260 +public: // ITfRange
   1.261 +
   1.262 +  STDMETHODIMP GetText(TfEditCookie ec, DWORD dwFlags, WCHAR *pchText,
   1.263 +                       ULONG cchMax, ULONG *pcch)
   1.264 +  {
   1.265 +    NS_NOTREACHED("ITfRange::GetText");
   1.266 +    return E_NOTIMPL;
   1.267 +  }
   1.268 +
   1.269 +  STDMETHODIMP SetText(TfEditCookie ec, DWORD dwFlags, const WCHAR *pchText,
   1.270 +                       LONG cch)
   1.271 +  {
   1.272 +    NS_NOTREACHED("ITfRange::SetText");
   1.273 +    return E_NOTIMPL;
   1.274 +  }
   1.275 +
   1.276 +  STDMETHODIMP GetFormattedText(TfEditCookie ec, IDataObject **ppDataObject)
   1.277 +  {
   1.278 +    NS_NOTREACHED("ITfRange::GetFormattedText");
   1.279 +    return E_NOTIMPL;
   1.280 +  }
   1.281 +
   1.282 +  STDMETHODIMP GetEmbedded(TfEditCookie ec, REFGUID rguidService, REFIID riid,
   1.283 +                           IUnknown **ppunk)
   1.284 +  {
   1.285 +    NS_NOTREACHED("ITfRange::GetEmbedded");
   1.286 +    return E_NOTIMPL;
   1.287 +  }
   1.288 +
   1.289 +  STDMETHODIMP InsertEmbedded(TfEditCookie ec, DWORD dwFlags,
   1.290 +                              IDataObject *pDataObject)
   1.291 +  {
   1.292 +    NS_NOTREACHED("ITfRange::InsertEmbedded");
   1.293 +    return E_NOTIMPL;
   1.294 +  }
   1.295 +
   1.296 +  STDMETHODIMP ShiftStart(TfEditCookie ec, LONG cchReq, LONG *pcch,
   1.297 +                          const TF_HALTCOND *pHalt)
   1.298 +  {
   1.299 +    NS_NOTREACHED("ITfRange::ShiftStart");
   1.300 +    return E_NOTIMPL;
   1.301 +  }
   1.302 +
   1.303 +  STDMETHODIMP ShiftEnd(TfEditCookie ec, LONG cchReq, LONG *pcch,
   1.304 +                        const TF_HALTCOND *pHalt)
   1.305 +  {
   1.306 +    NS_NOTREACHED("ITfRange::ShiftEnd");
   1.307 +    return E_NOTIMPL;
   1.308 +  }
   1.309 +
   1.310 +  STDMETHODIMP ShiftStartToRange(TfEditCookie ec, ITfRange *pRange,
   1.311 +                                 TfAnchor aPos)
   1.312 +  {
   1.313 +    NS_NOTREACHED("ITfRange::ShiftStartToRange");
   1.314 +    return E_NOTIMPL;
   1.315 +  }
   1.316 +
   1.317 +  STDMETHODIMP ShiftEndToRange(TfEditCookie ec, ITfRange *pRange, TfAnchor aPos)
   1.318 +  {
   1.319 +    NS_NOTREACHED("ITfRange::ShiftEndToRange");
   1.320 +    return E_NOTIMPL;
   1.321 +  }
   1.322 +
   1.323 +  STDMETHODIMP ShiftStartRegion(TfEditCookie ec, TfShiftDir dir,
   1.324 +                                BOOL *pfNoRegion)
   1.325 +  {
   1.326 +    NS_NOTREACHED("ITfRange::ShiftStartRegion");
   1.327 +    return E_NOTIMPL;
   1.328 +  }
   1.329 +
   1.330 +  STDMETHODIMP ShiftEndRegion(TfEditCookie ec, TfShiftDir dir, BOOL *pfNoRegion)
   1.331 +  {
   1.332 +    NS_NOTREACHED("ITfRange::ShiftEndRegion");
   1.333 +    return E_NOTIMPL;
   1.334 +  }
   1.335 +
   1.336 +  STDMETHODIMP IsEmpty(TfEditCookie ec, BOOL *pfEmpty)
   1.337 +  {
   1.338 +    NS_NOTREACHED("ITfRange::IsEmpty");
   1.339 +    return E_NOTIMPL;
   1.340 +  }
   1.341 +
   1.342 +  STDMETHODIMP Collapse(TfEditCookie ec, TfAnchor aPos)
   1.343 +  {
   1.344 +    NS_NOTREACHED("ITfRange::Collapse");
   1.345 +    return E_NOTIMPL;
   1.346 +  }
   1.347 +
   1.348 +  STDMETHODIMP IsEqualStart(TfEditCookie ec, ITfRange *pWith, TfAnchor aPos,
   1.349 +                            BOOL *pfEqual)
   1.350 +  {
   1.351 +    NS_NOTREACHED("ITfRange::IsEqualStart");
   1.352 +    return E_NOTIMPL;
   1.353 +  }
   1.354 +
   1.355 +  STDMETHODIMP IsEqualEnd(TfEditCookie ec, ITfRange *pWith, TfAnchor aPos,
   1.356 +                          BOOL *pfEqual)
   1.357 +  {
   1.358 +    NS_NOTREACHED("ITfRange::IsEqualEnd");
   1.359 +    return E_NOTIMPL;
   1.360 +  }
   1.361 +
   1.362 +  STDMETHODIMP CompareStart(TfEditCookie ec, ITfRange *pWith, TfAnchor aPos,
   1.363 +                            LONG *plResult)
   1.364 +  {
   1.365 +    NS_NOTREACHED("ITfRange::CompareStart");
   1.366 +    return E_NOTIMPL;
   1.367 +  }
   1.368 +
   1.369 +  STDMETHODIMP CompareEnd(TfEditCookie ec, ITfRange *pWith, TfAnchor aPos,
   1.370 +                          LONG *plResult)
   1.371 +  {
   1.372 +    NS_NOTREACHED("ITfRange::CompareEnd");
   1.373 +    return E_NOTIMPL;
   1.374 +  }
   1.375 +
   1.376 +  STDMETHODIMP AdjustForInsert(TfEditCookie ec, ULONG cchInsert,
   1.377 +                               BOOL *pfInsertOk)
   1.378 +  {
   1.379 +    NS_NOTREACHED("ITfRange::AdjustForInsert");
   1.380 +    return E_NOTIMPL;
   1.381 +  }
   1.382 +
   1.383 +  STDMETHODIMP GetGravity(TfGravity *pgStart, TfGravity *pgEnd)
   1.384 +  {
   1.385 +    NS_NOTREACHED("ITfRange::GetGravity");
   1.386 +    return E_NOTIMPL;
   1.387 +  }
   1.388 +
   1.389 +  STDMETHODIMP SetGravity(TfEditCookie ec, TfGravity gStart, TfGravity gEnd)
   1.390 +  {
   1.391 +    NS_NOTREACHED("ITfRange::SetGravity");
   1.392 +    return E_NOTIMPL;
   1.393 +  }
   1.394 +
   1.395 +  STDMETHODIMP Clone(ITfRange **ppClone)
   1.396 +  {
   1.397 +    NS_NOTREACHED("ITfRange::Clone");
   1.398 +    return E_NOTIMPL;
   1.399 +  }
   1.400 +
   1.401 +  STDMETHODIMP GetContext(ITfContext **ppContext)
   1.402 +  {
   1.403 +    NS_NOTREACHED("ITfRange::GetContext");
   1.404 +    return E_NOTIMPL;
   1.405 +  }
   1.406 +
   1.407 +public: // ITfRangeACP
   1.408 +
   1.409 +  STDMETHODIMP GetExtent(LONG *pacpAnchor, LONG *pcch)
   1.410 +  {
   1.411 +    NS_ENSURE_TRUE(pacpAnchor, E_FAIL);
   1.412 +    NS_ENSURE_TRUE(pcch, E_FAIL);
   1.413 +    *pacpAnchor = mStart;
   1.414 +    *pcch = mLength;
   1.415 +    return S_OK;
   1.416 +  }
   1.417 +
   1.418 +  STDMETHODIMP SetExtent(LONG acpAnchor, LONG cch)
   1.419 +  {
   1.420 +    mStart = acpAnchor;
   1.421 +    mLength = cch;
   1.422 +    return S_OK;
   1.423 +  }
   1.424 +};
   1.425 +
   1.426 +/******************************************************************************
   1.427 + * TSFEnumRangeImpl
   1.428 + ******************************************************************************/
   1.429 +
   1.430 +class TSFEnumRangeImpl : public IEnumTfRanges
   1.431 +{
   1.432 +private:
   1.433 +  ULONG mRefCnt;
   1.434 +  uint32_t mCurrentIndex;
   1.435 +
   1.436 +public:
   1.437 +  nsTArray<nsRefPtr<TSFRangeImpl> > mRanges;
   1.438 +
   1.439 +  TSFEnumRangeImpl() :
   1.440 +      mRefCnt(0), mCurrentIndex(0)
   1.441 +  {
   1.442 +  }
   1.443 +
   1.444 +  ~TSFEnumRangeImpl()
   1.445 +  {
   1.446 +  }
   1.447 +
   1.448 +public: // IUnknown
   1.449 +
   1.450 +  STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk)
   1.451 +  {
   1.452 +    *ppUnk = nullptr;
   1.453 +    if (IID_IUnknown == riid || IID_IEnumTfRanges == riid)
   1.454 +      *ppUnk = static_cast<IEnumTfRanges*>(this);
   1.455 +    if (*ppUnk)
   1.456 +      AddRef();
   1.457 +    return *ppUnk ? S_OK : E_NOINTERFACE;
   1.458 +  }
   1.459 +
   1.460 +  STDMETHODIMP_(ULONG) AddRef(void)
   1.461 +  {
   1.462 +    return ++mRefCnt;
   1.463 +  }
   1.464 +
   1.465 +  STDMETHODIMP_(ULONG) Release(void)
   1.466 +  {
   1.467 +    if (--mRefCnt) return mRefCnt;
   1.468 +    delete this;
   1.469 +    return 0;
   1.470 +  }
   1.471 +
   1.472 +public: // IEnumTfRanges
   1.473 +
   1.474 +  STDMETHODIMP Clone(IEnumTfRanges **ppEnum)
   1.475 +  {
   1.476 +    NS_NOTREACHED("IEnumTfRanges::Clone");
   1.477 +    return E_NOTIMPL;
   1.478 +  }
   1.479 +
   1.480 +  STDMETHODIMP Next(ULONG ulCount, ITfRange **ppRange, ULONG *pcFetched)
   1.481 +  {
   1.482 +    NS_ENSURE_TRUE(ppRange, E_FAIL);
   1.483 +    if (pcFetched)
   1.484 +      *pcFetched = 0;
   1.485 +    if (mCurrentIndex + ulCount - 1 >= mRanges.Length())
   1.486 +      return E_FAIL;
   1.487 +    for (uint32_t i = 0; i < ulCount; i++) {
   1.488 +      ppRange[i] = mRanges[mCurrentIndex++];
   1.489 +      ppRange[i]->AddRef();
   1.490 +      if (pcFetched)
   1.491 +        (*pcFetched)++;
   1.492 +    }
   1.493 +    return S_OK;
   1.494 +  }
   1.495 +
   1.496 +  STDMETHODIMP Reset()
   1.497 +  {
   1.498 +    mCurrentIndex = 0;
   1.499 +    return S_OK;
   1.500 +  }
   1.501 +
   1.502 +  STDMETHODIMP Skip(ULONG ulCount)
   1.503 +  {
   1.504 +    mCurrentIndex += ulCount;
   1.505 +    return S_OK;
   1.506 +  }
   1.507 +};
   1.508 +
   1.509 +/******************************************************************************
   1.510 + * TSFDispAttrInfoImpl
   1.511 + ******************************************************************************/
   1.512 +
   1.513 +class TSFDispAttrInfoImpl : public ITfDisplayAttributeInfo
   1.514 +{
   1.515 +private:
   1.516 +  ULONG mRefCnt;
   1.517 +  TF_DISPLAYATTRIBUTE mAttr;
   1.518 +
   1.519 +public:
   1.520 +
   1.521 +  TSFDispAttrInfoImpl(REFGUID aGUID) :
   1.522 +      mRefCnt(0)
   1.523 +  {
   1.524 +    if (aGUID == GUID_COMPOSING_SELECTION_ATTR) {
   1.525 +      mAttr.crText.type = TF_CT_NONE;
   1.526 +      mAttr.crBk.type = TF_CT_NONE;
   1.527 +      mAttr.lsStyle = TF_LS_SQUIGGLE;
   1.528 +      mAttr.fBoldLine = FALSE;
   1.529 +      mAttr.crLine.type = TF_CT_NONE;
   1.530 +      mAttr.bAttr = TF_ATTR_INPUT;
   1.531 +    } else {
   1.532 +      NS_NOTREACHED("TSFDispAttrInfoImpl::TSFDispAttrInfoImpl");
   1.533 +    }
   1.534 +  }
   1.535 +
   1.536 +  ~TSFDispAttrInfoImpl()
   1.537 +  {
   1.538 +  }
   1.539 +
   1.540 +public: // IUnknown
   1.541 +
   1.542 +  STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk)
   1.543 +  {
   1.544 +    *ppUnk = nullptr;
   1.545 +    if (IID_IUnknown == riid || IID_ITfDisplayAttributeInfo == riid)
   1.546 +      *ppUnk = static_cast<ITfDisplayAttributeInfo*>(this);
   1.547 +    if (*ppUnk)
   1.548 +      AddRef();
   1.549 +    return *ppUnk ? S_OK : E_NOINTERFACE;
   1.550 +  }
   1.551 +
   1.552 +  STDMETHODIMP_(ULONG) AddRef(void)
   1.553 +  {
   1.554 +    return ++mRefCnt;
   1.555 +  }
   1.556 +
   1.557 +  STDMETHODIMP_(ULONG) Release(void)
   1.558 +  {
   1.559 +    if (--mRefCnt) return mRefCnt;
   1.560 +    delete this;
   1.561 +    return 0;
   1.562 +  }
   1.563 +
   1.564 +public: // ITfDisplayAttributeInfo
   1.565 +
   1.566 +  STDMETHODIMP GetGUID(GUID *pguid)
   1.567 +  {
   1.568 +    NS_NOTREACHED("ITfDisplayAttributeInfo::GetGUID");
   1.569 +    return E_NOTIMPL;
   1.570 +  }
   1.571 +
   1.572 +  STDMETHODIMP GetDescription(BSTR *pbstrDesc)
   1.573 +  {
   1.574 +    NS_NOTREACHED("ITfDisplayAttributeInfo::GetDescription");
   1.575 +    return E_NOTIMPL;
   1.576 +  }
   1.577 +
   1.578 +  STDMETHODIMP GetAttributeInfo(TF_DISPLAYATTRIBUTE *pda)
   1.579 +  {
   1.580 +    NS_ENSURE_TRUE(pda, E_INVALIDARG);
   1.581 +    *pda = mAttr;
   1.582 +    return S_OK;
   1.583 +  }
   1.584 +
   1.585 +  STDMETHODIMP SetAttributeInfo(const TF_DISPLAYATTRIBUTE *pda)
   1.586 +  {
   1.587 +    NS_NOTREACHED("ITfDisplayAttributeInfo::SetAttributeInfo");
   1.588 +    return E_NOTIMPL;
   1.589 +  }
   1.590 +
   1.591 +  STDMETHODIMP Reset()
   1.592 +  {
   1.593 +    NS_NOTREACHED("ITfDisplayAttributeInfo::Reset");
   1.594 +    return E_NOTIMPL;
   1.595 +  }
   1.596 +};
   1.597 +
   1.598 +/******************************************************************************
   1.599 + * TSFAttrPropImpl
   1.600 + ******************************************************************************/
   1.601 +
   1.602 +class TSFAttrPropImpl : public ITfProperty
   1.603 +{
   1.604 +private:
   1.605 +  ULONG mRefCnt;
   1.606 +
   1.607 +public:
   1.608 +  nsTArray<nsRefPtr<TSFRangeImpl> > mRanges;
   1.609 +
   1.610 +  TSFAttrPropImpl() :
   1.611 +      mRefCnt(0)
   1.612 +  {
   1.613 +  }
   1.614 +
   1.615 +  ~TSFAttrPropImpl()
   1.616 +  {
   1.617 +  }
   1.618 +
   1.619 +public: // IUnknown
   1.620 +
   1.621 +  STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk)
   1.622 +  {
   1.623 +    *ppUnk = nullptr;
   1.624 +    if (IID_IUnknown == riid || IID_ITfProperty == riid ||
   1.625 +        IID_ITfReadOnlyProperty == riid)
   1.626 +      *ppUnk = static_cast<ITfProperty*>(this);
   1.627 +    if (*ppUnk)
   1.628 +      AddRef();
   1.629 +    return *ppUnk ? S_OK : E_NOINTERFACE;
   1.630 +  }
   1.631 +
   1.632 +  STDMETHODIMP_(ULONG) AddRef(void)
   1.633 +  {
   1.634 +    return ++mRefCnt;
   1.635 +  }
   1.636 +
   1.637 +  STDMETHODIMP_(ULONG) Release(void)
   1.638 +  {
   1.639 +    if (--mRefCnt) return mRefCnt;
   1.640 +    delete this;
   1.641 +    return 0;
   1.642 +  }
   1.643 +
   1.644 +public: // ITfProperty
   1.645 +
   1.646 +  STDMETHODIMP FindRange(TfEditCookie ec, ITfRange *pRange, ITfRange **ppRange,
   1.647 +                         TfAnchor aPos)
   1.648 +  {
   1.649 +    NS_NOTREACHED("ITfProperty::FindRange");
   1.650 +    return E_NOTIMPL;
   1.651 +  }
   1.652 +
   1.653 +  STDMETHODIMP SetValueStore(TfEditCookie ec, ITfRange *pRange,
   1.654 +                             ITfPropertyStore *pPropStore)
   1.655 +  {
   1.656 +    NS_NOTREACHED("ITfProperty::SetValueStore");
   1.657 +    return E_NOTIMPL;
   1.658 +  }
   1.659 +
   1.660 +  STDMETHODIMP SetValue(TfEditCookie ec, ITfRange *pRange,
   1.661 +                        const VARIANT *pvarValue)
   1.662 +  {
   1.663 +    NS_NOTREACHED("ITfProperty::SetValue");
   1.664 +    return E_NOTIMPL;
   1.665 +  }
   1.666 +
   1.667 +  STDMETHODIMP Clear(TfEditCookie ec, ITfRange *pRange)
   1.668 +  {
   1.669 +    NS_NOTREACHED("ITfProperty::Clear");
   1.670 +    return E_NOTIMPL;
   1.671 +  }
   1.672 +
   1.673 +public: // ITfReadOnlyProperty
   1.674 +
   1.675 +  STDMETHODIMP GetType(GUID *pguid)
   1.676 +  {
   1.677 +    NS_NOTREACHED("ITfReadOnlyProperty::GetType");
   1.678 +    return E_NOTIMPL;
   1.679 +  }
   1.680 +
   1.681 +  STDMETHODIMP EnumRanges(TfEditCookie ec, IEnumTfRanges **ppEnum,
   1.682 +                          ITfRange *pTargetRange)
   1.683 +  {
   1.684 +    NS_ENSURE_TRUE(ppEnum, E_INVALIDARG);
   1.685 +    NS_ENSURE_TRUE(pTargetRange, E_INVALIDARG);
   1.686 +
   1.687 +    // XXX ec checking is not implemented yet.
   1.688 +
   1.689 +    LONG targetStart = 0, targetEnd = 0;
   1.690 +    if (pTargetRange) {
   1.691 +      HRESULT hr = GetRegularExtent(pTargetRange, targetStart, targetEnd);
   1.692 +      NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.693 +    }
   1.694 +    nsRefPtr<TSFEnumRangeImpl> er = new TSFEnumRangeImpl();
   1.695 +    NS_ENSURE_TRUE(er, E_OUTOFMEMORY);
   1.696 +    for (uint32_t i = 0; i < mRanges.Length(); i++) {
   1.697 +      LONG start, end;
   1.698 +      HRESULT hr = GetRegularExtent(mRanges[i], start, end);
   1.699 +      NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.700 +      if (pTargetRange) {
   1.701 +        // If pTargetRange is not null and the current range is not overlapped
   1.702 +        // with it, we don't need to add range.
   1.703 +        if (targetStart > end || targetEnd < start)
   1.704 +          continue;
   1.705 +        // Otherwise, shrink to the target range.
   1.706 +        start = std::max(targetStart, start);
   1.707 +        end = std::min(targetEnd, end);
   1.708 +      }
   1.709 +      nsRefPtr<TSFRangeImpl> range = new TSFRangeImpl(start, end - start);
   1.710 +      NS_ENSURE_TRUE(range, E_OUTOFMEMORY);
   1.711 +      er->mRanges.AppendElement(range);
   1.712 +    }
   1.713 +    *ppEnum = er;
   1.714 +    (*ppEnum)->AddRef();
   1.715 +    return S_OK;
   1.716 +  }
   1.717 +
   1.718 +  STDMETHODIMP GetValue(TfEditCookie ec, ITfRange *pRange, VARIANT *pvarValue)
   1.719 +  {
   1.720 +    NS_ENSURE_TRUE(pvarValue, E_INVALIDARG);
   1.721 +
   1.722 +    LONG givenStart, givenEnd;
   1.723 +    HRESULT hr = GetRegularExtent(pRange, givenStart, givenEnd);
   1.724 +    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.725 +    for (uint32_t i = 0; i < mRanges.Length(); i++) {
   1.726 +      LONG start, end;
   1.727 +      HRESULT hr = GetRegularExtent(mRanges[i], start, end);
   1.728 +      NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.729 +      // pRange must be same as (or included in) a range of mRanges.
   1.730 +      if (givenStart > start || givenEnd < end)
   1.731 +        continue;
   1.732 +      pvarValue->vt = VT_I4;
   1.733 +      pvarValue->lVal = static_cast<DWORD>(GUID_ATOM_COMPOSING_SELECTION_ATTR);
   1.734 +      return S_OK;
   1.735 +    }
   1.736 +    return E_FAIL;
   1.737 +  }
   1.738 +
   1.739 +  STDMETHODIMP GetContext(ITfContext **ppContext)
   1.740 +  {
   1.741 +    NS_NOTREACHED("ITfReadOnlyProperty::GetContext");
   1.742 +    return E_NOTIMPL;
   1.743 +  }
   1.744 +};
   1.745 +
   1.746 +/******************************************************************************
   1.747 + * TSFContextImpl
   1.748 + ******************************************************************************/
   1.749 +
   1.750 +class TSFContextImpl : public ITfContext,
   1.751 +                       public ITfCompositionView, public ITextStoreACPSink
   1.752 +{
   1.753 +private:
   1.754 +  ULONG mRefCnt;
   1.755 +
   1.756 +public:
   1.757 +  nsRefPtr<TSFAttrPropImpl> mAttrProp;
   1.758 +  nsRefPtr<TSFDocumentMgrImpl> mDocMgr;
   1.759 +  bool mTextChanged;
   1.760 +  bool mSelChanged;
   1.761 +  TS_TEXTCHANGE mTextChangeData;
   1.762 +
   1.763 +public:
   1.764 +  TSFContextImpl(TSFDocumentMgrImpl* aDocMgr) :
   1.765 +      mDocMgr(aDocMgr), mRefCnt(0), mTextChanged(false),
   1.766 +      mSelChanged(false)
   1.767 +  {
   1.768 +    mAttrProp = new TSFAttrPropImpl();
   1.769 +    if (!mAttrProp) {
   1.770 +      NS_NOTREACHED("TSFContextImpl::TSFContextImpl (OOM)");
   1.771 +      return;
   1.772 +    }
   1.773 +  }
   1.774 +
   1.775 +  ~TSFContextImpl()
   1.776 +  {
   1.777 +  }
   1.778 +
   1.779 +public: // IUnknown
   1.780 +
   1.781 +  STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk)
   1.782 +  {
   1.783 +    *ppUnk = nullptr;
   1.784 +    if (IID_IUnknown == riid || IID_ITfContext == riid)
   1.785 +      *ppUnk = static_cast<ITfContext*>(this);
   1.786 +    else if (IID_ITextStoreACPSink == riid)
   1.787 +      *ppUnk = static_cast<ITextStoreACPSink*>(this);
   1.788 +    if (*ppUnk)
   1.789 +      AddRef();
   1.790 +    return *ppUnk ? S_OK : E_NOINTERFACE;
   1.791 +  }
   1.792 +
   1.793 +  STDMETHODIMP_(ULONG) AddRef(void)
   1.794 +  {
   1.795 +    return ++mRefCnt;
   1.796 +  }
   1.797 +
   1.798 +  STDMETHODIMP_(ULONG) Release(void)
   1.799 +  {
   1.800 +    if (--mRefCnt) return mRefCnt;
   1.801 +    delete this;
   1.802 +    return 0;
   1.803 +  }
   1.804 +
   1.805 +public: // ITfContext
   1.806 +
   1.807 +  STDMETHODIMP RequestEditSession(TfClientId tid, ITfEditSession *pes,
   1.808 +                                  DWORD dwFlags, HRESULT *phrSession)
   1.809 +  {
   1.810 +    NS_NOTREACHED("ITfContext::RequestEditSession");
   1.811 +    return E_NOTIMPL;
   1.812 +  }
   1.813 +
   1.814 +  STDMETHODIMP InWriteSession(TfClientId tid, BOOL *pfWriteSession)
   1.815 +  {
   1.816 +    NS_NOTREACHED("ITfContext::InWriteSession");
   1.817 +    return E_NOTIMPL;
   1.818 +  }
   1.819 +
   1.820 +  STDMETHODIMP GetSelection(TfEditCookie ec, ULONG ulIndex, ULONG ulCount,
   1.821 +                            TF_SELECTION *pSelection, ULONG *pcFetched)
   1.822 +  {
   1.823 +    NS_NOTREACHED("ITfContext::GetSelection");
   1.824 +    return E_NOTIMPL;
   1.825 +  }
   1.826 +
   1.827 +  STDMETHODIMP SetSelection(TfEditCookie ec, ULONG ulCount,
   1.828 +                         const TF_SELECTION *pSelection)
   1.829 +  {
   1.830 +    NS_NOTREACHED("ITfContext::SetSelection");
   1.831 +    return E_NOTIMPL;
   1.832 +  }
   1.833 +
   1.834 +  STDMETHODIMP GetStart(TfEditCookie ec, ITfRange **ppStart)
   1.835 +  {
   1.836 +    NS_NOTREACHED("ITfContext::GetStart");
   1.837 +    return E_NOTIMPL;
   1.838 +  }
   1.839 +
   1.840 +  STDMETHODIMP GetEnd(TfEditCookie ec, ITfRange **ppEnd)
   1.841 +  {
   1.842 +    NS_NOTREACHED("ITfContext::GetEnd");
   1.843 +    return E_NOTIMPL;
   1.844 +  }
   1.845 +
   1.846 +  STDMETHODIMP GetActiveView(ITfContextView **ppView)
   1.847 +  {
   1.848 +    NS_NOTREACHED("ITfContext::GetActiveView");
   1.849 +    return E_NOTIMPL;
   1.850 +  }
   1.851 +
   1.852 +  STDMETHODIMP EnumViews(IEnumTfContextViews **ppEnum)
   1.853 +  {
   1.854 +    NS_NOTREACHED("ITfContext::EnumViews");
   1.855 +    return E_NOTIMPL;
   1.856 +  }
   1.857 +
   1.858 +  STDMETHODIMP GetStatus(TF_STATUS *pdcs)
   1.859 +  {
   1.860 +    NS_NOTREACHED("ITfContext::GetStatus");
   1.861 +    return E_NOTIMPL;
   1.862 +  }
   1.863 +
   1.864 +  STDMETHODIMP GetProperty(REFGUID guidProp, ITfProperty **ppProp)
   1.865 +  {
   1.866 +    NS_ENSURE_TRUE(ppProp, E_INVALIDARG);
   1.867 +    if (guidProp == GUID_PROP_ATTRIBUTE) {
   1.868 +      (*ppProp) = mAttrProp;
   1.869 +      (*ppProp)->AddRef();
   1.870 +      return S_OK;
   1.871 +    }
   1.872 +    NS_NOTREACHED("ITfContext::GetProperty");
   1.873 +    return E_NOTIMPL;
   1.874 +  }
   1.875 +
   1.876 +  STDMETHODIMP GetAppProperty(REFGUID guidProp, ITfReadOnlyProperty **ppProp)
   1.877 +  {
   1.878 +    NS_NOTREACHED("ITfContext::GetAppProperty");
   1.879 +    return E_NOTIMPL;
   1.880 +  }
   1.881 +
   1.882 +  STDMETHODIMP TrackProperties(const GUID **prgProp, ULONG cProp,
   1.883 +                            const GUID **prgAppProp, ULONG cAppProp,
   1.884 +                            ITfReadOnlyProperty **ppProperty)
   1.885 +  {
   1.886 +    NS_NOTREACHED("ITfContext::TrackProperties");
   1.887 +    return E_NOTIMPL;
   1.888 +  }
   1.889 +
   1.890 +  STDMETHODIMP EnumProperties(IEnumTfProperties **ppEnum)
   1.891 +  {
   1.892 +    NS_NOTREACHED("ITfContext::EnumProperties");
   1.893 +    return E_NOTIMPL;
   1.894 +  }
   1.895 +
   1.896 +  STDMETHODIMP GetDocumentMgr(ITfDocumentMgr **ppDm)
   1.897 +  {
   1.898 +    NS_NOTREACHED("ITfContext::GetDocumentMgr");
   1.899 +    return E_NOTIMPL;
   1.900 +  }
   1.901 +
   1.902 +  STDMETHODIMP CreateRangeBackup(TfEditCookie ec, ITfRange *pRange,
   1.903 +                              ITfRangeBackup **ppBackup)
   1.904 +  {
   1.905 +    NS_NOTREACHED("ITfContext::CreateRangeBackup");
   1.906 +    return E_NOTIMPL;
   1.907 +  }
   1.908 +
   1.909 +public: // ITfCompositionView
   1.910 +
   1.911 +  STDMETHODIMP GetOwnerClsid(CLSID* pclsid)
   1.912 +  {
   1.913 +    NS_NOTREACHED("ITfCompositionView::GetOwnerClsid");
   1.914 +    return E_NOTIMPL;
   1.915 +  }
   1.916 +
   1.917 +  STDMETHODIMP GetRange(ITfRange** ppRange)
   1.918 +  {
   1.919 +    NS_ENSURE_TRUE(ppRange, E_INVALIDARG);
   1.920 +    NS_ENSURE_TRUE(mAttrProp->mRanges.Length() > 0, E_FAIL);
   1.921 +    LONG start = LONG_MAX, end = 0;
   1.922 +    for (uint32_t i = 0; i < mAttrProp->mRanges.Length(); i++) {
   1.923 +      LONG tmpStart, tmpEnd;
   1.924 +      HRESULT hr = GetRegularExtent(mAttrProp->mRanges[i], tmpStart, tmpEnd);
   1.925 +      NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.926 +      start = std::min(start, tmpStart);
   1.927 +      end = std::max(end, tmpEnd);
   1.928 +    }
   1.929 +    nsRefPtr<TSFRangeImpl> range = new TSFRangeImpl();
   1.930 +    NS_ENSURE_TRUE(range, E_OUTOFMEMORY);
   1.931 +    HRESULT hr = range->SetExtent(start, end - start);
   1.932 +    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.933 +    (*ppRange) = range;
   1.934 +    (*ppRange)->AddRef();
   1.935 +    return S_OK;
   1.936 +  }
   1.937 +
   1.938 +public: // ITextStoreACPSink
   1.939 +
   1.940 +  STDMETHODIMP OnTextChange(DWORD dwFlags, const TS_TEXTCHANGE *pChange)
   1.941 +  {
   1.942 +    mTextChanged = true;
   1.943 +    mTextChangeData = *pChange;
   1.944 +    return S_OK;
   1.945 +  }
   1.946 +
   1.947 +  STDMETHODIMP OnSelectionChange(void)
   1.948 +  {
   1.949 +    mSelChanged = true;
   1.950 +    return S_OK;
   1.951 +  }
   1.952 +
   1.953 +  STDMETHODIMP OnLayoutChange(TsLayoutCode lcode, TsViewCookie vcView)
   1.954 +  {
   1.955 +    return S_OK;
   1.956 +  }
   1.957 +
   1.958 +  STDMETHODIMP OnStatusChange(DWORD dwFlags)
   1.959 +  {
   1.960 +    return S_OK;
   1.961 +  }
   1.962 +
   1.963 +  STDMETHODIMP OnAttrsChange(LONG acpStart, LONG acpEnd, ULONG cAttrs,
   1.964 +                          const TS_ATTRID *paAttrs)
   1.965 +  {
   1.966 +    return S_OK;
   1.967 +  }
   1.968 +
   1.969 +  STDMETHODIMP OnLockGranted(DWORD dwLockFlags);
   1.970 +
   1.971 +  STDMETHODIMP OnStartEditTransaction(void)
   1.972 +  {
   1.973 +    return S_OK;
   1.974 +  }
   1.975 +
   1.976 +  STDMETHODIMP OnEndEditTransaction(void)
   1.977 +  {
   1.978 +    return S_OK;
   1.979 +  }
   1.980 +};
   1.981 +
   1.982 +/******************************************************************************
   1.983 + * TSFDocumentMgrImpl
   1.984 + ******************************************************************************/
   1.985 +
   1.986 +class TSFDocumentMgrImpl : public ITfDocumentMgr
   1.987 +{
   1.988 +private:
   1.989 +  ULONG mRefCnt;
   1.990 +
   1.991 +public:
   1.992 +  nsRefPtr<TSFMgrImpl> mMgr;
   1.993 +  nsRefPtr<ITextStoreACP> mStore;
   1.994 +  nsRefPtr<TSFContextImpl> mContextBase;
   1.995 +  nsRefPtr<TSFContextImpl> mContextTop; // XXX currently, we don't support this.
   1.996 +
   1.997 +public:
   1.998 +  TSFDocumentMgrImpl(TSFMgrImpl* aMgr) :
   1.999 +      mRefCnt(0), mMgr(aMgr)
  1.1000 +  {
  1.1001 +  }
  1.1002 +
  1.1003 +  ~TSFDocumentMgrImpl()
  1.1004 +  {
  1.1005 +  }
  1.1006 +
  1.1007 +public: // IUnknown
  1.1008 +
  1.1009 +  STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk)
  1.1010 +  {
  1.1011 +    *ppUnk = nullptr;
  1.1012 +    if (IID_IUnknown == riid || IID_ITfDocumentMgr == riid)
  1.1013 +      *ppUnk = static_cast<ITfDocumentMgr*>(this);
  1.1014 +    if (*ppUnk)
  1.1015 +      AddRef();
  1.1016 +    return *ppUnk ? S_OK : E_NOINTERFACE;
  1.1017 +  }
  1.1018 +
  1.1019 +  STDMETHODIMP_(ULONG) AddRef(void)
  1.1020 +  {
  1.1021 +    return ++mRefCnt;
  1.1022 +  }
  1.1023 +
  1.1024 +  STDMETHODIMP_(ULONG) Release(void);
  1.1025 +
  1.1026 +public: // ITfDocumentMgr
  1.1027 +
  1.1028 +  STDMETHODIMP CreateContext(TfClientId tidOwner, DWORD dwFlags,
  1.1029 +                             IUnknown *punk, ITfContext **ppic,
  1.1030 +                             TfEditCookie *pecTextStore)
  1.1031 +  {
  1.1032 +    nsRefPtr<TSFContextImpl> context = new TSFContextImpl(this);
  1.1033 +    punk->QueryInterface(IID_ITextStoreACP, getter_AddRefs(mStore));
  1.1034 +    NS_ENSURE_TRUE(mStore, E_FAIL);
  1.1035 +    HRESULT hr =
  1.1036 +      mStore->AdviseSink(IID_ITextStoreACPSink,
  1.1037 +                         static_cast<ITextStoreACPSink*>(context.get()),
  1.1038 +                         TS_AS_ALL_SINKS);
  1.1039 +    if (FAILED(hr)) mStore = nullptr;
  1.1040 +    NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL);
  1.1041 +    (*ppic) = context;
  1.1042 +    (*ppic)->AddRef();
  1.1043 +    *pecTextStore = 1;
  1.1044 +    return S_OK;
  1.1045 +  }
  1.1046 +
  1.1047 +  STDMETHODIMP Push(ITfContext *pic)
  1.1048 +  {
  1.1049 +    if (mContextTop) {
  1.1050 +      NS_NOTREACHED("TSFDocumentMgrImpl::Push stack is already full");
  1.1051 +      return E_FAIL;
  1.1052 +    }
  1.1053 +    if (mContextBase) {
  1.1054 +      NS_WARNING("TSFDocumentMgrImpl::Push additional context is pushed, but we don't support that yet.");
  1.1055 +      if (mContextBase == pic) {
  1.1056 +        NS_NOTREACHED("TSFDocumentMgrImpl::Push same context is pused again");
  1.1057 +        return E_FAIL;
  1.1058 +      }
  1.1059 +      mContextTop = static_cast<TSFContextImpl*>(pic);
  1.1060 +      return S_OK;
  1.1061 +    }
  1.1062 +    mContextBase = static_cast<TSFContextImpl*>(pic);
  1.1063 +    return S_OK;
  1.1064 +  }
  1.1065 +
  1.1066 +  STDMETHODIMP Pop(DWORD dwFlags)
  1.1067 +  {
  1.1068 +    if (!mStore)
  1.1069 +      return E_FAIL;
  1.1070 +    if (dwFlags == TF_POPF_ALL) {
  1.1071 +      NS_ENSURE_TRUE(mContextBase, E_FAIL);
  1.1072 +      mStore->UnadviseSink(static_cast<ITextStoreACPSink*>(mContextBase.get()));
  1.1073 +      mStore = nullptr;
  1.1074 +      mContextBase = nullptr;
  1.1075 +      mContextTop = nullptr;
  1.1076 +      return S_OK;
  1.1077 +    }
  1.1078 +    if (dwFlags == 0) {
  1.1079 +      if (!mContextTop) {
  1.1080 +        NS_NOTREACHED("TSFDocumentMgrImpl::Pop there is non-base context");
  1.1081 +        return E_FAIL;
  1.1082 +      }
  1.1083 +      mContextTop = nullptr;
  1.1084 +      return S_OK;
  1.1085 +    }
  1.1086 +    NS_NOTREACHED("TSFDocumentMgrImpl::Pop invalid flag");
  1.1087 +    return E_FAIL;
  1.1088 +  }
  1.1089 +
  1.1090 +  STDMETHODIMP GetTop(ITfContext **ppic)
  1.1091 +  {
  1.1092 +    (*ppic) = mContextTop ? mContextTop : mContextBase;
  1.1093 +    if (*ppic) (*ppic)->AddRef();
  1.1094 +    return S_OK;
  1.1095 +  }
  1.1096 +
  1.1097 +  STDMETHODIMP GetBase(ITfContext **ppic)
  1.1098 +  {
  1.1099 +    (*ppic) = mContextBase;
  1.1100 +    if (*ppic) (*ppic)->AddRef();
  1.1101 +    return S_OK;
  1.1102 +  }
  1.1103 +
  1.1104 +  STDMETHODIMP EnumContexts(IEnumTfContexts **ppEnum)
  1.1105 +  {
  1.1106 +    NS_NOTREACHED("ITfDocumentMgr::EnumContexts");
  1.1107 +    return E_NOTIMPL;
  1.1108 +  }
  1.1109 +
  1.1110 +};
  1.1111 +
  1.1112 +/******************************************************************************
  1.1113 + * TSFMgrImpl
  1.1114 + ******************************************************************************/
  1.1115 +
  1.1116 +class TSFMgrImpl : public ITfThreadMgr,
  1.1117 +                   public ITfDisplayAttributeMgr, public ITfCategoryMgr
  1.1118 +{
  1.1119 +private:
  1.1120 +  ULONG mRefCnt;
  1.1121 +
  1.1122 +public:
  1.1123 +  nsRefPtr<TestApp> mTestApp;
  1.1124 +  TestApp::test_type mTest;
  1.1125 +  bool mDeactivated;
  1.1126 +  TSFDocumentMgrImpl* mFocusedDocument; // Must be raw pointer, but strong.
  1.1127 +  int32_t mFocusCount;
  1.1128 +
  1.1129 +  TSFMgrImpl(TestApp* test) : mTestApp(test), mTest(nullptr), mRefCnt(0),
  1.1130 +    mDeactivated(false), mFocusedDocument(nullptr), mFocusCount(0)
  1.1131 +  {
  1.1132 +  }
  1.1133 +
  1.1134 +  ~TSFMgrImpl()
  1.1135 +  {
  1.1136 +  }
  1.1137 +
  1.1138 +public: // IUnknown
  1.1139 +
  1.1140 +  STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk)
  1.1141 +  {
  1.1142 +    *ppUnk = nullptr;
  1.1143 +    if (IID_IUnknown == riid || IID_ITfThreadMgr == riid)
  1.1144 +      *ppUnk = static_cast<ITfThreadMgr*>(this);
  1.1145 +    else if (IID_ITfDisplayAttributeMgr == riid)
  1.1146 +      *ppUnk = static_cast<ITfDisplayAttributeMgr*>(this);
  1.1147 +    else if (IID_ITfCategoryMgr == riid)
  1.1148 +      *ppUnk = static_cast<ITfCategoryMgr*>(this);
  1.1149 +    if (*ppUnk)
  1.1150 +      AddRef();
  1.1151 +    return *ppUnk ? S_OK : E_NOINTERFACE;
  1.1152 +  }
  1.1153 +
  1.1154 +  STDMETHODIMP_(ULONG) AddRef(void)
  1.1155 +  {
  1.1156 +    return ++mRefCnt;
  1.1157 +  }
  1.1158 +
  1.1159 +  STDMETHODIMP_(ULONG) Release(void)
  1.1160 +  {
  1.1161 +    if (--mRefCnt) return mRefCnt;
  1.1162 +    delete this;
  1.1163 +    return 0;
  1.1164 +  }
  1.1165 +
  1.1166 +public: // ITfThreadMgr
  1.1167 +
  1.1168 +  STDMETHODIMP Activate(TfClientId *ptid)
  1.1169 +  {
  1.1170 +    *ptid = 1;
  1.1171 +    return S_OK;
  1.1172 +  }
  1.1173 +
  1.1174 +  STDMETHODIMP Deactivate(void)
  1.1175 +  {
  1.1176 +    mDeactivated = true;
  1.1177 +    return S_OK;
  1.1178 +  }
  1.1179 +
  1.1180 +  STDMETHODIMP CreateDocumentMgr(ITfDocumentMgr **ppdim)
  1.1181 +  {
  1.1182 +    nsRefPtr<TSFDocumentMgrImpl> docMgr = new TSFDocumentMgrImpl(this);
  1.1183 +    if (!docMgr) {
  1.1184 +      NS_NOTREACHED("TSFMgrImpl::CreateDocumentMgr (OOM)");
  1.1185 +      return E_OUTOFMEMORY;
  1.1186 +    }
  1.1187 +    (*ppdim) = docMgr;
  1.1188 +    (*ppdim)->AddRef();
  1.1189 +    return S_OK;
  1.1190 +  }
  1.1191 +
  1.1192 +  STDMETHODIMP EnumDocumentMgrs(IEnumTfDocumentMgrs **ppEnum)
  1.1193 +  {
  1.1194 +    NS_NOTREACHED("ITfThreadMgr::EnumDocumentMgrs");
  1.1195 +    return E_NOTIMPL;
  1.1196 +  }
  1.1197 +
  1.1198 +  STDMETHODIMP GetFocus(ITfDocumentMgr **ppdimFocus)
  1.1199 +  {
  1.1200 +    (*ppdimFocus) = mFocusedDocument;
  1.1201 +    if (*ppdimFocus) (*ppdimFocus)->AddRef();
  1.1202 +    return S_OK;
  1.1203 +  }
  1.1204 +
  1.1205 +  STDMETHODIMP SetFocus(ITfDocumentMgr *pdimFocus)
  1.1206 +  {
  1.1207 +    if (!pdimFocus) {
  1.1208 +      NS_NOTREACHED("ITfThreadMgr::SetFocus must not be called with NULL");
  1.1209 +      return E_FAIL;
  1.1210 +    }
  1.1211 +    mFocusCount++;
  1.1212 +    if (mFocusedDocument == pdimFocus) {
  1.1213 +      return S_OK;
  1.1214 +    }
  1.1215 +    mFocusedDocument = static_cast<TSFDocumentMgrImpl*>(pdimFocus);
  1.1216 +    mFocusedDocument->AddRef();
  1.1217 +    return S_OK;
  1.1218 +  }
  1.1219 +
  1.1220 +  STDMETHODIMP AssociateFocus(HWND hwnd, ITfDocumentMgr *pdimNew,
  1.1221 +                           ITfDocumentMgr **ppdimPrev)
  1.1222 +  {
  1.1223 +    NS_NOTREACHED("ITfThreadMgr::AssociateFocus");
  1.1224 +    return E_NOTIMPL;
  1.1225 +  }
  1.1226 +
  1.1227 +  STDMETHODIMP IsThreadFocus(BOOL *pfThreadFocus)
  1.1228 +  {
  1.1229 +    *pfThreadFocus = TRUE;
  1.1230 +    return S_OK;
  1.1231 +  }
  1.1232 +
  1.1233 +  STDMETHODIMP GetFunctionProvider(REFCLSID clsid,
  1.1234 +                                ITfFunctionProvider **ppFuncProv)
  1.1235 +  {
  1.1236 +    NS_NOTREACHED("ITfThreadMgr::GetFunctionProvider");
  1.1237 +    return E_NOTIMPL;
  1.1238 +  }
  1.1239 +
  1.1240 +  STDMETHODIMP EnumFunctionProviders(IEnumTfFunctionProviders **ppEnum)
  1.1241 +  {
  1.1242 +    NS_NOTREACHED("ITfThreadMgr::EnumFunctionProviders");
  1.1243 +    return E_NOTIMPL;
  1.1244 +  }
  1.1245 +
  1.1246 +  STDMETHODIMP GetGlobalCompartment(ITfCompartmentMgr **ppCompMgr)
  1.1247 +  {
  1.1248 +    NS_NOTREACHED("ITfThreadMgr::GetGlobalCompartment");
  1.1249 +    return E_NOTIMPL;
  1.1250 +  }
  1.1251 +
  1.1252 +public: // ITfCategoryMgr
  1.1253 +
  1.1254 +  STDMETHODIMP RegisterCategory(REFCLSID rclsid, REFGUID rcatid, REFGUID rguid)
  1.1255 +  {
  1.1256 +    NS_NOTREACHED("ITfCategoryMgr::RegisterCategory");
  1.1257 +    return E_NOTIMPL;
  1.1258 +  }
  1.1259 +
  1.1260 +  STDMETHODIMP UnregisterCategory(REFCLSID rclsid, REFGUID rcatid, REFGUID rguid)
  1.1261 +  {
  1.1262 +    NS_NOTREACHED("ITfCategoryMgr::UnregisterCategory");
  1.1263 +    return E_NOTIMPL;
  1.1264 +  }
  1.1265 +
  1.1266 +  STDMETHODIMP EnumCategoriesInItem(REFGUID rguid, IEnumGUID **ppEnum)
  1.1267 +  {
  1.1268 +    NS_NOTREACHED("ITfCategoryMgr::EnumCategoriesInItem");
  1.1269 +    return E_NOTIMPL;
  1.1270 +  }
  1.1271 +
  1.1272 +  STDMETHODIMP EnumItemsInCategory(REFGUID rcatid, IEnumGUID **ppEnum)
  1.1273 +  {
  1.1274 +    NS_NOTREACHED("ITfCategoryMgr::EnumItemsInCategory");
  1.1275 +    return E_NOTIMPL;
  1.1276 +  }
  1.1277 +
  1.1278 +  STDMETHODIMP FindClosestCategory(REFGUID rguid, GUID *pcatid,
  1.1279 +                                   const GUID **ppcatidList, ULONG ulCount)
  1.1280 +  {
  1.1281 +    NS_NOTREACHED("ITfCategoryMgr::FindClosestCategory");
  1.1282 +    return E_NOTIMPL;
  1.1283 +  }
  1.1284 +
  1.1285 +  STDMETHODIMP RegisterGUIDDescription(REFCLSID rclsid, REFGUID rguid,
  1.1286 +                                       const WCHAR *pchDesc, ULONG cch)
  1.1287 +  {
  1.1288 +    NS_NOTREACHED("ITfCategoryMgr::RegisterGUIDDescription");
  1.1289 +    return E_NOTIMPL;
  1.1290 +  }
  1.1291 +
  1.1292 +  STDMETHODIMP UnregisterGUIDDescription(REFCLSID rclsid, REFGUID rguid)
  1.1293 +  {
  1.1294 +    NS_NOTREACHED("ITfCategoryMgr::UnregisterGUIDDescription");
  1.1295 +    return E_NOTIMPL;
  1.1296 +  }
  1.1297 +
  1.1298 +  STDMETHODIMP GetGUIDDescription(REFGUID rguid, BSTR *pbstrDesc)
  1.1299 +  {
  1.1300 +    NS_NOTREACHED("ITfCategoryMgr::GetGUIDDescription");
  1.1301 +    return E_NOTIMPL;
  1.1302 +  }
  1.1303 +
  1.1304 +  STDMETHODIMP RegisterGUIDDWORD(REFCLSID rclsid, REFGUID rguid, DWORD dw)
  1.1305 +  {
  1.1306 +    NS_NOTREACHED("ITfCategoryMgr::RegisterGUIDDWORD");
  1.1307 +    return E_NOTIMPL;
  1.1308 +  }
  1.1309 +
  1.1310 +  STDMETHODIMP UnregisterGUIDDWORD(REFCLSID rclsid, REFGUID rguid)
  1.1311 +  {
  1.1312 +    NS_NOTREACHED("ITfCategoryMgr::UnregisterGUIDDWORD");
  1.1313 +    return E_NOTIMPL;
  1.1314 +  }
  1.1315 +
  1.1316 +  STDMETHODIMP GetGUIDDWORD(REFGUID rguid, DWORD *pdw)
  1.1317 +  {
  1.1318 +    NS_NOTREACHED("ITfCategoryMgr::GetGUIDDWORD");
  1.1319 +    return E_NOTIMPL;
  1.1320 +  }
  1.1321 +
  1.1322 +  STDMETHODIMP RegisterGUID(REFGUID rguid, TfGuidAtom *pguidatom)
  1.1323 +  {
  1.1324 +    NS_NOTREACHED("ITfCategoryMgr::RegisterGUID");
  1.1325 +    return E_NOTIMPL;
  1.1326 +  }
  1.1327 +
  1.1328 +  STDMETHODIMP GetGUID(TfGuidAtom guidatom, GUID *pguid)
  1.1329 +  {
  1.1330 +    if (guidatom == GUID_ATOM_COMPOSING_SELECTION_ATTR) {
  1.1331 +      *pguid = GUID_COMPOSING_SELECTION_ATTR;
  1.1332 +      return S_OK;
  1.1333 +    }
  1.1334 +    NS_NOTREACHED("ITfCategoryMgr::GetGUID");
  1.1335 +    return E_FAIL;
  1.1336 +  }
  1.1337 +
  1.1338 +  STDMETHODIMP IsEqualTfGuidAtom(TfGuidAtom guidatom, REFGUID rguid,
  1.1339 +                                 BOOL *pfEqual)
  1.1340 +  {
  1.1341 +    NS_NOTREACHED("ITfCategoryMgr::IsEqualTfGuidAtom");
  1.1342 +    return E_NOTIMPL;
  1.1343 +  }
  1.1344 +
  1.1345 +public: // ITfDisplayAttributeMgr
  1.1346 +
  1.1347 +  STDMETHODIMP OnUpdateInfo()
  1.1348 +  {
  1.1349 +    NS_NOTREACHED("ITfDisplayAttributeMgr::OnUpdateInfo");
  1.1350 +    return E_NOTIMPL;
  1.1351 +  }
  1.1352 +
  1.1353 +  STDMETHODIMP EnumDisplayAttributeInfo(IEnumTfDisplayAttributeInfo **ppEnum)
  1.1354 +  {
  1.1355 +    NS_NOTREACHED("ITfDisplayAttributeMgr::EnumDisplayAttributeInfo");
  1.1356 +    return E_NOTIMPL;
  1.1357 +  }
  1.1358 +
  1.1359 +  STDMETHODIMP GetDisplayAttributeInfo(REFGUID guid,
  1.1360 +                                       ITfDisplayAttributeInfo **ppInfo,
  1.1361 +                                       CLSID *pclsidOwner)
  1.1362 +  {
  1.1363 +    NS_ENSURE_TRUE(ppInfo, E_INVALIDARG);
  1.1364 +    NS_ENSURE_TRUE(!pclsidOwner, E_INVALIDARG);
  1.1365 +    if (guid == GUID_COMPOSING_SELECTION_ATTR) {
  1.1366 +      (*ppInfo) = new TSFDispAttrInfoImpl(guid);
  1.1367 +      (*ppInfo)->AddRef();
  1.1368 +      return S_OK;
  1.1369 +    }
  1.1370 +    NS_NOTREACHED("ITfDisplayAttributeMgr::GetDisplayAttributeInfo");
  1.1371 +    return E_FAIL;
  1.1372 +  }
  1.1373 +
  1.1374 +public:
  1.1375 +
  1.1376 +  ITextStoreACP* GetFocusedStore()
  1.1377 +  {
  1.1378 +    return mFocusedDocument ? mFocusedDocument->mStore : nullptr;
  1.1379 +  }
  1.1380 +
  1.1381 +  TSFContextImpl* GetFocusedContext()
  1.1382 +  {
  1.1383 +    return mFocusedDocument ? mFocusedDocument->mContextBase : nullptr;
  1.1384 +  }
  1.1385 +
  1.1386 +  TSFAttrPropImpl* GetFocusedAttrProp()
  1.1387 +  {
  1.1388 +    TSFContextImpl* context = GetFocusedContext();
  1.1389 +    return context ? context->mAttrProp : nullptr;
  1.1390 +  }
  1.1391 +
  1.1392 +};
  1.1393 +
  1.1394 +STDMETHODIMP
  1.1395 +TSFContextImpl::OnLockGranted(DWORD dwLockFlags)
  1.1396 +{
  1.1397 +  // If we have a test, run it
  1.1398 +  if (mDocMgr->mMgr->mTest &&
  1.1399 +     !((*mDocMgr->mMgr->mTestApp).*(mDocMgr->mMgr->mTest))())
  1.1400 +    return S_FALSE;
  1.1401 +  return S_OK;
  1.1402 +}
  1.1403 +
  1.1404 +
  1.1405 +STDMETHODIMP_(ULONG)
  1.1406 +TSFDocumentMgrImpl::Release(void)
  1.1407 +{
  1.1408 +  --mRefCnt;
  1.1409 +  if (mRefCnt == 1 && mMgr->mFocusedDocument == this) {
  1.1410 +    mMgr->mFocusedDocument = nullptr;
  1.1411 +    --mRefCnt;
  1.1412 +  }
  1.1413 +  if (mRefCnt) return mRefCnt;
  1.1414 +  delete this;
  1.1415 +  return 0;
  1.1416 +}
  1.1417 +
  1.1418 +NS_IMPL_ISUPPORTS(TestApp, nsIWebProgressListener,
  1.1419 +                  nsISupportsWeakReference)
  1.1420 +
  1.1421 +nsresult
  1.1422 +TestApp::Run(void)
  1.1423 +{
  1.1424 +  // Create a test window
  1.1425 +  // We need a full-fledged window to test for TSF functionality
  1.1426 +  nsresult rv;
  1.1427 +  mAppShell = do_GetService(kAppShellCID);
  1.1428 +  NS_ENSURE_TRUE(mAppShell, NS_ERROR_UNEXPECTED);
  1.1429 +
  1.1430 +  nsCOMPtr<nsIAppShellService> appShellService(
  1.1431 +      do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
  1.1432 +  NS_ENSURE_TRUE(appShellService, NS_ERROR_UNEXPECTED);
  1.1433 +
  1.1434 +  nsCOMPtr<nsIURI> uri;
  1.1435 +  rv = NS_NewURI(getter_AddRefs(uri), "about:blank", nullptr);
  1.1436 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1437 +
  1.1438 +  rv = appShellService->CreateTopLevelWindow(nullptr, uri,
  1.1439 +                           nsIWebBrowserChrome::CHROME_DEFAULT,
  1.1440 +                           800 /*nsIAppShellService::SIZE_TO_CONTENT*/,
  1.1441 +                           600 /*nsIAppShellService::SIZE_TO_CONTENT*/,
  1.1442 +                           getter_AddRefs(mWindow));
  1.1443 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1444 +
  1.1445 +  nsCOMPtr<nsIDocShell> docShell;
  1.1446 +  rv = mWindow->GetDocShell(getter_AddRefs(docShell));
  1.1447 +  NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED);
  1.1448 +  nsCOMPtr<nsIWebProgress> progress(do_GetInterface(docShell));
  1.1449 +  NS_ENSURE_TRUE(progress, NS_ERROR_UNEXPECTED);
  1.1450 +  rv = progress->AddProgressListener(this,
  1.1451 +                                     nsIWebProgress::NOTIFY_STATE_WINDOW |
  1.1452 +                                         nsIWebProgress::NOTIFY_STATUS);
  1.1453 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1454 +
  1.1455 +  mAppShell->Run();
  1.1456 +  return NS_OK;
  1.1457 +}
  1.1458 +
  1.1459 +bool
  1.1460 +TestApp::CheckFailed(void)
  1.1461 +{
  1.1462 +  // All windows should be closed by now
  1.1463 +  if (mMgr && !mMgr->mDeactivated) {
  1.1464 +    fail("TSF not terminated properly");
  1.1465 +    mFailed = true;
  1.1466 +  }
  1.1467 +  mMgr = nullptr;
  1.1468 +  return mFailed;
  1.1469 +}
  1.1470 +
  1.1471 +nsresult
  1.1472 +TestApp::Init(void)
  1.1473 +{
  1.1474 +  // Replace TSF manager pointer, category manager pointer and display
  1.1475 +  // attribute manager pointer.
  1.1476 +  nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(mWindow));
  1.1477 +  NS_ENSURE_TRUE(baseWindow, NS_ERROR_UNEXPECTED);
  1.1478 +  nsCOMPtr<nsIWidget> widget;
  1.1479 +  nsresult rv = baseWindow->GetMainWidget(getter_AddRefs(widget));
  1.1480 +  NS_ENSURE_TRUE(widget, NS_ERROR_UNEXPECTED);
  1.1481 +
  1.1482 +  ITfThreadMgr **threadMgr = reinterpret_cast<ITfThreadMgr**>(
  1.1483 +      widget->GetNativeData(NS_NATIVE_TSF_THREAD_MGR));
  1.1484 +  if (!threadMgr) {
  1.1485 +    fail("nsIWidget::GetNativeData(NS_NATIVE_TSF_THREAD_MGR) not supported");
  1.1486 +    return NS_ERROR_FAILURE;
  1.1487 +  }
  1.1488 +  if (*threadMgr) {
  1.1489 +    (*threadMgr)->Deactivate();
  1.1490 +    (*threadMgr)->Release();
  1.1491 +    (*threadMgr) = nullptr;
  1.1492 +  } else {
  1.1493 +    // This is only for information. The test does not need TSF to run.
  1.1494 +    printf("TSF not initialized properly (TSF is not enabled/installed?)\n");
  1.1495 +  }
  1.1496 +
  1.1497 +  ITfCategoryMgr **catMgr = reinterpret_cast<ITfCategoryMgr**>(
  1.1498 +      widget->GetNativeData(NS_NATIVE_TSF_CATEGORY_MGR));
  1.1499 +  if (*catMgr) {
  1.1500 +    (*catMgr)->Release();
  1.1501 +    (*catMgr) = nullptr;
  1.1502 +  }
  1.1503 +  ITfDisplayAttributeMgr **daMgr = reinterpret_cast<ITfDisplayAttributeMgr**>(
  1.1504 +      widget->GetNativeData(NS_NATIVE_TSF_DISPLAY_ATTR_MGR));
  1.1505 +  if (*daMgr) {
  1.1506 +    (*daMgr)->Release();
  1.1507 +    (*daMgr) = nullptr;
  1.1508 +  }
  1.1509 +
  1.1510 +  mMgr = new TSFMgrImpl(this);
  1.1511 +  if (!mMgr) {
  1.1512 +    return NS_ERROR_OUT_OF_MEMORY;
  1.1513 +  }
  1.1514 +  (*threadMgr) = mMgr;
  1.1515 +  (*threadMgr)->AddRef();
  1.1516 +  (*catMgr) = mMgr;
  1.1517 +  (*catMgr)->AddRef();
  1.1518 +  (*daMgr) = mMgr;
  1.1519 +  (*daMgr)->AddRef();
  1.1520 +
  1.1521 +  // Apply the change
  1.1522 +  reinterpret_cast<ITfThreadMgr**>(
  1.1523 +      widget->GetNativeData(NS_NATIVE_TSF_THREAD_MGR));
  1.1524 +
  1.1525 +  // Create a couple of text boxes for testing
  1.1526 +  nsCOMPtr<nsIDOMWindow> win(do_GetInterface(mWindow));
  1.1527 +  NS_ENSURE_TRUE(win, NS_ERROR_UNEXPECTED);
  1.1528 +  nsCOMPtr<nsIDOMDocument> document;
  1.1529 +  rv = win->GetDocument(getter_AddRefs(document));
  1.1530 +  NS_ENSURE_TRUE(document, NS_ERROR_UNEXPECTED);
  1.1531 +  nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(document));
  1.1532 +  NS_ENSURE_TRUE(htmlDoc, NS_ERROR_UNEXPECTED);
  1.1533 +  nsCOMPtr<nsIDOMHTMLElement> htmlBody;
  1.1534 +  rv = htmlDoc->GetBody(getter_AddRefs(htmlBody));
  1.1535 +  NS_ENSURE_TRUE(htmlBody, NS_ERROR_UNEXPECTED);
  1.1536 +
  1.1537 +  nsCOMPtr<nsIDOMElement> form;
  1.1538 +  rv = htmlDoc->CreateElementNS(
  1.1539 +                     NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"),
  1.1540 +                     NS_LITERAL_STRING("form"),
  1.1541 +                     getter_AddRefs(form));
  1.1542 +  nsCOMPtr<nsIDOMElement> elem;
  1.1543 +  rv = htmlDoc->CreateElementNS(
  1.1544 +                     NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"),
  1.1545 +                     NS_LITERAL_STRING("input"),
  1.1546 +                     getter_AddRefs(elem));
  1.1547 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1548 +  elem->SetAttribute(NS_LITERAL_STRING("type"),
  1.1549 +                      NS_LITERAL_STRING("text"));
  1.1550 +  mInput = do_QueryInterface(elem);
  1.1551 +  NS_ENSURE_TRUE(mInput, NS_ERROR_UNEXPECTED);
  1.1552 +  rv = htmlDoc->CreateElementNS(
  1.1553 +                     NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"),
  1.1554 +                     NS_LITERAL_STRING("textarea"),
  1.1555 +                     getter_AddRefs(elem));
  1.1556 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1557 +  mTextArea = do_QueryInterface(elem);
  1.1558 +  NS_ENSURE_TRUE(mTextArea, NS_ERROR_UNEXPECTED);
  1.1559 +  rv = htmlDoc->CreateElementNS(
  1.1560 +                     NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"),
  1.1561 +                     NS_LITERAL_STRING("input"),
  1.1562 +                     getter_AddRefs(elem));
  1.1563 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1564 +  elem->SetAttribute(NS_LITERAL_STRING("type"),
  1.1565 +                     NS_LITERAL_STRING("button"));
  1.1566 +  mButton = do_QueryInterface(elem);
  1.1567 +  NS_ENSURE_TRUE(mButton, NS_ERROR_UNEXPECTED);
  1.1568 +
  1.1569 +  nsCOMPtr<nsIDOMNode> node;
  1.1570 +  rv = form->AppendChild(mInput, getter_AddRefs(node));
  1.1571 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1572 +  rv = form->AppendChild(mTextArea, getter_AddRefs(node));
  1.1573 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1574 +  rv = form->AppendChild(mButton, getter_AddRefs(node));
  1.1575 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1576 +  rv = htmlBody->AppendChild(form, getter_AddRefs(node));
  1.1577 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1578 +
  1.1579 +  // set a background color manually,
  1.1580 +  // otherwise the window might be transparent
  1.1581 +  static_cast<HTMLBodyElement*>(htmlBody)->
  1.1582 +      SetBgColor(NS_LITERAL_STRING("white"));
  1.1583 +
  1.1584 +  widget->Show(true);
  1.1585 +  widget->SetFocus();
  1.1586 +  return NS_OK;
  1.1587 +}
  1.1588 +
  1.1589 +nsresult
  1.1590 +TestApp::Term(void)
  1.1591 +{
  1.1592 +  mCurrentNode = nullptr;
  1.1593 +  mInput = nullptr;
  1.1594 +  mTextArea = nullptr;
  1.1595 +  mButton = nullptr;
  1.1596 +
  1.1597 +  nsCOMPtr<nsIDOMWindow> win(do_GetInterface(mWindow));
  1.1598 +  if (win)
  1.1599 +    win->Close();
  1.1600 +  win = nullptr;
  1.1601 +  mWindow = nullptr;
  1.1602 +
  1.1603 +  if (mAppShell)
  1.1604 +    mAppShell->Exit();
  1.1605 +  mAppShell = nullptr;
  1.1606 +  return NS_OK;
  1.1607 +}
  1.1608 +
  1.1609 +bool
  1.1610 +TestApp::RunTest(test_type aTest, bool aLock)
  1.1611 +{
  1.1612 +  bool succeeded;
  1.1613 +  if (aLock && mMgr && mMgr->GetFocusedStore()) {
  1.1614 +    mMgr->mTest = aTest;
  1.1615 +    HRESULT hr = E_FAIL;
  1.1616 +    mMgr->GetFocusedStore()->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &hr);
  1.1617 +    succeeded = hr == S_OK;
  1.1618 +  } else {
  1.1619 +    succeeded = (this->*aTest)();
  1.1620 +  }
  1.1621 +  mFailed |= !succeeded;
  1.1622 +  return succeeded;
  1.1623 +}
  1.1624 +
  1.1625 +NS_IMETHODIMP
  1.1626 +TestApp::OnStateChange(nsIWebProgress *aWebProgress,
  1.1627 +                        nsIRequest *aRequest,
  1.1628 +                        uint32_t aStateFlags,
  1.1629 +                        nsresult aStatus)
  1.1630 +{
  1.1631 +  NS_ASSERTION(aStateFlags & nsIWebProgressListener::STATE_IS_WINDOW &&
  1.1632 +              aStateFlags & nsIWebProgressListener::STATE_STOP, "wrong state");
  1.1633 +  if (NS_SUCCEEDED(Init())) {
  1.1634 +    mCurrentNode = mTextArea;
  1.1635 +    mTextArea->Focus();
  1.1636 +
  1.1637 +    if (RunTest(&TestApp::TestEditMessages))
  1.1638 +      passed("TestEditMessages");
  1.1639 +    if (RunTest(&TestApp::TestScrollMessages))
  1.1640 +      passed("TestScrollMessages");
  1.1641 +
  1.1642 +    if (RunTest(&TestApp::TestFocus, false))
  1.1643 +      passed("TestFocus");
  1.1644 +
  1.1645 +    mCurrentNode = mInput;
  1.1646 +    mInput->Focus();
  1.1647 +    if (mMgr->GetFocusedStore()) {
  1.1648 +      if (RunTest(&TestApp::TestClustering))
  1.1649 +        passed("TestClustering");
  1.1650 +    } else {
  1.1651 +      fail("no text store (clustering)");
  1.1652 +      mFailed = true;
  1.1653 +    }
  1.1654 +
  1.1655 +    printf("Testing TSF support in text input element...\n");
  1.1656 +    mCurrentNode = mInput;
  1.1657 +    mTestString = NS_LITERAL_STRING(
  1.1658 +      "This is a test of the Text Services Framework implementation.");
  1.1659 +    mInput->SetValue(mTestString);
  1.1660 +    mInput->Focus();
  1.1661 +    if (mMgr->GetFocusedStore()) {
  1.1662 +      if (RunTest(&TestApp::TestSelection))
  1.1663 +        passed("TestSelection (input)");
  1.1664 +      if (RunTest(&TestApp::TestText))
  1.1665 +        passed("TestText (input)");
  1.1666 +      if (RunTest(&TestApp::TestExtents))
  1.1667 +        passed("TestExtents (input)");
  1.1668 +      if (RunTest(&TestApp::TestComposition))
  1.1669 +        passed("TestComposition (input)");
  1.1670 +      if (RunTest(&TestApp::TestNotification, false))
  1.1671 +        passed("TestNotification (input)");
  1.1672 +    } else {
  1.1673 +      fail("no text store (input)");
  1.1674 +      mFailed = true;
  1.1675 +    }
  1.1676 +
  1.1677 +    printf("Testing TSF support in textarea element...\n");
  1.1678 +    mCurrentNode = mTextArea;
  1.1679 +    mTestString = NS_LITERAL_STRING(
  1.1680 +      "This is a test of the\r\nText Services Framework\r\nimplementation.");
  1.1681 +    mTextArea->SetValue(mTestString);
  1.1682 +    mTextArea->Focus();
  1.1683 +    if (mMgr->GetFocusedStore()) {
  1.1684 +      if (RunTest(&TestApp::TestSelection))
  1.1685 +        passed("TestSelection (textarea)");
  1.1686 +      if (RunTest(&TestApp::TestText))
  1.1687 +        passed("TestText (textarea)");
  1.1688 +      if (RunTest(&TestApp::TestExtents))
  1.1689 +        passed("TestExtents (textarea)");
  1.1690 +      if (RunTest(&TestApp::TestComposition))
  1.1691 +        passed("TestComposition (textarea)");
  1.1692 +      if (RunTest(&TestApp::TestNotification, false))
  1.1693 +        passed("TestNotification (textarea)");
  1.1694 +    } else {
  1.1695 +      fail("no text store (textarea)");
  1.1696 +      mFailed = true;
  1.1697 +    }
  1.1698 +  } else {
  1.1699 +    fail("initialization");
  1.1700 +    mFailed = true;
  1.1701 +  }
  1.1702 +  Term();
  1.1703 +  return NS_OK;
  1.1704 +}
  1.1705 +
  1.1706 +bool
  1.1707 +TestApp::TestFocus(void)
  1.1708 +{
  1.1709 +  uint32_t focus = mMgr->mFocusCount;
  1.1710 +  nsresult rv;
  1.1711 +
  1.1712 +  /* If these fail the cause is probably one or more of:
  1.1713 +   * - nsIMEStateManager::OnTextStateFocus not called by nsEventStateManager
  1.1714 +   * - nsIMEStateManager::OnTextStateBlur not called by nsEventStateManager
  1.1715 +   * - nsWindow::OnIMEFocusChange (nsIWidget) not called by nsIMEStateManager
  1.1716 +   * - nsTextStore::Create/Focus/Destroy not called by nsWindow
  1.1717 +   * - ITfThreadMgr::CreateDocumentMgr/SetFocus not called by nsTextStore
  1.1718 +   * - ITfDocumentMgr::CreateContext/Push not called by nsTextStore
  1.1719 +   */
  1.1720 +
  1.1721 +  rv = mInput->Focus();
  1.1722 +  if (!(NS_SUCCEEDED(rv) &&
  1.1723 +        mMgr->mFocusedDocument &&
  1.1724 +        mMgr->mFocusCount - focus == 1 &&
  1.1725 +        mMgr->GetFocusedStore())) {
  1.1726 +    fail("TestFocus: document focus was not set");
  1.1727 +    return false;
  1.1728 +  }
  1.1729 +
  1.1730 +  rv = mTextArea->Focus();
  1.1731 +  if (!(NS_SUCCEEDED(rv) &&
  1.1732 +        mMgr->mFocusedDocument &&
  1.1733 +        mMgr->mFocusCount - focus == 2 &&
  1.1734 +        mMgr->GetFocusedStore())) {
  1.1735 +    fail("TestFocus: document focus was not changed");
  1.1736 +    return false;
  1.1737 +  }
  1.1738 +
  1.1739 +  rv = mButton->Focus();
  1.1740 +  if (!(NS_SUCCEEDED(rv) &&
  1.1741 +        !mMgr->mFocusedDocument &&
  1.1742 +        mMgr->mFocusCount - focus == 2 &&
  1.1743 +        !mMgr->GetFocusedStore())) {
  1.1744 +    fail("TestFocus: document focus was changed");
  1.1745 +    return false;
  1.1746 +  }
  1.1747 +  return true;
  1.1748 +}
  1.1749 +
  1.1750 +bool
  1.1751 +TestApp::TestClustering(void)
  1.1752 +{
  1.1753 +  // Text for testing
  1.1754 +  const uint32_t STRING_LENGTH = 2;
  1.1755 +  char16_t string[3];
  1.1756 +  string[0] = 'e';
  1.1757 +  string[1] = 0x0301; // U+0301 'acute accent'
  1.1758 +  string[2] = nullptr;
  1.1759 +
  1.1760 +  if (!mMgr->GetFocusedStore()) {
  1.1761 +    fail("TestClustering: GetFocusedStore returns null #1");
  1.1762 +    return false;
  1.1763 +  }
  1.1764 +
  1.1765 +  // Replace entire string with our string
  1.1766 +  TS_TEXTCHANGE textChange;
  1.1767 +  HRESULT hr =
  1.1768 +    mMgr->GetFocusedStore()->SetText(0, 0, -1, string, STRING_LENGTH,
  1.1769 +                                     &textChange);
  1.1770 +  if (!(SUCCEEDED(hr) &&
  1.1771 +        0 == textChange.acpStart &&
  1.1772 +        STRING_LENGTH == textChange.acpNewEnd)) {
  1.1773 +    fail("TestClustering: SetText");
  1.1774 +    return false;
  1.1775 +  }
  1.1776 +
  1.1777 +  TsViewCookie view;
  1.1778 +  RECT rectLetter, rectAccent, rectWhole, rectCombined;
  1.1779 +  BOOL clipped, nonEmpty;
  1.1780 +
  1.1781 +  if (!mMgr->GetFocusedStore()) {
  1.1782 +    fail("TestClustering: GetFocusedStore returns null #2");
  1.1783 +    return false;
  1.1784 +  }
  1.1785 +
  1.1786 +  hr = mMgr->GetFocusedStore()->GetActiveView(&view);
  1.1787 +  if (!(SUCCEEDED(hr))) {
  1.1788 +    fail("TestClustering: GetActiveView");
  1.1789 +    return false;
  1.1790 +  }
  1.1791 +
  1.1792 +  if (!mMgr->GetFocusedStore()) {
  1.1793 +    fail("TestClustering: GetFocusedStore returns null #3");
  1.1794 +    return false;
  1.1795 +  }
  1.1796 +
  1.1797 +  // Get rect of first char (the letter)
  1.1798 +  hr = mMgr->GetFocusedStore()->GetTextExt(view, 0, STRING_LENGTH / 2,
  1.1799 +                                           &rectLetter, &clipped);
  1.1800 +  if (!(SUCCEEDED(hr))) {
  1.1801 +    fail("TestClustering: GetTextExt (letter)");
  1.1802 +    return false;
  1.1803 +  }
  1.1804 +
  1.1805 +  if (!mMgr->GetFocusedStore()) {
  1.1806 +    fail("TestClustering: GetFocusedStore returns null #4");
  1.1807 +    return false;
  1.1808 +  }
  1.1809 +
  1.1810 +  // Get rect of second char (the accent)
  1.1811 +  hr = mMgr->GetFocusedStore()->GetTextExt(view, STRING_LENGTH / 2,
  1.1812 +                                           STRING_LENGTH,
  1.1813 +                                           &rectAccent, &clipped);
  1.1814 +  if (!(SUCCEEDED(hr))) {
  1.1815 +    fail("TestClustering: GetTextExt (accent)");
  1.1816 +    return false;
  1.1817 +  }
  1.1818 +
  1.1819 +  if (!mMgr->GetFocusedStore()) {
  1.1820 +    fail("TestClustering: GetFocusedStore returns null #5");
  1.1821 +    return false;
  1.1822 +  }
  1.1823 +
  1.1824 +  // Get rect of combined char
  1.1825 +  hr = mMgr->GetFocusedStore()->GetTextExt(view, 0, STRING_LENGTH,
  1.1826 +                                           &rectWhole, &clipped);
  1.1827 +  if (!(SUCCEEDED(hr))) {
  1.1828 +    fail("TestClustering: GetTextExt (whole)");
  1.1829 +    return false;
  1.1830 +  }
  1.1831 +
  1.1832 +  nonEmpty = ::UnionRect(&rectCombined, &rectLetter, &rectAccent);
  1.1833 +  if (!(nonEmpty &&
  1.1834 +        ::EqualRect(&rectCombined, &rectWhole))) {
  1.1835 +    fail("TestClustering: unexpected combined rect");
  1.1836 +    return false;
  1.1837 +  }
  1.1838 +  return true;
  1.1839 +}
  1.1840 +
  1.1841 +bool
  1.1842 +TestApp::TestSelectionInternal(char* aTestName,
  1.1843 +                               LONG aStart,
  1.1844 +                               LONG aEnd,
  1.1845 +                               TsActiveSelEnd aSelEnd)
  1.1846 +{
  1.1847 +  bool succeeded = true, continueTest = true;
  1.1848 +  TS_SELECTION_ACP sel, testSel;
  1.1849 +  ULONG selFetched;
  1.1850 +
  1.1851 +  if (!mMgr->GetFocusedStore()) {
  1.1852 +    fail("TestSelectionInternal: GetFocusedStore returns null #1");
  1.1853 +    return false;
  1.1854 +  }
  1.1855 +
  1.1856 +  sel.acpStart = aStart;
  1.1857 +  sel.acpEnd = aEnd;
  1.1858 +  sel.style.ase = aSelEnd;
  1.1859 +  sel.style.fInterimChar = FALSE;
  1.1860 +  HRESULT hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
  1.1861 +  if (!(SUCCEEDED(hr))) {
  1.1862 +    fail("TestSelection: SetSelection (%s)", aTestName);
  1.1863 +    continueTest = succeeded = false;
  1.1864 +  }
  1.1865 +
  1.1866 +  if (continueTest) {
  1.1867 +    if (!mMgr->GetFocusedStore()) {
  1.1868 +      fail("TestSelectionInternal: GetFocusedStore returns null #2");
  1.1869 +      return false;
  1.1870 +    }
  1.1871 +
  1.1872 +    hr = mMgr->GetFocusedStore()->GetSelection(TS_DEFAULT_SELECTION, 1,
  1.1873 +                                               &testSel, &selFetched);
  1.1874 +    if (!(SUCCEEDED(hr) &&
  1.1875 +          selFetched == 1 &&
  1.1876 +          !memcmp(&sel, &testSel, sizeof(sel)))) {
  1.1877 +      fail("TestSelection: unexpected GetSelection result (%s)", aTestName);
  1.1878 +      succeeded = false;
  1.1879 +    }
  1.1880 +  }
  1.1881 +  return succeeded;
  1.1882 +}
  1.1883 +
  1.1884 +bool
  1.1885 +TestApp::TestSelection(void)
  1.1886 +{
  1.1887 +  bool succeeded = true;
  1.1888 +
  1.1889 +  /* If these fail the cause is probably one or more of:
  1.1890 +   * nsTextStore::GetSelection not sending NS_QUERY_SELECTED_TEXT
  1.1891 +   * NS_QUERY_SELECTED_TEXT not handled by ContentEventHandler
  1.1892 +   * Bug in NS_QUERY_SELECTED_TEXT handler
  1.1893 +   * nsTextStore::SetSelection not sending NS_SELECTION_SET
  1.1894 +   * NS_SELECTION_SET not handled by ContentEventHandler
  1.1895 +   * Bug in NS_SELECTION_SET handler
  1.1896 +   */
  1.1897 +
  1.1898 +  TS_SELECTION_ACP testSel;
  1.1899 +  ULONG selFetched;
  1.1900 +
  1.1901 +  if (!mMgr->GetFocusedStore()) {
  1.1902 +    fail("TestSelection: GetFocusedStore returns null");
  1.1903 +    return false;
  1.1904 +  }
  1.1905 +
  1.1906 +  HRESULT hr =
  1.1907 +    mMgr->GetFocusedStore()->GetSelection(0, 1, &testSel, &selFetched);
  1.1908 +  if (!(SUCCEEDED(hr) &&
  1.1909 +        selFetched == 1)) {
  1.1910 +    fail("TestSelection: GetSelection");
  1.1911 +    succeeded = false;
  1.1912 +  }
  1.1913 +
  1.1914 +  const LONG SELECTION1_START            = 0;
  1.1915 +  const LONG SELECTION1_END              = mTestString.Length();
  1.1916 +  const TsActiveSelEnd SELECTION1_SELEND = TS_AE_END;
  1.1917 +
  1.1918 +  if (!TestSelectionInternal("normal",
  1.1919 +                             SELECTION1_START,
  1.1920 +                             SELECTION1_END,
  1.1921 +                             SELECTION1_SELEND)) {
  1.1922 +    succeeded = false;
  1.1923 +  }
  1.1924 +
  1.1925 +  const LONG SELECTION2_START            = mTestString.Length() / 2;
  1.1926 +  const LONG SELECTION2_END              = SELECTION2_START;
  1.1927 +  const TsActiveSelEnd SELECTION2_SELEND = TS_AE_END;
  1.1928 +
  1.1929 +  if (!TestSelectionInternal("collapsed",
  1.1930 +                             SELECTION2_START,
  1.1931 +                             SELECTION2_END,
  1.1932 +                             SELECTION2_SELEND)) {
  1.1933 +    succeeded = false;
  1.1934 +  }
  1.1935 +
  1.1936 +  const LONG SELECTION3_START            = 12;
  1.1937 +  const LONG SELECTION3_END              = mTestString.Length() - 20;
  1.1938 +  const TsActiveSelEnd SELECTION3_SELEND = TS_AE_START;
  1.1939 +
  1.1940 +  if (!TestSelectionInternal("reversed",
  1.1941 +                             SELECTION3_START,
  1.1942 +                             SELECTION3_END,
  1.1943 +                             SELECTION3_SELEND)) {
  1.1944 +    succeeded = false;
  1.1945 +  }
  1.1946 +  return succeeded;
  1.1947 +}
  1.1948 +
  1.1949 +bool
  1.1950 +TestApp::TestText(void)
  1.1951 +{
  1.1952 +  const uint32_t BUFFER_SIZE  = (0x100);
  1.1953 +  const uint32_t RUNINFO_SIZE = (0x10);
  1.1954 +
  1.1955 +  bool succeeded = true, continueTest;
  1.1956 +  char16_t buffer[BUFFER_SIZE];
  1.1957 +  TS_RUNINFO runInfo[RUNINFO_SIZE];
  1.1958 +  ULONG bufferRet, runInfoRet;
  1.1959 +  LONG acpRet, acpCurrent;
  1.1960 +  TS_TEXTCHANGE textChange;
  1.1961 +  HRESULT hr;
  1.1962 +
  1.1963 +  /* If these fail the cause is probably one or more of:
  1.1964 +   * nsTextStore::GetText not sending NS_QUERY_TEXT_CONTENT
  1.1965 +   * NS_QUERY_TEXT_CONTENT not handled by ContentEventHandler
  1.1966 +   * Bug in NS_QUERY_TEXT_CONTENT handler
  1.1967 +   * nsTextStore::SetText not calling SetSelection or InsertTextAtSelection
  1.1968 +   * Bug in SetSelection or InsertTextAtSelection
  1.1969 +   *  NS_SELECTION_SET bug or NS_COMPOSITION_* / NS_TEXT_TEXT bug
  1.1970 +   */
  1.1971 +
  1.1972 +  if (!mMgr->GetFocusedStore()) {
  1.1973 +    fail("TestText: GetFocusedStore returns null #1");
  1.1974 +    return false;
  1.1975 +  }
  1.1976 +
  1.1977 +  // Get all text
  1.1978 +  hr = mMgr->GetFocusedStore()->GetText(0, -1, buffer, BUFFER_SIZE, &bufferRet,
  1.1979 +                                        runInfo, RUNINFO_SIZE, &runInfoRet,
  1.1980 +                                        &acpRet);
  1.1981 +  if (!(SUCCEEDED(hr) &&
  1.1982 +        bufferRet <= mTestString.Length() &&
  1.1983 +        !wcsncmp(mTestString.get(), buffer, bufferRet) &&
  1.1984 +        acpRet == LONG(bufferRet) &&
  1.1985 +        runInfoRet > 0)) {
  1.1986 +    fail("TestText: GetText 1");
  1.1987 +    succeeded = false;
  1.1988 +  }
  1.1989 +
  1.1990 +
  1.1991 +  if (!mMgr->GetFocusedStore()) {
  1.1992 +    fail("TestText: GetFocusedStore returns null #2");
  1.1993 +    return false;
  1.1994 +  }
  1.1995 +
  1.1996 +  // Get text from GETTEXT2_START to GETTEXT2_END
  1.1997 +  const uint32_t GETTEXT2_START       = (18);
  1.1998 +  const uint32_t GETTEXT2_END         = (mTestString.Length() - 16);
  1.1999 +  const uint32_t GETTEXT2_BUFFER_SIZE = (0x10);
  1.2000 +
  1.2001 +  hr = mMgr->GetFocusedStore()->GetText(GETTEXT2_START, GETTEXT2_END,
  1.2002 +                                        buffer, GETTEXT2_BUFFER_SIZE,
  1.2003 +                                        &bufferRet, runInfo, RUNINFO_SIZE,
  1.2004 +                                        &runInfoRet, &acpRet);
  1.2005 +  if (!(SUCCEEDED(hr) &&
  1.2006 +        bufferRet <= GETTEXT2_BUFFER_SIZE &&
  1.2007 +        !wcsncmp(mTestString.get() + GETTEXT2_START, buffer, bufferRet) &&
  1.2008 +        acpRet == LONG(bufferRet) + GETTEXT2_START &&
  1.2009 +        runInfoRet > 0)) {
  1.2010 +    fail("TestText: GetText 2");
  1.2011 +    succeeded = false;
  1.2012 +  }
  1.2013 +
  1.2014 +
  1.2015 +  if (!mMgr->GetFocusedStore()) {
  1.2016 +    fail("TestText: GetFocusedStore returns null #3");
  1.2017 +    return false;
  1.2018 +  }
  1.2019 +
  1.2020 +  // Replace text from SETTEXT1_START to SETTEXT1_END with insertString
  1.2021 +  const uint32_t SETTEXT1_START        = (8);
  1.2022 +  const uint32_t SETTEXT1_TAIL_LENGTH  = (40);
  1.2023 +  const uint32_t SETTEXT1_END          = (mTestString.Length() -
  1.2024 +                                          SETTEXT1_TAIL_LENGTH);
  1.2025 +  NS_NAMED_LITERAL_STRING(insertString, "(Inserted string)");
  1.2026 +
  1.2027 +  continueTest = true;
  1.2028 +  hr = mMgr->GetFocusedStore()->SetText(0, SETTEXT1_START, SETTEXT1_END,
  1.2029 +                                        insertString.get(),
  1.2030 +                                        insertString.Length(), &textChange);
  1.2031 +  if (!(SUCCEEDED(hr) &&
  1.2032 +        textChange.acpStart == SETTEXT1_START &&
  1.2033 +        textChange.acpOldEnd == LONG(SETTEXT1_END) &&
  1.2034 +        textChange.acpNewEnd == LONG(SETTEXT1_START +
  1.2035 +                                insertString.Length()))) {
  1.2036 +    fail("TestText: SetText 1");
  1.2037 +    continueTest = succeeded = false;
  1.2038 +  }
  1.2039 +
  1.2040 +  const uint32_t SETTEXT1_FINAL_LENGTH = (SETTEXT1_START +
  1.2041 +                                          SETTEXT1_TAIL_LENGTH +
  1.2042 +                                          insertString.Length());
  1.2043 +
  1.2044 +  if (continueTest) {
  1.2045 +    acpCurrent = 0;
  1.2046 +    while (acpCurrent < LONG(SETTEXT1_FINAL_LENGTH)) {
  1.2047 +      if (!mMgr->GetFocusedStore()) {
  1.2048 +        fail("TestText: GetFocusedStore returns null #4");
  1.2049 +        return false;
  1.2050 +      }
  1.2051 +
  1.2052 +      hr = mMgr->GetFocusedStore()->GetText(acpCurrent, -1, &buffer[acpCurrent],
  1.2053 +                                            BUFFER_SIZE, &bufferRet, runInfo,
  1.2054 +                                            RUNINFO_SIZE, &runInfoRet, &acpRet);
  1.2055 +      if (!(SUCCEEDED(hr) &&
  1.2056 +            acpRet > acpCurrent &&
  1.2057 +            bufferRet <= SETTEXT1_FINAL_LENGTH &&
  1.2058 +            runInfoRet > 0)) {
  1.2059 +        fail("TestText: GetText failed after SetTest 1");
  1.2060 +        continueTest = succeeded = false;
  1.2061 +        break;
  1.2062 +      }
  1.2063 +      acpCurrent = acpRet;
  1.2064 +    }
  1.2065 +  }
  1.2066 +
  1.2067 +  if (continueTest) {
  1.2068 +    if (!(acpCurrent == LONG(SETTEXT1_FINAL_LENGTH) &&
  1.2069 +          !wcsncmp(buffer, mTestString.get(), SETTEXT1_START) &&
  1.2070 +          !wcsncmp(&buffer[SETTEXT1_START], insertString.get(),
  1.2071 +                   insertString.Length()) &&
  1.2072 +          !wcsncmp(&buffer[SETTEXT1_START + insertString.Length()],
  1.2073 +                   mTestString.get() + SETTEXT1_END, SETTEXT1_TAIL_LENGTH))) {
  1.2074 +      fail("TestText: unexpected GetText result after SetText 1");
  1.2075 +      succeeded = false;
  1.2076 +    }
  1.2077 +  }
  1.2078 +
  1.2079 +
  1.2080 +  if (!mMgr->GetFocusedStore()) {
  1.2081 +    fail("TestText: GetFocusedStore returns null #5");
  1.2082 +    return false;
  1.2083 +  }
  1.2084 +
  1.2085 +  // Restore entire text to original text (mTestString)
  1.2086 +  continueTest = true;
  1.2087 +  hr = mMgr->GetFocusedStore()->SetText(0, 0, -1, mTestString.get(),
  1.2088 +                                        mTestString.Length(), &textChange);
  1.2089 +  if (!(SUCCEEDED(hr) &&
  1.2090 +        textChange.acpStart == 0 &&
  1.2091 +        textChange.acpOldEnd == LONG(SETTEXT1_FINAL_LENGTH) &&
  1.2092 +        textChange.acpNewEnd == LONG(mTestString.Length()))) {
  1.2093 +    fail("TestText: SetText 2");
  1.2094 +    continueTest = succeeded = false;
  1.2095 +  }
  1.2096 +
  1.2097 +  if (continueTest) {
  1.2098 +    acpCurrent = 0;
  1.2099 +    while (acpCurrent < LONG(mTestString.Length())) {
  1.2100 +      if (!mMgr->GetFocusedStore()) {
  1.2101 +        fail("TestText: GetFocusedStore returns null #6");
  1.2102 +        return false;
  1.2103 +      }
  1.2104 +
  1.2105 +      hr = mMgr->GetFocusedStore()->GetText(acpCurrent, -1, &buffer[acpCurrent],
  1.2106 +                                            BUFFER_SIZE, &bufferRet, runInfo,
  1.2107 +                                            RUNINFO_SIZE, &runInfoRet, &acpRet);
  1.2108 +      if (!(SUCCEEDED(hr) &&
  1.2109 +            acpRet > acpCurrent &&
  1.2110 +            bufferRet <= mTestString.Length() &&
  1.2111 +            runInfoRet > 0)) {
  1.2112 +        fail("TestText: GetText failed after SetText 2");
  1.2113 +        continueTest = succeeded = false;
  1.2114 +        break;
  1.2115 +      }
  1.2116 +      acpCurrent = acpRet;
  1.2117 +    }
  1.2118 +  }
  1.2119 +
  1.2120 +  if (continueTest) {
  1.2121 +    if (!(acpCurrent == LONG(mTestString.Length()) &&
  1.2122 +          !wcsncmp(buffer, mTestString.get(), mTestString.Length()))) {
  1.2123 +      fail("TestText: unexpected GetText result after SetText 2");
  1.2124 +      succeeded = false;
  1.2125 +    }
  1.2126 +  }
  1.2127 +  return succeeded;
  1.2128 +}
  1.2129 +
  1.2130 +bool
  1.2131 +TestApp::TestExtents(void)
  1.2132 +{
  1.2133 +  if (!mMgr->GetFocusedStore()) {
  1.2134 +    fail("TestExtents: GetFocusedStore returns null #1");
  1.2135 +    return false;
  1.2136 +  }
  1.2137 +
  1.2138 +  TS_SELECTION_ACP sel;
  1.2139 +  sel.acpStart = 0;
  1.2140 +  sel.acpEnd = 0;
  1.2141 +  sel.style.ase = TS_AE_END;
  1.2142 +  sel.style.fInterimChar = FALSE;
  1.2143 +  mMgr->GetFocusedStore()->SetSelection(1, &sel);
  1.2144 +
  1.2145 +  nsCOMPtr<nsISelectionController> selCon;
  1.2146 +  if (!(NS_SUCCEEDED(GetSelCon(getter_AddRefs(selCon))) && selCon)) {
  1.2147 +    fail("TestExtents: get nsISelectionController");
  1.2148 +    return false;
  1.2149 +  }
  1.2150 +  selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
  1.2151 +              nsISelectionController::SELECTION_FOCUS_REGION, true);
  1.2152 +
  1.2153 +  nsCOMPtr<nsIDOMWindow> window(do_GetInterface(mWindow));
  1.2154 +  if (!window) {
  1.2155 +    fail("TestExtents: get nsIDOMWindow");
  1.2156 +    return false;
  1.2157 +  }
  1.2158 +  RECT windowRect, screenRect, textRect1, textRect2;
  1.2159 +  BOOL clipped;
  1.2160 +  int32_t val;
  1.2161 +  TsViewCookie view;
  1.2162 +  HRESULT hr;
  1.2163 +
  1.2164 +  nsresult nsr = window->GetScreenX(&val);
  1.2165 +  windowRect.left = val;
  1.2166 +  nsr |= window->GetScreenY(&val);
  1.2167 +  windowRect.top = val;
  1.2168 +  nsr |= window->GetOuterWidth(&val);
  1.2169 +  windowRect.right = windowRect.left + val;
  1.2170 +  nsr |= window->GetOuterHeight(&val);
  1.2171 +  windowRect.bottom = windowRect.top + val;
  1.2172 +  if (!(NS_SUCCEEDED(nsr))) {
  1.2173 +    fail("TestExtents: get window rect failed");
  1.2174 +    return false;
  1.2175 +  }
  1.2176 +
  1.2177 +  if (!mMgr->GetFocusedStore()) {
  1.2178 +    fail("TestExtents: GetFocusedStore returns null #2");
  1.2179 +    return false;
  1.2180 +  }
  1.2181 +
  1.2182 +  hr = mMgr->GetFocusedStore()->GetActiveView(&view);
  1.2183 +  if (!(SUCCEEDED(hr))) {
  1.2184 +    fail("TestExtents: GetActiveView");
  1.2185 +    return false;
  1.2186 +  }
  1.2187 +
  1.2188 +  if (!mMgr->GetFocusedStore()) {
  1.2189 +    fail("TestExtents: GetFocusedStore returns null #3");
  1.2190 +    return false;
  1.2191 +  }
  1.2192 +
  1.2193 +  bool succeeded = true;
  1.2194 +  HWND hwnd;
  1.2195 +  hr = mMgr->GetFocusedStore()->GetWnd(view, &hwnd);
  1.2196 +  if (!(SUCCEEDED(hr) &&
  1.2197 +        ::IsWindow(hwnd))) {
  1.2198 +    fail("TestExtents: GetWnd");
  1.2199 +    succeeded = false;
  1.2200 +  }
  1.2201 +
  1.2202 +  ::SetRectEmpty(&screenRect);
  1.2203 +
  1.2204 +  if (!mMgr->GetFocusedStore()) {
  1.2205 +    fail("TestExtents: GetFocusedStore returns null #4");
  1.2206 +    return false;
  1.2207 +  }
  1.2208 +
  1.2209 +  hr = mMgr->GetFocusedStore()->GetScreenExt(view, &screenRect);
  1.2210 +  if (!(SUCCEEDED(hr) &&
  1.2211 +        screenRect.left > windowRect.left &&
  1.2212 +        screenRect.top > windowRect.top &&
  1.2213 +        screenRect.right > screenRect.left &&
  1.2214 +        screenRect.bottom > screenRect.top &&
  1.2215 +        screenRect.right < windowRect.right &&
  1.2216 +        screenRect.bottom < windowRect.bottom)) {
  1.2217 +    fail("TestExtents: GetScreenExt");
  1.2218 +    succeeded = false;
  1.2219 +  }
  1.2220 +
  1.2221 +  const LONG GETTEXTEXT1_START = 0;
  1.2222 +  const LONG GETTEXTEXT1_END   = 0;
  1.2223 +
  1.2224 +  ::SetRectEmpty(&textRect1);
  1.2225 +
  1.2226 +  if (!mMgr->GetFocusedStore()) {
  1.2227 +    fail("TestExtents: GetFocusedStore returns null #5");
  1.2228 +    return false;
  1.2229 +  }
  1.2230 +
  1.2231 +  hr = mMgr->GetFocusedStore()->GetTextExt(view, GETTEXTEXT1_START,
  1.2232 +                                           GETTEXTEXT1_END, &textRect1,
  1.2233 +                                           &clipped);
  1.2234 +  if (!(SUCCEEDED(hr) &&
  1.2235 +        textRect1.left >= screenRect.left &&
  1.2236 +        textRect1.top >= screenRect.top &&
  1.2237 +        textRect1.right < screenRect.right &&
  1.2238 +        textRect1.bottom <= screenRect.bottom &&
  1.2239 +        textRect1.right >= textRect1.left &&
  1.2240 +        textRect1.bottom > textRect1.top)) {
  1.2241 +    fail("TestExtents: GetTextExt (offset %ld to %ld)",
  1.2242 +         GETTEXTEXT1_START, GETTEXTEXT1_END);
  1.2243 +    succeeded = false;
  1.2244 +  }
  1.2245 +
  1.2246 +  const LONG GETTEXTEXT2_START = 10;
  1.2247 +  const LONG GETTEXTEXT2_END   = 25;
  1.2248 +
  1.2249 +  ::SetRectEmpty(&textRect2);
  1.2250 +
  1.2251 +  if (!mMgr->GetFocusedStore()) {
  1.2252 +    fail("TestExtents: GetFocusedStore returns null #6");
  1.2253 +    return false;
  1.2254 +  }
  1.2255 +
  1.2256 +  hr = mMgr->GetFocusedStore()->GetTextExt(view, GETTEXTEXT2_START,
  1.2257 +                                           GETTEXTEXT2_END, &textRect2,
  1.2258 +                                           &clipped);
  1.2259 +  if (!(SUCCEEDED(hr) &&
  1.2260 +        textRect2.left >= screenRect.left &&
  1.2261 +        textRect2.top >= screenRect.top &&
  1.2262 +        textRect2.right <= screenRect.right &&
  1.2263 +        textRect2.bottom <= screenRect.bottom &&
  1.2264 +        textRect2.right > textRect2.left &&
  1.2265 +        textRect2.bottom > textRect2.top)) {
  1.2266 +    fail("TestExtents: GetTextExt (offset %ld to %ld)",
  1.2267 +         GETTEXTEXT2_START, GETTEXTEXT2_END);
  1.2268 +    succeeded = false;
  1.2269 +  }
  1.2270 +
  1.2271 +  // Offsets must be between GETTEXTEXT2_START and GETTEXTEXT2_END
  1.2272 +  const LONG GETTEXTEXT3_START = 23;
  1.2273 +  const LONG GETTEXTEXT3_END   = 23;
  1.2274 +
  1.2275 +  ::SetRectEmpty(&textRect1);
  1.2276 +
  1.2277 +  if (!mMgr->GetFocusedStore()) {
  1.2278 +    fail("TestExtents: GetFocusedStore returns null #7");
  1.2279 +    return false;
  1.2280 +  }
  1.2281 +
  1.2282 +  hr = mMgr->GetFocusedStore()->GetTextExt(view, GETTEXTEXT3_START,
  1.2283 +                                           GETTEXTEXT3_END, &textRect1,
  1.2284 +                                           &clipped);
  1.2285 +  // Rectangle must be entirely inside the previous rectangle,
  1.2286 +  // since GETTEXTEXT3_START and GETTEXTEXT3_END are between
  1.2287 +  // GETTEXTEXT2_START and GETTEXTEXT2_START
  1.2288 +  if (!(SUCCEEDED(hr) && ::IsRectEmpty(&textRect1) ||
  1.2289 +        (textRect1.left >= textRect2.left &&
  1.2290 +        textRect1.top >= textRect2.top &&
  1.2291 +        textRect1.right <= textRect2.right &&
  1.2292 +        textRect1.bottom <= textRect2.bottom &&
  1.2293 +        textRect1.right >= textRect1.left &&
  1.2294 +        textRect1.bottom > textRect1.top))) {
  1.2295 +    fail("TestExtents: GetTextExt (offset %ld to %ld)",
  1.2296 +         GETTEXTEXT3_START, GETTEXTEXT3_END);
  1.2297 +    succeeded = false;
  1.2298 +  }
  1.2299 +  return succeeded;
  1.2300 +}
  1.2301 +
  1.2302 +bool
  1.2303 +TestApp::TestCompositionSelectionAndText(char* aTestName,
  1.2304 +                                         LONG aExpectedSelStart,
  1.2305 +                                         LONG aExpectedSelEnd,
  1.2306 +                                         nsString& aReferenceString)
  1.2307 +{
  1.2308 +  if (!mMgr->GetFocusedStore()) {
  1.2309 +    fail("TestCompositionSelectionAndText: GetFocusedStore returns null #1");
  1.2310 +    return false;
  1.2311 +  }
  1.2312 +
  1.2313 +  TS_SELECTION_ACP currentSel;
  1.2314 +  ULONG selFetched = 0;
  1.2315 +  HRESULT hr = mMgr->GetFocusedStore()->GetSelection(TF_DEFAULT_SELECTION, 1,
  1.2316 +                                                     &currentSel, &selFetched);
  1.2317 +  if (!(SUCCEEDED(hr) &&
  1.2318 +        1 == selFetched &&
  1.2319 +        currentSel.acpStart == aExpectedSelStart &&
  1.2320 +        currentSel.acpEnd == aExpectedSelEnd)) {
  1.2321 +    fail("TestComposition: GetSelection (%s)", aTestName);
  1.2322 +    return false;
  1.2323 +  }
  1.2324 +
  1.2325 +  const uint32_t bufferSize = 0x100, runInfoSize = 0x10;
  1.2326 +  char16_t buffer[bufferSize];
  1.2327 +  TS_RUNINFO runInfo[runInfoSize];
  1.2328 +  ULONG bufferRet, runInfoRet;
  1.2329 +  LONG acpRet, acpCurrent = 0;
  1.2330 +  while (acpCurrent < LONG(aReferenceString.Length())) {
  1.2331 +    if (!mMgr->GetFocusedStore()) {
  1.2332 +      fail("TestCompositionSelectionAndText: GetFocusedStore returns null #2");
  1.2333 +      return false;
  1.2334 +    }
  1.2335 +
  1.2336 +    hr = mMgr->GetFocusedStore()->GetText(acpCurrent, aReferenceString.Length(),
  1.2337 +                                          &buffer[acpCurrent], bufferSize,
  1.2338 +                                          &bufferRet, runInfo, runInfoSize,
  1.2339 +                                          &runInfoRet, &acpRet);
  1.2340 +    if (!(SUCCEEDED(hr) &&
  1.2341 +          acpRet > acpCurrent &&
  1.2342 +          bufferRet <= aReferenceString.Length() &&
  1.2343 +          runInfoRet > 0)) {
  1.2344 +      fail("TestComposition: GetText (%s)", aTestName);
  1.2345 +      return false;
  1.2346 +    }
  1.2347 +    acpCurrent = acpRet;
  1.2348 +  }
  1.2349 +  if (!(acpCurrent == aReferenceString.Length() &&
  1.2350 +        !wcsncmp(buffer, aReferenceString.get(), aReferenceString.Length()))) {
  1.2351 +    fail("TestComposition: unexpected GetText result (%s)", aTestName);
  1.2352 +    return false;
  1.2353 +  }
  1.2354 +  return true;
  1.2355 +}
  1.2356 +
  1.2357 +bool
  1.2358 +TestApp::TestComposition(void)
  1.2359 +{
  1.2360 +  if (!mMgr->GetFocusedStore()) {
  1.2361 +    fail("TestComposition: GetFocusedStore returns null #1");
  1.2362 +    return false;
  1.2363 +  }
  1.2364 +
  1.2365 +  nsRefPtr<ITfContextOwnerCompositionSink> sink;
  1.2366 +  HRESULT hr =
  1.2367 +    mMgr->GetFocusedStore()->QueryInterface(IID_ITfContextOwnerCompositionSink,
  1.2368 +                                            getter_AddRefs(sink));
  1.2369 +  if (!(SUCCEEDED(hr))) {
  1.2370 +    fail("TestComposition: QueryInterface");
  1.2371 +    return false;
  1.2372 +  }
  1.2373 +
  1.2374 +  const LONG PRECOMPOSITION_SEL_START            = 2;
  1.2375 +  const LONG PRECOMPOSITION_SEL_END              = PRECOMPOSITION_SEL_START;
  1.2376 +  const TsActiveSelEnd PRECOMPOSITION_SEL_SELEND = TS_AE_END;
  1.2377 +
  1.2378 +  TS_SELECTION_ACP sel;
  1.2379 +  sel.acpStart = PRECOMPOSITION_SEL_START;
  1.2380 +  sel.acpEnd = PRECOMPOSITION_SEL_END;
  1.2381 +  sel.style.ase = PRECOMPOSITION_SEL_SELEND;
  1.2382 +  sel.style.fInterimChar = FALSE;
  1.2383 +  hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
  1.2384 +  if (!(SUCCEEDED(hr))) {
  1.2385 +    fail("TestComposition: SetSelection (pre-composition)");
  1.2386 +    return false;
  1.2387 +  }
  1.2388 +
  1.2389 +  if (!mMgr->GetFocusedStore()) {
  1.2390 +    fail("TestComposition: GetFocusedStore returns null #2");
  1.2391 +    return false;
  1.2392 +  }
  1.2393 +
  1.2394 +  TS_TEXTCHANGE textChange;
  1.2395 +  NS_NAMED_LITERAL_STRING(insertString1, "Compo1");
  1.2396 +  hr = mMgr->GetFocusedStore()->InsertTextAtSelection(TF_IAS_NOQUERY,
  1.2397 +                                                      insertString1.get(),
  1.2398 +                                                      insertString1.Length(),
  1.2399 +                                                      nullptr, nullptr,
  1.2400 +                                                      &textChange);
  1.2401 +  if (!(SUCCEEDED(hr) &&
  1.2402 +        sel.acpEnd == textChange.acpStart &&
  1.2403 +        sel.acpEnd == textChange.acpOldEnd &&
  1.2404 +        sel.acpEnd + insertString1.Length() == textChange.acpNewEnd)) {
  1.2405 +    fail("TestComposition: InsertTextAtSelection");
  1.2406 +    return false;
  1.2407 +  }
  1.2408 +  sel.acpEnd = textChange.acpNewEnd;
  1.2409 +
  1.2410 +  if (!mMgr->GetFocusedAttrProp()) {
  1.2411 +    fail("TestComposition: GetFocusedAttrProp returns null #1");
  1.2412 +    return false;
  1.2413 +  }
  1.2414 +  mMgr->GetFocusedAttrProp()->mRanges.Clear();
  1.2415 +  nsRefPtr<TSFRangeImpl> range =
  1.2416 +    new TSFRangeImpl(textChange.acpStart,
  1.2417 +                     textChange.acpNewEnd - textChange.acpOldEnd);
  1.2418 +  if (!mMgr->GetFocusedAttrProp()) {
  1.2419 +    fail("TestComposition: GetFocusedAttrProp returns null #2");
  1.2420 +    return false;
  1.2421 +  }
  1.2422 +  mMgr->GetFocusedAttrProp()->mRanges.AppendElement(range);
  1.2423 +
  1.2424 +  BOOL okay = FALSE;
  1.2425 +  hr = sink->OnStartComposition(mMgr->GetFocusedContext(), &okay);
  1.2426 +  if (!(SUCCEEDED(hr) &&
  1.2427 +        okay)) {
  1.2428 +    fail("TestComposition: OnStartComposition");
  1.2429 +    return false;
  1.2430 +  }
  1.2431 +
  1.2432 +
  1.2433 +  if (!mMgr->GetFocusedStore()) {
  1.2434 +    fail("TestComposition: GetFocusedStore returns null #3");
  1.2435 +    return false;
  1.2436 +  }
  1.2437 +
  1.2438 +  NS_NAMED_LITERAL_STRING(insertString2, "Composition2");
  1.2439 +  hr = mMgr->GetFocusedStore()->SetText(0, range->mStart + range->mLength,
  1.2440 +                                        range->mStart + range->mLength,
  1.2441 +                                        insertString2.get(),
  1.2442 +                                        insertString2.Length(),
  1.2443 +                                        &textChange);
  1.2444 +  if (!(SUCCEEDED(hr) &&
  1.2445 +        sel.acpEnd == textChange.acpStart &&
  1.2446 +        sel.acpEnd == textChange.acpOldEnd &&
  1.2447 +        sel.acpEnd + insertString2.Length() == textChange.acpNewEnd)) {
  1.2448 +    fail("TestComposition: SetText 1");
  1.2449 +    return false;
  1.2450 +  }
  1.2451 +  sel.acpEnd = textChange.acpNewEnd;
  1.2452 +  range->mLength += textChange.acpNewEnd - textChange.acpOldEnd;
  1.2453 +
  1.2454 +
  1.2455 +  if (!mMgr->GetFocusedStore()) {
  1.2456 +    fail("TestComposition: GetFocusedStore returns null #4");
  1.2457 +    return false;
  1.2458 +  }
  1.2459 +
  1.2460 +  const LONG COMPOSITION3_TEXT_START_OFFSET = -8; // offset 8 from the end
  1.2461 +  const LONG COMPOSITION3_TEXT_END_OFFSET   = 4;
  1.2462 +
  1.2463 +  const LONG COMPOSITION3_TEXT_START = range->mStart + range->mLength +
  1.2464 +                                       COMPOSITION3_TEXT_START_OFFSET;
  1.2465 +  const LONG COMPOSITION3_TEXT_END   = COMPOSITION3_TEXT_START +
  1.2466 +                                       COMPOSITION3_TEXT_END_OFFSET;
  1.2467 +
  1.2468 +  NS_NAMED_LITERAL_STRING(insertString3, "Compo3");
  1.2469 +  hr = mMgr->GetFocusedStore()->SetText(0, COMPOSITION3_TEXT_START,
  1.2470 +                                        COMPOSITION3_TEXT_END,
  1.2471 +                                        insertString3.get(),
  1.2472 +                                        insertString3.Length(),
  1.2473 +                                        &textChange);
  1.2474 +  if (!(SUCCEEDED(hr) &&
  1.2475 +        sel.acpEnd + COMPOSITION3_TEXT_START_OFFSET == textChange.acpStart &&
  1.2476 +        sel.acpEnd + COMPOSITION3_TEXT_START_OFFSET +
  1.2477 +            COMPOSITION3_TEXT_END_OFFSET == textChange.acpOldEnd &&
  1.2478 +        sel.acpEnd + insertString3.Length() + COMPOSITION3_TEXT_START_OFFSET ==
  1.2479 +            textChange.acpNewEnd)) {
  1.2480 +    fail("TestComposition: SetText 2");
  1.2481 +    return false;
  1.2482 +  }
  1.2483 +  sel.acpEnd = textChange.acpNewEnd;
  1.2484 +  range->mLength += textChange.acpNewEnd - textChange.acpOldEnd;
  1.2485 +
  1.2486 +
  1.2487 +  nsString referenceString;
  1.2488 +  referenceString.Append(mTestString.get(), sel.acpStart);
  1.2489 +  referenceString.Append(insertString1);
  1.2490 +  referenceString.Append(insertString2.get(),
  1.2491 +      insertString2.Length() + COMPOSITION3_TEXT_START_OFFSET);
  1.2492 +  referenceString.Append(insertString3);
  1.2493 +  referenceString.Append(insertString2.get() + insertString2.Length() -
  1.2494 +      COMPOSITION3_TEXT_END_OFFSET, COMPOSITION3_TEXT_END_OFFSET);
  1.2495 +  referenceString.Append(mTestString.get() + sel.acpStart,
  1.2496 +      COMPOSITION3_TEXT_END_OFFSET);
  1.2497 +
  1.2498 +  if (!TestCompositionSelectionAndText("composition",
  1.2499 +           sel.acpEnd, sel.acpEnd,
  1.2500 +           referenceString))
  1.2501 +    return false;
  1.2502 +
  1.2503 +
  1.2504 +  if (!mMgr->GetFocusedStore()) {
  1.2505 +    fail("TestComposition: GetFocusedStore returns null #5");
  1.2506 +    return false;
  1.2507 +  }
  1.2508 +
  1.2509 +  const LONG POSTCOMPOSITION_SEL_START = sel.acpEnd - 8;
  1.2510 +  const LONG POSTCOMPOSITION_SEL_END   = POSTCOMPOSITION_SEL_START + 2;
  1.2511 +
  1.2512 +  sel.acpStart = POSTCOMPOSITION_SEL_START;
  1.2513 +  sel.acpEnd = POSTCOMPOSITION_SEL_END;
  1.2514 +  hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
  1.2515 +  if (!(SUCCEEDED(hr))) {
  1.2516 +    fail("TestComposition: SetSelection (composition)");
  1.2517 +    return false;
  1.2518 +  }
  1.2519 +
  1.2520 +  if (!mMgr->GetFocusedAttrProp()) {
  1.2521 +    fail("TestComposition: GetFocusedAttrProp returns null #3");
  1.2522 +    return false;
  1.2523 +  }
  1.2524 +  mMgr->GetFocusedAttrProp()->mRanges.Clear();
  1.2525 +
  1.2526 +  hr = sink->OnEndComposition(mMgr->GetFocusedContext());
  1.2527 +  if (!(SUCCEEDED(hr))) {
  1.2528 +    fail("TestComposition: OnEndComposition");
  1.2529 +    return false;
  1.2530 +  }
  1.2531 +
  1.2532 +  if (!TestCompositionSelectionAndText("post-composition",
  1.2533 +           sel.acpStart, sel.acpEnd,
  1.2534 +           referenceString))
  1.2535 +    return false;
  1.2536 +
  1.2537 +  const LONG EMPTYCOMPOSITION_START  = range->mStart + 2;
  1.2538 +  const LONG EMPTYCOMPOSITION_LENGTH = range->mLength - 4;
  1.2539 +
  1.2540 +  range->mStart = EMPTYCOMPOSITION_START;
  1.2541 +  range->mLength = EMPTYCOMPOSITION_LENGTH;
  1.2542 +  if (!mMgr->GetFocusedAttrProp()) {
  1.2543 +    fail("TestComposition: GetFocusedAttrProp returns null #4");
  1.2544 +    return false;
  1.2545 +  }
  1.2546 +  mMgr->GetFocusedAttrProp()->mRanges.AppendElement(range);
  1.2547 +
  1.2548 +  okay = FALSE;
  1.2549 +  hr = sink->OnStartComposition(mMgr->GetFocusedContext(), &okay);
  1.2550 +  if (!(SUCCEEDED(hr) &&
  1.2551 +        okay)) {
  1.2552 +    fail("TestComposition: OnStartComposition (empty composition)");
  1.2553 +    return false;
  1.2554 +  }
  1.2555 +
  1.2556 +  if (!mMgr->GetFocusedAttrProp()) {
  1.2557 +    fail("TestComposition: GetFocusedAttrProp returns null #5");
  1.2558 +    return false;
  1.2559 +  }
  1.2560 +  mMgr->GetFocusedAttrProp()->mRanges.Clear();
  1.2561 +
  1.2562 +  hr = sink->OnEndComposition(mMgr->GetFocusedContext());
  1.2563 +  if (!(SUCCEEDED(hr))) {
  1.2564 +    fail("TestComposition: OnEndComposition (empty composition)");
  1.2565 +    return false;
  1.2566 +  }
  1.2567 +
  1.2568 +  if (!TestCompositionSelectionAndText("empty composition",
  1.2569 +           range->mStart, range->mStart + range->mLength,
  1.2570 +           referenceString))
  1.2571 +    return false;
  1.2572 +
  1.2573 +  return true;
  1.2574 +}
  1.2575 +
  1.2576 +bool
  1.2577 +TestApp::TestNotificationTextChange(nsIWidget* aWidget,
  1.2578 +                                    uint32_t aCode,
  1.2579 +                                    const nsAString& aCharacter,
  1.2580 +                                    LONG aStart,
  1.2581 +                                    LONG aOldEnd,
  1.2582 +                                    LONG aNewEnd)
  1.2583 +{
  1.2584 +  MSG msg;
  1.2585 +  if (::PeekMessageW(&msg, nullptr, WM_USER_TSF_TEXTCHANGE,
  1.2586 +                     WM_USER_TSF_TEXTCHANGE, PM_REMOVE))
  1.2587 +    ::DispatchMessageW(&msg);
  1.2588 +  if (!mMgr->GetFocusedContext()) {
  1.2589 +    fail("TestNotificationTextChange: GetFocusedContext returns null");
  1.2590 +    return false;
  1.2591 +  }
  1.2592 +  mMgr->GetFocusedContext()->mTextChanged = false;
  1.2593 +  nsresult nsr = aWidget->SynthesizeNativeKeyEvent(0, aCode, 0,
  1.2594 +                              aCharacter, aCharacter);
  1.2595 +  if (::PeekMessageW(&msg, nullptr, WM_USER_TSF_TEXTCHANGE,
  1.2596 +                     WM_USER_TSF_TEXTCHANGE, PM_REMOVE))
  1.2597 +    ::DispatchMessageW(&msg);
  1.2598 +  return NS_SUCCEEDED(nsr) &&
  1.2599 +         mMgr->GetFocusedContext()->mTextChanged &&
  1.2600 +         aStart == mMgr->GetFocusedContext()->mTextChangeData.acpStart &&
  1.2601 +         aOldEnd == mMgr->GetFocusedContext()->mTextChangeData.acpOldEnd &&
  1.2602 +         aNewEnd == mMgr->GetFocusedContext()->mTextChangeData.acpNewEnd;
  1.2603 +}
  1.2604 +
  1.2605 +bool
  1.2606 +TestApp::TestNotification(void)
  1.2607 +{
  1.2608 +  nsresult nsr;
  1.2609 +  // get selection to test notification support
  1.2610 +  nsCOMPtr<nsISelectionController> selCon;
  1.2611 +  if (!(NS_SUCCEEDED(GetSelCon(getter_AddRefs(selCon))) && selCon)) {
  1.2612 +    fail("TestNotification: get nsISelectionController");
  1.2613 +    return false;
  1.2614 +  }
  1.2615 +
  1.2616 +  nsr = selCon->CompleteMove(false, false);
  1.2617 +  if (!(NS_SUCCEEDED(nsr))) {
  1.2618 +    fail("TestNotification: CompleteMove");
  1.2619 +    return false;
  1.2620 +  }
  1.2621 +
  1.2622 +  if (!mMgr->GetFocusedContext()) {
  1.2623 +    fail("TestNotification: GetFocusedContext returns null #1");
  1.2624 +    return false;
  1.2625 +  }
  1.2626 +
  1.2627 +  mMgr->GetFocusedContext()->mSelChanged = false;
  1.2628 +  nsr = selCon->CharacterMove(true, false);
  1.2629 +  if (!(NS_SUCCEEDED(nsr) &&
  1.2630 +        mMgr->GetFocusedContext()->mSelChanged)) {
  1.2631 +    fail("TestNotification: CharacterMove");
  1.2632 +    return false;
  1.2633 +  }
  1.2634 +
  1.2635 +  if (!mMgr->GetFocusedContext()) {
  1.2636 +    fail("TestNotification: GetFocusedContext returns null #2");
  1.2637 +    return false;
  1.2638 +  }
  1.2639 +
  1.2640 +  mMgr->GetFocusedContext()->mSelChanged = false;
  1.2641 +  nsr = selCon->CharacterMove(true, true);
  1.2642 +  if (!(NS_SUCCEEDED(nsr) &&
  1.2643 +        mMgr->GetFocusedContext()->mSelChanged)) {
  1.2644 +    fail("TestNotification: CharacterMove (extend)");
  1.2645 +    return false;
  1.2646 +  }
  1.2647 +
  1.2648 +  nsCOMPtr<nsIWidget> widget;
  1.2649 +  if (!GetWidget(getter_AddRefs(widget))) {
  1.2650 +    fail("TestNotification: get nsIWidget");
  1.2651 +    return false;
  1.2652 +  }
  1.2653 +
  1.2654 +  NS_NAMED_LITERAL_STRING(character, "");
  1.2655 +  NS_NAMED_LITERAL_STRING(characterA, "A");
  1.2656 +
  1.2657 +  // The selection test code above placed the selection at offset 1 to 2
  1.2658 +  const LONG TEXTCHANGE1_START  = 1;
  1.2659 +  const LONG TEXTCHANGE1_OLDEND = 2;
  1.2660 +  const LONG TEXTCHANGE1_NEWEND = 2;
  1.2661 +
  1.2662 +  // replace single selected character with 'A'
  1.2663 +  if (!TestNotificationTextChange(widget, 'A', characterA,
  1.2664 +        TEXTCHANGE1_START, TEXTCHANGE1_OLDEND, TEXTCHANGE1_NEWEND)) {
  1.2665 +    fail("TestNotification: text change 1");
  1.2666 +    return false;
  1.2667 +  }
  1.2668 +
  1.2669 +  const LONG TEXTCHANGE2_START  = TEXTCHANGE1_NEWEND;
  1.2670 +  const LONG TEXTCHANGE2_OLDEND = TEXTCHANGE1_NEWEND;
  1.2671 +  const LONG TEXTCHANGE2_NEWEND = TEXTCHANGE1_NEWEND + 1;
  1.2672 +
  1.2673 +  // insert 'A'
  1.2674 +  if (!TestNotificationTextChange(widget, 'A', characterA,
  1.2675 +        TEXTCHANGE2_START, TEXTCHANGE2_OLDEND, TEXTCHANGE2_NEWEND)) {
  1.2676 +    fail("TestNotification: text change 2");
  1.2677 +    return false;
  1.2678 +  }
  1.2679 +
  1.2680 +  const LONG TEXTCHANGE3_START  = TEXTCHANGE2_NEWEND - 1;
  1.2681 +  const LONG TEXTCHANGE3_OLDEND = TEXTCHANGE2_NEWEND;
  1.2682 +  const LONG TEXTCHANGE3_NEWEND = TEXTCHANGE2_NEWEND - 1;
  1.2683 +
  1.2684 +  // backspace
  1.2685 +  if (!TestNotificationTextChange(widget, '\b', character,
  1.2686 +        TEXTCHANGE3_START, TEXTCHANGE3_OLDEND, TEXTCHANGE3_NEWEND)) {
  1.2687 +    fail("TestNotification: text change 3");
  1.2688 +    return false;
  1.2689 +  }
  1.2690 +  return true;
  1.2691 +}
  1.2692 +
  1.2693 +bool
  1.2694 +TestApp::TestEditMessages(void)
  1.2695 +{
  1.2696 +  mTestString = NS_LITERAL_STRING(
  1.2697 +    "This is a test of\nthe native editing command messages");
  1.2698 +  // 0123456789012345678901 2345678901234567890123456789012
  1.2699 +  // 0         1         2          3         4         5
  1.2700 +
  1.2701 +  // The native text string is increased by converting \n to \r\n.
  1.2702 +  uint32_t testStringLength = mTestString.Length() + 1;
  1.2703 +
  1.2704 +  mTextArea->SetValue(mTestString);
  1.2705 +  mTextArea->Focus();
  1.2706 +
  1.2707 +  nsCOMPtr<nsIWidget> widget;
  1.2708 +  if (!GetWidget(getter_AddRefs(widget))) {
  1.2709 +    fail("TestEditMessages: get nsIWidget");
  1.2710 +    return false;
  1.2711 +  }
  1.2712 +
  1.2713 +  HWND wnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
  1.2714 +  bool result = true;
  1.2715 +
  1.2716 +  if (!::SendMessage(wnd, EM_CANUNDO, 0, 0)) {
  1.2717 +    fail("TestEditMessages: EM_CANUNDO");
  1.2718 +    return false;
  1.2719 +  }
  1.2720 +
  1.2721 +  if (::SendMessage(wnd, EM_CANREDO, 0, 0)) {
  1.2722 +    fail("TestEditMessages: EM_CANREDO #1");
  1.2723 +    return false;
  1.2724 +  }
  1.2725 +
  1.2726 +
  1.2727 +  if (!::SendMessage(wnd, EM_UNDO, 0, 0)) {
  1.2728 +    fail("TestEditMessages: EM_UNDO #1");
  1.2729 +    return false;
  1.2730 +  }
  1.2731 +
  1.2732 +  nsAutoString str;
  1.2733 +  mTextArea->GetValue(str);
  1.2734 +  if (str == mTestString) {
  1.2735 +    fail("TestEditMessage: EM_UNDO #1, failed to execute");
  1.2736 +    printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
  1.2737 +    return false;
  1.2738 +  }
  1.2739 +
  1.2740 +  if (!::SendMessage(wnd, EM_CANREDO, 0, 0)) {
  1.2741 +    fail("TestEditMessages: EM_CANREDO #2");
  1.2742 +    return false;
  1.2743 +  }
  1.2744 +
  1.2745 +  if (!::SendMessage(wnd, EM_REDO, 0, 0)) {
  1.2746 +    fail("TestEditMessages: EM_REDO #1");
  1.2747 +    return false;
  1.2748 +  }
  1.2749 +
  1.2750 +  mTextArea->GetValue(str);
  1.2751 +  if (str != mTestString) {
  1.2752 +    fail("TestEditMessage: EM_REDO #1, failed to execute");
  1.2753 +    printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
  1.2754 +    return false;
  1.2755 +  }
  1.2756 +
  1.2757 +  TS_SELECTION_ACP sel;
  1.2758 +  HRESULT hr;
  1.2759 +
  1.2760 +  sel.acpStart = 0;
  1.2761 +  sel.acpEnd = testStringLength;
  1.2762 +  sel.style.ase = TS_AE_END;
  1.2763 +  sel.style.fInterimChar = FALSE;
  1.2764 +  hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
  1.2765 +  if (!(SUCCEEDED(hr))) {
  1.2766 +    fail("TestEditMessages: SetSelection #1");
  1.2767 +    return false;
  1.2768 +  }
  1.2769 +
  1.2770 +  ::SendMessage(wnd, WM_CUT, 0, 0);
  1.2771 +  mTextArea->GetValue(str);
  1.2772 +  if (!str.IsEmpty()) {
  1.2773 +    fail("TestEditMessages: WM_CUT");
  1.2774 +    printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
  1.2775 +    return false;
  1.2776 +  }
  1.2777 +
  1.2778 +  ::SendMessage(wnd, WM_PASTE, 0, 0);
  1.2779 +  mTextArea->GetValue(str);
  1.2780 +  if (str != mTestString) {
  1.2781 +    fail("TestEditMessages: WM_PASTE #1");
  1.2782 +    printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
  1.2783 +    return false;
  1.2784 +  }
  1.2785 +
  1.2786 +  ::SendMessage(wnd, WM_PASTE, 0, 0);
  1.2787 +  mTextArea->GetValue(str);
  1.2788 +  nsAutoString expectedStr(mTestString);
  1.2789 +  expectedStr += mTestString;
  1.2790 +  if (str != expectedStr) {
  1.2791 +    fail("TestEditMessages: WM_PASTE #2");
  1.2792 +    printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
  1.2793 +    return false;
  1.2794 +  }
  1.2795 +
  1.2796 +  sel.acpStart = 0;
  1.2797 +  sel.acpEnd = testStringLength;
  1.2798 +  hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
  1.2799 +  if (!(SUCCEEDED(hr))) {
  1.2800 +    fail("TestEditMessages: SetSelection #2");
  1.2801 +    return false;
  1.2802 +  }
  1.2803 +
  1.2804 +  ::SendMessage(wnd, WM_CLEAR, 0, 0);
  1.2805 +  mTextArea->GetValue(str);
  1.2806 +  if (str != mTestString) {
  1.2807 +    fail("TestEditMessages: WM_CLEAR #1");
  1.2808 +    printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
  1.2809 +    return false;
  1.2810 +  }
  1.2811 +
  1.2812 +  sel.acpStart = 4;
  1.2813 +  sel.acpEnd = testStringLength;
  1.2814 +  hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
  1.2815 +  if (!(SUCCEEDED(hr))) {
  1.2816 +    fail("TestEditMessages: SetSelection #3");
  1.2817 +    return false;
  1.2818 +  }
  1.2819 +
  1.2820 +  ::SendMessage(wnd, WM_COPY, 0, 0);
  1.2821 +  mTextArea->GetValue(str);
  1.2822 +  if (str != mTestString) {
  1.2823 +    fail("TestEditMessages: WM_COPY");
  1.2824 +    printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
  1.2825 +    return false;
  1.2826 +  }
  1.2827 +
  1.2828 +  if (!::SendMessage(wnd, EM_CANPASTE, 0, 0)) {
  1.2829 +    fail("TestEditMessages: EM_CANPASTE #1");
  1.2830 +    return false;
  1.2831 +  }
  1.2832 +
  1.2833 +  if (!::SendMessage(wnd, EM_CANPASTE, CF_TEXT, 0)) {
  1.2834 +    fail("TestEditMessages: EM_CANPASTE #2");
  1.2835 +    return false;
  1.2836 +  }
  1.2837 +
  1.2838 +  if (!::SendMessage(wnd, EM_CANPASTE, CF_UNICODETEXT, 0)) {
  1.2839 +    fail("TestEditMessages: EM_CANPASTE #3");
  1.2840 +    return false;
  1.2841 +  }
  1.2842 +
  1.2843 +  ::SendMessage(wnd, WM_PASTE, 0, 0);
  1.2844 +  mTextArea->GetValue(str);
  1.2845 +  if (str != mTestString) {
  1.2846 +    fail("TestEditMessages: WM_PASTE #3");
  1.2847 +    printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
  1.2848 +    return false;
  1.2849 +  }
  1.2850 +
  1.2851 +  sel.acpStart = 4;
  1.2852 +  sel.acpEnd = testStringLength;
  1.2853 +  hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
  1.2854 +  if (!(SUCCEEDED(hr))) {
  1.2855 +    fail("TestEditMessages: SetSelection #3");
  1.2856 +    return false;
  1.2857 +  }
  1.2858 +
  1.2859 +  ::SendMessage(wnd, WM_CLEAR, 0, 0);
  1.2860 +  mTextArea->GetValue(str);
  1.2861 +  if (str != NS_LITERAL_STRING("This")) {
  1.2862 +    fail("TestEditMessages: WM_CLEAR #2");
  1.2863 +    printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
  1.2864 +    return false;
  1.2865 +  }
  1.2866 +
  1.2867 +  ::SendMessage(wnd, WM_PASTE, 0, 0);
  1.2868 +  mTextArea->GetValue(str);
  1.2869 +  if (str != mTestString) {
  1.2870 +    fail("TestEditMessages: WM_PASTE #4");
  1.2871 +    printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
  1.2872 +    return false;
  1.2873 +  }
  1.2874 +
  1.2875 +  return true;
  1.2876 +}
  1.2877 +
  1.2878 +bool
  1.2879 +TestApp::TestScrollMessages(void)
  1.2880 +{
  1.2881 +  NS_NAMED_LITERAL_STRING(kLine, "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\n");
  1.2882 +  mTestString.Truncate();
  1.2883 +  for (uint32_t i = 0; i < 30; i++) {
  1.2884 +    mTestString.Append(kLine);
  1.2885 +  }
  1.2886 +
  1.2887 +  mTextArea->SetAttribute(NS_LITERAL_STRING("style"),
  1.2888 +    NS_LITERAL_STRING("width:3em;height:3em;word-wrap:normal;"));
  1.2889 +  mTextArea->SetValue(mTestString);
  1.2890 +  mTextArea->Focus();
  1.2891 +
  1.2892 +  nsCOMPtr<nsIWidget> widget;
  1.2893 +  if (!GetWidget(getter_AddRefs(widget))) {
  1.2894 +    fail("TestScrollMessages: get nsIWidget");
  1.2895 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.2896 +    return false;
  1.2897 +  }
  1.2898 +
  1.2899 +  nsCOMPtr<nsIDOMElement> textArea = do_QueryInterface(mTextArea);
  1.2900 +  if (!textArea) {
  1.2901 +    fail("TestScrollMessages: get nsIDOMElement");
  1.2902 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.2903 +    return false;
  1.2904 +  }
  1.2905 +
  1.2906 +#define DO_CHECK(aFailureCondition, aDescription) \
  1.2907 +  if (aFailureCondition) { \
  1.2908 +    nsAutoCString str(aDescription); \
  1.2909 +    str.Append(": "); \
  1.2910 +    str.Append(#aFailureCondition); \
  1.2911 +    fail(str.get()); \
  1.2912 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString()); \
  1.2913 +    return false; \
  1.2914 +  }
  1.2915 +
  1.2916 +  HWND wnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
  1.2917 +
  1.2918 +  textArea->SetScrollTop(0);
  1.2919 +  textArea->SetScrollLeft(0);
  1.2920 +
  1.2921 +  if (::SendMessage(wnd, WM_VSCROLL, SB_LINEDOWN, 0) != 0) {
  1.2922 +    fail("TestScrollMessages: SendMessage WM_VSCROLL #1");
  1.2923 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.2924 +    return false;
  1.2925 +  }
  1.2926 +
  1.2927 +  int32_t x, y, prevX, prevY;
  1.2928 +  textArea->GetScrollTop(&y);
  1.2929 +  textArea->GetScrollLeft(&x);
  1.2930 +
  1.2931 +  DO_CHECK(x != 0, "TestScrollMessages: SendMessage WM_VSCROLL #1");
  1.2932 +  DO_CHECK(y == 0, "TestScrollMessages: SendMessage WM_VSCROLL #1");
  1.2933 +
  1.2934 +  if (::SendMessage(wnd, WM_HSCROLL, SB_LINERIGHT, 0) != 0) {
  1.2935 +    fail("TestScrollMessages: SendMessage WM_HSCROLL #1");
  1.2936 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.2937 +    return false;
  1.2938 +  }
  1.2939 +
  1.2940 +  prevX = x;
  1.2941 +  prevY = y;
  1.2942 +  textArea->GetScrollTop(&y);
  1.2943 +  textArea->GetScrollLeft(&x);
  1.2944 +
  1.2945 +  const int32_t kLineWidth  = x;
  1.2946 +  const int32_t kLineHeight = y;
  1.2947 +
  1.2948 +  DO_CHECK(x == 0,     "TestScrollMessages: SendMessage WM_HSCROLL #1");
  1.2949 +  DO_CHECK(y != prevY, "TestScrollMessages: SendMessage WM_HSCROLL #1");
  1.2950 +
  1.2951 +  if (::SendMessage(wnd, WM_VSCROLL, SB_LINEUP, 0) != 0) {
  1.2952 +    fail("TestScrollMessages: SendMessage WM_VSCROLL #2");
  1.2953 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.2954 +    return false;
  1.2955 +  }
  1.2956 +
  1.2957 +  prevX = x;
  1.2958 +  prevY = y;
  1.2959 +  textArea->GetScrollTop(&y);
  1.2960 +  textArea->GetScrollLeft(&x);
  1.2961 +
  1.2962 +  DO_CHECK(x != prevX, "TestScrollMessages: SendMessage WM_VSCROLL #2");
  1.2963 +  DO_CHECK(y != 0,     "TestScrollMessages: SendMessage WM_VSCROLL #2");
  1.2964 +
  1.2965 +  if (::SendMessage(wnd, WM_HSCROLL, SB_LINELEFT, 0) != 0) {
  1.2966 +    fail("TestScrollMessages: SendMessage WM_HSCROLL #2");
  1.2967 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.2968 +    return false;
  1.2969 +  }
  1.2970 +
  1.2971 +  prevX = x;
  1.2972 +  prevY = y;
  1.2973 +  textArea->GetScrollTop(&y);
  1.2974 +  textArea->GetScrollLeft(&x);
  1.2975 +
  1.2976 +  DO_CHECK(x != 0, "TestScrollMessages: SendMessage WM_HSCROLL #2");
  1.2977 +  DO_CHECK(y != 0, "TestScrollMessages: SendMessage WM_HSCROLL #2");
  1.2978 +
  1.2979 +  if (::SendMessage(wnd, WM_VSCROLL, SB_PAGEDOWN, 0) != 0) {
  1.2980 +    fail("TestScrollMessages: SendMessage WM_VSCROLL #3");
  1.2981 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.2982 +    return false;
  1.2983 +  }
  1.2984 +
  1.2985 +  prevX = x;
  1.2986 +  prevY = y;
  1.2987 +  textArea->GetScrollTop(&y);
  1.2988 +  textArea->GetScrollLeft(&x);
  1.2989 +
  1.2990 +  DO_CHECK(x != 0,           "TestScrollMessages: SendMessage WM_VSCROLL #3");
  1.2991 +  DO_CHECK(y <= kLineHeight, "TestScrollMessages: SendMessage WM_VSCROLL #3");
  1.2992 +
  1.2993 +  if (::SendMessage(wnd, WM_HSCROLL, SB_PAGERIGHT, 0) != 0) {
  1.2994 +    fail("TestScrollMessages: SendMessage WM_HSCROLL #3");
  1.2995 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.2996 +    return false;
  1.2997 +  }
  1.2998 +
  1.2999 +  prevX = x;
  1.3000 +  prevY = y;
  1.3001 +  textArea->GetScrollTop(&y);
  1.3002 +  textArea->GetScrollLeft(&x);
  1.3003 +
  1.3004 +  DO_CHECK(x <= kLineWidth, "TestScrollMessages: SendMessage WM_HSCROLL #3");
  1.3005 +  DO_CHECK(y != prevY,      "TestScrollMessages: SendMessage WM_HSCROLL #3");
  1.3006 +
  1.3007 +  const int32_t kPageWidth  = x;
  1.3008 +  const int32_t kPageHeight = y;
  1.3009 +
  1.3010 +  ::SendMessage(wnd, WM_VSCROLL, SB_LINEDOWN, 0);
  1.3011 +  ::SendMessage(wnd, WM_VSCROLL, SB_LINEUP, 0);
  1.3012 +  ::SendMessage(wnd, WM_HSCROLL, SB_LINERIGHT, 0);
  1.3013 +  ::SendMessage(wnd, WM_HSCROLL, SB_LINELEFT, 0);
  1.3014 +
  1.3015 +  prevX = x;
  1.3016 +  prevY = y;
  1.3017 +  textArea->GetScrollTop(&y);
  1.3018 +  textArea->GetScrollLeft(&x);
  1.3019 +
  1.3020 +  DO_CHECK(x != prevX, "TestScrollMessages: SB_LINELEFT scrolled wrong amount");
  1.3021 +  DO_CHECK(y != prevY, "TestScrollMessages: SB_LINEUP scrolled wrong amount");
  1.3022 +
  1.3023 +  if (::SendMessage(wnd, WM_VSCROLL, SB_PAGEUP, 0) != 0) {
  1.3024 +    fail("TestScrollMessages: SendMessage WM_VSCROLL #4");
  1.3025 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.3026 +    return false;
  1.3027 +  }
  1.3028 +
  1.3029 +  prevX = x;
  1.3030 +  prevY = y;
  1.3031 +  textArea->GetScrollTop(&y);
  1.3032 +  textArea->GetScrollLeft(&x);
  1.3033 +
  1.3034 +  DO_CHECK(x != prevX, "TestScrollMessages: SendMessage WM_VSCROLL #4");
  1.3035 +  DO_CHECK(y != 0,     "TestScrollMessages: SendMessage WM_VSCROLL #4");
  1.3036 +
  1.3037 +  if (::SendMessage(wnd, WM_HSCROLL, SB_PAGELEFT, 0) != 0) {
  1.3038 +    fail("TestScrollMessages: SendMessage WM_HSCROLL #4");
  1.3039 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.3040 +    return false;
  1.3041 +  }
  1.3042 +
  1.3043 +  prevX = x;
  1.3044 +  prevY = y;
  1.3045 +  textArea->GetScrollTop(&y);
  1.3046 +  textArea->GetScrollLeft(&x);
  1.3047 +
  1.3048 +  DO_CHECK(x != 0, "TestScrollMessages: SendMessage WM_HSCROLL #4");
  1.3049 +  DO_CHECK(y != 0, "TestScrollMessages: SendMessage WM_HSCROLL #4");
  1.3050 +
  1.3051 +  if (::SendMessage(wnd, WM_VSCROLL, SB_BOTTOM, 0) != 0) {
  1.3052 +    fail("TestScrollMessages: SendMessage WM_VSCROLL #5");
  1.3053 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.3054 +    return false;
  1.3055 +  }
  1.3056 +
  1.3057 +  prevX = x;
  1.3058 +  prevY = y;
  1.3059 +  textArea->GetScrollTop(&y);
  1.3060 +  textArea->GetScrollLeft(&x);
  1.3061 +
  1.3062 +  DO_CHECK(x != 0,           "TestScrollMessages: SendMessage WM_VSCROLL #5");
  1.3063 +  DO_CHECK(y <= kPageHeight, "TestScrollMessages: SendMessage WM_VSCROLL #5");
  1.3064 +
  1.3065 +  if (::SendMessage(wnd, WM_HSCROLL, SB_RIGHT, 0) != 0) {
  1.3066 +    fail("TestScrollMessages: SendMessage WM_HSCROLL #6");
  1.3067 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.3068 +    return false;
  1.3069 +  }
  1.3070 +
  1.3071 +  prevX = x;
  1.3072 +  prevY = y;
  1.3073 +  textArea->GetScrollTop(&y);
  1.3074 +  textArea->GetScrollLeft(&x);
  1.3075 +
  1.3076 +  DO_CHECK(x <= kPageWidth, "TestScrollMessages: SendMessage WM_HSCROLL #5");
  1.3077 +  DO_CHECK(y != prevY,      "TestScrollMessages: SendMessage WM_HSCROLL #5");
  1.3078 +
  1.3079 +  ::SendMessage(wnd, WM_VSCROLL, SB_LINEDOWN, 0);
  1.3080 +  ::SendMessage(wnd, WM_HSCROLL, SB_LINERIGHT, 0);
  1.3081 +
  1.3082 +  prevX = x;
  1.3083 +  prevY = y;
  1.3084 +  textArea->GetScrollTop(&y);
  1.3085 +  textArea->GetScrollLeft(&x);
  1.3086 +
  1.3087 +  DO_CHECK(x != prevX, "SB_RIGHT didn't scroll to right most");
  1.3088 +  DO_CHECK(y != prevY, "SB_BOTTOM didn't scroll to bottom most");
  1.3089 +
  1.3090 +  ::SendMessage(wnd, WM_VSCROLL, SB_PAGEUP, 0);
  1.3091 +  ::SendMessage(wnd, WM_VSCROLL, SB_PAGEDOWN, 0);
  1.3092 +  ::SendMessage(wnd, WM_HSCROLL, SB_PAGELEFT, 0);
  1.3093 +  ::SendMessage(wnd, WM_HSCROLL, SB_PAGERIGHT, 0);
  1.3094 +
  1.3095 +  prevX = x;
  1.3096 +  prevY = y;
  1.3097 +  textArea->GetScrollTop(&y);
  1.3098 +  textArea->GetScrollLeft(&x);
  1.3099 +
  1.3100 +  DO_CHECK(x != prevX, "TestScrollMessages: SB_PAGELEFT scrolled wrong amount");
  1.3101 +  DO_CHECK(y != prevY, "TestScrollMessages: SB_PAGEUP scrolled wrong amount");
  1.3102 +
  1.3103 +  if (::SendMessage(wnd, WM_VSCROLL, SB_TOP, 0) != 0) {
  1.3104 +    fail("TestScrollMessages: SendMessage WM_VSCROLL #6");
  1.3105 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.3106 +    return false;
  1.3107 +  }
  1.3108 +
  1.3109 +  prevX = x;
  1.3110 +  prevY = y;
  1.3111 +  textArea->GetScrollTop(&y);
  1.3112 +  textArea->GetScrollLeft(&x);
  1.3113 +
  1.3114 +  DO_CHECK(x != prevX, "TestScrollMessages: SendMessage WM_VSCROLL #6");
  1.3115 +  DO_CHECK(y != 0,     "TestScrollMessages: SendMessage WM_VSCROLL #6");
  1.3116 +
  1.3117 +  if (::SendMessage(wnd, WM_HSCROLL, SB_LEFT, 0) != 0) {
  1.3118 +    fail("TestScrollMessages: SendMessage WM_HSCROLL #4");
  1.3119 +    mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.3120 +    return false;
  1.3121 +  }
  1.3122 +
  1.3123 +  prevX = x;
  1.3124 +  prevY = y;
  1.3125 +  textArea->GetScrollTop(&y);
  1.3126 +  textArea->GetScrollLeft(&x);
  1.3127 +
  1.3128 +  DO_CHECK(x != 0, "TestScrollMessages: SendMessage WM_HSCROLL #6");
  1.3129 +  DO_CHECK(y != 0, "TestScrollMessages: SendMessage WM_HSCROLL #6");
  1.3130 +#undef DO_CHECK
  1.3131 +
  1.3132 +  mTextArea->SetAttribute(NS_LITERAL_STRING("style"), EmptyString());
  1.3133 +  return true;
  1.3134 +}
  1.3135 +
  1.3136 +bool
  1.3137 +TestApp::GetWidget(nsIWidget** aWidget)
  1.3138 +{
  1.3139 +  nsCOMPtr<nsIDocShell> docShell;
  1.3140 +  nsresult rv = mWindow->GetDocShell(getter_AddRefs(docShell));
  1.3141 +  if (NS_FAILED(rv) || !docShell) {
  1.3142 +    return false;
  1.3143 +  }
  1.3144 +
  1.3145 +  nsCOMPtr<nsIPresShell> presShell;
  1.3146 +  rv = docShell->GetPresShell(getter_AddRefs(presShell));
  1.3147 +  if (NS_FAILED(rv) || !presShell) {
  1.3148 +    return false;
  1.3149 +  }
  1.3150 +
  1.3151 +  nsRefPtr<nsViewManager> viewManager = presShell->GetViewManager();
  1.3152 +  if (!viewManager) {
  1.3153 +    return false;
  1.3154 +  }
  1.3155 +
  1.3156 +  rv = viewManager->GetRootWidget(aWidget);
  1.3157 +  return (NS_SUCCEEDED(rv) && aWidget);
  1.3158 +}
  1.3159 +
  1.3160 +nsresult
  1.3161 +TestApp::GetSelCon(nsISelectionController** aSelCon)
  1.3162 +{
  1.3163 +  nsCOMPtr<nsIDocShell> docShell;
  1.3164 +  nsresult nsr = mWindow->GetDocShell(getter_AddRefs(docShell));
  1.3165 +  if (NS_SUCCEEDED(nsr) && docShell) {
  1.3166 +    nsCOMPtr<nsIPresShell> presShell;
  1.3167 +    nsr = docShell->GetPresShell(getter_AddRefs(presShell));
  1.3168 +    if (NS_SUCCEEDED(nsr) && presShell) {
  1.3169 +      nsIFrame* frame = 
  1.3170 +        nsCOMPtr<nsIContent>(do_QueryInterface(mCurrentNode))->GetPrimaryFrame();
  1.3171 +      if (frame) {
  1.3172 +        nsPresContext* presContext = presShell->GetPresContext();
  1.3173 +        if (presContext) {
  1.3174 +          nsr = frame->GetSelectionController(presContext, aSelCon);
  1.3175 +        }
  1.3176 +      }
  1.3177 +    }
  1.3178 +  }
  1.3179 +  return nsr;
  1.3180 +}
  1.3181 +
  1.3182 +int main(int argc, char** argv)
  1.3183 +{
  1.3184 +  ScopedXPCOM xpcom("TestWinTSF (bug #88831)");
  1.3185 +  if (xpcom.failed())
  1.3186 +    return 1;
  1.3187 +
  1.3188 +  nsRefPtr<TestApp> tests = new TestApp();
  1.3189 +  if (!tests)
  1.3190 +    return 1;
  1.3191 +
  1.3192 +  if (NS_FAILED(tests->Run())) {
  1.3193 +    fail("run failed");
  1.3194 +    return 1;
  1.3195 +  }
  1.3196 +  return int(tests->CheckFailed());
  1.3197 +}

mercurial