author | Jim Chen <nchen@mozilla.com> |
Thu, 08 Oct 2015 15:25:49 -0400 | |
changeset 266984 | 64460d7a57db2fbdb05213ddbb538636adcb0637 |
parent 266983 | fd8e1746870e57c537646dfd219847e55727cba9 |
child 266985 | d68116719755ae6f51be5198ae2a91916741f7cd |
push id | 29504 |
push user | cbook@mozilla.com |
push date | Fri, 09 Oct 2015 09:43:23 +0000 |
treeherder | mozilla-central@d01dd42e654b [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | esawin |
bugs | 1209574 |
milestone | 44.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -127,18 +127,16 @@ import android.widget.Toast; public class GeckoAppShell { private static final String LOGTAG = "GeckoAppShell"; private static final boolean LOGGING = false; // We have static members only. private GeckoAppShell() { } - private static GeckoEditableListener editableListener; - private static final CrashHandler CRASH_HANDLER = new CrashHandler() { @Override protected String getAppPackageName() { return AppConstants.ANDROID_PACKAGE_NAME; } @Override protected Context getAppContext() { @@ -319,27 +317,16 @@ public class GeckoAppShell private static LayerView sLayerView; public static void setLayerView(LayerView lv) { if (sLayerView == lv) { return; } sLayerView = lv; - - // We should have a unique GeckoEditable instance per nsWindow instance, - // so even though we have a new view here, the underlying nsWindow is the same, - // and we don't create a new GeckoEditable. - if (editableListener == null) { - // Starting up; istall new Gecko-to-Java editable listener. - editableListener = new GeckoEditable(); - } else { - // Bind the existing GeckoEditable instance to the new LayerView - GeckoAppShell.notifyIMEContext(GeckoEditableListener.IME_STATE_DISABLED, "", "", ""); - } } @RobocopTarget public static LayerView getLayerView() { return sLayerView; } /** @@ -414,41 +401,16 @@ public class GeckoAppShell * The Gecko-side API: API methods that Gecko calls */ @WrapForJNI(allowMultithread = true, noThrow = true) public static void handleUncaughtException(Thread thread, Throwable e) { CRASH_HANDLER.uncaughtException(thread, e); } - @WrapForJNI - public static void notifyIME(int type) { - if (editableListener != null) { - editableListener.notifyIME(type); - } - } - - @WrapForJNI - public static void notifyIMEContext(int state, String typeHint, - String modeHint, String actionHint) { - if (editableListener != null) { - editableListener.notifyIMEContext(state, typeHint, - modeHint, actionHint); - } - } - - @WrapForJNI - public static void notifyIMEChange(String text, int start, int end, int newEnd) { - if (newEnd < 0) { // Selection change - editableListener.onSelectionChange(start, end); - } else { // Text change - editableListener.onTextChange(text, start, end, newEnd); - } - } - private static final Object sEventAckLock = new Object(); private static boolean sWaitingForEventAck; // Block the current thread until the Gecko event loop is caught up public static void sendEventToGeckoSync(GeckoEvent e) { e.setAckNeeded(true); long time = SystemClock.uptimeMillis();
--- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -11,16 +11,17 @@ import java.lang.reflect.InvocationHandl import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Semaphore; import org.json.JSONObject; import org.mozilla.gecko.AppConstants.Versions; +import org.mozilla.gecko.annotation.WrapForJNI; import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.util.GeckoEventListener; import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils.AssertBehavior; import android.os.Handler; import android.os.Looper; import android.text.Editable; @@ -342,17 +343,22 @@ final class GeckoEditable } } boolean isEmpty() { return mActions.isEmpty(); } } + @WrapForJNI GeckoEditable() { + if (DEBUG) { + // Called by nsWindow. + ThreadUtils.assertOnGeckoThread(); + } mActionQueue = new ActionQueue(); mSavedSelectionStart = -1; mUpdateGecko = true; mText = new SpannableStringBuilder(); mChangedText = new SpannableStringBuilder(); final Class<?>[] PROXY_INTERFACES = { Editable.class }; @@ -763,17 +769,17 @@ final class GeckoEditable for (Object span : spans) { if ((mText.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) { throw new IllegalStateException("composition not cancelled"); } } } } - @Override + @WrapForJNI @Override public void notifyIME(final int type) { if (DEBUG) { // GeckoEditableListener methods should all be called from the Gecko thread ThreadUtils.assertOnGeckoThread(); // NOTIFY_IME_REPLY_EVENT is logged separately, inside geckoActionReply() if (type != NOTIFY_IME_REPLY_EVENT) { Log.d(LOGTAG, "notifyIME(" + getConstantName(GeckoEditableListener.class, "NOTIFY_IME_", type) + @@ -839,22 +845,22 @@ final class GeckoEditable } else if (type == NOTIFY_IME_OF_FOCUS) { mGeckoFocused = true; mSuppressCompositions = false; EventDispatcher.getInstance(). registerGeckoThreadListener(this, "TextSelection:DraggingHandle"); } } - @Override + @WrapForJNI @Override public void notifyIMEContext(final int state, final String typeHint, - final String modeHint, final String actionHint) { - // Because we want to be able to bind GeckoEditable to the newest LayerView instance, - // this can be called from the Java IC thread in addition to the Gecko thread. + final String modeHint, final String actionHint) { if (DEBUG) { + // GeckoEditableListener methods should all be called from the Gecko thread + ThreadUtils.assertOnGeckoThread(); Log.d(LOGTAG, "notifyIMEContext(" + getConstantName(GeckoEditableListener.class, "IME_STATE_", state) + ", \"" + typeHint + "\", \"" + modeHint + "\", \"" + actionHint + "\")"); } geckoPostToIc(new Runnable() { @Override public void run() { // Make sure there are no other things going on @@ -867,17 +873,17 @@ final class GeckoEditable mListener = GeckoInputConnection.create(v, GeckoEditable.this); v.setInputConnectionListener((InputConnectionListener) mListener); mListener.notifyIMEContext(state, typeHint, modeHint, actionHint); } } }); } - @Override + @WrapForJNI @Override public void onSelectionChange(final int start, final int end) { if (DEBUG) { // GeckoEditableListener methods should all be called from the Gecko thread ThreadUtils.assertOnGeckoThread(); Log.d(LOGTAG, "onSelectionChange(" + start + ", " + end + ")"); } if (start < 0 || start > mText.length() || end < 0 || end > mText.length()) { Log.e(LOGTAG, "invalid selection notification range: " + @@ -923,19 +929,19 @@ final class GeckoEditable mText.insert(start, newText); } private boolean isSameText(int start, int oldEnd, CharSequence newText) { return oldEnd - start == newText.length() && TextUtils.regionMatches(mText, start, newText, 0, oldEnd - start); } - @Override + @WrapForJNI @Override public void onTextChange(final CharSequence text, final int start, - final int unboundedOldEnd, final int unboundedNewEnd) { + final int unboundedOldEnd, final int unboundedNewEnd) { if (DEBUG) { // GeckoEditableListener methods should all be called from the Gecko thread ThreadUtils.assertOnGeckoThread(); StringBuilder sb = new StringBuilder("onTextChange("); debugAppend(sb, text); sb.append(", ").append(start).append(", ") .append(unboundedOldEnd).append(", ") .append(unboundedNewEnd).append(")");
--- a/mobile/android/base/GeckoEditableListener.java +++ b/mobile/android/base/GeckoEditableListener.java @@ -1,22 +1,26 @@ /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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/. */ package org.mozilla.gecko; +import org.mozilla.gecko.annotation.WrapForJNI; + /** * Interface for the Editable to listen on the Gecko thread, as well as for the IC thread to listen * to the Editable. */ interface GeckoEditableListener { // IME notification type for notifyIME(), corresponding to NotificationToIME enum in Gecko + @WrapForJNI int NOTIFY_IME_OPEN_VKB = -2; + @WrapForJNI int NOTIFY_IME_REPLY_EVENT = -1; int NOTIFY_IME_OF_FOCUS = 1; int NOTIFY_IME_OF_BLUR = 2; int NOTIFY_IME_TO_COMMIT_COMPOSITION = 8; int NOTIFY_IME_TO_CANCEL_COMPOSITION = 9; // IME enabled state for notifyIMEContext() int IME_STATE_DISABLED = 0; int IME_STATE_ENABLED = 1;
--- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -545,40 +545,16 @@ auto GeckoAppShell::NetworkLinkType() -> constexpr char GeckoAppShell::NotifyDefaultPrevented_t::name[]; constexpr char GeckoAppShell::NotifyDefaultPrevented_t::signature[]; auto GeckoAppShell::NotifyDefaultPrevented(bool a0) -> void { return mozilla::jni::Method<NotifyDefaultPrevented_t>::Call(nullptr, nullptr, a0); } -constexpr char GeckoAppShell::NotifyIME_t::name[]; -constexpr char GeckoAppShell::NotifyIME_t::signature[]; - -auto GeckoAppShell::NotifyIME(int32_t a0) -> void -{ - return mozilla::jni::Method<NotifyIME_t>::Call(nullptr, nullptr, a0); -} - -constexpr char GeckoAppShell::NotifyIMEChange_t::name[]; -constexpr char GeckoAppShell::NotifyIMEChange_t::signature[]; - -auto GeckoAppShell::NotifyIMEChange(mozilla::jni::String::Param a0, int32_t a1, int32_t a2, int32_t a3) -> void -{ - return mozilla::jni::Method<NotifyIMEChange_t>::Call(nullptr, nullptr, a0, a1, a2, a3); -} - -constexpr char GeckoAppShell::NotifyIMEContext_t::name[]; -constexpr char GeckoAppShell::NotifyIMEContext_t::signature[]; - -auto GeckoAppShell::NotifyIMEContext(int32_t a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2, mozilla::jni::String::Param a3) -> void -{ - return mozilla::jni::Method<NotifyIMEContext_t>::Call(nullptr, nullptr, a0, a1, a2, a3); -} - constexpr char GeckoAppShell::NotifyWakeLockChanged_t::name[]; constexpr char GeckoAppShell::NotifyWakeLockChanged_t::signature[]; auto GeckoAppShell::NotifyWakeLockChanged(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1) -> void { return mozilla::jni::Method<NotifyWakeLockChanged_t>::Call(nullptr, nullptr, a0, a1); } @@ -737,16 +713,60 @@ auto GeckoAppShell::Vibrate1(int64_t a0) constexpr char GeckoAppShell::VibrateA_t::name[]; constexpr char GeckoAppShell::VibrateA_t::signature[]; auto GeckoAppShell::VibrateA(mozilla::jni::LongArray::Param a0, int32_t a1) -> void { return mozilla::jni::Method<VibrateA_t>::Call(nullptr, nullptr, a0, a1); } +constexpr char GeckoEditable::name[]; + +constexpr char GeckoEditable::New_t::name[]; +constexpr char GeckoEditable::New_t::signature[]; + +auto GeckoEditable::New() -> GeckoEditable::LocalRef +{ + return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr); +} + +constexpr char GeckoEditable::NotifyIME_t::name[]; +constexpr char GeckoEditable::NotifyIME_t::signature[]; + +auto GeckoEditable::NotifyIME(int32_t a0) const -> void +{ + return mozilla::jni::Method<NotifyIME_t>::Call(this, nullptr, a0); +} + +constexpr char GeckoEditable::NotifyIMEContext_t::name[]; +constexpr char GeckoEditable::NotifyIMEContext_t::signature[]; + +auto GeckoEditable::NotifyIMEContext(int32_t a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2, mozilla::jni::String::Param a3) const -> void +{ + return mozilla::jni::Method<NotifyIMEContext_t>::Call(this, nullptr, a0, a1, a2, a3); +} + +constexpr char GeckoEditable::OnSelectionChange_t::name[]; +constexpr char GeckoEditable::OnSelectionChange_t::signature[]; + +auto GeckoEditable::OnSelectionChange(int32_t a0, int32_t a1) const -> void +{ + return mozilla::jni::Method<OnSelectionChange_t>::Call(this, nullptr, a0, a1); +} + +constexpr char GeckoEditable::OnTextChange_t::name[]; +constexpr char GeckoEditable::OnTextChange_t::signature[]; + +auto GeckoEditable::OnTextChange(mozilla::jni::String::Param a0, int32_t a1, int32_t a2, int32_t a3) const -> void +{ + return mozilla::jni::Method<OnTextChange_t>::Call(this, nullptr, a0, a1, a2, a3); +} + +constexpr char GeckoEditableListener::name[]; + constexpr char GeckoJavaSampler::name[]; constexpr char GeckoJavaSampler::GetFrameNameJavaProfilingWrapper_t::name[]; constexpr char GeckoJavaSampler::GetFrameNameJavaProfilingWrapper_t::signature[]; auto GeckoJavaSampler::GetFrameNameJavaProfilingWrapper(int32_t a0, int32_t a1, int32_t a2) -> mozilla::jni::String::LocalRef { return mozilla::jni::Method<GetFrameNameJavaProfilingWrapper_t>::Call(nullptr, nullptr, a0, a1, a2);
--- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -1309,76 +1309,16 @@ public: static const bool isMultithreaded = false; static const mozilla::jni::ExceptionMode exceptionMode = mozilla::jni::ExceptionMode::ABORT; }; static auto NotifyDefaultPrevented(bool) -> void; public: - struct NotifyIME_t { - typedef GeckoAppShell Owner; - typedef void ReturnType; - typedef void SetterType; - typedef mozilla::jni::Args< - int32_t> Args; - static constexpr char name[] = "notifyIME"; - static constexpr char signature[] = - "(I)V"; - static const bool isStatic = true; - static const bool isMultithreaded = false; - static const mozilla::jni::ExceptionMode exceptionMode = - mozilla::jni::ExceptionMode::ABORT; - }; - - static auto NotifyIME(int32_t) -> void; - -public: - struct NotifyIMEChange_t { - typedef GeckoAppShell Owner; - typedef void ReturnType; - typedef void SetterType; - typedef mozilla::jni::Args< - mozilla::jni::String::Param, - int32_t, - int32_t, - int32_t> Args; - static constexpr char name[] = "notifyIMEChange"; - static constexpr char signature[] = - "(Ljava/lang/String;III)V"; - static const bool isStatic = true; - static const bool isMultithreaded = false; - static const mozilla::jni::ExceptionMode exceptionMode = - mozilla::jni::ExceptionMode::ABORT; - }; - - static auto NotifyIMEChange(mozilla::jni::String::Param, int32_t, int32_t, int32_t) -> void; - -public: - struct NotifyIMEContext_t { - typedef GeckoAppShell Owner; - typedef void ReturnType; - typedef void SetterType; - typedef mozilla::jni::Args< - int32_t, - mozilla::jni::String::Param, - mozilla::jni::String::Param, - mozilla::jni::String::Param> Args; - static constexpr char name[] = "notifyIMEContext"; - static constexpr char signature[] = - "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"; - static const bool isStatic = true; - static const bool isMultithreaded = false; - static const mozilla::jni::ExceptionMode exceptionMode = - mozilla::jni::ExceptionMode::ABORT; - }; - - static auto NotifyIMEContext(int32_t, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param) -> void; - -public: struct NotifyWakeLockChanged_t { typedef GeckoAppShell Owner; typedef void ReturnType; typedef void SetterType; typedef mozilla::jni::Args< mozilla::jni::String::Param, mozilla::jni::String::Param> Args; static constexpr char name[] = "notifyWakeLockChanged"; @@ -1759,16 +1699,150 @@ public: static const mozilla::jni::ExceptionMode exceptionMode = mozilla::jni::ExceptionMode::ABORT; }; static auto VibrateA(mozilla::jni::LongArray::Param, int32_t) -> void; }; +class GeckoEditable : public mozilla::jni::Class<GeckoEditable> +{ +public: + typedef mozilla::jni::Ref<GeckoEditable> Ref; + typedef mozilla::jni::LocalRef<GeckoEditable> LocalRef; + typedef mozilla::jni::GlobalRef<GeckoEditable> GlobalRef; + typedef const mozilla::jni::Param<GeckoEditable>& Param; + + static constexpr char name[] = + "org/mozilla/gecko/GeckoEditable"; + +protected: + GeckoEditable(jobject instance) : Class(instance) {} + +public: + struct New_t { + typedef GeckoEditable Owner; + typedef GeckoEditable::LocalRef ReturnType; + typedef GeckoEditable::Param SetterType; + typedef mozilla::jni::Args<> Args; + static constexpr char name[] = "<init>"; + static constexpr char signature[] = + "()V"; + static const bool isStatic = false; + static const bool isMultithreaded = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + static auto New() -> GeckoEditable::LocalRef; + +public: + struct NotifyIME_t { + typedef GeckoEditable Owner; + typedef void ReturnType; + typedef void SetterType; + typedef mozilla::jni::Args< + int32_t> Args; + static constexpr char name[] = "notifyIME"; + static constexpr char signature[] = + "(I)V"; + static const bool isStatic = false; + static const bool isMultithreaded = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + auto NotifyIME(int32_t) const -> void; + +public: + struct NotifyIMEContext_t { + typedef GeckoEditable Owner; + typedef void ReturnType; + typedef void SetterType; + typedef mozilla::jni::Args< + int32_t, + mozilla::jni::String::Param, + mozilla::jni::String::Param, + mozilla::jni::String::Param> Args; + static constexpr char name[] = "notifyIMEContext"; + static constexpr char signature[] = + "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"; + static const bool isStatic = false; + static const bool isMultithreaded = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + auto NotifyIMEContext(int32_t, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param) const -> void; + +public: + struct OnSelectionChange_t { + typedef GeckoEditable Owner; + typedef void ReturnType; + typedef void SetterType; + typedef mozilla::jni::Args< + int32_t, + int32_t> Args; + static constexpr char name[] = "onSelectionChange"; + static constexpr char signature[] = + "(II)V"; + static const bool isStatic = false; + static const bool isMultithreaded = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + auto OnSelectionChange(int32_t, int32_t) const -> void; + +public: + struct OnTextChange_t { + typedef GeckoEditable Owner; + typedef void ReturnType; + typedef void SetterType; + typedef mozilla::jni::Args< + mozilla::jni::String::Param, + int32_t, + int32_t, + int32_t> Args; + static constexpr char name[] = "onTextChange"; + static constexpr char signature[] = + "(Ljava/lang/CharSequence;III)V"; + static const bool isStatic = false; + static const bool isMultithreaded = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + auto OnTextChange(mozilla::jni::String::Param, int32_t, int32_t, int32_t) const -> void; + +}; + +class GeckoEditableListener : public mozilla::jni::Class<GeckoEditableListener> +{ +public: + typedef mozilla::jni::Ref<GeckoEditableListener> Ref; + typedef mozilla::jni::LocalRef<GeckoEditableListener> LocalRef; + typedef mozilla::jni::GlobalRef<GeckoEditableListener> GlobalRef; + typedef const mozilla::jni::Param<GeckoEditableListener>& Param; + + static constexpr char name[] = + "org/mozilla/gecko/GeckoEditableListener"; + +protected: + GeckoEditableListener(jobject instance) : Class(instance) {} + +public: + static const int32_t NOTIFY_IME_OPEN_VKB = -2; + +public: + static const int32_t NOTIFY_IME_REPLY_EVENT = -1; + +}; + class GeckoJavaSampler : public mozilla::jni::Class<GeckoJavaSampler> { public: typedef mozilla::jni::Ref<GeckoJavaSampler> Ref; typedef mozilla::jni::LocalRef<GeckoJavaSampler> LocalRef; typedef mozilla::jni::GlobalRef<GeckoJavaSampler> GlobalRef; typedef const mozilla::jni::Param<GeckoJavaSampler>& Param;
--- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -244,16 +244,20 @@ nsWindow::Natives::Open(const jni::Class args, getter_AddRefs(window)); MOZ_ASSERT(window); nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(window); MOZ_ASSERT(widget); gGeckoViewWindow = static_cast<nsWindow*>(widget.get()); gGeckoViewWindow->mNatives = mozilla::MakeUnique<Natives>(gGeckoViewWindow); + + // Create GeckoEditable for the new nsWindow/GeckoView pair. + gGeckoViewWindow->mEditable = GeckoEditable::New(); + AttachNative(GeckoView::Window::LocalRef(cls.Env(), gvWindow), gGeckoViewWindow->mNatives.get()); } void nsWindow::Natives::DisposeNative(const GeckoView::Window::LocalRef& instance) { // FIXME: because we don't support separate nsWindow for each GeckoView @@ -1006,18 +1010,18 @@ nsWindow::OnGlobalAndroidEvent(AndroidGe } case AndroidGeckoEvent::KEY_EVENT: win->UserActivity(); win->OnKeyEvent(ae); break; case AndroidGeckoEvent::IME_EVENT: - win->UserActivity(); - win->OnIMEEvent(ae); + gGeckoViewWindow->UserActivity(); + gGeckoViewWindow->OnIMEEvent(ae); break; case AndroidGeckoEvent::IME_KEY_EVENT: // Keys synthesized by Java IME code are saved in the mIMEKeyEvents // array until the next IME_REPLACE_TEXT event, at which point // these keys are dispatched in sequence. win->mIMEKeyEvents.AppendElement(*ae); break; @@ -1803,17 +1807,17 @@ public: }; /* * Get the current composition object, if any. */ nsRefPtr<mozilla::TextComposition> nsWindow::GetIMEComposition() { - MOZ_ASSERT(this == TopWindow()); + MOZ_ASSERT(this == FindTopLevel()); return mozilla::IMEStateManager::GetTextCompositionFor(this); } /* Remove the composition but leave the text content as-is */ void nsWindow::RemoveIMEComposition() @@ -1879,49 +1883,49 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent * // we just use INT32_MAX IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE); notification.mTextChangeData.mStartOffset = 0; notification.mTextChangeData.mRemovedEndOffset = notification.mTextChangeData.mAddedEndOffset = INT32_MAX / 2; NotifyIMEOfTextChange(notification); FlushIMEChanges(); } - GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); + mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); return; } else if (ae->Action() == AndroidGeckoEvent::IME_UPDATE_CONTEXT) { - GeckoAppShell::NotifyIMEContext(mInputContext.mIMEState.mEnabled, - mInputContext.mHTMLInputType, - mInputContext.mHTMLInputInputmode, - mInputContext.mActionHint); + mEditable->NotifyIMEContext(mInputContext.mIMEState.mEnabled, + mInputContext.mHTMLInputType, + mInputContext.mHTMLInputInputmode, + mInputContext.mActionHint); mIMEUpdatingContext = false; return; } if (mIMEMaskEventsCount > 0) { // Still reply to events, but don't do anything else if (ae->Action() == AndroidGeckoEvent::IME_SYNCHRONIZE || ae->Action() == AndroidGeckoEvent::IME_COMPOSE_TEXT || ae->Action() == AndroidGeckoEvent::IME_REPLACE_TEXT) { - GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); + mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); } return; } switch (ae->Action()) { case AndroidGeckoEvent::IME_FLUSH_CHANGES: { FlushIMEChanges(); } break; case AndroidGeckoEvent::IME_SYNCHRONIZE: { FlushIMEChanges(); - GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); + mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); } break; case AndroidGeckoEvent::IME_REPLACE_TEXT: case AndroidGeckoEvent::IME_COMPOSE_TEXT: { /* Replace text in Gecko thread from ae->Start() to ae->End() @@ -1956,17 +1960,18 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent * } if (!mIMEKeyEvents.IsEmpty()) { for (uint32_t i = 0; i < mIMEKeyEvents.Length(); i++) { OnKeyEvent(&mIMEKeyEvents[i]); } mIMEKeyEvents.Clear(); FlushIMEChanges(); - GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); + mEditable->NotifyIME( + GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); // Break out of the switch block break; } { WidgetCompositionEvent event(true, eCompositionStart, this); InitEvent(event, nullptr); DispatchEvent(&event); @@ -2007,17 +2012,17 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent * DispatchEvent(&compositionCommitEvent); } if (mInputContext.mMayBeIMEUnaware) { SendIMEDummyKeyEvents(); } FlushIMEChanges(); - GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); + mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); } break; case AndroidGeckoEvent::IME_SET_SELECTION: { /* Set Gecko selection to ae->Start() to ae->End() @@ -2171,23 +2176,27 @@ nsWindow::UserActivity() if (mIdleService) { mIdleService->ResetIdleTimeOut(0); } } nsresult nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification) { - MOZ_ASSERT(this == TopWindow()); + MOZ_ASSERT(this == FindTopLevel()); + + if (!mEditable) { + return NS_ERROR_NOT_AVAILABLE; + } switch (aIMENotification.mMessage) { case REQUEST_TO_COMMIT_COMPOSITION: //ALOGIME("IME: REQUEST_TO_COMMIT_COMPOSITION: s=%d", aState); RemoveIMEComposition(); - GeckoAppShell::NotifyIME(REQUEST_TO_COMMIT_COMPOSITION); + mEditable->NotifyIME(REQUEST_TO_COMMIT_COMPOSITION); return NS_OK; case REQUEST_TO_CANCEL_COMPOSITION: ALOGIME("IME: REQUEST_TO_CANCEL_COMPOSITION"); // Cancel composition on Gecko side if (!!GetIMEComposition()) { nsRefPtr<nsWindow> kungFuDeathGrip(this); @@ -2195,33 +2204,33 @@ nsWindow::NotifyIMEInternal(const IMENot WidgetCompositionEvent compositionCommitEvent( true, eCompositionCommit, this); InitEvent(compositionCommitEvent, nullptr); // Dispatch it with empty mData value for canceling the // composition DispatchEvent(&compositionCommitEvent); } - GeckoAppShell::NotifyIME(REQUEST_TO_CANCEL_COMPOSITION); + mEditable->NotifyIME(REQUEST_TO_CANCEL_COMPOSITION); return NS_OK; case NOTIFY_IME_OF_FOCUS: ALOGIME("IME: NOTIFY_IME_OF_FOCUS"); - GeckoAppShell::NotifyIME(NOTIFY_IME_OF_FOCUS); + mEditable->NotifyIME(NOTIFY_IME_OF_FOCUS); return NS_OK; case NOTIFY_IME_OF_BLUR: ALOGIME("IME: NOTIFY_IME_OF_BLUR"); // Mask events because we lost focus. On the next focus event, // Gecko will notify Java, and Java will send an acknowledge focus // event back to Gecko. That is where we unmask event handling mIMEMaskEventsCount++; - GeckoAppShell::NotifyIME(NOTIFY_IME_OF_BLUR); + mEditable->NotifyIME(NOTIFY_IME_OF_BLUR); return NS_OK; case NOTIFY_IME_OF_SELECTION_CHANGE: if (mIMEMaskSelectionUpdate) { return NS_OK; } ALOGIME("IME: NOTIFY_IME_OF_SELECTION_CHANGE"); @@ -2241,26 +2250,30 @@ nsWindow::NotifyIMEInternal(const IMENot NS_IMETHODIMP_(void) nsWindow::SetInputContext(const InputContext& aContext, const InputContextAction& aAction) { #ifdef MOZ_B2GDROID // Disable the Android keyboard on b2gdroid. return; #endif - nsWindow *top = TopWindow(); + nsWindow *top = FindTopLevel(); if (top && this != top) { // We are using an IME event later to notify Java, and the IME event // will be processed by the top window. Therefore, to ensure the // IME event uses the correct mInputContext, we need to let the top // window process SetInputContext top->SetInputContext(aContext, aAction); return; } + if (!mEditable) { + return; + } + ALOGIME("IME: SetInputContext: s=0x%X, 0x%X, action=0x%X, 0x%X", aContext.mIMEState.mEnabled, aContext.mIMEState.mOpen, aAction.mCause, aAction.mFocusChange); // Ensure that opening the virtual keyboard is allowed for this specific // InputContext depending on the content.ime.strict.policy pref if (aContext.mIMEState.mEnabled != IMEState::DISABLED && aContext.mIMEState.mEnabled != IMEState::PLUGIN && @@ -2279,33 +2292,33 @@ nsWindow::SetInputContext(const InputCon enabled = IMEState::DISABLED; } mInputContext = aContext; mInputContext.mIMEState.mEnabled = enabled; if (enabled == IMEState::ENABLED && aAction.UserMightRequestOpenVKB()) { // Don't reset keyboard when we should simply open the vkb - GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_OPEN_VKB); + mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_OPEN_VKB); return; } if (mIMEUpdatingContext) { return; } AndroidGeckoEvent *event = AndroidGeckoEvent::MakeIMEEvent( AndroidGeckoEvent::IME_UPDATE_CONTEXT); nsAppShell::gAppShell->PostEvent(event); mIMEUpdatingContext = true; } NS_IMETHODIMP_(InputContext) nsWindow::GetInputContext() { - nsWindow *top = TopWindow(); + nsWindow *top = FindTopLevel(); if (top && this != top) { // We let the top window process SetInputContext, // so we should let it process GetInputContext as well. return top->GetInputContext(); } InputContext context = mInputContext; context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED; // We assume that there is only one context per process on Android @@ -2355,39 +2368,40 @@ nsWindow::FlushIMEChanges() InitEvent(event, nullptr); event.InitForQueryTextContent(change.mStart, change.mNewEnd - change.mStart); DispatchEvent(&event); NS_ENSURE_TRUE_VOID(event.mSucceeded); NS_ENSURE_TRUE_VOID(event.mReply.mContentsRoot == imeRoot.get()); } - GeckoAppShell::NotifyIMEChange(event.mReply.mString, change.mStart, - change.mOldEnd, change.mNewEnd); + mEditable->OnTextChange(event.mReply.mString, change.mStart, + change.mOldEnd, change.mNewEnd); } mIMETextChanges.Clear(); if (mIMESelectionChanged) { WidgetQueryContentEvent event(true, eQuerySelectedText, this); InitEvent(event, nullptr); DispatchEvent(&event); NS_ENSURE_TRUE_VOID(event.mSucceeded); NS_ENSURE_TRUE_VOID(event.mReply.mContentsRoot == imeRoot.get()); - GeckoAppShell::NotifyIMEChange(EmptyString(), - int32_t(event.GetSelectionStart()), - int32_t(event.GetSelectionEnd()), -1); + mEditable->OnSelectionChange(int32_t(event.GetSelectionStart()), + int32_t(event.GetSelectionEnd())); mIMESelectionChanged = false; } } nsresult nsWindow::NotifyIMEOfTextChange(const IMENotification& aIMENotification) { + MOZ_ASSERT(this == FindTopLevel()); + MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE, "NotifyIMEOfTextChange() is called with invaild notification"); ALOGIME("IME: NotifyIMEOfTextChange: s=%d, oe=%d, ne=%d", aIMENotification.mTextChangeData.mStartOffset, aIMENotification.mTextChangeData.mRemovedEndOffset, aIMENotification.mTextChangeData.mAddedEndOffset);
--- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -44,16 +44,19 @@ public: NS_DECL_ISUPPORTS_INHERITED static void InitNatives(); class Natives; // Object that implements native GeckoView calls; // nullptr for nsWindows that were not opened from GeckoView. mozilla::UniquePtr<Natives> mNatives; + // GeckoEditable instance used by this nsWindow; + // nullptr for nsWindows that are not GeckoViews. + mozilla::widget::GeckoEditable::GlobalRef mEditable; static void OnGlobalAndroidEvent(mozilla::AndroidGeckoEvent *ae); static mozilla::gfx::IntSize GetAndroidScreenBounds(); static nsWindow* TopWindow(); bool OnContextmenuEvent(mozilla::AndroidGeckoEvent *ae); void OnLongTapEvent(mozilla::AndroidGeckoEvent *ae); bool OnMultitouchEvent(mozilla::AndroidGeckoEvent *ae);