Bug 789706 part.1 Create native caret over our caret when ITextStoreACP::GetTextExt() is called during composition r=emk

This commit is contained in:
Masayuki Nakano 2014-01-31 11:17:24 +09:00
parent 9ef3919738
commit 1aa091b2bc
2 changed files with 102 additions and 6 deletions

View File

@ -529,6 +529,7 @@ nsTextStore::nsTextStore()
mInputScopeRequested = false;
mIsRecordingActionsWithoutLock = false;
mNotifySelectionChange = false;
mNativeCaretIsCreated = false;
mIsIMM_IME = IsIMM_IME(::GetKeyboardLayout(0));
// We hope that 5 or more actions don't occur at once.
mPendingActions.SetCapacity(5);
@ -876,9 +877,7 @@ nsTextStore::RequestLock(DWORD dwLockFlags,
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
this, GetLockFlagNameStr(mLock).get()));
if (IsReadWriteLocked()) {
FlushPendingActions();
}
DidLockGranted();
while (mLockQueued) {
mLock = mLockQueued;
mLockQueued = 0;
@ -893,9 +892,7 @@ nsTextStore::RequestLock(DWORD dwLockFlags,
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
this, GetLockFlagNameStr(mLock).get()));
if (IsReadWriteLocked()) {
FlushPendingActions();
}
DidLockGranted();
}
mLock = 0;
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
@ -925,6 +922,18 @@ nsTextStore::RequestLock(DWORD dwLockFlags,
return E_FAIL;
}
void
nsTextStore::DidLockGranted()
{
if (mNativeCaretIsCreated) {
::DestroyCaret();
mNativeCaretIsCreated = false;
}
if (IsReadWriteLocked()) {
FlushPendingActions();
}
}
void
nsTextStore::FlushPendingActions()
{
@ -2413,6 +2422,20 @@ nsTextStore::GetTextExt(TsViewCookie vcView,
// not equal if text rect was clipped
*pfClipped = !::EqualRect(prc, &textRect);
// ATOK refers native caret position and size on Desktop applications for
// deciding candidate window. Therefore, we need to create native caret
// for hacking the bug.
if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop &&
mComposition.IsComposing() &&
mComposition.mStart <= acpStart && mComposition.EndOffset() >= acpStart &&
mComposition.mStart <= acpEnd && mComposition.EndOffset() >= acpEnd) {
if (mNativeCaretIsCreated) {
::DestroyCaret();
mNativeCaretIsCreated = false;
}
CreateNativeCaret();
}
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::GetTextExt() succeeded: "
"*prc={ left=%ld, top=%ld, right=%ld, bottom=%ld }, *pfClipped=%s",
@ -3190,6 +3213,69 @@ nsTextStore::OnLayoutChange()
return NS_OK;
}
void
nsTextStore::CreateNativeCaret()
{
// This method must work only on desktop application.
if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Desktop) {
return;
}
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::CreateNativeCaret(), "
"mComposition.IsComposing()=%s",
this, GetBoolName(mComposition.IsComposing())));
Selection& currentSel = CurrentSelection();
if (currentSel.IsDirty()) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to "
"CurrentSelection() failure", this));
return;
}
// XXX If this is called without composition and the selection isn't
// collapsed, is it OK?
uint32_t caretOffset = currentSel.MaxOffset();
WidgetQueryContentEvent queryCaretRect(true, NS_QUERY_CARET_RECT, mWidget);
queryCaretRect.InitForQueryCaretRect(caretOffset);
mWidget->InitEvent(queryCaretRect);
mWidget->DispatchWindowEvent(&queryCaretRect);
if (!queryCaretRect.mSucceeded) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to "
"NS_QUERY_CARET_RECT failure (offset=%d)", this, caretOffset));
return;
}
nsIntRect& caretRect = queryCaretRect.mReply.mRect;
mNativeCaretIsCreated = ::CreateCaret(mWidget->GetWindowHandle(), nullptr,
caretRect.width, caretRect.height);
if (!mNativeCaretIsCreated) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to "
"CreateCaret() failure", this));
return;
}
nsWindow* window = static_cast<nsWindow*>(mWidget.get());
nsWindow* toplevelWindow = window->GetTopLevelWindow(false);
if (!toplevelWindow) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to "
"no top level window", this));
return;
}
if (toplevelWindow != window) {
caretRect.MoveBy(toplevelWindow->WidgetToScreenOffset());
caretRect.MoveBy(-window->WidgetToScreenOffset());
}
::SetCaretPos(caretRect.x, caretRect.y);
}
void
nsTextStore::CommitCompositionInternal(bool aDiscard)
{

View File

@ -230,6 +230,10 @@ protected:
bool IsReadLocked() const { return IsReadLock(mLock); }
bool IsReadWriteLocked() const { return IsReadWriteLock(mLock); }
// This is called immediately after a call of OnLockGranted() of mSink.
// Note that mLock isn't cleared yet when this is called.
void DidLockGranted();
bool GetScreenExtInternal(RECT &aScreenExt);
// If aDispatchTextEvent is true, this method will dispatch text event if
// this is called during IME composing. aDispatchTextEvent should be true
@ -265,6 +269,10 @@ protected:
const TS_ATTRID *paFilterAttrs);
void SetInputScope(const nsString& aHTMLInputType);
// Creates native caret over our caret. This method only works on desktop
// application. Otherwise, this does nothing.
void CreateNativeCaret();
// Holds the pointer to our current win32 or metro widget
nsRefPtr<nsWindowBase> mWidget;
// Document manager for the currently focused editor
@ -644,6 +652,8 @@ protected:
// during recoding actions and then, FlushPendingActions() will call
// mSink->OnSelectionChange().
bool mNotifySelectionChange;
// While there is native caret, this is true. Otherwise, false.
bool mNativeCaretIsCreated;
// True if current IME is implemented with IMM.
bool mIsIMM_IME;