mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
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:
parent
d5457902e2
commit
53a1107cd1
@ -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)
|
||||
TextInputProcessor::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher)
|
||||
{
|
||||
|
@ -32,6 +32,9 @@ public:
|
||||
// TextEventDispatcherListener
|
||||
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
||||
const IMENotification& aNotification) override;
|
||||
|
||||
NS_IMETHOD_(nsIMEUpdatePreference) GetIMEUpdatePreference() override;
|
||||
|
||||
NS_IMETHOD_(void)
|
||||
OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) override;
|
||||
|
||||
|
@ -579,6 +579,7 @@ GECKOVIEW_AIDLS = \
|
||||
org/mozilla/gecko/IGeckoEditableChild.aidl \
|
||||
org/mozilla/gecko/IGeckoEditableParent.aidl \
|
||||
org/mozilla/gecko/process/IChildProcess.aidl \
|
||||
org/mozilla/gecko/process/IProcessManager.aidl \
|
||||
$(NULL)
|
||||
|
||||
geckoview_aidl_src_path := $(topsrcdir)/mobile/android/geckoview/src/main/aidl
|
||||
|
@ -1191,4 +1191,5 @@ gvjar.sources += ['generated/org/mozilla/gecko/' + x for x in [
|
||||
'IGeckoEditableChild.java',
|
||||
'IGeckoEditableParent.java',
|
||||
'process/IChildProcess.java',
|
||||
'process/IProcessManager.java',
|
||||
]]
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import android.os.IBinder;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import org.mozilla.gecko.IGeckoEditableChild;
|
||||
@ -11,20 +12,21 @@ import org.mozilla.gecko.IGeckoEditableChild;
|
||||
// Interface for GeckoEditable calls from child to parent
|
||||
interface IGeckoEditableParent {
|
||||
// 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.
|
||||
void notifyIMEContext(int state, String typeHint, String modeHint, String actionHint);
|
||||
|
||||
// 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.
|
||||
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.
|
||||
void onDefaultKeyEvent(in KeyEvent event);
|
||||
void onDefaultKeyEvent(IBinder token, in KeyEvent event);
|
||||
|
||||
// Update the screen location of current composition.
|
||||
void updateCompositionRects(in RectF[] rects);
|
||||
void updateCompositionRects(IBinder token, in RectF[] rects);
|
||||
}
|
||||
|
@ -3,10 +3,13 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.process;
|
||||
|
||||
import org.mozilla.gecko.process.IProcessManager;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
interface IChildProcess {
|
||||
void stop();
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -19,6 +19,7 @@ import org.mozilla.gecko.util.ThreadUtils.AssertBehavior;
|
||||
|
||||
import android.graphics.RectF;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.text.Editable;
|
||||
@ -61,7 +62,11 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
private Handler mIcRunHandler;
|
||||
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 */ GeckoView mView;
|
||||
|
||||
@ -71,7 +76,6 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
private boolean mNeedUpdateComposition; // 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 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_LINECOLOR = 8;
|
||||
|
||||
private void onKeyEvent(KeyEvent event, int action, int savedMetaState,
|
||||
boolean isSynthesizedImeKey) throws RemoteException {
|
||||
private void onKeyEvent(final IGeckoEditableChild child, KeyEvent event, int action,
|
||||
int savedMetaState, boolean isSynthesizedImeKey)
|
||||
throws RemoteException {
|
||||
// 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
|
||||
// a new key event just to change its action field.
|
||||
@ -117,7 +122,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
final int keyPressMetaState = (unicodeChar >= ' ' &&
|
||||
unicodeChar != unmodifiedUnicodeChar) ? unmodifiedMetaState : metaState;
|
||||
|
||||
mEditableChild.onKeyEvent(action, event.getKeyCode(), event.getScanCode(),
|
||||
child.onKeyEvent(action, event.getKeyCode(), event.getScanCode(),
|
||||
metaState, keyPressMetaState, event.getEventTime(),
|
||||
domPrintableKeyValue, event.getRepeatCount(), event.getFlags(),
|
||||
isSynthesizedImeKey, event);
|
||||
@ -167,34 +172,26 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
|
||||
public synchronized void currentReplace(final int start, final int end,
|
||||
final CharSequence newText) {
|
||||
if (DEBUG) {
|
||||
ThreadUtils.assertOnGeckoThread();
|
||||
}
|
||||
// On Gecko or binder thread.
|
||||
mCurrentText.replace(start, end, newText);
|
||||
addCurrentChangeLocked(start, end, start + newText.length());
|
||||
}
|
||||
|
||||
public synchronized void currentSetSelection(final int start, final int end) {
|
||||
if (DEBUG) {
|
||||
ThreadUtils.assertOnGeckoThread();
|
||||
}
|
||||
// On Gecko or binder thread.
|
||||
Selection.setSelection(mCurrentText, start, end);
|
||||
mCurrentSelectionChanged = true;
|
||||
}
|
||||
|
||||
public synchronized void currentSetSpan(final Object obj, final int start,
|
||||
final int end, final int flags) {
|
||||
if (DEBUG) {
|
||||
ThreadUtils.assertOnGeckoThread();
|
||||
}
|
||||
// On Gecko or binder thread.
|
||||
mCurrentText.setSpan(obj, start, end, flags);
|
||||
addCurrentChangeLocked(start, end, end);
|
||||
}
|
||||
|
||||
public synchronized void currentRemoveSpan(final Object obj) {
|
||||
if (DEBUG) {
|
||||
ThreadUtils.assertOnGeckoThread();
|
||||
}
|
||||
// On Gecko or binder thread.
|
||||
if (obj == null) {
|
||||
mCurrentText.clearSpans();
|
||||
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
|
||||
// be read-only. Editing should be done through one of the current*** methods.
|
||||
public Spanned getCurrentText() {
|
||||
if (DEBUG) {
|
||||
ThreadUtils.assertOnGeckoThread();
|
||||
}
|
||||
// On Gecko or binder thread.
|
||||
return mCurrentText;
|
||||
}
|
||||
|
||||
@ -438,8 +433,8 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
getConstantName(Action.class, "TYPE_", action.mType) + ")");
|
||||
}
|
||||
|
||||
if (mListener == null) {
|
||||
// We haven't initialized or we've been destroyed.
|
||||
if (mFocusedChild == null || mListener == null) {
|
||||
// We haven't been focused or initialized, or we've been destroyed.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -458,7 +453,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
switch (action.mType) {
|
||||
case Action.TYPE_EVENT:
|
||||
case Action.TYPE_SET_HANDLER:
|
||||
mEditableChild.onImeSynchronize();
|
||||
mFocusedChild.onImeSynchronize();
|
||||
break;
|
||||
|
||||
case Action.TYPE_SET_SPAN:
|
||||
@ -472,7 +467,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
action.mSpanObject == Selection.SELECTION_START ||
|
||||
action.mSpanObject == Selection.SELECTION_END);
|
||||
|
||||
mEditableChild.onImeSynchronize();
|
||||
mFocusedChild.onImeSynchronize();
|
||||
break;
|
||||
|
||||
case Action.TYPE_REMOVE_SPAN:
|
||||
@ -482,7 +477,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
mNeedUpdateComposition |= (flags & Spanned.SPAN_INTERMEDIATE) == 0 &&
|
||||
(flags & Spanned.SPAN_COMPOSING) != 0;
|
||||
|
||||
mEditableChild.onImeSynchronize();
|
||||
mFocusedChild.onImeSynchronize();
|
||||
break;
|
||||
|
||||
case Action.TYPE_REPLACE_TEXT:
|
||||
@ -498,7 +493,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
sendCharKeyEvents(action);
|
||||
}
|
||||
mText.shadowReplace(action.mStart, action.mEnd, action.mSequence);
|
||||
mEditableChild.onImeReplaceText(
|
||||
mFocusedChild.onImeReplaceText(
|
||||
action.mStart, action.mEnd, action.mSequence.toString());
|
||||
break;
|
||||
|
||||
@ -548,7 +543,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
if (DEBUG) {
|
||||
Log.d(LOGTAG, "sending: " + event);
|
||||
}
|
||||
onKeyEvent(event, event.getAction(),
|
||||
onKeyEvent(mFocusedChild, event, event.getAction(),
|
||||
/* metaState */ 0, /* isSynthesizedImeKey */ true);
|
||||
}
|
||||
}
|
||||
@ -575,7 +570,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private void setDefaultEditableChild(final IGeckoEditableChild child) {
|
||||
mEditableChild = child;
|
||||
mDefaultChild = child;
|
||||
}
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
@ -701,7 +696,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
if (found) {
|
||||
icSendComposition(text, selStart, selEnd, composingStart, composingEnd);
|
||||
if (notifyGecko) {
|
||||
mEditableChild.onImeUpdateComposition(composingStart, composingEnd);
|
||||
mFocusedChild.onImeUpdateComposition(composingStart, composingEnd);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -709,7 +704,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
|
||||
if (notifyGecko) {
|
||||
// Set the selection by using a composition without ranges
|
||||
mEditableChild.onImeUpdateComposition(selStart, selEnd);
|
||||
mFocusedChild.onImeUpdateComposition(selStart, selEnd);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
@ -733,7 +728,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
}
|
||||
|
||||
if (selEnd >= composingStart && selEnd <= composingEnd) {
|
||||
mEditableChild.onImeAddCompositionRange(
|
||||
mFocusedChild.onImeAddCompositionRange(
|
||||
selEnd - composingStart, selEnd - composingStart,
|
||||
IME_RANGE_CARETPOSITION, 0, 0, false, 0, 0, 0);
|
||||
}
|
||||
@ -806,7 +801,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
rangeBackColor = tp.bgColor;
|
||||
}
|
||||
}
|
||||
mEditableChild.onImeAddCompositionRange(
|
||||
mFocusedChild.onImeAddCompositionRange(
|
||||
rangeStart - composingStart, rangeEnd - composingStart,
|
||||
rangeType, rangeStyles, rangeLineStyle, rangeBoldLine,
|
||||
rangeForeColor, rangeBackColor, rangeLineColor);
|
||||
@ -838,8 +833,17 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
event-type action, and update the shadow text accordingly.
|
||||
*/
|
||||
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();
|
||||
onKeyEvent(event, action, metaState, /* isSynthesizedImeKey */ false);
|
||||
onKeyEvent(mFocusedChild, event, action, metaState,
|
||||
/* isSynthesizedImeKey */ false);
|
||||
icOfferAction(new Action(Action.TYPE_EVENT));
|
||||
} catch (final RemoteException e) {
|
||||
Log.e(LOGTAG, "Remote call failed", e);
|
||||
@ -952,16 +956,16 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
@Override // GeckoEditableClient
|
||||
public void requestCursorUpdates(int requestMode) {
|
||||
try {
|
||||
mEditableChild.onImeRequestCursorUpdates(requestMode);
|
||||
if (mFocusedChild != null) {
|
||||
mFocusedChild.onImeRequestCursorUpdates(requestMode);
|
||||
}
|
||||
} catch (final RemoteException e) {
|
||||
Log.e(LOGTAG, "Remote call failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void geckoSetIcHandler(final Handler newHandler) {
|
||||
if (DEBUG) {
|
||||
ThreadUtils.assertOnGeckoThread();
|
||||
}
|
||||
// On Gecko or binder thread.
|
||||
mIcPostHandler.post(new Runnable() { // posting to old IC thread
|
||||
@Override
|
||||
public void run() {
|
||||
@ -980,13 +984,10 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
|
||||
private void geckoActionReply(final Action action) {
|
||||
// On Gecko or binder thread.
|
||||
if (!mGeckoFocused) {
|
||||
if (DEBUG) {
|
||||
Log.d(LOGTAG, "discarding stale reply");
|
||||
}
|
||||
if (action == null) {
|
||||
Log.w(LOGTAG, "Mismatched reply");
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(LOGTAG, "reply: Action(" +
|
||||
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
|
||||
public void notifyIME(final int type) {
|
||||
public void notifyIME(final IGeckoEditableChild child, final int type) {
|
||||
// On Gecko or binder thread.
|
||||
if (DEBUG) {
|
||||
// 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());
|
||||
if (!mActions.isEmpty()) {
|
||||
// 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) {
|
||||
mFocusedChild = child;
|
||||
mNeedSync = false;
|
||||
mText.syncShadowText(/* listener */ null);
|
||||
} else if (type == GeckoEditableListener.NOTIFY_IME_OF_BLUR) {
|
||||
mFocusedChild = 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
|
||||
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.
|
||||
if (DEBUG) {
|
||||
Log.d(LOGTAG, "notifyIMEContext(" +
|
||||
@ -1074,6 +1106,10 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
", \"" + typeHint + "\", \"" + modeHint + "\", \"" + actionHint + "\")");
|
||||
}
|
||||
|
||||
// Don't check token for notifyIMEContext, because the calls all come
|
||||
// from the parent process.
|
||||
ThreadUtils.assertOnGeckoThread();
|
||||
|
||||
mIcPostHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -1086,12 +1122,17 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
}
|
||||
|
||||
@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.
|
||||
if (DEBUG) {
|
||||
Log.d(LOGTAG, "onSelectionChange(" + start + ", " + end + ")");
|
||||
}
|
||||
|
||||
if (!binderCheckToken(token, /* allowNull */ false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIgnoreSelectionChange) {
|
||||
mIgnoreSelectionChange = false;
|
||||
} else {
|
||||
@ -1112,8 +1153,8 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
}
|
||||
|
||||
@Override // IGeckoEditableParent
|
||||
public void onTextChange(final CharSequence text, final int start,
|
||||
final int unboundedOldEnd) {
|
||||
public void onTextChange(final IBinder token, final CharSequence text,
|
||||
final int start, final int unboundedOldEnd) {
|
||||
// On Gecko or binder thread.
|
||||
if (DEBUG) {
|
||||
StringBuilder sb = new StringBuilder("onTextChange(");
|
||||
@ -1122,6 +1163,10 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
Log.d(LOGTAG, sb.toString());
|
||||
}
|
||||
|
||||
if (!binderCheckToken(token, /* allowNull */ false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int currentLength = mText.getCurrentText().length();
|
||||
final int oldEnd = unboundedOldEnd > currentLength ? currentLength : unboundedOldEnd;
|
||||
final int newEnd = start + text.length();
|
||||
@ -1227,7 +1272,7 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
}
|
||||
|
||||
@Override // IGeckoEditableParent
|
||||
public void onDefaultKeyEvent(final KeyEvent event) {
|
||||
public void onDefaultKeyEvent(final IBinder token, final KeyEvent event) {
|
||||
// On Gecko or binder thread.
|
||||
if (DEBUG) {
|
||||
StringBuilder sb = new StringBuilder("onDefaultKeyEvent(");
|
||||
@ -1239,6 +1284,11 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -1251,12 +1301,16 @@ final class GeckoEditable extends IGeckoEditableParent.Stub
|
||||
}
|
||||
|
||||
@Override // IGeckoEditableParent
|
||||
public void updateCompositionRects(final RectF[] rects) {
|
||||
public void updateCompositionRects(final IBinder token, final RectF[] rects) {
|
||||
// On Gecko or binder thread.
|
||||
if (DEBUG) {
|
||||
Log.d(LOGTAG, "updateCompositionRects(rects.length = " + rects.length + ")");
|
||||
}
|
||||
|
||||
if (!binderCheckToken(token, /* allowNull */ false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIcPostHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -26,13 +26,65 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
|
||||
private static final boolean DEBUG = false;
|
||||
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 IGeckoEditableChild mEditableChild;
|
||||
|
||||
private int mCurrentTextLength; // Used by Gecko thread
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
/* package */ GeckoEditableChild(final IGeckoEditableParent 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
|
||||
@ -67,7 +119,8 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
|
||||
|
||||
@Override // IInterface
|
||||
public IBinder asBinder() {
|
||||
return null;
|
||||
// Return the GeckoEditableParent's binder as our binder for comparison purposes.
|
||||
return mEditableParent.asBinder();
|
||||
}
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
@ -92,7 +145,7 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
|
||||
}
|
||||
|
||||
try {
|
||||
mEditableParent.notifyIME(type);
|
||||
mEditableParent.notifyIME(mEditableChild, type);
|
||||
} catch (final RemoteException e) {
|
||||
Log.e(LOGTAG, "Remote call failed", e);
|
||||
return;
|
||||
@ -130,7 +183,7 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
|
||||
throw new IllegalArgumentException("invalid selection notification range");
|
||||
}
|
||||
|
||||
mEditableParent.onSelectionChange(start, end);
|
||||
mEditableParent.onSelectionChange(mEditableChild.asBinder(), start, end);
|
||||
}
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko", exceptionMode = "ignore")
|
||||
@ -166,7 +219,7 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
|
||||
|
||||
mCurrentTextLength += start + text.length() - oldEnd;
|
||||
// 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")
|
||||
@ -184,7 +237,7 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
|
||||
}
|
||||
|
||||
try {
|
||||
mEditableParent.onDefaultKeyEvent(event);
|
||||
mEditableParent.onDefaultKeyEvent(mEditableChild.asBinder(), event);
|
||||
} catch (final RemoteException e) {
|
||||
Log.e(LOGTAG, "Remote call failed", e);
|
||||
}
|
||||
@ -199,7 +252,7 @@ final class GeckoEditableChild extends JNIObject implements IGeckoEditableChild
|
||||
}
|
||||
|
||||
try {
|
||||
mEditableParent.updateCompositionRects(rects);
|
||||
mEditableParent.updateCompositionRects(mEditableChild.asBinder(), rects);
|
||||
} catch (final RemoteException e) {
|
||||
Log.e(LOGTAG, "Remote call failed", e);
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ import android.view.KeyEvent;
|
||||
interface GeckoEditableListener {
|
||||
// IME notification type for notifyIME(), corresponding to NotificationToIME enum in Gecko
|
||||
@WrapForJNI
|
||||
int NOTIFY_IME_OF_TOKEN = -3;
|
||||
@WrapForJNI
|
||||
int NOTIFY_IME_OPEN_VKB = -2;
|
||||
@WrapForJNI
|
||||
int NOTIFY_IME_REPLY_EVENT = -1;
|
||||
|
@ -141,15 +141,16 @@ public class GeckoThread extends Thread {
|
||||
private boolean mDebugging;
|
||||
|
||||
// Child process parameters
|
||||
private int mCrashFileDescriptor;
|
||||
private int mIPCFileDescriptor;
|
||||
private int mCrashFileDescriptor = -1;
|
||||
private int mIPCFileDescriptor = -1;
|
||||
|
||||
GeckoThread() {
|
||||
setName("Gecko");
|
||||
}
|
||||
|
||||
private boolean isChildProcess() {
|
||||
return mIPCFileDescriptor != -1;
|
||||
@WrapForJNI
|
||||
private static boolean isChildProcess() {
|
||||
return INSTANCE.mIPCFileDescriptor != -1;
|
||||
}
|
||||
|
||||
private synchronized boolean init(final GeckoProfile profile, final String[] args,
|
||||
|
@ -5,6 +5,8 @@
|
||||
package org.mozilla.gecko.process;
|
||||
|
||||
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.util.ThreadUtils;
|
||||
|
||||
@ -25,7 +27,7 @@ import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Map;
|
||||
|
||||
public final class GeckoProcessManager {
|
||||
public final class GeckoProcessManager extends IProcessManager.Stub {
|
||||
private static final String LOGTAG = "GeckoProcessManager";
|
||||
private static final GeckoProcessManager INSTANCE = new GeckoProcessManager();
|
||||
|
||||
@ -33,6 +35,15 @@ public final class GeckoProcessManager {
|
||||
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 {
|
||||
public final String mType;
|
||||
private boolean mWait = false;
|
||||
@ -150,7 +161,7 @@ public final class GeckoProcessManager {
|
||||
crashPfd = ParcelFileDescriptor.fromFd(crashFd);
|
||||
}
|
||||
ParcelFileDescriptor ipcPfd = ParcelFileDescriptor.fromFd(ipcFd);
|
||||
connection.mChild.start(args, crashPfd, ipcPfd);
|
||||
connection.mChild.start(this, args, crashPfd, ipcPfd);
|
||||
if (crashPfd != null) {
|
||||
crashPfd.close();
|
||||
}
|
||||
|
@ -6,7 +6,9 @@
|
||||
package org.mozilla.gecko.process;
|
||||
|
||||
import org.mozilla.gecko.annotation.JNITarget;
|
||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.IGeckoEditableParent;
|
||||
import org.mozilla.gecko.mozglue.GeckoLoader;
|
||||
import org.mozilla.gecko.GeckoThread;
|
||||
import org.mozilla.gecko.mozglue.SafeIntent;
|
||||
@ -18,23 +20,35 @@ import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
public class GeckoServiceChildProcess extends Service {
|
||||
|
||||
static private String LOGTAG = "GeckoServiceChildProcess";
|
||||
|
||||
private boolean serviceStarted;
|
||||
private static IProcessManager sProcessManager;
|
||||
|
||||
static private void stop() {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
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() {
|
||||
super.onCreate();
|
||||
}
|
||||
@ -59,14 +73,16 @@ public class GeckoServiceChildProcess extends Service {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(final String[] args,
|
||||
public void start(final IProcessManager procMan,
|
||||
final String[] args,
|
||||
final ParcelFileDescriptor crashReporterPfd,
|
||||
final ParcelFileDescriptor ipcPfd) {
|
||||
if (serviceStarted) {
|
||||
if (sProcessManager != null) {
|
||||
Log.e(LOGTAG, "Attempting to start a service that has already been started.");
|
||||
return;
|
||||
}
|
||||
serviceStarted = true;
|
||||
sProcessManager = procMan;
|
||||
|
||||
final int crashReporterFd = crashReporterPfd != null ? crashReporterPfd.detachFd() : -1;
|
||||
final int ipcFd = ipcPfd != null ? ipcPfd.detachFd() : -1;
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
|
@ -435,7 +435,7 @@ Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jo
|
||||
gBootstrap->GeckoStart(jenv, argv, argc, sAppData);
|
||||
ElfLoader::Singleton.ExpectShutdown(true);
|
||||
} else {
|
||||
gBootstrap->XRE_SetAndroidChildFds(crashFd, ipcFd);
|
||||
gBootstrap->XRE_SetAndroidChildFds(jenv, crashFd, ipcFd);
|
||||
gBootstrap->XRE_SetProcessType(argv[argc - 1]);
|
||||
|
||||
XREChildData childData;
|
||||
|
@ -74,8 +74,8 @@ public:
|
||||
::GeckoStart(aEnv, argv, argc, aAppData);
|
||||
}
|
||||
|
||||
virtual void XRE_SetAndroidChildFds(int aCrashFd, int aIPCFd) override {
|
||||
::XRE_SetAndroidChildFds(aCrashFd, aIPCFd);
|
||||
virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aCrashFd, int aIPCFd) override {
|
||||
::XRE_SetAndroidChildFds(aEnv, aCrashFd, aIPCFd);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -113,7 +113,7 @@ public:
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
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
|
||||
|
||||
#ifdef LIBFUZZER
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "chrome/common/child_process.h"
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
#include "chrome/common/ipc_channel.h"
|
||||
#include "mozilla/jni/Utils.h"
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
#include "mozilla/ipc/BrowserProcessSubThread.h"
|
||||
@ -239,8 +240,9 @@ GeckoProcessType sChildProcessType = GeckoProcessType_Default;
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
void
|
||||
XRE_SetAndroidChildFds (int crashFd, int ipcFd)
|
||||
XRE_SetAndroidChildFds (JNIEnv* env, int crashFd, int ipcFd)
|
||||
{
|
||||
mozilla::jni::SetGeckoThreadEnv(env);
|
||||
#if defined(MOZ_CRASHREPORTER)
|
||||
CrashReporter::SetNotificationPipeForChild(crashFd);
|
||||
#endif // defined(MOZ_CRASHREPORTER)
|
||||
|
@ -693,6 +693,11 @@ PuppetWidget::RequestIMEToCommitComposition(bool aCancel)
|
||||
nsresult
|
||||
PuppetWidget::NotifyIMEInternal(const IMENotification& aIMENotification)
|
||||
{
|
||||
if (mNativeTextEventDispatcherListener) {
|
||||
// Use mNativeTextEventDispatcherListener for IME notifications.
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
switch (aIMENotification.mMessage) {
|
||||
case REQUEST_TO_COMMIT_COMPOSITION:
|
||||
return RequestIMEToCommitComposition(false);
|
||||
@ -857,6 +862,11 @@ PuppetWidget::NotifyIMEOfCompositionUpdate(
|
||||
nsIMEUpdatePreference
|
||||
PuppetWidget::GetIMEUpdatePreference()
|
||||
{
|
||||
if (mNativeTextEventDispatcherListener) {
|
||||
// Use mNativeTextEventDispatcherListener for IME preference.
|
||||
return mNativeTextEventDispatcherListener->GetIMEUpdatePreference();
|
||||
}
|
||||
|
||||
// e10s requires IME content cache in in the TabParent for handling query
|
||||
// content event only with the parent process. Therefore, this process
|
||||
// needs to receive a lot of information from the focused editor to sent
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ContentCache.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/TextEventDispatcherListener.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -183,6 +184,10 @@ public:
|
||||
virtual InputContext GetInputContext() override;
|
||||
virtual NativeIMEContext GetNativeIMEContext() override;
|
||||
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
|
||||
TextEventDispatcherListener* GetNativeTextEventDispatcherListener() override
|
||||
{ return mNativeTextEventDispatcherListener; }
|
||||
void SetNativeTextEventDispatcherListener(TextEventDispatcherListener* aListener)
|
||||
{ mNativeTextEventDispatcherListener = aListener; }
|
||||
|
||||
virtual void SetCursor(nsCursor aCursor) override;
|
||||
virtual nsresult SetCursor(imgIContainer* aCursor,
|
||||
@ -376,6 +381,8 @@ private:
|
||||
|
||||
nsCOMArray<nsIKeyEventInPluginCallback> mKeyEventInPluginCallbacks;
|
||||
|
||||
RefPtr<TextEventDispatcherListener> mNativeTextEventDispatcherListener;
|
||||
|
||||
protected:
|
||||
bool mEnabled;
|
||||
bool mVisible;
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
struct nsIMEUpdatePreference;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
@ -30,6 +32,11 @@ public:
|
||||
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
||||
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
|
||||
* is releasing the listener.
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "AndroidRect.h"
|
||||
#include "KeyEvent.h"
|
||||
#include "PuppetWidget.h"
|
||||
#include "android_npapi.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsISelection.h"
|
||||
@ -391,7 +392,7 @@ GeckoEditableSupport::RemoveComposition(RemoveCompositionFlag aFlag)
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
|
||||
NS_ENSURE_SUCCESS_VOID(mDispatcher->BeginNativeInputTransaction());
|
||||
NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(mDispatcher));
|
||||
mDispatcher->CommitComposition(
|
||||
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()));
|
||||
} else {
|
||||
RemoveComposition();
|
||||
NS_ENSURE_SUCCESS_VOID(dispatcher->BeginNativeInputTransaction());
|
||||
NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(dispatcher));
|
||||
dispatcher->DispatchKeyboardEvent(msg, event, status);
|
||||
if (widget->Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
|
||||
// Skip default processing.
|
||||
@ -463,6 +464,12 @@ GeckoEditableSupport::OnKeyEvent(int32_t aAction, int32_t aKeyCode,
|
||||
if (aIsSynthesizedImeKey) {
|
||||
mIMEKeyEvents.AppendElement(
|
||||
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 {
|
||||
dispatcher->MaybeDispatchKeypressEvents(pressEvent, status);
|
||||
}
|
||||
@ -482,7 +489,7 @@ GeckoEditableSupport::SendIMEDummyKeyEvent(nsIWidget* aWidget, EventMessage msg)
|
||||
WidgetKeyboardEvent event(true, msg, aWidget);
|
||||
event.mTime = PR_Now() / 1000;
|
||||
MOZ_ASSERT(event.mKeyCode == 0);
|
||||
NS_ENSURE_SUCCESS_VOID(mDispatcher->BeginNativeInputTransaction());
|
||||
NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(mDispatcher));
|
||||
mDispatcher->DispatchKeyboardEvent(msg, event, status);
|
||||
}
|
||||
|
||||
@ -757,7 +764,7 @@ GeckoEditableSupport::OnImeReplaceText(int32_t aStart, int32_t aEnd,
|
||||
*/
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
NS_ENSURE_TRUE_VOID(mDispatcher && widget);
|
||||
NS_ENSURE_SUCCESS_VOID(mDispatcher->BeginNativeInputTransaction());
|
||||
NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(mDispatcher));
|
||||
|
||||
RefPtr<TextComposition> composition(GetComposition());
|
||||
MOZ_ASSERT(!composition || !composition->IsEditorHandlingEvent());
|
||||
@ -792,11 +799,17 @@ GeckoEditableSupport::OnImeReplaceText(int32_t aStart, int32_t aEnd,
|
||||
// widget for duplicated events is initially nullptr.
|
||||
event->mWidget = widget;
|
||||
|
||||
if (event->mMessage == eKeyPress) {
|
||||
mDispatcher->MaybeDispatchKeypressEvents(*event, status);
|
||||
} else {
|
||||
if (event->mMessage != eKeyPress) {
|
||||
mDispatcher->DispatchKeyboardEvent(
|
||||
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()) {
|
||||
break;
|
||||
@ -952,7 +965,7 @@ GeckoEditableSupport::OnImeUpdateComposition(int32_t aStart, int32_t aEnd)
|
||||
text, event.mData.Length(), event.mRanges->Length());
|
||||
#endif // DEBUG_ANDROID_IME
|
||||
|
||||
NS_ENSURE_SUCCESS_VOID(mDispatcher->BeginNativeInputTransaction());
|
||||
NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(mDispatcher));
|
||||
mDispatcher->SetPendingComposition(string, mIMERanges);
|
||||
mDispatcher->FlushPendingComposition(status);
|
||||
mIMERanges->Clear();
|
||||
@ -1024,6 +1037,21 @@ GeckoEditableSupport::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
||||
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;
|
||||
mIMEKeyEvents.Clear();
|
||||
FlushIMEText();
|
||||
@ -1043,7 +1071,7 @@ GeckoEditableSupport::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
||||
|
||||
if (!mIMEMaskEventsCount) {
|
||||
mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_OF_BLUR);
|
||||
mDispatcher = nullptr;
|
||||
OnRemovedFrom(mDispatcher);
|
||||
}
|
||||
|
||||
// Mask events because we lost focus. Unmask on the next focus.
|
||||
@ -1091,6 +1119,12 @@ GeckoEditableSupport::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
||||
void
|
||||
GeckoEditableSupport::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher)
|
||||
{
|
||||
mDispatcher = nullptr;
|
||||
|
||||
if (mIsRemote) {
|
||||
// When we're remote, detach every time.
|
||||
OnDetach();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -1101,7 +1135,7 @@ GeckoEditableSupport::WillDispatchKeyboardEvent(
|
||||
{
|
||||
}
|
||||
|
||||
nsIMEUpdatePreference
|
||||
NS_IMETHODIMP_(nsIMEUpdatePreference)
|
||||
GeckoEditableSupport::GetIMEUpdatePreference()
|
||||
{
|
||||
// While a plugin has focus, Listener doesn't need any notifications.
|
||||
|
@ -89,9 +89,11 @@ class GeckoEditableSupport final
|
||||
COMMIT_IME_COMPOSITION
|
||||
};
|
||||
|
||||
const bool mIsRemote;
|
||||
nsWindow::WindowPtr<GeckoEditableSupport> mWindow; // Parent only
|
||||
RefPtr<TextEventDispatcher> mDispatcher;
|
||||
java::GeckoEditableChild::GlobalRef mEditable;
|
||||
bool mEditableAttached;
|
||||
InputContext mInputContext;
|
||||
AutoTArray<UniquePtr<mozilla::WidgetEvent>, 4> mIMEKeyEvents;
|
||||
AutoTArray<IMETextChange, 4> mIMETextChanges;
|
||||
@ -107,6 +109,15 @@ class GeckoEditableSupport final
|
||||
return mDispatcher ? mDispatcher->GetWidget() : mWindow;
|
||||
}
|
||||
|
||||
nsresult BeginInputTransaction(TextEventDispatcher* aDispatcher)
|
||||
{
|
||||
if (mIsRemote) {
|
||||
return aDispatcher->BeginInputTransaction(this);
|
||||
} else {
|
||||
return aDispatcher->BeginNativeInputTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~GeckoEditableSupport() {}
|
||||
|
||||
RefPtr<TextComposition> GetComposition() const;
|
||||
@ -154,11 +165,14 @@ public:
|
||||
mozilla::Move(aCall)));
|
||||
}
|
||||
|
||||
// Constructor for main process GeckoEditableChild.
|
||||
GeckoEditableSupport(nsWindow::NativePtr<GeckoEditableSupport>* aPtr,
|
||||
nsWindow* aWindow,
|
||||
java::GeckoEditableChild::Param aEditableChild)
|
||||
: mWindow(aPtr, aWindow)
|
||||
: mIsRemote(!aWindow)
|
||||
, mWindow(aPtr, aWindow)
|
||||
, mEditable(aEditableChild)
|
||||
, mEditableAttached(!mIsRemote)
|
||||
, mIMERanges(new TextRangeArray())
|
||||
, mIMEMaskEventsCount(1) // Mask IME events since there's no focus yet
|
||||
, mIMEUpdatingContext(false)
|
||||
@ -167,12 +181,19 @@ public:
|
||||
, mIMEMonitorCursor(false)
|
||||
{}
|
||||
|
||||
// Constructor for content process GeckoEditableChild.
|
||||
GeckoEditableSupport(java::GeckoEditableChild::Param aEditableChild)
|
||||
: GeckoEditableSupport(nullptr, nullptr, aEditableChild)
|
||||
{}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// TextEventDispatcherListener methods
|
||||
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
||||
const IMENotification& aNotification) override;
|
||||
|
||||
NS_IMETHOD_(nsIMEUpdatePreference) GetIMEUpdatePreference() override;
|
||||
|
||||
NS_IMETHOD_(void) OnRemovedFrom(
|
||||
TextEventDispatcher* aTextEventDispatcher) override;
|
||||
|
||||
@ -182,8 +203,6 @@ public:
|
||||
uint32_t aIndexOfKeypress,
|
||||
void* aData) override;
|
||||
|
||||
nsIMEUpdatePreference GetIMEUpdatePreference();
|
||||
|
||||
void SetInputContext(const InputContext& aContext,
|
||||
const InputContextAction& aAction);
|
||||
|
||||
@ -194,8 +213,9 @@ public:
|
||||
|
||||
void OnDetach() {
|
||||
RefPtr<GeckoEditableSupport> self(this);
|
||||
nsAppShell::PostEvent([self] {
|
||||
DisposeNative(self->mEditable);
|
||||
nsAppShell::PostEvent([this, self] {
|
||||
mEditableAttached = false;
|
||||
DisposeNative(mEditable);
|
||||
});
|
||||
}
|
||||
|
||||
|
62
widget/android/GeckoProcessManager.h
Normal file
62
widget/android/GeckoProcessManager.h
Normal 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
|
@ -459,6 +459,21 @@ const JNINativeMethod VsyncSource::Natives<Impl>::methods[] = {
|
||||
::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 */
|
||||
} /* mozilla */
|
||||
#endif // GeneratedJNINatives_h
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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::signature[];
|
||||
|
||||
@ -1750,6 +1758,23 @@ auto VsyncSource::INSTANCE() -> VsyncSource::LocalRef
|
||||
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[] =
|
||||
"org/mozilla/gecko/util/Clipboard";
|
||||
|
||||
|
@ -2460,6 +2460,8 @@ public:
|
||||
|
||||
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_REPLY_EVENT = -1;
|
||||
@ -2587,6 +2589,25 @@ public:
|
||||
|
||||
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 {
|
||||
typedef GeckoThread Owner;
|
||||
typedef void ReturnType;
|
||||
@ -5003,6 +5024,71 @@ public:
|
||||
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>
|
||||
{
|
||||
public:
|
||||
|
@ -124,6 +124,12 @@ void SetGeckoThreadEnv(JNIEnv* aEnv)
|
||||
"loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
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(
|
||||
aEnv->FindClass("org/mozilla/gecko/GeckoApp"));
|
||||
aEnv->ExceptionClear();
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "nsIDOMWakeLockListener.h"
|
||||
#include "nsIPowerManagerService.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
#include "nsITabChild.h"
|
||||
#include "nsIURIFixup.h"
|
||||
#include "nsCategoryManagerUtils.h"
|
||||
#include "nsCDefaultURIFixup.h"
|
||||
@ -35,6 +36,7 @@
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "prenv.h"
|
||||
|
||||
#include "AndroidBridge.h"
|
||||
@ -65,6 +67,7 @@
|
||||
#include "ANRReporter.h"
|
||||
#include "GeckoBatteryManager.h"
|
||||
#include "GeckoNetworkManager.h"
|
||||
#include "GeckoProcessManager.h"
|
||||
#include "GeckoScreenOrientation.h"
|
||||
#include "PrefsHelper.h"
|
||||
#include "fennec/MemoryMonitor.h"
|
||||
@ -384,6 +387,10 @@ nsAppShell::nsAppShell()
|
||||
}
|
||||
|
||||
if (!XRE_IsParentProcess()) {
|
||||
if (jni::IsAvailable()) {
|
||||
// Set the corresponding state in GeckoThread.
|
||||
java::GeckoThread::SetState(java::GeckoThread::State::RUNNING());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -394,6 +401,7 @@ nsAppShell::nsAppShell()
|
||||
GeckoThreadSupport::Init();
|
||||
mozilla::GeckoBatteryManager::Init();
|
||||
mozilla::GeckoNetworkManager::Init();
|
||||
mozilla::GeckoProcessManager::Init();
|
||||
mozilla::GeckoScreenOrientation::Init();
|
||||
mozilla::PrefsHelper::Init();
|
||||
nsWindow::InitNatives();
|
||||
@ -437,7 +445,7 @@ nsAppShell::~nsAppShell()
|
||||
sWakeLockListener = nullptr;
|
||||
}
|
||||
|
||||
if (jni::IsAvailable()) {
|
||||
if (jni::IsAvailable() && XRE_IsParentProcess()) {
|
||||
DestroyAndroidUiThread();
|
||||
AndroidBridge::DeconstructBridge();
|
||||
}
|
||||
@ -502,6 +510,7 @@ nsAppShell::Init()
|
||||
obsServ->AddObserver(this, "browser-delayed-startup-finished", false);
|
||||
obsServ->AddObserver(this, "profile-after-change", 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, "xpcom-shutdown", false);
|
||||
}
|
||||
@ -595,6 +604,37 @@ nsAppShell::Observe(nsISupports* aSubject,
|
||||
if (jni::IsAvailable()) {
|
||||
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) {
|
||||
@ -626,7 +666,7 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
||||
// (bug 750713). Looper messages effectively have the lowest
|
||||
// priority because we only process them before we're about to
|
||||
// wait for new events.
|
||||
if (jni::IsAvailable() &&
|
||||
if (jni::IsAvailable() && XRE_IsParentProcess() &&
|
||||
AndroidBridge::Bridge()->PumpMessageLoop()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/jni/Natives.h"
|
||||
@ -147,6 +148,13 @@ public:
|
||||
mozilla::UniquePtr<Event>(*eventFactory)(
|
||||
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);
|
||||
|
||||
void SetBrowserApp(nsIAndroidBrowserApp* aBrowserApp) {
|
||||
|
@ -2121,20 +2121,6 @@ nsWindow::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
|
||||
nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
|
||||
TouchPointerState aPointerState,
|
||||
|
@ -130,7 +130,9 @@ public:
|
||||
, mWindowLock(NativePtr<Impl>::sName)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mPtr->mPtr = this;
|
||||
if (mPtr) {
|
||||
mPtr->mPtr = this;
|
||||
}
|
||||
}
|
||||
|
||||
~WindowPtr()
|
||||
@ -272,7 +274,6 @@ public:
|
||||
virtual void SetInputContext(const InputContext& aContext,
|
||||
const InputContextAction& aAction) override;
|
||||
virtual InputContext GetInputContext() override;
|
||||
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
|
||||
|
||||
void SetSelectionDragState(bool aState);
|
||||
LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
|
||||
@ -315,6 +316,8 @@ public:
|
||||
// event (like a keypress or mouse click).
|
||||
void UserActivity();
|
||||
|
||||
mozilla::java::GeckoEditable::Ref& GetEditableParent() { return mEditable; }
|
||||
|
||||
protected:
|
||||
void BringToFront();
|
||||
nsWindow *FindTopLevel();
|
||||
|
@ -774,6 +774,7 @@ public:
|
||||
// TextEventDispatcherListener methods
|
||||
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
||||
const IMENotification& aNotification) override;
|
||||
NS_IMETHOD_(nsIMEUpdatePreference) GetIMEUpdatePreference() override;
|
||||
NS_IMETHOD_(void) OnRemovedFrom(
|
||||
TextEventDispatcher* aTextEventDispatcher) override;
|
||||
NS_IMETHOD_(void) WillDispatchKeyboardEvent(
|
||||
|
@ -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)
|
||||
IMEInputHandler::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher)
|
||||
{
|
||||
|
@ -398,7 +398,6 @@ public:
|
||||
void* aCallbackData,
|
||||
uint32_t aGeckoKeyCode,
|
||||
uint32_t aCocoaKeyCode);
|
||||
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
|
||||
|
||||
virtual nsTransparencyMode GetTransparencyMode() override;
|
||||
virtual void SetTransparencyMode(nsTransparencyMode aMode) override;
|
||||
|
@ -1893,15 +1893,6 @@ nsChildView::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
|
||||
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>* editorView = mView;
|
||||
|
@ -324,8 +324,8 @@ IMContextWrapper::GetTextEventDispatcher()
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
nsIMEUpdatePreference
|
||||
IMContextWrapper::GetIMEUpdatePreference() const
|
||||
NS_IMETHODIMP_(nsIMEUpdatePreference)
|
||||
IMContextWrapper::GetIMEUpdatePreference()
|
||||
{
|
||||
// While a plugin has focus, IMContextWrapper doesn't need any
|
||||
// notifications.
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
|
||||
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
||||
const IMENotification& aNotification) override;
|
||||
NS_IMETHOD_(nsIMEUpdatePreference) GetIMEUpdatePreference() override;
|
||||
NS_IMETHOD_(void) OnRemovedFrom(
|
||||
TextEventDispatcher* aTextEventDispatcher) override;
|
||||
NS_IMETHOD_(void) WillDispatchKeyboardEvent(
|
||||
@ -51,8 +52,6 @@ public:
|
||||
// I.e., the focus is in the normal editors.
|
||||
bool IsEnabled() const;
|
||||
|
||||
nsIMEUpdatePreference GetIMEUpdatePreference() const;
|
||||
|
||||
// OnFocusWindow is a notification that aWindow is going to be focused.
|
||||
void OnFocusWindow(nsWindow* aWindow);
|
||||
// OnBlurWindow is a notification that aWindow is going to be unfocused.
|
||||
|
@ -6099,15 +6099,6 @@ nsWindow::GetInputContext()
|
||||
return context;
|
||||
}
|
||||
|
||||
nsIMEUpdatePreference
|
||||
nsWindow::GetIMEUpdatePreference()
|
||||
{
|
||||
if (!mIMContext) {
|
||||
return nsIMEUpdatePreference();
|
||||
}
|
||||
return mIMContext->GetIMEUpdatePreference();
|
||||
}
|
||||
|
||||
TextEventDispatcherListener*
|
||||
nsWindow::GetNativeTextEventDispatcherListener()
|
||||
{
|
||||
|
@ -274,7 +274,6 @@ public:
|
||||
virtual void SetInputContext(const InputContext& aContext,
|
||||
const InputContextAction& aAction) override;
|
||||
virtual InputContext GetInputContext() override;
|
||||
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
|
||||
virtual TextEventDispatcherListener*
|
||||
GetNativeTextEventDispatcherListener() override;
|
||||
bool ExecuteNativeKeyBindingRemapped(
|
||||
|
@ -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
|
||||
nsBaseWidget::EnsureTextEventDispatcher()
|
||||
{
|
||||
|
@ -288,7 +288,7 @@ public:
|
||||
void* aCallbackData) override { return false; }
|
||||
bool ComputeShouldAccelerate();
|
||||
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 already_AddRefed<nsIWidget>
|
||||
CreateChild(const LayoutDeviceIntRect& aRect,
|
||||
|
@ -56,6 +56,12 @@ WinTextEventDispatcherListener::NotifyIME(
|
||||
return IMEHandler::NotifyIME(window, aNotification);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsIMEUpdatePreference)
|
||||
WinTextEventDispatcherListener::GetIMEUpdatePreference()
|
||||
{
|
||||
return IMEHandler::GetUpdatePreference();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
WinTextEventDispatcherListener::OnRemovedFrom(
|
||||
TextEventDispatcher* aTextEventDispatcher)
|
||||
|
@ -29,6 +29,7 @@ public:
|
||||
|
||||
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
||||
const IMENotification& aNotification) override;
|
||||
NS_IMETHOD_(nsIMEUpdatePreference) GetIMEUpdatePreference() override;
|
||||
NS_IMETHOD_(void) OnRemovedFrom(
|
||||
TextEventDispatcher* aTextEventDispatcher) override;
|
||||
NS_IMETHOD_(void) WillDispatchKeyboardEvent(
|
||||
|
@ -7225,12 +7225,6 @@ nsWindow::GetInputContext()
|
||||
return mInputContext;
|
||||
}
|
||||
|
||||
nsIMEUpdatePreference
|
||||
nsWindow::GetIMEUpdatePreference()
|
||||
{
|
||||
return IMEHandler::GetUpdatePreference();
|
||||
}
|
||||
|
||||
TextEventDispatcherListener*
|
||||
nsWindow::GetNativeTextEventDispatcherListener()
|
||||
{
|
||||
|
@ -210,7 +210,6 @@ public:
|
||||
virtual nsTransparencyMode GetTransparencyMode() override;
|
||||
virtual void UpdateOpaqueRegion(const LayoutDeviceIntRegion& aOpaqueRegion) override;
|
||||
#endif // MOZ_XUL
|
||||
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
|
||||
virtual nsresult SetNonClientMargins(LayoutDeviceIntMargin& aMargins) override;
|
||||
void SetDrawsInTitlebar(bool aState) override;
|
||||
virtual void UpdateWindowDraggingRegion(const LayoutDeviceIntRegion& aRegion) override;
|
||||
|
@ -22,6 +22,10 @@
|
||||
#include "XREChildData.h"
|
||||
#include "XREShellData.h"
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
#include <jni.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A directory service key which provides the platform-correct "application
|
||||
* 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)
|
||||
XRE_API(void,
|
||||
XRE_SetAndroidChildFds, (int crashFd, int ipcFd))
|
||||
XRE_SetAndroidChildFds, (JNIEnv* env, int crashFd, int ipcFd))
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
XRE_API(void,
|
||||
|
Loading…
Reference in New Issue
Block a user