diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 1caff32ba7f1..f2c944a626f4 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -234,6 +234,16 @@ parent: */ prio(urgent) async NotifyIMEEditorRect(nsIntRect rect); + /** + * Notifies chrome to position change + * + * editorRect Rect of current focused editor + * compositionRects Rects of current composition string + */ + prio(urgent) async NotifyIMEPositionChange(nsIntRect editorRect, + nsIntRect[] compositionRects, + nsIntRect caretRect); + /** * Instructs chrome to end any pending composition * diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index b187662a2a68..aab4d5d5cc83 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -1495,6 +1495,29 @@ TabParent::RecvNotifyIMEEditorRect(const nsIntRect& aRect) return true; } +bool +TabParent::RecvNotifyIMEPositionChange( + const nsIntRect& aEditorRect, + const InfallibleTArray& aCompositionRects, + const nsIntRect& aCaretRect) +{ + mIMEEditorRect = aEditorRect; + mIMECompositionRects = aCompositionRects; + mIMECaretRect = aCaretRect; + + nsCOMPtr widget = GetWidget(); + if (!widget) { + return true; + } + + const nsIMEUpdatePreference updatePreference = + widget->GetIMEUpdatePreference(); + if (updatePreference.WantPositionChanged()) { + widget->NotifyIME(IMENotification(NOTIFY_IME_OF_POSITION_CHANGE)); + } + return true; +} + bool TabParent::RecvRequestFocus(const bool& aCanRaise) { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 1d9f0ca1e6ac..d763a16a4ccd 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -179,6 +179,10 @@ public: virtual bool RecvNotifyIMEMouseButtonEvent(const widget::IMENotification& aEventMessage, bool* aConsumedByIME) MOZ_OVERRIDE; virtual bool RecvNotifyIMEEditorRect(const nsIntRect& aRect) MOZ_OVERRIDE; + virtual bool RecvNotifyIMEPositionChange( + const nsIntRect& aEditoRect, + const InfallibleTArray& aCompositionRects, + const nsIntRect& aCaretRect) MOZ_OVERRIDE; virtual bool RecvEndIMEComposition(const bool& aCancel, nsString* aComposition) MOZ_OVERRIDE; virtual bool RecvGetInputContext(int32_t* aIMEEnabled, diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp index 7aa6a7b43f77..b4e9fcaafbd4 100644 --- a/widget/PuppetWidget.cpp +++ b/widget/PuppetWidget.cpp @@ -448,6 +448,8 @@ PuppetWidget::NotifyIME(const IMENotification& aIMENotification) return NotifyIMEOfUpdateComposition(); case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT: return NotifyIMEOfMouseButtonEvent(aIMENotification); + case NOTIFY_IME_OF_POSITION_CHANGE: + return NotifyIMEOfPositionChange(); default: return NS_ERROR_NOT_IMPLEMENTED; } @@ -546,57 +548,110 @@ PuppetWidget::NotifyIMEOfUpdateComposition() NS_ENSURE_TRUE(mTabChild, NS_ERROR_FAILURE); - nsRefPtr textComposition = - IMEStateManager::GetTextCompositionFor(this); - NS_ENSURE_TRUE(textComposition, NS_ERROR_FAILURE); - - nsEventStatus status; - nsTArray textRectArray(textComposition->String().Length()); - uint32_t startOffset = textComposition->NativeOffsetOfStartComposition(); - uint32_t endOffset = textComposition->String().Length() + startOffset; - for (uint32_t i = startOffset; i < endOffset; i++) { - WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, this); - InitEvent(textRect, nullptr); - textRect.InitForQueryTextRect(i, 1); - DispatchEvent(&textRect, status); - NS_ENSURE_TRUE(textRect.mSucceeded, NS_ERROR_FAILURE); - - textRectArray.AppendElement(textRect.mReply.mRect); + uint32_t startOffset; + uint32_t targetCauseOffset; + nsAutoTArray textRectArray; + if (!GetCompositionRects(startOffset, + textRectArray, + targetCauseOffset)) { + return NS_ERROR_FAILURE; } - - uint32_t targetCauseOffset = textComposition->OffsetOfTargetClause(); - WidgetQueryContentEvent caretRect(true, NS_QUERY_CARET_RECT, this); - InitEvent(caretRect, nullptr); - caretRect.InitForQueryCaretRect(targetCauseOffset); - DispatchEvent(&caretRect, status); - NS_ENSURE_TRUE(caretRect.mSucceeded, NS_ERROR_FAILURE); + nsIntRect caretRect; + GetCaretRect(caretRect, targetCauseOffset); mTabChild->SendNotifyIMESelectedCompositionRect(startOffset, textRectArray, targetCauseOffset, - caretRect.mReply.mRect); + caretRect); return NS_OK; } +bool +PuppetWidget::GetCompositionRects(uint32_t& aStartOffset, + nsTArray& aTextRectArray, + uint32_t& aTargetCauseOffset) +{ + nsRefPtr textComposition = + IMEStateManager::GetTextCompositionFor(this); + NS_ENSURE_TRUE(textComposition, false); + + nsEventStatus status; + aTextRectArray.SetCapacity(textComposition->String().Length()); + aStartOffset = textComposition->NativeOffsetOfStartComposition(); + aTargetCauseOffset = textComposition->OffsetOfTargetClause(); + uint32_t endOffset = textComposition->String().Length() + aStartOffset; + for (uint32_t i = aStartOffset; i < endOffset; i++) { + WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, this); + InitEvent(textRect, nullptr); + textRect.InitForQueryTextRect(i, 1); + DispatchEvent(&textRect, status); + NS_ENSURE_TRUE(textRect.mSucceeded, false); + + aTextRectArray.AppendElement(textRect.mReply.mRect); + } + return true; +} + +uint32_t +PuppetWidget::GetCaretOffset() +{ + nsEventStatus status; + WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT, this); + InitEvent(selection, nullptr); + DispatchEvent(&selection, status); + NS_ENSURE_TRUE(selection.mSucceeded, 0); + + return selection.mReply.mOffset; +} + +bool +PuppetWidget::GetCaretRect(nsIntRect& aCaretRect, uint32_t aCaretOffset) +{ + nsEventStatus status; + WidgetQueryContentEvent caretRect(true, NS_QUERY_CARET_RECT, this); + InitEvent(caretRect, nullptr); + caretRect.InitForQueryCaretRect(aCaretOffset); + DispatchEvent(&caretRect, status); + NS_ENSURE_TRUE(caretRect.mSucceeded, false); + + aCaretRect = caretRect.mReply.mRect; + + return true; +} + nsresult PuppetWidget::NotifyIMEOfEditorRect() { #ifndef MOZ_CROSS_PROCESS_IME return NS_OK; #endif + if (NS_WARN_IF(!mTabChild)) { + return NS_ERROR_FAILURE; + } + nsIntRect rect; + if (!GetEditorRect(rect)) { + return NS_ERROR_FAILURE; + } + mTabChild->SendNotifyIMEEditorRect(rect); + return NS_OK; +} + +bool +PuppetWidget::GetEditorRect(nsIntRect& aRect) +{ nsEventStatus status; WidgetQueryContentEvent editorRectEvent(true, NS_QUERY_EDITOR_RECT, this); InitEvent(editorRectEvent); DispatchEvent(&editorRectEvent, status); - if (editorRectEvent.mSucceeded) { - mTabChild->SendNotifyIMEEditorRect(editorRectEvent.mReply.mRect); + if (NS_WARN_IF(!editorRectEvent.mSucceeded)) { + return false; } + aRect = editorRectEvent.mReply.mRect; - return NS_OK; + return true; } - nsIMEUpdatePreference PuppetWidget::GetIMEUpdatePreference() { @@ -604,7 +659,8 @@ PuppetWidget::GetIMEUpdatePreference() // e10s requires IME information cache into TabParent return nsIMEUpdatePreference(mIMEPreferenceOfParent.mWantUpdates | nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE | - nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE); + nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE | + nsIMEUpdatePreference::NOTIFY_POSITION_CHANGE ); #else // B2G doesn't handle IME as widget-level. return nsIMEUpdatePreference(); @@ -695,6 +751,40 @@ PuppetWidget::NotifyIMEOfMouseButtonEvent( return consumedByIME ? NS_SUCCESS_EVENT_CONSUMED : NS_OK; } +nsresult +PuppetWidget::NotifyIMEOfPositionChange() +{ +#ifndef MOZ_CROSS_PROCESS_IME + return NS_OK; +#endif + if (NS_WARN_IF(!mTabChild)) { + return NS_ERROR_FAILURE; + } + + nsIntRect editorRect; + if (!GetEditorRect(editorRect)) { + return NS_ERROR_FAILURE; + } + + uint32_t startOffset; + uint32_t targetCauseOffset; + nsAutoTArray textRectArray; + if (!GetCompositionRects(startOffset, + textRectArray, + targetCauseOffset)) { + // no composition string, get caret offset by NS_QUERY_SELECTED_TEXT + targetCauseOffset = GetCaretOffset(); + } + + nsIntRect caretRect; + GetCaretRect(caretRect, targetCauseOffset); + if (!mTabChild->SendNotifyIMEPositionChange(editorRect, textRectArray, + caretRect)) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + NS_IMETHODIMP PuppetWidget::SetCursor(nsCursor aCursor) { diff --git a/widget/PuppetWidget.h b/widget/PuppetWidget.h index f79cb37fc214..cd7c0d34975e 100644 --- a/widget/PuppetWidget.h +++ b/widget/PuppetWidget.h @@ -217,6 +217,14 @@ private: nsresult NotifyIMEOfTextChange(const IMENotification& aIMENotification); nsresult NotifyIMEOfMouseButtonEvent(const IMENotification& aIMENotification); nsresult NotifyIMEOfEditorRect(); + nsresult NotifyIMEOfPositionChange(); + + bool GetEditorRect(nsIntRect& aEditorRect); + bool GetCompositionRects(uint32_t& aStartOffset, + nsTArray& aRectArray, + uint32_t& aTargetCauseOffset); + bool GetCaretRect(nsIntRect& aCaretRect, uint32_t aCaretOffset); + uint32_t GetCaretOffset(); class PaintTask : public nsRunnable { public: