From ef02e15d4c3f64ffacfb2bda72b6ff498b88753b Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Wed, 12 Sep 2012 08:53:12 +0900 Subject: [PATCH] Bug 544773 part.1 TSF module should log its behavior r=jimm --- widget/windows/nsTextStore.cpp | 1612 +++++++++++++++++++++++++++----- widget/windows/nsTextStore.h | 13 + 2 files changed, 1400 insertions(+), 225 deletions(-) diff --git a/widget/windows/nsTextStore.cpp b/widget/windows/nsTextStore.cpp index 6eb7c0695b63..23c7479a4198 100644 --- a/widget/windows/nsTextStore.cpp +++ b/widget/windows/nsTextStore.cpp @@ -5,11 +5,16 @@ #include +#ifdef MOZ_LOGGING +#define FORCE_PR_LOG /* Allow logging in the release build */ +#endif // MOZ_LOGGING +#include "prlog.h" + #include "nscore.h" #include "nsTextStore.h" #include "nsWindow.h" -#include "prlog.h" #include "nsPrintfCString.h" +#include "WinUtils.h" #include "mozilla/Preferences.h" using namespace mozilla; @@ -28,11 +33,227 @@ nsTextStore* nsTextStore::sTsfTextStore = NULL; UINT nsTextStore::sFlushTIPInputMessage = 0; #ifdef PR_LOGGING + +/** + * TSF related code should log its behavior even on release build especially + * in the interface methods. + * + * In interface methods, use PR_LOG_ALWAYS. + * In internal methods, use PR_LOG_DEBUG for logging normal behavior. + * For logging error, use PR_LOG_ERROR. + * + * When an instance method is called, start with following text: + * "TSF: 0x%p nsFoo::Bar(", the 0x%p should be the "this" of the nsFoo. + * after that, start with: + * "TSF: 0x%p nsFoo::Bar(" + * In an internal method, start with following text: + * "TSF: 0x%p nsFoo::Bar(" + * When a static method is called, start with following text: + * "TSF: nsFoo::Bar(" + */ + PRLogModuleInfo* sTextStoreLog = nullptr; -#endif + +static const char* +GetBoolName(bool aBool) +{ + return aBool ? "true" : "false"; +} + +static const char* +GetIMEEnabledName(IMEState::Enabled aIMEEnabled) +{ + switch (aIMEEnabled) { + case IMEState::DISABLED: + return "DISABLED"; + case IMEState::ENABLED: + return "ENABLED"; + case IMEState::PASSWORD: + return "PASSWORD"; + case IMEState::PLUGIN: + return "PLUGIN"; + default: + return "Invalid"; + } +} + +static nsCString +GetRIIDNameStr(REFIID aRIID) +{ + LPOLESTR str = nullptr; + HRESULT hr = ::StringFromIID(aRIID, &str); + if (FAILED(hr) || !str || !str[0]) { + return EmptyCString(); + } + + nsAutoString key(L"Interface\\"); + key += str; + + nsAutoCString result; + PRUnichar buf[256]; + if (WinUtils::GetRegistryKey(HKEY_CLASSES_ROOT, key.get(), nullptr, + buf, sizeof(buf))) { + result = NS_ConvertUTF16toUTF8(buf); + } else { + result = NS_ConvertUTF16toUTF8(str); + } + + ::CoTaskMemFree(str); + return result; +} + +static const char* +GetCommonReturnValueName(HRESULT aResult) +{ + switch (aResult) { + case S_OK: + return "S_OK"; + case E_ABORT: + return "E_ABORT"; + case E_ACCESSDENIED: + return "E_ACCESSDENIED"; + case E_FAIL: + return "E_FAIL"; + case E_HANDLE: + return "E_HANDLE"; + case E_INVALIDARG: + return "E_INVALIDARG"; + case E_NOINTERFACE: + return "E_NOINTERFACE"; + case E_NOTIMPL: + return "E_NOTIMPL"; + case E_OUTOFMEMORY: + return "E_OUTOFMEMORY"; + case E_POINTER: + return "E_POINTER"; + case E_UNEXPECTED: + return "E_UNEXPECTED"; + default: + return SUCCEEDED(aResult) ? "Succeeded" : "Failed"; + } +} + +static const char* +GetTextStoreReturnValueName(HRESULT aResult) +{ + switch (aResult) { + case TS_E_FORMAT: + return "TS_E_FORMAT"; + case TS_E_INVALIDPOINT: + return "TS_E_INVALIDPOINT"; + case TS_E_INVALIDPOS: + return "TS_E_INVALIDPOS"; + case TS_E_NOINTERFACE: + return "TS_E_NOINTERFACE"; + case TS_E_NOLAYOUT: + return "TS_E_NOLAYOUT"; + case TS_E_NOLOCK: + return "TS_E_NOLOCK"; + case TS_E_NOOBJECT: + return "TS_E_NOOBJECT"; + case TS_E_NOSELECTION: + return "TS_E_NOSELECTION"; + case TS_E_NOSERVICE: + return "TS_E_NOSERVICE"; + case TS_E_READONLY: + return "TS_E_READONLY"; + case TS_E_SYNCHRONOUS: + return "TS_E_SYNCHRONOUS"; + case TS_S_ASYNC: + return "TS_S_ASYNC"; + default: + return GetCommonReturnValueName(aResult); + } +} + +static const nsCString +GetSinkMaskNameStr(DWORD aSinkMask) +{ + nsAutoCString description; + if (aSinkMask & TS_AS_TEXT_CHANGE) { + description.AppendLiteral("TS_AS_TEXT_CHANGE"); + } + if (aSinkMask & TS_AS_SEL_CHANGE) { + if (!description.IsEmpty()) { + description.AppendLiteral(" | "); + } + description.AppendLiteral("TS_AS_SEL_CHANGE"); + } + if (aSinkMask & TS_AS_LAYOUT_CHANGE) { + if (!description.IsEmpty()) { + description.AppendLiteral(" | "); + } + description.AppendLiteral("TS_AS_LAYOUT_CHANGE"); + } + if (aSinkMask & TS_AS_ATTR_CHANGE) { + if (!description.IsEmpty()) { + description.AppendLiteral(" | "); + } + description.AppendLiteral("TS_AS_ATTR_CHANGE"); + } + if (aSinkMask & TS_AS_STATUS_CHANGE) { + if (!description.IsEmpty()) { + description.AppendLiteral(" | "); + } + description.AppendLiteral("TS_AS_STATUS_CHANGE"); + } + if (description.IsEmpty()) { + description.AppendLiteral("not-specified"); + } + return description; +} + +static const char* +GetActiveSelEndName(TsActiveSelEnd aSelEnd) +{ + return aSelEnd == TS_AE_NONE ? "TS_AE_NONE" : + aSelEnd == TS_AE_START ? "TS_AE_START" : + aSelEnd == TS_AE_END ? "TS_AE_END" : "Unknown"; +} + +static const nsCString +GetLockFlagNameStr(DWORD aLockFlags) +{ + nsAutoCString description; + if ((aLockFlags & TS_LF_READWRITE) == TS_LF_READWRITE) { + description.AppendLiteral("TS_LF_READWRITE"); + } else if (aLockFlags & TS_LF_READ) { + description.AppendLiteral("TS_LF_READ"); + } + if (aLockFlags & TS_LF_SYNC) { + if (!description.IsEmpty()) { + description.AppendLiteral(" | "); + } + description.AppendLiteral("TS_LF_SYNC"); + } + if (description.IsEmpty()) { + description.AppendLiteral("not-specified"); + } + return description; +} + +static const char* +GetTextRunTypeName(TsRunType aRunType) +{ + switch (aRunType) { + case TS_RT_PLAIN: + return "TS_RT_PLAIN"; + case TS_RT_HIDDEN: + return "TS_RT_HIDDEN"; + case TS_RT_OPAQUE: + return "TS_RT_OPAQUE"; + default: + return "Unknown"; + } +} + +#endif // #ifdef PR_LOGGING nsTextStore::nsTextStore() { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::nsTestStore(): instance is created", this)); + mRefCnt = 1; mEditCookie = 0; mSinkMask = 0; @@ -46,6 +267,11 @@ nsTextStore::nsTextStore() nsTextStore::~nsTextStore() { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore instance is destroyed, " + "mWindow=0x%p, mDocumentMgr=0x%p, mContext=0x%p", + this, mWindow, mDocumentMgr, mContext)); + if (mCompositionTimer) { mCompositionTimer->Cancel(); mCompositionTimer = nullptr; @@ -57,34 +283,66 @@ bool nsTextStore::Create(nsWindow* aWindow, IMEState::Enabled aIMEEnabled) { - if (!mDocumentMgr) { - // Create document manager - HRESULT hr = sTsfThreadMgr->CreateDocumentMgr( - getter_AddRefs(mDocumentMgr)); - NS_ENSURE_TRUE(SUCCEEDED(hr), false); - mWindow = aWindow; - // Create context and add it to document manager - hr = mDocumentMgr->CreateContext(sTsfClientId, 0, - static_cast(this), - getter_AddRefs(mContext), &mEditCookie); - if (SUCCEEDED(hr)) { - SetInputContextInternal(aIMEEnabled); - hr = mDocumentMgr->Push(mContext); - } - if (SUCCEEDED(hr)) { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: Created, window=%08x\n", aWindow)); - return true; - } + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::Create(aWindow=0x%p, aIMEEnabled=%s)", + this, aWindow, GetIMEEnabledName(aIMEEnabled))); + + if (mDocumentMgr) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::Create() FAILED due to already initialized", + this)); + return false; + } + + // Create document manager + HRESULT hr = sTsfThreadMgr->CreateDocumentMgr( + getter_AddRefs(mDocumentMgr)); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::Create() FAILED to create DocumentMgr " + "(0x%08X)", this, hr)); + return false; + } + mWindow = aWindow; + // Create context and add it to document manager + hr = mDocumentMgr->CreateContext(sTsfClientId, 0, + static_cast(this), + getter_AddRefs(mContext), &mEditCookie); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::Create() FAILED to create the context " + "(0x%08X)", this, hr)); + mDocumentMgr = NULL; + return false; + } + + SetInputContextInternal(aIMEEnabled); + + hr = mDocumentMgr->Push(mContext); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::Create() FAILED to push the context (0x%08X)", + this, hr)); + // XXX Why don't we use NS_IF_RELEASE() here?? mContext = NULL; mDocumentMgr = NULL; + return false; } - return false; + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::Create() succeeded: " + "mDocumentMgr=0x%p, mContext=0x%p, mEditCookie=0x%08X", + this, mDocumentMgr, mContext, mEditCookie)); + + return true; } bool nsTextStore::Destroy(void) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::Destroy()", this)); + if (mWindow) { // When blurred, Tablet Input Panel posts "blur" messages // and try to insert text when the message is retrieved later. @@ -103,9 +361,10 @@ nsTextStore::Destroy(void) mDocumentMgr = NULL; } mSink = NULL; - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: Destroyed, window=%08x\n", mWindow)); mWindow = NULL; + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::Destroy() succeeded", this)); return true; } @@ -123,6 +382,10 @@ nsTextStore::QueryInterface(REFIID riid, AddRef(); return S_OK; } + + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::QueryInterface() FAILED, riid=%s", + this, GetRIIDNameStr(riid).get())); return E_NOINTERFACE; } @@ -145,42 +408,85 @@ nsTextStore::AdviseSink(REFIID riid, IUnknown *punk, DWORD dwMask) { - NS_ENSURE_TRUE(punk && IID_ITextStoreACPSink == riid, E_INVALIDARG); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::AdviseSink(riid=%s, punk=0x%p, dwMask=%s), " + "mSink=0x%p, mSinkMask=%s", + this, GetRIIDNameStr(riid).get(), punk, GetSinkMaskNameStr(dwMask).get(), + mSink, GetSinkMaskNameStr(mSinkMask).get())); + + if (!punk) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to the null punk", + this)); + return E_UNEXPECTED; + } + + if (IID_ITextStoreACPSink != riid) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to " + "unsupported interface", this)); + return E_INVALIDARG; // means unsupported interface. + } + if (!mSink) { // Install sink punk->QueryInterface(IID_ITextStoreACPSink, getter_AddRefs(mSink)); - NS_ENSURE_TRUE(mSink, E_UNEXPECTED); + if (!mSink) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to " + "punk not having the interface", this)); + return E_UNEXPECTED; + } } else { // If sink is already installed we check to see if they are the same // Get IUnknown from both sides for comparison nsRefPtr comparison1, comparison2; punk->QueryInterface(IID_IUnknown, getter_AddRefs(comparison1)); mSink->QueryInterface(IID_IUnknown, getter_AddRefs(comparison2)); - if (comparison1 != comparison2) + if (comparison1 != comparison2) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to " + "the sink being different from the stored sink", this)); return CONNECT_E_ADVISELIMIT; + } } // Update mask either for a new sink or an existing sink mSinkMask = dwMask; - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: Sink installed, punk=%08x\n", punk)); return S_OK; } STDMETHODIMP nsTextStore::UnadviseSink(IUnknown *punk) { - NS_ENSURE_TRUE(punk, E_INVALIDARG); - NS_ENSURE_TRUE(mSink, CONNECT_E_NOCONNECTION); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::UnadviseSink(punk=0x%p), mSink=0x%p", + this, punk, mSink)); + + if (!punk) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::UnadviseSink() FAILED due to the null punk", + this)); + return E_INVALIDARG; + } + if (!mSink) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::UnadviseSink() FAILED due to " + "any sink not stored", this)); + return CONNECT_E_NOCONNECTION; + } // Get IUnknown from both sides for comparison nsRefPtr comparison1, comparison2; punk->QueryInterface(IID_IUnknown, getter_AddRefs(comparison1)); mSink->QueryInterface(IID_IUnknown, getter_AddRefs(comparison2)); // Unadvise only if sinks are the same - NS_ENSURE_TRUE(comparison1 == comparison2, CONNECT_E_NOCONNECTION); + if (comparison1 != comparison2) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::UnadviseSink() FAILED due to " + "the sink being different from the stored sink", this)); + return CONNECT_E_NOCONNECTION; + } mSink = NULL; mSinkMask = 0; - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: Sink removed, punk=%08x\n", punk)); return S_OK; } @@ -188,39 +494,79 @@ STDMETHODIMP nsTextStore::RequestLock(DWORD dwLockFlags, HRESULT *phrSession) { - NS_ENSURE_TRUE(mSink, E_FAIL); - NS_ENSURE_TRUE(phrSession, E_INVALIDARG); - if (mLock) { - // only time when reentrant lock is allowed is when caller holds a - // read-only lock and is requesting an async write lock - if (TS_LF_READ == (mLock & TS_LF_READWRITE) && - TS_LF_READWRITE == (dwLockFlags & TS_LF_READWRITE) && - !(dwLockFlags & TS_LF_SYNC)) { - *phrSession = TS_S_ASYNC; - mLockQueued = dwLockFlags & (~TS_LF_SYNC); - } else { - // no more locks allowed - *phrSession = TS_E_SYNCHRONOUS; - return E_FAIL; - } - } else { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::RequestLock(dwLockFlags=%s, phrSession=0x%p), " + "mLock=%s", this, GetLockFlagNameStr(dwLockFlags).get(), phrSession, + GetLockFlagNameStr(mLock).get())); + + if (!mSink) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::RequestLock() FAILED due to " + "any sink not stored", this)); + return E_FAIL; + } + if (!phrSession) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::RequestLock() FAILED due to " + "null phrSession", this)); + return E_INVALIDARG; + } + + if (!mLock) { // put on lock mLock = dwLockFlags & (~TS_LF_SYNC); + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::RequestLock() notifying OnLockGranted()...", + this)); *phrSession = mSink->OnLockGranted(mLock); while (mLockQueued) { mLock = mLockQueued; mLockQueued = 0; + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::RequestLock() notifying OnLockGranted() " + "with mLockQueued (%s)...", + this, GetLockFlagNameStr(mLock).get())); mSink->OnLockGranted(mLock); } mLock = 0; + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::RequestLock() succeeded: *phrSession=%s", + this, GetTextStoreReturnValueName(*phrSession))); + return S_OK; } - return S_OK; + + // only time when reentrant lock is allowed is when caller holds a + // read-only lock and is requesting an async write lock + if (IsReadLocked() && !IsReadWriteLocked() && IsReadWriteLock(dwLockFlags) && + !(dwLockFlags & TS_LF_SYNC)) { + *phrSession = TS_S_ASYNC; + mLockQueued = dwLockFlags & (~TS_LF_SYNC); + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::RequestLock() stores the request in the " + "queue, *phrSession=TS_S_ASYNC", this)); + return S_OK; + } + + // no more locks allowed + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::RequestLock() didn't allow to lock, " + "*phrSession=TS_E_SYNCHRONOUS", this)); + *phrSession = TS_E_SYNCHRONOUS; + return E_FAIL; } STDMETHODIMP nsTextStore::GetStatus(TS_STATUS *pdcs) { - NS_ENSURE_TRUE(pdcs, E_INVALIDARG); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetStatus(pdcs=0x%p)", this, pdcs)); + + if (!pdcs) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetStatus() FAILED due to null pdcs", this)); + return E_INVALIDARG; + } pdcs->dwDynamicFlags = 0; // we use a "flat" text model for TSF support so no hidden text pdcs->dwStaticFlags = TS_SS_NOHIDDENTEXT; @@ -235,12 +581,23 @@ nsTextStore::QueryInsert(LONG acpTestStart, LONG *pacpResultEnd) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: QueryInsert, start=%ld end=%ld cch=%lu\n", - acpTestStart, acpTestEnd, cch)); - // We don't test to see if these positions are - // after the end of document for performance reasons - NS_ENSURE_TRUE(0 <= acpTestStart && acpTestStart <= acpTestEnd && - pacpResultStart && pacpResultEnd, E_INVALIDARG); + ("TSF: 0x%p nsTextStore::QueryInsert(acpTestStart=%ld, " + "acpTestEnd=%ld, cch=%lu, pacpResultStart=0x%p, pacpResultEnd=0x%p)", + this, acpTestStart, acpTestEnd, cch, acpTestStart, acpTestEnd)); + + if (!pacpResultStart || !pacpResultEnd) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::QueryInsert() FAILED due to " + "the null argument", this)); + return E_INVALIDARG; + } + + if (acpTestStart < 0 || acpTestStart > acpTestEnd) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::QueryInsert() FAILED due to " + "wrong argument", this)); + return E_INVALIDARG; + } // XXX need to adjust to cluster boundary // Assume we are given good offsets for now @@ -248,7 +605,9 @@ nsTextStore::QueryInsert(LONG acpTestStart, *pacpResultEnd = acpTestStart + cch; PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: QueryInsert SUCCEEDED\n")); + ("TSF: 0x%p nsTextStore::QueryInsert() succeeded: " + "*pacpResultStart=%ld, *pacpResultEnd=%ld)", + this, *pacpResultStart, *pacpResultEnd)); return S_OK; } @@ -258,34 +617,94 @@ nsTextStore::GetSelection(ULONG ulIndex, TS_SELECTION_ACP *pSelection, ULONG *pcFetched) { - NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK); - NS_ENSURE_TRUE(ulCount && pSelection && pcFetched, E_INVALIDARG); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetSelection(ulIndex=%lu, ulCount=%lu, " + "pSelection=0x%p, pcFetched=0x%p)", + this, ulIndex, ulCount, pSelection, pcFetched)); + + if (!IsReadLocked()) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetSelection() FAILED due to not locked", + this)); + return TS_E_NOLOCK; + } + if (!ulCount || !pSelection || !pcFetched) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetSelection() FAILED due to " + "null argument", this)); + return E_INVALIDARG; + } *pcFetched = 0; - NS_ENSURE_TRUE((ULONG)TS_DEFAULT_SELECTION == ulIndex || 0 == ulIndex, - TS_E_NOSELECTION); + + if (ulIndex != static_cast(TS_DEFAULT_SELECTION) && + ulIndex != 0) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetSelection() FAILED due to " + "unsupported selection", this)); + return TS_E_NOSELECTION; + } + + if (!GetSelectionInternal(*pSelection)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetSelection() FAILED to get selection", + this)); + return E_FAIL; + } + + *pcFetched = 1; + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetSelection() succeeded", this)); + return S_OK; +} + +bool +nsTextStore::GetSelectionInternal(TS_SELECTION_ACP &aSelectionACP) +{ if (mCompositionView) { + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::GetSelectionInternal(), " + "there is no composition view", this)); + // Emulate selection during compositions - *pSelection = mCompositionSelection; + aSelectionACP = mCompositionSelection; } else { + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::GetSelectionInternal(), " + "try to get normal selection...", this)); + // Construct and initialize an event to get selection info nsQueryContentEvent event(true, NS_QUERY_SELECTED_TEXT, mWindow); mWindow->InitEvent(event); mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, E_FAIL); + if (!event.mSucceeded) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetSelectionInternal() FAILED to " + "query selected text", this)); + return false; + } // Usually the selection anchor (beginning) position corresponds to the // TSF start and the selection focus (ending) position corresponds to // the TSF end, but if selection is reversed the focus now corresponds // to the TSF start and the anchor now corresponds to the TSF end - pSelection->acpStart = event.mReply.mOffset; - pSelection->acpEnd = pSelection->acpStart + event.mReply.mString.Length(); - pSelection->style.ase = event.mReply.mString.Length() && - event.mReply.mReversed ? TS_AE_START : TS_AE_END; + aSelectionACP.acpStart = event.mReply.mOffset; + aSelectionACP.acpEnd = + aSelectionACP.acpStart + event.mReply.mString.Length(); + aSelectionACP.style.ase = + event.mReply.mString.Length() && event.mReply.mReversed ? TS_AE_START : + TS_AE_END; // No support for interim character - pSelection->style.fInterimChar = 0; + aSelectionACP.style.fInterimChar = FALSE; } - *pcFetched = 1; - return S_OK; + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetSelectionInternal() succeeded: " + "acpStart=%lu, acpEnd=%lu, style.ase=%s, style.fInterimChar=%s", + this, aSelectionACP.acpStart, aSelectionACP.acpEnd, + GetActiveSelEndName(aSelectionACP.style.ase), + GetBoolName(aSelectionACP.style.fInterimChar))); + + return true; } static HRESULT @@ -443,25 +862,30 @@ nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty, HRESULT hr; #ifdef PR_LOGGING - LONG start = 0, length = 0; - hr = GetRangeExtent(aRange, &start, &length); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: GetDisplayAttribute range=%ld-%ld\n", - start - mCompositionStart, start - mCompositionStart + length)); + if (PR_LOG_TEST(sTextStoreLog, PR_LOG_DEBUG)) { + LONG start = 0, length = 0; + hr = GetRangeExtent(aRange, &start, &length); + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::GetDisplayAttribute(): " + "GetDisplayAttribute range=%ld-%ld (hr=%s)", + this, start - mCompositionStart, start - mCompositionStart + length, + GetCommonReturnValueName(hr))); + } #endif VARIANT propValue; ::VariantInit(&propValue); hr = aAttrProperty->GetValue(TfEditCookie(mEditCookie), aRange, &propValue); if (FAILED(hr)) { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - (" ITfProperty::GetValue Failed\n")); + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " + "ITfProperty::GetValue() failed", this)); return hr; } if (VT_I4 != propValue.vt) { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - (" ITfProperty::GetValue returns non-VT_I4 value\n")); + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " + "ITfProperty::GetValue() returns non-VT_I4 value", this)); ::VariantClear(&propValue); return E_FAIL; } @@ -471,8 +895,9 @@ nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty, hr = sCategoryMgr->GetGUID(DWORD(propValue.lVal), &guid); ::VariantClear(&propValue); if (FAILED(hr)) { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - (" ITfCategoryMgr::GetGUID Failed\n")); + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " + "ITfCategoryMgr::GetGUID() failed", this)); return hr; } @@ -481,21 +906,23 @@ nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty, hr = sDisplayAttrMgr->GetDisplayAttributeInfo(guid, getter_AddRefs(info), NULL); if (FAILED(hr) || !info) { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - (" ITfDisplayAttributeMgr::GetDisplayAttributeInfo Failed\n")); + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " + "ITfDisplayAttributeMgr::GetDisplayAttributeInfo() failed", this)); return hr; } hr = info->GetAttributeInfo(aResult); if (FAILED(hr)) { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - (" ITfDisplayAttributeInfo::GetAttributeInfo Failed\n")); + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " + "ITfDisplayAttributeInfo::GetAttributeInfo() failed", this)); return hr; } - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: GetDisplayAttribute Result={ %s }\n", - GetLogTextFor(*aResult).get())); + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::GetDisplayAttribute() succeeded: " + "Result={ %s }", this, GetLogTextFor(*aResult).get())); return S_OK; } @@ -553,20 +980,46 @@ IsSameTextEvent(const nsTextEvent* aEvent1, const nsTextEvent* aEvent2) HRESULT nsTextStore::UpdateCompositionExtent(ITfRange* aRangeNew) { - NS_ENSURE_TRUE(mCompositionView, E_FAIL); + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::UpdateCompositionExtent(aRangeNew=0x%p), " + "mCompositionView=0x%p", this, aRangeNew, mCompositionView)); + + if (!mCompositionView) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::UpdateCompositionExtent() FAILED due to " + "no composition view", this)); + return E_FAIL; + } HRESULT hr; nsRefPtr pComposition(mCompositionView); nsRefPtr composingRange(aRangeNew); if (!composingRange) { hr = pComposition->GetRange(getter_AddRefs(composingRange)); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::UpdateCompositionExtent() FAILED due to " + "pComposition->GetRange() failure", this)); + return hr; + } } // Get starting offset of the composition LONG compStart = 0, compLength = 0; hr = GetRangeExtent(composingRange, &compStart, &compLength); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::UpdateCompositionExtent() FAILED due to " + "GetRangeExtent() failure", this)); + return hr; + } + + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::UpdateCompositionExtent(), range=%ld-%ld, " + "mCompositionStart=%ld, mCompositionString.Length()=%lu", + this, compStart, compStart + compLength, mCompositionStart, + mCompositionString.Length())); + if (mCompositionStart != compStart || mCompositionString.Length() != (ULONG)compLength) { // If the queried composition length is different from the length @@ -577,16 +1030,12 @@ nsTextStore::UpdateCompositionExtent(ITfRange* aRangeNew) // will accomplish this automagically. OnEndComposition(pComposition); OnStartCompositionInternal(pComposition, composingRange, true); - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: UpdateCompositionExtent, (reset) range=%ld-%ld\n", - compStart, compStart + compLength)); } else { mCompositionLength = compLength; - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: UpdateCompositionExtent, range=%ld-%ld\n", - compStart, compStart + compLength)); } + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::UpdateCompositionExtent() succeeded", this)); return S_OK; } @@ -637,10 +1086,18 @@ GetLineStyle(TF_DA_LINESTYLE aTSFLineStyle, uint8_t &aTextRangeLineStyle) HRESULT nsTextStore::SendTextEventForCompositionString() { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SendTextEventForCompositionString\n")); + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString(), " + "mCompositionView=0x%p, mCompositionString=\"%s\"", + this, mCompositionView, + NS_ConvertUTF16toUTF8(mCompositionString).get())); - NS_ENSURE_TRUE(mCompositionView, E_FAIL); + if (!mCompositionView) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() FAILED " + "due to no composition view", this)); + return E_FAIL; + } // Getting display attributes is *really* complicated! // We first get the context and the property objects to query for @@ -653,7 +1110,12 @@ nsTextStore::SendTextEventForCompositionString() nsRefPtr attrPropetry; HRESULT hr = mContext->GetProperty(GUID_PROP_ATTRIBUTE, getter_AddRefs(attrPropetry)); - NS_ENSURE_TRUE(SUCCEEDED(hr) && attrPropetry, hr); + if (FAILED(hr) || !attrPropetry) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() FAILED " + "due to mContext->GetProperty() failure", this)); + return FAILED(hr) ? hr : E_FAIL; + } // Use NS_TEXT_TEXT to set composition string nsTextEvent event(true, NS_TEXT_TEXT, mWindow); @@ -661,12 +1123,22 @@ nsTextStore::SendTextEventForCompositionString() nsRefPtr composingRange; hr = mCompositionView->GetRange(getter_AddRefs(composingRange)); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() FAILED " + "due to mCompositionView->GetRange() failure", this)); + return hr; + } nsRefPtr enumRanges; hr = attrPropetry->EnumRanges(TfEditCookie(mEditCookie), getter_AddRefs(enumRanges), composingRange); - NS_ENSURE_TRUE(SUCCEEDED(hr) && enumRanges, hr); + if (FAILED(hr) || !enumRanges) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() FAILED " + "due to attrPropetry->EnumRanges() failure", this)); + return FAILED(hr) ? hr : E_FAIL; + } nsAutoTArray textRanges; nsTextRange newRange; @@ -767,27 +1239,34 @@ nsTextStore::SendTextEventForCompositionString() // it can be a cause of flickering. if (IsSameTextEvent(mLastDispatchedTextEvent, &event)) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SendTextEventForCompositionString does not dispatch\n")); + ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() " + "succeeded but any DOM events are not dispatched", this)); return S_OK; } if (mCompositionString != mLastDispatchedCompositionString) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() " + "dispatching compositionupdate event...", this)); nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE, mWindow); mWindow->InitEvent(compositionUpdate); compositionUpdate.data = mCompositionString; mLastDispatchedCompositionString = mCompositionString; mWindow->DispatchWindowEvent(&compositionUpdate); - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SendTextEventForCompositionString compositionupdate " - "DISPATCHED\n")); } if (mWindow && !mWindow->Destroyed()) { - mWindow->DispatchWindowEvent(&event); PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SendTextEventForCompositionString text event DISPATCHED\n")); + ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() " + "dispatching text event...", this)); + mWindow->DispatchWindowEvent(&event); } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() " + "succeeded", this)); + return SaveTextEvent(&event); } @@ -795,23 +1274,44 @@ HRESULT nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, bool aDispatchTextEvent) { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SetSelection, sel=%ld-%ld\n", - pSelection->acpStart, pSelection->acpEnd)); + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::SetSelectionInternal(pSelection=%ld-%ld, " + "aDispatchTextEvent=%s), %s", + this, pSelection->acpStart, pSelection->acpEnd, + GetBoolName(aDispatchTextEvent), + mCompositionView ? "there is composition view" : + "there is no composition view")); + if (mCompositionView) { if (aDispatchTextEvent) { HRESULT hr = UpdateCompositionExtent(nullptr); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " + "UpdateCompositionExtent() failure", this)); + return hr; + } + } + if (pSelection->acpStart < mCompositionStart || + pSelection->acpEnd > + mCompositionStart + static_cast(mCompositionString.Length())) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " + "the selection being out of the composition string", this)); + return TS_E_INVALIDPOS; } // Emulate selection during compositions - NS_ENSURE_TRUE(pSelection->acpStart >= mCompositionStart && - pSelection->acpEnd <= mCompositionStart + - LONG(mCompositionString.Length()), TS_E_INVALIDPOS); mCompositionSelection = *pSelection; if (aDispatchTextEvent) { HRESULT hr = SendTextEventForCompositionString(); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " + "SendTextEventForCompositionString() failure", this)); + return hr; + } } + return S_OK; } else { nsSelectionEvent event(true, NS_SELECTION_SET, mWindow); event.mOffset = pSelection->acpStart; @@ -819,10 +1319,13 @@ nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, event.mReversed = pSelection->style.ase == TS_AE_START; mWindow->InitEvent(event); mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, E_FAIL); + if (!event.mSucceeded) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " + "NS_SELECTION_SET failure", this)); + return E_FAIL; + } } - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SetSelection SUCCEEDED\n")); return S_OK; } @@ -830,10 +1333,39 @@ STDMETHODIMP nsTextStore::SetSelection(ULONG ulCount, const TS_SELECTION_ACP *pSelection) { - NS_ENSURE_TRUE(TS_LF_READWRITE == (mLock & TS_LF_READWRITE), TS_E_NOLOCK); - NS_ENSURE_TRUE(1 == ulCount && pSelection, E_INVALIDARG); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::SetSelection(ulCount=%lu)", + this, ulCount)); - return SetSelectionInternal(pSelection, true); + if (!IsReadWriteLocked()) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " + "not locked (read-write)", this)); + return TS_E_NOLOCK; + } + if (ulCount != 1) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " + "trying setting multiple selection", this)); + return E_INVALIDARG; + } + if (!pSelection) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " + "null argument", this)); + return E_INVALIDARG; + } + + HRESULT hr = SetSelectionInternal(pSelection, true); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " + "SetSelectionInternal() failure", this)); + } else { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::SetSelection() succeeded", this)); + } + return hr; } STDMETHODIMP @@ -847,12 +1379,39 @@ nsTextStore::GetText(LONG acpStart, ULONG *pulRunInfoOut, LONG *pacpNext) { - NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK); - NS_ENSURE_TRUE(pcchPlainOut && (pchPlain || prgRunInfo) && - (!cchPlainReq == !pchPlain) && - (!ulRunInfoReq == !prgRunInfo), E_INVALIDARG); - NS_ENSURE_TRUE(0 <= acpStart && -1 <= acpEnd && - (-1 == acpEnd || acpStart <= acpEnd), TS_E_INVALIDPOS); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetText(acpStart=%ld, acpEnd=%ld, pchPlain=0x%p, " + "cchPlainReq=%lu, pcchPlainOut=0x%p, prgRunInfo=0x%p, ulRunInfoReq=%lu, " + "pulRunInfoOut=0x%p, pacpNext=0x%p), %s, mCompositionStart=%ld, " + "mCompositionLength=%ld, mCompositionString.Length()=%lu", + this, acpStart, acpEnd, pchPlain, cchPlainReq, pcchPlainOut, + prgRunInfo, ulRunInfoReq, pulRunInfoOut, pacpNext, + mCompositionView ? "there is composition view" : + "there is no composition view", + mCompositionStart, mCompositionLength, + mCompositionString.Length())); + + if (!IsReadLocked()) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetText() FAILED due to " + "not locked (read)", this)); + return TS_E_NOLOCK; + } + + if (!pcchPlainOut || (!pchPlain && !prgRunInfo) || + !cchPlainReq != !pchPlain || !ulRunInfoReq != !prgRunInfo) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetText() FAILED due to " + "invalid argument", this)); + return E_INVALIDARG; + } + + if (acpStart < 0 || acpEnd < -1 || (acpEnd != -1 && acpStart > acpEnd)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetText() FAILED due to " + "invalid position", this)); + return TS_E_INVALIDPOS; + } // Making sure to NULL-terminate string just to be on the safe side *pcchPlainOut = 0; @@ -891,7 +1450,12 @@ nsTextStore::GetText(LONG acpStart, mWindow->InitEvent(event); event.InitForQueryTextContent(uint32_t(acpStart), length); mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, E_FAIL); + if (!event.mSucceeded) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetText() FAILED due to " + "NS_QUERY_TEXT_CONTENT failure: length=%lu", this, length)); + return E_FAIL; + } if (compOldEnd > compNewStart || compNewEnd > compNewStart) { // Resync composition string @@ -902,8 +1466,12 @@ nsTextStore::GetText(LONG acpStart, compNewEnd - mCompositionStart); length = uint32_t(LONG(length) - compOldEnd + compNewEnd); } - NS_ENSURE_TRUE(-1 == acpEnd || event.mReply.mString.Length() == length, - TS_E_INVALIDPOS); + if (-1 != acpEnd && event.mReply.mString.Length() != length) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetText() FAILED due to " + "unexpected length=%lu", this, length)); + return TS_E_INVALIDPOS; + } length = NS_MIN(length, event.mReply.mString.Length()); if (pchPlain && cchPlainReq) { @@ -919,6 +1487,14 @@ nsTextStore::GetText(LONG acpStart, } if (pacpNext) *pacpNext = acpStart + length; } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetText() succeeded: pcchPlainOut=0x%p, " + "*prgRunInfo={ uCount=%lu, type=%s }, *pulRunInfoOut=%lu, " + "*pacpNext=%ld)", + this, pcchPlainOut, prgRunInfo ? prgRunInfo->uCount : 0, + prgRunInfo ? GetTextRunTypeName(prgRunInfo->type) : "N/A", + pulRunInfoOut ? pulRunInfoOut : 0, pacpNext ? pacpNext : 0)); return S_OK; } @@ -930,18 +1506,44 @@ nsTextStore::SetText(DWORD dwFlags, ULONG cch, TS_TEXTCHANGE *pChange) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::SetText(dwFlags=%s, acpStart=%ld, acpEnd=%ld, " + "pchText=0x%p \"%s\", cch=%lu, pChange=0x%p), %s", + this, dwFlags == TS_ST_CORRECTION ? "TS_ST_CORRECTION" : + "not-specified", + acpStart, acpEnd, pchText, + pchText && cch ? + NS_ConvertUTF16toUTF8(pchText, cch).get() : "", + cch, pChange, + mCompositionView ? "there is composition view" : + "there is no composition view")); + // Per SDK documentation, and since we don't have better // ways to do this, this method acts as a helper to // call SetSelection followed by InsertTextAtSelection - NS_ENSURE_TRUE(TS_LF_READWRITE == (mLock & TS_LF_READWRITE), TS_E_NOLOCK); + if (!IsReadWriteLocked()) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SetText() FAILED due to " + "not locked (read)", this)); + return TS_E_NOLOCK; + } + TS_SELECTION_ACP selection; selection.acpStart = acpStart; selection.acpEnd = acpEnd; selection.style.ase = TS_AE_END; selection.style.fInterimChar = 0; // Set selection to desired range - NS_ENSURE_TRUE(SUCCEEDED(SetSelectionInternal(&selection)), E_FAIL); + HRESULT hr = SetSelectionInternal(&selection); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::SetText() FAILED due to " + "SetSelectionInternal() failure", this)); + return hr; + } // Replace just selected text + // XXX We should make something like InserTextAtSelectionInternal() for + // making the log clearer if InsertTextAtSelection() is called internally. return InsertTextAtSelection(TS_IAS_NOQUERY, pchText, cch, NULL, NULL, pChange); } @@ -951,6 +1553,10 @@ nsTextStore::GetFormattedText(LONG acpStart, LONG acpEnd, IDataObject **ppDataObject) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetFormattedText() called " + "but not supported (E_NOTIMPL)", this)); + // no support for formatted text return E_NOTIMPL; } @@ -961,6 +1567,10 @@ nsTextStore::GetEmbedded(LONG acpPos, REFIID riid, IUnknown **ppunk) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetEmbedded() called " + "but not supported (E_NOTIMPL)", this)); + // embedded objects are not supported return E_NOTIMPL; } @@ -970,6 +1580,10 @@ nsTextStore::QueryInsertEmbedded(const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::QueryInsertEmbedded() called " + "but not supported, *pfInsertable=FALSE (S_OK)", this)); + // embedded objects are not supported *pfInsertable = FALSE; return S_OK; @@ -982,6 +1596,10 @@ nsTextStore::InsertEmbedded(DWORD dwFlags, IDataObject *pDataObject, TS_TEXTCHANGE *pChange) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::InsertEmbedded() called " + "but not supported (E_NOTIMPL)", this)); + // embedded objects are not supported return E_NOTIMPL; } @@ -991,6 +1609,10 @@ nsTextStore::RequestSupportedAttrs(DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::RequestSupportedAttrs() called " + "but not supported (S_OK)", this)); + // no attributes defined return S_OK; } @@ -1001,6 +1623,10 @@ nsTextStore::RequestAttrsAtPosition(LONG acpPos, const TS_ATTRID *paFilterAttrs, DWORD dwFlags) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::RequestAttrsAtPosition() called " + "but not supported (S_OK)", this)); + // no per character attributes defined return S_OK; } @@ -1011,6 +1637,10 @@ nsTextStore::RequestAttrsTransitioningAtPosition(LONG acpPos, const TS_ATTRID *paFilterAttr, DWORD dwFlags) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::RequestAttrsTransitioningAtPosition() called " + "but not supported (S_OK)", this)); + // no per character attributes defined return S_OK; } @@ -1025,7 +1655,17 @@ nsTextStore::FindNextAttrTransition(LONG acpStart, BOOL *pfFound, LONG *plFoundOffset) { - NS_ENSURE_TRUE(pacpNext && pfFound && plFoundOffset, E_INVALIDARG); + if (!pacpNext || !pfFound || !plFoundOffset) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::FindNextAttrTransition() FAILED due to " + "null argument", this)); + return E_INVALIDARG; + } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::FindNextAttrTransition() called " + "but not supported (S_OK)", this)); + // no per character attributes defined *pacpNext = *plFoundOffset = acpHalt; *pfFound = FALSE; @@ -1037,7 +1677,17 @@ nsTextStore::RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched) { - NS_ENSURE_TRUE(pcFetched && ulCount && paAttrVals, E_INVALIDARG); + if (!pcFetched || !ulCount || !paAttrVals) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() FAILED due to " + "null argument", this)); + return E_INVALIDARG; + } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() called " + "but not supported, *pcFetched=0 (S_OK)", this)); + // no attributes defined *pcFetched = 0; return S_OK; @@ -1046,15 +1696,35 @@ nsTextStore::RetrieveRequestedAttrs(ULONG ulCount, STDMETHODIMP nsTextStore::GetEndACP(LONG *pacp) { - NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK); - NS_ENSURE_TRUE(pacp, E_INVALIDARG); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetEndACP(pacp=0x%p)", this, pacp)); + + if (!IsReadLocked()) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetEndACP() FAILED due to " + "not locked (read)", this)); + return TS_E_NOLOCK; + } + + if (!pacp) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetEndACP() FAILED due to " + "null argument", this)); + return E_INVALIDARG; + } + // Flattened text is retrieved and its length returned nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, mWindow); mWindow->InitEvent(event); // Return entire text event.InitForQueryTextContent(0, PR_INT32_MAX); mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, E_FAIL); + if (!event.mSucceeded) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetEndACP() FAILED due to " + "NS_QUERY_TEXT_CONTENT failure", this)); + return E_FAIL; + } *pacp = LONG(event.mReply.mString.Length()); return S_OK; } @@ -1064,8 +1734,21 @@ nsTextStore::GetEndACP(LONG *pacp) STDMETHODIMP nsTextStore::GetActiveView(TsViewCookie *pvcView) { - NS_ENSURE_TRUE(pvcView, E_INVALIDARG); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetActiveView(pvcView=0x%p)", this, pvcView)); + + if (!pvcView) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetActiveView() FAILED due to " + "null argument", this)); + return E_INVALIDARG; + } + *pvcView = TEXTSTORE_DEFAULT_VIEW; + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetActiveView() succeeded: *pvcView=%ld", + this, *pvcView)); return S_OK; } @@ -1075,8 +1758,25 @@ nsTextStore::GetACPFromPoint(TsViewCookie vcView, DWORD dwFlags, LONG *pacp) { - NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK); - NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView, E_INVALIDARG); + if (!IsReadLocked()) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " + "not locked (read)", this)); + return TS_E_NOLOCK; + } + + if (vcView != TEXTSTORE_DEFAULT_VIEW) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " + "called with invalid view", this)); + return E_INVALIDARG; + } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetACPFromPoint(vcView=%ld, " + "pt(0x%p)={ x=%ld, y=%ld }, dwFlags=%s, pacp=0x%p) called " + "but not supported (E_NOTIMPL)", this)); + // not supported for now return E_NOTIMPL; } @@ -1088,17 +1788,50 @@ nsTextStore::GetTextExt(TsViewCookie vcView, RECT *prc, BOOL *pfClipped) { - NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK); - NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView && prc && pfClipped, - E_INVALIDARG); - NS_ENSURE_TRUE(acpStart >= 0 && acpEnd >= acpStart, TS_E_INVALIDPOS); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetTextExt(vcView=%ld, " + "acpStart=%ld, acpEnd=%ld, prc=0x%p, pfClipped=0x%p)", + this, vcView, acpStart, acpEnd, prc, pfClipped)); + + if (!IsReadLocked()) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + "not locked (read)", this)); + return TS_E_NOLOCK; + } + + if (vcView != TEXTSTORE_DEFAULT_VIEW) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + "called with invalid view", this)); + return E_INVALIDARG; + } + + if (!prc || !pfClipped) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + "null argument", this)); + return E_INVALIDARG; + } + + if (acpStart < 0 || acpEnd < acpStart) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + "invalid position", this)); + return TS_E_INVALIDPOS; + } // use NS_QUERY_TEXT_RECT to get rect in system, screen coordinates nsQueryContentEvent event(true, NS_QUERY_TEXT_RECT, mWindow); mWindow->InitEvent(event); event.InitForQueryTextRect(acpStart, acpEnd - acpStart); mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, TS_E_INVALIDPOS); + if (!event.mSucceeded) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + "NS_QUERY_TEXT_RECT failure", this)); + return TS_E_INVALIDPOS; // but unexpected failure, maybe. + } // IMEs don't like empty rects, fix here if (event.mReply.mRect.width <= 0) event.mReply.mRect.width = 1; @@ -1110,13 +1843,22 @@ nsTextStore::GetTextExt(TsViewCookie vcView, event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWindow); // Result rect is in top level widget coordinates refWindow = refWindow->GetTopLevelWindow(false); - NS_ENSURE_TRUE(refWindow, E_FAIL); + if (!refWindow) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + "no top level window", this)); + return E_FAIL; + } event.mReply.mRect.MoveBy(refWindow->WidgetToScreenOffset()); // get bounding screen rect to test for clipping - HRESULT hr = GetScreenExt(vcView, prc); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + if (!GetScreenExtInternal(*prc)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + "GetScreenExtInternal() failure", this)); + return E_FAIL; + } // clip text rect to bounding rect RECT textRect; @@ -1128,6 +1870,13 @@ nsTextStore::GetTextExt(TsViewCookie vcView, // not equal if text rect was clipped *pfClipped = !::EqualRect(prc, &textRect); + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetTextExt() succeeded: " + "*prc={ left=%ld, top=%ld, right=%ld, bottom=%ld }, *pfClipped=%s", + this, prc->left, prc->top, prc->right, prc->bottom, + GetBoolName(*pfClipped))); + return S_OK; } @@ -1135,22 +1884,73 @@ STDMETHODIMP nsTextStore::GetScreenExt(TsViewCookie vcView, RECT *prc) { - NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView && prc, E_INVALIDARG); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetScreenExt(vcView=%ld, prc=0x%p)", + this, vcView, prc)); + + if (vcView != TEXTSTORE_DEFAULT_VIEW) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " + "called with invalid view", this)); + return E_INVALIDARG; + } + + if (!prc) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " + "null argument", this)); + return E_INVALIDARG; + } + + if (!GetScreenExtInternal(*prc)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " + "GetScreenExtInternal() failure", this)); + return E_FAIL; + } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetScreenExt() succeeded: " + "*prc={ left=%ld, top=%ld, right=%ld, bottom=%ld }", + this, prc->left, prc->top, prc->right, prc->bottom)); + return S_OK; +} + +bool +nsTextStore::GetScreenExtInternal(RECT &aScreenExt) +{ + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::GetScreenExtInternal()", this)); + // use NS_QUERY_EDITOR_RECT to get rect in system, screen coordinates nsQueryContentEvent event(true, NS_QUERY_EDITOR_RECT, mWindow); mWindow->InitEvent(event); mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, E_FAIL); + if (!event.mSucceeded) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " + "NS_QUERY_EDITOR_RECT failure", this)); + return false; + } nsWindow* refWindow = static_cast( event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWindow); // Result rect is in top level widget coordinates refWindow = refWindow->GetTopLevelWindow(false); - NS_ENSURE_TRUE(refWindow, E_FAIL); + if (!refWindow) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " + "no top level window", this)); + return false; + } nsIntRect boundRect; - nsresult rv = refWindow->GetClientBounds(boundRect); - NS_ENSURE_SUCCESS(rv, E_FAIL); + if (NS_FAILED(refWindow->GetClientBounds(boundRect))) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " + "failed to get the client bounds", this)); + return false; + } boundRect.MoveTo(0, 0); @@ -1158,20 +1958,47 @@ nsTextStore::GetScreenExt(TsViewCookie vcView, boundRect.IntersectRect(event.mReply.mRect, boundRect); if (!boundRect.IsEmpty()) { boundRect.MoveBy(refWindow->WidgetToScreenOffset()); - ::SetRect(prc, boundRect.x, boundRect.y, + ::SetRect(&aScreenExt, boundRect.x, boundRect.y, boundRect.XMost(), boundRect.YMost()); } else { - ::SetRectEmpty(prc); + ::SetRectEmpty(&aScreenExt); } - return S_OK; + + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() succeeded: " + "aScreenExt={ left=%ld, top=%ld, right=%ld, bottom=%ld }", + this, aScreenExt.left, aScreenExt.top, + aScreenExt.right, aScreenExt.bottom)); + return true; } STDMETHODIMP nsTextStore::GetWnd(TsViewCookie vcView, HWND *phwnd) { - NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView && phwnd, E_INVALIDARG); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetWnd(vcView=%ld, phwnd=0x%p), mWindow=0x%p", + this, vcView, phwnd, mWindow)); + + if (vcView != TEXTSTORE_DEFAULT_VIEW) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetWnd() FAILED due to " + "called with invalid view", this)); + return E_INVALIDARG; + } + + if (!phwnd) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " + "null argument", this)); + return E_INVALIDARG; + } + *phwnd = mWindow->GetWindowHandle(); + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::GetWnd() succeeded: *phwnd=0x%p", + this, static_cast(*phwnd))); return S_OK; } @@ -1184,17 +2011,48 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, TS_TEXTCHANGE *pChange) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: InsertTextAtSelection, cch=%lu\n", cch)); - NS_ENSURE_TRUE(TS_LF_READWRITE == (mLock & TS_LF_READWRITE), TS_E_NOLOCK); - NS_ENSURE_TRUE(!cch || pchText, E_INVALIDARG); + ("TSF: 0x%p nsTextStore::InsertTextAtSelection(dwFlags=%s, " + "pchText=0x%p \"%s\", cch=%lu, pacpStart=0x%p, pacpEnd=0x%p, " + "pChange=0x%p), %s", + this, dwFlags == 0 ? "0" : + dwFlags == TF_IAS_NOQUERY ? "TF_IAS_NOQUERY" : + dwFlags == TF_IAS_QUERYONLY ? "TF_IAS_QUERYONLY" : "Unknown", + pchText, + pchText && cch ? NS_ConvertUTF16toUTF8(pchText, cch).get() : "", + cch, pacpStart, pacpEnd, pChange, + mCompositionView ? "there is composition view" : + "there is no composition view")); + + if (!IsReadWriteLocked()) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + "not locked (read)", this)); + return TS_E_NOLOCK; + } + + if (cch && !pchText) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + "null pchText", this)); + return E_INVALIDARG; + } // Get selection first TS_SELECTION_ACP sel; - ULONG selFetched; - NS_ENSURE_TRUE(SUCCEEDED(GetSelection( - TS_DEFAULT_SELECTION, 1, &sel, &selFetched)) && selFetched, E_FAIL); + if (!GetSelectionInternal(sel)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + "GetSelectionInternal() failure", this)); + return E_FAIL; + } + if (TS_IAS_QUERYONLY == dwFlags) { - NS_ENSURE_TRUE(pacpStart && pacpEnd, E_INVALIDARG); + if (!pacpStart || !pacpEnd) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + "null argument", this)); + return E_INVALIDARG; + } // Simulate text insertion *pacpStart = sel.acpStart; *pacpEnd = sel.acpEnd; @@ -1204,9 +2062,19 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, pChange->acpNewEnd = sel.acpStart + cch; } } else { - NS_ENSURE_TRUE(pChange, E_INVALIDARG); - NS_ENSURE_TRUE(TS_IAS_NOQUERY == dwFlags || (pacpStart && pacpEnd), - E_INVALIDARG); + if (!pChange) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + "null pChange", this)); + return E_INVALIDARG; + } + if (TS_IAS_NOQUERY != dwFlags && (!pacpStart || !pacpEnd)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + "null argument", this)); + return E_INVALIDARG; + } + if (mCompositionView) { // Emulate text insertion during compositions, because during a // composition, editor expects the whole composition string to @@ -1220,19 +2088,30 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, mCompositionSelection.acpEnd = mCompositionSelection.acpStart; mCompositionSelection.style.ase = TS_AE_END; PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: InsertTextAtSelection, replaced=%lu-%lu\n", + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() replaced a " + "part of (%lu-%lu) the composition string, waiting " + "SetSelection() or OnUpdateComposition()...", this, sel.acpStart - mCompositionStart, sel.acpEnd - mCompositionStart)); } else { // Use a temporary composition to contain the text + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() dispatching " + "a compositionstart event...", this)); nsCompositionEvent compEvent(true, NS_COMPOSITION_START, mWindow); mWindow->InitEvent(compEvent); mWindow->DispatchWindowEvent(&compEvent); if (mWindow && !mWindow->Destroyed()) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() dispatching " + "a compositionupdate event...", this)); compEvent.message = NS_COMPOSITION_UPDATE; compEvent.data.Assign(pchText, cch); mWindow->DispatchWindowEvent(&compEvent); if (mWindow && !mWindow->Destroyed()) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() " + "dispatching a text event...", this)); nsTextEvent event(true, NS_TEXT_TEXT, mWindow); mWindow->InitEvent(event); event.theText.Assign(pchText, cch); @@ -1240,6 +2119,9 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, NS_LITERAL_STRING("\n")); mWindow->DispatchWindowEvent(&event); if (mWindow && !mWindow->Destroyed()) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() " + "dispatching a compositionend event...", this)); compEvent.message = NS_COMPOSITION_END; mWindow->DispatchWindowEvent(&compEvent); } @@ -1249,8 +2131,12 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, pChange->acpStart = sel.acpStart; pChange->acpOldEnd = sel.acpEnd; // Get new selection - NS_ENSURE_TRUE(SUCCEEDED(GetSelection( - TS_DEFAULT_SELECTION, 1, &sel, &selFetched)) && selFetched, E_FAIL); + if (!GetSelectionInternal(sel)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + "GetSelectionInternal() failure after inserted the text", this)); + return E_FAIL; + } pChange->acpNewEnd = sel.acpEnd; if (TS_IAS_NOQUERY != dwFlags) { *pacpStart = pChange->acpStart; @@ -1258,7 +2144,12 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, } } PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: InsertTextAtSelection SUCCEEDED\n")); + ("TSF: 0x%p nsTextStore::InsertTextAtSelection() succeeded: " + "*pacpStart=%ld, *pacpEnd=%ld, " + "*pChange={ acpStart=%ld, acpOldEnd=%ld, acpNewEnd=%ld })", + this, pacpStart ? *pacpStart : 0, pacpEnd ? *pacpEnd : 0, + pChange ? pChange->acpStart: 0, pChange ? pChange->acpOldEnd : 0, + pChange ? pChange->acpNewEnd : 0)); return S_OK; } @@ -1269,6 +2160,10 @@ nsTextStore::InsertEmbeddedAtSelection(DWORD dwFlags, LONG *pacpEnd, TS_TEXTCHANGE *pChange) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::InsertEmbeddedAtSelection() called " + "but not supported (E_NOTIMPL)", this)); + // embedded objects are not supported return E_NOTIMPL; } @@ -1278,13 +2173,30 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition, ITfRange* aRange, bool aPreserveSelection) { + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::OnStartCompositionInternal(" + "pComposition=0x%p, aRange=0x%p, aPreserveSelection=%s), " + "mCompositionView=0x%p", + this, pComposition, aRange, GetBoolName(aPreserveSelection), + mCompositionView)); + mCompositionView = pComposition; HRESULT hr = GetRangeExtent(aRange, &mCompositionStart, &mCompositionLength); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnStartCompositionInternal() FAILED due " + "to GetRangeExtent() failure", this)); + return hr; + } - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: OnStartComposition, range=%ld-%ld\n", mCompositionStart, - mCompositionStart + mCompositionLength)); + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::OnStartCompositionInternal(), " + "mCompositionStart=%ld, mCompositionLength=%ld", + this, mCompositionStart, mCompositionLength)); + + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::OnStartCompositionInternal(), " + "dispatching selectionset event...")); // Select composition range so the new composition replaces the range nsSelectionEvent selEvent(true, NS_SELECTION_SET, mWindow); @@ -1293,13 +2205,28 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition, selEvent.mLength = uint32_t(mCompositionLength); selEvent.mReversed = false; mWindow->DispatchWindowEvent(&selEvent); - NS_ENSURE_TRUE(selEvent.mSucceeded, E_FAIL); + if (!selEvent.mSucceeded) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnStartCompositionInternal() FAILED due " + "to NS_SELECTION_SET failure", this)); + return E_FAIL; + } // Set up composition nsQueryContentEvent queryEvent(true, NS_QUERY_SELECTED_TEXT, mWindow); mWindow->InitEvent(queryEvent); mWindow->DispatchWindowEvent(&queryEvent); - NS_ENSURE_TRUE(queryEvent.mSucceeded, E_FAIL); + if (!queryEvent.mSucceeded) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnStartCompositionInternal() FAILED due " + "to NS_QUERY_SELECTED_TEXT failure", this)); + return E_FAIL; + } + + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::OnStartCompositionInternal(), " + "dispatching compositionstart event...")); + mCompositionString = queryEvent.mReply.mString; if (!aPreserveSelection) { mCompositionSelection.acpStart = mCompositionStart; @@ -1310,6 +2237,16 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition, nsCompositionEvent event(true, NS_COMPOSITION_START, mWindow); mWindow->InitEvent(event); mWindow->DispatchWindowEvent(&event); + + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::OnStartCompositionInternal() succeeded: " + "mCompositionStart=%ld, mCompositionLength=%ld, " + "mCompositionSelection={ acpStart=%ld, acpEnd=%ld, style.ase=%s, " + "style.iInterimChar=%s }", + this, mCompositionStart, mCompositionLength, + mCompositionSelection.acpStart, mCompositionSelection.acpEnd, + GetActiveSelEndName(mCompositionSelection.style.ase), + GetBoolName(mCompositionSelection.style.fInterimChar))); return S_OK; } @@ -1329,18 +2266,36 @@ STDMETHODIMP nsTextStore::OnStartComposition(ITfCompositionView* pComposition, BOOL* pfOk) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnStartComposition(pComposition=0x%p, " + "pfOk=0x%p), mCompositionView=0x%p", + this, pComposition, pfOk, mCompositionView)); + *pfOk = FALSE; // Only one composition at a time - if (mCompositionView) + if (mCompositionView) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnStartComposition() FAILED due to " + "there is another composition already (but returns S_OK)", this)); return S_OK; + } nsRefPtr range; HRESULT hr = pComposition->GetRange(getter_AddRefs(range)); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - hr = OnStartCompositionInternal(pComposition, range, false); - if (FAILED(hr)) + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnStartComposition() FAILED due to " + "pComposition->GetRange() failure", this)); return hr; + } + hr = OnStartCompositionInternal(pComposition, range, false); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnStartComposition() FAILED due to " + "OnStartCompositionInternal() failure", this)); + return hr; + } NS_ASSERTION(!mCompositionTimer, "The timer is alive!"); mCompositionTimer = do_CreateInstance(NS_TIMER_CONTRACTID); @@ -1350,6 +2305,8 @@ nsTextStore::OnStartComposition(ITfCompositionView* pComposition, nsITimer::TYPE_REPEATING_SLACK); } *pfOk = TRUE; + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnStartComposition() succeeded", this)); return S_OK; } @@ -1357,26 +2314,89 @@ STDMETHODIMP nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition, ITfRange* pRangeNew) { - NS_ENSURE_TRUE(mCompositionView && - mCompositionView == pComposition && - mDocumentMgr && mContext, E_UNEXPECTED); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnUpdateComposition(pComposition=0x%p, " + "pRangeNew=0x%p), mCompositionView=0x%p", + this, pComposition, pRangeNew, mCompositionView)); - if (!pRangeNew) // pRangeNew is null when the update is not complete + if (!mDocumentMgr || !mContext) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " + "not ready for the composition", this)); + return E_UNEXPECTED; + } + if (!mCompositionView) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " + "no active composition", this)); + return E_UNEXPECTED; + } + if (mCompositionView != pComposition) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " + "different composition view specified", this)); + return E_UNEXPECTED; + } + + // pRangeNew is null when the update is not complete + if (!pRangeNew) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnUpdateComposition() succeeded but " + "not complete", this)); return S_OK; + } HRESULT hr = UpdateCompositionExtent(pRangeNew); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " + "UpdateCompositionExtent() failure", this)); + return hr; + } - return SendTextEventForCompositionString(); + hr = SendTextEventForCompositionString(); + if (FAILED(hr)) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " + "SendTextEventForCompositionString() failure", this)); + return hr; + } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnUpdateComposition() succeeded: " + "mCompositionStart=%ld, mCompositionLength=%ld, " + "mCompositionSelection={ acpStart=%ld, acpEnd=%ld, style.ase=%s, " + "style.iInterimChar=%s }, mCompositionString=\"%s\"", + this, mCompositionStart, mCompositionLength, + mCompositionSelection.acpStart, mCompositionSelection.acpEnd, + GetActiveSelEndName(mCompositionSelection.style.ase), + GetBoolName(mCompositionSelection.style.fInterimChar), + NS_ConvertUTF16toUTF8(mCompositionString).get())); + return S_OK; } STDMETHODIMP nsTextStore::OnEndComposition(ITfCompositionView* pComposition) { - NS_ENSURE_TRUE(mCompositionView && - mCompositionView == pComposition, E_UNEXPECTED); PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: OnEndComposition\n")); + ("TSF: 0x%p nsTextStore::OnEndComposition(pComposition=0x%p), " + "mCompositionView=0x%p, mCompositionString=\"%s\"", + this, pComposition, mCompositionView, + NS_ConvertUTF16toUTF8(mCompositionString).get())); + + if (!mCompositionView) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to " + "no active composition", this)); + return E_UNEXPECTED; + } + + if (mCompositionView != pComposition) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to " + "different composition view specified", this)); + return E_UNEXPECTED; + } // Clear the saved text event SaveTextEvent(nullptr); @@ -1387,6 +2407,9 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition) } if (mCompositionString != mLastDispatchedCompositionString) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnEndComposition(), " + "dispatching compositionupdate event...", this)); nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE, mWindow); mWindow->InitEvent(compositionUpdate); @@ -1395,11 +2418,16 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition) mWindow->DispatchWindowEvent(&compositionUpdate); if (!mWindow || mWindow->Destroyed()) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: CompositionUpdate caused aborting compositionend\n")); + ("TSF: 0x%p nsTextStore::OnEndComposition(), " + "succeeded, but the widget has gone", this)); return S_OK; } } + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnEndComposition(), " + "dispatching text event...", this)); + // Use NS_TEXT_TEXT to commit composition string nsTextEvent textEvent(true, NS_TEXT_TEXT, mWindow); mWindow->InitEvent(textEvent); @@ -1410,29 +2438,51 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition) if (!mWindow || mWindow->Destroyed()) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: Text event caused aborting compositionend\n")); + ("TSF: 0x%p nsTextStore::OnEndComposition(), " + "succeeded, but the widget has gone", this)); return S_OK; } + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnEndComposition(), " + "dispatching compositionend event...", this)); + nsCompositionEvent event(true, NS_COMPOSITION_END, mWindow); event.data = mLastDispatchedCompositionString; mWindow->InitEvent(event); mWindow->DispatchWindowEvent(&event); + if (!mWindow || mWindow->Destroyed()) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnEndComposition(), " + "succeeded, but the widget has gone", this)); + return S_OK; + } + mCompositionView = NULL; mCompositionString.Truncate(0); mLastDispatchedCompositionString.Truncate(); // Maintain selection SetSelectionInternal(&mCompositionSelection); + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnEndComposition(), succeeded", this)); return S_OK; } +// static nsresult nsTextStore::OnFocusChange(bool aFocus, nsWindow* aWindow, IMEState::Enabled aIMEEnabled) { + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: nsTextStore::OnFocusChange(aFocus=%s, aWindow=0x%p, " + "aIMEEnabled=%s), sTsfThreadMgr=0x%p, sTsfTextStore=0x%p", + GetBoolName(aFocus), aWindow, GetIMEEnabledName(aIMEEnabled), + sTsfThreadMgr, sTsfTextStore)); + // no change notifications if TSF is disabled if (!sTsfThreadMgr || !sTsfTextStore) return NS_ERROR_NOT_AVAILABLE; @@ -1454,6 +2504,14 @@ nsTextStore::OnTextChangeInternal(uint32_t aStart, uint32_t aOldEnd, uint32_t aNewEnd) { + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::OnTextChangeInternal(aStart=%lu, " + "aOldEnd=%lu, aNewEnd=%lu), mLock=%s, mSink=0x%p, mSinkMask=%s, " + "mTextChange={ acpStart=%ld, acpOldEnd=%ld, acpNewEnd=%ld }", + this, aStart, aOldEnd, aNewEnd, GetLockFlagNameStr(mLock).get(), + mSink, GetSinkMaskNameStr(mSinkMask).get(), mTextChange.acpStart, + mTextChange.acpOldEnd, mTextChange.acpNewEnd)); + if (!mLock && mSink && 0 != (mSinkMask & TS_AS_TEXT_CHANGE)) { mTextChange.acpStart = NS_MIN(mTextChange.acpStart, LONG(aStart)); mTextChange.acpOldEnd = NS_MAX(mTextChange.acpOldEnd, LONG(aOldEnd)); @@ -1467,8 +2525,21 @@ nsTextStore::OnTextChangeInternal(uint32_t aStart, void nsTextStore::OnTextChangeMsgInternal(void) { + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::OnTextChangeMsgInternal(), mLock=%s, " + "mSink=0x%p, mSinkMask=%s, mTextChange={ acpStart=%ld, " + "acpOldEnd=%ld, acpNewEnd=%ld }", + this, GetLockFlagNameStr(mLock).get(), mSink, + GetSinkMaskNameStr(mSinkMask).get(), mTextChange.acpStart, + mTextChange.acpOldEnd, mTextChange.acpNewEnd)); + if (!mLock && mSink && 0 != (mSinkMask & TS_AS_TEXT_CHANGE) && PR_INT32_MAX > mTextChange.acpStart) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnTextChangeMsgInternal(), calling" + "mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, " + "acpNewEnd=%ld })...", this, mTextChange.acpStart, + mTextChange.acpOldEnd, mTextChange.acpNewEnd)); mSink->OnTextChange(0, &mTextChange); mTextChange.acpStart = PR_INT32_MAX; mTextChange.acpOldEnd = mTextChange.acpNewEnd = 0; @@ -1478,7 +2549,16 @@ nsTextStore::OnTextChangeMsgInternal(void) nsresult nsTextStore::OnSelectionChangeInternal(void) { + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), mLock=%s, " + "mSink=0x%p, mSinkMask=%s", + this, GetLockFlagNameStr(mLock).get(), mSink, + GetSinkMaskNameStr(mSinkMask).get())); + if (!mLock && mSink && 0 != (mSinkMask & TS_AS_SEL_CHANGE)) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), calling " + "mSink->OnSelectionChange()...", this)); mSink->OnSelectionChange(); } return NS_OK; @@ -1494,6 +2574,9 @@ nsTextStore::OnCompositionTimer() // power when the focused editor has very long text. Ideally, we should call // this only when the composition string screen position is changed by window // moving, resizing. And also reflowing and scrolling the contents. + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::OnCompositionTimer(), calling " + "mSink->OnLayoutChange()...", this)); HRESULT hr = mSink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); @@ -1503,6 +2586,14 @@ nsTextStore::OnCompositionTimer() void nsTextStore::CommitCompositionInternal(bool aDiscard) { + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::CommitCompositionInternal(aDiscard=%s), " + "mLock=%s, mSink=0x%p, mContext=0x%p, mCompositionView=0x%p, " + "mCompositionString=\"%s\"", + this, GetBoolName(aDiscard), GetLockFlagNameStr(mLock).get(), mSink, + mContext, mCompositionView, + NS_ConvertUTF16toUTF8(mCompositionString))); + if (mCompositionView && aDiscard) { mCompositionString.Truncate(0); if (mSink && !mLock) { @@ -1510,6 +2601,11 @@ nsTextStore::CommitCompositionInternal(bool aDiscard) textChange.acpStart = mCompositionStart; textChange.acpOldEnd = mCompositionStart + mCompositionLength; textChange.acpNewEnd = mCompositionStart; + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: 0x%p nsTextStore::CommitCompositionInternal(), calling" + "mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, " + "acpNewEnd=%ld })...", this, textChange.acpStart, + textChange.acpOldEnd, textChange.acpNewEnd)); mSink->OnTextChange(0, &textChange); } } @@ -1521,8 +2617,13 @@ nsTextStore::CommitCompositionInternal(bool aDiscard) nsRefPtr services; context->QueryInterface(IID_ITfContextOwnerCompositionServices, getter_AddRefs(services)); - if (services) + if (services) { + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::CommitCompositionInternal(), " + "requesting TerminateComposition() for the context 0x%p...", + this, context)); services->TerminateComposition(NULL); + } } if (context != mContext) break; @@ -1547,24 +2648,34 @@ GetCompartment(IUnknown* pUnk, (*aCompartment) != NULL; } +// static void nsTextStore::SetIMEOpenState(bool aState) { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SetIMEOpenState, state=%lu\n", aState)); + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: nsTextStore::SetIMEOpenState(aState=%s)", GetBoolName(aState))); nsRefPtr comp; if (!GetCompartment(sTsfThreadMgr, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, - getter_AddRefs(comp))) + getter_AddRefs(comp))) { + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: nsTextStore::SetIMEOpenState() FAILED due to" + "no compartment available")); return; + } VARIANT variant; variant.vt = VT_I4; variant.lVal = aState; + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: nsTextStore::SetIMEOpenState(), setting " + "0x%04X to GUID_COMPARTMENT_KEYBOARD_OPENCLOSE...", + variant.lVal)); comp->SetValue(sTsfClientId, &variant); } +// static bool nsTextStore::GetIMEOpenState(void) { @@ -1586,8 +2697,10 @@ nsTextStore::GetIMEOpenState(void) void nsTextStore::SetInputContextInternal(IMEState::Enabled aState) { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SetInputContext, state=%ld\n", static_cast(aState))); + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::SetInputContextInternal(aState=%s), " + "mContext=0x%p", + this, GetIMEEnabledName(aState), mContext)); VARIANT variant; variant.vt = VT_I4; @@ -1599,8 +2712,13 @@ nsTextStore::SetInputContextInternal(IMEState::Enabled aState) nsRefPtr comp; do { if (GetCompartment(context, GUID_COMPARTMENT_KEYBOARD_DISABLED, - getter_AddRefs(comp))) + getter_AddRefs(comp))) { + PR_LOG(sTextStoreLog, PR_LOG_DEBUG, + ("TSF: 0x%p nsTextStore::SetInputContextInternal(), setting " + "0x%04X to GUID_COMPARTMENT_KEYBOARD_DISABLED of context 0x%p...", + this, variant.lVal, context)); comp->SetValue(sTsfClientId, &variant); + } if (context != mContext) break; @@ -1609,62 +2727,106 @@ nsTextStore::SetInputContextInternal(IMEState::Enabled aState) } while (context != mContext); } +// static void nsTextStore::Initialize(void) { #ifdef PR_LOGGING - if (!sTextStoreLog) + if (!sTextStoreLog) { sTextStoreLog = PR_NewLogModule("nsTextStoreWidgets"); + } #endif + + bool enableTsf = Preferences::GetBool("intl.enable_tsf_support", false); + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: nsTextStore::Initialize(), TSF is %s", + enableTsf ? "enabled" : "disabled")); + if (!enableTsf) { + return; + } + if (!sTsfThreadMgr) { - bool enableTsf = - Preferences::GetBool("intl.enable_tsf_support", false); - if (enableTsf) { - if (SUCCEEDED(CoCreateInstance(CLSID_TF_ThreadMgr, NULL, - CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, - reinterpret_cast(&sTsfThreadMgr)))) { - if (FAILED(sTsfThreadMgr->Activate(&sTsfClientId))) { - NS_RELEASE(sTsfThreadMgr); - NS_WARNING("failed to activate TSF\n"); - } - } else - // TSF not installed? - NS_WARNING("failed to create TSF manager\n"); + if (SUCCEEDED(CoCreateInstance(CLSID_TF_ThreadMgr, NULL, + CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, + reinterpret_cast(&sTsfThreadMgr)))) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: nsTextStore::Initialize() succeeded to " + "create the thread manager, activating...")); + if (FAILED(sTsfThreadMgr->Activate(&sTsfClientId))) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: nsTextStore::Initialize() FAILED to activate, " + "releasing the thread manager...")); + NS_RELEASE(sTsfThreadMgr); + } } +#ifdef PR_LOGGING + else { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: nsTextStore::Initialize() FAILED to " + "create the thread manager")); + } +#endif // #ifdef PR_LOGGING } if (sTsfThreadMgr && !sTsfTextStore) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: nsTextStore::Initialize() is creating " + "an nsTextStore instance...")); sTsfTextStore = new nsTextStore(); - if (!sTsfTextStore) - NS_ERROR("failed to create text store"); } if (sTsfThreadMgr && !sDisplayAttrMgr) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: nsTextStore::Initialize() is creating " + "a display attribute manager instance...")); HRESULT hr = ::CoCreateInstance(CLSID_TF_DisplayAttributeMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfDisplayAttributeMgr, reinterpret_cast(&sDisplayAttrMgr)); - if (FAILED(hr) || !sDisplayAttrMgr) - NS_ERROR("failed to create display attribute manager"); + if (FAILED(hr) || !sDisplayAttrMgr) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: nsTextStore::Initialize() FAILED to create " + "a display attribute manager instance")); + } } - if (sTsfThreadMgr && !sCategoryMgr) { + if (sTsfThreadMgr && sDisplayAttrMgr && !sCategoryMgr) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: nsTextStore::Initialize() is creating " + "a category manager instance...")); HRESULT hr = ::CoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfCategoryMgr, reinterpret_cast(&sCategoryMgr)); - if (FAILED(hr) || !sCategoryMgr) - NS_ERROR("failed to create category manager"); + if (FAILED(hr) || !sCategoryMgr) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: nsTextStore::Initialize() FAILED to create " + "a category manager instance")); + // release the display manager because it cannot work without the + // category manager + NS_RELEASE(sDisplayAttrMgr); + } } if (sTsfThreadMgr && !sFlushTIPInputMessage) { sFlushTIPInputMessage = ::RegisterWindowMessageW( NS_LITERAL_STRING("Flush TIP Input Message").get()); } + + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, + ("TSF: nsTextStore::Initialize(), sTsfThreadMgr=0x%p, " + "sTsfClientId=0x%08X, sTsfTextStore=0x%p, sDisplayAttrMgr=0x%p, " + "sCategoryMgr=0x%p", + sTsfThreadMgr, sTsfClientId, sTsfTextStore, + sDisplayAttrMgr, sCategoryMgr)); } +// static void nsTextStore::Terminate(void) { + PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: nsTextStore::Terminate()")); + NS_IF_RELEASE(sDisplayAttrMgr); NS_IF_RELEASE(sCategoryMgr); NS_IF_RELEASE(sTsfTextStore); + sTsfClientId = 0; if (sTsfThreadMgr) { sTsfThreadMgr->Deactivate(); NS_RELEASE(sTsfThreadMgr); diff --git a/widget/windows/nsTextStore.h b/widget/windows/nsTextStore.h index a7c2b486fefc..cedcfbb20328 100644 --- a/widget/windows/nsTextStore.h +++ b/widget/windows/nsTextStore.h @@ -155,6 +155,19 @@ protected: bool Create(nsWindow*, IMEState::Enabled); bool Destroy(void); + bool IsReadLock(DWORD aLock) const + { + return (TS_LF_READ == (aLock & TS_LF_READ)); + } + bool IsReadWriteLock(DWORD aLock) const + { + return (TS_LF_READWRITE == (aLock & TS_LF_READWRITE)); + } + bool IsReadLocked() const { return IsReadLock(mLock); } + bool IsReadWriteLocked() const { return IsReadWriteLock(mLock); } + + bool GetScreenExtInternal(RECT &aScreenExt); + bool GetSelectionInternal(TS_SELECTION_ACP &aSelectionACP); // If aDispatchTextEvent is true, this method will dispatch text event if // this is called during IME composing. aDispatchTextEvent should be true // only when this is called from SetSelection. Because otherwise, the text