--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -583,16 +583,17 @@ GK_ATOM(modifiers, "modifiers")
GK_ATOM(monochrome, "monochrome")
GK_ATOM(mousedown, "mousedown")
GK_ATOM(mousemove, "mousemove")
GK_ATOM(mouseout, "mouseout")
GK_ATOM(mouseover, "mouseover")
GK_ATOM(mousethrough, "mousethrough")
GK_ATOM(mouseup, "mouseup")
GK_ATOM(moz_opaque, "moz-opaque")
+GK_ATOM(moz_action_hint, "mozactionhint")
GK_ATOM(x_moz_errormessage, "x-moz-errormessage")
GK_ATOM(msthemecompatible, "msthemecompatible")
GK_ATOM(multicol, "multicol")
GK_ATOM(multiple, "multiple")
GK_ATOM(name, "name")
GK_ATOM(_namespace, "namespace")
GK_ATOM(namespaceAlias, "namespace-alias")
GK_ATOM(namespaceUri, "namespace-uri")
--- a/content/events/src/nsIMEStateManager.cpp
+++ b/content/events/src/nsIMEStateManager.cpp
@@ -269,20 +269,24 @@ nsIMEStateManager::SetIMEState(PRUint32
if (aState & nsIContent::IME_STATUS_MASK_ENABLED) {
nsIWidget_MOZILLA_2_0_BRANCH* widget2 = static_cast<nsIWidget_MOZILLA_2_0_BRANCH*>(aWidget);
if (!widget2)
return;
PRUint32 state = nsContentUtils::GetWidgetStatusFromIMEStatus(aState);
IMEContext context;
context.mStatus = state;
-
- if (aContent && aContent->Tag() == nsGkAtoms::input) {
+
+ if (aContent && aContent->GetNameSpaceID() == kNameSpaceID_XHTML &&
+ (aContent->Tag() == nsGkAtoms::input ||
+ aContent->Tag() == nsGkAtoms::textarea)) {
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type,
context.mHTMLInputType);
+ aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint,
+ context.mActionHint);
}
widget2->SetInputMode(context);
nsContentUtils::AddScriptRunner(new IMEEnabledStateChangedEvent(state));
}
if (aState & nsIContent::IME_STATUS_MASK_OPENED) {
PRBool open = !!(aState & nsIContent::IME_STATUS_OPEN);
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -164,17 +164,17 @@ parent:
* 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);
- SetInputMode(PRUint32 value, nsString type);
+ SetInputMode(PRUint32 value, nsString type, nsString actionHint);
sync GetIMEOpenState() returns (PRBool value);
SetIMEOpenState(PRBool value);
PContentPermissionRequest(nsCString aType, URI uri);
PContentDialog(PRUint32 aType, nsCString aName, nsCString aFeatures,
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -490,27 +490,28 @@ TabParent::RecvGetIMEEnabled(PRUint32* a
if (widget2) {
widget2->GetInputMode(context);
*aValue = context.mStatus;
}
return true;
}
bool
-TabParent::RecvSetInputMode(const PRUint32& aValue, const nsString& aType)
+TabParent::RecvSetInputMode(const PRUint32& aValue, const nsString& aType, const nsString& aAction)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget || !AllowContentIME())
return true;
nsIWidget_MOZILLA_2_0_BRANCH* widget2 = static_cast<nsIWidget_MOZILLA_2_0_BRANCH*>(widget.get());
IMEContext context;
context.mStatus = aValue;
context.mHTMLInputType.Assign(aType);
+ context.mActionHint.Assign(aAction);
widget2->SetInputMode(context);
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
if (!observerService)
return true;
nsAutoString state;
state.AppendInt(aValue);
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -97,17 +97,17 @@ public:
const PRUint32& aNewEnd);
virtual bool RecvNotifyIMESelection(const PRUint32& aSeqno,
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 RecvSetInputMode(const PRUint32& aValue, const nsString& aType);
+ virtual bool RecvSetInputMode(const PRUint32& aValue, const nsString& aType, const nsString& aAction);
virtual bool RecvGetIMEOpenState(PRBool* aValue);
virtual bool RecvSetIMEOpenState(const PRBool& aValue);
virtual PContentDialogParent* AllocPContentDialog(const PRUint32& aType,
const nsCString& aName,
const nsCString& aFeatures,
const InfallibleTArray<int>& aIntParams,
const InfallibleTArray<nsString>& aStringParams);
virtual bool DeallocPContentDialog(PContentDialogParent* aDialog)
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -341,16 +341,21 @@ abstract public class GeckoApp
case KeyEvent.KEYCODE_DEL:
// See comments in GeckoInputConnection.onKeyDel
if (surfaceView != null &&
surfaceView.inputConnection != null &&
surfaceView.inputConnection.onKeyDel()) {
return true;
}
break;
+ case KeyEvent.KEYCODE_ENTER:
+ if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 &&
+ surfaceView.mIMEActionHint.equalsIgnoreCase("next"))
+ event = new KeyEvent(event.getAction(), KeyEvent.KEYCODE_TAB);
+ break;
default:
break;
}
// KeyListener returns true if it handled the event for us.
if (GeckoApp.surfaceView.mIMEState == GeckoSurfaceView.IME_STATE_DISABLED ||
keyCode == KeyEvent.KEYCODE_ENTER ||
!GeckoApp.surfaceView.mKeyListener.onKeyDown(GeckoApp.surfaceView, GeckoApp.surfaceView.mEditable, keyCode, event))
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -251,24 +251,26 @@ class GeckoAppShell
case NOTIFY_IME_FOCUSCHANGE:
GeckoApp.surfaceView.mIMEFocus = state != 0;
IMEStateUpdater.resetIME();
break;
}
}
- public static void notifyIMEEnabled(int state, String hint) {
+ public static void notifyIMEEnabled(int state, String typeHint,
+ String actionHint) {
if (GeckoApp.surfaceView == null)
return;
/* When IME is 'disabled', IME processing is disabled.
In addition, the IME UI is hidden */
GeckoApp.surfaceView.mIMEState = state;
- GeckoApp.surfaceView.mIMEHint = hint;
+ GeckoApp.surfaceView.mIMETypeHint = typeHint;
+ GeckoApp.surfaceView.mIMEActionHint = actionHint;
IMEStateUpdater.enableIME();
}
public static void notifyIMEChange(String text, int start, int end, int newEnd) {
if (GeckoApp.surfaceView == null ||
GeckoApp.surfaceView.inputConnection == null)
return;
--- a/embedding/android/GeckoSurfaceView.java
+++ b/embedding/android/GeckoSurfaceView.java
@@ -82,17 +82,18 @@ class GeckoSurfaceView
mBufferWidth = 0;
mBufferHeight = 0;
mSurfaceLock = new ReentrantLock();
mEditableFactory = Editable.Factory.getInstance();
setupEditable("");
mIMEState = IME_STATE_DISABLED;
- mIMEHint = "";
+ mIMETypeHint = "";
+ mIMEActionHint = "";
}
protected void finalize() throws Throwable {
super.finalize();
}
/*
* Called on main thread
@@ -291,38 +292,50 @@ class GeckoSurfaceView
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
outAttrs.imeOptions = EditorInfo.IME_ACTION_GO;
mKeyListener = TextKeyListener.getInstance();
if (mIMEState == IME_STATE_PASSWORD)
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_PASSWORD;
- else if (mIMEHint.equalsIgnoreCase("url"))
+ else if (mIMETypeHint.equalsIgnoreCase("url"))
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_URI;
- else if (mIMEHint.equalsIgnoreCase("email"))
+ else if (mIMETypeHint.equalsIgnoreCase("email"))
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
- else if (mIMEHint.equalsIgnoreCase("search"))
+ else if (mIMETypeHint.equalsIgnoreCase("search"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_SEARCH;
- else if (mIMEHint.equalsIgnoreCase("tel"))
+ else if (mIMETypeHint.equalsIgnoreCase("tel"))
outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
- else if (mIMEHint.equalsIgnoreCase("number") ||
- mIMEHint.equalsIgnoreCase("range"))
+ else if (mIMETypeHint.equalsIgnoreCase("number") ||
+ mIMETypeHint.equalsIgnoreCase("range"))
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER;
- else if (mIMEHint.equalsIgnoreCase("datetime") ||
- mIMEHint.equalsIgnoreCase("datetime-local"))
+ else if (mIMETypeHint.equalsIgnoreCase("datetime") ||
+ mIMETypeHint.equalsIgnoreCase("datetime-local"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_NORMAL;
- else if (mIMEHint.equalsIgnoreCase("date"))
+ else if (mIMETypeHint.equalsIgnoreCase("date"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_DATE;
- else if (mIMEHint.equalsIgnoreCase("time"))
+ else if (mIMETypeHint.equalsIgnoreCase("time"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_TIME;
+ if (mIMEActionHint.equalsIgnoreCase("go"))
+ outAttrs.imeOptions = EditorInfo.IME_ACTION_GO;
+ else if (mIMEActionHint.equalsIgnoreCase("done"))
+ outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE;
+ else if (mIMEActionHint.equalsIgnoreCase("next"))
+ outAttrs.imeOptions = EditorInfo.IME_ACTION_NEXT;
+ else if (mIMEActionHint.equalsIgnoreCase("search"))
+ outAttrs.imeOptions = EditorInfo.IME_ACTION_SEARCH;
+ else if (mIMEActionHint.equalsIgnoreCase("send"))
+ outAttrs.imeOptions = EditorInfo.IME_ACTION_SEND;
+ else
+ outAttrs.actionLabel = mIMEActionHint;
inputConnection.reset();
return inputConnection;
}
public void setupEditable(String contents)
{
mEditable = mEditableFactory.newEditable(contents);
mEditable.setSpan(inputConnection, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
@@ -399,17 +412,18 @@ class GeckoSurfaceView
public static final int IME_STATE_PASSWORD = 2;
GeckoInputConnection inputConnection;
KeyListener mKeyListener;
Editable mEditable;
Editable.Factory mEditableFactory;
boolean mIMEFocus;
int mIMEState;
- String mIMEHint;
+ String mIMETypeHint;
+ String mIMEActionHint;
// Software rendering
ByteBuffer mSoftwareBuffer;
Bitmap mSoftwareBitmap;
final SynchronousQueue<ByteBuffer> mSyncBuf = new SynchronousQueue<ByteBuffer>();
}
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -64,17 +64,17 @@
<children includes="image|deck|stack|box">
<xul:image class="autocomplete-icon" allowevents="true"/>
</children>
<xul:hbox anonid="textbox-input-box" class="textbox-input-box" flex="1" xbl:inherits="tooltiptext=inputtooltiptext">
<children/>
<html:input anonid="input" class="autocomplete-textbox textbox-input"
flex="1" allowevents="true"
- xbl:inherits="tooltiptext=inputtooltiptext,onfocus,onblur,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey"/>
+ xbl:inherits="tooltiptext=inputtooltiptext,onfocus,onblur,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,mozactionhint"/>
</xul:hbox>
<children includes="hbox"/>
</xul:hbox>
<xul:dropmarker anonid="historydropmarker" class="autocomplete-history-dropmarker"
allowevents="true"
xbl:inherits="open,enablehistory,parentfocused=focused"/>
--- a/toolkit/content/widgets/textbox.xml
+++ b/toolkit/content/widgets/textbox.xml
@@ -16,17 +16,17 @@
<stylesheet src="chrome://global/content/textbox.css"/>
<stylesheet src="chrome://global/skin/textbox.css"/>
</resources>
<content>
<children/>
<xul:hbox class="textbox-input-box" flex="1" xbl:inherits="context,spellcheck">
<html:input class="textbox-input" flex="1" anonid="input"
- xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,noinitialfocus"/>
+ xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,noinitialfocus,mozactionhint"/>
</xul:hbox>
</content>
<implementation implements="nsIAccessibleProvider, nsIDOMXULTextBoxElement, nsIDOMXULLabeledControlElement">
<property name="accessibleType" readonly="true">
<getter>
<![CDATA[
return Components.interfaces.nsIAccessibleProvider.XULTextBox;
@@ -302,18 +302,18 @@
</handler>
</handlers>
</binding>
<binding id="search-textbox" extends="chrome://global/content/bindings/textbox.xml#textbox">
<content>
<children/>
<xul:hbox class="textbox-input-box" flex="1" xbl:inherits="context,spellcheck" align="center">
- <html:input class="textbox-input" flex="1" anonid="input"
- xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey"/>
+ <html:input class="textbox-input" flex="1" anonid="input" mozactionhint="search"
+ xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,mozactionhint"/>
<xul:deck class="textbox-search-icons" anonid="search-icons">
<xul:image class="textbox-search-icon"
onclick="document.getBindingParent(this)._iconClick();"
xbl:inherits="src=image,searchbutton,disabled"/>
<xul:image class="textbox-search-clear"
onclick="document.getBindingParent(this)._clearSearch();"
xbl:inherits="disabled"/>
</xul:deck>
@@ -430,17 +430,17 @@
</handler>
</handlers>
</binding>
<binding id="textarea" extends="chrome://global/content/bindings/textbox.xml#textbox">
<content>
<xul:hbox class="textbox-input-box" flex="1" xbl:inherits="context,spellcheck">
<html:textarea class="textbox-textarea" flex="1" anonid="input"
- xbl:inherits="onfocus,onblur,xbl:text=value,disabled,tabindex,rows,cols,readonly,wrap,placeholder"><children/></html:textarea>
+ xbl:inherits="onfocus,onblur,xbl:text=value,disabled,tabindex,rows,cols,readonly,wrap,placeholder,mozactionhint"><children/></html:textarea>
</xul:hbox>
</content>
</binding>
<binding id="input-box">
<content context="_child">
<children/>
<xul:menupopup anonid="input-box-contextmenu"
--- a/widget/public/nsIWidget.h
+++ b/widget/public/nsIWidget.h
@@ -238,16 +238,19 @@ struct nsIMEUpdatePreference {
* Contains IMEStatus plus information about the current
* input context that the IME can use as hints if desired.
*/
struct IMEContext {
PRUint32 mStatus;
/* The type of the input if the input is a html input field */
nsString mHTMLInputType;
+
+ /* A hint for the action that is performed when the input is submitted */
+ nsString mActionHint;
};
/**
* The base class for all the widgets. It provides the interface for
* all basic and necessary functionality.
*/
class nsIWidget : public nsISupports {
--- a/widget/src/android/AndroidBridge.cpp
+++ b/widget/src/android/AndroidBridge.cpp
@@ -93,17 +93,17 @@ AndroidBridge::Init(JNIEnv *jEnv,
jEnv->GetJavaVM(&mJavaVM);
mJNIEnv = nsnull;
mThread = nsnull;
mGeckoAppShellClass = (jclass) jEnv->NewGlobalRef(jGeckoAppShellClass);
jNotifyIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIME", "(II)V");
- jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;)V");
+ jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;Ljava/lang/String;)V");
jNotifyIMEChange = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V");
jEnableAccelerometer = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableAccelerometer", "(Z)V");
jEnableLocation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocation", "(Z)V");
jReturnIMEQueryResult = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "returnIMEQueryResult", "(Ljava/lang/String;II)V");
jScheduleRestart = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "scheduleRestart", "()V");
jNotifyAppShellReady = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "onAppShellReady", "()V");
jNotifyXreExit = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "onXreExit", "()V");
jGetHandlersForMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getHandlersForMimeType", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;");
@@ -206,27 +206,30 @@ void
AndroidBridge::NotifyIME(int aType, int aState)
{
if (sBridge)
JNI()->CallStaticVoidMethod(sBridge->mGeckoAppShellClass,
sBridge->jNotifyIME, aType, aState);
}
void
-AndroidBridge::NotifyIMEEnabled(int aState, const nsAString& aHint)
+AndroidBridge::NotifyIMEEnabled(int aState, const nsAString& aTypeHint,
+ const nsAString& aActionHint)
{
if (!sBridge)
return;
- nsPromiseFlatString hint(aHint);
+ nsPromiseFlatString typeHint(aTypeHint);
+ nsPromiseFlatString actionHint(aActionHint);
- jvalue args[2];
+ jvalue args[3];
AutoLocalJNIFrame jniFrame(1);
args[0].i = aState;
- args[1].l = JNI()->NewString(hint.get(), hint.Length());
+ args[1].l = JNI()->NewString(typeHint.get(), typeHint.Length());
+ args[2].l = JNI()->NewString(actionHint.get(), actionHint.Length());
JNI()->CallStaticVoidMethodA(sBridge->mGeckoAppShellClass,
sBridge->jNotifyIMEEnabled, args);
}
void
AndroidBridge::NotifyIMEChange(const PRUnichar *aText, PRUint32 aTextLen,
int aStart, int aEnd, int aNewEnd)
{
--- a/widget/src/android/AndroidBridge.h
+++ b/widget/src/android/AndroidBridge.h
@@ -101,17 +101,18 @@ public:
// SetMainThread.
PRBool SetMainThread(void *thr);
JNIEnv* AttachThread(PRBool asDaemon = PR_TRUE);
/* These are all implemented in Java */
static void NotifyIME(int aType, int aState);
- static void NotifyIMEEnabled(int aState, const nsAString& aHint);
+ static void NotifyIMEEnabled(int aState, const nsAString& aTypeHint,
+ const nsAString& aActionHint);
static void NotifyIMEChange(const PRUnichar *aText, PRUint32 aTextLen, int aStart, int aEnd, int aNewEnd);
void EnableAccelerometer(bool aEnable);
void EnableLocation(bool aEnable);
void ReturnIMEQueryResult(const PRUnichar *aResult, PRUint32 aLen, int aSelStart, int aSelLen);
--- a/widget/src/android/nsWindow.cpp
+++ b/widget/src/android/nsWindow.cpp
@@ -1646,17 +1646,17 @@ nsWindow::ResetInputState()
}
NS_IMETHODIMP
nsWindow::SetInputMode(const IMEContext& aContext)
{
ALOGIME("IME: SetInputMode: s=%d", aContext.mStatus);
mIMEContext = aContext;
- AndroidBridge::NotifyIMEEnabled(int(aContext.mStatus), aContext.mHTMLInputType);
+ AndroidBridge::NotifyIMEEnabled(int(aContext.mStatus), aContext.mHTMLInputType, aContext.mActionHint);
return NS_OK;
}
NS_IMETHODIMP
nsWindow::GetInputMode(IMEContext& aContext)
{
aContext = mIMEContext;
return NS_OK;
--- a/widget/src/xpwidgets/PuppetWidget.cpp
+++ b/widget/src/xpwidgets/PuppetWidget.cpp
@@ -368,17 +368,17 @@ PuppetWidget::SetIMEOpenState(PRBool aSt
return NS_OK;
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
PuppetWidget::SetInputMode(const IMEContext& aContext)
{
if (mTabChild &&
- mTabChild->SendSetInputMode(aContext.mStatus, aContext.mHTMLInputType))
+ mTabChild->SendSetInputMode(aContext.mStatus, aContext.mHTMLInputType, aContext.mActionHint))
return NS_OK;
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
PuppetWidget::GetIMEOpenState(PRBool *aState)
{
if (mTabChild &&