widget/tests/TestWinTSF.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial