From f2a58d2261e87cf477755ba3b9e1aa0aa17b53cf Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Thu, 11 Jun 2015 19:50:15 +0900 Subject: [PATCH] Bug 1130937 part.2 nsGtkIMModule should set candidiate window position to bottom left of the target clause in vertical writing mode r=m_kato --- widget/TextEvents.h | 9 +++++++++ widget/TextRange.h | 32 ++++++++++++++++++++--------- widget/gtk/nsGtkIMModule.cpp | 39 +++++++++++++++++++++++++----------- widget/gtk/nsGtkIMModule.h | 30 ++++++++++++++++++++------- 4 files changed, 82 insertions(+), 28 deletions(-) diff --git a/widget/TextEvents.h b/widget/TextEvents.h index 44fc72379bac..2ffbee554162 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -410,6 +410,15 @@ public: return mRanges ? mRanges->TargetClauseOffset() : 0; } + uint32_t TargetClauseLength() const + { + uint32_t length = UINT32_MAX; + if (mRanges) { + length = mRanges->TargetClauseLength(); + } + return length == UINT32_MAX ? mData.Length() : length; + } + uint32_t RangeCount() const { return mRanges ? mRanges->Length() : 0; diff --git a/widget/TextRange.h b/widget/TextRange.h index b492ad9f0096..36abbf09dca8 100644 --- a/widget/TextRange.h +++ b/widget/TextRange.h @@ -195,6 +195,18 @@ class TextRangeArray final : public nsAutoTArray NS_INLINE_DECL_REFCOUNTING(TextRangeArray) + const TextRange* GetTargetClause() const + { + for (uint32_t i = 0; i < Length(); ++i) { + const TextRange& range = ElementAt(i); + if (range.mRangeType == NS_TEXTRANGE_SELECTEDRAWTEXT || + range.mRangeType == NS_TEXTRANGE_SELECTEDCONVERTEDTEXT) { + return ⦥ + } + } + return nullptr; + } + public: bool IsComposing() const { @@ -206,18 +218,20 @@ public: return false; } - // Returns target clase offset. If there are selected clauses, this returns + // Returns target clause offset. If there are selected clauses, this returns // the first selected clause offset. Otherwise, 0. uint32_t TargetClauseOffset() const { - for (uint32_t i = 0; i < Length(); ++i) { - const TextRange& range = ElementAt(i); - if (range.mRangeType == NS_TEXTRANGE_SELECTEDRAWTEXT || - range.mRangeType == NS_TEXTRANGE_SELECTEDCONVERTEDTEXT) { - return range.mStartOffset; - } - } - return 0; + const TextRange* range = GetTargetClause(); + return range ? range->mStartOffset : 0; + } + + // Returns target clause length. If there are selected clauses, this returns + // the first selected clause length. Otherwise, UINT32_MAX. + uint32_t TargetClauseLength() const + { + const TextRange* range = GetTargetClause(); + return range ? range->Length() : UINT32_MAX; } bool Equals(const TextRangeArray& aOther) const diff --git a/widget/gtk/nsGtkIMModule.cpp b/widget/gtk/nsGtkIMModule.cpp index 1b9021db71c4..19484e27c486 100644 --- a/widget/gtk/nsGtkIMModule.cpp +++ b/widget/gtk/nsGtkIMModule.cpp @@ -14,6 +14,7 @@ #include "mozilla/MiscEvents.h" #include "mozilla/Preferences.h" #include "mozilla/TextEvents.h" +#include "WritingModes.h" using namespace mozilla; using namespace mozilla::widget; @@ -111,7 +112,6 @@ nsGtkIMModule::nsGtkIMModule(nsWindow* aOwnerWindow) , mComposingContext(nullptr) , mCompositionStart(UINT32_MAX) , mProcessingKeyEvent(nullptr) - , mCompositionTargetOffset(UINT32_MAX) , mCompositionState(eCompositionState_NotComposing) , mIsIMFocused(false) , mIsDeletingSurrounding(false) @@ -535,7 +535,7 @@ nsGtkIMModule::OnUpdateComposition() return; } - SetCursorPosition(GetActiveContext(), mCompositionTargetOffset); + SetCursorPosition(GetActiveContext()); } void @@ -819,7 +819,8 @@ nsGtkIMModule::OnStartCompositionNative(GtkIMContext *aContext) if (!DispatchCompositionStart(aContext)) { return; } - mCompositionTargetOffset = mCompositionStart; + mCompositionTargetRange.mOffset = mCompositionStart; + mCompositionTargetRange.mLength = 0; } /* static */ @@ -1195,7 +1196,9 @@ nsGtkIMModule::DispatchCompositionChangeEvent( // We cannot call SetCursorPosition for e10s-aware. // DispatchEvent is async on e10s, so composition rect isn't updated now // on tab parent. - mCompositionTargetOffset = targetOffset; + mCompositionTargetRange.mOffset = targetOffset; + mCompositionTargetRange.mLength = + compositionChangeEvent.mRanges->TargetClauseLength(); return true; } @@ -1238,7 +1241,7 @@ nsGtkIMModule::DispatchCompositionCommitEvent( NS_COMPOSITION_COMMIT_AS_IS; mCompositionState = eCompositionState_NotComposing; mCompositionStart = UINT32_MAX; - mCompositionTargetOffset = UINT32_MAX; + mCompositionTargetRange.Clear(); mDispatchedCompositionString.Truncate(); WidgetCompositionEvent compositionCommitEvent(true, message, @@ -1393,16 +1396,19 @@ nsGtkIMModule::CreateTextRangeArray(GtkIMContext* aContext, } void -nsGtkIMModule::SetCursorPosition(GtkIMContext* aContext, - uint32_t aTargetOffset) +nsGtkIMModule::SetCursorPosition(GtkIMContext* aContext) { MOZ_LOG(gGtkIMLog, LogLevel::Info, - ("GtkIMModule(%p): SetCursorPosition, aContext=%p, aTargetOffset=%u", - this, aContext, aTargetOffset)); + ("GtkIMModule(%p): SetCursorPosition, aContext=%p, " + "mCompositionTargetRange={ mOffset=%u, mLength=%u }" + "mSelection.mWritingMode=%s", + this, aContext, mCompositionTargetRange.mOffset, + mCompositionTargetRange.mLength, + GetWritingModeName(mSelection.mWritingMode).get())); - if (aTargetOffset == UINT32_MAX) { + if (!mCompositionTargetRange.IsValid()) { MOZ_LOG(gGtkIMLog, LogLevel::Info, - (" FAILED, aTargetOffset is wrong offset")); + (" FAILED, mCompositionTargetRange is invalid")); return; } @@ -1420,7 +1426,15 @@ nsGtkIMModule::SetCursorPosition(GtkIMContext* aContext, WidgetQueryContentEvent charRect(true, NS_QUERY_TEXT_RECT, mLastFocusedWindow); - charRect.InitForQueryTextRect(aTargetOffset, 1); + if (mSelection.mWritingMode.IsVertical()) { + // For preventing the candidate window to overlap the target clause, + // we should set fake (typically, very tall) caret rect. + uint32_t length = mCompositionTargetRange.mLength ? + mCompositionTargetRange.mLength : 1; + charRect.InitForQueryTextRect(mCompositionTargetRange.mOffset, length); + } else { + charRect.InitForQueryTextRect(mCompositionTargetRange.mOffset, 1); + } InitEvent(charRect); nsEventStatus status; mLastFocusedWindow->DispatchEvent(&charRect, status); @@ -1429,6 +1443,7 @@ nsGtkIMModule::SetCursorPosition(GtkIMContext* aContext, (" FAILED, NS_QUERY_TEXT_RECT was failed")); return; } + nsWindow* rootWindow = static_cast(mLastFocusedWindow->GetTopLevelWidget()); diff --git a/widget/gtk/nsGtkIMModule.h b/widget/gtk/nsGtkIMModule.h index fcb190d77019..c0ffc221589d 100644 --- a/widget/gtk/nsGtkIMModule.h +++ b/widget/gtk/nsGtkIMModule.h @@ -125,8 +125,27 @@ protected: // event. GdkEventKey* mProcessingKeyEvent; - // current target offset of IME composition - uint32_t mCompositionTargetOffset; + struct Range + { + uint32_t mOffset; + uint32_t mLength; + + Range() + : mOffset(UINT32_MAX) + , mLength(UINT32_MAX) + { + } + + bool IsValid() const { return mOffset != UINT32_MAX; } + void Clear() + { + mOffset = UINT32_MAX; + mLength = UINT32_MAX; + } + }; + + // current target offset and length of IME composition + Range mCompositionTargetRange; // mCompositionState indicates current status of composition. enum eCompositionState { @@ -327,14 +346,11 @@ protected: const nsAString& aLastDispatchedData); /** - * Sets the offset's cursor position to IME. + * Move the candidate window with "fake" cursor position. * * @param aContext A GtkIMContext which is being handled. - * @param aTargetOffset Offset of a character which is anchor of - * a candidate window. This is offset in - * UTF-16 string. */ - void SetCursorPosition(GtkIMContext* aContext, uint32_t aTargetOffset); + void SetCursorPosition(GtkIMContext* aContext); // Queries the current selection offset of the window. uint32_t GetSelectionOffset(nsWindow* aWindow);