Bug 1234422 TSFTextStore should retry to notify TSF/TIP of layout change if synchronous calls of OnLayoutChange() don't cause retrieving layout information r=m_kato

This commit is contained in:
Masayuki Nakano 2015-12-30 01:05:46 +09:00
parent 99ec363485
commit 369e8fb38b
3 changed files with 114 additions and 29 deletions

View File

@ -1315,7 +1315,8 @@ TSFTextStore::TSFTextStore()
, mRequestedAttrValues(false)
, mIsRecordingActionsWithoutLock(false)
, mPendingOnSelectionChange(false)
, mPendingOnLayoutChange(false)
, mHasReturnedNoLayoutError(false)
, mWaitingQueryLayout(false)
, mPendingDestroy(false)
, mDeferClearingLockedContent(false)
, mNativeCaretIsCreated(false)
@ -1670,7 +1671,7 @@ TSFTextStore::DidLockGranted()
// If the widget has gone, we don't need to notify anything.
if (!mWidget || mWidget->Destroyed()) {
mPendingOnSelectionChange = false;
mPendingOnLayoutChange = false;
mHasReturnedNoLayoutError = false;
}
}
@ -1695,7 +1696,7 @@ TSFTextStore::FlushPendingActions()
mPendingActions.Clear();
mLockedContent.Clear();
mPendingOnSelectionChange = false;
mPendingOnLayoutChange = false;
mHasReturnedNoLayoutError = false;
return;
}
@ -1901,11 +1902,11 @@ TSFTextStore::MaybeFlushPendingNotifications()
"mLockedContent is cleared", this));
}
if (mPendingOnLayoutChange) {
if (mHasReturnedNoLayoutError) {
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("TSF: 0x%p TSFTextStore::MaybeFlushPendingNotifications(), "
"calling TSFTextStore::NotifyTSFOfLayoutChange()...", this));
NotifyTSFOfLayoutChange(true);
NotifyTSFOfLayoutChange();
}
if (mPendingOnSelectionChange) {
@ -3339,10 +3340,11 @@ TSFTextStore::GetACPFromPoint(TsViewCookie vcView,
{
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("TSF: 0x%p TSFTextStore::GetACPFromPoint(pvcView=%d, pt=%p (x=%d, "
"y=%d), dwFlags=%s, pacp=%p, mDeferNotifyingTSF=%s",
"y=%d), dwFlags=%s, pacp=%p, mDeferNotifyingTSF=%s, "
"mWaitingQueryLayout=%s",
this, vcView, pt, pt ? pt->x : 0, pt ? pt->y : 0,
GetACPFromPointFlagName(dwFlags).get(), pacp,
GetBoolName(mDeferNotifyingTSF)));
GetBoolName(mDeferNotifyingTSF), GetBoolName(mWaitingQueryLayout)));
if (!IsReadLocked()) {
MOZ_LOG(sTextStoreLog, LogLevel::Error,
@ -3372,11 +3374,13 @@ TSFTextStore::GetACPFromPoint(TsViewCookie vcView,
return E_INVALIDARG;
}
mWaitingQueryLayout = false;
if (mLockedContent.IsLayoutChanged()) {
MOZ_LOG(sTextStoreLog, LogLevel::Error,
("TSF: 0x%p TSFTextStore::GetACPFromPoint() FAILED due to "
"layout not recomputed", this));
mPendingOnLayoutChange = true;
("TSF: 0x%p TSFTextStore::GetACPFromPoint() returned "
"TS_E_NOLAYOUT", this));
mHasReturnedNoLayoutError = true;
return TS_E_NOLAYOUT;
}
@ -3492,9 +3496,9 @@ TSFTextStore::GetTextExt(TsViewCookie vcView,
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("TSF: 0x%p TSFTextStore::GetTextExt(vcView=%ld, "
"acpStart=%ld, acpEnd=%ld, prc=0x%p, pfClipped=0x%p), "
"mDeferNotifyingTSF=%s",
"mDeferNotifyingTSF=%s, mWaitingQueryLayout=%s",
this, vcView, acpStart, acpEnd, prc, pfClipped,
GetBoolName(mDeferNotifyingTSF)));
GetBoolName(mDeferNotifyingTSF), GetBoolName(mWaitingQueryLayout)));
if (!IsReadLocked()) {
MOZ_LOG(sTextStoreLog, LogLevel::Error,
@ -3524,6 +3528,8 @@ TSFTextStore::GetTextExt(TsViewCookie vcView,
return TS_E_INVALIDPOS;
}
mWaitingQueryLayout = false;
// NOTE: TSF (at least on Win 8.1) doesn't return TS_E_NOLAYOUT to the
// caller even if we return it. It's converted to just E_FAIL.
// However, this is fixed on Win 10.
@ -3611,9 +3617,9 @@ TSFTextStore::GetTextExt(TsViewCookie vcView,
if (mLockedContent.IsLayoutChangedAfter(acpEnd)) {
MOZ_LOG(sTextStoreLog, LogLevel::Error,
("TSF: 0x%p TSFTextStore::GetTextExt() FAILED due to "
"layout not recomputed at %d", this, acpEnd));
mPendingOnLayoutChange = true;
("TSF: 0x%p TSFTextStore::GetTextExt() returned TS_E_NOLAYOUT "
"(acpEnd=%d)", this, acpEnd));
mHasReturnedNoLayoutError = true;
return TS_E_NOLAYOUT;
}
@ -4768,7 +4774,7 @@ TSFTextStore::OnLayoutChangeInternal()
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("TSF: 0x%p TSFTextStore::OnLayoutChangeInternal(), calling "
"NotifyTSFOfLayoutChange()...", this));
if (NS_WARN_IF(!NotifyTSFOfLayoutChange(mPendingOnLayoutChange))) {
if (NS_WARN_IF(!NotifyTSFOfLayoutChange())) {
rv = NS_ERROR_FAILURE;
}
@ -4781,9 +4787,16 @@ TSFTextStore::OnLayoutChangeInternal()
}
bool
TSFTextStore::NotifyTSFOfLayoutChange(bool aFlush)
TSFTextStore::NotifyTSFOfLayoutChange()
{
mPendingOnLayoutChange = false;
bool returnedNoLayoutError = mHasReturnedNoLayoutError;
// If we returned TS_E_NOLAYOUT, TIP should query the computed layout again.
mWaitingQueryLayout = returnedNoLayoutError;
// For avoiding to call this method again at unlocking the document during
// calls of OnLayoutChange(), reset mHasReturnedNoLayoutError.
mHasReturnedNoLayoutError = false;
// Now, layout has been computed. We should notify mLockedContent for
// making GetTextExt() and GetACPFromPoint() not return TS_E_NOLAYOUT.
@ -4796,7 +4809,7 @@ TSFTextStore::NotifyTSFOfLayoutChange(bool aFlush)
MaybeDestroyNativeCaret();
// This method should return true if either way succeeds.
bool ret = false;
bool ret = true;
if (mSink) {
MOZ_LOG(sTextStoreLog, LogLevel::Info,
@ -4804,12 +4817,16 @@ TSFTextStore::NotifyTSFOfLayoutChange(bool aFlush)
"calling ITextStoreACPSink::OnLayoutChange()...",
this));
HRESULT hr = mSink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW);
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("TSF: 0x%p TSFTextStore::NotifyTSFOfLayoutChange(), "
"called ITextStoreACPSink::OnLayoutChange()",
this));
ret = SUCCEEDED(hr);
}
// The layout change caused by composition string change should cause
// calling ITfContextOwnerServices::OnLayoutChange() too.
if (aFlush && mContext) {
if (returnedNoLayoutError && mContext) {
RefPtr<ITfContextOwnerServices> service;
mContext->QueryInterface(IID_ITfContextOwnerServices,
getter_AddRefs(service));
@ -4819,11 +4836,66 @@ TSFTextStore::NotifyTSFOfLayoutChange(bool aFlush)
"calling ITfContextOwnerServices::OnLayoutChange()...",
this));
HRESULT hr = service->OnLayoutChange();
ret = SUCCEEDED(hr);
ret = ret && SUCCEEDED(hr);
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("TSF: 0x%p TSFTextStore::NotifyTSFOfLayoutChange(), "
"called ITfContextOwnerServices::OnLayoutChange()",
this));
}
}
return ret;
if (!mWidget || mWidget->Destroyed()) {
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("TSF: 0x%p TSFTextStore::NotifyTSFOfLayoutChange(), "
"the widget is destroyed during calling OnLayoutChange()",
this));
return ret;
}
if (mDestroyed) {
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("TSF: 0x%p TSFTextStore::NotifyTSFOfLayoutChange(), "
"the TSFTextStore instance is destroyed during calling "
"OnLayoutChange()",
this));
return ret;
}
if (!mWaitingQueryLayout) {
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("TSF: 0x%p TSFTextStore::NotifyTSFOfLayoutChange(), "
"succeeded notifying TIP of our layout change",
this));
return ret;
}
// If TIP hasn't accessed our new layout information yet, TSF and/or TIP may
// have met some trouble during calls of OnLayoutChange(). It should be
// tried again later.
mHasReturnedNoLayoutError = returnedNoLayoutError;
::PostMessage(mWidget->GetWindowHandle(),
MOZ_WM_NOTIY_TSF_OF_LAYOUT_CHANGE,
reinterpret_cast<WPARAM>(this), 0);
return true;
}
void
TSFTextStore::NotifyTSFOfLayoutChangeAgain()
{
// Before preforming this method, TIP has accessed our layout information,
// we don't need to notify TIP of layout change anymore.
if (!mWaitingQueryLayout) {
return;
}
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("TSF: 0x%p TSFTextStore::NotifyTSFOfLayoutChangeAgain(), "
"calling NotifyTSFOfLayoutChange()...", this));
NotifyTSFOfLayoutChange();
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("TSF: 0x%p TSFTextStore::NotifyTSFOfLayoutChangeAgain(), "
"called NotifyTSFOfLayoutChange()", this));
}
nsresult
@ -5462,6 +5534,13 @@ TSFTextStore::ProcessMessage(nsWindowBase* aWindow,
}
CommitComposition(false);
break;
case MOZ_WM_NOTIY_TSF_OF_LAYOUT_CHANGE: {
TSFTextStore* textStore = reinterpret_cast<TSFTextStore*>(aWParam);
if (textStore == sEnabledTextStore) {
textStore->NotifyTSFOfLayoutChangeAgain();
}
break;
}
}
}

View File

@ -296,7 +296,8 @@ protected:
void NotifyTSFOfTextChange(const TS_TEXTCHANGE& aTextChange);
void NotifyTSFOfSelectionChange();
bool NotifyTSFOfLayoutChange(bool aFlush);
bool NotifyTSFOfLayoutChange();
void NotifyTSFOfLayoutChangeAgain();
HRESULT HandleRequestAttrs(DWORD aFlags,
ULONG aFilterCount,
@ -828,11 +829,14 @@ protected:
// mSink->OnSelectionChange() after mLock becomes 0.
bool mPendingOnSelectionChange;
// If GetTextExt() or GetACPFromPoint() is called and the layout hasn't been
// calculated yet, these methods return TS_E_NOLAYOUT. Then, RequestLock()
// will call mSink->OnLayoutChange() and
// ITfContextOwnerServices::OnLayoutChange() after the layout is fixed and
// the document is unlocked.
bool mPendingOnLayoutChange;
// calculated yet, these methods return TS_E_NOLAYOUT. At that time,
// mHasReturnedNoLayoutError is set to true.
bool mHasReturnedNoLayoutError;
// Before calling ITextStoreACPSink::OnLayoutChange() and
// ITfContextOwnerServices::OnLayoutChange(), mWaitingQueryLayout is set to
// true. This is set to false when GetTextExt() or GetACPFromPoint() is
// called.
bool mWaitingQueryLayout;
// During the documet is locked, we shouldn't destroy the instance.
// If this is true, the instance will be destroyed after unlocked.
bool mPendingDestroy;

View File

@ -36,7 +36,9 @@
// If a popup window is being activated, we try to reactivate the previous
// window with this message.
#define MOZ_WM_REACTIVATE (WM_APP+0x0314)
// If TSFTextStore needs to notify TSF/TIP of layout change later, this
// message is posted.
#define MOZ_WM_NOTIY_TSF_OF_LAYOUT_CHANGE (WM_APP+0x0315)
// Internal message for ensuring the file picker is visible on multi monitor
// systems, and when the screen resolution changes.
#define MOZ_WM_ENSUREVISIBLE (WM_APP+0x374F)