mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-01 05:48:26 +00:00
Bug 591047 - (5/7) Adding IME notification support to content fake widget; r=roc a=blocking-fennec
This commit is contained in:
parent
bc89960daa
commit
ae74ab03d0
@ -58,6 +58,7 @@ using nsTextEvent;
|
||||
using nsQueryContentEvent;
|
||||
using nsSelectionEvent;
|
||||
using RemoteDOMEvent;
|
||||
using nsIMEUpdatePreference;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -90,6 +91,69 @@ parent:
|
||||
sync SyncMessage(nsString aMessage, nsString aJSON)
|
||||
returns (nsString[] retval);
|
||||
|
||||
/**
|
||||
* Notifies chrome that there is a focus change involving an editable
|
||||
* object (input, textarea, document, contentEditable. etc.)
|
||||
*
|
||||
* focus PR_TRUE if editable object is receiving focus
|
||||
* PR_FALSE if losing focus
|
||||
* preference Native widget preference for IME updates
|
||||
*/
|
||||
sync NotifyIMEFocus(PRBool focus)
|
||||
returns (nsIMEUpdatePreference preference);
|
||||
|
||||
/**
|
||||
* Notifies chrome that there has been a change in text content
|
||||
* One call can encompass both a delete and an insert operation
|
||||
* Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
|
||||
*
|
||||
* offset Starting offset of the change
|
||||
* end Ending offset of the range deleted
|
||||
* newEnd New ending offset after insertion
|
||||
*
|
||||
* for insertion, offset == end
|
||||
* for deletion, offset == newEnd
|
||||
*/
|
||||
NotifyIMETextChange(PRUint32 offset, PRUint32 end, PRUint32 newEnd);
|
||||
|
||||
/**
|
||||
* Notifies chrome that there has been a change in selection
|
||||
* Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
|
||||
*
|
||||
* anchor Offset where the selection started
|
||||
* focus Offset where the caret is
|
||||
*/
|
||||
NotifyIMESelection(PRUint32 anchor, PRUint32 focus);
|
||||
|
||||
/**
|
||||
* Notifies chrome to refresh its text cache
|
||||
* Only called when NotifyIMEFocus returns PR_TRUE for mWantHints
|
||||
*
|
||||
* text The entire content of the text field
|
||||
*/
|
||||
NotifyIMETextHint(nsString text);
|
||||
|
||||
/**
|
||||
* Instructs chrome to end any pending composition
|
||||
*
|
||||
* cancel PR_TRUE if composition should be cancelled
|
||||
* composition Text to commit before ending the composition
|
||||
*
|
||||
* if cancel is PR_TRUE,
|
||||
* widget should return empty string for composition
|
||||
* if cancel is PR_FALSE,
|
||||
* widget should return the current composition text
|
||||
*/
|
||||
sync EndIMEComposition(PRBool cancel) returns (nsString composition);
|
||||
|
||||
sync GetIMEEnabled() returns (PRUint32 value);
|
||||
|
||||
SetIMEEnabled(PRUint32 value);
|
||||
|
||||
sync GetIMEOpenState() returns (PRBool value);
|
||||
|
||||
SetIMEOpenState(PRBool value);
|
||||
|
||||
PContentPermissionRequest(nsCString aType, URI uri);
|
||||
|
||||
PContentDialog(PRUint32 aType, nsCString aName, nsCString aFeatures,
|
||||
|
@ -311,6 +311,114 @@ TabParent::RecvAsyncMessage(const nsString& aMessage,
|
||||
return ReceiveMessage(aMessage, PR_FALSE, aJSON, nsnull);
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvNotifyIMEFocus(const PRBool& aFocus,
|
||||
nsIMEUpdatePreference* aPreference)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget)
|
||||
return true;
|
||||
|
||||
nsresult rv = widget->OnIMEFocusChange(aFocus);
|
||||
|
||||
if (aFocus) {
|
||||
if (NS_SUCCEEDED(rv) && rv != NS_SUCCESS_IME_NO_UPDATES) {
|
||||
*aPreference = widget->GetIMEUpdatePreference();
|
||||
} else {
|
||||
aPreference->mWantUpdates = PR_FALSE;
|
||||
aPreference->mWantHints = PR_FALSE;
|
||||
}
|
||||
} else {
|
||||
mIMECacheText.Truncate(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvNotifyIMETextChange(const PRUint32& aStart,
|
||||
const PRUint32& aEnd,
|
||||
const PRUint32& aNewEnd)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget)
|
||||
return true;
|
||||
|
||||
widget->OnIMETextChange(aStart, aEnd, aNewEnd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvNotifyIMESelection(const PRUint32& aAnchor,
|
||||
const PRUint32& aFocus)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget)
|
||||
return true;
|
||||
|
||||
widget->OnIMESelectionChange();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvNotifyIMETextHint(const nsString& aText)
|
||||
{
|
||||
// Replace our cache with new text
|
||||
mIMECacheText = aText;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvEndIMEComposition(const PRBool& aCancel,
|
||||
nsString* aComposition)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget)
|
||||
return true;
|
||||
|
||||
if (aCancel) {
|
||||
widget->CancelIMEComposition();
|
||||
} else {
|
||||
widget->ResetInputState();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvGetIMEEnabled(PRUint32* aValue)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (widget)
|
||||
widget->GetIMEEnabled(aValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvSetIMEEnabled(const PRUint32& aValue)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (widget)
|
||||
widget->SetIMEEnabled(aValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvGetIMEOpenState(PRBool* aValue)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (widget)
|
||||
widget->GetIMEOpenState(aValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvSetIMEOpenState(const PRBool& aValue)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (widget)
|
||||
widget->SetIMEOpenState(aValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::ReceiveMessage(const nsString& aMessage,
|
||||
PRBool aSync,
|
||||
@ -469,5 +577,19 @@ TabParent::GetFrameLoader() const
|
||||
return frameLoaderOwner ? frameLoaderOwner->GetFrameLoader() : nsnull;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIWidget>
|
||||
TabParent::GetWidget() const
|
||||
{
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
|
||||
if (!content)
|
||||
return nsnull;
|
||||
|
||||
nsIFrame *frame = content->GetPrimaryFrame();
|
||||
if (!frame)
|
||||
return nsnull;
|
||||
|
||||
return nsCOMPtr<nsIWidget>(frame->GetNearestWidget()).forget();
|
||||
}
|
||||
|
||||
} // namespace tabs
|
||||
} // namespace mozilla
|
||||
|
@ -91,6 +91,20 @@ public:
|
||||
nsTArray<nsString>* aJSONRetVal);
|
||||
virtual bool RecvAsyncMessage(const nsString& aMessage,
|
||||
const nsString& aJSON);
|
||||
virtual bool RecvNotifyIMEFocus(const PRBool& aFocus,
|
||||
nsIMEUpdatePreference* aPreference);
|
||||
virtual bool RecvNotifyIMETextChange(const PRUint32& aStart,
|
||||
const PRUint32& aEnd,
|
||||
const PRUint32& aNewEnd);
|
||||
virtual bool RecvNotifyIMESelection(const PRUint32& aAnchor,
|
||||
const PRUint32& aFocus);
|
||||
virtual bool RecvNotifyIMETextHint(const nsString& aText);
|
||||
virtual bool RecvEndIMEComposition(const PRBool& aCancel,
|
||||
nsString* aComposition);
|
||||
virtual bool RecvGetIMEEnabled(PRUint32* aValue);
|
||||
virtual bool RecvSetIMEEnabled(const PRUint32& aValue);
|
||||
virtual bool RecvGetIMEOpenState(PRBool* aValue);
|
||||
virtual bool RecvSetIMEOpenState(const PRBool& aValue);
|
||||
virtual PContentDialogParent* AllocPContentDialog(const PRUint32& aType,
|
||||
const nsCString& aName,
|
||||
const nsCString& aFeatures,
|
||||
@ -201,8 +215,12 @@ protected:
|
||||
nsString mSecurityTooltipText;
|
||||
nsCOMPtr<nsISupports> mSecurityStatusObject;
|
||||
|
||||
// IME
|
||||
nsString mIMECacheText;
|
||||
|
||||
private:
|
||||
already_AddRefed<nsFrameLoader> GetFrameLoader() const;
|
||||
already_AddRefed<nsIWidget> GetWidget() const;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -279,6 +279,24 @@ struct ParamTraits<nsSelectionEvent>
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<nsIMEUpdatePreference>
|
||||
{
|
||||
typedef nsIMEUpdatePreference paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mWantUpdates);
|
||||
WriteParam(aMsg, aParam.mWantHints);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
return ReadParam(aMsg, aIter, &aResult->mWantUpdates) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mWantHints);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // nsGUIEventIPC_h__
|
||||
|
@ -110,6 +110,8 @@ PuppetWidget::Create(nsIWidget *aParent,
|
||||
->CreateOffscreenSurface(gfxIntSize(1, 1),
|
||||
gfxASurface::ContentFromFormat(gfxASurface::ImageFormatARGB32));
|
||||
|
||||
mIMEComposing = PR_FALSE;
|
||||
|
||||
PuppetWidget* parent = static_cast<PuppetWidget*>(aParent);
|
||||
if (parent) {
|
||||
parent->SetChild(this);
|
||||
@ -272,7 +274,14 @@ PuppetWidget::DispatchEvent(nsGUIEvent* event, nsEventStatus& aStatus)
|
||||
|
||||
aStatus = nsEventStatus_eIgnore;
|
||||
if (mEventCallback) {
|
||||
if (event->message == NS_COMPOSITION_START) {
|
||||
mIMEComposing = PR_TRUE;
|
||||
}
|
||||
aStatus = (*mEventCallback)(event);
|
||||
|
||||
if (event->message == NS_COMPOSITION_END) {
|
||||
mIMEComposing = PR_FALSE;
|
||||
}
|
||||
} else if (mChild) {
|
||||
event->widget = mChild;
|
||||
mChild->DispatchEvent(event, aStatus);
|
||||
@ -296,6 +305,151 @@ PuppetWidget::GetThebesSurface()
|
||||
return mSurface;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PuppetWidget::IMEEndComposition(PRBool aCancel)
|
||||
{
|
||||
if (!mIMEComposing)
|
||||
return NS_OK;
|
||||
|
||||
nsEventStatus status;
|
||||
nsTextEvent textEvent(PR_TRUE, NS_TEXT_TEXT, this);
|
||||
InitEvent(textEvent, nsnull);
|
||||
if (!mTabChild ||
|
||||
!mTabChild->SendEndIMEComposition(aCancel, &textEvent.theText)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
DispatchEvent(&textEvent, status);
|
||||
|
||||
nsCompositionEvent compEvent(PR_TRUE, NS_COMPOSITION_END, this);
|
||||
InitEvent(compEvent, nsnull);
|
||||
DispatchEvent(&compEvent, status);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetWidget::ResetInputState()
|
||||
{
|
||||
return IMEEndComposition(PR_FALSE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetWidget::CancelComposition()
|
||||
{
|
||||
return IMEEndComposition(PR_TRUE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetWidget::SetIMEOpenState(PRBool aState)
|
||||
{
|
||||
if (mTabChild &&
|
||||
mTabChild->SendSetIMEOpenState(aState))
|
||||
return NS_OK;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetWidget::SetIMEEnabled(PRUint32 aState)
|
||||
{
|
||||
if (mTabChild &&
|
||||
mTabChild->SendSetIMEEnabled(aState))
|
||||
return NS_OK;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetWidget::GetIMEOpenState(PRBool *aState)
|
||||
{
|
||||
if (mTabChild &&
|
||||
mTabChild->SendGetIMEOpenState(aState))
|
||||
return NS_OK;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetWidget::GetIMEEnabled(PRUint32 *aState)
|
||||
{
|
||||
if (mTabChild &&
|
||||
mTabChild->SendGetIMEEnabled(aState))
|
||||
return NS_OK;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetWidget::OnIMEFocusChange(PRBool aFocus)
|
||||
{
|
||||
if (!mTabChild)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (aFocus) {
|
||||
nsEventStatus status;
|
||||
nsQueryContentEvent queryEvent(PR_TRUE, NS_QUERY_TEXT_CONTENT, this);
|
||||
InitEvent(queryEvent, nsnull);
|
||||
// Query entire content
|
||||
queryEvent.InitForQueryTextContent(0, PR_UINT32_MAX);
|
||||
DispatchEvent(&queryEvent, status);
|
||||
|
||||
if (queryEvent.mSucceeded) {
|
||||
mTabChild->SendNotifyIMETextHint(queryEvent.mReply.mString);
|
||||
}
|
||||
}
|
||||
|
||||
mIMEPreference.mWantUpdates = PR_FALSE;
|
||||
mIMEPreference.mWantHints = PR_FALSE;
|
||||
if (!mTabChild->SendNotifyIMEFocus(aFocus, &mIMEPreference))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (aFocus) {
|
||||
if (!mIMEPreference.mWantUpdates && !mIMEPreference.mWantHints)
|
||||
// call OnIMEFocusChange on blur but no other updates
|
||||
return NS_SUCCESS_IME_NO_UPDATES;
|
||||
OnIMESelectionChange(); // Update selection
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetWidget::OnIMETextChange(PRUint32 aStart, PRUint32 aEnd, PRUint32 aNewEnd)
|
||||
{
|
||||
if (!mTabChild)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (mIMEPreference.mWantHints) {
|
||||
nsEventStatus status;
|
||||
nsQueryContentEvent queryEvent(PR_TRUE, NS_QUERY_TEXT_CONTENT, this);
|
||||
InitEvent(queryEvent, nsnull);
|
||||
queryEvent.InitForQueryTextContent(0, PR_UINT32_MAX);
|
||||
DispatchEvent(&queryEvent, status);
|
||||
|
||||
if (queryEvent.mSucceeded) {
|
||||
mTabChild->SendNotifyIMETextHint(queryEvent.mReply.mString);
|
||||
}
|
||||
}
|
||||
if (mIMEPreference.mWantUpdates) {
|
||||
mTabChild->SendNotifyIMETextChange(aStart, aEnd, aNewEnd);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetWidget::OnIMESelectionChange(void)
|
||||
{
|
||||
if (!mTabChild)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (mIMEPreference.mWantUpdates) {
|
||||
nsEventStatus status;
|
||||
nsQueryContentEvent queryEvent(PR_TRUE, NS_QUERY_SELECTED_TEXT, this);
|
||||
InitEvent(queryEvent, nsnull);
|
||||
DispatchEvent(&queryEvent, status);
|
||||
|
||||
if (queryEvent.mSucceeded) {
|
||||
mTabChild->SendNotifyIMESelection(queryEvent.GetSelectionStart(),
|
||||
queryEvent.GetSelectionEnd());
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PuppetWidget::DispatchPaintEvent()
|
||||
{
|
||||
|
@ -168,12 +168,25 @@ public:
|
||||
// virtual nsIDeviceContext* GetDeviceContext();
|
||||
virtual gfxASurface* GetThebesSurface();
|
||||
|
||||
NS_IMETHOD ResetInputState();
|
||||
NS_IMETHOD SetIMEOpenState(PRBool aState);
|
||||
NS_IMETHOD GetIMEOpenState(PRBool *aState);
|
||||
NS_IMETHOD SetIMEEnabled(PRUint32 aState);
|
||||
NS_IMETHOD GetIMEEnabled(PRUint32 *aState);
|
||||
NS_IMETHOD CancelComposition();
|
||||
NS_IMETHOD OnIMEFocusChange(PRBool aFocus);
|
||||
NS_IMETHOD OnIMETextChange(PRUint32 aOffset, PRUint32 aEnd,
|
||||
PRUint32 aNewEnd);
|
||||
NS_IMETHOD OnIMESelectionChange(void);
|
||||
|
||||
private:
|
||||
nsresult DispatchPaintEvent();
|
||||
nsresult DispatchResizeEvent();
|
||||
|
||||
void SetChild(PuppetWidget* aChild);
|
||||
|
||||
nsresult IMEEndComposition(PRBool aCancel);
|
||||
|
||||
class PaintTask : public nsRunnable {
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
@ -200,6 +213,9 @@ private:
|
||||
// XXX/cjones: keeping this around until we teach LayerManager to do
|
||||
// retained-content-only transactions
|
||||
nsRefPtr<gfxASurface> mSurface;
|
||||
// IME
|
||||
nsIMEUpdatePreference mIMEPreference;
|
||||
PRPackedBool mIMEComposing;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
|
Loading…
x
Reference in New Issue
Block a user