Bug 1343075 - Use GeckoEditableSupport from PuppetWidget; r=masayuki r=rbarker r=snorp r=esawin

Bug 1343075 - 1a. Add TextEventDispatcherListener::GetIMEUpdatePreference; r=masayuki

Add a GetIMEUpdatePreference method to TextEventDispatcherListener to
optionally control which IME notifications are received by NotifyIME.
This patch also makes nsBaseWidget forward its GetIMEUpdatePreference
call to the widget's native TextEventDispatcherListener.

Bug 1343075 - 1b. Implement GetIMEUpdatePreference for all TextEventDispatcherListener; r=masayuki

This patch implements GetIMEUpdatePreference for all
TextEventDispatcherListener implementations, by moving previous
implementations of nsIWidget::GetIMEUpdatePreference.

Bug 1343075 - 2. Allow setting a PuppetWidget's native TextEventDispatcherListener; r=masayuki

In PuppetWidget, add getter and setter for the widget's native
TextEventDispatcherListener. This allows overriding of PuppetWidget's
default IME handling. For example, on Android, the PuppetWidget's native
TextEventDispatcherListener will communicate directly with Java IME code
in the main process.

Bug 1343075 - 3. Add AIDL interface for main process; r=rbarker

Add AIDL definition and implementation for an interface for the main
process that child processes can access.

Bug 1343075 - 4. Set Gecko thread JNIEnv for child process; r=snorp

Add a JNIEnv* parameter to XRE_SetAndroidChildFds, which is used to set
the Gecko thread JNIEnv for child processes. XRE_SetAndroidChildFds is
the only Android-specific entry point for child processes, so I think
it's the most logical place to initialize JNI.

Bug 1343075 - 5. Support multiple remote GeckoEditableChild; r=esawin

Support remote GeckoEditableChild instances that are created in the
content processes and connect to the parent process GeckoEditableParent
through binders.

Support having multiple GeckoEditableChild instances in GeckoEditable by
keeping track of which child is currently focused, and only allow
calls to/from the focused child by using access tokens.

Bug 1343075 - 6. Add method to get GeckoEditableParent instance; r=esawin

Add IProcessManager.getEditableParent, which a content process can call
to get the GeckoEditableParent instance that corresponds to a given
content process tab, from the main process.

Bug 1343075 - 7. Support GeckoEditableSupport in content processes; r=esawin

Support creating and running GeckoEditableSupport attached to a
PuppetWidget in content processes.

Because we don't know PuppetWidget's lifetime as well as nsWindow's,
when attached to PuppetWidget, we need to attach/detach our native
object on focus/blur, respectively.

Bug 1343075 - 8. Connect GeckoEditableSupport on PuppetWidget creation; r=esawin

Listen to the "tab-child-created" notification and attach our content
process GeckoEditableSupport to the new PuppetWidget.

Bug 1343075 - 9. Update auto-generated bindings; r=me
This commit is contained in:
Jim Chen
2017-03-07 22:34:39 -05:00
parent 9175d429d9
commit 0911a44f43
46 changed files with 632 additions and 151 deletions

View File

@@ -698,6 +698,13 @@ TextInputProcessor::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
} }
} }
NS_IMETHODIMP_(nsIMEUpdatePreference)
TextInputProcessor::GetIMEUpdatePreference()
{
// TextInputProcessor::NotifyIME does not require extra change notifications.
return nsIMEUpdatePreference();
}
NS_IMETHODIMP_(void) NS_IMETHODIMP_(void)
TextInputProcessor::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) TextInputProcessor::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher)
{ {

View File

@@ -32,6 +32,9 @@ public:
// TextEventDispatcherListener // TextEventDispatcherListener
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher, NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
const IMENotification& aNotification) override; const IMENotification& aNotification) override;
NS_IMETHOD_(nsIMEUpdatePreference) GetIMEUpdatePreference() override;
NS_IMETHOD_(void) NS_IMETHOD_(void)
OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) override; OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) override;

View File

@@ -579,6 +579,7 @@ GECKOVIEW_AIDLS = \
org/mozilla/gecko/IGeckoEditableChild.aidl \ org/mozilla/gecko/IGeckoEditableChild.aidl \
org/mozilla/gecko/IGeckoEditableParent.aidl \ org/mozilla/gecko/IGeckoEditableParent.aidl \
org/mozilla/gecko/process/IChildProcess.aidl \ org/mozilla/gecko/process/IChildProcess.aidl \
org/mozilla/gecko/process/IProcessManager.aidl \
$(NULL) $(NULL)
geckoview_aidl_src_path := $(topsrcdir)/mobile/android/geckoview/src/main/aidl geckoview_aidl_src_path := $(topsrcdir)/mobile/android/geckoview/src/main/aidl

View File

@@ -1191,4 +1191,5 @@ gvjar.sources += ['generated/org/mozilla/gecko/' + x for x in [
'IGeckoEditableChild.java', 'IGeckoEditableChild.java',
'IGeckoEditableParent.java', 'IGeckoEditableParent.java',
'process/IChildProcess.java', 'process/IChildProcess.java',
'process/IProcessManager.java',
]] ]]

View File

@@ -4,6 +4,7 @@
package org.mozilla.gecko; package org.mozilla.gecko;
import android.os.IBinder;
import android.view.KeyEvent; import android.view.KeyEvent;
import org.mozilla.gecko.IGeckoEditableChild; import org.mozilla.gecko.IGeckoEditableChild;
@@ -11,20 +12,21 @@ import org.mozilla.gecko.IGeckoEditableChild;
// Interface for GeckoEditable calls from child to parent // Interface for GeckoEditable calls from child to parent
interface IGeckoEditableParent { interface IGeckoEditableParent {
// Notify an IME event of a type defined in GeckoEditableListener. // Notify an IME event of a type defined in GeckoEditableListener.
void notifyIME(int type); void notifyIME(IGeckoEditableChild child, int type);
// Notify a change in editor state or type. // Notify a change in editor state or type.
void notifyIMEContext(int state, String typeHint, String modeHint, String actionHint); void notifyIMEContext(int state, String typeHint, String modeHint, String actionHint);
// Notify a change in editor selection. // Notify a change in editor selection.
void onSelectionChange(int start, int end); void onSelectionChange(IBinder token, int start, int end);
// Notify a change in editor text. // Notify a change in editor text.
void onTextChange(in CharSequence text, int start, int unboundedOldEnd); void onTextChange(IBinder token, in CharSequence text,
int start, int unboundedOldEnd);
// Perform the default action associated with a key event. // Perform the default action associated with a key event.
void onDefaultKeyEvent(in KeyEvent event); void onDefaultKeyEvent(IBinder token, in KeyEvent event);
// Update the screen location of current composition. // Update the screen location of current composition.
void updateCompositionRects(in RectF[] rects); void updateCompositionRects(IBinder token, in RectF[] rects);
} }

View File

@@ -3,10 +3,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.process; package org.mozilla.gecko.process;
import org.mozilla.gecko.process.IProcessManager;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
interface IChildProcess { interface IChildProcess {
void stop(); void stop();
int getPid(); int getPid();
void start(in String[] args, in ParcelFileDescriptor crashReporterPfd, in ParcelFileDescriptor ipcPfd); void start(in IProcessManager procMan, in String[] args, in ParcelFileDescriptor crashReporterPfd, in ParcelFileDescriptor ipcPfd);
} }

View File

@@ -0,0 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.process;
import org.mozilla.gecko.IGeckoEditableParent;
interface IProcessManager {
IGeckoEditableParent getEditableParent(long contentId, long tabId);
}

View File

@@ -19,6 +19,7 @@ import org.mozilla.gecko.util.ThreadUtils.AssertBehavior;
import android.graphics.RectF; import android.graphics.RectF;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.RemoteException; import android.os.RemoteException;
import android.text.Editable; import android.text.Editable;
@@ -61,7 +62,11 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
private Handler mIcRunHandler; private Handler mIcRunHandler;
private Handler mIcPostHandler; private Handler mIcPostHandler;
/* package */ IGeckoEditableChild mEditableChild; // Parent process child used as a default for key events.
/* package */ IGeckoEditableChild mDefaultChild; // Used by IC thread.
// Parent or content process child that has the focus.
/* package */ IGeckoEditableChild mFocusedChild; // Used by IC thread.
/* package */ IBinder mFocusedToken; // Used by Gecko/binder thread.
/* package */ GeckoEditableListener mListener; /* package */ GeckoEditableListener mListener;
/* package */ GeckoView mView; /* package */ GeckoView mView;
@@ -71,7 +76,6 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
private boolean mNeedUpdateComposition; // Used by IC thread private boolean mNeedUpdateComposition; // Used by IC thread
private boolean mSuppressKeyUp; // Used by IC thread private boolean mSuppressKeyUp; // Used by IC thread
private boolean mGeckoFocused; // Used by Gecko thread
private boolean mIgnoreSelectionChange; // Used by Gecko thread private boolean mIgnoreSelectionChange; // Used by Gecko thread
private static final int IME_RANGE_CARETPOSITION = 1; private static final int IME_RANGE_CARETPOSITION = 1;
@@ -92,8 +96,9 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
private static final int IME_RANGE_BACKCOLOR = 4; private static final int IME_RANGE_BACKCOLOR = 4;
private static final int IME_RANGE_LINECOLOR = 8; private static final int IME_RANGE_LINECOLOR = 8;
private void onKeyEvent(KeyEvent event, int action, int savedMetaState, private void onKeyEvent(final IGeckoEditableChild child, KeyEvent event, int action,
boolean isSynthesizedImeKey) throws RemoteException { int savedMetaState, boolean isSynthesizedImeKey)
throws RemoteException {
// Use a separate action argument so we can override the key's original action, // Use a separate action argument so we can override the key's original action,
// e.g. change ACTION_MULTIPLE to ACTION_DOWN. That way we don't have to allocate // e.g. change ACTION_MULTIPLE to ACTION_DOWN. That way we don't have to allocate
// a new key event just to change its action field. // a new key event just to change its action field.
@@ -117,7 +122,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
final int keyPressMetaState = (unicodeChar >= ' ' && final int keyPressMetaState = (unicodeChar >= ' ' &&
unicodeChar != unmodifiedUnicodeChar) ? unmodifiedMetaState : metaState; unicodeChar != unmodifiedUnicodeChar) ? unmodifiedMetaState : metaState;
mEditableChild.onKeyEvent(action, event.getKeyCode(), event.getScanCode(), child.onKeyEvent(action, event.getKeyCode(), event.getScanCode(),
metaState, keyPressMetaState, event.getEventTime(), metaState, keyPressMetaState, event.getEventTime(),
domPrintableKeyValue, event.getRepeatCount(), event.getFlags(), domPrintableKeyValue, event.getRepeatCount(), event.getFlags(),
isSynthesizedImeKey, event); isSynthesizedImeKey, event);
@@ -167,34 +172,26 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
public synchronized void currentReplace(final int start, final int end, public synchronized void currentReplace(final int start, final int end,
final CharSequence newText) { final CharSequence newText) {
if (DEBUG) { // On Gecko or binder thread.
ThreadUtils.assertOnGeckoThread();
}
mCurrentText.replace(start, end, newText); mCurrentText.replace(start, end, newText);
addCurrentChangeLocked(start, end, start + newText.length()); addCurrentChangeLocked(start, end, start + newText.length());
} }
public synchronized void currentSetSelection(final int start, final int end) { public synchronized void currentSetSelection(final int start, final int end) {
if (DEBUG) { // On Gecko or binder thread.
ThreadUtils.assertOnGeckoThread();
}
Selection.setSelection(mCurrentText, start, end); Selection.setSelection(mCurrentText, start, end);
mCurrentSelectionChanged = true; mCurrentSelectionChanged = true;
} }
public synchronized void currentSetSpan(final Object obj, final int start, public synchronized void currentSetSpan(final Object obj, final int start,
final int end, final int flags) { final int end, final int flags) {
if (DEBUG) { // On Gecko or binder thread.
ThreadUtils.assertOnGeckoThread();
}
mCurrentText.setSpan(obj, start, end, flags); mCurrentText.setSpan(obj, start, end, flags);
addCurrentChangeLocked(start, end, end); addCurrentChangeLocked(start, end, end);
} }
public synchronized void currentRemoveSpan(final Object obj) { public synchronized void currentRemoveSpan(final Object obj) {
if (DEBUG) { // On Gecko or binder thread.
ThreadUtils.assertOnGeckoThread();
}
if (obj == null) { if (obj == null) {
mCurrentText.clearSpans(); mCurrentText.clearSpans();
addCurrentChangeLocked(0, mCurrentText.length(), mCurrentText.length()); addCurrentChangeLocked(0, mCurrentText.length(), mCurrentText.length());
@@ -212,9 +209,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
// Return Spanned instead of Editable because the returned object is supposed to // Return Spanned instead of Editable because the returned object is supposed to
// be read-only. Editing should be done through one of the current*** methods. // be read-only. Editing should be done through one of the current*** methods.
public Spanned getCurrentText() { public Spanned getCurrentText() {
if (DEBUG) { // On Gecko or binder thread.
ThreadUtils.assertOnGeckoThread();
}
return mCurrentText; return mCurrentText;
} }
@@ -438,8 +433,8 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
getConstantName(Action.class, "TYPE_", action.mType) + ")"); getConstantName(Action.class, "TYPE_", action.mType) + ")");
} }
if (mListener == null) { if (mFocusedChild == null || mListener == null) {
// We haven't initialized or we've been destroyed. // We haven't been focused or initialized, or we've been destroyed.
return; return;
} }
@@ -458,7 +453,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
switch (action.mType) { switch (action.mType) {
case Action.TYPE_EVENT: case Action.TYPE_EVENT:
case Action.TYPE_SET_HANDLER: case Action.TYPE_SET_HANDLER:
mEditableChild.onImeSynchronize(); mFocusedChild.onImeSynchronize();
break; break;
case Action.TYPE_SET_SPAN: case Action.TYPE_SET_SPAN:
@@ -472,7 +467,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
action.mSpanObject == Selection.SELECTION_START || action.mSpanObject == Selection.SELECTION_START ||
action.mSpanObject == Selection.SELECTION_END); action.mSpanObject == Selection.SELECTION_END);
mEditableChild.onImeSynchronize(); mFocusedChild.onImeSynchronize();
break; break;
case Action.TYPE_REMOVE_SPAN: case Action.TYPE_REMOVE_SPAN:
@@ -482,7 +477,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
mNeedUpdateComposition |= (flags & Spanned.SPAN_INTERMEDIATE) == 0 && mNeedUpdateComposition |= (flags & Spanned.SPAN_INTERMEDIATE) == 0 &&
(flags & Spanned.SPAN_COMPOSING) != 0; (flags & Spanned.SPAN_COMPOSING) != 0;
mEditableChild.onImeSynchronize(); mFocusedChild.onImeSynchronize();
break; break;
case Action.TYPE_REPLACE_TEXT: case Action.TYPE_REPLACE_TEXT:
@@ -498,7 +493,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
sendCharKeyEvents(action); sendCharKeyEvents(action);
} }
mText.shadowReplace(action.mStart, action.mEnd, action.mSequence); mText.shadowReplace(action.mStart, action.mEnd, action.mSequence);
mEditableChild.onImeReplaceText( mFocusedChild.onImeReplaceText(
action.mStart, action.mEnd, action.mSequence.toString()); action.mStart, action.mEnd, action.mSequence.toString());
break; break;
@@ -548,7 +543,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
if (DEBUG) { if (DEBUG) {
Log.d(LOGTAG, "sending: " + event); Log.d(LOGTAG, "sending: " + event);
} }
onKeyEvent(event, event.getAction(), onKeyEvent(mFocusedChild, event, event.getAction(),
/* metaState */ 0, /* isSynthesizedImeKey */ true); /* metaState */ 0, /* isSynthesizedImeKey */ true);
} }
} }
@@ -575,7 +570,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
@WrapForJNI(calledFrom = "gecko") @WrapForJNI(calledFrom = "gecko")
private void setDefaultEditableChild(final IGeckoEditableChild child) { private void setDefaultEditableChild(final IGeckoEditableChild child) {
mEditableChild = child; mDefaultChild = child;
} }
@WrapForJNI(calledFrom = "gecko") @WrapForJNI(calledFrom = "gecko")
@@ -701,7 +696,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
if (found) { if (found) {
icSendComposition(text, selStart, selEnd, composingStart, composingEnd); icSendComposition(text, selStart, selEnd, composingStart, composingEnd);
if (notifyGecko) { if (notifyGecko) {
mEditableChild.onImeUpdateComposition(composingStart, composingEnd); mFocusedChild.onImeUpdateComposition(composingStart, composingEnd);
} }
return true; return true;
} }
@@ -709,7 +704,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
if (notifyGecko) { if (notifyGecko) {
// Set the selection by using a composition without ranges // Set the selection by using a composition without ranges
mEditableChild.onImeUpdateComposition(selStart, selEnd); mFocusedChild.onImeUpdateComposition(selStart, selEnd);
} }
if (DEBUG) { if (DEBUG) {
@@ -733,7 +728,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
} }
if (selEnd >= composingStart && selEnd <= composingEnd) { if (selEnd >= composingStart && selEnd <= composingEnd) {
mEditableChild.onImeAddCompositionRange( mFocusedChild.onImeAddCompositionRange(
selEnd - composingStart, selEnd - composingStart, selEnd - composingStart, selEnd - composingStart,
IME_RANGE_CARETPOSITION, 0, 0, false, 0, 0, 0); IME_RANGE_CARETPOSITION, 0, 0, false, 0, 0, 0);
} }
@@ -806,7 +801,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
rangeBackColor = tp.bgColor; rangeBackColor = tp.bgColor;
} }
} }
mEditableChild.onImeAddCompositionRange( mFocusedChild.onImeAddCompositionRange(
rangeStart - composingStart, rangeEnd - composingStart, rangeStart - composingStart, rangeEnd - composingStart,
rangeType, rangeStyles, rangeLineStyle, rangeBoldLine, rangeType, rangeStyles, rangeLineStyle, rangeBoldLine,
rangeForeColor, rangeBackColor, rangeLineColor); rangeForeColor, rangeBackColor, rangeLineColor);
@@ -838,8 +833,17 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
event-type action, and update the shadow text accordingly. event-type action, and update the shadow text accordingly.
*/ */
try { try {
if (mFocusedChild == null) {
// Not focused; send simple key event to chrome window.
onKeyEvent(mDefaultChild, event, action, metaState,
/* isSynthesizedImeKey */ false);
return;
}
// Focused; key event may go to chrome window or to content window.
icMaybeSendComposition(); icMaybeSendComposition();
onKeyEvent(event, action, metaState, /* isSynthesizedImeKey */ false); onKeyEvent(mFocusedChild, event, action, metaState,
/* isSynthesizedImeKey */ false);
icOfferAction(new Action(Action.TYPE_EVENT)); icOfferAction(new Action(Action.TYPE_EVENT));
} catch (final RemoteException e) { } catch (final RemoteException e) {
Log.e(LOGTAG, "Remote call failed", e); Log.e(LOGTAG, "Remote call failed", e);
@@ -952,16 +956,16 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
@Override // GeckoEditableClient @Override // GeckoEditableClient
public void requestCursorUpdates(int requestMode) { public void requestCursorUpdates(int requestMode) {
try { try {
mEditableChild.onImeRequestCursorUpdates(requestMode); if (mFocusedChild != null) {
mFocusedChild.onImeRequestCursorUpdates(requestMode);
}
} catch (final RemoteException e) { } catch (final RemoteException e) {
Log.e(LOGTAG, "Remote call failed", e); Log.e(LOGTAG, "Remote call failed", e);
} }
} }
private void geckoSetIcHandler(final Handler newHandler) { private void geckoSetIcHandler(final Handler newHandler) {
if (DEBUG) { // On Gecko or binder thread.
ThreadUtils.assertOnGeckoThread();
}
mIcPostHandler.post(new Runnable() { // posting to old IC thread mIcPostHandler.post(new Runnable() { // posting to old IC thread
@Override @Override
public void run() { public void run() {
@@ -980,13 +984,10 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
private void geckoActionReply(final Action action) { private void geckoActionReply(final Action action) {
// On Gecko or binder thread. // On Gecko or binder thread.
if (!mGeckoFocused) { if (action == null) {
if (DEBUG) { Log.w(LOGTAG, "Mismatched reply");
Log.d(LOGTAG, "discarding stale reply");
}
return; return;
} }
if (DEBUG) { if (DEBUG) {
Log.d(LOGTAG, "reply: Action(" + Log.d(LOGTAG, "reply: Action(" +
getConstantName(Action.class, "TYPE_", action.mType) + ")"); getConstantName(Action.class, "TYPE_", action.mType) + ")");
@@ -1015,8 +1016,18 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
} }
} }
private synchronized boolean binderCheckToken(final IBinder token,
final boolean allowNull) {
// Verify that we're getting an IME notification from the currently focused child.
if (mFocusedToken == token || (mFocusedToken == null && allowNull)) {
return true;
}
Log.w(LOGTAG, "Invalid token");
return false;
}
@Override // IGeckoEditableParent @Override // IGeckoEditableParent
public void notifyIME(final int type) { public void notifyIME(final IGeckoEditableChild child, final int type) {
// On Gecko or binder thread. // On Gecko or binder thread.
if (DEBUG) { if (DEBUG) {
// NOTIFY_IME_REPLY_EVENT is logged separately, inside geckoActionReply() // NOTIFY_IME_REPLY_EVENT is logged separately, inside geckoActionReply()
@@ -1027,7 +1038,32 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
} }
} }
if (type == GeckoEditableListener.NOTIFY_IME_REPLY_EVENT) { final IBinder token = child.asBinder();
if (type == GeckoEditableListener.NOTIFY_IME_OF_TOKEN) {
synchronized (this) {
if (mFocusedToken != null && mFocusedToken != token &&
mFocusedToken.pingBinder()) {
// Focused child already exists and is alive.
Log.w(LOGTAG, "Already focused");
return;
}
mFocusedToken = token;
return;
}
} else if (type == GeckoEditableListener.NOTIFY_IME_OPEN_VKB) {
// Always from parent process.
ThreadUtils.assertOnGeckoThread();
} else if (!binderCheckToken(token, /* allowNull */ false)) {
return;
}
if (type == GeckoEditableListener.NOTIFY_IME_OF_BLUR) {
synchronized (this) {
onTextChange(token, "", 0, Integer.MAX_VALUE);
mActions.clear();
mFocusedToken = null;
}
} else if (type == GeckoEditableListener.NOTIFY_IME_REPLY_EVENT) {
geckoActionReply(mActions.poll()); geckoActionReply(mActions.poll());
if (!mActions.isEmpty()) { if (!mActions.isEmpty()) {
// Only post to IC thread below when the queue is empty. // Only post to IC thread below when the queue is empty.
@@ -1046,8 +1082,11 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
} }
if (type == GeckoEditableListener.NOTIFY_IME_OF_FOCUS && mListener != null) { if (type == GeckoEditableListener.NOTIFY_IME_OF_FOCUS && mListener != null) {
mFocusedChild = child;
mNeedSync = false; mNeedSync = false;
mText.syncShadowText(/* listener */ null); mText.syncShadowText(/* listener */ null);
} else if (type == GeckoEditableListener.NOTIFY_IME_OF_BLUR) {
mFocusedChild = null;
} }
if (mListener != null) { if (mListener != null) {
@@ -1055,18 +1094,11 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
} }
} }
}); });
// Update the mGeckoFocused flag.
if (type == GeckoEditableListener.NOTIFY_IME_OF_BLUR) {
mGeckoFocused = false;
} else if (type == GeckoEditableListener.NOTIFY_IME_OF_FOCUS) {
mGeckoFocused = true;
}
} }
@Override // IGeckoEditableParent @Override // IGeckoEditableParent
public void notifyIMEContext(final int state, final String typeHint, public void notifyIMEContext(final int state, final String typeHint,
final String modeHint, final String actionHint) { final String modeHint, final String actionHint) {
// On Gecko or binder thread. // On Gecko or binder thread.
if (DEBUG) { if (DEBUG) {
Log.d(LOGTAG, "notifyIMEContext(" + Log.d(LOGTAG, "notifyIMEContext(" +
@@ -1074,6 +1106,10 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
", \"" + typeHint + "\", \"" + modeHint + "\", \"" + actionHint + "\")"); ", \"" + typeHint + "\", \"" + modeHint + "\", \"" + actionHint + "\")");
} }
// Don't check token for notifyIMEContext, because the calls all come
// from the parent process.
ThreadUtils.assertOnGeckoThread();
mIcPostHandler.post(new Runnable() { mIcPostHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -1086,12 +1122,17 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
} }
@Override // IGeckoEditableParent @Override // IGeckoEditableParent
public void onSelectionChange(final int start, final int end) { public void onSelectionChange(final IBinder token,
final int start, final int end) {
// On Gecko or binder thread. // On Gecko or binder thread.
if (DEBUG) { if (DEBUG) {
Log.d(LOGTAG, "onSelectionChange(" + start + ", " + end + ")"); Log.d(LOGTAG, "onSelectionChange(" + start + ", " + end + ")");
} }
if (!binderCheckToken(token, /* allowNull */ false)) {
return;
}
if (mIgnoreSelectionChange) { if (mIgnoreSelectionChange) {
mIgnoreSelectionChange = false; mIgnoreSelectionChange = false;
} else { } else {
@@ -1112,8 +1153,8 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
} }
@Override // IGeckoEditableParent @Override // IGeckoEditableParent
public void onTextChange(final CharSequence text, final int start, public void onTextChange(final IBinder token, final CharSequence text,
final int unboundedOldEnd) { final int start, final int unboundedOldEnd) {
// On Gecko or binder thread. // On Gecko or binder thread.
if (DEBUG) { if (DEBUG) {
StringBuilder sb = new StringBuilder("onTextChange("); StringBuilder sb = new StringBuilder("onTextChange(");
@@ -1122,6 +1163,10 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
Log.d(LOGTAG, sb.toString()); Log.d(LOGTAG, sb.toString());
} }
if (!binderCheckToken(token, /* allowNull */ false)) {
return;
}
final int currentLength = mText.getCurrentText().length(); final int currentLength = mText.getCurrentText().length();
final int oldEnd = unboundedOldEnd > currentLength ? currentLength : unboundedOldEnd; final int oldEnd = unboundedOldEnd > currentLength ? currentLength : unboundedOldEnd;
final int newEnd = start + text.length(); final int newEnd = start + text.length();
@@ -1227,7 +1272,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
} }
@Override // IGeckoEditableParent @Override // IGeckoEditableParent
public void onDefaultKeyEvent(final KeyEvent event) { public void onDefaultKeyEvent(final IBinder token, final KeyEvent event) {
// On Gecko or binder thread. // On Gecko or binder thread.
if (DEBUG) { if (DEBUG) {
StringBuilder sb = new StringBuilder("onDefaultKeyEvent("); StringBuilder sb = new StringBuilder("onDefaultKeyEvent(");
@@ -1239,6 +1284,11 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
Log.d(LOGTAG, sb.toString()); Log.d(LOGTAG, sb.toString());
} }
// Allow default key processing even if we're not focused.
if (!binderCheckToken(token, /* allowNull */ true)) {
return;
}
mIcPostHandler.post(new Runnable() { mIcPostHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -1251,12 +1301,16 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
} }
@Override // IGeckoEditableParent @Override // IGeckoEditableParent
public void updateCompositionRects(final RectF[] rects) { public void updateCompositionRects(final IBinder token, final RectF[] rects) {
// On Gecko or binder thread. // On Gecko or binder thread.
if (DEBUG) { if (DEBUG) {
Log.d(LOGTAG, "updateCompositionRects(rects.length = " + rects.length + ")"); Log.d(LOGTAG, "updateCompositionRects(rects.length = " + rects.length + ")");
} }
if (!binderCheckToken(token, /* allowNull */ false)) {
return;
}
mIcPostHandler.post(new Runnable() { mIcPostHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {

View File

@@ -26,13 +26,65 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
private static final String LOGTAG = "GeckoEditableChild"; private static final String LOGTAG = "GeckoEditableChild";
private final class RemoteChild extends IGeckoEditableChild.Stub {
@Override // IGeckoEditableChild
public void onKeyEvent(int action, int keyCode, int scanCode, int metaState,
int keyPressMetaState, long time, int domPrintableKeyValue,
int repeatCount, int flags, boolean isSynthesizedImeKey,
KeyEvent event) {
GeckoEditableChild.this.onKeyEvent(
action, keyCode, scanCode, metaState, keyPressMetaState, time,
domPrintableKeyValue, repeatCount, flags, isSynthesizedImeKey, event);
}
@Override // IGeckoEditableChild
public void onImeSynchronize() {
GeckoEditableChild.this.onImeSynchronize();
}
@Override // IGeckoEditableChild
public void onImeReplaceText(int start, int end, String text) {
GeckoEditableChild.this.onImeReplaceText(start, end, text);
}
@Override // IGeckoEditableChild
public void onImeAddCompositionRange(int start, int end, int rangeType,
int rangeStyles, int rangeLineStyle,
boolean rangeBoldLine, int rangeForeColor,
int rangeBackColor, int rangeLineColor) {
GeckoEditableChild.this.onImeAddCompositionRange(
start, end, rangeType, rangeStyles, rangeLineStyle, rangeBoldLine,
rangeForeColor, rangeBackColor, rangeLineColor);
}
@Override // IGeckoEditableChild
public void onImeUpdateComposition(int start, int end) {
GeckoEditableChild.this.onImeUpdateComposition(start, end);
}
@Override // IGeckoEditableChild
public void onImeRequestCursorUpdates(int requestMode) {
GeckoEditableChild.this.onImeRequestCursorUpdates(requestMode);
}
}
private final IGeckoEditableParent mEditableParent; private final IGeckoEditableParent mEditableParent;
private final IGeckoEditableChild mEditableChild;
private int mCurrentTextLength; // Used by Gecko thread private int mCurrentTextLength; // Used by Gecko thread
@WrapForJNI(calledFrom = "gecko") @WrapForJNI(calledFrom = "gecko")
/* package */ GeckoEditableChild(final IGeckoEditableParent editableParent) { /* package */ GeckoEditableChild(final IGeckoEditableParent editableParent) {
mEditableParent = editableParent; mEditableParent = editableParent;
final IBinder binder = editableParent.asBinder();
if (binder.queryLocalInterface(IGeckoEditableParent.class.getName()) != null) {
// IGeckoEditableParent is local; i.e. we're in the main process.
mEditableChild = this;
} else {
// IGeckoEditableParent is remote; i.e. we're in a content process.
mEditableChild = new RemoteChild();
}
} }
@WrapForJNI(dispatchTo = "proxy") @Override // IGeckoEditableChild @WrapForJNI(dispatchTo = "proxy") @Override // IGeckoEditableChild
@@ -67,7 +119,8 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
@Override // IInterface @Override // IInterface
public IBinder asBinder() { public IBinder asBinder() {
return null; // Return the GeckoEditableParent's binder as our binder for comparison purposes.
return mEditableParent.asBinder();
} }
@WrapForJNI(calledFrom = "gecko") @WrapForJNI(calledFrom = "gecko")
@@ -92,7 +145,7 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
} }
try { try {
mEditableParent.notifyIME(type); mEditableParent.notifyIME(mEditableChild, type);
} catch (final RemoteException e) { } catch (final RemoteException e) {
Log.e(LOGTAG, "Remote call failed", e); Log.e(LOGTAG, "Remote call failed", e);
return; return;
@@ -130,7 +183,7 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
throw new IllegalArgumentException("invalid selection notification range"); throw new IllegalArgumentException("invalid selection notification range");
} }
mEditableParent.onSelectionChange(start, end); mEditableParent.onSelectionChange(mEditableChild.asBinder(), start, end);
} }
@WrapForJNI(calledFrom = "gecko", exceptionMode = "ignore") @WrapForJNI(calledFrom = "gecko", exceptionMode = "ignore")
@@ -166,7 +219,7 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
mCurrentTextLength += start + text.length() - oldEnd; mCurrentTextLength += start + text.length() - oldEnd;
// Need unboundedOldEnd so GeckoEditable can distinguish changed text vs cleared text. // Need unboundedOldEnd so GeckoEditable can distinguish changed text vs cleared text.
mEditableParent.onTextChange(text, start, unboundedOldEnd); mEditableParent.onTextChange(mEditableChild.asBinder(), text, start, unboundedOldEnd);
} }
@WrapForJNI(calledFrom = "gecko") @WrapForJNI(calledFrom = "gecko")
@@ -184,7 +237,7 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
} }
try { try {
mEditableParent.onDefaultKeyEvent(event); mEditableParent.onDefaultKeyEvent(mEditableChild.asBinder(), event);
} catch (final RemoteException e) { } catch (final RemoteException e) {
Log.e(LOGTAG, "Remote call failed", e); Log.e(LOGTAG, "Remote call failed", e);
} }
@@ -199,7 +252,7 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
} }
try { try {
mEditableParent.updateCompositionRects(rects); mEditableParent.updateCompositionRects(mEditableChild.asBinder(), rects);
} catch (final RemoteException e) { } catch (final RemoteException e) {
Log.e(LOGTAG, "Remote call failed", e); Log.e(LOGTAG, "Remote call failed", e);
} }

View File

@@ -17,6 +17,8 @@ import android.view.KeyEvent;
interface GeckoEditableListener { interface GeckoEditableListener {
// IME notification type for notifyIME(), corresponding to NotificationToIME enum in Gecko // IME notification type for notifyIME(), corresponding to NotificationToIME enum in Gecko
@WrapForJNI @WrapForJNI
int NOTIFY_IME_OF_TOKEN = -3;
@WrapForJNI
int NOTIFY_IME_OPEN_VKB = -2; int NOTIFY_IME_OPEN_VKB = -2;
@WrapForJNI @WrapForJNI
int NOTIFY_IME_REPLY_EVENT = -1; int NOTIFY_IME_REPLY_EVENT = -1;

View File

@@ -141,15 +141,16 @@ public class GeckoThread extends Thread {
private boolean mDebugging; private boolean mDebugging;
// Child process parameters // Child process parameters
private int mCrashFileDescriptor; private int mCrashFileDescriptor = -1;
private int mIPCFileDescriptor; private int mIPCFileDescriptor = -1;
GeckoThread() { GeckoThread() {
setName("Gecko"); setName("Gecko");
} }
private boolean isChildProcess() { @WrapForJNI
return mIPCFileDescriptor != -1; private static boolean isChildProcess() {
return INSTANCE.mIPCFileDescriptor != -1;
} }
private synchronized boolean init(final GeckoProfile profile, final String[] args, private synchronized boolean init(final GeckoProfile profile, final String[] args,

View File

@@ -5,6 +5,8 @@
package org.mozilla.gecko.process; package org.mozilla.gecko.process;
import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.IGeckoEditableParent;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.mozglue.GeckoLoader; import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils;
@@ -25,7 +27,7 @@ import java.util.Collections;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.Map; import java.util.Map;
public final class GeckoProcessManager { public final class GeckoProcessManager extends IProcessManager.Stub {
private static final String LOGTAG = "GeckoProcessManager"; private static final String LOGTAG = "GeckoProcessManager";
private static final GeckoProcessManager INSTANCE = new GeckoProcessManager(); private static final GeckoProcessManager INSTANCE = new GeckoProcessManager();
@@ -33,6 +35,15 @@ public final class GeckoProcessManager {
return INSTANCE; return INSTANCE;
} }
@WrapForJNI(stubName = "GetEditableParent")
private static native IGeckoEditableParent nativeGetEditableParent(long contentId,
long tabId);
@Override // IProcessManager
public IGeckoEditableParent getEditableParent(final long contentId, final long tabId) {
return nativeGetEditableParent(contentId, tabId);
}
private static final class ChildConnection implements ServiceConnection, IBinder.DeathRecipient { private static final class ChildConnection implements ServiceConnection, IBinder.DeathRecipient {
public final String mType; public final String mType;
private boolean mWait = false; private boolean mWait = false;
@@ -150,7 +161,7 @@ public final class GeckoProcessManager {
crashPfd = ParcelFileDescriptor.fromFd(crashFd); crashPfd = ParcelFileDescriptor.fromFd(crashFd);
} }
ParcelFileDescriptor ipcPfd = ParcelFileDescriptor.fromFd(ipcFd); ParcelFileDescriptor ipcPfd = ParcelFileDescriptor.fromFd(ipcFd);
connection.mChild.start(args, crashPfd, ipcPfd); connection.mChild.start(this, args, crashPfd, ipcPfd);
if (crashPfd != null) { if (crashPfd != null) {
crashPfd.close(); crashPfd.close();
} }

View File

@@ -6,7 +6,9 @@
package org.mozilla.gecko.process; package org.mozilla.gecko.process;
import org.mozilla.gecko.annotation.JNITarget; import org.mozilla.gecko.annotation.JNITarget;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.IGeckoEditableParent;
import org.mozilla.gecko.mozglue.GeckoLoader; import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.GeckoThread; import org.mozilla.gecko.GeckoThread;
import org.mozilla.gecko.mozglue.SafeIntent; import org.mozilla.gecko.mozglue.SafeIntent;
@@ -18,23 +20,35 @@ import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.Process; import android.os.Process;
import android.os.RemoteException;
import android.util.Log; import android.util.Log;
public class GeckoServiceChildProcess extends Service { public class GeckoServiceChildProcess extends Service {
static private String LOGTAG = "GeckoServiceChildProcess"; static private String LOGTAG = "GeckoServiceChildProcess";
private boolean serviceStarted; private static IProcessManager sProcessManager;
static private void stop() { static private void stop() {
ThreadUtils.postToUiThread(new Runnable() { ThreadUtils.postToUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
Process.killProcess(Process.myPid());; Process.killProcess(Process.myPid());
} }
}); });
} }
@WrapForJNI(calledFrom = "gecko")
private static IGeckoEditableParent getEditableParent(final long contentId,
final long tabId) {
try {
return sProcessManager.getEditableParent(contentId, tabId);
} catch (final RemoteException e) {
Log.e(LOGTAG, "Cannot get editable", e);
return null;
}
}
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
} }
@@ -59,14 +73,16 @@ public class GeckoServiceChildProcess extends Service {
} }
@Override @Override
public void start(final String[] args, public void start(final IProcessManager procMan,
final String[] args,
final ParcelFileDescriptor crashReporterPfd, final ParcelFileDescriptor crashReporterPfd,
final ParcelFileDescriptor ipcPfd) { final ParcelFileDescriptor ipcPfd) {
if (serviceStarted) { if (sProcessManager != null) {
Log.e(LOGTAG, "Attempting to start a service that has already been started."); Log.e(LOGTAG, "Attempting to start a service that has already been started.");
return; return;
} }
serviceStarted = true; sProcessManager = procMan;
final int crashReporterFd = crashReporterPfd != null ? crashReporterPfd.detachFd() : -1; final int crashReporterFd = crashReporterPfd != null ? crashReporterPfd.detachFd() : -1;
final int ipcFd = ipcPfd != null ? ipcPfd.detachFd() : -1; final int ipcFd = ipcPfd != null ? ipcPfd.detachFd() : -1;
ThreadUtils.postToUiThread(new Runnable() { ThreadUtils.postToUiThread(new Runnable() {

View File

@@ -435,7 +435,7 @@ Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jo
gBootstrap->GeckoStart(jenv, argv, argc, sAppData); gBootstrap->GeckoStart(jenv, argv, argc, sAppData);
ElfLoader::Singleton.ExpectShutdown(true); ElfLoader::Singleton.ExpectShutdown(true);
} else { } else {
gBootstrap->XRE_SetAndroidChildFds(crashFd, ipcFd); gBootstrap->XRE_SetAndroidChildFds(jenv, crashFd, ipcFd);
gBootstrap->XRE_SetProcessType(argv[argc - 1]); gBootstrap->XRE_SetProcessType(argv[argc - 1]);
XREChildData childData; XREChildData childData;

View File

@@ -74,8 +74,8 @@ public:
::GeckoStart(aEnv, argv, argc, aAppData); ::GeckoStart(aEnv, argv, argc, aAppData);
} }
virtual void XRE_SetAndroidChildFds(int aCrashFd, int aIPCFd) override { virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aCrashFd, int aIPCFd) override {
::XRE_SetAndroidChildFds(aCrashFd, aIPCFd); ::XRE_SetAndroidChildFds(aEnv, aCrashFd, aIPCFd);
} }
#endif #endif

View File

@@ -113,7 +113,7 @@ public:
#ifdef MOZ_WIDGET_ANDROID #ifdef MOZ_WIDGET_ANDROID
virtual void GeckoStart(JNIEnv* aEnv, char** argv, int argc, const StaticXREAppData& aAppData) = 0; virtual void GeckoStart(JNIEnv* aEnv, char** argv, int argc, const StaticXREAppData& aAppData) = 0;
virtual void XRE_SetAndroidChildFds(int aCrashFd, int aIPCFd) = 0; virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aCrashFd, int aIPCFd) = 0;
#endif #endif
#ifdef LIBFUZZER #ifdef LIBFUZZER

View File

@@ -52,6 +52,7 @@
#include "chrome/common/child_process.h" #include "chrome/common/child_process.h"
#if defined(MOZ_WIDGET_ANDROID) #if defined(MOZ_WIDGET_ANDROID)
#include "chrome/common/ipc_channel.h" #include "chrome/common/ipc_channel.h"
#include "mozilla/jni/Utils.h"
#endif // defined(MOZ_WIDGET_ANDROID) #endif // defined(MOZ_WIDGET_ANDROID)
#include "mozilla/ipc/BrowserProcessSubThread.h" #include "mozilla/ipc/BrowserProcessSubThread.h"
@@ -239,8 +240,9 @@ GeckoProcessType sChildProcessType = GeckoProcessType_Default;
#if defined(MOZ_WIDGET_ANDROID) #if defined(MOZ_WIDGET_ANDROID)
void void
XRE_SetAndroidChildFds (int crashFd, int ipcFd) XRE_SetAndroidChildFds (JNIEnv* env, int crashFd, int ipcFd)
{ {
mozilla::jni::SetGeckoThreadEnv(env);
#if defined(MOZ_CRASHREPORTER) #if defined(MOZ_CRASHREPORTER)
CrashReporter::SetNotificationPipeForChild(crashFd); CrashReporter::SetNotificationPipeForChild(crashFd);
#endif // defined(MOZ_CRASHREPORTER) #endif // defined(MOZ_CRASHREPORTER)

View File

@@ -693,6 +693,11 @@ PuppetWidget::RequestIMEToCommitComposition(bool aCancel)
nsresult nsresult
PuppetWidget::NotifyIMEInternal(const IMENotification& aIMENotification) PuppetWidget::NotifyIMEInternal(const IMENotification& aIMENotification)
{ {
if (mNativeTextEventDispatcherListener) {
// Use mNativeTextEventDispatcherListener for IME notifications.
return NS_ERROR_NOT_IMPLEMENTED;
}
switch (aIMENotification.mMessage) { switch (aIMENotification.mMessage) {
case REQUEST_TO_COMMIT_COMPOSITION: case REQUEST_TO_COMMIT_COMPOSITION:
return RequestIMEToCommitComposition(false); return RequestIMEToCommitComposition(false);
@@ -857,6 +862,11 @@ PuppetWidget::NotifyIMEOfCompositionUpdate(
nsIMEUpdatePreference nsIMEUpdatePreference
PuppetWidget::GetIMEUpdatePreference() PuppetWidget::GetIMEUpdatePreference()
{ {
if (mNativeTextEventDispatcherListener) {
// Use mNativeTextEventDispatcherListener for IME preference.
return mNativeTextEventDispatcherListener->GetIMEUpdatePreference();
}
// e10s requires IME content cache in in the TabParent for handling query // e10s requires IME content cache in in the TabParent for handling query
// content event only with the parent process. Therefore, this process // content event only with the parent process. Therefore, this process
// needs to receive a lot of information from the focused editor to sent // needs to receive a lot of information from the focused editor to sent

View File

@@ -26,6 +26,7 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/ContentCache.h" #include "mozilla/ContentCache.h"
#include "mozilla/EventForwards.h" #include "mozilla/EventForwards.h"
#include "mozilla/TextEventDispatcherListener.h"
namespace mozilla { namespace mozilla {
@@ -183,6 +184,10 @@ public:
virtual InputContext GetInputContext() override; virtual InputContext GetInputContext() override;
virtual NativeIMEContext GetNativeIMEContext() override; virtual NativeIMEContext GetNativeIMEContext() override;
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override; virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
TextEventDispatcherListener* GetNativeTextEventDispatcherListener() override
{ return mNativeTextEventDispatcherListener; }
void SetNativeTextEventDispatcherListener(TextEventDispatcherListener* aListener)
{ mNativeTextEventDispatcherListener = aListener; }
virtual void SetCursor(nsCursor aCursor) override; virtual void SetCursor(nsCursor aCursor) override;
virtual nsresult SetCursor(imgIContainer* aCursor, virtual nsresult SetCursor(imgIContainer* aCursor,
@@ -376,6 +381,8 @@ private:
nsCOMArray<nsIKeyEventInPluginCallback> mKeyEventInPluginCallbacks; nsCOMArray<nsIKeyEventInPluginCallback> mKeyEventInPluginCallbacks;
RefPtr<TextEventDispatcherListener> mNativeTextEventDispatcherListener;
protected: protected:
bool mEnabled; bool mEnabled;
bool mVisible; bool mVisible;

View File

@@ -7,6 +7,8 @@
#include "nsWeakReference.h" #include "nsWeakReference.h"
struct nsIMEUpdatePreference;
namespace mozilla { namespace mozilla {
namespace widget { namespace widget {
@@ -30,6 +32,11 @@ public:
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher, NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
const IMENotification& aNotification) = 0; const IMENotification& aNotification) = 0;
/**
* Returns preference for which IME notification are received by NotifyIME().
*/
NS_IMETHOD_(nsIMEUpdatePreference) GetIMEUpdatePreference() = 0;
/** /**
* OnRemovedFrom() is called when the TextEventDispatcher stops working and * OnRemovedFrom() is called when the TextEventDispatcher stops working and
* is releasing the listener. * is releasing the listener.

View File

@@ -8,6 +8,7 @@
#include "AndroidRect.h" #include "AndroidRect.h"
#include "KeyEvent.h" #include "KeyEvent.h"
#include "PuppetWidget.h"
#include "android_npapi.h" #include "android_npapi.h"
#include "nsIContent.h" #include "nsIContent.h"
#include "nsISelection.h" #include "nsISelection.h"
@@ -391,7 +392,7 @@ GeckoEditableSupport::RemoveComposition(RemoveCompositionFlag aFlag)
nsEventStatus status = nsEventStatus_eIgnore; nsEventStatus status = nsEventStatus_eIgnore;
NS_ENSURE_SUCCESS_VOID(mDispatcher->BeginNativeInputTransaction()); NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(mDispatcher));
mDispatcher->CommitComposition( mDispatcher->CommitComposition(
status, aFlag == CANCEL_IME_COMPOSITION ? &EmptyString() : nullptr); status, aFlag == CANCEL_IME_COMPOSITION ? &EmptyString() : nullptr);
} }
@@ -442,7 +443,7 @@ GeckoEditableSupport::OnKeyEvent(int32_t aAction, int32_t aKeyCode,
mIMEKeyEvents.AppendElement(UniquePtr<WidgetEvent>(event.Duplicate())); mIMEKeyEvents.AppendElement(UniquePtr<WidgetEvent>(event.Duplicate()));
} else { } else {
RemoveComposition(); RemoveComposition();
NS_ENSURE_SUCCESS_VOID(dispatcher->BeginNativeInputTransaction()); NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(dispatcher));
dispatcher->DispatchKeyboardEvent(msg, event, status); dispatcher->DispatchKeyboardEvent(msg, event, status);
if (widget->Destroyed() || status == nsEventStatus_eConsumeNoDefault) { if (widget->Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
// Skip default processing. // Skip default processing.
@@ -463,6 +464,12 @@ GeckoEditableSupport::OnKeyEvent(int32_t aAction, int32_t aKeyCode,
if (aIsSynthesizedImeKey) { if (aIsSynthesizedImeKey) {
mIMEKeyEvents.AppendElement( mIMEKeyEvents.AppendElement(
UniquePtr<WidgetEvent>(pressEvent.Duplicate())); UniquePtr<WidgetEvent>(pressEvent.Duplicate()));
} else if (nsIWidget::UsePuppetWidgets()) {
AutoCacheNativeKeyCommands autoCache(
static_cast<PuppetWidget*>(widget.get()));
// Don't use native key bindings.
autoCache.CacheNoCommands();
dispatcher->MaybeDispatchKeypressEvents(pressEvent, status);
} else { } else {
dispatcher->MaybeDispatchKeypressEvents(pressEvent, status); dispatcher->MaybeDispatchKeypressEvents(pressEvent, status);
} }
@@ -482,7 +489,7 @@ GeckoEditableSupport::SendIMEDummyKeyEvent(nsIWidget* aWidget, EventMessage msg)
WidgetKeyboardEvent event(true, msg, aWidget); WidgetKeyboardEvent event(true, msg, aWidget);
event.mTime = PR_Now() / 1000; event.mTime = PR_Now() / 1000;
MOZ_ASSERT(event.mKeyCode == 0); MOZ_ASSERT(event.mKeyCode == 0);
NS_ENSURE_SUCCESS_VOID(mDispatcher->BeginNativeInputTransaction()); NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(mDispatcher));
mDispatcher->DispatchKeyboardEvent(msg, event, status); mDispatcher->DispatchKeyboardEvent(msg, event, status);
} }
@@ -757,7 +764,7 @@ GeckoEditableSupport::OnImeReplaceText(int32_t aStart, int32_t aEnd,
*/ */
nsCOMPtr<nsIWidget> widget = GetWidget(); nsCOMPtr<nsIWidget> widget = GetWidget();
NS_ENSURE_TRUE_VOID(mDispatcher && widget); NS_ENSURE_TRUE_VOID(mDispatcher && widget);
NS_ENSURE_SUCCESS_VOID(mDispatcher->BeginNativeInputTransaction()); NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(mDispatcher));
RefPtr<TextComposition> composition(GetComposition()); RefPtr<TextComposition> composition(GetComposition());
MOZ_ASSERT(!composition || !composition->IsEditorHandlingEvent()); MOZ_ASSERT(!composition || !composition->IsEditorHandlingEvent());
@@ -792,11 +799,17 @@ GeckoEditableSupport::OnImeReplaceText(int32_t aStart, int32_t aEnd,
// widget for duplicated events is initially nullptr. // widget for duplicated events is initially nullptr.
event->mWidget = widget; event->mWidget = widget;
if (event->mMessage == eKeyPress) { if (event->mMessage != eKeyPress) {
mDispatcher->MaybeDispatchKeypressEvents(*event, status);
} else {
mDispatcher->DispatchKeyboardEvent( mDispatcher->DispatchKeyboardEvent(
event->mMessage, *event, status); event->mMessage, *event, status);
} else if (nsIWidget::UsePuppetWidgets()) {
AutoCacheNativeKeyCommands autoCache(
static_cast<PuppetWidget*>(widget.get()));
// Don't use native key bindings.
autoCache.CacheNoCommands();
mDispatcher->MaybeDispatchKeypressEvents(*event, status);
} else {
mDispatcher->MaybeDispatchKeypressEvents(*event, status);
} }
if (widget->Destroyed()) { if (widget->Destroyed()) {
break; break;
@@ -952,7 +965,7 @@ GeckoEditableSupport::OnImeUpdateComposition(int32_t aStart, int32_t aEnd)
text, event.mData.Length(), event.mRanges->Length()); text, event.mData.Length(), event.mRanges->Length());
#endif // DEBUG_ANDROID_IME #endif // DEBUG_ANDROID_IME
NS_ENSURE_SUCCESS_VOID(mDispatcher->BeginNativeInputTransaction()); NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(mDispatcher));
mDispatcher->SetPendingComposition(string, mIMERanges); mDispatcher->SetPendingComposition(string, mIMERanges);
mDispatcher->FlushPendingComposition(status); mDispatcher->FlushPendingComposition(status);
mIMERanges->Clear(); mIMERanges->Clear();
@@ -1024,6 +1037,21 @@ GeckoEditableSupport::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
return; return;
} }
mEditable->NotifyIME(
GeckoEditableListener::NOTIFY_IME_OF_TOKEN);
if (mIsRemote) {
if (!mEditableAttached) {
// Re-attach on focus; see OnRemovedFrom().
AttachNative(mEditable, this);
mEditableAttached = true;
}
// Because GeckoEditableSupport in content process doesn't
// manage the active input context, we need to retrieve the
// input context from the widget, for use by
// OnImeReplaceText.
mInputContext = widget->GetInputContext();
}
mDispatcher = dispatcher; mDispatcher = dispatcher;
mIMEKeyEvents.Clear(); mIMEKeyEvents.Clear();
FlushIMEText(); FlushIMEText();
@@ -1043,7 +1071,7 @@ GeckoEditableSupport::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
if (!mIMEMaskEventsCount) { if (!mIMEMaskEventsCount) {
mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_OF_BLUR); mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_OF_BLUR);
mDispatcher = nullptr; OnRemovedFrom(mDispatcher);
} }
// Mask events because we lost focus. Unmask on the next focus. // Mask events because we lost focus. Unmask on the next focus.
@@ -1091,6 +1119,12 @@ GeckoEditableSupport::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
void void
GeckoEditableSupport::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) GeckoEditableSupport::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher)
{ {
mDispatcher = nullptr;
if (mIsRemote) {
// When we're remote, detach every time.
OnDetach();
}
} }
void void
@@ -1101,7 +1135,7 @@ GeckoEditableSupport::WillDispatchKeyboardEvent(
{ {
} }
nsIMEUpdatePreference NS_IMETHODIMP_(nsIMEUpdatePreference)
GeckoEditableSupport::GetIMEUpdatePreference() GeckoEditableSupport::GetIMEUpdatePreference()
{ {
// While a plugin has focus, Listener doesn't need any notifications. // While a plugin has focus, Listener doesn't need any notifications.

View File

@@ -89,9 +89,11 @@ class GeckoEditableSupport final
COMMIT_IME_COMPOSITION COMMIT_IME_COMPOSITION
}; };
const bool mIsRemote;
nsWindow::WindowPtr<GeckoEditableSupport> mWindow; // Parent only nsWindow::WindowPtr<GeckoEditableSupport> mWindow; // Parent only
RefPtr<TextEventDispatcher> mDispatcher; RefPtr<TextEventDispatcher> mDispatcher;
java::GeckoEditableChild::GlobalRef mEditable; java::GeckoEditableChild::GlobalRef mEditable;
bool mEditableAttached;
InputContext mInputContext; InputContext mInputContext;
AutoTArray<UniquePtr<mozilla::WidgetEvent>, 4> mIMEKeyEvents; AutoTArray<UniquePtr<mozilla::WidgetEvent>, 4> mIMEKeyEvents;
AutoTArray<IMETextChange, 4> mIMETextChanges; AutoTArray<IMETextChange, 4> mIMETextChanges;
@@ -107,6 +109,15 @@ class GeckoEditableSupport final
return mDispatcher ? mDispatcher->GetWidget() : mWindow; return mDispatcher ? mDispatcher->GetWidget() : mWindow;
} }
nsresult BeginInputTransaction(TextEventDispatcher* aDispatcher)
{
if (mIsRemote) {
return aDispatcher->BeginInputTransaction(this);
} else {
return aDispatcher->BeginNativeInputTransaction();
}
}
virtual ~GeckoEditableSupport() {} virtual ~GeckoEditableSupport() {}
RefPtr<TextComposition> GetComposition() const; RefPtr<TextComposition> GetComposition() const;
@@ -154,11 +165,14 @@ public:
mozilla::Move(aCall))); mozilla::Move(aCall)));
} }
// Constructor for main process GeckoEditableChild.
GeckoEditableSupport(nsWindow::NativePtr<GeckoEditableSupport>* aPtr, GeckoEditableSupport(nsWindow::NativePtr<GeckoEditableSupport>* aPtr,
nsWindow* aWindow, nsWindow* aWindow,
java::GeckoEditableChild::Param aEditableChild) java::GeckoEditableChild::Param aEditableChild)
: mWindow(aPtr, aWindow) : mIsRemote(!aWindow)
, mWindow(aPtr, aWindow)
, mEditable(aEditableChild) , mEditable(aEditableChild)
, mEditableAttached(!mIsRemote)
, mIMERanges(new TextRangeArray()) , mIMERanges(new TextRangeArray())
, mIMEMaskEventsCount(1) // Mask IME events since there's no focus yet , mIMEMaskEventsCount(1) // Mask IME events since there's no focus yet
, mIMEUpdatingContext(false) , mIMEUpdatingContext(false)
@@ -167,12 +181,19 @@ public:
, mIMEMonitorCursor(false) , mIMEMonitorCursor(false)
{} {}
// Constructor for content process GeckoEditableChild.
GeckoEditableSupport(java::GeckoEditableChild::Param aEditableChild)
: GeckoEditableSupport(nullptr, nullptr, aEditableChild)
{}
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
// TextEventDispatcherListener methods // TextEventDispatcherListener methods
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher, NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
const IMENotification& aNotification) override; const IMENotification& aNotification) override;
NS_IMETHOD_(nsIMEUpdatePreference) GetIMEUpdatePreference() override;
NS_IMETHOD_(void) OnRemovedFrom( NS_IMETHOD_(void) OnRemovedFrom(
TextEventDispatcher* aTextEventDispatcher) override; TextEventDispatcher* aTextEventDispatcher) override;
@@ -182,8 +203,6 @@ public:
uint32_t aIndexOfKeypress, uint32_t aIndexOfKeypress,
void* aData) override; void* aData) override;
nsIMEUpdatePreference GetIMEUpdatePreference();
void SetInputContext(const InputContext& aContext, void SetInputContext(const InputContext& aContext,
const InputContextAction& aAction); const InputContextAction& aAction);
@@ -194,8 +213,9 @@ public:
void OnDetach() { void OnDetach() {
RefPtr<GeckoEditableSupport> self(this); RefPtr<GeckoEditableSupport> self(this);
nsAppShell::PostEvent([self] { nsAppShell::PostEvent([this, self] {
DisposeNative(self->mEditable); mEditableAttached = false;
DisposeNative(mEditable);
}); });
} }

View File

@@ -0,0 +1,62 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GeckoProcessManager_h
#define GeckoProcessManager_h
#include "GeneratedJNINatives.h"
#include "WidgetUtils.h"
#include "nsAppShell.h"
#include "nsWindow.h"
#include "mozilla/RefPtr.h"
#include "mozilla/dom/ContentProcessManager.h"
namespace mozilla {
class GeckoProcessManager final
: public java::GeckoProcessManager::Natives<GeckoProcessManager>
{
GeckoProcessManager() = delete;
static already_AddRefed<nsIWidget>
GetWidget(int64_t aContentId, int64_t aTabId)
{
using namespace dom;
MOZ_ASSERT(NS_IsMainThread());
ContentProcessManager* const cpm =
ContentProcessManager::GetSingleton();
NS_ENSURE_TRUE(cpm, nullptr);
RefPtr<TabParent> tab = cpm->GetTopLevelTabParentByProcessAndTabId(
ContentParentId(aContentId), TabId(aTabId));
NS_ENSURE_TRUE(tab, nullptr);
nsCOMPtr<nsPIDOMWindowOuter> domWin = tab->GetParentWindowOuter();
NS_ENSURE_TRUE(domWin, nullptr);
return WidgetUtils::DOMWindowToWidget(domWin);
}
public:
static jni::Object::LocalRef
GetEditableParent(int64_t aContentId, int64_t aTabId)
{
// On binder thread.
jni::Object::GlobalRef ret;
nsAppShell::SyncRunEvent([aContentId, aTabId, &ret] {
nsCOMPtr<nsIWidget> widget = GetWidget(aContentId, aTabId);
if (widget) {
ret = static_cast<nsWindow*>(widget.get())->GetEditableParent();
}
});
return ret;
}
};
} // namespace mozilla
#endif // GeckoProcessManager_h

View File

@@ -459,6 +459,21 @@ const JNINativeMethod VsyncSource::Natives<Impl>::methods[] = {
::template Wrap<&Impl::NotifyVsync>) ::template Wrap<&Impl::NotifyVsync>)
}; };
template<class Impl>
class GeckoProcessManager::Natives : public mozilla::jni::NativeImpl<GeckoProcessManager, Impl>
{
public:
static const JNINativeMethod methods[1];
};
template<class Impl>
const JNINativeMethod GeckoProcessManager::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<GeckoProcessManager::GetEditableParent_t>(
mozilla::jni::NativeStub<GeckoProcessManager::GetEditableParent_t, Impl>
::template Wrap<&Impl::GetEditableParent>)
};
} /* java */ } /* java */
} /* mozilla */ } /* mozilla */
#endif // GeneratedJNINatives_h #endif // GeneratedJNINatives_h

View File

@@ -859,6 +859,14 @@ auto GeckoThread::CheckAndSetState(mozilla::jni::Object::Param a0, mozilla::jni:
return mozilla::jni::Method<CheckAndSetState_t>::Call(GeckoThread::Context(), nullptr, a0, a1); return mozilla::jni::Method<CheckAndSetState_t>::Call(GeckoThread::Context(), nullptr, a0, a1);
} }
constexpr char GeckoThread::IsChildProcess_t::name[];
constexpr char GeckoThread::IsChildProcess_t::signature[];
auto GeckoThread::IsChildProcess() -> bool
{
return mozilla::jni::Method<IsChildProcess_t>::Call(GeckoThread::Context(), nullptr);
}
constexpr char GeckoThread::CreateServices_t::name[]; constexpr char GeckoThread::CreateServices_t::name[];
constexpr char GeckoThread::CreateServices_t::signature[]; constexpr char GeckoThread::CreateServices_t::signature[];
@@ -1750,6 +1758,23 @@ auto VsyncSource::INSTANCE() -> VsyncSource::LocalRef
return mozilla::jni::Field<INSTANCE_t>::Get(VsyncSource::Context(), nullptr); return mozilla::jni::Field<INSTANCE_t>::Get(VsyncSource::Context(), nullptr);
} }
const char GeckoProcessManager::name[] =
"org/mozilla/gecko/process/GeckoProcessManager";
constexpr char GeckoProcessManager::GetEditableParent_t::name[];
constexpr char GeckoProcessManager::GetEditableParent_t::signature[];
const char GeckoServiceChildProcess::name[] =
"org/mozilla/gecko/process/GeckoServiceChildProcess";
constexpr char GeckoServiceChildProcess::GetEditableParent_t::name[];
constexpr char GeckoServiceChildProcess::GetEditableParent_t::signature[];
auto GeckoServiceChildProcess::GetEditableParent(int64_t a0, int64_t a1) -> mozilla::jni::Object::LocalRef
{
return mozilla::jni::Method<GetEditableParent_t>::Call(GeckoServiceChildProcess::Context(), nullptr, a0, a1);
}
const char Clipboard::name[] = const char Clipboard::name[] =
"org/mozilla/gecko/util/Clipboard"; "org/mozilla/gecko/util/Clipboard";

View File

@@ -2460,6 +2460,8 @@ public:
static const int32_t NOTIFY_IME_OF_FOCUS = 1; static const int32_t NOTIFY_IME_OF_FOCUS = 1;
static const int32_t NOTIFY_IME_OF_TOKEN = -3;
static const int32_t NOTIFY_IME_OPEN_VKB = -2; static const int32_t NOTIFY_IME_OPEN_VKB = -2;
static const int32_t NOTIFY_IME_REPLY_EVENT = -1; static const int32_t NOTIFY_IME_REPLY_EVENT = -1;
@@ -2587,6 +2589,25 @@ public:
static auto CheckAndSetState(mozilla::jni::Object::Param, mozilla::jni::Object::Param) -> bool; static auto CheckAndSetState(mozilla::jni::Object::Param, mozilla::jni::Object::Param) -> bool;
struct IsChildProcess_t {
typedef GeckoThread Owner;
typedef bool ReturnType;
typedef bool SetterType;
typedef mozilla::jni::Args<> Args;
static constexpr char name[] = "isChildProcess";
static constexpr char signature[] =
"()Z";
static const bool isStatic = true;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::ANY;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::CURRENT;
};
static auto IsChildProcess() -> bool;
struct CreateServices_t { struct CreateServices_t {
typedef GeckoThread Owner; typedef GeckoThread Owner;
typedef void ReturnType; typedef void ReturnType;
@@ -5003,6 +5024,71 @@ public:
template<class Impl> class Natives; template<class Impl> class Natives;
}; };
class GeckoProcessManager : public mozilla::jni::ObjectBase<GeckoProcessManager>
{
public:
static const char name[];
explicit GeckoProcessManager(const Context& ctx) : ObjectBase<GeckoProcessManager>(ctx) {}
struct GetEditableParent_t {
typedef GeckoProcessManager Owner;
typedef mozilla::jni::Object::LocalRef ReturnType;
typedef mozilla::jni::Object::Param SetterType;
typedef mozilla::jni::Args<
int64_t,
int64_t> Args;
static constexpr char name[] = "nativeGetEditableParent";
static constexpr char signature[] =
"(JJ)Lorg/mozilla/gecko/IGeckoEditableParent;";
static const bool isStatic = true;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::ANY;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::CURRENT;
};
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::ANY;
template<class Impl> class Natives;
};
class GeckoServiceChildProcess : public mozilla::jni::ObjectBase<GeckoServiceChildProcess>
{
public:
static const char name[];
explicit GeckoServiceChildProcess(const Context& ctx) : ObjectBase<GeckoServiceChildProcess>(ctx) {}
struct GetEditableParent_t {
typedef GeckoServiceChildProcess Owner;
typedef mozilla::jni::Object::LocalRef ReturnType;
typedef mozilla::jni::Object::Param SetterType;
typedef mozilla::jni::Args<
int64_t,
int64_t> Args;
static constexpr char name[] = "getEditableParent";
static constexpr char signature[] =
"(JJ)Lorg/mozilla/gecko/IGeckoEditableParent;";
static const bool isStatic = true;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::GECKO;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::CURRENT;
};
static auto GetEditableParent(int64_t, int64_t) -> mozilla::jni::Object::LocalRef;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::GECKO;
};
class Clipboard : public mozilla::jni::ObjectBase<Clipboard> class Clipboard : public mozilla::jni::ObjectBase<Clipboard>
{ {
public: public:

View File

@@ -124,6 +124,12 @@ void SetGeckoThreadEnv(JNIEnv* aEnv)
"loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
MOZ_ASSERT(sClassLoader && sClassLoaderLoadClass); MOZ_ASSERT(sClassLoader && sClassLoaderLoadClass);
if (java::GeckoThread::IsChildProcess()) {
// Disallow Fennec-only classes from being used in child processes.
sIsFennec = false;
return;
}
auto geckoAppClass = Class::LocalRef::Adopt( auto geckoAppClass = Class::LocalRef::Adopt(
aEnv->FindClass("org/mozilla/gecko/GeckoApp")); aEnv->FindClass("org/mozilla/gecko/GeckoApp"));
aEnv->ExceptionClear(); aEnv->ExceptionClear();

View File

@@ -24,6 +24,7 @@
#include "nsIDOMWakeLockListener.h" #include "nsIDOMWakeLockListener.h"
#include "nsIPowerManagerService.h" #include "nsIPowerManagerService.h"
#include "nsISpeculativeConnect.h" #include "nsISpeculativeConnect.h"
#include "nsITabChild.h"
#include "nsIURIFixup.h" #include "nsIURIFixup.h"
#include "nsCategoryManagerUtils.h" #include "nsCategoryManagerUtils.h"
#include "nsCDefaultURIFixup.h" #include "nsCDefaultURIFixup.h"
@@ -35,6 +36,7 @@
#include "mozilla/Services.h" #include "mozilla/Services.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/Hal.h" #include "mozilla/Hal.h"
#include "mozilla/dom/TabChild.h"
#include "prenv.h" #include "prenv.h"
#include "AndroidBridge.h" #include "AndroidBridge.h"
@@ -65,6 +67,7 @@
#include "ANRReporter.h" #include "ANRReporter.h"
#include "GeckoBatteryManager.h" #include "GeckoBatteryManager.h"
#include "GeckoNetworkManager.h" #include "GeckoNetworkManager.h"
#include "GeckoProcessManager.h"
#include "GeckoScreenOrientation.h" #include "GeckoScreenOrientation.h"
#include "PrefsHelper.h" #include "PrefsHelper.h"
#include "fennec/MemoryMonitor.h" #include "fennec/MemoryMonitor.h"
@@ -384,6 +387,10 @@ nsAppShell::nsAppShell()
} }
if (!XRE_IsParentProcess()) { if (!XRE_IsParentProcess()) {
if (jni::IsAvailable()) {
// Set the corresponding state in GeckoThread.
java::GeckoThread::SetState(java::GeckoThread::State::RUNNING());
}
return; return;
} }
@@ -394,6 +401,7 @@ nsAppShell::nsAppShell()
GeckoThreadSupport::Init(); GeckoThreadSupport::Init();
mozilla::GeckoBatteryManager::Init(); mozilla::GeckoBatteryManager::Init();
mozilla::GeckoNetworkManager::Init(); mozilla::GeckoNetworkManager::Init();
mozilla::GeckoProcessManager::Init();
mozilla::GeckoScreenOrientation::Init(); mozilla::GeckoScreenOrientation::Init();
mozilla::PrefsHelper::Init(); mozilla::PrefsHelper::Init();
nsWindow::InitNatives(); nsWindow::InitNatives();
@@ -437,7 +445,7 @@ nsAppShell::~nsAppShell()
sWakeLockListener = nullptr; sWakeLockListener = nullptr;
} }
if (jni::IsAvailable()) { if (jni::IsAvailable() && XRE_IsParentProcess()) {
DestroyAndroidUiThread(); DestroyAndroidUiThread();
AndroidBridge::DeconstructBridge(); AndroidBridge::DeconstructBridge();
} }
@@ -502,6 +510,7 @@ nsAppShell::Init()
obsServ->AddObserver(this, "browser-delayed-startup-finished", false); obsServ->AddObserver(this, "browser-delayed-startup-finished", false);
obsServ->AddObserver(this, "profile-after-change", false); obsServ->AddObserver(this, "profile-after-change", false);
obsServ->AddObserver(this, "chrome-document-loaded", false); obsServ->AddObserver(this, "chrome-document-loaded", false);
obsServ->AddObserver(this, "tab-child-created", false);
obsServ->AddObserver(this, "quit-application-granted", false); obsServ->AddObserver(this, "quit-application-granted", false);
obsServ->AddObserver(this, "xpcom-shutdown", false); obsServ->AddObserver(this, "xpcom-shutdown", false);
} }
@@ -595,6 +604,37 @@ nsAppShell::Observe(nsISupports* aSubject,
if (jni::IsAvailable()) { if (jni::IsAvailable()) {
mozilla::PrefsHelper::OnPrefChange(aData); mozilla::PrefsHelper::OnPrefChange(aData);
} }
} else if (!strcmp(aTopic, "tab-child-created")) {
// Associate the PuppetWidget of the newly-created TabChild with a
// GeckoEditableChild instance.
MOZ_ASSERT(!XRE_IsParentProcess());
dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
nsCOMPtr<nsITabChild> ptabChild = do_QueryInterface(aSubject);
NS_ENSURE_TRUE(contentChild && ptabChild, NS_OK);
// Get the content/tab ID in order to get the correct
// IGeckoEditableParent object, which GeckoEditableChild uses to
// communicate with the parent process.
const auto tabChild = static_cast<dom::TabChild*>(ptabChild.get());
const uint64_t contentId = contentChild->GetID();
const uint64_t tabId = tabChild->GetTabId();
NS_ENSURE_TRUE(contentId && tabId, NS_OK);
auto editableParent = java::GeckoServiceChildProcess::GetEditableParent(
contentId, tabId);
NS_ENSURE_TRUE(editableParent, NS_OK);
RefPtr<widget::PuppetWidget> widget(tabChild->WebWidget());
auto editableChild = java::GeckoEditableChild::New(editableParent);
NS_ENSURE_TRUE(widget && editableChild, NS_OK);
RefPtr<GeckoEditableSupport> editableSupport =
new GeckoEditableSupport(editableChild);
// Tell PuppetWidget to use our listener for IME operations.
widget->SetNativeTextEventDispatcherListener(editableSupport);
} }
if (removeObserver) { if (removeObserver) {
@@ -626,7 +666,7 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
// (bug 750713). Looper messages effectively have the lowest // (bug 750713). Looper messages effectively have the lowest
// priority because we only process them before we're about to // priority because we only process them before we're about to
// wait for new events. // wait for new events.
if (jni::IsAvailable() && if (jni::IsAvailable() && XRE_IsParentProcess() &&
AndroidBridge::Bridge()->PumpMessageLoop()) { AndroidBridge::Bridge()->PumpMessageLoop()) {
return true; return true;
} }

View File

@@ -13,6 +13,7 @@
#include "mozilla/Monitor.h" #include "mozilla/Monitor.h"
#include "mozilla/Move.h" #include "mozilla/Move.h"
#include "mozilla/StaticPtr.h" #include "mozilla/StaticPtr.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h" #include "mozilla/Unused.h"
#include "mozilla/jni/Natives.h" #include "mozilla/jni/Natives.h"
@@ -147,6 +148,13 @@ public:
mozilla::UniquePtr<Event>(*eventFactory)( mozilla::UniquePtr<Event>(*eventFactory)(
mozilla::UniquePtr<Event>&&) = nullptr); mozilla::UniquePtr<Event>&&) = nullptr);
template<typename T> static
typename mozilla::EnableIf<!mozilla::IsBaseOf<Event, T>::value, void>::Type
SyncRunEvent(T&& lambda)
{
SyncRunEvent(LambdaEvent<T>(mozilla::Forward<T>(lambda)));
}
static already_AddRefed<nsIURI> ResolveURI(const nsCString& aUriStr); static already_AddRefed<nsIURI> ResolveURI(const nsCString& aUriStr);
void SetBrowserApp(nsIAndroidBrowserApp* aBrowserApp) { void SetBrowserApp(nsIAndroidBrowserApp* aBrowserApp) {

View File

@@ -2121,20 +2121,6 @@ nsWindow::GetInputContext()
return top->mEditableSupport->GetInputContext(); return top->mEditableSupport->GetInputContext();
} }
nsIMEUpdatePreference
nsWindow::GetIMEUpdatePreference()
{
nsWindow* top = FindTopLevel();
MOZ_ASSERT(top);
if (!top->mEditableSupport) {
// Non-GeckoView windows don't support IME operations.
return nsIMEUpdatePreference();
}
return top->mEditableSupport->GetIMEUpdatePreference();
}
nsresult nsresult
nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId, nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
TouchPointerState aPointerState, TouchPointerState aPointerState,

View File

@@ -130,7 +130,9 @@ public:
, mWindowLock(NativePtr<Impl>::sName) , mWindowLock(NativePtr<Impl>::sName)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
mPtr->mPtr = this; if (mPtr) {
mPtr->mPtr = this;
}
} }
~WindowPtr() ~WindowPtr()
@@ -272,7 +274,6 @@ public:
virtual void SetInputContext(const InputContext& aContext, virtual void SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) override; const InputContextAction& aAction) override;
virtual InputContext GetInputContext() override; virtual InputContext GetInputContext() override;
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
void SetSelectionDragState(bool aState); void SetSelectionDragState(bool aState);
LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr, LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
@@ -315,6 +316,8 @@ public:
// event (like a keypress or mouse click). // event (like a keypress or mouse click).
void UserActivity(); void UserActivity();
mozilla::java::GeckoEditable::Ref& GetEditableParent() { return mEditable; }
protected: protected:
void BringToFront(); void BringToFront();
nsWindow *FindTopLevel(); nsWindow *FindTopLevel();

View File

@@ -774,6 +774,7 @@ public:
// TextEventDispatcherListener methods // TextEventDispatcherListener methods
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher, NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
const IMENotification& aNotification) override; const IMENotification& aNotification) override;
NS_IMETHOD_(nsIMEUpdatePreference) GetIMEUpdatePreference() override;
NS_IMETHOD_(void) OnRemovedFrom( NS_IMETHOD_(void) OnRemovedFrom(
TextEventDispatcher* aTextEventDispatcher) override; TextEventDispatcher* aTextEventDispatcher) override;
NS_IMETHOD_(void) WillDispatchKeyboardEvent( NS_IMETHOD_(void) WillDispatchKeyboardEvent(

View File

@@ -2627,6 +2627,15 @@ IMEInputHandler::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
} }
} }
NS_IMETHODIMP_(nsIMEUpdatePreference)
IMEInputHandler::GetIMEUpdatePreference()
{
// XXX Shouldn't we move floating window which shows composition string
// when plugin has focus and its parent is scrolled or the window is
// moved?
return nsIMEUpdatePreference();
}
NS_IMETHODIMP_(void) NS_IMETHODIMP_(void)
IMEInputHandler::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) IMEInputHandler::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher)
{ {

View File

@@ -398,7 +398,6 @@ public:
void* aCallbackData, void* aCallbackData,
uint32_t aGeckoKeyCode, uint32_t aGeckoKeyCode,
uint32_t aCocoaKeyCode); uint32_t aCocoaKeyCode);
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
virtual nsTransparencyMode GetTransparencyMode() override; virtual nsTransparencyMode GetTransparencyMode() override;
virtual void SetTransparencyMode(nsTransparencyMode aMode) override; virtual void SetTransparencyMode(nsTransparencyMode aMode) override;

View File

@@ -1893,15 +1893,6 @@ nsChildView::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
return keyBindings->Execute(aEvent, aCallback, aCallbackData); return keyBindings->Execute(aEvent, aCallback, aCallbackData);
} }
nsIMEUpdatePreference
nsChildView::GetIMEUpdatePreference()
{
// XXX Shouldn't we move floating window which shows composition string
// when plugin has focus and its parent is scrolled or the window is
// moved?
return nsIMEUpdatePreference();
}
NSView<mozView>* nsChildView::GetEditorView() NSView<mozView>* nsChildView::GetEditorView()
{ {
NSView<mozView>* editorView = mView; NSView<mozView>* editorView = mView;

View File

@@ -324,8 +324,8 @@ IMContextWrapper::GetTextEventDispatcher()
return dispatcher; return dispatcher;
} }
nsIMEUpdatePreference NS_IMETHODIMP_(nsIMEUpdatePreference)
IMContextWrapper::GetIMEUpdatePreference() const IMContextWrapper::GetIMEUpdatePreference()
{ {
// While a plugin has focus, IMContextWrapper doesn't need any // While a plugin has focus, IMContextWrapper doesn't need any
// notifications. // notifications.

View File

@@ -33,6 +33,7 @@ public:
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher, NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
const IMENotification& aNotification) override; const IMENotification& aNotification) override;
NS_IMETHOD_(nsIMEUpdatePreference) GetIMEUpdatePreference() override;
NS_IMETHOD_(void) OnRemovedFrom( NS_IMETHOD_(void) OnRemovedFrom(
TextEventDispatcher* aTextEventDispatcher) override; TextEventDispatcher* aTextEventDispatcher) override;
NS_IMETHOD_(void) WillDispatchKeyboardEvent( NS_IMETHOD_(void) WillDispatchKeyboardEvent(
@@ -51,8 +52,6 @@ public:
// I.e., the focus is in the normal editors. // I.e., the focus is in the normal editors.
bool IsEnabled() const; bool IsEnabled() const;
nsIMEUpdatePreference GetIMEUpdatePreference() const;
// OnFocusWindow is a notification that aWindow is going to be focused. // OnFocusWindow is a notification that aWindow is going to be focused.
void OnFocusWindow(nsWindow* aWindow); void OnFocusWindow(nsWindow* aWindow);
// OnBlurWindow is a notification that aWindow is going to be unfocused. // OnBlurWindow is a notification that aWindow is going to be unfocused.

View File

@@ -6099,15 +6099,6 @@ nsWindow::GetInputContext()
return context; return context;
} }
nsIMEUpdatePreference
nsWindow::GetIMEUpdatePreference()
{
if (!mIMContext) {
return nsIMEUpdatePreference();
}
return mIMContext->GetIMEUpdatePreference();
}
TextEventDispatcherListener* TextEventDispatcherListener*
nsWindow::GetNativeTextEventDispatcherListener() nsWindow::GetNativeTextEventDispatcherListener()
{ {

View File

@@ -274,7 +274,6 @@ public:
virtual void SetInputContext(const InputContext& aContext, virtual void SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) override; const InputContextAction& aAction) override;
virtual InputContext GetInputContext() override; virtual InputContext GetInputContext() override;
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
virtual TextEventDispatcherListener* virtual TextEventDispatcherListener*
GetNativeTextEventDispatcherListener() override; GetNativeTextEventDispatcherListener() override;
bool ExecuteNativeKeyBindingRemapped( bool ExecuteNativeKeyBindingRemapped(

View File

@@ -1813,6 +1813,18 @@ nsBaseWidget::NotifyIME(const IMENotification& aIMENotification)
} }
} }
nsIMEUpdatePreference
nsBaseWidget::GetIMEUpdatePreference()
{
RefPtr<TextEventDispatcherListener> listener =
GetNativeTextEventDispatcherListener();
if (!listener) {
// Default is to not send additional change notifications to NotifyIME.
return nsIMEUpdatePreference();
}
return listener->GetIMEUpdatePreference();
}
void void
nsBaseWidget::EnsureTextEventDispatcher() nsBaseWidget::EnsureTextEventDispatcher()
{ {

View File

@@ -288,7 +288,7 @@ public:
void* aCallbackData) override { return false; } void* aCallbackData) override { return false; }
bool ComputeShouldAccelerate(); bool ComputeShouldAccelerate();
virtual bool WidgetTypeSupportsAcceleration() { return true; } virtual bool WidgetTypeSupportsAcceleration() { return true; }
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override { return nsIMEUpdatePreference(); } virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
virtual MOZ_MUST_USE nsresult OnDefaultButtonLoaded(const LayoutDeviceIntRect& aButtonRect) override { return NS_ERROR_NOT_IMPLEMENTED; } virtual MOZ_MUST_USE nsresult OnDefaultButtonLoaded(const LayoutDeviceIntRect& aButtonRect) override { return NS_ERROR_NOT_IMPLEMENTED; }
virtual already_AddRefed<nsIWidget> virtual already_AddRefed<nsIWidget>
CreateChild(const LayoutDeviceIntRect& aRect, CreateChild(const LayoutDeviceIntRect& aRect,

View File

@@ -56,6 +56,12 @@ WinTextEventDispatcherListener::NotifyIME(
return IMEHandler::NotifyIME(window, aNotification); return IMEHandler::NotifyIME(window, aNotification);
} }
NS_IMETHODIMP_(nsIMEUpdatePreference)
WinTextEventDispatcherListener::GetIMEUpdatePreference()
{
return IMEHandler::GetUpdatePreference();
}
NS_IMETHODIMP_(void) NS_IMETHODIMP_(void)
WinTextEventDispatcherListener::OnRemovedFrom( WinTextEventDispatcherListener::OnRemovedFrom(
TextEventDispatcher* aTextEventDispatcher) TextEventDispatcher* aTextEventDispatcher)

View File

@@ -29,6 +29,7 @@ public:
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher, NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
const IMENotification& aNotification) override; const IMENotification& aNotification) override;
NS_IMETHOD_(nsIMEUpdatePreference) GetIMEUpdatePreference() override;
NS_IMETHOD_(void) OnRemovedFrom( NS_IMETHOD_(void) OnRemovedFrom(
TextEventDispatcher* aTextEventDispatcher) override; TextEventDispatcher* aTextEventDispatcher) override;
NS_IMETHOD_(void) WillDispatchKeyboardEvent( NS_IMETHOD_(void) WillDispatchKeyboardEvent(

View File

@@ -7225,12 +7225,6 @@ nsWindow::GetInputContext()
return mInputContext; return mInputContext;
} }
nsIMEUpdatePreference
nsWindow::GetIMEUpdatePreference()
{
return IMEHandler::GetUpdatePreference();
}
TextEventDispatcherListener* TextEventDispatcherListener*
nsWindow::GetNativeTextEventDispatcherListener() nsWindow::GetNativeTextEventDispatcherListener()
{ {

View File

@@ -210,7 +210,6 @@ public:
virtual nsTransparencyMode GetTransparencyMode() override; virtual nsTransparencyMode GetTransparencyMode() override;
virtual void UpdateOpaqueRegion(const LayoutDeviceIntRegion& aOpaqueRegion) override; virtual void UpdateOpaqueRegion(const LayoutDeviceIntRegion& aOpaqueRegion) override;
#endif // MOZ_XUL #endif // MOZ_XUL
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
virtual nsresult SetNonClientMargins(LayoutDeviceIntMargin& aMargins) override; virtual nsresult SetNonClientMargins(LayoutDeviceIntMargin& aMargins) override;
void SetDrawsInTitlebar(bool aState) override; void SetDrawsInTitlebar(bool aState) override;
virtual void UpdateWindowDraggingRegion(const LayoutDeviceIntRegion& aRegion) override; virtual void UpdateWindowDraggingRegion(const LayoutDeviceIntRegion& aRegion) override;

View File

@@ -22,6 +22,10 @@
#include "XREChildData.h" #include "XREChildData.h"
#include "XREShellData.h" #include "XREShellData.h"
#if defined(MOZ_WIDGET_ANDROID)
#include <jni.h>
#endif
/** /**
* A directory service key which provides the platform-correct "application * A directory service key which provides the platform-correct "application
* data" directory as follows, where $name and $vendor are as defined above and * data" directory as follows, where $name and $vendor are as defined above and
@@ -407,7 +411,7 @@ XRE_API(const char*,
#if defined(MOZ_WIDGET_ANDROID) #if defined(MOZ_WIDGET_ANDROID)
XRE_API(void, XRE_API(void,
XRE_SetAndroidChildFds, (int crashFd, int ipcFd)) XRE_SetAndroidChildFds, (JNIEnv* env, int crashFd, int ipcFd))
#endif // defined(MOZ_WIDGET_ANDROID) #endif // defined(MOZ_WIDGET_ANDROID)
XRE_API(void, XRE_API(void,