author | Masayuki Nakano <masayuki@d-toybox.com> |
Wed, 16 Mar 2016 13:47:48 +0900 | |
changeset 328766 | 24f0cbec55c3dc87a826145e584aa27da2d6be2f |
parent 328765 | a9ffc169e99cf0006cdc29810e1b41f884a1ff53 |
child 328767 | 545efe0fba8180b3443cbd9a21d7a60dcb68bfaf |
push id | 1146 |
push user | Callek@gmail.com |
push date | Mon, 25 Jul 2016 16:35:44 +0000 |
treeherder | mozilla-release@a55778f9cd5a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | m_kato |
bugs | 1137561 |
milestone | 48.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/widget/TextEventDispatcher.h +++ b/widget/TextEventDispatcher.h @@ -220,16 +220,25 @@ public: * ClearPendingComposition() makes this instance forget pending composition. */ void ClearPendingComposition() { mPendingComposition.Clear(); } /** + * GetPendingCompositionClauses() returns text ranges which was appended by + * AppendClauseToPendingComposition() or SetPendingComposition(). + */ + const TextRangeArray* GetPendingCompositionClauses() const + { + return mPendingComposition.GetClauses(); + } + + /** * @see nsIWidget::NotifyIME() */ nsresult NotifyIME(const IMENotification& aIMENotification); /** * DispatchKeyboardEvent() maybe dispatches aKeyboardEvent. * * @param aMessage Must be eKeyDown or eKeyUp. @@ -296,16 +305,17 @@ private: PendingComposition(); nsresult SetString(const nsAString& aString); nsresult AppendClause(uint32_t aLength, uint32_t aAttribute); nsresult SetCaret(uint32_t aOffset, uint32_t aLength); nsresult Set(const nsAString& aString, const TextRangeArray* aRanges); nsresult Flush(TextEventDispatcher* aDispatcher, nsEventStatus& aStatus, const WidgetEventTime* aEventTime); + const TextRangeArray* GetClauses() const { return mClauses; } void Clear(); private: nsString mString; RefPtr<TextRangeArray> mClauses; TextRange mCaret; void EnsureClauseArray();
--- a/widget/windows/IMMHandler.cpp +++ b/widget/windows/IMMHandler.cpp @@ -1101,16 +1101,17 @@ void IMMHandler::OnIMEStartCompositionOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam) { MOZ_LOG(gIMMLog, LogLevel::Info, ("IMM: OnIMEStartCompositionOnPlugin, hWnd=%08x, mIsComposingOnPlugin=%s", aWindow->GetWindowHandle(), GetBoolName(mIsComposingOnPlugin))); mIsComposingOnPlugin = true; + mDispatcher = GetTextEventDispatcherFor(aWindow); mComposingWindow = aWindow; IMEContext context(aWindow); SetIMERelatedWindowsPosOnPlugin(aWindow, context); // On widnowless plugin, we should assume that the focused editor is always // in horizontal writing mode. AdjustCompositionFont(aWindow, context, WritingMode()); } @@ -1126,21 +1127,23 @@ IMMHandler::OnIMECompositionOnPlugin(nsW aWindow->GetWindowHandle(), lParam, GetBoolName(mIsComposingOnPlugin), GetBoolName(lParam & GCS_RESULTSTR), GetBoolName(lParam & GCS_COMPSTR), GetBoolName(lParam & GCS_COMPATTR), GetBoolName(lParam & GCS_COMPCLAUSE), GetBoolName(lParam & GCS_CURSORPOS))); // We should end composition if there is a committed string. if (IS_COMMITTING_LPARAM(lParam)) { mIsComposingOnPlugin = false; mComposingWindow = nullptr; + mDispatcher = nullptr; return; } // Continue composition if there is still a string being composed. if (IS_COMPOSING_LPARAM(lParam)) { mIsComposingOnPlugin = true; + mDispatcher = GetTextEventDispatcherFor(aWindow); mComposingWindow = aWindow; IMEContext context(aWindow); SetIMERelatedWindowsPosOnPlugin(aWindow, context); } } void IMMHandler::OnIMEEndCompositionOnPlugin(nsWindow* aWindow, @@ -1148,16 +1151,17 @@ IMMHandler::OnIMEEndCompositionOnPlugin( LPARAM lParam) { MOZ_LOG(gIMMLog, LogLevel::Info, ("IMM: OnIMEEndCompositionOnPlugin, hWnd=%08x, mIsComposingOnPlugin=%s", aWindow->GetWindowHandle(), GetBoolName(mIsComposingOnPlugin))); mIsComposingOnPlugin = false; mComposingWindow = nullptr; + mDispatcher = nullptr; if (mNativeCaretIsCreated) { ::DestroyCaret(); mNativeCaretIsCreated = false; } } bool @@ -1253,16 +1257,23 @@ IMMHandler::OnCharOnPlugin(nsWindow* aWi // WM_CHAR on plug-in is always handled by nsWindow. return false; } /**************************************************************************** * others ****************************************************************************/ +TextEventDispatcher* +IMMHandler::GetTextEventDispatcherFor(nsWindow* aWindow) +{ + return aWindow == mComposingWindow && mDispatcher ? + mDispatcher : aWindow->GetTextEventDispatcher(); +} + void IMMHandler::HandleStartComposition(nsWindow* aWindow, const IMEContext& aContext) { NS_PRECONDITION(!mIsComposing, "HandleStartComposition is called but mIsComposing is TRUE"); Selection& selection = GetSelection(); @@ -1273,23 +1284,37 @@ IMMHandler::HandleStartComposition(nsWin return; } AdjustCompositionFont(aWindow, aContext, selection.mWritingMode); mCompositionStart = selection.mOffset; mCursorPosition = NO_IME_CARET; - WidgetCompositionEvent event(true, eCompositionStart, aWindow); - LayoutDeviceIntPoint point(0, 0); - aWindow->InitEvent(event, &point); - DispatchEvent(aWindow, event); + RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcherFor(aWindow); + nsresult rv = dispatcher->BeginNativeInputTransaction(); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_LOG(gIMMLog, LogLevel::Error, + ("IMM: HandleStartComposition, FAILED due to " + "TextEventDispatcher::BeginNativeInputTransaction() failure")); + return; + } + WidgetEventTime eventTime = aWindow->CurrentMessageWidgetEventTime(); + nsEventStatus status; + rv = dispatcher->StartComposition(status, &eventTime); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_LOG(gIMMLog, LogLevel::Error, + ("IMM: HandleStartComposition, FAILED, due to " + "TextEventDispatcher::StartComposition() failure")); + return; + } mIsComposing = true; mComposingWindow = aWindow; + mDispatcher = dispatcher; MOZ_LOG(gIMMLog, LogLevel::Info, ("IMM: HandleStartComposition, START composition, mCompositionStart=%ld", mCompositionStart)); } bool IMMHandler::HandleComposition(nsWindow* aWindow, @@ -1542,27 +1567,37 @@ IMMHandler::HandleEndComposition(nsWindo aWindow, aCommitString, aCommitString ? NS_ConvertUTF16toUTF8(*aCommitString).get() : "")); if (mNativeCaretIsCreated) { ::DestroyCaret(); mNativeCaretIsCreated = false; } - EventMessage message = - aCommitString ? eCompositionCommit : eCompositionCommitAsIs; - WidgetCompositionEvent compositionCommitEvent(true, message, aWindow); - LayoutDeviceIntPoint point(0, 0); - aWindow->InitEvent(compositionCommitEvent, &point); - if (aCommitString) { - compositionCommitEvent.mData = *aCommitString; + RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcherFor(aWindow); + nsresult rv = dispatcher->BeginNativeInputTransaction(); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_LOG(gIMMLog, LogLevel::Error, + ("IMM: HandleEndComposition, FAILED due to " + "TextEventDispatcher::BeginNativeInputTransaction() failure")); + return; } - DispatchEvent(aWindow, compositionCommitEvent); + WidgetEventTime eventTime = aWindow->CurrentMessageWidgetEventTime(); + nsEventStatus status; + rv = dispatcher->CommitComposition(status, aCommitString, &eventTime); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_LOG(gIMMLog, LogLevel::Error, + ("IMM: HandleStartComposition, FAILED, due to " + "TextEventDispatcher::CommitComposition() failure")); + return; + } mIsComposing = false; + // XXX aWindow and mComposingWindow are always same?? mComposingWindow = nullptr; + mDispatcher = nullptr; } bool IMMHandler::HandleReconvert(nsWindow* aWindow, LPARAM lParam, LRESULT* oResult) { *oResult = 0; @@ -1924,126 +1959,137 @@ IMMHandler::DispatchCompositionChangeEve // fire compositionchange event during composing. if (!ShouldDrawCompositionStringOurselves()) { // But we need to adjust composition window pos and native caret pos, here. SetIMERelatedWindowsPos(aWindow, aContext); return; } RefPtr<nsWindow> kungFuDeathGrip(aWindow); - - LayoutDeviceIntPoint point(0, 0); - - WidgetCompositionEvent event(true, eCompositionChange, aWindow); - - aWindow->InitEvent(event, &point); - - event.mRanges = CreateTextRangeArray(); - event.mData = mCompositionString; - - DispatchEvent(aWindow, event); + RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcherFor(aWindow); + nsresult rv = dispatcher->BeginNativeInputTransaction(); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_LOG(gIMMLog, LogLevel::Error, + ("IMM: DispatchCompositionChangeEvent, FAILED due to " + "TextEventDispatcher::BeginNativeInputTransaction() failure")); + return; + } - // Calling SetIMERelatedWindowsPos will be failure on e10s at this point. - // compositionchange event will notify NOTIFY_IME_OF_COMPOSITION_UPDATE, then - // it will call SetIMERelatedWindowsPos. -} + // NOTE: Calling SetIMERelatedWindowsPos() from this method will be failure + // in e10s mode. compositionchange event will notify this of + // NOTIFY_IME_OF_COMPOSITION_UPDATE, then SetIMERelatedWindowsPos() + // will be called. -already_AddRefed<TextRangeArray> -IMMHandler::CreateTextRangeArray() -{ - // Sogou (Simplified Chinese IME) returns contradictory values: The cursor - // position is actual cursor position. However, other values (composition - // string and attributes) are empty. So, if you want to remove following - // assertion, be careful. - NS_ASSERTION(ShouldDrawCompositionStringOurselves(), - "CreateTextRangeArray is called when we don't need to fire " - "compositionchange event"); + // XXX Sogou (Simplified Chinese IME) returns contradictory values: + // The cursor position is actual cursor position. However, other values + // (composition string and attributes) are empty. - RefPtr<TextRangeArray> textRangeArray = new TextRangeArray(); - - TextRange range; if (mCompositionString.IsEmpty()) { // Don't append clause information if composition string is empty. - } else if (mClauseArray.Length() == 0) { + } else if (mClauseArray.IsEmpty()) { // Some IMEs don't return clause array information, then, we assume that // all characters in the composition string are in one clause. - range.mStartOffset = 0; - range.mEndOffset = mCompositionString.Length(); - range.mRangeType = NS_TEXTRANGE_RAWINPUT; - textRangeArray->AppendElement(range); - MOZ_LOG(gIMMLog, LogLevel::Info, - ("IMM: CreateTextRangeArray, mClauseLength=0")); + ("IMM: DispatchCompositionChangeEvent, mClauseArray.Length()=0")); + rv =dispatcher->SetPendingComposition(mCompositionString, nullptr); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_LOG(gIMMLog, LogLevel::Error, + ("IMM: DispatchCompositionChangeEvent, FAILED due to" + "TextEventDispatcher::SetPendingComposition() failure")); + return; + } } else { // iterate over the attributes + rv = dispatcher->SetPendingCompositionString(mCompositionString); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_LOG(gIMMLog, LogLevel::Error, + ("IMM: DispatchCompositionChangeEvent, FAILED due to" + "TextEventDispatcher::SetPendingCompositionString() failure")); + return; + } uint32_t lastOffset = 0; for (uint32_t i = 0; i < mClauseArray.Length() - 1; i++) { uint32_t current = mClauseArray[i + 1]; if (current > mCompositionString.Length()) { MOZ_LOG(gIMMLog, LogLevel::Info, - ("IMM: CreateTextRangeArray, mClauseArray[%ld]=%lu. " + ("IMM: DispatchCompositionChangeEvent, mClauseArray[%ld]=%lu. " "This is larger than mCompositionString.Length()=%lu", i + 1, current, mCompositionString.Length())); current = int32_t(mCompositionString.Length()); } - range.mRangeType = PlatformToNSAttr(mAttributeArray[lastOffset]); - range.mStartOffset = lastOffset; - range.mEndOffset = current; - textRangeArray->AppendElement(range); + uint32_t length = current - lastOffset; + uint32_t attr = PlatformToNSAttr(mAttributeArray[lastOffset]); + rv = dispatcher->AppendClauseToPendingComposition(length, attr); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_LOG(gIMMLog, LogLevel::Error, + ("IMM: DispatchCompositionChangeEvent, FAILED due to" + "TextEventDispatcher::AppendClauseToPendingComposition() failure")); + return; + } lastOffset = current; MOZ_LOG(gIMMLog, LogLevel::Info, - ("IMM: CreateTextRangeArray, index=%ld, rangeType=%s, range=[%lu-%lu]", - i, GetRangeTypeName(range.mRangeType), range.mStartOffset, - range.mEndOffset)); + ("IMM: DispatchCompositionChangeEvent, index=%ld, rangeType=%s, " + "range length=%lu", + i, GetRangeTypeName(attr), length)); } } if (mCursorPosition == NO_IME_CARET) { MOZ_LOG(gIMMLog, LogLevel::Info, - ("IMM: CreateTextRangeArray, no caret")); - return textRangeArray.forget(); - } + ("IMM: DispatchCompositionChangeEvent, no caret")); + } else { + uint32_t cursor = static_cast<uint32_t>(mCursorPosition); + if (cursor > mCompositionString.Length()) { + MOZ_LOG(gIMMLog, LogLevel::Info, + ("IMM: CreateTextRangeArray, mCursorPosition=%ld. " + "This is larger than mCompositionString.Length()=%lu", + mCursorPosition, mCompositionString.Length())); + cursor = mCompositionString.Length(); + } - uint32_t cursor = static_cast<uint32_t>(mCursorPosition); - if (cursor > mCompositionString.Length()) { - MOZ_LOG(gIMMLog, LogLevel::Info, - ("IMM: CreateTextRangeArray, mCursorPosition=%ld. " - "This is larger than mCompositionString.Length()=%lu", - mCursorPosition, mCompositionString.Length())); - cursor = mCompositionString.Length(); + // If caret is in the target clause, the target clause will be painted as + // normal selection range. Since caret shouldn't be in selection range on + // Windows, we shouldn't append caret range in such case. + const TextRangeArray* clauses = dispatcher->GetPendingCompositionClauses(); + const TextRange* targetClause = + clauses ? clauses->GetTargetClause() : nullptr; + if (targetClause && + cursor >= targetClause->mStartOffset && + cursor <= targetClause->mEndOffset) { + // Forget the caret position specified by IME since Gecko's caret position + // will be at the end of composition string. + mCursorPosition = NO_IME_CARET; + MOZ_LOG(gIMMLog, LogLevel::Info, + ("IMM: CreateTextRangeArray, no caret due to it's in the target " + "clause, now, mCursorPosition is NO_IME_CARET")); + } + + if (mCursorPosition != NO_IME_CARET) { + rv = dispatcher->SetCaretInPendingComposition(cursor, 0); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_LOG(gIMMLog, LogLevel::Error, + ("IMM: DispatchCompositionChangeEvent, FAILED due to" + "TextEventDispatcher::SetCaretInPendingComposition() failure")); + return; + } + } } - // If caret is in the target clause, the target clause will be painted as - // normal selection range. Since caret shouldn't be in selection range on - // Windows, we shouldn't append caret range in such case. - const TextRange* targetClause = textRangeArray->GetTargetClause(); - if (targetClause && - cursor >= targetClause->mStartOffset && - cursor <= targetClause->mEndOffset) { - // Forget the caret position specified by IME since Gecko's caret position - // will be at the end of composition string. - mCursorPosition = NO_IME_CARET; - MOZ_LOG(gIMMLog, LogLevel::Info, - ("IMM: CreateTextRangeArray, no caret due to it's in the target clause, " - "now, mCursorPosition is NO_IME_CARET")); - return textRangeArray.forget(); + WidgetEventTime eventTime = aWindow->CurrentMessageWidgetEventTime(); + nsEventStatus status; + rv = dispatcher->FlushPendingComposition(status, &eventTime); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_LOG(gIMMLog, LogLevel::Error, + ("IMM: DispatchCompositionChangeEvent, FAILED due to" + "TextEventDispatcher::FlushPendingComposition() failure")); + return; } - - range.mStartOffset = range.mEndOffset = cursor; - range.mRangeType = NS_TEXTRANGE_CARETPOSITION; - textRangeArray->AppendElement(range); - - MOZ_LOG(gIMMLog, LogLevel::Info, - ("IMM: CreateTextRangeArray, caret position=%ld", - range.mStartOffset)); - - return textRangeArray.forget(); } void IMMHandler::GetCompositionString(const IMEContext& aContext, DWORD aIndex, nsAString& aCompositionString) const { aCompositionString.Truncate();
--- a/widget/windows/IMMHandler.h +++ b/widget/windows/IMMHandler.h @@ -8,16 +8,17 @@ #include "nscore.h" #include <windows.h> #include "nsCOMPtr.h" #include "nsString.h" #include "nsTArray.h" #include "nsIWidget.h" #include "mozilla/EventForwards.h" +#include "mozilla/TextEventDispatcher.h" #include "nsRect.h" #include "WritingModes.h" #include "npapi.h" class nsWindow; namespace mozilla { namespace widget { @@ -369,17 +370,16 @@ protected: * I.e., this should be called only during composing. If a composition is * being committed, only HandleCompositionEnd() should be called. * * @param aWindow The window which has the composition. * @param aContext Native IME context which has the composition. */ void DispatchCompositionChangeEvent(nsWindow* aWindow, const IMEContext& aContext); - already_AddRefed<mozilla::TextRangeArray> CreateTextRangeArray(); nsresult EnsureClauseArray(int32_t aCount); nsresult EnsureAttributeArray(int32_t aCount); /** * When WM_IME_CHAR is received and passed to DefWindowProc, we need to * record the messages. In other words, we should record the messages * when we receive WM_IME_CHAR on windowless plug-in (if we have focus, @@ -409,17 +409,20 @@ protected: void EnqueueIMECharRecords(WPARAM wParam, LPARAM lParam) { MSG msg; msg.wParam = wParam; msg.lParam = lParam; mPassedIMEChar.AppendElement(msg); } + TextEventDispatcher* GetTextEventDispatcherFor(nsWindow* aWindow); + nsWindow* mComposingWindow; + RefPtr<TextEventDispatcher> mDispatcher; nsString mCompositionString; InfallibleTArray<uint32_t> mClauseArray; InfallibleTArray<uint8_t> mAttributeArray; int32_t mCursorPosition; uint32_t mCompositionStart; struct Selection