From 63b7a19a57856c900721ca4e75bba3cff0279221 Mon Sep 17 00:00:00 2001 From: Armen Zambrano Gasparnian Date: Wed, 30 Sep 2015 08:07:40 -0400 Subject: [PATCH 001/189] Bug 1203085 - Silence unnecessary error about not finding artifacts. DONTBUILD. r=jlund When we added support for finding artifacts from TaskCluster BBB tasks we added an error for not finding the artifacts either via buildbot properties or through the TC APIs. Unfortunately, this error did not take into consideration when mozharness sets the artifacts through the options --installer-url and --test-url. We're removing the error as few lines below the error logging is sufficient to handle all three cases and not raise misleading errors. --HG-- extra : commitid : 1nxRrdDWutr extra : histedit_source : b0720a9783cea7cdde9866fd09d5d8847c9c08e3 --- testing/mozharness/mozharness/mozilla/testing/testbase.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/testing/mozharness/mozharness/mozilla/testing/testbase.py b/testing/mozharness/mozharness/mozilla/testing/testbase.py index 782300ae85df..72e0ed24e23b 100755 --- a/testing/mozharness/mozharness/mozilla/testing/testbase.py +++ b/testing/mozharness/mozharness/mozilla/testing/testbase.py @@ -309,11 +309,6 @@ class TestingMixin(VirtualenvMixin, BuildbotMixin, ResourceMonitoringMixin, self.find_artifacts_from_buildbot_changes() elif 'taskId' in self.buildbot_config['properties']: self.find_artifacts_from_taskcluster() - else: - self.exception( - "We have not been able to determine which artifacts " - "to use in order to run the tests." - ) missing = [] if not self.installer_url: From 6fad91d10c63ee44a19d20f02f0436133cd3b304 Mon Sep 17 00:00:00 2001 From: Armen Zambrano Gasparnian Date: Tue, 6 Oct 2015 09:51:34 -0400 Subject: [PATCH 002/189] Bug 1211885 - Do not try to test if a .dmg file is_tarfile(). r=ahal --HG-- extra : commitid : 2LM7PfRKjEO extra : histedit_source : fc8e5e1b60adc577639e0bb4c3edf09127d92224 --- testing/mozbase/mozinstall/mozinstall/mozinstall.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/mozbase/mozinstall/mozinstall/mozinstall.py b/testing/mozbase/mozinstall/mozinstall/mozinstall.py index 2360660fe479..efc821cf84e4 100755 --- a/testing/mozbase/mozinstall/mozinstall/mozinstall.py +++ b/testing/mozbase/mozinstall/mozinstall/mozinstall.py @@ -110,12 +110,12 @@ def install(src, dest): trbk = None try: install_dir = None - if zipfile.is_zipfile(src) or tarfile.is_tarfile(src): - install_dir = mozfile.extract(src, dest)[0] - elif src.lower().endswith('.dmg'): + if src.lower().endswith('.dmg'): install_dir = _install_dmg(src, dest) elif src.lower().endswith('.exe'): install_dir = _install_exe(src, dest) + elif zipfile.is_zipfile(src) or tarfile.is_tarfile(src): + install_dir = mozfile.extract(src, dest)[0] return install_dir From 4050ce22a42b47ae0c8d61d61d6cb457f1f3fe57 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Wed, 7 Oct 2015 08:57:30 -0400 Subject: [PATCH 003/189] Bug 1200426 - Allow specifying parameter type when queuing native calls; r=snorp When we queue native calls in GeckoThread, we try to deduce the types of the arguments through Object.getClass(). However, there are cases where this could fail. For example, the argument could be null, or could be a String instance but the parameter type is really CharSequence. This patch introduces a way to optionally include parameter types for the queued call. When a passed-in argument is a Class instance, it is treated as the type for the next queued parameter, and the next argument is treated as the value for the queued parameter. For example, > // Queue a call with CharSequence parameter, using a String argument. > GeckoThread.queueNativeCall(..., CharSequence.class, "123"); > // Queue a call with String parameter, using a null argument. > GeckoThread.queueNativeCall(..., String.class, null); Deduction is still performed when the type is missing: > // Queue a call with int, String, and boolean parameter. > GeckoThread.queueNativeCall(..., 42, "123", true); > // Queue the same call but with a null argument. > GeckoThread.queueNativeCall(..., 42, String.class, null, true); --- mobile/android/base/GeckoThread.java | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/mobile/android/base/GeckoThread.java b/mobile/android/base/GeckoThread.java index 4b15a81d28ab..c3907e07005c 100644 --- a/mobile/android/base/GeckoThread.java +++ b/mobile/android/base/GeckoThread.java @@ -165,8 +165,15 @@ public class GeckoThread extends Thread implements GeckoEventListener { private static void queueNativeCallLocked(final Class cls, final String methodName, final Object obj, final Object[] args, final State state) { - final Class[] argTypes = new Class[args.length]; + final ArrayList> argTypes = new ArrayList<>(args.length); + final ArrayList argValues = new ArrayList<>(args.length); + for (int i = 0; i < args.length; i++) { + if (args[i] instanceof Class) { + argTypes.add((Class) args[i]); + argValues.add(args[++i]); + continue; + } Class argType = args[i].getClass(); if (argType == Boolean.class) argType = Boolean.TYPE; else if (argType == Byte.class) argType = Byte.TYPE; @@ -176,20 +183,24 @@ public class GeckoThread extends Thread implements GeckoEventListener { else if (argType == Integer.class) argType = Integer.TYPE; else if (argType == Long.class) argType = Long.TYPE; else if (argType == Short.class) argType = Short.TYPE; - argTypes[i] = argType; + argTypes.add(argType); + argValues.add(args[i]); } final Method method; try { - method = cls.getDeclaredMethod(methodName, argTypes); + method = cls.getDeclaredMethod( + methodName, argTypes.toArray(new Class[argTypes.size()])); } catch (final NoSuchMethodException e) { throw new UnsupportedOperationException("Cannot find method", e); } if (QUEUED_CALLS.size() == 0 && isStateAtLeast(state)) { - invokeMethod(method, obj, args); + invokeMethod(method, obj, argValues.toArray()); return; } - QUEUED_CALLS.add(new QueuedCall(method, obj, args, state)); + + QUEUED_CALLS.add(new QueuedCall( + method, obj, argValues.toArray(), state)); } /** @@ -200,7 +211,8 @@ public class GeckoThread extends Thread implements GeckoEventListener { * run when Gecko is at or after RUNNING state. * @param cls Class that declares the static method. * @param methodName Name of the static method. - * @param args Args to call the static method with. + * @param args Args to call the static method with; to specify a parameter type, + * pass in a Class instance first, followed by the value. */ public static void queueNativeCallUntil(final State state, final Class cls, final String methodName, final Object... args) { @@ -225,7 +237,8 @@ public class GeckoThread extends Thread implements GeckoEventListener { * @param state The Gecko state in which the native call could be executed. * @param obj Object that declares the instance method. * @param methodName Name of the instance method. - * @param args Args to call the instance method with. + * @param args Args to call the instance method with; to specify a parameter type, + * pass in a Class instance first, followed by the value. */ public static void queueNativeCallUntil(final State state, final Object obj, final String methodName, final Object... args) { From 0f413bc2a37422a827930bef5cda101e25f9651b Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Wed, 7 Oct 2015 08:57:30 -0400 Subject: [PATCH 004/189] Bug 1200426 - Convert PROCESS_OBJECT GeckoEvent to native call; r=snorp The PROCESS_OBJECT GeckoEvent is used to set the layer client object in Gecko once Gecko is done loading. This patch converts it to a native call in GeckoView.Window. --- mobile/android/base/GeckoEvent.java | 12 ------------ mobile/android/base/GeckoView.java | 11 +++++++++-- widget/android/AndroidJavaWrappers.cpp | 9 --------- widget/android/AndroidJavaWrappers.h | 10 ---------- widget/android/GeneratedJNINatives.h | 6 +++++- widget/android/GeneratedJNIWrappers.cpp | 3 +++ widget/android/GeneratedJNIWrappers.h | 16 ++++++++++++++++ widget/android/nsAppShell.cpp | 11 ----------- widget/android/nsWindow.cpp | 8 ++++++++ 9 files changed, 41 insertions(+), 45 deletions(-) diff --git a/mobile/android/base/GeckoEvent.java b/mobile/android/base/GeckoEvent.java index e8de7251a8d4..54c7cc02cef4 100644 --- a/mobile/android/base/GeckoEvent.java +++ b/mobile/android/base/GeckoEvent.java @@ -73,7 +73,6 @@ public class GeckoEvent { KEY_EVENT(1), MOTION_EVENT(2), SENSOR_EVENT(3), - PROCESS_OBJECT(4), LOCATION_EVENT(5), IME_EVENT(6), SIZE_CHANGED(8), @@ -159,8 +158,6 @@ public class GeckoEvent { public static final int ACTION_GAMEPAD_BUTTON = 1; public static final int ACTION_GAMEPAD_AXES = 2; - public static final int ACTION_OBJECT_LAYER_CLIENT = 1; - private final int mType; private int mAction; private boolean mAckNeeded; @@ -222,8 +219,6 @@ public class GeckoEvent { private float mGamepadButtonValue; private float[] mGamepadValues; - private Object mObject; - private GeckoEvent(NativeGeckoEvent event) { mType = event.value; } @@ -584,13 +579,6 @@ public class GeckoEvent { return event; } - public static GeckoEvent createObjectEvent(final int action, final Object object) { - GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.PROCESS_OBJECT); - event.mAction = action; - event.mObject = object; - return event; - } - public static GeckoEvent createLocationEvent(Location l) { GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOCATION_EVENT); event.mLocation = l; diff --git a/mobile/android/base/GeckoView.java b/mobile/android/base/GeckoView.java index f7cbadabd192..c3225d64e171 100644 --- a/mobile/android/base/GeckoView.java +++ b/mobile/android/base/GeckoView.java @@ -110,6 +110,7 @@ public class GeckoView extends LayerView @WrapForJNI private static final class Window extends JNIObject { static native void open(Window instance, int width, int height); + static native void setLayerClient(Object client); @Override protected native void disposeNative(); } @@ -142,8 +143,14 @@ public class GeckoView extends LayerView GeckoAppShell.setLayerView(this); initializeView(EventDispatcher.getInstance()); - GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent( - GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, getLayerClientObject())); + + if (GeckoThread.isStateAtLeast(GeckoThread.State.JNI_READY)) { + Window.setLayerClient(getLayerClientObject()); + } else { + GeckoThread.queueNativeCallUntil(GeckoThread.State.JNI_READY, + Window.class, "setLayerClient", + Object.class, getLayerClientObject()); + } // TODO: Fennec currently takes care of its own initialization, so this // flag is a hack used in Fennec to prevent GeckoView initialization. diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index 91b07d54b550..caeedda2ae03 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -70,7 +70,6 @@ jfieldID AndroidGeckoEvent::jGamepadButtonField = 0; jfieldID AndroidGeckoEvent::jGamepadButtonPressedField = 0; jfieldID AndroidGeckoEvent::jGamepadButtonValueField = 0; jfieldID AndroidGeckoEvent::jGamepadValuesField = 0; -jfieldID AndroidGeckoEvent::jObjectField = 0; jclass AndroidPoint::jPointClass = 0; jfieldID AndroidPoint::jXField = 0; @@ -178,7 +177,6 @@ AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv) jGamepadButtonPressedField = geckoEvent.getField("mGamepadButtonPressed", "Z"); jGamepadButtonValueField = geckoEvent.getField("mGamepadButtonValue", "F"); jGamepadValuesField = geckoEvent.getField("mGamepadValues", "[F"); - jObjectField = geckoEvent.getField("mObject", "Ljava/lang/Object;"); } void @@ -473,13 +471,6 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj) mMetaState = jenv->GetIntField(jobj, jMetaStateField); break; - case PROCESS_OBJECT: { - const jobject obj = jenv->GetObjectField(jobj, jObjectField); - mObject.Init(obj, jenv); - jenv->DeleteLocalRef(obj); - break; - } - case LOCATION_EVENT: { jobject location = jenv->GetObjectField(jobj, jLocationField); mGeoPosition = AndroidLocation::CreateGeoPosition(jenv, location); diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h index a84f6a27e24c..ed4e06e69ac0 100644 --- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -571,7 +571,6 @@ public: float GamepadButtonValue() { return mGamepadButtonValue; } const nsTArray& GamepadValues() { return mGamepadValues; } int RequestId() { return mCount; } // for convenience - const AutoGlobalWrappedJavaObject& Object() { return mObject; } bool CanCoalesceWith(AndroidGeckoEvent* ae); WidgetTouchEvent MakeTouchEvent(nsIWidget* widget); MultiTouchInput MakeMultiTouchInput(nsIWidget* widget); @@ -624,7 +623,6 @@ protected: mozilla::layers::ScrollableLayerGuid mApzGuid; uint64_t mApzInputBlockId; nsEventStatus mApzEventStatus; - AutoGlobalWrappedJavaObject mObject; void ReadIntArray(nsTArray &aVals, JNIEnv *jenv, @@ -707,15 +705,12 @@ protected: static jfieldID jGamepadButtonValueField; static jfieldID jGamepadValuesField; - static jfieldID jObjectField; - public: enum { NATIVE_POKE = 0, KEY_EVENT = 1, MOTION_EVENT = 2, SENSOR_EVENT = 3, - PROCESS_OBJECT = 4, LOCATION_EVENT = 5, IME_EVENT = 6, SIZE_CHANGED = 8, @@ -786,11 +781,6 @@ public: ACTION_GAMEPAD_BUTTON = 1, ACTION_GAMEPAD_AXES = 2 }; - - enum { - ACTION_OBJECT_LAYER_CLIENT = 1, - dummy_object_enum_list_end - }; }; class nsJNIString : public nsString diff --git a/widget/android/GeneratedJNINatives.h b/widget/android/GeneratedJNINatives.h index c372a34d2b00..ee351387834b 100644 --- a/widget/android/GeneratedJNINatives.h +++ b/widget/android/GeneratedJNINatives.h @@ -93,7 +93,11 @@ public: mozilla::jni::MakeNativeMethod( mozilla::jni::NativeStub - ::template Wrap<&Impl::Open>) + ::template Wrap<&Impl::Open>), + + mozilla::jni::MakeNativeMethod( + mozilla::jni::NativeStub + ::template Wrap<&Impl::SetLayerClient>) }; }; diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index 3623a5365e1c..5b372dd7581d 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -985,6 +985,9 @@ constexpr char GeckoView::Window::DisposeNative_t::signature[]; constexpr char GeckoView::Window::Open_t::name[]; constexpr char GeckoView::Window::Open_t::signature[]; +constexpr char GeckoView::Window::SetLayerClient_t::name[]; +constexpr char GeckoView::Window::SetLayerClient_t::signature[]; + constexpr char PrefsHelper::name[]; constexpr char PrefsHelper::GetPrefsById_t::name[]; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index 79eddff3d163..b3f88b357732 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -2394,6 +2394,22 @@ public: mozilla::jni::ExceptionMode::ABORT; }; +public: + struct SetLayerClient_t { + typedef Window Owner; + typedef void ReturnType; + typedef void SetterType; + typedef mozilla::jni::Args< + mozilla::jni::Object::Param> Args; + static constexpr char name[] = "setLayerClient"; + static constexpr char signature[] = + "(Ljava/lang/Object;)V"; + static const bool isStatic = true; + static const bool isMultithreaded = true; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + public: template class Natives; }; diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp index 8dbb9144bd53..a0dbc7b7c39d 100644 --- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -434,17 +434,6 @@ nsAppShell::LegacyGeckoEvent::Run() } break; - case AndroidGeckoEvent::PROCESS_OBJECT: { - - switch (curEvent->Action()) { - case AndroidGeckoEvent::ACTION_OBJECT_LAYER_CLIENT: - AndroidBridge::Bridge()->SetLayerClient( - widget::GeckoLayerClient::Ref::From(curEvent->Object().wrappedObject())); - break; - } - break; - } - case AndroidGeckoEvent::LOCATION_EVENT: { if (!gLocationCallback) break; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 56a31bbd8c8c..f1e21b5376aa 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -187,6 +187,14 @@ public: static void Open(const jni::ClassObject::LocalRef& cls, GeckoView::Window::Param gvWindow, int32_t width, int32_t height); + + // Set the active layer client object + static void SetLayerClient(jni::Object::Param client) + { + MOZ_ASSERT(NS_IsMainThread()); + AndroidBridge::Bridge()->SetLayerClient( + widget::GeckoLayerClient::Ref::From(client.Get())); + } }; void From 4ab3b96976a649ba2e00a4879bc09948bf4fcb50 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Wed, 7 Oct 2015 08:57:30 -0400 Subject: [PATCH 005/189] Bug 1209574 - Generate C++ name for any Java class in chain of declared classes; r=snorp Right now, when we generate bindings for Java class A, and we encounter a Java type B, we generate a corresponding C++ name only if A == B, otherwise we generate a generic "jni::Object" C++ name. For example, class Foo { class Bar { Foo getFoo(Bar bar); } } In C++, Foo.Bar.getFoo would become, class Foo { class Bar { jni::Object::LocalRef getFoo(Bar::Param bar); }; }; This patch extends the code generator so that any Java class in the chain of declared classes gets a corresponding C++ name. The above example now becomes, class Foo { class Bar { Foo::LocalRef getFoo(Bar::Param bar); }; }; --- build/annotationProcessors/CodeGenerator.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/build/annotationProcessors/CodeGenerator.java b/build/annotationProcessors/CodeGenerator.java index 0bba34e3af0a..0a8e6d5f44a0 100644 --- a/build/annotationProcessors/CodeGenerator.java +++ b/build/annotationProcessors/CodeGenerator.java @@ -66,15 +66,37 @@ public class CodeGenerator { return (includeScope ? clsName + "::" : "") + uniqueName + "_t"; } + /** + * Return the C++ type name for this class or any class within the chain + * of declaring classes, if the target class matches the given type. + * + * Return null if the given type does not match any class searched. + */ + private String getMatchingClassType(final Class type) { + Class cls = this.cls; + String clsName = this.clsName; + + while (cls != null) { + if (type == cls) { + return clsName; + } + cls = cls.getDeclaringClass(); + clsName = clsName.substring(0, Math.max(0, clsName.lastIndexOf("::"))); + } + return null; + } + private String getNativeParameterType(Class type, AnnotationInfo info) { - if (type == cls) { + final String clsName = getMatchingClassType(type); + if (clsName != null) { return Utils.getUnqualifiedName(clsName) + "::Param"; } return Utils.getNativeParameterType(type, info); } private String getNativeReturnType(Class type, AnnotationInfo info) { - if (type == cls) { + final String clsName = getMatchingClassType(type); + if (clsName != null) { return Utils.getUnqualifiedName(clsName) + "::LocalRef"; } return Utils.getNativeReturnType(type, info); From eb54e04df1abb03394bf102d6a46a4af26820c97 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Wed, 7 Oct 2015 08:57:30 -0400 Subject: [PATCH 006/189] Bug 1209574 - Generate constants for non-accessible static final fields; r=snorp We try to generate a C++ constant for static final fields, but that was failing for inaccessible fields. Now we set the field to be accessible so that we do end up generating a C++ constant. --- build/annotationProcessors/CodeGenerator.java | 1 + widget/android/GeneratedJNIWrappers.cpp | 8 -------- widget/android/GeneratedJNIWrappers.h | 16 +--------------- 3 files changed, 2 insertions(+), 23 deletions(-) diff --git a/build/annotationProcessors/CodeGenerator.java b/build/annotationProcessors/CodeGenerator.java index 0a8e6d5f44a0..b36d1602eb71 100644 --- a/build/annotationProcessors/CodeGenerator.java +++ b/build/annotationProcessors/CodeGenerator.java @@ -392,6 +392,7 @@ public class CodeGenerator { if (isStatic && isFinal && (type.isPrimitive() || type == String.class)) { Object val = null; try { + field.setAccessible(true); val = field.get(null); } catch (final IllegalAccessException e) { } diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index 5b372dd7581d..fcc500eac510 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -1507,14 +1507,6 @@ auto SQLiteBridgeException::New(mozilla::jni::String::Param a0) -> SQLiteBridgeE return mozilla::jni::Constructor::Call(nullptr, nullptr, a0); } -constexpr char SQLiteBridgeException::SerialVersionUID_t::name[]; -constexpr char SQLiteBridgeException::SerialVersionUID_t::signature[]; - -auto SQLiteBridgeException::SerialVersionUID() -> int64_t -{ - return mozilla::jni::Field::Get(nullptr, nullptr); -} - constexpr char Clipboard::name[]; constexpr char Clipboard::ClearText_t::name[]; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index b3f88b357732..4731d5ecb2f6 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -3647,21 +3647,7 @@ public: static auto New(mozilla::jni::String::Param) -> SQLiteBridgeException::LocalRef; public: - struct SerialVersionUID_t { - typedef SQLiteBridgeException Owner; - typedef int64_t ReturnType; - typedef int64_t SetterType; - typedef mozilla::jni::Args<> Args; - static constexpr char name[] = "serialVersionUID"; - static constexpr char signature[] = - "J"; - static const bool isStatic = true; - static const bool isMultithreaded = true; - static const mozilla::jni::ExceptionMode exceptionMode = - mozilla::jni::ExceptionMode::ABORT; - }; - - static auto SerialVersionUID() -> int64_t; + static const int64_t SerialVersionUID = 1; }; From d514a62034af4a4357f706926f6c7f6c4108dc9e Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Wed, 7 Oct 2015 08:57:30 -0400 Subject: [PATCH 007/189] Bug 1209574 - Move InputConnectionHandler out of gfx package; r=esawin InputConnectionHandler really doesn't belong in the gfx package, and the code to call key event handlers really doesn't belong in LayerView. This patch refactors things, so that InputConnectionHandler is renamed to org.mozilla.gecko.InputConnectionListener, and the interface is now used by GeckoView instead of by LayerView. --- mobile/android/base/GeckoAppShell.java | 8 +- mobile/android/base/GeckoEditable.java | 5 +- mobile/android/base/GeckoInputConnection.java | 5 +- mobile/android/base/GeckoView.java | 76 +++++++++++++++++++ ...dler.java => InputConnectionListener.java} | 7 +- mobile/android/base/gfx/LayerView.java | 65 ---------------- mobile/android/base/moz.build | 2 +- 7 files changed, 90 insertions(+), 78 deletions(-) rename mobile/android/base/{gfx/InputConnectionHandler.java => InputConnectionListener.java} (84%) diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 8395f75c9b05..0681c4b21a43 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -317,9 +317,9 @@ public class GeckoAppShell } } - private static LayerView sLayerView; + private static GeckoView sLayerView; - public static void setLayerView(LayerView lv) { + public static void setLayerView(GeckoView lv) { if (sLayerView == lv) { return; } @@ -338,7 +338,7 @@ public class GeckoAppShell } @RobocopTarget - public static LayerView getLayerView() { + public static GeckoView getLayerView() { return sLayerView; } @@ -2417,7 +2417,7 @@ public class GeckoAppShell private static boolean sImeWasEnabledOnLastResize = false; public static void viewSizeChanged() { - LayerView v = getLayerView(); + GeckoView v = getLayerView(); if (v == null) { return; } diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java index 1d0b7203491e..18c54041a7ed 100644 --- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -16,7 +16,6 @@ import java.util.concurrent.Semaphore; import org.json.JSONObject; import org.mozilla.gecko.AppConstants.Versions; -import org.mozilla.gecko.gfx.InputConnectionHandler; import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.util.GeckoEventListener; import org.mozilla.gecko.util.ThreadUtils; @@ -863,10 +862,10 @@ final class GeckoEditable // Set InputConnectionHandler in notifyIMEContext because // GeckoInputConnection.notifyIMEContext calls restartInput() which will invoke // InputConnectionHandler.onCreateInputConnection - LayerView v = GeckoAppShell.getLayerView(); + GeckoView v = GeckoAppShell.getLayerView(); if (v != null) { mListener = GeckoInputConnection.create(v, GeckoEditable.this); - v.setInputConnectionHandler((InputConnectionHandler)mListener); + v.setInputConnectionListener((InputConnectionListener) mListener); mListener.notifyIMEContext(state, typeHint, modeHint, actionHint); } } diff --git a/mobile/android/base/GeckoInputConnection.java b/mobile/android/base/GeckoInputConnection.java index 1e4d5ff2d64c..eda840d69d63 100644 --- a/mobile/android/base/GeckoInputConnection.java +++ b/mobile/android/base/GeckoInputConnection.java @@ -11,7 +11,6 @@ import java.lang.reflect.Proxy; import java.util.concurrent.SynchronousQueue; import org.mozilla.gecko.AppConstants.Versions; -import org.mozilla.gecko.gfx.InputConnectionHandler; import org.mozilla.gecko.util.Clipboard; import org.mozilla.gecko.util.GamepadUtils; import org.mozilla.gecko.util.ThreadUtils; @@ -40,7 +39,7 @@ import android.view.inputmethod.InputMethodManager; class GeckoInputConnection extends BaseInputConnection - implements InputConnectionHandler, GeckoEditableListener { + implements InputConnectionListener, GeckoEditableListener { private static final boolean DEBUG = false; protected static final String LOGTAG = "GeckoInputConnection"; @@ -1007,7 +1006,7 @@ final class DebugGeckoInputConnection public static GeckoEditableListener create(View targetView, GeckoEditableClient editable) { final Class[] PROXY_INTERFACES = { InputConnection.class, - InputConnectionHandler.class, + InputConnectionListener.class, GeckoEditableListener.class }; DebugGeckoInputConnection dgic = new DebugGeckoInputConnection(targetView, editable); diff --git a/mobile/android/base/GeckoView.java b/mobile/android/base/GeckoView.java index c3225d64e171..442b957b89bf 100644 --- a/mobile/android/base/GeckoView.java +++ b/mobile/android/base/GeckoView.java @@ -30,10 +30,14 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.TypedArray; import android.os.Bundle; +import android.os.Handler; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; +import android.view.KeyEvent; import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; public class GeckoView extends LayerView implements ContextGetter { @@ -44,6 +48,8 @@ public class GeckoView extends LayerView private ChromeDelegate mChromeDelegate; private ContentDelegate mContentDelegate; + private InputConnectionListener mInputConnectionListener; + private final GeckoEventListener mGeckoEventListener = new GeckoEventListener() { @Override public void handleMessage(final String event, final JSONObject message) { @@ -233,6 +239,76 @@ public class GeckoView extends LayerView window.disposeNative(); } + /* package */ void setInputConnectionListener(final InputConnectionListener icl) { + mInputConnectionListener = icl; + } + + @Override + public Handler getHandler() { + if (mInputConnectionListener != null) { + return mInputConnectionListener.getHandler(super.getHandler()); + } + return super.getHandler(); + } + + @Override + public InputConnection onCreateInputConnection(EditorInfo outAttrs) { + if (mInputConnectionListener != null) { + return mInputConnectionListener.onCreateInputConnection(outAttrs); + } + return null; + } + + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + if (super.onKeyPreIme(keyCode, event)) { + return true; + } + return mInputConnectionListener != null && + mInputConnectionListener.onKeyPreIme(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (super.onKeyUp(keyCode, event)) { + return true; + } + return mInputConnectionListener != null && + mInputConnectionListener.onKeyUp(keyCode, event); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (super.onKeyDown(keyCode, event)) { + return true; + } + return mInputConnectionListener != null && + mInputConnectionListener.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + if (super.onKeyLongPress(keyCode, event)) { + return true; + } + return mInputConnectionListener != null && + mInputConnectionListener.onKeyLongPress(keyCode, event); + } + + @Override + public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { + if (super.onKeyMultiple(keyCode, repeatCount, event)) { + return true; + } + return mInputConnectionListener != null && + mInputConnectionListener.onKeyMultiple(keyCode, repeatCount, event); + } + + /* package */ boolean isIMEEnabled() { + return mInputConnectionListener != null && + mInputConnectionListener.isIMEEnabled(); + } + /** * Add a Browser to the GeckoView container. * @param url The URL resource to load into the new Browser. diff --git a/mobile/android/base/gfx/InputConnectionHandler.java b/mobile/android/base/InputConnectionListener.java similarity index 84% rename from mobile/android/base/gfx/InputConnectionHandler.java rename to mobile/android/base/InputConnectionListener.java index 9b3ca381b5a4..baddc4ed25cc 100644 --- a/mobile/android/base/gfx/InputConnectionHandler.java +++ b/mobile/android/base/InputConnectionListener.java @@ -2,14 +2,17 @@ * 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.gfx; +package org.mozilla.gecko; import android.os.Handler; import android.view.KeyEvent; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; -public interface InputConnectionHandler +/** + * Interface for interacting with GeckoInputConnection from GeckoView. + */ +interface InputConnectionListener { Handler getHandler(Handler defHandler); InputConnection onCreateInputConnection(EditorInfo outAttrs); diff --git a/mobile/android/base/gfx/LayerView.java b/mobile/android/base/gfx/LayerView.java index ecd54eecea6e..846a81de89ed 100644 --- a/mobile/android/base/gfx/LayerView.java +++ b/mobile/android/base/gfx/LayerView.java @@ -31,7 +31,6 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.SurfaceTexture; -import android.os.Handler; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; @@ -41,8 +40,6 @@ import android.view.SurfaceView; import android.view.TextureView; import android.view.View; import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; import android.view.InputDevice; import android.widget.LinearLayout; import android.widget.ScrollView; @@ -57,7 +54,6 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener private PanZoomController mPanZoomController; private DynamicToolbarAnimator mToolbarAnimator; private final GLController mGLController; - private InputConnectionHandler mInputConnectionHandler; private LayerRenderer mRenderer; /* Must be a PAINT_xxx constant */ private int mPaintState; @@ -136,7 +132,6 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener mToolbarAnimator = mLayerClient.getDynamicToolbarAnimator(); mRenderer = new LayerRenderer(this); - mInputConnectionHandler = null; setFocusable(true); setFocusableInTouchMode(true); @@ -364,71 +359,11 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener mLayerClient.setIsRTL(aIsRTL); } - public void setInputConnectionHandler(InputConnectionHandler inputConnectionHandler) { - mInputConnectionHandler = inputConnectionHandler; - } - - @Override - public Handler getHandler() { - if (mInputConnectionHandler != null) - return mInputConnectionHandler.getHandler(super.getHandler()); - return super.getHandler(); - } - - @Override - public InputConnection onCreateInputConnection(EditorInfo outAttrs) { - if (mInputConnectionHandler != null) - return mInputConnectionHandler.onCreateInputConnection(outAttrs); - return null; - } - - @Override - public boolean onKeyPreIme(int keyCode, KeyEvent event) { - if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyPreIme(keyCode, event)) { - return true; - } - return false; - } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mPanZoomController != null && mPanZoomController.onKeyEvent(event)) { return true; } - if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyDown(keyCode, event)) { - return true; - } - return false; - } - - @Override - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyLongPress(keyCode, event)) { - return true; - } - return false; - } - - @Override - public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { - if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyMultiple(keyCode, repeatCount, event)) { - return true; - } - return false; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyUp(keyCode, event)) { - return true; - } - return false; - } - - public boolean isIMEEnabled() { - if (mInputConnectionHandler != null) { - return mInputConnectionHandler.isIMEEnabled(); - } return false; } diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 8a09891e005b..d393c5c928d8 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -288,7 +288,6 @@ gbjar.sources += [ 'gfx/GeckoLayerClient.java', 'gfx/GLController.java', 'gfx/ImmutableViewportMetrics.java', - 'gfx/InputConnectionHandler.java', 'gfx/IntSize.java', 'gfx/JavaPanZoomController.java', 'gfx/Layer.java', @@ -381,6 +380,7 @@ gbjar.sources += [ 'home/TopSitesThumbnailView.java', 'home/TransitionAwareCursorLoaderCallbacks.java', 'home/TwoLinePageRow.java', + 'InputConnectionListener.java', 'InputMethods.java', 'IntentHelper.java', 'javaaddons/JavaAddonManager.java', From c430fa611d72243c407ba3d93fff942b1243212e Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Wed, 7 Oct 2015 08:57:31 -0400 Subject: [PATCH 008/189] Bug 1209574 - Move GeckoEditable management to nsWindow; r=esawin This patch removes the GeckoEditable code in GeckoAppShell, and make nsWindow create a GeckoEditable for itself when opening a window. Instead of calling GeckoAppShell, nsWindow can now call GeckoEditable methods directly. --- mobile/android/base/GeckoAppShell.java | 38 ---- mobile/android/base/GeckoEditable.java | 22 +- .../android/base/GeckoEditableListener.java | 4 + widget/android/GeneratedJNIWrappers.cpp | 68 +++--- widget/android/GeneratedJNIWrappers.h | 194 ++++++++++++------ widget/android/nsWindow.cpp | 56 ++--- widget/android/nsWindow.h | 3 + 7 files changed, 230 insertions(+), 155 deletions(-) diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 0681c4b21a43..93ba98b8635c 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -132,8 +132,6 @@ public class GeckoAppShell // We have static members only. private GeckoAppShell() { } - private static GeckoEditableListener editableListener; - private static final CrashHandler CRASH_HANDLER = new CrashHandler() { @Override protected String getAppPackageName() { @@ -324,17 +322,6 @@ public class GeckoAppShell 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 @@ -419,31 +406,6 @@ public class GeckoAppShell 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; diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java index 18c54041a7ed..5e4aec53090c 100644 --- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -16,6 +16,7 @@ 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; @@ -347,7 +348,12 @@ final class GeckoEditable } } + @WrapForJNI GeckoEditable() { + if (DEBUG) { + // Called by nsWindow. + ThreadUtils.assertOnGeckoThread(); + } mActionQueue = new ActionQueue(); mSavedSelectionStart = -1; mUpdateGecko = true; @@ -768,7 +774,7 @@ final class GeckoEditable } } - @Override + @WrapForJNI @Override public void notifyIME(final int type) { if (DEBUG) { // GeckoEditableListener methods should all be called from the Gecko thread @@ -844,12 +850,12 @@ final class GeckoEditable } } - @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 + "\")"); @@ -872,7 +878,7 @@ final class GeckoEditable }); } - @Override + @WrapForJNI @Override public void onSelectionChange(final int start, final int end) { if (DEBUG) { // GeckoEditableListener methods should all be called from the Gecko thread @@ -928,9 +934,9 @@ final class GeckoEditable 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(); diff --git a/mobile/android/base/GeckoEditableListener.java b/mobile/android/base/GeckoEditableListener.java index f8b9daa5b781..a68ba0d62137 100644 --- a/mobile/android/base/GeckoEditableListener.java +++ b/mobile/android/base/GeckoEditableListener.java @@ -5,13 +5,17 @@ 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; diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index fcc500eac510..f0352463f628 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -542,30 +542,6 @@ auto GeckoAppShell::NotifyDefaultPrevented(bool a0) -> void return mozilla::jni::Method::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::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::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::Call(nullptr, nullptr, a0, a1, a2, a3); -} - constexpr char GeckoAppShell::NotifyWakeLockChanged_t::name[]; constexpr char GeckoAppShell::NotifyWakeLockChanged_t::signature[]; @@ -734,6 +710,50 @@ auto GeckoAppShell::VibrateA(mozilla::jni::LongArray::Param a0, int32_t a1) -> v return mozilla::jni::Method::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::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::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::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::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::Call(this, nullptr, a0, a1, a2, a3); +} + +constexpr char GeckoEditableListener::name[]; + constexpr char GeckoJavaSampler::name[]; constexpr char GeckoJavaSampler::GetFrameNameJavaProfilingWrapper_t::name[]; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index 4731d5ecb2f6..9f090705f14e 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -1295,66 +1295,6 @@ public: 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; @@ -1746,6 +1686,140 @@ public: }; +class GeckoEditable : public mozilla::jni::Class +{ +public: + typedef mozilla::jni::Ref Ref; + typedef mozilla::jni::LocalRef LocalRef; + typedef mozilla::jni::GlobalRef GlobalRef; + typedef const mozilla::jni::Param& 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[] = ""; + 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 +{ +public: + typedef mozilla::jni::Ref Ref; + typedef mozilla::jni::LocalRef LocalRef; + typedef mozilla::jni::GlobalRef GlobalRef; + typedef const mozilla::jni::Param& 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 { public: diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index f1e21b5376aa..22f30932357a 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -249,6 +249,10 @@ nsWindow::Natives::Open(const jni::ClassObject::LocalRef& cls, gGeckoViewWindow = static_cast(widget.get()); gGeckoViewWindow->mNatives = mozilla::MakeUnique(gGeckoViewWindow); + + // Create GeckoEditable for the new nsWindow/GeckoView pair. + gGeckoViewWindow->mEditable = GeckoEditable::New(); + AttachNative(GeckoView::Window::LocalRef(cls.Env(), gvWindow), gGeckoViewWindow->mNatives.get()); } @@ -1011,8 +1015,8 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae) break; case AndroidGeckoEvent::IME_EVENT: - win->UserActivity(); - win->OnIMEEvent(ae); + gGeckoViewWindow->UserActivity(); + gGeckoViewWindow->OnIMEEvent(ae); break; case AndroidGeckoEvent::IME_KEY_EVENT: @@ -1808,7 +1812,7 @@ public: nsRefPtr nsWindow::GetIMEComposition() { - MOZ_ASSERT(this == TopWindow()); + MOZ_ASSERT(this == FindTopLevel()); return mozilla::IMEStateManager::GetTextCompositionFor(this); } @@ -1884,14 +1888,14 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) 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; } @@ -1901,7 +1905,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) 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; } @@ -1916,7 +1920,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) case AndroidGeckoEvent::IME_SYNCHRONIZE: { FlushIMEChanges(); - GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); + mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); } break; @@ -1961,7 +1965,8 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) } mIMEKeyEvents.Clear(); FlushIMEChanges(); - GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); + mEditable->NotifyIME( + GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); // Break out of the switch block break; } @@ -2012,7 +2017,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) } FlushIMEChanges(); - GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); + mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); } break; @@ -2176,13 +2181,13 @@ nsWindow::UserActivity() nsresult nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification) { - MOZ_ASSERT(this == TopWindow()); + MOZ_ASSERT(this == FindTopLevel()); 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: @@ -2200,12 +2205,12 @@ nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification) 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: @@ -2216,7 +2221,7 @@ nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification) // 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: @@ -2246,7 +2251,7 @@ nsWindow::SetInputContext(const InputContext& aContext, // 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 @@ -2284,7 +2289,7 @@ nsWindow::SetInputContext(const InputContext& aContext, 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; } @@ -2300,7 +2305,7 @@ nsWindow::SetInputContext(const InputContext& aContext, 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. @@ -2360,8 +2365,8 @@ nsWindow::FlushIMEChanges() 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(); @@ -2373,9 +2378,8 @@ nsWindow::FlushIMEChanges() 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; } } @@ -2383,6 +2387,8 @@ nsWindow::FlushIMEChanges() 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"); diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h index 417562157eda..0247c81721a9 100644 --- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -49,6 +49,9 @@ public: // Object that implements native GeckoView calls; // nullptr for nsWindows that were not opened from GeckoView. mozilla::UniquePtr 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(); From 4e7741fcb4645c2168a657356c389310c49f2399 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Wed, 7 Oct 2015 08:57:31 -0400 Subject: [PATCH 009/189] Bug 1209574 - Switch GeckoInputConnection for each new GeckoView; r=esawin The GeckoEditable instance doesn't change for each nsWindow instance. However, because a GeckoInputConnection is associated with a GeckoView, when we create a new GeckoView, we need to attach a new GeckoInputConnection to the existing nsWindow's GeckoEditable. This patch makes us do that inside nsWindow::Natives::Open by calling GeckoEditable.OnViewChange. --- mobile/android/base/GeckoEditable.java | 47 +++++++++++++++++-------- mobile/android/base/GeckoView.java | 7 ++-- widget/android/GeneratedJNIWrappers.cpp | 8 +++++ widget/android/GeneratedJNIWrappers.h | 21 ++++++++++- widget/android/nsWindow.cpp | 7 ++++ 5 files changed, 72 insertions(+), 18 deletions(-) diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java index 5e4aec53090c..be7a98f6c3ee 100644 --- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -366,12 +366,41 @@ final class GeckoEditable Editable.class.getClassLoader(), PROXY_INTERFACES, this); - LayerView v = GeckoAppShell.getLayerView(); - mListener = GeckoInputConnection.create(v, this); - mIcRunHandler = mIcPostHandler = ThreadUtils.getUiHandler(); } + @WrapForJNI + /* package */ void onViewChange(final GeckoView v) { + if (DEBUG) { + // Called by nsWindow. + ThreadUtils.assertOnGeckoThread(); + Log.d(LOGTAG, "onViewChange(" + v + ")"); + } + + final GeckoEditableListener newListener = GeckoInputConnection.create(v, this); + geckoPostToIc(new Runnable() { + @Override + public void run() { + if (DEBUG) { + Log.d(LOGTAG, "onViewChange (set listener)"); + } + // Make sure there are no other things going on + mActionQueue.syncWithGecko(); + mListener = newListener; + } + }); + + ThreadUtils.postToUiThread(new Runnable() { + @Override + public void run() { + if (DEBUG) { + Log.d(LOGTAG, "onViewChange (set IC)"); + } + v.setInputConnectionListener((InputConnectionListener) newListener); + } + }); + } + private boolean onIcThread() { return mIcRunHandler.getLooper() == Looper.myLooper(); } @@ -863,17 +892,7 @@ final class GeckoEditable geckoPostToIc(new Runnable() { @Override public void run() { - // Make sure there are no other things going on - mActionQueue.syncWithGecko(); - // Set InputConnectionHandler in notifyIMEContext because - // GeckoInputConnection.notifyIMEContext calls restartInput() which will invoke - // InputConnectionHandler.onCreateInputConnection - GeckoView v = GeckoAppShell.getLayerView(); - if (v != null) { - mListener = GeckoInputConnection.create(v, GeckoEditable.this); - v.setInputConnectionListener((InputConnectionListener) mListener); - mListener.notifyIMEContext(state, typeHint, modeHint, actionHint); - } + mListener.notifyIMEContext(state, typeHint, modeHint, actionHint); } }); } diff --git a/mobile/android/base/GeckoView.java b/mobile/android/base/GeckoView.java index 442b957b89bf..e877d8d437f2 100644 --- a/mobile/android/base/GeckoView.java +++ b/mobile/android/base/GeckoView.java @@ -115,7 +115,7 @@ public class GeckoView extends LayerView @WrapForJNI private static final class Window extends JNIObject { - static native void open(Window instance, int width, int height); + static native void open(Window instance, GeckoView view, int width, int height); static native void setLayerClient(Object client); @Override protected native void disposeNative(); } @@ -225,10 +225,11 @@ public class GeckoView extends LayerView final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) { - Window.open(window, metrics.widthPixels, metrics.heightPixels); + Window.open(window, this, metrics.widthPixels, metrics.heightPixels); } else { GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY, Window.class, - "open", window, metrics.widthPixels, metrics.heightPixels); + "open", window, GeckoView.class, this, + metrics.widthPixels, metrics.heightPixels); } } diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index f0352463f628..a909126962f9 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -752,6 +752,14 @@ auto GeckoEditable::OnTextChange(mozilla::jni::String::Param a0, int32_t a1, int return mozilla::jni::Method::Call(this, nullptr, a0, a1, a2, a3); } +constexpr char GeckoEditable::OnViewChange_t::name[]; +constexpr char GeckoEditable::OnViewChange_t::signature[]; + +auto GeckoEditable::OnViewChange(mozilla::jni::Object::Param a0) const -> void +{ + return mozilla::jni::Method::Call(this, nullptr, a0); +} + constexpr char GeckoEditableListener::name[]; constexpr char GeckoJavaSampler::name[]; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index 9f090705f14e..330d8785fb2e 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -1796,6 +1796,24 @@ public: auto OnTextChange(mozilla::jni::String::Param, int32_t, int32_t, int32_t) const -> void; +public: + struct OnViewChange_t { + typedef GeckoEditable Owner; + typedef void ReturnType; + typedef void SetterType; + typedef mozilla::jni::Args< + mozilla::jni::Object::Param> Args; + static constexpr char name[] = "onViewChange"; + static constexpr char signature[] = + "(Lorg/mozilla/gecko/GeckoView;)V"; + static const bool isStatic = false; + static const bool isMultithreaded = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + auto OnViewChange(mozilla::jni::Object::Param) const -> void; + }; class GeckoEditableListener : public mozilla::jni::Class @@ -2457,11 +2475,12 @@ public: typedef void SetterType; typedef mozilla::jni::Args< Window::Param, + GeckoView::Param, int32_t, int32_t> Args; static constexpr char name[] = "open"; static constexpr char signature[] = - "(Lorg/mozilla/gecko/GeckoView$Window;II)V"; + "(Lorg/mozilla/gecko/GeckoView$Window;Lorg/mozilla/gecko/GeckoView;II)V"; static const bool isStatic = true; static const bool isMultithreaded = true; static const mozilla::jni::ExceptionMode exceptionMode = diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 22f30932357a..6ac04567079c 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -186,6 +186,7 @@ public: // Create and attach a window. static void Open(const jni::ClassObject::LocalRef& cls, GeckoView::Window::Param gvWindow, + GeckoView::Param view, int32_t width, int32_t height); // Set the active layer client object @@ -200,6 +201,7 @@ public: void nsWindow::Natives::Open(const jni::ClassObject::LocalRef& cls, GeckoView::Window::Param gvWindow, + GeckoView::Param view, int32_t width, int32_t height) { MOZ_ASSERT(NS_IsMainThread()); @@ -210,6 +212,10 @@ nsWindow::Natives::Open(const jni::ClassObject::LocalRef& cls, if (gGeckoViewWindow) { // Should have been created the first time. MOZ_ASSERT(gGeckoViewWindow->mNatives); + + // Associate our previous GeckoEditable with the new GeckoView. + gGeckoViewWindow->mEditable->OnViewChange(view); + AttachNative(GeckoView::Window::LocalRef(cls.Env(), gvWindow), gGeckoViewWindow->mNatives.get()); return; @@ -252,6 +258,7 @@ nsWindow::Natives::Open(const jni::ClassObject::LocalRef& cls, // Create GeckoEditable for the new nsWindow/GeckoView pair. gGeckoViewWindow->mEditable = GeckoEditable::New(); + gGeckoViewWindow->mEditable->OnViewChange(view); AttachNative(GeckoView::Window::LocalRef(cls.Env(), gvWindow), gGeckoViewWindow->mNatives.get()); From 920ff85cd5b08f0c4bbfe1d2aaf4fadc143717e2 Mon Sep 17 00:00:00 2001 From: Daniel Glazman Date: Wed, 7 Oct 2015 16:07:12 +0300 Subject: [PATCH 010/189] Bug 898321 - Return success from nsTableEditor::GetCellAt if frame not found; r=ehsan Adjusted by Aryeh Gregor for review comments. --- editor/libeditor/nsTableEditor.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/editor/libeditor/nsTableEditor.cpp b/editor/libeditor/nsTableEditor.cpp index 40549d64a905..cb706cc91a3c 100644 --- a/editor/libeditor/nsTableEditor.cpp +++ b/editor/libeditor/nsTableEditor.cpp @@ -2724,8 +2724,10 @@ nsHTMLEditor::GetCellAt(nsIDOMElement* aTable, int32_t aRowIndex, int32_t aColIn } nsTableOuterFrame* tableFrame = GetTableFrame(aTable); - if (!tableFrame) - return NS_ERROR_FAILURE; + if (!tableFrame) { + *aCell = nullptr; + return NS_EDITOR_ELEMENT_NOT_FOUND; + } nsCOMPtr domCell = do_QueryInterface(tableFrame->GetCellAt(aRowIndex, aColIndex)); From 006ecb6285e2afc22776ce6cda6702c478733cfa Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Wed, 7 Oct 2015 16:07:39 +0300 Subject: [PATCH 011/189] Bug 1192855 - Check validity in advance for nsRange::InsertNode; r=hsivonen --- dom/base/nsINode.cpp | 68 ++- dom/base/nsINode.h | 7 + dom/base/nsRange.cpp | 11 + .../failures/html/dom/ranges/mochitest.ini | 7 + .../ranges/test_Range-insertNode.html.json | 6 + .../test_Range-surroundContents.html.json | 44 ++ dom/imptests/html/dom/common.js | 267 +++++++--- dom/imptests/moz.build | 1 + .../path-objects/2d.path.arc.shape.3.html.ini | 1 - .../meta/dom/ranges/Range-insertNode.html.ini | 468 ------------------ .../webstorage/event_setattribute.html.ini | 2 +- 11 files changed, 319 insertions(+), 563 deletions(-) create mode 100644 dom/imptests/failures/html/dom/ranges/mochitest.ini create mode 100644 dom/imptests/failures/html/dom/ranges/test_Range-insertNode.html.json create mode 100644 dom/imptests/failures/html/dom/ranges/test_Range-surroundContents.html.json diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index f116b3f50d2b..6768a56c3bb7 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -1876,6 +1876,50 @@ bool IsAllowedAsChild(nsIContent* aNewChild, nsINode* aParent, return false; } +void +nsINode::EnsurePreInsertionValidity(nsINode& aNewChild, nsINode* aRefChild, + ErrorResult& aError) +{ + EnsurePreInsertionValidity1(aNewChild, aRefChild, aError); + if (aError.Failed()) { + return; + } + EnsurePreInsertionValidity2(false, aNewChild, aRefChild, aError); +} + +void +nsINode::EnsurePreInsertionValidity1(nsINode& aNewChild, nsINode* aRefChild, + ErrorResult& aError) +{ + if ((!IsNodeOfType(eDOCUMENT) && + !IsNodeOfType(eDOCUMENT_FRAGMENT) && + !IsElement()) || + !aNewChild.IsNodeOfType(eCONTENT)) { + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); + return; + } +} + +void +nsINode::EnsurePreInsertionValidity2(bool aReplace, nsINode& aNewChild, + nsINode* aRefChild, ErrorResult& aError) +{ + nsIContent* newContent = aNewChild.AsContent(); + if (newContent->IsRootOfAnonymousSubtree()) { + // This is anonymous content. Don't allow its insertion + // anywhere, since it might have UnbindFromTree calls coming + // its way. + aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return; + } + + // Make sure that the inserted node is allowed as a child of its new parent. + if (!IsAllowedAsChild(newContent, this, aReplace, aRefChild)) { + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); + return; + } +} + nsINode* nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild, nsINode* aRefChild, ErrorResult& aError) @@ -1887,11 +1931,8 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild, // the bad XBL cases. MOZ_ASSERT_IF(aReplace, aRefChild); - if ((!IsNodeOfType(eDOCUMENT) && - !IsNodeOfType(eDOCUMENT_FRAGMENT) && - !IsElement()) || - !aNewChild->IsNodeOfType(eCONTENT)) { - aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); + EnsurePreInsertionValidity1(*aNewChild, aRefChild, aError); + if (aError.Failed()) { return nullptr; } @@ -1939,19 +1980,8 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild, } } - nsIDocument* doc = OwnerDoc(); - nsIContent* newContent = static_cast(aNewChild); - if (newContent->IsRootOfAnonymousSubtree()) { - // This is anonymous content. Don't allow its insertion - // anywhere, since it might have UnbindFromTree calls coming - // its way. - aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return nullptr; - } - - // Make sure that the inserted node is allowed as a child of its new parent. - if (!IsAllowedAsChild(newContent, this, aReplace, aRefChild)) { - aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); + EnsurePreInsertionValidity2(aReplace, *aNewChild, aRefChild, aError); + if (aError.Failed()) { return nullptr; } @@ -1971,6 +2001,7 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild, Maybe, 50> > fragChildren; // Remove the new child from the old parent if one exists + nsIContent* newContent = aNewChild->AsContent(); nsCOMPtr oldParent = newContent->GetParentNode(); if (oldParent) { int32_t removeIndex = oldParent->IndexOf(newContent); @@ -2180,6 +2211,7 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild, // DocumentType nodes are the only nodes that can have a null // ownerDocument according to the DOM spec, and we need to allow // inserting them w/o calling AdoptNode(). + nsIDocument* doc = OwnerDoc(); if (doc != newContent->OwnerDoc()) { aError = AdoptNodeIntoOwnerDoc(this, aNewChild); if (aError.Failed()) { diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h index 5b49332823c9..7d2bb425804e 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -1735,6 +1735,8 @@ public: // The DOM spec says that when nodeValue is defined to be null "setting it // has no effect", so we don't throw an exception. } + void EnsurePreInsertionValidity(nsINode& aNewChild, nsINode* aRefChild, + mozilla::ErrorResult& aError); nsINode* InsertBefore(nsINode& aNode, nsINode* aChild, mozilla::ErrorResult& aError) { @@ -1884,6 +1886,11 @@ protected: nsresult CompareDocumentPosition(nsIDOMNode* aOther, uint16_t* aReturn); + void EnsurePreInsertionValidity1(nsINode& aNewChild, nsINode* aRefChild, + mozilla::ErrorResult& aError); + void EnsurePreInsertionValidity2(bool aReplace, nsINode& aNewChild, + nsINode* aRefChild, + mozilla::ErrorResult& aError); nsresult ReplaceOrInsertBefore(bool aReplace, nsIDOMNode *aNewChild, nsIDOMNode *aRefChild, nsIDOMNode **aReturn); nsINode* ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild, diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp index 9f0b0376c17c..25b3415ddb59 100644 --- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -2485,6 +2485,12 @@ nsRange::InsertNode(nsINode& aNode, ErrorResult& aRv) return; } + referenceParentNode->EnsurePreInsertionValidity(aNode, tStartContainer, + aRv); + if (aRv.Failed()) { + return; + } + nsCOMPtr secondPart; aRv = startTextNode->SplitText(tStartOffset, getter_AddRefs(secondPart)); if (aRv.Failed()) { @@ -2505,6 +2511,11 @@ nsRange::InsertNode(nsINode& aNode, ErrorResult& aRv) if (aRv.Failed()) { return; } + + tStartContainer->EnsurePreInsertionValidity(aNode, referenceNode, aRv); + if (aRv.Failed()) { + return; + } } // We might need to update the end to include the new node (bug 433662). diff --git a/dom/imptests/failures/html/dom/ranges/mochitest.ini b/dom/imptests/failures/html/dom/ranges/mochitest.ini new file mode 100644 index 000000000000..da0d1a7711c4 --- /dev/null +++ b/dom/imptests/failures/html/dom/ranges/mochitest.ini @@ -0,0 +1,7 @@ +# THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT +[DEFAULT] +support-files = + + +[test_Range-insertNode.html.json] +[test_Range-surroundContents.html.json] diff --git a/dom/imptests/failures/html/dom/ranges/test_Range-insertNode.html.json b/dom/imptests/failures/html/dom/ranges/test_Range-insertNode.html.json new file mode 100644 index 000000000000..a5ac1621d285 --- /dev/null +++ b/dom/imptests/failures/html/dom/ranges/test_Range-insertNode.html.json @@ -0,0 +1,6 @@ +{ + "0,1: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node paras[0].firstChild": true, + "4,2: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node paras[1].firstChild": true, + "6,6: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedPara1.firstChild": true, + "8,4: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignPara1.firstChild": true +} diff --git a/dom/imptests/failures/html/dom/ranges/test_Range-surroundContents.html.json b/dom/imptests/failures/html/dom/ranges/test_Range-surroundContents.html.json new file mode 100644 index 000000000000..720ee5edb632 --- /dev/null +++ b/dom/imptests/failures/html/dom/ranges/test_Range-surroundContents.html.json @@ -0,0 +1,44 @@ +{ + "0,1: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node paras[0].firstChild": true, + "1,1: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node paras[0].firstChild": true, + "2,1: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node paras[0].firstChild": true, + "3,1: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node paras[0].firstChild": true, + "4,2: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node paras[1].firstChild": true, + "5,2: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node paras[1].firstChild": true, + "6,6: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedPara1.firstChild": true, + "7,6: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedPara1.firstChild": true, + "8,4: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignPara1.firstChild": true, + "9,4: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignPara1.firstChild": true, + "37,0: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node paras[0]": true, + "37,0: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node paras[0]": true, + "37,1: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node paras[0].firstChild": true, + "37,1: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node paras[0].firstChild": true, + "37,2: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node paras[1].firstChild": true, + "37,2: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node paras[1].firstChild": true, + "37,3: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node foreignPara1": true, + "37,3: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node foreignPara1": true, + "37,4: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node foreignPara1.firstChild": true, + "37,4: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node foreignPara1.firstChild": true, + "37,5: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedPara1": true, + "37,5: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedPara1": true, + "37,6: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedPara1.firstChild": true, + "37,6: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedPara1.firstChild": true, + "37,8: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedDiv": true, + "37,8: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedDiv": true, + "37,10: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node foreignPara2": true, + "37,10: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node foreignPara2": true, + "37,12: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node xmlElement": true, + "37,12: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node xmlElement": true, + "37,13: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedTextNode": true, + "37,13: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedTextNode": true, + "37,14: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node foreignTextNode": true, + "37,14: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node foreignTextNode": true, + "37,15: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node processingInstruction": true, + "37,15: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node processingInstruction": true, + "37,16: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedProcessingInstruction": true, + "37,16: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedProcessingInstruction": true, + "37,17: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node comment": true, + "37,17: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node comment": true, + "37,18: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedComment": true, + "37,18: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedComment": true +} diff --git a/dom/imptests/html/dom/common.js b/dom/imptests/html/dom/common.js index 91ccb4425d7d..dc7528a9a934 100644 --- a/dom/imptests/html/dom/common.js +++ b/dom/imptests/html/dom/common.js @@ -827,94 +827,211 @@ function myExtractContents(range) { } /** - * insertNode() implementation, following the spec. If an exception is - * supposed to be thrown, will return a string with the name (e.g., - * "HIERARCHY_REQUEST_ERR") instead of a document fragment. It might also - * return an arbitrary human-readable string if a condition is hit that implies - * a spec bug. + * insertNode() implementation, following the spec. If an exception is meant + * to be thrown, will return a string with the expected exception name, for + * instance "HIERARCHY_REQUEST_ERR". */ function myInsertNode(range, node) { - // "If the detached flag is set, throw an "InvalidStateError" exception and - // terminate these steps." - // - // Assume that if accessing collapsed throws, it's detached. - try { - range.collapsed; - } catch (e) { - return "INVALID_STATE_ERR"; - } + // "If range's start node is either a ProcessingInstruction or Comment + // node, or a Text node whose parent is null, throw an + // "HierarchyRequestError" exception and terminate these steps." + if (range.startContainer.nodeType == Node.PROCESSING_INSTRUCTION_NODE + || range.startContainer.nodeType == Node.COMMENT_NODE + || (range.startContainer.nodeType == Node.TEXT_NODE + && !range.startContainer.parentNode)) { + return "HIERARCHY_REQUEST_ERR"; + } - // "If start node is a Comment node, or a Text node whose parent is null, - // throw an "HierarchyRequestError" exception and terminate these steps." - if (range.startContainer.nodeType == Node.COMMENT_NODE - || (range.startContainer.nodeType == Node.TEXT_NODE - && !range.startContainer.parentNode)) { - return "HIERARCHY_REQUEST_ERR"; - } + // "Let referenceNode be null." + var referenceNode = null; - // "If start node is a Text node, split it with offset context object's - // start offset, and let reference node be the result." - var referenceNode; - if (range.startContainer.nodeType == Node.TEXT_NODE) { - // We aren't testing how ranges vary under mutations, and browsers vary - // in how they mutate for splitText, so let's just force the correct - // way. - var start = [range.startContainer, range.startOffset]; - var end = [range.endContainer, range.endOffset]; + // "If range's start node is a Text node, set referenceNode to that Text node." + if (range.startContainer.nodeType == Node.TEXT_NODE) { + referenceNode = range.startContainer; - referenceNode = range.startContainer.splitText(range.startOffset); + // "Otherwise, set referenceNode to the child of start node whose index is + // start offset, and null if there is no such child." + } else { + if (range.startOffset < range.startContainer.childNodes.length) { + referenceNode = range.startContainer.childNodes[range.startOffset]; + } else { + referenceNode = null; + } + } - if (start[0] == end[0] - && end[1] > start[1]) { - end[0] = referenceNode; - end[1] -= start[1]; - } else if (end[0] == start[0].parentNode - && end[1] > indexOf(referenceNode)) { - end[1]++; - } - range.setStart(start[0], start[1]); - range.setEnd(end[0], end[1]); + // "Let parent be range's start node if referenceNode is null, and + // referenceNode's parent otherwise." + var parent_ = referenceNode === null ? range.startContainer : + referenceNode.parentNode; - // "Otherwise, let reference node be the child of start node whose index is - // start offset, or null if there is no such child." - } else { - referenceNode = range.startContainer.childNodes[range.startOffset]; - if (typeof referenceNode == "undefined") { - referenceNode = null; - } - } + // "Ensure pre-insertion validity of node into parent before + // referenceNode." + var error = ensurePreInsertionValidity(node, parent_, referenceNode); + if (error) { + return error; + } - // "If reference node is null, let parent be start node." - var parent_; - if (!referenceNode) { - parent_ = range.startContainer; + // "If range's start node is a Text node, set referenceNode to the result + // of splitting it with offset range's start offset." + if (range.startContainer.nodeType == Node.TEXT_NODE) { + referenceNode = range.startContainer.splitText(range.startOffset); + } - // "Otherwise, let parent be the parent of reference node." - } else { - parent_ = referenceNode.parentNode; - } + // "If node is referenceNode, set referenceNode to its next sibling." + if (node == referenceNode) { + referenceNode = referenceNode.nextSibling; + } - // "Let new offset be the index of reference node, or parent's length if - // reference node is null." - var newOffset = referenceNode ? indexOf(referenceNode) : nodeLength(parent_); + // "If node's parent is not null, remove node from its parent." + if (node.parentNode) { + node.parentNode.removeChild(node); + } - // "Add node's length to new offset, if node is a DocumentFragment. - // Otherwise add one to new offset." - newOffset += node.nodeType == Node.DOCUMENT_FRAGMENT_NODE - ? nodeLength(node) - : 1; + // "Let newOffset be parent's length if referenceNode is null, and + // referenceNode's index otherwise." + var newOffset = referenceNode === null ? nodeLength(parent_) : + indexOf(referenceNode); - // "Pre-insert node into parent before reference node." - try { - parent_.insertBefore(node, referenceNode); - } catch (e) { - return getDomExceptionName(e); - } + // "Increase newOffset by node's length if node is a DocumentFragment node, + // and one otherwise." + newOffset += node.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? + nodeLength(node) : 1; - // "If start and end are the same, set end to (parent, new offset)." - if (range.collapsed) { - range.setEnd(parent_, newOffset); - } + // "Pre-insert node into parent before referenceNode." + parent_.insertBefore(node, referenceNode); + + // "If range's start and end are the same, set range's end to (parent, + // newOffset)." + if (range.startContainer == range.endContainer + && range.startOffset == range.endOffset) { + range.setEnd(parent_, newOffset); + } +} + +// To make filter() calls more readable +function isElement(node) { + return node.nodeType == Node.ELEMENT_NODE; +} + +function isText(node) { + return node.nodeType == Node.TEXT_NODE; +} + +function isDoctype(node) { + return node.nodeType == Node.DOCUMENT_TYPE_NODE; +} + +function ensurePreInsertionValidity(node, parent_, child) { + // "If parent is not a Document, DocumentFragment, or Element node, throw a + // HierarchyRequestError." + if (parent_.nodeType != Node.DOCUMENT_NODE + && parent_.nodeType != Node.DOCUMENT_FRAGMENT_NODE + && parent_.nodeType != Node.ELEMENT_NODE) { + return "HIERARCHY_REQUEST_ERR"; + } + + // "If node is a host-including inclusive ancestor of parent, throw a + // HierarchyRequestError." + // + // XXX Does not account for host + if (isInclusiveAncestor(node, parent_)) { + return "HIERARCHY_REQUEST_ERR"; + } + + // "If child is not null and its parent is not parent, throw a NotFoundError + // exception." + if (child && child.parentNode != parent_) { + return "NOT_FOUND_ERR"; + } + + // "If node is not a DocumentFragment, DocumentType, Element, Text, + // ProcessingInstruction, or Comment node, throw a HierarchyRequestError." + if (node.nodeType != Node.DOCUMENT_FRAGMENT_NODE + && node.nodeType != Node.DOCUMENT_TYPE_NODE + && node.nodeType != Node.ELEMENT_NODE + && node.nodeType != Node.TEXT_NODE + && node.nodeType != Node.PROCESSING_INSTRUCTION_NODE + && node.nodeType != Node.COMMENT_NODE) { + return "HIERARCHY_REQUEST_ERR"; + } + + // "If either node is a Text node and parent is a document, or node is a + // doctype and parent is not a document, throw a HierarchyRequestError." + if ((node.nodeType == Node.TEXT_NODE + && parent_.nodeType == Node.DOCUMENT_NODE) + || (node.nodeType == Node.DOCUMENT_TYPE_NODE + && parent_.nodeType != Node.DOCUMENT_NODE)) { + return "HIERARCHY_REQUEST_ERR"; + } + + // "If parent is a document, and any of the statements below, switched on + // node, are true, throw a HierarchyRequestError." + if (parent_.nodeType == Node.DOCUMENT_NODE) { + switch (node.nodeType) { + case Node.DOCUMENT_FRAGMENT_NODE: + // "If node has more than one element child or has a Text node + // child. Otherwise, if node has one element child and either + // parent has an element child, child is a doctype, or child is not + // null and a doctype is following child." + if ([].filter.call(node.childNodes, isElement).length > 1) { + return "HIERARCHY_REQUEST_ERR"; + } + + if ([].some.call(node.childNodes, isText)) { + return "HIERARCHY_REQUEST_ERR"; + } + + if ([].filter.call(node.childNodes, isElement).length == 1) { + if ([].some.call(parent_.childNodes, isElement)) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (child && child.nodeType == Node.DOCUMENT_TYPE_NODE) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (child && [].slice.call(parent_.childNodes, indexOf(child) + 1) + .filter(isDoctype)) { + return "HIERARCHY_REQUEST_ERR"; + } + } + break; + + case Node.ELEMENT_NODE: + // "parent has an element child, child is a doctype, or child is + // not null and a doctype is following child." + if ([].some.call(parent_.childNodes, isElement)) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (child.nodeType == Node.DOCUMENT_TYPE_NODE) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (child && [].slice.call(parent_.childNodes, indexOf(child) + 1) + .filter(isDoctype)) { + return "HIERARCHY_REQUEST_ERR"; + } + break; + + case Node.DOCUMENT_TYPE_NODE: + // "parent has a doctype child, an element is preceding child, or + // child is null and parent has an element child." + if ([].some.call(parent_.childNodes, isDoctype)) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (child && [].slice.call(parent_.childNodes, 0, indexOf(child)) + .some(isElement)) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (!child && [].some.call(parent_.childNodes, isElement)) { + return "HIERARCHY_REQUEST_ERR"; + } + break; + } + } } /** diff --git a/dom/imptests/moz.build b/dom/imptests/moz.build index b4e160bd0672..38f581c197d7 100644 --- a/dom/imptests/moz.build +++ b/dom/imptests/moz.build @@ -18,6 +18,7 @@ MOCHITEST_MANIFESTS += [ 'failures/html/dom/lists/mochitest.ini', 'failures/html/dom/mochitest.ini', 'failures/html/dom/nodes/mochitest.ini', + 'failures/html/dom/ranges/mochitest.ini', 'failures/html/html/browsers/the-window-object/mochitest.ini', 'failures/html/html/browsers/the-window-object/named-access-on-the-window-object/mochitest.ini', 'failures/html/html/dom/documents/dta/doc.gEBN/mochitest.ini', diff --git a/testing/web-platform/meta/2dcontext/path-objects/2d.path.arc.shape.3.html.ini b/testing/web-platform/meta/2dcontext/path-objects/2d.path.arc.shape.3.html.ini index 1241415518dc..d7254edc497c 100644 --- a/testing/web-platform/meta/2dcontext/path-objects/2d.path.arc.shape.3.html.ini +++ b/testing/web-platform/meta/2dcontext/path-objects/2d.path.arc.shape.3.html.ini @@ -6,4 +6,3 @@ if (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - diff --git a/testing/web-platform/meta/dom/ranges/Range-insertNode.html.ini b/testing/web-platform/meta/dom/ranges/Range-insertNode.html.ini index 012f2884aaef..3b1426fdd788 100644 --- a/testing/web-platform/meta/dom/ranges/Range-insertNode.html.ini +++ b/testing/web-platform/meta/dom/ranges/Range-insertNode.html.ini @@ -1,482 +1,14 @@ [Range-insertNode.html] type: testharness - [0,0: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node paras[0\]] - expected: FAIL - - [0,0: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node paras[0\]] - expected: FAIL - [0,1: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node paras[0\].firstChild] expected: FAIL - [0,7: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node document] - expected: FAIL - - [0,7: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node document] - expected: FAIL - - [0,9: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node foreignDoc] - expected: FAIL - - [0,9: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node foreignDoc] - expected: FAIL - - [0,11: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node xmlDoc] - expected: FAIL - - [0,11: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node xmlDoc] - expected: FAIL - - [0,20: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node doctype] - expected: FAIL - - [0,20: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node doctype] - expected: FAIL - - [0,21: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node foreignDoctype] - expected: FAIL - - [0,21: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 0\], node foreignDoctype] - expected: FAIL - - [1,0: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node paras[0\]] - expected: FAIL - - [1,0: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node paras[0\]] - expected: FAIL - - [1,7: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node document] - expected: FAIL - - [1,7: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node document] - expected: FAIL - - [1,9: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node foreignDoc] - expected: FAIL - - [1,9: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node foreignDoc] - expected: FAIL - - [1,11: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node xmlDoc] - expected: FAIL - - [1,11: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node xmlDoc] - expected: FAIL - - [1,20: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node doctype] - expected: FAIL - - [1,20: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node doctype] - expected: FAIL - - [1,21: resulting DOM for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node foreignDoctype] - expected: FAIL - - [1,21: resulting range position for range [paras[0\].firstChild, 0, paras[0\].firstChild, 1\], node foreignDoctype] - expected: FAIL - - [2,0: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node paras[0\]] - expected: FAIL - - [2,0: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node paras[0\]] - expected: FAIL - - [2,7: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node document] - expected: FAIL - - [2,7: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node document] - expected: FAIL - - [2,9: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node foreignDoc] - expected: FAIL - - [2,9: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node foreignDoc] - expected: FAIL - - [2,11: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node xmlDoc] - expected: FAIL - - [2,11: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node xmlDoc] - expected: FAIL - - [2,20: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node doctype] - expected: FAIL - - [2,20: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node doctype] - expected: FAIL - - [2,21: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node foreignDoctype] - expected: FAIL - - [2,21: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 8\], node foreignDoctype] - expected: FAIL - - [3,0: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node paras[0\]] - expected: FAIL - - [3,0: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node paras[0\]] - expected: FAIL - - [3,7: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node document] - expected: FAIL - - [3,7: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node document] - expected: FAIL - - [3,9: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node foreignDoc] - expected: FAIL - - [3,9: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node foreignDoc] - expected: FAIL - - [3,11: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node xmlDoc] - expected: FAIL - - [3,11: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node xmlDoc] - expected: FAIL - - [3,20: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node doctype] - expected: FAIL - - [3,20: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node doctype] - expected: FAIL - - [3,21: resulting DOM for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node foreignDoctype] - expected: FAIL - - [3,21: resulting range position for range [paras[0\].firstChild, 2, paras[0\].firstChild, 9\], node foreignDoctype] - expected: FAIL - [4,2: resulting range position for range [paras[1\].firstChild, 0, paras[1\].firstChild, 0\], node paras[1\].firstChild] expected: FAIL - [4,7: resulting DOM for range [paras[1\].firstChild, 0, paras[1\].firstChild, 0\], node document] - expected: FAIL - - [4,7: resulting range position for range [paras[1\].firstChild, 0, paras[1\].firstChild, 0\], node document] - expected: FAIL - - [4,9: resulting DOM for range [paras[1\].firstChild, 0, paras[1\].firstChild, 0\], node foreignDoc] - expected: FAIL - - [4,9: resulting range position for range [paras[1\].firstChild, 0, paras[1\].firstChild, 0\], node foreignDoc] - expected: FAIL - - [4,11: resulting DOM for range [paras[1\].firstChild, 0, paras[1\].firstChild, 0\], node xmlDoc] - expected: FAIL - - [4,11: resulting range position for range [paras[1\].firstChild, 0, paras[1\].firstChild, 0\], node xmlDoc] - expected: FAIL - - [4,20: resulting DOM for range [paras[1\].firstChild, 0, paras[1\].firstChild, 0\], node doctype] - expected: FAIL - - [4,20: resulting range position for range [paras[1\].firstChild, 0, paras[1\].firstChild, 0\], node doctype] - expected: FAIL - - [4,21: resulting DOM for range [paras[1\].firstChild, 0, paras[1\].firstChild, 0\], node foreignDoctype] - expected: FAIL - - [4,21: resulting range position for range [paras[1\].firstChild, 0, paras[1\].firstChild, 0\], node foreignDoctype] - expected: FAIL - - [5,7: resulting DOM for range [paras[1\].firstChild, 2, paras[1\].firstChild, 9\], node document] - expected: FAIL - - [5,7: resulting range position for range [paras[1\].firstChild, 2, paras[1\].firstChild, 9\], node document] - expected: FAIL - - [5,9: resulting DOM for range [paras[1\].firstChild, 2, paras[1\].firstChild, 9\], node foreignDoc] - expected: FAIL - - [5,9: resulting range position for range [paras[1\].firstChild, 2, paras[1\].firstChild, 9\], node foreignDoc] - expected: FAIL - - [5,11: resulting DOM for range [paras[1\].firstChild, 2, paras[1\].firstChild, 9\], node xmlDoc] - expected: FAIL - - [5,11: resulting range position for range [paras[1\].firstChild, 2, paras[1\].firstChild, 9\], node xmlDoc] - expected: FAIL - - [5,20: resulting DOM for range [paras[1\].firstChild, 2, paras[1\].firstChild, 9\], node doctype] - expected: FAIL - - [5,20: resulting range position for range [paras[1\].firstChild, 2, paras[1\].firstChild, 9\], node doctype] - expected: FAIL - - [5,21: resulting DOM for range [paras[1\].firstChild, 2, paras[1\].firstChild, 9\], node foreignDoctype] - expected: FAIL - - [5,21: resulting range position for range [paras[1\].firstChild, 2, paras[1\].firstChild, 9\], node foreignDoctype] - expected: FAIL - - [6,5: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node detachedPara1] - expected: FAIL - - [6,5: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node detachedPara1] - expected: FAIL - [6,6: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node detachedPara1.firstChild] expected: FAIL - [6,7: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node document] - expected: FAIL - - [6,7: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node document] - expected: FAIL - - [6,8: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node detachedDiv] - expected: FAIL - - [6,8: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node detachedDiv] - expected: FAIL - - [6,9: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node foreignDoc] - expected: FAIL - - [6,9: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node foreignDoc] - expected: FAIL - - [6,11: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node xmlDoc] - expected: FAIL - - [6,11: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node xmlDoc] - expected: FAIL - - [6,20: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node doctype] - expected: FAIL - - [6,20: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node doctype] - expected: FAIL - - [6,21: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node foreignDoctype] - expected: FAIL - - [6,21: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0\], node foreignDoctype] - expected: FAIL - - [7,5: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node detachedPara1] - expected: FAIL - - [7,5: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node detachedPara1] - expected: FAIL - - [7,7: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node document] - expected: FAIL - - [7,7: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node document] - expected: FAIL - - [7,8: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node detachedDiv] - expected: FAIL - - [7,8: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node detachedDiv] - expected: FAIL - - [7,9: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node foreignDoc] - expected: FAIL - - [7,9: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node foreignDoc] - expected: FAIL - - [7,11: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node xmlDoc] - expected: FAIL - - [7,11: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node xmlDoc] - expected: FAIL - - [7,20: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node doctype] - expected: FAIL - - [7,20: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node doctype] - expected: FAIL - - [7,21: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node foreignDoctype] - expected: FAIL - - [7,21: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8\], node foreignDoctype] - expected: FAIL - - [8,3: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node foreignPara1] - expected: FAIL - - [8,3: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node foreignPara1] - expected: FAIL - [8,4: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node foreignPara1.firstChild] expected: FAIL - [8,7: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node document] - expected: FAIL - - [8,7: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node document] - expected: FAIL - - [8,9: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node foreignDoc] - expected: FAIL - - [8,9: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node foreignDoc] - expected: FAIL - - [8,11: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node xmlDoc] - expected: FAIL - - [8,11: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node xmlDoc] - expected: FAIL - - [8,20: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node doctype] - expected: FAIL - - [8,20: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node doctype] - expected: FAIL - - [8,21: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node foreignDoctype] - expected: FAIL - - [8,21: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0\], node foreignDoctype] - expected: FAIL - - [9,3: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node foreignPara1] - expected: FAIL - - [9,3: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node foreignPara1] - expected: FAIL - - [9,7: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node document] - expected: FAIL - - [9,7: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node document] - expected: FAIL - - [9,9: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node foreignDoc] - expected: FAIL - - [9,9: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node foreignDoc] - expected: FAIL - - [9,11: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node xmlDoc] - expected: FAIL - - [9,11: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node xmlDoc] - expected: FAIL - - [9,20: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node doctype] - expected: FAIL - - [9,20: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node doctype] - expected: FAIL - - [9,21: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node foreignDoctype] - expected: FAIL - - [9,21: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8\], node foreignDoctype] - expected: FAIL - - [18,0: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node paras[0\]] - expected: FAIL - - [18,0: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node paras[0\]] - expected: FAIL - - [18,7: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node document] - expected: FAIL - - [18,7: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node document] - expected: FAIL - - [18,9: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node foreignDoc] - expected: FAIL - - [18,9: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node foreignDoc] - expected: FAIL - - [18,11: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node xmlDoc] - expected: FAIL - - [18,11: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node xmlDoc] - expected: FAIL - - [18,20: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node doctype] - expected: FAIL - - [18,20: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node doctype] - expected: FAIL - - [18,21: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node foreignDoctype] - expected: FAIL - - [18,21: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 0\], node foreignDoctype] - expected: FAIL - - [19,0: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node paras[0\]] - expected: FAIL - - [19,0: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node paras[0\]] - expected: FAIL - - [19,7: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node document] - expected: FAIL - - [19,7: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node document] - expected: FAIL - - [19,9: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node foreignDoc] - expected: FAIL - - [19,9: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node foreignDoc] - expected: FAIL - - [19,11: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node xmlDoc] - expected: FAIL - - [19,11: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node xmlDoc] - expected: FAIL - - [19,20: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node doctype] - expected: FAIL - - [19,20: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node doctype] - expected: FAIL - - [19,21: resulting DOM for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node foreignDoctype] - expected: FAIL - - [19,21: resulting range position for range [paras[0\].firstChild, 0, paras[1\].firstChild, 8\], node foreignDoctype] - expected: FAIL - - [20,0: resulting DOM for range [paras[0\].firstChild, 3, paras[3\], 1\], node paras[0\]] - expected: FAIL - - [20,0: resulting range position for range [paras[0\].firstChild, 3, paras[3\], 1\], node paras[0\]] - expected: FAIL - - [20,7: resulting DOM for range [paras[0\].firstChild, 3, paras[3\], 1\], node document] - expected: FAIL - - [20,7: resulting range position for range [paras[0\].firstChild, 3, paras[3\], 1\], node document] - expected: FAIL - - [20,9: resulting DOM for range [paras[0\].firstChild, 3, paras[3\], 1\], node foreignDoc] - expected: FAIL - - [20,9: resulting range position for range [paras[0\].firstChild, 3, paras[3\], 1\], node foreignDoc] - expected: FAIL - - [20,11: resulting DOM for range [paras[0\].firstChild, 3, paras[3\], 1\], node xmlDoc] - expected: FAIL - - [20,11: resulting range position for range [paras[0\].firstChild, 3, paras[3\], 1\], node xmlDoc] - expected: FAIL - - [20,20: resulting DOM for range [paras[0\].firstChild, 3, paras[3\], 1\], node doctype] - expected: FAIL - - [20,20: resulting range position for range [paras[0\].firstChild, 3, paras[3\], 1\], node doctype] - expected: FAIL - - [20,21: resulting DOM for range [paras[0\].firstChild, 3, paras[3\], 1\], node foreignDoctype] - expected: FAIL - - [20,21: resulting range position for range [paras[0\].firstChild, 3, paras[3\], 1\], node foreignDoctype] - expected: FAIL - diff --git a/testing/web-platform/meta/webstorage/event_setattribute.html.ini b/testing/web-platform/meta/webstorage/event_setattribute.html.ini index 52e9828092aa..f92948cb78bc 100644 --- a/testing/web-platform/meta/webstorage/event_setattribute.html.ini +++ b/testing/web-platform/meta/webstorage/event_setattribute.html.ini @@ -1,7 +1,7 @@ [event_setattribute.html] type: testharness disabled: - if e10s and os == "linux": https://bugzilla.mozilla.org/show_bug.cgi?id=1210717 + if e10s and (os == "linux"): https://bugzilla.mozilla.org/show_bug.cgi?id=1210717 [localStorage mutations fire StorageEvents that are caught by the event listener attached via setattribute.] expected: FAIL From 8a61b380af498de8596cbe77b5beacb6d8d5d88a Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 7 Oct 2015 09:31:32 -0400 Subject: [PATCH 012/189] Bug 1211624. document.all should be iterable, and so should be various other things that have an anonymous indexed getter. r=qdot --- dom/base/test/mochitest.ini | 1 + dom/base/test/test_document.all_iteration.html | 11 +++++++++++ dom/bindings/Codegen.py | 9 ++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 dom/base/test/test_document.all_iteration.html diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 4627b1174760..a0bae4613277 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -851,3 +851,4 @@ skip-if = e10s || os != 'linux' || buildapp != 'browser' [test_explicit_user_agent.html] [test_change_policy.html] skip-if = buildapp == 'b2g' #no ssl support +[test_document.all_iteration.html] diff --git a/dom/base/test/test_document.all_iteration.html b/dom/base/test/test_document.all_iteration.html new file mode 100644 index 000000000000..a5140d9df114 --- /dev/null +++ b/dom/base/test/test_document.all_iteration.html @@ -0,0 +1,11 @@ + + +Test for document.all iteration behavior + + +
+ diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 755ca476bb20..593e422630cd 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -2222,7 +2222,14 @@ class MethodDefiner(PropertyDefiner): return (any("@@iterator" in m.aliases for m in methods) or any("@@iterator" == r["name"] for r in regular)) - if (any(m.isGetter() and m.isIndexed() for m in methods)): + # Check whether we need to output an @@iterator due to having an indexed + # getter. We only do this while outputting non-static and + # non-unforgeable methods, since the @@iterator function will be + # neither. + if (not static and + not unforgeable and + descriptor.supportsIndexedProperties() and + isMaybeExposedIn(descriptor.operations['IndexedGetter'], descriptor)): if hasIterator(methods, self.regular): raise TypeError("Cannot have indexed getter/attr on " "interface %s with other members " From 175bd2224a00dc6390f768a58ce8bdefdde3b40a Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Wed, 7 Oct 2015 14:30:50 +0100 Subject: [PATCH 013/189] Bug 1208403 - Fix byteSizeOfScript shell function to check for scripted functions. r=jonco --HG-- extra : rebase_source : 05b74ef7e9e42a7d3801fa8c999bc0e06b2a7f8d --- js/src/builtin/TestingFunctions.cpp | 11 ++++++++++- js/src/jit-test/tests/basic/bug1208403.js | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/basic/bug1208403.js diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 6dc84e513ca4..cae252c0d368 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2494,7 +2494,16 @@ ByteSizeOfScript(JSContext*cx, unsigned argc, Value* vp) return false; } - RootedScript script(cx, args[0].toObject().as().getOrCreateScript(cx)); + JSFunction* fun = &args[0].toObject().as(); + if (fun->isNative()) { + JS_ReportError(cx, "Argument must be a scripted function"); + return false; + } + + RootedScript script(cx, fun->getOrCreateScript(cx)); + if (!script) + return false; + mozilla::MallocSizeOf mallocSizeOf = cx->runtime()->debuggerMallocSizeOf; { diff --git a/js/src/jit-test/tests/basic/bug1208403.js b/js/src/jit-test/tests/basic/bug1208403.js new file mode 100644 index 000000000000..5077fcef0458 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1208403.js @@ -0,0 +1,2 @@ +// |jit-test| error: scripted function +byteSizeOfScript(Array); From d36aaa89f44e1445ff9fa91a346766289f98942d Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 11:59:47 +1100 Subject: [PATCH 014/189] Bug 1211652: Add sourcebuffer.mode = sequence mochitest. r=gerald --- dom/media/mediasource/test/mochitest.ini | 2 + .../mediasource/test/test_Sequence_mp4.html | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 dom/media/mediasource/test/test_Sequence_mp4.html diff --git a/dom/media/mediasource/test/mochitest.ini b/dom/media/mediasource/test/mochitest.ini index 0005ff4e41b6..2d990ce0b9b7 100644 --- a/dom/media/mediasource/test/mochitest.ini +++ b/dom/media/mediasource/test/mochitest.ini @@ -78,6 +78,8 @@ skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_SeekTwice_mp4.html] skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ +[test_Sequence_mp4.html] +skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_SetModeThrows.html] [test_SplitAppendDelay.html] [test_SplitAppendDelay_mp4.html] diff --git a/dom/media/mediasource/test/test_Sequence_mp4.html b/dom/media/mediasource/test/test_Sequence_mp4.html new file mode 100644 index 000000000000..f0542438d9a1 --- /dev/null +++ b/dom/media/mediasource/test/test_Sequence_mp4.html @@ -0,0 +1,39 @@ + + + + MSE: Don't get stuck buffering for too long when we have frames to show + + + + + +

+
+ + From a02b64b1498d26520c14b7eb4b2356075cc8173a Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 7 Oct 2015 12:00:52 +1100 Subject: [PATCH 015/189] Bug 1212164: Prevent use of demuxer before initialization completes. r=cpearce --- dom/media/MediaFormatReader.cpp | 8 ++++++-- dom/media/MediaFormatReader.h | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index be12573a1c8d..812fa159f2b5 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -63,9 +63,10 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder, MediaDataDemuxer* aDemuxer, TaskQueue* aBorrowedTaskQueue) : MediaDecoderReader(aDecoder, aBorrowedTaskQueue) - , mDemuxer(aDemuxer) , mAudio(this, MediaData::AUDIO_DATA, Preferences::GetUint("media.audio-decode-ahead", 2)) , mVideo(this, MediaData::VIDEO_DATA, Preferences::GetUint("media.video-decode-ahead", 2)) + , mDemuxer(aDemuxer) + , mDemuxerInitDone(false) , mLastReportedNumDecodedFrames(0) , mLayersBackendType(layers::LayersBackend::LAYERS_NONE) , mInitDone(false) @@ -286,6 +287,8 @@ MediaFormatReader::OnDemuxerInitDone(nsresult) MOZ_ASSERT(OnTaskQueue()); mDemuxerInitRequest.Complete(); + mDemuxerInitDone = true; + // To decode, we need valid video and a place to put it. bool videoActive = !!mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack) && mDecoder->GetImageContainer(); @@ -1623,7 +1626,8 @@ MediaFormatReader::NotifyDemuxer(uint32_t aLength, int64_t aOffset) MOZ_ASSERT(OnTaskQueue()); LOGV("aLength=%u, aOffset=%lld", aLength, aOffset); - if (mShutdown || !mDemuxer) { + if (mShutdown || !mDemuxer || + (!mDemuxerInitDone && !mDemuxerInitRequest.Exists())) { return; } diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 935648091b5c..fd301af5ae96 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -154,7 +154,6 @@ private: size_t SizeOfQueue(TrackType aTrack); - nsRefPtr mDemuxer; nsRefPtr mPlatform; class DecoderCallback : public MediaDataDecoderCallback { @@ -357,6 +356,8 @@ private: void OnDecoderInitFailed(MediaDataDecoder::DecoderFailureReason aReason); // Demuxer objects. + nsRefPtr mDemuxer; + bool mDemuxerInitDone; void OnDemuxerInitDone(nsresult); void OnDemuxerInitFailed(DemuxerFailureReason aFailure); MozPromiseRequestHolder mDemuxerInitRequest; From 9861c50a98409eeac8f9efb6fd123e4afaeab82f Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 22:55:18 +1100 Subject: [PATCH 016/189] Bug 1211335: Have FFMpegDecoderModule properly return if a codec is supported. r=cpearce --- .../platforms/ffmpeg/FFmpegDataDecoder.cpp | 28 +++++++++++-------- .../platforms/ffmpeg/FFmpegDataDecoder.h | 2 ++ .../platforms/ffmpeg/FFmpegDecoderModule.h | 9 ++++-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp index 6079c8673be4..84e4c24f6add 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp @@ -70,24 +70,16 @@ ChoosePixelFormat(AVCodecContext* aCodecContext, const PixelFormat* aFormats) nsresult FFmpegDataDecoder::InitDecoder() { - StaticMutexAutoLock mon(sMonitor); - FFMPEG_LOG("Initialising FFmpeg decoder."); - if (!sFFmpegInitDone) { - avcodec_register_all(); -#ifdef DEBUG - av_log_set_level(AV_LOG_DEBUG); -#endif - sFFmpegInitDone = true; - } - - AVCodec* codec = avcodec_find_decoder(mCodecID); + AVCodec* codec = FindAVCodec(mCodecID); if (!codec) { NS_WARNING("Couldn't find ffmpeg decoder"); return NS_ERROR_FAILURE; } + StaticMutexAutoLock mon(sMonitor); + if (!(mCodecContext = avcodec_alloc_context3(codec))) { NS_WARNING("Couldn't init ffmpeg context"); return NS_ERROR_FAILURE; @@ -240,4 +232,18 @@ FFmpegDataDecoder::PrepareFrame() return mFrame; } +/* static */ AVCodec* +FFmpegDataDecoder::FindAVCodec(AVCodecID aCodec) +{ + StaticMutexAutoLock mon(sMonitor); + if (!sFFmpegInitDone) { + avcodec_register_all(); +#ifdef DEBUG + av_log_set_level(AV_LOG_DEBUG); +#endif + sFFmpegInitDone = true; + } + return avcodec_find_decoder(aCodec); +} + } // namespace mozilla diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h index 9b7cfb124839..c8f98e0835ea 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h @@ -36,6 +36,8 @@ public: nsresult Drain() override; nsresult Shutdown() override; + static AVCodec* FindAVCodec(AVCodecID aCodec); + protected: // Flush and Drain operation, always run virtual void ProcessFlush(); diff --git a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h index 0e99695d205d..24322d2da541 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h +++ b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h @@ -68,8 +68,13 @@ public: bool SupportsMimeType(const nsACString& aMimeType) override { - return FFmpegAudioDecoder::GetCodecId(aMimeType) != AV_CODEC_ID_NONE || - FFmpegH264Decoder::GetCodecId(aMimeType) != AV_CODEC_ID_NONE; + AVCodecID audioCodec = FFmpegAudioDecoder::GetCodecId(aMimeType); + AVCodecID videoCodec = FFmpegH264Decoder::GetCodecId(aMimeType); + if (audioCodec == AV_CODEC_ID_NONE && videoCodec == AV_CODEC_ID_NONE) { + return false; + } + AVCodecID codec = audioCodec != AV_CODEC_ID_NONE ? audioCodec : videoCodec; + return !!FFmpegDataDecoder::FindAVCodec(codec); } ConversionRequired From cc74e2d1a4724ddd0347524f2151082cbb5760bf Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Mon, 5 Oct 2015 18:59:24 +1100 Subject: [PATCH 017/189] Bug 1206977: P1. Remove unused PDM function members. r=cpearce --- dom/media/platforms/PlatformDecoderModule.h | 4 ---- dom/media/platforms/agnostic/BlankDecoderModule.cpp | 5 ----- 2 files changed, 9 deletions(-) diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index bd633f6b4e30..4bebc973ac49 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -110,10 +110,6 @@ public: // feeding it to MediaDataDecoder::Input. virtual ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const = 0; - virtual bool SupportsSharedDecoders(const VideoInfo& aConfig) const { - return !AgnosticMimeType(aConfig.mMimeType); - } - protected: PlatformDecoderModule() {} virtual ~PlatformDecoderModule() {} diff --git a/dom/media/platforms/agnostic/BlankDecoderModule.cpp b/dom/media/platforms/agnostic/BlankDecoderModule.cpp index b6a77f6298bd..f176055f59dc 100644 --- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp +++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp @@ -251,11 +251,6 @@ public: return true; } - bool - SupportsSharedDecoders(const VideoInfo& aConfig) const override { - return false; - } - ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override { From dd5e99c6940c4ff7f003ad3279912aff635dedb1 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Mon, 5 Oct 2015 21:08:56 +1100 Subject: [PATCH 018/189] Bug 1206977: P2. Wrap PDM creation in a new PDMFactory class. r=cpearce There is no change of behaviour from the original PlatformDecoderModule. --- dom/media/MediaFormatReader.cpp | 6 +- dom/media/platforms/PDMFactory.cpp | 244 ++++++++++++++++++ dom/media/platforms/PDMFactory.h | 80 ++++++ dom/media/platforms/PlatformDecoderModule.cpp | 226 +--------------- dom/media/platforms/PlatformDecoderModule.h | 24 +- .../platforms/ffmpeg/FFmpegDecoderModule.h | 3 +- .../platforms/ffmpeg/FFmpegRuntimeLinker.cpp | 6 + .../platforms/ffmpeg/FFmpegRuntimeLinker.h | 2 + dom/media/platforms/moz.build | 1 + 9 files changed, 346 insertions(+), 246 deletions(-) create mode 100644 dom/media/platforms/PDMFactory.cpp create mode 100644 dom/media/platforms/PDMFactory.h diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 812fa159f2b5..f33848c5882e 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -240,15 +240,13 @@ MediaFormatReader::IsWaitingOnCDMResource() { bool MediaFormatReader::IsSupportedAudioMimeType(const nsACString& aMimeType) { - return mPlatform && (mPlatform->SupportsMimeType(aMimeType) || - PlatformDecoderModule::AgnosticMimeType(aMimeType)); + return mPlatform && mPlatform->SupportsMimeType(aMimeType); } bool MediaFormatReader::IsSupportedVideoMimeType(const nsACString& aMimeType) { - return mPlatform && (mPlatform->SupportsMimeType(aMimeType) || - PlatformDecoderModule::AgnosticMimeType(aMimeType)); + return mPlatform && mPlatform->SupportsMimeType(aMimeType); } nsRefPtr diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp new file mode 100644 index 000000000000..a2e5f23d64e2 --- /dev/null +++ b/dom/media/platforms/PDMFactory.cpp @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/. */ + +#include "PDMFactory.h" + +#ifdef XP_WIN +#include "WMFDecoderModule.h" +#endif +#ifdef MOZ_FFMPEG +#include "FFmpegRuntimeLinker.h" +#endif +#ifdef MOZ_APPLEMEDIA +#include "AppleDecoderModule.h" +#endif +#ifdef MOZ_GONK_MEDIACODEC +#include "GonkDecoderModule.h" +#endif +#ifdef MOZ_WIDGET_ANDROID +#include "AndroidDecoderModule.h" +#endif +#include "GMPDecoderModule.h" + +#include "mozilla/Preferences.h" +#include "mozilla/TaskQueue.h" + +#include "mozilla/SharedThreadPool.h" + +#include "MediaInfo.h" +#include "FuzzingWrapper.h" +#include "H264Converter.h" + +#include "OpusDecoder.h" +#include "VorbisDecoder.h" +#include "VPXDecoder.h" + +namespace mozilla { + +extern already_AddRefed CreateAgnosticDecoderModule(); +extern already_AddRefed CreateBlankDecoderModule(); + +bool PDMFactory::sUseBlankDecoder = false; +bool PDMFactory::sGonkDecoderEnabled = false; +bool PDMFactory::sAndroidMCDecoderEnabled = false; +bool PDMFactory::sAndroidMCDecoderPreferred = false; +bool PDMFactory::sGMPDecoderEnabled = false; +bool PDMFactory::sEnableFuzzingWrapper = false; +uint32_t PDMFactory::sVideoOutputMinimumInterval_ms = 0; +bool PDMFactory::sDontDelayInputExhausted = false; + +/* static */ +void +PDMFactory::Init() +{ + MOZ_ASSERT(NS_IsMainThread()); + static bool alreadyInitialized = false; + if (alreadyInitialized) { + return; + } + alreadyInitialized = true; + + Preferences::AddBoolVarCache(&sUseBlankDecoder, + "media.fragmented-mp4.use-blank-decoder"); +#ifdef MOZ_GONK_MEDIACODEC + Preferences::AddBoolVarCache(&sGonkDecoderEnabled, + "media.fragmented-mp4.gonk.enabled", false); +#endif +#ifdef MOZ_WIDGET_ANDROID + Preferences::AddBoolVarCache(&sAndroidMCDecoderEnabled, + "media.fragmented-mp4.android-media-codec.enabled", false); + Preferences::AddBoolVarCache(&sAndroidMCDecoderPreferred, + "media.fragmented-mp4.android-media-codec.preferred", false); +#endif + + Preferences::AddBoolVarCache(&sGMPDecoderEnabled, + "media.fragmented-mp4.gmp.enabled", false); + + Preferences::AddBoolVarCache(&sEnableFuzzingWrapper, + "media.decoder.fuzzing.enabled", false); + Preferences::AddUintVarCache(&sVideoOutputMinimumInterval_ms, + "media.decoder.fuzzing.video-output-minimum-interval-ms", 0); + Preferences::AddBoolVarCache(&sDontDelayInputExhausted, + "media.decoder.fuzzing.dont-delay-inputexhausted", false); + +#ifdef XP_WIN + WMFDecoderModule::Init(); +#endif +#ifdef MOZ_APPLEMEDIA + AppleDecoderModule::Init(); +#endif +#ifdef MOZ_FFMPEG + FFmpegRuntimeLinker::Link(); +#endif +} + +PDMFactory::PDMFactory() + : mCurrentPDM(CreatePDM()) +{ + if (!mCurrentPDM || NS_FAILED(mCurrentPDM->Startup())) { + mCurrentPDM = CreateAgnosticDecoderModule(); + } +} + +PDMFactory::~PDMFactory() +{ +} + +already_AddRefed +PDMFactory::CreateDecoder(const TrackInfo& aConfig, + FlushableTaskQueue* aTaskQueue, + MediaDataDecoderCallback* aCallback, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer) +{ + MOZ_ASSERT(mCurrentPDM); + + nsRefPtr m; + + bool hasPlatformDecoder = mCurrentPDM->SupportsMimeType(aConfig.mMimeType); + + if (aConfig.GetAsAudioInfo()) { + if (!hasPlatformDecoder && VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { + m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), + aTaskQueue, + aCallback); + } else if (!hasPlatformDecoder && OpusDataDecoder::IsOpus(aConfig.mMimeType)) { + m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), + aTaskQueue, + aCallback); + } else { + m = mCurrentPDM->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), + aTaskQueue, + aCallback); + } + return m.forget(); + } + + if (!aConfig.GetAsVideoInfo()) { + return nullptr; + } + + MediaDataDecoderCallback* callback = aCallback; + nsRefPtr callbackWrapper; + if (sEnableFuzzingWrapper) { + callbackWrapper = new DecoderCallbackFuzzingWrapper(aCallback); + callbackWrapper->SetVideoOutputMinimumInterval( + TimeDuration::FromMilliseconds(sVideoOutputMinimumInterval_ms)); + callbackWrapper->SetDontDelayInputExhausted(sDontDelayInputExhausted); + callback = callbackWrapper.get(); + } + + if (H264Converter::IsH264(aConfig)) { + nsRefPtr h + = new H264Converter(mCurrentPDM, + *aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + const nsresult rv = h->GetLastError(); + if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { + // The H264Converter either successfully created the wrapped decoder, + // or there wasn't enough AVCC data to do so. Otherwise, there was some + // problem, for example WMF DLLs were missing. + m = h.forget(); + } + } else if (!hasPlatformDecoder && VPXDecoder::IsVPX(aConfig.mMimeType)) { + m = new VPXDecoder(*aConfig.GetAsVideoInfo(), + aImageContainer, + aTaskQueue, + callback); + } else { + m = mCurrentPDM->CreateVideoDecoder(*aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + } + + if (callbackWrapper && m) { + m = new DecoderFuzzingWrapper(m.forget(), callbackWrapper.forget()); + } + + return m.forget(); +} + +bool +PDMFactory::SupportsMimeType(const nsACString& aMimeType) +{ + MOZ_ASSERT(mCurrentPDM); + return mCurrentPDM->SupportsMimeType(aMimeType) || + VPXDecoder::IsVPX(aMimeType) || + OpusDataDecoder::IsOpus(aMimeType) || + VorbisDataDecoder::IsVorbis(aMimeType); +} + +already_AddRefed +PDMFactory::CreatePDM() +{ + if (sGMPDecoderEnabled) { + nsRefPtr m(new GMPDecoderModule()); + return m.forget(); + } +#ifdef MOZ_WIDGET_ANDROID + if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled){ + nsRefPtr m(new AndroidDecoderModule()); + return m.forget(); + } +#endif + if (sUseBlankDecoder) { + return CreateBlankDecoderModule(); + } +#ifdef XP_WIN + nsRefPtr m(new WMFDecoderModule()); + return m.forget(); +#endif +#ifdef MOZ_FFMPEG + nsRefPtr mffmpeg = FFmpegRuntimeLinker::CreateDecoderModule(); + if (mffmpeg) { + return mffmpeg.forget(); + } +#endif +#ifdef MOZ_APPLEMEDIA + nsRefPtr m(new AppleDecoderModule()); + return m.forget(); +#endif +#ifdef MOZ_GONK_MEDIACODEC + if (sGonkDecoderEnabled) { + nsRefPtr m(new GonkDecoderModule()); + return m.forget(); + } +#endif +#ifdef MOZ_WIDGET_ANDROID + if(sAndroidMCDecoderEnabled){ + nsRefPtr m(new AndroidDecoderModule()); + return m.forget(); + } +#endif + return nullptr; +} + +} // namespace mozilla diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h new file mode 100644 index 000000000000..2cd70a83bfcc --- /dev/null +++ b/dom/media/platforms/PDMFactory.h @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/. */ + +#if !defined(PDMFactory_h_) +#define PDMFactory_h_ + +#include "PlatformDecoderModule.h" + +namespace mozilla { + +class PDMFactory : public PlatformDecoderModule { +public: + PDMFactory(); + virtual ~PDMFactory(); + + // Call on the main thread to initialize the static state + // needed by Create(). + static void Init(); + + already_AddRefed + CreateDecoder(const TrackInfo& aConfig, + FlushableTaskQueue* aTaskQueue, + MediaDataDecoderCallback* aCallback, + layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, + layers::ImageContainer* aImageContainer = nullptr) override; + + bool SupportsMimeType(const nsACString& aMimeType) override; + + ConversionRequired + DecoderNeedsConversion(const TrackInfo& aConfig) const override + { + MOZ_CRASH("Should never reach this function"); + return ConversionRequired::kNeedNone; + } + +protected: + // Decode thread. + already_AddRefed + CreateVideoDecoder(const VideoInfo& aConfig, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer, + FlushableTaskQueue* aVideoTaskQueue, + MediaDataDecoderCallback* aCallback) override + { + MOZ_CRASH("Should never reach this function"); + return nullptr; + } + + // Decode thread. + already_AddRefed + CreateAudioDecoder(const AudioInfo& aConfig, + FlushableTaskQueue* aAudioTaskQueue, + MediaDataDecoderCallback* aCallback) override + { + MOZ_CRASH("Should never reach this function"); + return nullptr; + } + +private: + already_AddRefed CreatePDM(); + + // Caches pref media.fragmented-mp4.use-blank-decoder + static bool sUseBlankDecoder; + static bool sGonkDecoderEnabled; + static bool sAndroidMCDecoderPreferred; + static bool sAndroidMCDecoderEnabled; + static bool sGMPDecoderEnabled; + static bool sEnableFuzzingWrapper; + static uint32_t sVideoOutputMinimumInterval_ms; + static bool sDontDelayInputExhausted; + + nsRefPtr mCurrentPDM; +}; + +} // namespace mozilla + +#endif /* PDMFactory_h_ */ diff --git a/dom/media/platforms/PlatformDecoderModule.cpp b/dom/media/platforms/PlatformDecoderModule.cpp index 70294c9c1a0b..fdb495744f8b 100644 --- a/dom/media/platforms/PlatformDecoderModule.cpp +++ b/dom/media/platforms/PlatformDecoderModule.cpp @@ -5,40 +5,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "PlatformDecoderModule.h" - -#ifdef XP_WIN -#include "WMFDecoderModule.h" -#endif -#ifdef MOZ_FFMPEG -#include "FFmpegRuntimeLinker.h" -#endif -#ifdef MOZ_APPLEMEDIA -#include "AppleDecoderModule.h" -#endif -#ifdef MOZ_GONK_MEDIACODEC -#include "GonkDecoderModule.h" -#endif -#ifdef MOZ_WIDGET_ANDROID -#include "AndroidDecoderModule.h" -#endif -#include "GMPDecoderModule.h" - -#include "mozilla/Preferences.h" -#include "mozilla/TaskQueue.h" - +#include "PDMFactory.h" #ifdef MOZ_EME #include "EMEDecoderModule.h" #include "mozilla/CDMProxy.h" #endif -#include "mozilla/SharedThreadPool.h" - -#include "MediaInfo.h" -#include "FuzzingWrapper.h" -#include "H264Converter.h" - -#include "OpusDecoder.h" -#include "VorbisDecoder.h" -#include "VPXDecoder.h" PRLogModuleInfo* GetPDMLog() { static PRLogModuleInfo* log = nullptr; @@ -50,65 +21,12 @@ PRLogModuleInfo* GetPDMLog() { namespace mozilla { -extern already_AddRefed CreateAgnosticDecoderModule(); -extern already_AddRefed CreateBlankDecoderModule(); - -bool PlatformDecoderModule::sUseBlankDecoder = false; -bool PlatformDecoderModule::sFFmpegDecoderEnabled = false; -bool PlatformDecoderModule::sGonkDecoderEnabled = false; -bool PlatformDecoderModule::sAndroidMCDecoderEnabled = false; -bool PlatformDecoderModule::sAndroidMCDecoderPreferred = false; -bool PlatformDecoderModule::sGMPDecoderEnabled = false; -bool PlatformDecoderModule::sEnableFuzzingWrapper = false; -uint32_t PlatformDecoderModule::sVideoOutputMinimumInterval_ms = 0; -bool PlatformDecoderModule::sDontDelayInputExhausted = false; - /* static */ void PlatformDecoderModule::Init() { MOZ_ASSERT(NS_IsMainThread()); - static bool alreadyInitialized = false; - if (alreadyInitialized) { - return; - } - alreadyInitialized = true; - - Preferences::AddBoolVarCache(&sUseBlankDecoder, - "media.fragmented-mp4.use-blank-decoder"); - Preferences::AddBoolVarCache(&sFFmpegDecoderEnabled, - "media.fragmented-mp4.ffmpeg.enabled", false); - -#ifdef MOZ_GONK_MEDIACODEC - Preferences::AddBoolVarCache(&sGonkDecoderEnabled, - "media.fragmented-mp4.gonk.enabled", false); -#endif -#ifdef MOZ_WIDGET_ANDROID - Preferences::AddBoolVarCache(&sAndroidMCDecoderEnabled, - "media.fragmented-mp4.android-media-codec.enabled", false); - Preferences::AddBoolVarCache(&sAndroidMCDecoderPreferred, - "media.fragmented-mp4.android-media-codec.preferred", false); -#endif - - Preferences::AddBoolVarCache(&sGMPDecoderEnabled, - "media.fragmented-mp4.gmp.enabled", false); - - Preferences::AddBoolVarCache(&sEnableFuzzingWrapper, - "media.decoder.fuzzing.enabled", false); - Preferences::AddUintVarCache(&sVideoOutputMinimumInterval_ms, - "media.decoder.fuzzing.video-output-minimum-interval-ms", 0); - Preferences::AddBoolVarCache(&sDontDelayInputExhausted, - "media.decoder.fuzzing.dont-delay-inputexhausted", false); - -#ifdef XP_WIN - WMFDecoderModule::Init(); -#endif -#ifdef MOZ_APPLEMEDIA - AppleDecoderModule::Init(); -#endif -#ifdef MOZ_FFMPEG - FFmpegRuntimeLinker::Link(); -#endif + PDMFactory::Init(); } #ifdef MOZ_EME @@ -142,135 +60,7 @@ already_AddRefed PlatformDecoderModule::Create() { // Note: This (usually) runs on the decode thread. - - nsRefPtr m(CreatePDM()); - - if (m && NS_SUCCEEDED(m->Startup())) { - return m.forget(); - } - return CreateAgnosticDecoderModule(); -} - -/* static */ -already_AddRefed -PlatformDecoderModule::CreatePDM() -{ - if (sGMPDecoderEnabled) { - nsRefPtr m(new GMPDecoderModule()); - return m.forget(); - } -#ifdef MOZ_WIDGET_ANDROID - if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled){ - nsRefPtr m(new AndroidDecoderModule()); - return m.forget(); - } -#endif - if (sUseBlankDecoder) { - return CreateBlankDecoderModule(); - } -#ifdef XP_WIN - nsRefPtr m(new WMFDecoderModule()); - return m.forget(); -#endif -#ifdef MOZ_FFMPEG - nsRefPtr mffmpeg = FFmpegRuntimeLinker::CreateDecoderModule(); - if (mffmpeg) { - return mffmpeg.forget(); - } -#endif -#ifdef MOZ_APPLEMEDIA - nsRefPtr m(new AppleDecoderModule()); - return m.forget(); -#endif -#ifdef MOZ_GONK_MEDIACODEC - if (sGonkDecoderEnabled) { - nsRefPtr m(new GonkDecoderModule()); - return m.forget(); - } -#endif -#ifdef MOZ_WIDGET_ANDROID - if(sAndroidMCDecoderEnabled){ - nsRefPtr m(new AndroidDecoderModule()); - return m.forget(); - } -#endif - return nullptr; -} - -already_AddRefed -PlatformDecoderModule::CreateDecoder(const TrackInfo& aConfig, - FlushableTaskQueue* aTaskQueue, - MediaDataDecoderCallback* aCallback, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer) -{ - nsRefPtr m; - - bool hasPlatformDecoder = SupportsMimeType(aConfig.mMimeType); - - if (aConfig.GetAsAudioInfo()) { - if (!hasPlatformDecoder && VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { - m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); - } else if (!hasPlatformDecoder && OpusDataDecoder::IsOpus(aConfig.mMimeType)) { - m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); - } else { - m = CreateAudioDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); - } - return m.forget(); - } - - if (!aConfig.GetAsVideoInfo()) { - return nullptr; - } - - MediaDataDecoderCallback* callback = aCallback; - nsRefPtr callbackWrapper; - if (sEnableFuzzingWrapper) { - callbackWrapper = new DecoderCallbackFuzzingWrapper(aCallback); - callbackWrapper->SetVideoOutputMinimumInterval( - TimeDuration::FromMilliseconds(sVideoOutputMinimumInterval_ms)); - callbackWrapper->SetDontDelayInputExhausted(sDontDelayInputExhausted); - callback = callbackWrapper.get(); - } - - if (H264Converter::IsH264(aConfig)) { - nsRefPtr h - = new H264Converter(this, - *aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); - const nsresult rv = h->GetLastError(); - if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { - // The H264Converter either successfully created the wrapped decoder, - // or there wasn't enough AVCC data to do so. Otherwise, there was some - // problem, for example WMF DLLs were missing. - m = h.forget(); - } - } else if (!hasPlatformDecoder && VPXDecoder::IsVPX(aConfig.mMimeType)) { - m = new VPXDecoder(*aConfig.GetAsVideoInfo(), - aImageContainer, - aTaskQueue, - callback); - } else { - m = CreateVideoDecoder(*aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); - } - - if (callbackWrapper && m) { - m = new DecoderFuzzingWrapper(m.forget(), callbackWrapper.forget()); - } - + nsRefPtr m = new PDMFactory; return m.forget(); } @@ -282,14 +72,4 @@ PlatformDecoderModule::SupportsMimeType(const nsACString& aMimeType) aMimeType.EqualsLiteral("video/avc"); } -/* static */ -bool -PlatformDecoderModule::AgnosticMimeType(const nsACString& aMimeType) -{ - return VPXDecoder::IsVPX(aMimeType) || - OpusDataDecoder::IsOpus(aMimeType) || - VorbisDataDecoder::IsVorbis(aMimeType); -} - - } // namespace mozilla diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index 4bebc973ac49..e8d4426354d1 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -63,8 +63,6 @@ public: // PlatformDecoderModule created per MP4Reader. // This is called on the decode task queue. static already_AddRefed Create(); - // As Create() but do not initialize the created PlatformDecoderModule. - static already_AddRefed CreatePDM(); // Perform any per-instance initialization. // This is called on the decode task queue. @@ -87,7 +85,10 @@ public: FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, - layers::ImageContainer* aImageContainer = nullptr); + layers::ImageContainer* aImageContainer = nullptr) + { + MOZ_CRASH(); + } // An audio decoder module must support AAC by default. // A video decoder must support H264 by default. @@ -95,10 +96,6 @@ public: // to be extended virtual bool SupportsMimeType(const nsACString& aMimeType); - // MimeType can be decoded with shipped decoders if no platform decoders exist - static bool AgnosticMimeType(const nsACString& aMimeType); - - enum ConversionRequired { kNeedNone, kNeedAVCC, @@ -115,6 +112,8 @@ protected: virtual ~PlatformDecoderModule() {} friend class H264Converter; + friend class PDMFactory; + // Creates a Video decoder. The layers backend is passed in so that // decoders can determine whether hardware accelerated decoding can be used. // Asynchronous decoding of video should be done in runnables dispatched @@ -147,17 +146,6 @@ protected: CreateAudioDecoder(const AudioInfo& aConfig, FlushableTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) = 0; - - // Caches pref media.fragmented-mp4.use-blank-decoder - static bool sUseBlankDecoder; - static bool sFFmpegDecoderEnabled; - static bool sGonkDecoderEnabled; - static bool sAndroidMCDecoderPreferred; - static bool sAndroidMCDecoderEnabled; - static bool sGMPDecoderEnabled; - static bool sEnableFuzzingWrapper; - static uint32_t sVideoOutputMinimumInterval_ms; - static bool sDontDelayInputExhausted; }; // A callback used by MediaDataDecoder to return output/errors to the diff --git a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h index 24322d2da541..ef9973d1ce2b 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h +++ b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h @@ -10,6 +10,7 @@ #include "PlatformDecoderModule.h" #include "FFmpegAudioDecoder.h" #include "FFmpegH264Decoder.h" +#include "FFmpegRuntimeLinker.h" namespace mozilla { @@ -23,7 +24,7 @@ public: { uint32_t major, minor; GetVersion(major, minor); - if (major < 54 && !sFFmpegDecoderEnabled) { + if (major < 54 && !FFmpegRuntimeLinker::sFFmpegDecoderEnabled) { return nullptr; } nsRefPtr pdm = new FFmpegDecoderModule(); diff --git a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp index ca3d9fea75e0..a60851de21cd 100644 --- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp @@ -9,12 +9,15 @@ #include "FFmpegRuntimeLinker.h" #include "mozilla/ArrayUtils.h" #include "FFmpegLog.h" +#include "mozilla/Preferences.h" #define NUM_ELEMENTS(X) (sizeof(X) / sizeof((X)[0])) namespace mozilla { +bool FFmpegRuntimeLinker::sFFmpegDecoderEnabled = false; + FFmpegRuntimeLinker::LinkStatus FFmpegRuntimeLinker::sLinkStatus = LinkStatus_INIT; @@ -59,6 +62,9 @@ FFmpegRuntimeLinker::Link() return sLinkStatus == LinkStatus_SUCCEEDED; } + Preferences::AddBoolVarCache(&sFFmpegDecoderEnabled, + "media.fragmented-mp4.ffmpeg.enabled", false); + MOZ_ASSERT(NS_IsMainThread()); for (size_t i = 0; i < ArrayLength(sLibs); i++) { diff --git a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h index 68e42f15ce64..5e098dfa1f10 100644 --- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h +++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h @@ -22,6 +22,8 @@ public: static void Unlink(); static already_AddRefed CreateDecoderModule(); + static bool sFFmpegDecoderEnabled; + private: static void* sLinkedLib; static const AvCodecLib* sLib; diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index 66e17091aa07..ae84d1f0144c 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -18,6 +18,7 @@ UNIFIED_SOURCES += [ 'agnostic/OpusDecoder.cpp', 'agnostic/VorbisDecoder.cpp', 'agnostic/VPXDecoder.cpp', + 'PDMFactory.cpp', 'PlatformDecoderModule.cpp', 'wrappers/FuzzingWrapper.cpp', 'wrappers/H264Converter.cpp' From 35090bba3a3dedadc163306d400abd0d683b94ed Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 09:08:03 +1100 Subject: [PATCH 019/189] Bug 1206977: P3. Allow PDM fallback. r=cpearce We now search in all the PDM present the one that can handle the media. --- dom/media/platforms/PDMFactory.cpp | 141 ++++++++++++++++------------- dom/media/platforms/PDMFactory.h | 8 +- 2 files changed, 86 insertions(+), 63 deletions(-) diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index a2e5f23d64e2..f14b8a0bd5d4 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -96,11 +96,8 @@ PDMFactory::Init() } PDMFactory::PDMFactory() - : mCurrentPDM(CreatePDM()) { - if (!mCurrentPDM || NS_FAILED(mCurrentPDM->Startup())) { - mCurrentPDM = CreateAgnosticDecoderModule(); - } + CreatePDMs(); } PDMFactory::~PDMFactory() @@ -114,25 +111,22 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer) { - MOZ_ASSERT(mCurrentPDM); - + nsRefPtr current = GetDecoder(aConfig.mMimeType); nsRefPtr m; - bool hasPlatformDecoder = mCurrentPDM->SupportsMimeType(aConfig.mMimeType); - if (aConfig.GetAsAudioInfo()) { - if (!hasPlatformDecoder && VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { + if (!current && VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), aTaskQueue, aCallback); - } else if (!hasPlatformDecoder && OpusDataDecoder::IsOpus(aConfig.mMimeType)) { + } else if (!current && OpusDataDecoder::IsOpus(aConfig.mMimeType)) { m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), aTaskQueue, aCallback); - } else { - m = mCurrentPDM->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); + } else if (current) { + m = current->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), + aTaskQueue, + aCallback); } return m.forget(); } @@ -151,32 +145,34 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, callback = callbackWrapper.get(); } - if (H264Converter::IsH264(aConfig)) { - nsRefPtr h - = new H264Converter(mCurrentPDM, - *aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); - const nsresult rv = h->GetLastError(); - if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { - // The H264Converter either successfully created the wrapped decoder, - // or there wasn't enough AVCC data to do so. Otherwise, there was some - // problem, for example WMF DLLs were missing. - m = h.forget(); - } - } else if (!hasPlatformDecoder && VPXDecoder::IsVPX(aConfig.mMimeType)) { + if (!current && VPXDecoder::IsVPX(aConfig.mMimeType)) { m = new VPXDecoder(*aConfig.GetAsVideoInfo(), aImageContainer, aTaskQueue, callback); - } else { - m = mCurrentPDM->CreateVideoDecoder(*aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); + } else if (current) { + if (H264Converter::IsH264(aConfig)) { + nsRefPtr h + = new H264Converter(current, + *aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + const nsresult rv = h->GetLastError(); + if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { + // The H264Converter either successfully created the wrapped decoder, + // or there wasn't enough AVCC data to do so. Otherwise, there was some + // problem, for example WMF DLLs were missing. + m = h.forget(); + } + } else { + m = current->CreateVideoDecoder(*aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + } } if (callbackWrapper && m) { @@ -189,56 +185,79 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, bool PDMFactory::SupportsMimeType(const nsACString& aMimeType) { - MOZ_ASSERT(mCurrentPDM); - return mCurrentPDM->SupportsMimeType(aMimeType) || + nsRefPtr current = GetDecoder(aMimeType); + return current || VPXDecoder::IsVPX(aMimeType) || OpusDataDecoder::IsOpus(aMimeType) || VorbisDataDecoder::IsVorbis(aMimeType); } -already_AddRefed -PDMFactory::CreatePDM() +void +PDMFactory::CreatePDMs() { + nsRefPtr m; + if (sGMPDecoderEnabled) { - nsRefPtr m(new GMPDecoderModule()); - return m.forget(); + m = new GMPDecoderModule(); + StartupPDM(m); } #ifdef MOZ_WIDGET_ANDROID - if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled){ - nsRefPtr m(new AndroidDecoderModule()); - return m.forget(); + if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled) { + m = new AndroidDecoderModule(); + StartupPDM(m); } #endif - if (sUseBlankDecoder) { - return CreateBlankDecoderModule(); - } #ifdef XP_WIN - nsRefPtr m(new WMFDecoderModule()); - return m.forget(); + m = new WMFDecoderModule(); + StartupPDM(m); #endif #ifdef MOZ_FFMPEG - nsRefPtr mffmpeg = FFmpegRuntimeLinker::CreateDecoderModule(); - if (mffmpeg) { - return mffmpeg.forget(); - } + m = FFmpegRuntimeLinker::CreateDecoderModule(); + StartupPDM(m); #endif #ifdef MOZ_APPLEMEDIA - nsRefPtr m(new AppleDecoderModule()); - return m.forget(); + m = new AppleDecoderModule(); + StartupPDM(m); #endif #ifdef MOZ_GONK_MEDIACODEC if (sGonkDecoderEnabled) { - nsRefPtr m(new GonkDecoderModule()); - return m.forget(); + m = new GonkDecoderModule(); + StartupPDM(m); } #endif #ifdef MOZ_WIDGET_ANDROID if(sAndroidMCDecoderEnabled){ - nsRefPtr m(new AndroidDecoderModule()); - return m.forget(); + m = new AndroidDecoderModule(); + StartupPDM(m); } #endif - return nullptr; + if (sUseBlankDecoder) { + m = CreateBlankDecoderModule(); + StartupPDM(m); + } +} + +bool +PDMFactory::StartupPDM(PlatformDecoderModule* aPDM) +{ + if (aPDM && NS_SUCCEEDED(aPDM->Startup())) { + mCurrentPDMs.AppendElement(aPDM); + return true; + } + return false; +} + +already_AddRefed +PDMFactory::GetDecoder(const nsACString& aMimeType) +{ + nsRefPtr pdm; + for (auto& current : mCurrentPDMs) { + if (current->SupportsMimeType(aMimeType)) { + pdm = current; + break; + } + } + return pdm.forget(); } } // namespace mozilla diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h index 2cd70a83bfcc..4f88f215ea4f 100644 --- a/dom/media/platforms/PDMFactory.h +++ b/dom/media/platforms/PDMFactory.h @@ -60,7 +60,11 @@ protected: } private: - already_AddRefed CreatePDM(); + void CreatePDMs(); + // Startup the provided PDM and add it to our list if successful. + bool StartupPDM(PlatformDecoderModule* aPDM); + // Returns the first PDM in our list supporting the mimetype. + already_AddRefed GetDecoder(const nsACString& aMimeType); // Caches pref media.fragmented-mp4.use-blank-decoder static bool sUseBlankDecoder; @@ -72,7 +76,7 @@ private: static uint32_t sVideoOutputMinimumInterval_ms; static bool sDontDelayInputExhausted; - nsRefPtr mCurrentPDM; + nsTArray> mCurrentPDMs; }; } // namespace mozilla From 9e830ea93037251b668179d6c1bbc45ad087d854 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 09:53:02 +1100 Subject: [PATCH 020/189] Bug 1206977: P4. Add AgnosticDecoderModule object. r=cpearce This removes the need for PDMFactory to know anything about decoders. --- dom/media/platforms/PDMFactory.cpp | 75 ++++++++----------- .../agnostic/AgnosticDecoderModule.cpp | 61 +++++++++++++++ .../agnostic/AgnosticDecoderModule.h | 39 ++++++++++ .../platforms/agnostic/BlankDecoderModule.cpp | 17 ----- dom/media/platforms/moz.build | 2 + 5 files changed, 132 insertions(+), 62 deletions(-) create mode 100644 dom/media/platforms/agnostic/AgnosticDecoderModule.cpp create mode 100644 dom/media/platforms/agnostic/AgnosticDecoderModule.h diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index f14b8a0bd5d4..54006762716a 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -32,9 +32,7 @@ #include "FuzzingWrapper.h" #include "H264Converter.h" -#include "OpusDecoder.h" -#include "VorbisDecoder.h" -#include "VPXDecoder.h" +#include "AgnosticDecoderModule.h" namespace mozilla { @@ -112,22 +110,15 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, layers::ImageContainer* aImageContainer) { nsRefPtr current = GetDecoder(aConfig.mMimeType); + if (!current) { + return nullptr; + } nsRefPtr m; if (aConfig.GetAsAudioInfo()) { - if (!current && VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { - m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); - } else if (!current && OpusDataDecoder::IsOpus(aConfig.mMimeType)) { - m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); - } else if (current) { - m = current->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), + m = current->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), aTaskQueue, aCallback); - } return m.forget(); } @@ -145,34 +136,27 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, callback = callbackWrapper.get(); } - if (!current && VPXDecoder::IsVPX(aConfig.mMimeType)) { - m = new VPXDecoder(*aConfig.GetAsVideoInfo(), - aImageContainer, - aTaskQueue, - callback); - } else if (current) { - if (H264Converter::IsH264(aConfig)) { - nsRefPtr h - = new H264Converter(current, - *aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); - const nsresult rv = h->GetLastError(); - if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { - // The H264Converter either successfully created the wrapped decoder, - // or there wasn't enough AVCC data to do so. Otherwise, there was some - // problem, for example WMF DLLs were missing. - m = h.forget(); - } - } else { - m = current->CreateVideoDecoder(*aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); + if (H264Converter::IsH264(aConfig)) { + nsRefPtr h + = new H264Converter(current, + *aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + const nsresult rv = h->GetLastError(); + if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { + // The H264Converter either successfully created the wrapped decoder, + // or there wasn't enough AVCC data to do so. Otherwise, there was some + // problem, for example WMF DLLs were missing. + m = h.forget(); } + } else { + m = current->CreateVideoDecoder(*aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); } if (callbackWrapper && m) { @@ -186,10 +170,7 @@ bool PDMFactory::SupportsMimeType(const nsACString& aMimeType) { nsRefPtr current = GetDecoder(aMimeType); - return current || - VPXDecoder::IsVPX(aMimeType) || - OpusDataDecoder::IsOpus(aMimeType) || - VorbisDataDecoder::IsVorbis(aMimeType); + return !!current; } void @@ -231,6 +212,10 @@ PDMFactory::CreatePDMs() StartupPDM(m); } #endif + + m = new AgnosticDecoderModule(); + StartupPDM(m); + if (sUseBlankDecoder) { m = CreateBlankDecoderModule(); StartupPDM(m); diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp new file mode 100644 index 000000000000..c877e80f392f --- /dev/null +++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/. */ + +#include "AgnosticDecoderModule.h" +#include "OpusDecoder.h" +#include "VorbisDecoder.h" +#include "VPXDecoder.h" + +namespace mozilla { + +bool +AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType) +{ + return VPXDecoder::IsVPX(aMimeType) || + OpusDataDecoder::IsOpus(aMimeType) || + VorbisDataDecoder::IsVorbis(aMimeType); +} + +already_AddRefed +AgnosticDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer, + FlushableTaskQueue* aVideoTaskQueue, + MediaDataDecoderCallback* aCallback) +{ + nsRefPtr m; + + if (VPXDecoder::IsVPX(aConfig.mMimeType)) { + m = new VPXDecoder(*aConfig.GetAsVideoInfo(), + aImageContainer, + aVideoTaskQueue, + aCallback); + } + + return m.forget(); +} + +already_AddRefed +AgnosticDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, + FlushableTaskQueue* aAudioTaskQueue, + MediaDataDecoderCallback* aCallback) +{ + nsRefPtr m; + + if (VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { + m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), + aAudioTaskQueue, + aCallback); + } else if (OpusDataDecoder::IsOpus(aConfig.mMimeType)) { + m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), + aAudioTaskQueue, + aCallback); + } + + return m.forget(); +} + +} // namespace mozilla diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.h b/dom/media/platforms/agnostic/AgnosticDecoderModule.h new file mode 100644 index 000000000000..97cc23e799b4 --- /dev/null +++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.h @@ -0,0 +1,39 @@ +#if !defined(AgnosticDecoderModule_h_) +#define AgnosticDecoderModule_h_ + +#include "PlatformDecoderModule.h" + +namespace mozilla { + +class AgnosticDecoderModule : public PlatformDecoderModule { +public: + AgnosticDecoderModule() = default; + virtual ~AgnosticDecoderModule() = default; + + bool SupportsMimeType(const nsACString& aMimeType) override; + + ConversionRequired + DecoderNeedsConversion(const TrackInfo& aConfig) const override + { + return ConversionRequired::kNeedNone; + } + +protected: + // Decode thread. + already_AddRefed + CreateVideoDecoder(const VideoInfo& aConfig, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer, + FlushableTaskQueue* aVideoTaskQueue, + MediaDataDecoderCallback* aCallback) override; + + // Decode thread. + already_AddRefed + CreateAudioDecoder(const AudioInfo& aConfig, + FlushableTaskQueue* aAudioTaskQueue, + MediaDataDecoderCallback* aCallback) override; +}; + +} // namespace mozilla + +#endif /* AgnosticDecoderModule_h_ */ diff --git a/dom/media/platforms/agnostic/BlankDecoderModule.cpp b/dom/media/platforms/agnostic/BlankDecoderModule.cpp index f176055f59dc..5b6e788f2964 100644 --- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp +++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp @@ -259,27 +259,10 @@ public: }; -class AgnosticDecoderModule : public BlankDecoderModule { -public: - - bool SupportsMimeType(const nsACString& aMimeType) override - { - // This module does not support any decoders itself, - // agnostic decoders are created in PlatformDecoderModule::CreateDecoder - return false; - } -}; - already_AddRefed CreateBlankDecoderModule() { nsRefPtr pdm = new BlankDecoderModule(); return pdm.forget(); } -already_AddRefed CreateAgnosticDecoderModule() -{ - nsRefPtr adm = new AgnosticDecoderModule(); - return adm.forget(); -} - } // namespace mozilla diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index ae84d1f0144c..8a217ce267c1 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS += [ + 'agnostic/AgnosticDecoderModule.h', 'agnostic/OpusDecoder.h', 'agnostic/VorbisDecoder.h', 'agnostic/VPXDecoder.h', @@ -14,6 +15,7 @@ EXPORTS += [ ] UNIFIED_SOURCES += [ + 'agnostic/AgnosticDecoderModule.cpp', 'agnostic/BlankDecoderModule.cpp', 'agnostic/OpusDecoder.cpp', 'agnostic/VorbisDecoder.cpp', From ff58eec4021188169b3792e0c3d715248ce13b34 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 10:17:12 +1100 Subject: [PATCH 021/189] Bug 1206977: P5. Update PlatformDecoderModule documentation. r=cpearce Mostly removes no longer relevant doc. --- dom/media/platforms/PlatformDecoderModule.h | 39 +++++++++------------ 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index e8d4426354d1..9c041e7a1171 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -30,24 +30,20 @@ class MediaDataDecoderCallback; class FlushableTaskQueue; class CDMProxy; -// The PlatformDecoderModule interface is used by the MP4Reader to abstract -// access to the H264 and Audio (AAC/MP3) decoders provided by various platforms. -// It may be extended to support other codecs in future. Each platform (Windows, -// MacOSX, Linux, B2G etc) must implement a PlatformDecoderModule to provide -// access to its decoders in order to get decompressed H.264/AAC from the -// MP4Reader. +// The PlatformDecoderModule interface is used by the MediaFormatReader to +// abstract access to decoders provided by various +// platforms. +// Each platform (Windows, MacOSX, Linux, B2G etc) must implement a +// PlatformDecoderModule to provide access to its decoders in order to get +// decompressed H.264/AAC from the MediaFormatReader. // -// Video decoding is asynchronous, and should be performed on the task queue +// Decoding is asynchronous, and should be performed on the task queue // provided if the underlying platform isn't already exposing an async API. // -// Platforms that don't have a corresponding PlatformDecoderModule won't be -// able to play the H.264/AAC data output by the MP4Reader. In practice this -// means that we won't have fragmented MP4 supported in Media Source -// Extensions. -// // A cross-platform decoder module that discards input and produces "blank" // output samples exists for testing, and is created when the pref // "media.fragmented-mp4.use-blank-decoder" is true. + class PlatformDecoderModule { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformDecoderModule) @@ -59,8 +55,7 @@ public: // Factory method that creates the appropriate PlatformDecoderModule for // the platform we're running on. Caller is responsible for deleting this // instance. It's expected that there will be multiple - // PlatformDecoderModules alive at the same time. There is one - // PlatformDecoderModule created per MP4Reader. + // PlatformDecoderModules alive at the same time. // This is called on the decode task queue. static already_AddRefed Create(); @@ -90,10 +85,7 @@ public: MOZ_CRASH(); } - // An audio decoder module must support AAC by default. - // A video decoder must support H264 by default. - // If more codecs are to be supported, SupportsMimeType will have - // to be extended + // Indicates if the PlatformDecoderModule supports decoding of aMimeType. virtual bool SupportsMimeType(const nsACString& aMimeType); enum ConversionRequired { @@ -149,7 +141,8 @@ protected: }; // A callback used by MediaDataDecoder to return output/errors to the -// MP4Reader. Implementation is threadsafe, and can be called on any thread. +// MediaFormatReader. +// Implementation is threadsafe, and can be called on any thread. class MediaDataDecoderCallback { public: virtual ~MediaDataDecoderCallback() {} @@ -179,7 +172,7 @@ public: // // Unless otherwise noted, all functions are only called on the decode task // queue. An exception is the MediaDataDecoder in -// MP4Reader::IsVideoAccelerated() for which all calls (Init(), +// MediaFormatReader::IsVideoAccelerated() for which all calls (Init(), // IsHardwareAccelerated(), and Shutdown()) are from the main thread. // // Don't block inside these functions, unless it's explicitly noted that you @@ -207,7 +200,7 @@ public: // Initialize the decoder. The decoder should be ready to decode once // promise resolves. The decoder should do any initialization here, rather // than in its constructor or PlatformDecoderModule::Create*Decoder(), - // so that if the MP4Reader needs to shutdown during initialization, + // so that if the MediaFormatReader needs to shutdown during initialization, // it can call Shutdown() to cancel this operation. Any initialization // that requires blocking the calling thread in this function *must* // be done here so that it can be canceled by calling Shutdown()! @@ -222,7 +215,7 @@ public: // decoding resumes after the seek. // While the reader calls Flush(), it ignores all output sent to it; // it is safe (but pointless) to send output while Flush is called. - // The MP4Reader will not call Input() while it's calling Flush(). + // The MediaFormatReader will not call Input() while it's calling Flush(). virtual nsresult Flush() = 0; // Causes all complete samples in the pipeline that can be decoded to be @@ -230,7 +223,7 @@ public: // it drops the input samples. The decoder may be holding onto samples // that are required to decode samples that it expects to get in future. // This is called when the demuxer reaches end of stream. - // The MP4Reader will not call Input() while it's calling Drain(). + // The MediaFormatReader will not call Input() while it's calling Drain(). // This function is asynchronous. The MediaDataDecoder must call // MediaDataDecoderCallback::DrainComplete() once all remaining // samples have been output. From c463ef6fd5c2b924a3f66ba1403e5ec3b2a7d6ed Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 10:23:26 +1100 Subject: [PATCH 022/189] Bug 1206977: P6. Make PlatformDecoderModule::SupportsMimeType pure virtual. r=cpearce --- dom/media/platforms/PlatformDecoderModule.cpp | 8 -------- dom/media/platforms/PlatformDecoderModule.h | 2 +- dom/media/platforms/agnostic/eme/EMEDecoderModule.h | 9 +++++++++ dom/media/platforms/agnostic/gmp/GMPDecoderModule.h | 8 ++++++++ dom/media/platforms/apple/AppleDecoderModule.cpp | 4 +++- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/dom/media/platforms/PlatformDecoderModule.cpp b/dom/media/platforms/PlatformDecoderModule.cpp index fdb495744f8b..e47e30e4bac2 100644 --- a/dom/media/platforms/PlatformDecoderModule.cpp +++ b/dom/media/platforms/PlatformDecoderModule.cpp @@ -64,12 +64,4 @@ PlatformDecoderModule::Create() return m.forget(); } -bool -PlatformDecoderModule::SupportsMimeType(const nsACString& aMimeType) -{ - return aMimeType.EqualsLiteral("audio/mp4a-latm") || - aMimeType.EqualsLiteral("video/mp4") || - aMimeType.EqualsLiteral("video/avc"); -} - } // namespace mozilla diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index 9c041e7a1171..18b80827bcd5 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -86,7 +86,7 @@ public: } // Indicates if the PlatformDecoderModule supports decoding of aMimeType. - virtual bool SupportsMimeType(const nsACString& aMimeType); + virtual bool SupportsMimeType(const nsACString& aMimeType) = 0; enum ConversionRequired { kNeedNone, diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h index 23740ecfeb1c..dd8c864fad5e 100644 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h +++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h @@ -42,6 +42,15 @@ public: ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override; + bool + SupportsMimeType(const nsACString& aMimeType) override + { + // TODO Properly. + return aMimeType.EqualsLiteral("audio/mp4a-latm") || + aMimeType.EqualsLiteral("video/mp4") || + aMimeType.EqualsLiteral("video/avc"); + } + private: nsRefPtr mProxy; // Will be null if CDM has decoding capability. diff --git a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h index 990f8b804fcf..1a60997c96cc 100644 --- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h +++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h @@ -33,6 +33,14 @@ public: ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override; + + bool + SupportsMimeType(const nsACString& aMimeType) override + { + // TODO properly. + return aMimeType.EqualsLiteral("audio/mp4a-latm") || + aMimeType.EqualsLiteral("video/avc"); + } }; } // namespace mozilla diff --git a/dom/media/platforms/apple/AppleDecoderModule.cpp b/dom/media/platforms/apple/AppleDecoderModule.cpp index c9b82613e08d..8e0b1d482c48 100644 --- a/dom/media/platforms/apple/AppleDecoderModule.cpp +++ b/dom/media/platforms/apple/AppleDecoderModule.cpp @@ -110,7 +110,9 @@ bool AppleDecoderModule::SupportsMimeType(const nsACString& aMimeType) { return aMimeType.EqualsLiteral("audio/mpeg") || - PlatformDecoderModule::SupportsMimeType(aMimeType); + aMimeType.EqualsLiteral("audio/mp4a-latm") || + aMimeType.EqualsLiteral("video/mp4") || + aMimeType.EqualsLiteral("video/avc"); } PlatformDecoderModule::ConversionRequired From 61bf9de8cf26b2d3aa17edae5805dd2be5b020ec Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 15:32:18 +1100 Subject: [PATCH 023/189] Bug 1206977: [webm] P7. Remove IntelWebMVideoDecoder. r=kinetik That code path is no longer used and handled directly in the MediaFormatReader. Also, partially revert commit ac6d0b0befb2 as it broke WebMReader. --- dom/media/webm/AudioDecoder.cpp | 12 +- dom/media/webm/IntelWebMVideoDecoder.cpp | 443 -------------------- dom/media/webm/IntelWebMVideoDecoder.h | 97 ----- dom/media/webm/SoftwareWebMVideoDecoder.cpp | 10 +- dom/media/webm/SoftwareWebMVideoDecoder.h | 4 +- dom/media/webm/WebMReader.cpp | 51 +-- dom/media/webm/WebMReader.h | 13 +- dom/media/webm/moz.build | 5 - 8 files changed, 16 insertions(+), 619 deletions(-) delete mode 100644 dom/media/webm/IntelWebMVideoDecoder.cpp delete mode 100644 dom/media/webm/IntelWebMVideoDecoder.h diff --git a/dom/media/webm/AudioDecoder.cpp b/dom/media/webm/AudioDecoder.cpp index 288aeadd752a..f23de9bad704 100644 --- a/dom/media/webm/AudioDecoder.cpp +++ b/dom/media/webm/AudioDecoder.cpp @@ -47,7 +47,7 @@ ogg_packet InitOggPacket(const unsigned char* aData, size_t aLength, class VorbisDecoder : public WebMAudioDecoder { public: - nsRefPtr Init() override; + nsresult Init() override; void Shutdown() override; nsresult ResetDecode() override; nsresult DecodeHeader(const unsigned char* aData, size_t aLength) override; @@ -94,14 +94,14 @@ VorbisDecoder::Shutdown() mReader = nullptr; } -nsRefPtr +nsresult VorbisDecoder::Init() { vorbis_info_init(&mVorbisInfo); vorbis_comment_init(&mVorbisComment); PodZero(&mVorbisDsp); PodZero(&mVorbisBlock); - return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__); + return NS_OK; } nsresult @@ -229,7 +229,7 @@ VorbisDecoder::Decode(const unsigned char* aData, size_t aLength, class OpusDecoder : public WebMAudioDecoder { public: - nsRefPtr Init() override; + nsresult Init() override; void Shutdown() override; nsresult ResetDecode() override; nsresult DecodeHeader(const unsigned char* aData, size_t aLength) override; @@ -277,10 +277,10 @@ OpusDecoder::Shutdown() mReader = nullptr; } -nsRefPtr +nsresult OpusDecoder::Init() { - return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__); + return NS_OK; } nsresult diff --git a/dom/media/webm/IntelWebMVideoDecoder.cpp b/dom/media/webm/IntelWebMVideoDecoder.cpp deleted file mode 100644 index e0bf886219a1..000000000000 --- a/dom/media/webm/IntelWebMVideoDecoder.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ -#include "IntelWebMVideoDecoder.h" - -#include "mozilla/TaskQueue.h" - -#include "gfx2DGlue.h" -#include "Layers.h" -#include "MediaResource.h" -#include "mozilla/dom/HTMLMediaElement.h" -#include "nsError.h" -#include "mozilla/SharedThreadPool.h" -#include "VorbisUtils.h" -#include "nestegg/nestegg.h" - -#define VPX_DONT_DEFINE_STDINT_TYPES -#include "vpx/vp8dx.h" -#include "vpx/vpx_decoder.h" - -#undef LOG -extern PRLogModuleInfo* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) - -namespace mozilla { - -using layers::Image; -using layers::LayerManager; -using layers::LayersBackend; - -class VP8Sample : public MediaRawData -{ -public: - VP8Sample(int64_t aTimestamp, - int64_t aDuration, - int64_t aByteOffset, - uint8_t* aData, - size_t aSize, - bool aSyncPoint) - : MediaRawData(aData, aSize) - { - mTimecode = -1; - mTime = aTimestamp; - mDuration = aDuration; - mOffset = aByteOffset; - mKeyframe = aSyncPoint; - } -}; - -IntelWebMVideoDecoder::IntelWebMVideoDecoder(WebMReader* aReader) - : WebMVideoDecoder() - , mReader(aReader) - , mMonitor("IntelWebMVideoDecoder") - , mNumSamplesInput(0) - , mNumSamplesOutput(0) - , mDecodeAhead(2) - , mInputExhausted(false) - , mDrainComplete(false) - , mError(false) - , mEOS(false) - , mIsFlushing(false) -{ - MOZ_COUNT_CTOR(IntelWebMVideoDecoder); -} - -IntelWebMVideoDecoder::~IntelWebMVideoDecoder() -{ - MOZ_COUNT_DTOR(IntelWebMVideoDecoder); - Shutdown(); -} - -void -IntelWebMVideoDecoder::Shutdown() -{ - if (mMediaDataDecoder) { - Flush(); - mMediaDataDecoder->Shutdown(); - mMediaDataDecoder = nullptr; - } - - mTaskQueue = nullptr; - - mQueuedVideoSample = nullptr; - mReader = nullptr; -} - -/* static */ -WebMVideoDecoder* -IntelWebMVideoDecoder::Create(WebMReader* aReader) -{ - nsAutoPtr decoder(new IntelWebMVideoDecoder(aReader)); - - decoder->mTaskQueue = aReader->GetVideoTaskQueue(); - NS_ENSURE_TRUE(decoder->mTaskQueue, nullptr); - - return decoder.forget(); -} - -bool -IntelWebMVideoDecoder::IsSupportedVideoMimeType(const nsACString& aMimeType) -{ - return (aMimeType.EqualsLiteral("video/webm; codecs=vp8") || - aMimeType.EqualsLiteral("video/webm; codecs=vp9")) && - mPlatform->SupportsMimeType(aMimeType); -} - -nsRefPtr -IntelWebMVideoDecoder::Init(unsigned int aWidth, unsigned int aHeight) -{ - mPlatform = PlatformDecoderModule::Create(); - if (!mPlatform) { - return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); - } - - mDecoderConfig = new VideoInfo(); - mDecoderConfig->mDuration = 0; - mDecoderConfig->mDisplay.width = aWidth; - mDecoderConfig->mDisplay.height = aHeight; - - switch (mReader->GetVideoCodec()) { - case NESTEGG_CODEC_VP8: - mDecoderConfig->mMimeType = "video/webm; codecs=vp8"; - break; - case NESTEGG_CODEC_VP9: - mDecoderConfig->mMimeType = "video/webm; codecs=vp9"; - break; - default: - return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); - } - - const VideoInfo& video = *mDecoderConfig; - if (!IsSupportedVideoMimeType(video.mMimeType)) { - return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); - } - mMediaDataDecoder = - mPlatform->CreateDecoder(video, - mTaskQueue, - this, - mReader->GetLayersBackendType(), - mReader->GetDecoder()->GetImageContainer()); - if (!mMediaDataDecoder) { - return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); - } - - return mMediaDataDecoder->Init(); -} - -bool -IntelWebMVideoDecoder::Demux(nsRefPtr& aSample, bool* aEOS) -{ - nsRefPtr holder(mReader->NextPacket(WebMReader::VIDEO)); - if (!holder) { - return false; - } - - nestegg_packet* packet = holder->Packet(); - unsigned int track = 0; - int r = nestegg_packet_track(packet, &track); - if (r == -1) { - return false; - } - - unsigned int count = 0; - r = nestegg_packet_count(packet, &count); - if (r == -1) { - return false; - } - - if (count > 1) { - NS_WARNING("Packet contains more than one video frame"); - return false; - } - - int64_t tstamp = holder->Timestamp(); - - // The end time of this frame is the start time of the next frame. Fetch - // the timestamp of the next packet for this track. If we've reached the - // end of the resource, use the file's duration as the end time of this - // video frame. - int64_t next_tstamp = 0; - nsRefPtr next_holder(mReader->NextPacket(WebMReader::VIDEO)); - if (next_holder) { - next_tstamp = holder->Timestamp(); - mReader->PushVideoPacket(next_holder); - } else { - next_tstamp = tstamp; - next_tstamp += tstamp - mReader->GetLastVideoFrameTime(); - } - mReader->SetLastVideoFrameTime(tstamp); - - unsigned char* data; - size_t length; - r = nestegg_packet_data(packet, 0, &data, &length); - if (r == -1) { - return false; - } - - vpx_codec_stream_info_t si; - PodZero(&si); - si.sz = sizeof(si); - if (mReader->GetVideoCodec() == NESTEGG_CODEC_VP8) { - vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), data, length, &si); - } else if (mReader->GetVideoCodec() == NESTEGG_CODEC_VP9) { - vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), data, length, &si); - } - - MOZ_ASSERT(mPlatform && mMediaDataDecoder); - - aSample = new VP8Sample(tstamp, - next_tstamp - tstamp, - 0, - data, - length, - si.is_kf); - if (!aSample->Data()) { - return false; - } - - return true; -} - -bool -IntelWebMVideoDecoder::Decode() -{ - MOZ_ASSERT(mMediaDataDecoder); - - mMonitor.Lock(); - uint64_t prevNumFramesOutput = mNumSamplesOutput; - while (prevNumFramesOutput == mNumSamplesOutput) { - mMonitor.AssertCurrentThreadOwns(); - if (mError) { - // Decode error! - mMonitor.Unlock(); - return false; - } - while (prevNumFramesOutput == mNumSamplesOutput && - (mInputExhausted || - (mNumSamplesInput - mNumSamplesOutput) < mDecodeAhead) && - !mEOS) { - mMonitor.AssertCurrentThreadOwns(); - mMonitor.Unlock(); - nsRefPtr compressed(PopSample()); - if (!compressed) { - // EOS, or error. Let the state machine know there are no more - // frames coming. - LOG("Draining Video"); - mMonitor.Lock(); - MOZ_ASSERT(!mEOS); - mEOS = true; - MOZ_ASSERT(!mDrainComplete); - mDrainComplete = false; - mMonitor.Unlock(); - mMediaDataDecoder->Drain(); - } else { -#ifdef LOG_SAMPLE_DECODE - LOG("PopSample %s time=%lld dur=%lld", TrackTypeToStr(aTrack), - compressed->mTime, compressed->mDuration); -#endif - mMonitor.Lock(); - mDrainComplete = false; - mInputExhausted = false; - mNumSamplesInput++; - mMonitor.Unlock(); - if (NS_FAILED(mMediaDataDecoder->Input(compressed))) { - return false; - } - } - mMonitor.Lock(); - } - mMonitor.AssertCurrentThreadOwns(); - while (!mError && - prevNumFramesOutput == mNumSamplesOutput && - (!mInputExhausted || mEOS) && - !mDrainComplete) { - mMonitor.Wait(); - } - if (mError || - (mEOS && mDrainComplete)) { - break; - } - - } - mMonitor.AssertCurrentThreadOwns(); - bool rv = !(mEOS || mError); - mMonitor.Unlock(); - return rv; -} - -bool -IntelWebMVideoDecoder::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& aParsed) -{ - MOZ_ASSERT(mReader->GetDecoder()); - - Flush(); - - // Loop until we reach the next keyframe after the threshold. - while (true) { - nsRefPtr compressed(PopSample()); - if (!compressed) { - // EOS, or error. Let the state machine know. - return false; - } - aParsed++; - if (!compressed->mKeyframe || - compressed->mTime < aTimeThreshold) { - continue; - } - mQueuedVideoSample = compressed; - break; - } - - return true; -} - -bool -IntelWebMVideoDecoder::DecodeVideoFrame(bool& aKeyframeSkip, - int64_t aTimeThreshold) -{ - AbstractMediaDecoder::AutoNotifyDecoded a(mReader->GetDecoder()); - - MOZ_ASSERT(mPlatform && mReader->GetDecoder()); - - if (aKeyframeSkip) { - bool ok = SkipVideoDemuxToNextKeyFrame(aTimeThreshold, a.mDropped); - if (!ok) { - NS_WARNING("Failed to skip demux up to next keyframe"); - return false; - } - a.mParsed = a.mDropped; - aKeyframeSkip = false; - nsresult rv = mMediaDataDecoder->Flush(); - NS_ENSURE_SUCCESS(rv, false); - } - - MOZ_ASSERT(mReader->OnTaskQueue()); - bool rv = Decode(); - { - // Report the number of "decoded" frames as the difference in the - // mNumSamplesOutput field since the last time we were called. - MonitorAutoLock mon(mMonitor); - uint64_t delta = mNumSamplesOutput - mLastReportedNumDecodedFrames; - a.mDecoded = static_cast(delta); - mLastReportedNumDecodedFrames = mNumSamplesOutput; - } - return rv; -} - -already_AddRefed -IntelWebMVideoDecoder::PopSample() -{ - if (mQueuedVideoSample) { - return mQueuedVideoSample.forget(); - } - nsRefPtr sample; - while (mSampleQueue.empty()) { - bool eos = false; - bool ok = Demux(sample, &eos); - if (!ok || eos) { - MOZ_ASSERT(!sample); - return nullptr; - } - MOZ_ASSERT(sample); - mSampleQueue.push_back(sample.forget()); - } - - MOZ_ASSERT(!mSampleQueue.empty()); - sample = mSampleQueue.front().forget(); - mSampleQueue.pop_front(); - return sample.forget(); -} - -void -IntelWebMVideoDecoder::Output(MediaData* aSample) -{ -#ifdef LOG_SAMPLE_DECODE - LOG("Decoded video sample time=%lld dur=%lld", - aSample->mTime, aSample->mDuration); -#endif - - // Don't accept output while we're flushing. - MonitorAutoLock mon(mMonitor); - if (mIsFlushing) { - mon.NotifyAll(); - return; - } - - MOZ_ASSERT(aSample->mType == MediaData::VIDEO_DATA); - mReader->VideoQueue().Push(static_cast(aSample)); - - mNumSamplesOutput++; - mon.NotifyAll(); -} - -void -IntelWebMVideoDecoder::DrainComplete() -{ - MonitorAutoLock mon(mMonitor); - mDrainComplete = true; - mon.NotifyAll(); -} - -void -IntelWebMVideoDecoder::InputExhausted() -{ - MonitorAutoLock mon(mMonitor); - mInputExhausted = true; - mon.NotifyAll(); -} - -void -IntelWebMVideoDecoder::Error() -{ - MonitorAutoLock mon(mMonitor); - mError = true; - mon.NotifyAll(); -} - -nsresult -IntelWebMVideoDecoder::Flush() -{ - if (!mReader->GetDecoder()) { - return NS_ERROR_FAILURE; - } - // Purge the current decoder's state. - // Set a flag so that we ignore all output while we call - // MediaDataDecoder::Flush(). - { - MonitorAutoLock mon(mMonitor); - mIsFlushing = true; - mDrainComplete = false; - mEOS = false; - } - mMediaDataDecoder->Flush(); - { - MonitorAutoLock mon(mMonitor); - mIsFlushing = false; - } - return NS_OK; -} - -} // namespace mozilla diff --git a/dom/media/webm/IntelWebMVideoDecoder.h b/dom/media/webm/IntelWebMVideoDecoder.h deleted file mode 100644 index 4d8343c10dcf..000000000000 --- a/dom/media/webm/IntelWebMVideoDecoder.h +++ /dev/null @@ -1,97 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ -#if !defined(IntelWebMVideoDecoder_h_) -#define IntelWebMVideoDecoder_h_ - -#include - -#include "WebMReader.h" -#include "nsAutoPtr.h" -#include "PlatformDecoderModule.h" -#include "mozilla/Monitor.h" - -#include "MediaInfo.h" -#include "MediaData.h" - -class TaskQueue; - -namespace mozilla { - -class VP8Sample; - -typedef std::deque> VP8SampleQueue; - -class IntelWebMVideoDecoder : public WebMVideoDecoder, public MediaDataDecoderCallback -{ -public: - static WebMVideoDecoder* Create(WebMReader* aReader); - virtual nsRefPtr Init(unsigned int aWidth = 0, - unsigned int aHeight = 0) override; - virtual nsresult Flush() override; - virtual void Shutdown() override; - - virtual bool DecodeVideoFrame(bool &aKeyframeSkip, - int64_t aTimeThreshold) override; - - virtual void Output(MediaData* aSample) override; - - virtual void DrainComplete() override; - - virtual void InputExhausted() override; - virtual void Error() override; - - virtual bool OnReaderTaskQueue() override - { - return mReader->OnTaskQueue(); - } - - IntelWebMVideoDecoder(WebMReader* aReader); - ~IntelWebMVideoDecoder(); - -private: - void InitLayersBackendType(); - - bool Decode(); - - bool Demux(nsRefPtr& aSample, bool* aEOS); - - bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed); - - bool IsSupportedVideoMimeType(const nsACString& aMimeType); - - already_AddRefed PopSample(); - - nsRefPtr mReader; - nsRefPtr mPlatform; - nsRefPtr mMediaDataDecoder; - - // TaskQueue on which decoder can choose to decode. - // Only non-null up until the decoder is created. - nsRefPtr mTaskQueue; - - // Monitor that protects all non-threadsafe state; the primitives - // that follow. - Monitor mMonitor; - nsAutoPtr mDecoderConfig; - - VP8SampleQueue mSampleQueue; - nsRefPtr mQueuedVideoSample; - uint64_t mNumSamplesInput; - uint64_t mNumSamplesOutput; - uint64_t mLastReportedNumDecodedFrames; - uint32_t mDecodeAhead; - - // Whether this stream exists in the media. - bool mInputExhausted; - bool mDrainComplete; - bool mError; - bool mEOS; - bool mIsFlushing; -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/webm/SoftwareWebMVideoDecoder.cpp b/dom/media/webm/SoftwareWebMVideoDecoder.cpp index 3e46e4ec6cc4..f7f6453b5b52 100644 --- a/dom/media/webm/SoftwareWebMVideoDecoder.cpp +++ b/dom/media/webm/SoftwareWebMVideoDecoder.cpp @@ -53,16 +53,10 @@ SoftwareWebMVideoDecoder::Create(WebMReader* aReader) return new SoftwareWebMVideoDecoder(aReader); } -nsRefPtr +nsresult SoftwareWebMVideoDecoder::Init(unsigned int aWidth, unsigned int aHeight) { - nsresult rv = InitDecoder(aWidth, aHeight); - - if (NS_SUCCEEDED(rv)) { - return InitPromise::CreateAndResolve(TrackType::kVideoTrack, __func__); - } - - return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); + return InitDecoder(aWidth, aHeight); } nsresult diff --git a/dom/media/webm/SoftwareWebMVideoDecoder.h b/dom/media/webm/SoftwareWebMVideoDecoder.h index defa631638c0..2d3950691ab4 100644 --- a/dom/media/webm/SoftwareWebMVideoDecoder.h +++ b/dom/media/webm/SoftwareWebMVideoDecoder.h @@ -17,8 +17,8 @@ class SoftwareWebMVideoDecoder : public WebMVideoDecoder public: static WebMVideoDecoder* Create(WebMReader* aReader); - virtual nsRefPtr Init(unsigned int aWidth = 0, - unsigned int aHeight = 0) override; + virtual nsresult Init(unsigned int aWidth = 0, + unsigned int aHeight = 0) override; virtual bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) override; diff --git a/dom/media/webm/WebMReader.cpp b/dom/media/webm/WebMReader.cpp index 9fe76f1ee58a..a0e42b85d937 100644 --- a/dom/media/webm/WebMReader.cpp +++ b/dom/media/webm/WebMReader.cpp @@ -20,11 +20,6 @@ #include "vpx/vp8dx.h" #include "vpx/vpx_decoder.h" -// IntelWebMVideoDecoder uses the WMF backend, which is Windows Vista+ only. -#if defined(MOZ_PDM_VPX) -#include "IntelWebMVideoDecoder.h" -#endif - // Un-comment to enable logging of seek bisections. //#define SEEK_LOGGING @@ -125,10 +120,6 @@ static void webm_log(nestegg * context, va_end(args); } -#if defined(MOZ_PDM_VPX) -static bool sIsIntelDecoderEnabled = false; -#endif - WebMReader::WebMReader(AbstractMediaDecoder* aDecoder, TaskQueue* aBorrowedTaskQueue) : MediaDecoderReader(aDecoder, aBorrowedTaskQueue) , mContext(nullptr) @@ -149,10 +140,6 @@ WebMReader::WebMReader(AbstractMediaDecoder* aDecoder, TaskQueue* aBorrowedTaskQ if (!gNesteggLog) { gNesteggLog = PR_NewLogModule("Nestegg"); } - -#if defined(MOZ_PDM_VPX) - sIsIntelDecoderEnabled = Preferences::GetBool("media.webm.intel_decoder.enabled", false); -#endif } WebMReader::~WebMReader() @@ -168,12 +155,6 @@ WebMReader::~WebMReader() nsRefPtr WebMReader::Shutdown() { -#if defined(MOZ_PDM_VPX) - if (mVideoTaskQueue) { - mVideoTaskQueue->BeginShutdown(); - mVideoTaskQueue->AwaitShutdownAndIdle(); - } -#endif if (mAudioDecoder) { mAudioDecoder->Shutdown(); mAudioDecoder = nullptr; @@ -189,18 +170,6 @@ WebMReader::Shutdown() nsresult WebMReader::Init(MediaDecoderReader* aCloneDonor) { -#if defined(MOZ_PDM_VPX) - if (sIsIntelDecoderEnabled) { - PlatformDecoderModule::Init(); - - InitLayersBackendType(); - - mVideoTaskQueue = new FlushableTaskQueue( - SharedThreadPool::Get(NS_LITERAL_CSTRING("IntelVP8 Video Decode"))); - NS_ENSURE_TRUE(mVideoTaskQueue, NS_ERROR_FAILURE); - } -#endif - if (aCloneDonor) { mBufferedState = static_cast(aCloneDonor)->mBufferedState; } else { @@ -327,23 +296,13 @@ WebMReader::RetrieveWebMMetadata(MediaInfo* aInfo) mVideoCodec = nestegg_track_codec_id(mContext, track); -#if defined(MOZ_PDM_VPX) - if (sIsIntelDecoderEnabled) { - mVideoDecoder = IntelWebMVideoDecoder::Create(this); - } -#endif - - // If there's no decoder yet (e.g. HW decoder not available), use the software decoder. if (!mVideoDecoder) { mVideoDecoder = SoftwareWebMVideoDecoder::Create(this); } - if (mVideoDecoder) { - mInitPromises.AppendElement(mVideoDecoder->Init(params.display_width, - params.display_height)); - } - - if (!mVideoDecoder) { + if (!mVideoDecoder || + NS_FAILED(mVideoDecoder->Init(params.display_width, + params.display_height))) { Cleanup(); return NS_ERROR_FAILURE; } @@ -424,9 +383,7 @@ WebMReader::RetrieveWebMMetadata(MediaInfo* aInfo) return NS_ERROR_FAILURE; } - if (mAudioDecoder) { - mInitPromises.AppendElement(mAudioDecoder->Init()); - } else { + if (!mAudioDecoder || NS_FAILED(mAudioDecoder->Init())) { Cleanup(); return NS_ERROR_FAILURE; } diff --git a/dom/media/webm/WebMReader.h b/dom/media/webm/WebMReader.h index 6df8b4d67efb..8060654aaca2 100644 --- a/dom/media/webm/WebMReader.h +++ b/dom/media/webm/WebMReader.h @@ -11,7 +11,6 @@ #include "FlushableTaskQueue.h" #include "MediaDecoderReader.h" #include "MediaResource.h" -#include "PlatformDecoderModule.h" #include "nsAutoRef.h" #include "nestegg/nestegg.h" @@ -26,9 +25,7 @@ namespace mozilla { static const unsigned NS_PER_USEC = 1000; static const double NS_PER_S = 1e9; -typedef MediaDataDecoder::InitPromise InitPromise; typedef TrackInfo::TrackType TrackType; -typedef MediaDataDecoder::DecoderFailureReason DecoderFailureReason; class WebMBufferedState; class WebMPacketQueue; @@ -39,7 +36,7 @@ class WebMReader; class WebMVideoDecoder { public: - virtual nsRefPtr Init(unsigned int aWidth = 0, unsigned int aHeight = 0) = 0; + virtual nsresult Init(unsigned int aWidth = 0, unsigned int aHeight = 0) = 0; virtual nsresult Flush() { return NS_OK; } virtual void Shutdown() = 0; virtual bool DecodeVideoFrame(bool &aKeyframeSkip, @@ -52,7 +49,7 @@ public: class WebMAudioDecoder { public: - virtual nsRefPtr Init() = 0; + virtual nsresult Init() = 0; virtual void Shutdown() = 0; virtual nsresult ResetDecode() = 0; virtual nsresult DecodeHeader(const unsigned char* aData, size_t aLength) = 0; @@ -122,7 +119,6 @@ public: int64_t GetLastVideoFrameTime(); void SetLastVideoFrameTime(int64_t aFrameTime); layers::LayersBackend GetLayersBackendType() { return mLayersBackendType; } - FlushableTaskQueue* GetVideoTaskQueue() { return mVideoTaskQueue; } uint64_t GetCodecDelay() { return mCodecDelay; } protected: @@ -167,8 +163,6 @@ private: nsAutoPtr mAudioDecoder; nsAutoPtr mVideoDecoder; - nsTArray> mInitPromises; - // Queue of video and audio packets that have been read but not decoded. These // must only be accessed from the decode thread. WebMPacketQueue mVideoPackets; @@ -212,9 +206,6 @@ private: layers::LayersBackend mLayersBackendType; - // For hardware video decoding. - nsRefPtr mVideoTaskQueue; - // Booleans to indicate if we have audio and/or video data bool mHasVideo; bool mHasAudio; diff --git a/dom/media/webm/moz.build b/dom/media/webm/moz.build index cab25d63ee3a..8dd3e99bf24d 100644 --- a/dom/media/webm/moz.build +++ b/dom/media/webm/moz.build @@ -5,7 +5,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS += [ - 'IntelWebMVideoDecoder.h', 'NesteggPacketHolder.h', 'SoftwareWebMVideoDecoder.h', 'WebMBufferedParser.h', @@ -23,10 +22,6 @@ UNIFIED_SOURCES += [ 'WebMReader.cpp', ] -if CONFIG['MOZ_FMP4'] and CONFIG['MOZ_WMF']: - DEFINES['MOZ_PDM_VPX'] = True - UNIFIED_SOURCES += ['IntelWebMVideoDecoder.cpp'] - if CONFIG['MOZ_WEBM_ENCODER']: EXPORTS += ['WebMWriter.h'] UNIFIED_SOURCES += ['EbmlComposer.cpp', From 5d54dafcb32691bbd19888a31b73d0c222c6095f Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 19:56:29 +1100 Subject: [PATCH 024/189] Bug 1206977: P8. Have PDMFactory directly manage the EMEDecoderModule. r=cpearce --- dom/media/MediaFormatReader.cpp | 18 +++------- dom/media/MediaFormatReader.h | 4 +-- dom/media/platforms/PDMFactory.cpp | 33 +++++++++++++++++-- dom/media/platforms/PDMFactory.h | 12 +++++++ dom/media/platforms/PlatformDecoderModule.cpp | 30 ----------------- dom/media/platforms/PlatformDecoderModule.h | 10 ------ .../agnostic/eme/EMEDecoderModule.cpp | 2 +- .../platforms/agnostic/eme/EMEDecoderModule.h | 7 ++-- dom/media/platforms/moz.build | 1 + 9 files changed, 54 insertions(+), 63 deletions(-) diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index f33848c5882e..fbe35320595b 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -170,7 +170,7 @@ nsresult MediaFormatReader::Init(MediaDecoderReader* aCloneDonor) { MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - PlatformDecoderModule::Init(); + PDMFactory::Init(); InitLayersBackendType(); @@ -380,29 +380,19 @@ MediaFormatReader::EnsureDecodersCreated() MOZ_ASSERT(OnTaskQueue()); if (!mPlatform) { + mPlatform = new PDMFactory(); + NS_ENSURE_TRUE(mPlatform, false); if (IsEncrypted()) { #ifdef MOZ_EME - // We have encrypted audio or video. We'll need a CDM to decrypt and - // possibly decode this. Wait until we've received a CDM from the - // JavaScript player app. Note: we still go through the motions here - // even if EME is disabled, so that if script tries and fails to create - // a CDM, we can detect that and notify chrome and show some UI - // explaining that we failed due to EME being disabled. MOZ_ASSERT(mCDMProxy); - mPlatform = PlatformDecoderModule::CreateCDMWrapper(mCDMProxy); - NS_ENSURE_TRUE(mPlatform, false); + mPlatform->SetCDMProxy(mCDMProxy); #else // EME not supported. return false; #endif - } else { - mPlatform = PlatformDecoderModule::Create(); - NS_ENSURE_TRUE(mPlatform, false); } } - MOZ_ASSERT(mPlatform); - if (HasAudio() && !mAudio.mDecoder) { NS_ENSURE_TRUE(IsSupportedAudioMimeType(mInfo.mAudio.mMimeType), false); diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index fd301af5ae96..90015bbcbf4f 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -13,7 +13,7 @@ #include "MediaDataDemuxer.h" #include "MediaDecoderReader.h" -#include "PlatformDecoderModule.h" +#include "PDMFactory.h" namespace mozilla { @@ -154,7 +154,7 @@ private: size_t SizeOfQueue(TrackType aTrack); - nsRefPtr mPlatform; + nsRefPtr mPlatform; class DecoderCallback : public MediaDataDecoderCallback { public: diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index 54006762716a..450f8f521222 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -34,6 +34,11 @@ #include "AgnosticDecoderModule.h" +#ifdef MOZ_EME +#include "EMEDecoderModule.h" +#include "mozilla/CDMProxy.h" +#endif + namespace mozilla { extern already_AddRefed CreateAgnosticDecoderModule(); @@ -109,7 +114,9 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer) { - nsRefPtr current = GetDecoder(aConfig.mMimeType); + nsRefPtr current = (mEMEPDM && aConfig.mCrypto.mValid) + ? mEMEPDM : GetDecoder(aConfig.mMimeType); + if (!current) { return nullptr; } @@ -117,8 +124,8 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, if (aConfig.GetAsAudioInfo()) { m = current->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); + aTaskQueue, + aCallback); return m.forget(); } @@ -169,6 +176,9 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, bool PDMFactory::SupportsMimeType(const nsACString& aMimeType) { + if (mEMEPDM) { + return mEMEPDM->SupportsMimeType(aMimeType); + } nsRefPtr current = GetDecoder(aMimeType); return !!current; } @@ -245,4 +255,21 @@ PDMFactory::GetDecoder(const nsACString& aMimeType) return pdm.forget(); } +#ifdef MOZ_EME +void +PDMFactory::SetCDMProxy(CDMProxy* aProxy) +{ + bool cdmDecodesAudio; + bool cdmDecodesVideo; + { + CDMCaps::AutoLock caps(aProxy->Capabilites()); + cdmDecodesAudio = caps.CanDecryptAndDecodeAudio(); + cdmDecodesVideo = caps.CanDecryptAndDecodeVideo(); + } + + nsRefPtr m = new PDMFactory(); + mEMEPDM = new EMEDecoderModule(aProxy, m, cdmDecodesAudio, cdmDecodesVideo); +} +#endif + } // namespace mozilla diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h index 4f88f215ea4f..b6c8870dae8d 100644 --- a/dom/media/platforms/PDMFactory.h +++ b/dom/media/platforms/PDMFactory.h @@ -9,6 +9,8 @@ #include "PlatformDecoderModule.h" +class CDMProxy; + namespace mozilla { class PDMFactory : public PlatformDecoderModule { @@ -29,6 +31,15 @@ public: bool SupportsMimeType(const nsACString& aMimeType) override; +#ifdef MOZ_EME + // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or + // decrypt-and-decode EME encrypted content. If the CDM only decrypts and + // does not decode, we create a PDM and use that to create MediaDataDecoders + // that we use on on aTaskQueue to decode the decrypted stream. + // This is called on the decode task queue. + void SetCDMProxy(CDMProxy* aProxy); +#endif + ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override { @@ -77,6 +88,7 @@ private: static bool sDontDelayInputExhausted; nsTArray> mCurrentPDMs; + nsRefPtr mEMEPDM; }; } // namespace mozilla diff --git a/dom/media/platforms/PlatformDecoderModule.cpp b/dom/media/platforms/PlatformDecoderModule.cpp index e47e30e4bac2..9f10a9402886 100644 --- a/dom/media/platforms/PlatformDecoderModule.cpp +++ b/dom/media/platforms/PlatformDecoderModule.cpp @@ -6,10 +6,6 @@ #include "PlatformDecoderModule.h" #include "PDMFactory.h" -#ifdef MOZ_EME -#include "EMEDecoderModule.h" -#include "mozilla/CDMProxy.h" -#endif PRLogModuleInfo* GetPDMLog() { static PRLogModuleInfo* log = nullptr; @@ -29,32 +25,6 @@ PlatformDecoderModule::Init() PDMFactory::Init(); } -#ifdef MOZ_EME -/* static */ -already_AddRefed -PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy) -{ - bool cdmDecodesAudio; - bool cdmDecodesVideo; - { - CDMCaps::AutoLock caps(aProxy->Capabilites()); - cdmDecodesAudio = caps.CanDecryptAndDecodeAudio(); - cdmDecodesVideo = caps.CanDecryptAndDecodeVideo(); - } - - // We always create a default PDM in order to decode - // non-encrypted tracks. - nsRefPtr pdm = Create(); - if (!pdm) { - return nullptr; - } - - nsRefPtr emepdm( - new EMEDecoderModule(aProxy, pdm, cdmDecodesAudio, cdmDecodesVideo)); - return emepdm.forget(); -} -#endif - /* static */ already_AddRefed PlatformDecoderModule::Create() diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index 18b80827bcd5..20dfaa86f537 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -63,16 +63,6 @@ public: // This is called on the decode task queue. virtual nsresult Startup() { return NS_OK; }; -#ifdef MOZ_EME - // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or - // decrypt-and-decode EME encrypted content. If the CDM only decrypts and - // does not decode, we create a PDM and use that to create MediaDataDecoders - // that we use on on aTaskQueue to decode the decrypted stream. - // This is called on the decode task queue. - static already_AddRefed - CreateCDMWrapper(CDMProxy* aProxy); -#endif - // Creates a decoder. // See CreateVideoDecoder and CreateAudioDecoder for implementation details. virtual already_AddRefed diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp index a2fd57796f0b..46bccab7e483 100644 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp +++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp @@ -191,7 +191,7 @@ EMEMediaDataDecoderProxy::Shutdown() } EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy, - PlatformDecoderModule* aPDM, + PDMFactory* aPDM, bool aCDMDecodesAudio, bool aCDMDecodesVideo) : mProxy(aProxy) diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h index dd8c864fad5e..42e01f0c564a 100644 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h +++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h @@ -8,6 +8,7 @@ #define EMEDecoderModule_h_ #include "PlatformDecoderModule.h" +#include "PDMFactory.h" #include "gmp-decryption.h" namespace mozilla { @@ -19,12 +20,13 @@ private: public: EMEDecoderModule(CDMProxy* aProxy, - PlatformDecoderModule* aPDM, + PDMFactory* aPDM, bool aCDMDecodesAudio, bool aCDMDecodesVideo); virtual ~EMEDecoderModule(); +protected: // Decode thread. already_AddRefed CreateVideoDecoder(const VideoInfo& aConfig, @@ -54,12 +56,11 @@ public: private: nsRefPtr mProxy; // Will be null if CDM has decoding capability. - nsRefPtr mPDM; + nsRefPtr mPDM; // We run the PDM on its own task queue. nsRefPtr mTaskQueue; bool mCDMDecodesAudio; bool mCDMDecodesVideo; - }; } // namespace mozilla diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index 8a217ce267c1..58f24494fd04 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -9,6 +9,7 @@ EXPORTS += [ 'agnostic/OpusDecoder.h', 'agnostic/VorbisDecoder.h', 'agnostic/VPXDecoder.h', + 'PDMFactory.h', 'PlatformDecoderModule.h', 'wrappers/FuzzingWrapper.h', 'wrappers/H264Converter.h' From 620a0262c90a0c48efbb395d9823037edf10af26 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 20:10:31 +1100 Subject: [PATCH 025/189] Bug 1206977: P9. Ensure PDMs are only ever created through the PDMFactory. r=cpearce --- dom/media/MP3Decoder.cpp | 8 ++-- dom/media/fmp4/MP4Decoder.cpp | 23 +++++----- dom/media/platforms/PDMFactory.h | 45 +++++-------------- dom/media/platforms/PlatformDecoderModule.cpp | 22 --------- dom/media/platforms/PlatformDecoderModule.h | 23 ---------- 5 files changed, 26 insertions(+), 95 deletions(-) diff --git a/dom/media/MP3Decoder.cpp b/dom/media/MP3Decoder.cpp index c6415a26ce27..b4ae9e0b78ed 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/MP3Decoder.cpp @@ -10,7 +10,7 @@ #include "MediaFormatReader.h" #include "MP3Demuxer.h" #include "mozilla/Preferences.h" -#include "PlatformDecoderModule.h" +#include "PDMFactory.h" namespace mozilla { @@ -32,10 +32,10 @@ MP3Decoder::CreateStateMachine() { static already_AddRefed CreateTestMP3Decoder(AudioInfo& aConfig) { - PlatformDecoderModule::Init(); + PDMFactory::Init(); - nsRefPtr platform = PlatformDecoderModule::Create(); - if (!platform || !platform->SupportsMimeType(aConfig.mMimeType)) { + nsRefPtr platform = new PDMFactory(); + if (!platform->SupportsMimeType(aConfig.mMimeType)) { return nullptr; } diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index bf15839327bf..517b75e7c6ae 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -31,6 +31,8 @@ #include "FFmpegRuntimeLinker.h" #endif +#include "PDMFactory.h" + namespace mozilla { #if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG) @@ -149,11 +151,8 @@ MP4Decoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, } // Verify that we have a PDM that supports the whitelisted types. - PlatformDecoderModule::Init(); - nsRefPtr platform = PlatformDecoderModule::Create(); - if (!platform) { - return false; - } + PDMFactory::Init(); + nsRefPtr platform = new PDMFactory(); for (const nsCString& codecMime : codecMimes) { if (!platform->SupportsMimeType(codecMime)) { return false; @@ -184,7 +183,7 @@ IsFFmpegAvailable() #ifndef MOZ_FFMPEG return false; #else - PlatformDecoderModule::Init(); + PDMFactory::Init(); nsRefPtr m = FFmpegRuntimeLinker::CreateDecoderModule(); return !!m; #endif @@ -274,10 +273,10 @@ CreateTestH264Decoder(layers::LayersBackend aBackend, aConfig.mExtraData->AppendElements(sTestH264ExtraData, MOZ_ARRAY_LENGTH(sTestH264ExtraData)); - PlatformDecoderModule::Init(); + PDMFactory::Init(); - nsRefPtr platform = PlatformDecoderModule::Create(); - if (!platform || !platform->SupportsMimeType(NS_LITERAL_CSTRING("video/mp4"))) { + nsRefPtr platform = new PDMFactory(); + if (!platform->SupportsMimeType(NS_LITERAL_CSTRING("video/mp4"))) { return nullptr; } @@ -330,10 +329,10 @@ MP4Decoder::CanCreateH264Decoder() static already_AddRefed CreateTestAACDecoder(AudioInfo& aConfig) { - PlatformDecoderModule::Init(); + PDMFactory::Init(); - nsRefPtr platform = PlatformDecoderModule::Create(); - if (!platform || !platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"))) { + nsRefPtr platform = new PDMFactory(); + if (!platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"))) { return nullptr; } diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h index b6c8870dae8d..7accf3776403 100644 --- a/dom/media/platforms/PDMFactory.h +++ b/dom/media/platforms/PDMFactory.h @@ -13,23 +13,29 @@ class CDMProxy; namespace mozilla { -class PDMFactory : public PlatformDecoderModule { +class PDMFactory final { public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PDMFactory) + PDMFactory(); - virtual ~PDMFactory(); // Call on the main thread to initialize the static state // needed by Create(). static void Init(); + // Factory method that creates the appropriate PlatformDecoderModule for + // the platform we're running on. Caller is responsible for deleting this + // instance. It's expected that there will be multiple + // PlatformDecoderModules alive at the same time. + // This is called on the decode task queue. already_AddRefed CreateDecoder(const TrackInfo& aConfig, FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, - layers::ImageContainer* aImageContainer = nullptr) override; + layers::ImageContainer* aImageContainer = nullptr); - bool SupportsMimeType(const nsACString& aMimeType) override; + bool SupportsMimeType(const nsACString& aMimeType); #ifdef MOZ_EME // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or @@ -40,37 +46,8 @@ public: void SetCDMProxy(CDMProxy* aProxy); #endif - ConversionRequired - DecoderNeedsConversion(const TrackInfo& aConfig) const override - { - MOZ_CRASH("Should never reach this function"); - return ConversionRequired::kNeedNone; - } - -protected: - // Decode thread. - already_AddRefed - CreateVideoDecoder(const VideoInfo& aConfig, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, - MediaDataDecoderCallback* aCallback) override - { - MOZ_CRASH("Should never reach this function"); - return nullptr; - } - - // Decode thread. - already_AddRefed - CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, - MediaDataDecoderCallback* aCallback) override - { - MOZ_CRASH("Should never reach this function"); - return nullptr; - } - private: + virtual ~PDMFactory(); void CreatePDMs(); // Startup the provided PDM and add it to our list if successful. bool StartupPDM(PlatformDecoderModule* aPDM); diff --git a/dom/media/platforms/PlatformDecoderModule.cpp b/dom/media/platforms/PlatformDecoderModule.cpp index 9f10a9402886..bb02119700bc 100644 --- a/dom/media/platforms/PlatformDecoderModule.cpp +++ b/dom/media/platforms/PlatformDecoderModule.cpp @@ -5,7 +5,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "PlatformDecoderModule.h" -#include "PDMFactory.h" PRLogModuleInfo* GetPDMLog() { static PRLogModuleInfo* log = nullptr; @@ -14,24 +13,3 @@ PRLogModuleInfo* GetPDMLog() { } return log; } - -namespace mozilla { - -/* static */ -void -PlatformDecoderModule::Init() -{ - MOZ_ASSERT(NS_IsMainThread()); - PDMFactory::Init(); -} - -/* static */ -already_AddRefed -PlatformDecoderModule::Create() -{ - // Note: This (usually) runs on the decode thread. - nsRefPtr m = new PDMFactory; - return m.forget(); -} - -} // namespace mozilla diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index 20dfaa86f537..2191814dc4b2 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -48,33 +48,10 @@ class PlatformDecoderModule { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformDecoderModule) - // Call on the main thread to initialize the static state - // needed by Create(). - static void Init(); - - // Factory method that creates the appropriate PlatformDecoderModule for - // the platform we're running on. Caller is responsible for deleting this - // instance. It's expected that there will be multiple - // PlatformDecoderModules alive at the same time. - // This is called on the decode task queue. - static already_AddRefed Create(); - // Perform any per-instance initialization. // This is called on the decode task queue. virtual nsresult Startup() { return NS_OK; }; - // Creates a decoder. - // See CreateVideoDecoder and CreateAudioDecoder for implementation details. - virtual already_AddRefed - CreateDecoder(const TrackInfo& aConfig, - FlushableTaskQueue* aTaskQueue, - MediaDataDecoderCallback* aCallback, - layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, - layers::ImageContainer* aImageContainer = nullptr) - { - MOZ_CRASH(); - } - // Indicates if the PlatformDecoderModule supports decoding of aMimeType. virtual bool SupportsMimeType(const nsACString& aMimeType) = 0; From bfea6860dd164ca0d470c744b5a6634b18d329e0 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 21:03:52 +1100 Subject: [PATCH 026/189] Bug 1206977: P10. Remove redundant code. r=cpearce The same checks are performed in the PDMFactory::SupportsMimeType --- dom/media/fmp4/MP4Decoder.cpp | 74 +---------------------------------- 1 file changed, 1 insertion(+), 73 deletions(-) diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 517b75e7c6ae..4199cf9eff38 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -27,10 +27,6 @@ #endif #include "mozilla/layers/LayersTypes.h" -#ifdef MOZ_FFMPEG -#include "FFmpegRuntimeLinker.h" -#endif - #include "PDMFactory.h" namespace mozilla { @@ -177,79 +173,11 @@ MP4Decoder::CanHandleMediaType(const nsAString& aContentType) return CanHandleMediaType(NS_ConvertUTF16toUTF8(mimeType), codecs); } -static bool -IsFFmpegAvailable() -{ -#ifndef MOZ_FFMPEG - return false; -#else - PDMFactory::Init(); - nsRefPtr m = FFmpegRuntimeLinker::CreateDecoderModule(); - return !!m; -#endif -} - -static bool -IsAppleAvailable() -{ -#ifndef MOZ_APPLEMEDIA - // Not the right platform. - return false; -#else - return Preferences::GetBool("media.apple.mp4.enabled", false); -#endif -} - -static bool -IsAndroidAvailable() -{ -#ifndef MOZ_WIDGET_ANDROID - return false; -#else - // We need android.media.MediaCodec which exists in API level 16 and higher. - return AndroidBridge::Bridge() && (AndroidBridge::Bridge()->GetAPIVersion() >= 16); -#endif -} - -static bool -IsGonkMP4DecoderAvailable() -{ -#ifndef MOZ_GONK_MEDIACODEC - return false; -#else - return Preferences::GetBool("media.fragmented-mp4.gonk.enabled", false); -#endif -} - -static bool -IsGMPDecoderAvailable() -{ - return Preferences::GetBool("media.fragmented-mp4.gmp.enabled", false); -} - -static bool -HavePlatformMPEGDecoders() -{ - return Preferences::GetBool("media.fragmented-mp4.use-blank-decoder") || -#ifdef XP_WIN - // We have H.264/AAC platform decoders on Windows Vista and up. - IsVistaOrLater() || -#endif - IsAndroidAvailable() || - IsFFmpegAvailable() || - IsAppleAvailable() || - IsGonkMP4DecoderAvailable() || - IsGMPDecoderAvailable() || - // TODO: Other platforms... - false; -} - /* static */ bool MP4Decoder::IsEnabled() { - return Preferences::GetBool("media.fragmented-mp4.enabled") && - HavePlatformMPEGDecoders(); + return Preferences::GetBool("media.fragmented-mp4.enabled"); } static const uint8_t sTestH264ExtraData[] = { From d9cf3168c40c72bbfb725531de74bdf2ac696c21 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 7 Oct 2015 10:37:38 +1100 Subject: [PATCH 027/189] Bug 1206977: P11. Don't rely on SupportsMimeType to determine if a track can be played. r=cpearce The PDMFactory will run more accurate checks based on the TrackInfo object and will fail to create a decoder if the type is unsupported. So use that instead --- dom/media/MP3Decoder.cpp | 7 ------- dom/media/MediaFormatReader.cpp | 18 ------------------ dom/media/MediaFormatReader.h | 2 -- dom/media/fmp4/MP4Decoder.cpp | 14 -------------- 4 files changed, 41 deletions(-) diff --git a/dom/media/MP3Decoder.cpp b/dom/media/MP3Decoder.cpp index b4ae9e0b78ed..f15dd1a23f50 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/MP3Decoder.cpp @@ -35,15 +35,8 @@ CreateTestMP3Decoder(AudioInfo& aConfig) PDMFactory::Init(); nsRefPtr platform = new PDMFactory(); - if (!platform->SupportsMimeType(aConfig.mMimeType)) { - return nullptr; - } - nsRefPtr decoder( platform->CreateDecoder(aConfig, nullptr, nullptr)); - if (!decoder) { - return nullptr; - } return decoder.forget(); } diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index fbe35320595b..6b0af2bcdf2b 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -237,18 +237,6 @@ MediaFormatReader::IsWaitingOnCDMResource() { #endif } -bool -MediaFormatReader::IsSupportedAudioMimeType(const nsACString& aMimeType) -{ - return mPlatform && mPlatform->SupportsMimeType(aMimeType); -} - -bool -MediaFormatReader::IsSupportedVideoMimeType(const nsACString& aMimeType) -{ - return mPlatform && mPlatform->SupportsMimeType(aMimeType); -} - nsRefPtr MediaFormatReader::AsyncReadMetadata() { @@ -394,9 +382,6 @@ MediaFormatReader::EnsureDecodersCreated() } if (HasAudio() && !mAudio.mDecoder) { - NS_ENSURE_TRUE(IsSupportedAudioMimeType(mInfo.mAudio.mMimeType), - false); - mAudio.mDecoderInitialized = false; mAudio.mDecoder = mPlatform->CreateDecoder(mAudio.mInfo ? @@ -408,9 +393,6 @@ MediaFormatReader::EnsureDecodersCreated() } if (HasVideo() && !mVideo.mDecoder) { - NS_ENSURE_TRUE(IsSupportedVideoMimeType(mInfo.mVideo.mMimeType), - false); - mVideo.mDecoderInitialized = false; // Decoders use the layers backend to decide if they can use hardware decoding, // so specify LAYERS_NONE if we want to forcibly disable it. diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 90015bbcbf4f..64f1d5c92112 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -147,8 +147,6 @@ private: void Error(TrackType aTrack); void Flush(TrackType aTrack); void DrainComplete(TrackType aTrack); - bool IsSupportedAudioMimeType(const nsACString& aMimeType); - bool IsSupportedVideoMimeType(const nsACString& aMimeType); bool ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold); diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 4199cf9eff38..97081b4a3825 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -204,15 +204,8 @@ CreateTestH264Decoder(layers::LayersBackend aBackend, PDMFactory::Init(); nsRefPtr platform = new PDMFactory(); - if (!platform->SupportsMimeType(NS_LITERAL_CSTRING("video/mp4"))) { - return nullptr; - } - nsRefPtr decoder( platform->CreateDecoder(aConfig, nullptr, nullptr, aBackend, nullptr)); - if (!decoder) { - return nullptr; - } return decoder.forget(); } @@ -260,15 +253,8 @@ CreateTestAACDecoder(AudioInfo& aConfig) PDMFactory::Init(); nsRefPtr platform = new PDMFactory(); - if (!platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"))) { - return nullptr; - } - nsRefPtr decoder( platform->CreateDecoder(aConfig, nullptr, nullptr)); - if (!decoder) { - return nullptr; - } return decoder.forget(); } From e4ea0dae9d2179bf66ffedf0229f069bebf2771e Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 7 Oct 2015 10:40:48 +1100 Subject: [PATCH 028/189] Bug 1206977: P12. Properly shutdown all created test decoders. r=cpearce --- dom/media/MP3Decoder.cpp | 1 + dom/media/fmp4/MP4Decoder.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/dom/media/MP3Decoder.cpp b/dom/media/MP3Decoder.cpp index f15dd1a23f50..588c26eecb4d 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/MP3Decoder.cpp @@ -56,6 +56,7 @@ CanCreateMP3Decoder() config.mBitDepth = 16; nsRefPtr decoder(CreateTestMP3Decoder(config)); if (decoder) { + decoder->Shutdown(); result = true; } haveCachedResult = true; diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 97081b4a3825..47ea102b02f8 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -220,6 +220,7 @@ MP4Decoder::IsVideoAccelerated(layers::LayersBackend aBackend, nsACString& aFail return false; } bool result = decoder->IsHardwareAccelerated(aFailureReason); + decoder->Shutdown(); return result; } @@ -293,6 +294,7 @@ MP4Decoder::CanCreateAACDecoder() MOZ_ARRAY_LENGTH(sTestAACExtraData)); nsRefPtr decoder(CreateTestAACDecoder(config)); if (decoder) { + decoder->Shutdown(); result = true; } haveCachedResult = true; From e32d97b854873cad9ff71cfb4d8611a5141888c2 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 7 Oct 2015 10:51:51 +1100 Subject: [PATCH 029/189] Bug 1206977: P13. Assert that data fed to EMEDecoderModule is encrypted. r=cpearce The PDMFactory ensures that the EMEDecoderModule is only used for encrypted data, we can simplify EMEDecoderModule and make strong assumptions --- .../platforms/agnostic/eme/EMEDecoderModule.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp index 46bccab7e483..bdf95e5632e9 100644 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp +++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp @@ -230,7 +230,9 @@ EMEDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, FlushableTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback) { - if (mCDMDecodesVideo && aConfig.mCrypto.mValid) { + MOZ_ASSERT(aConfig.mCrypto.mValid); + + if (mCDMDecodesVideo) { nsRefPtr wrapper = CreateDecoderWrapper(aCallback, mProxy, aVideoTaskQueue); wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy, aConfig, @@ -252,10 +254,6 @@ EMEDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, return nullptr; } - if (!aConfig.mCrypto.mValid) { - return decoder.forget(); - } - nsRefPtr emeDecoder(new EMEDecryptor(decoder, aCallback, mProxy, @@ -268,7 +266,9 @@ EMEDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, FlushableTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) { - if (mCDMDecodesAudio && aConfig.mCrypto.mValid) { + MOZ_ASSERT(aConfig.mCrypto.mValid); + + if (mCDMDecodesAudio) { nsRefPtr wrapper = CreateDecoderWrapper(aCallback, mProxy, aAudioTaskQueue); wrapper->SetProxyTarget(new EMEAudioDecoder(mProxy, aConfig, @@ -284,10 +284,6 @@ EMEDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, return nullptr; } - if (!aConfig.mCrypto.mValid) { - return decoder.forget(); - } - nsRefPtr emeDecoder(new EMEDecryptor(decoder, aCallback, mProxy, From c5052e863aba90b354ccda738e88089c4054668d Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 7 Oct 2015 11:14:46 +1100 Subject: [PATCH 030/189] Bug 1206977: P14. Remove obsolete / redundant code. r=cpearce --- dom/media/MP3Decoder.cpp | 40 ++---------------- dom/media/fmp4/MP4Decoder.cpp | 80 ----------------------------------- dom/media/fmp4/MP4Decoder.h | 2 - 3 files changed, 4 insertions(+), 118 deletions(-) diff --git a/dom/media/MP3Decoder.cpp b/dom/media/MP3Decoder.cpp index 588c26eecb4d..c4bf6bab426e 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/MP3Decoder.cpp @@ -29,44 +29,12 @@ MP3Decoder::CreateStateMachine() { return new MediaDecoderStateMachine(this, reader); } -static already_AddRefed -CreateTestMP3Decoder(AudioInfo& aConfig) -{ - PDMFactory::Init(); - - nsRefPtr platform = new PDMFactory(); - nsRefPtr decoder( - platform->CreateDecoder(aConfig, nullptr, nullptr)); - - return decoder.forget(); -} - -static bool -CanCreateMP3Decoder() -{ - static bool haveCachedResult = false; - static bool result = false; - if (haveCachedResult) { - return result; - } - AudioInfo config; - config.mMimeType = "audio/mpeg"; - config.mRate = 48000; - config.mChannels = 2; - config.mBitDepth = 16; - nsRefPtr decoder(CreateTestMP3Decoder(config)); - if (decoder) { - decoder->Shutdown(); - result = true; - } - haveCachedResult = true; - return result; -} - /* static */ bool MP3Decoder::IsEnabled() { - return CanCreateMP3Decoder(); + PDMFactory::Init(); + nsRefPtr platform = new PDMFactory(); + return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mpeg")); } /* static */ @@ -74,7 +42,7 @@ bool MP3Decoder::CanHandleMediaType(const nsACString& aType, const nsAString& aCodecs) { if (aType.EqualsASCII("audio/mp3") || aType.EqualsASCII("audio/mpeg")) { - return CanCreateMP3Decoder() && + return IsEnabled() && (aCodecs.IsEmpty() || aCodecs.EqualsASCII("mp3")); } return false; diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 47ea102b02f8..e92be5c3d630 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -224,84 +224,4 @@ MP4Decoder::IsVideoAccelerated(layers::LayersBackend aBackend, nsACString& aFail return result; } -/* static */ bool -MP4Decoder::CanCreateH264Decoder() -{ -#ifdef XP_WIN - static bool haveCachedResult = false; - static bool result = false; - if (haveCachedResult) { - return result; - } - VideoInfo config; - nsRefPtr decoder( - CreateTestH264Decoder(layers::LayersBackend::LAYERS_BASIC, config)); - if (decoder) { - decoder->Shutdown(); - result = true; - } - haveCachedResult = true; - return result; -#else - return IsEnabled(); -#endif -} - -#ifdef XP_WIN -static already_AddRefed -CreateTestAACDecoder(AudioInfo& aConfig) -{ - PDMFactory::Init(); - - nsRefPtr platform = new PDMFactory(); - nsRefPtr decoder( - platform->CreateDecoder(aConfig, nullptr, nullptr)); - - return decoder.forget(); -} - -// bipbop.mp4's extradata/config... -static const uint8_t sTestAACExtraData[] = { - 0x03, 0x80, 0x80, 0x80, 0x22, 0x00, 0x02, 0x00, 0x04, 0x80, - 0x80, 0x80, 0x14, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x11, 0x51, 0x00, 0x00, 0x11, 0x51, 0x05, 0x80, 0x80, 0x80, - 0x02, 0x13, 0x90, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02 -}; - -static const uint8_t sTestAACConfig[] = { 0x13, 0x90 }; - -#endif // XP_WIN - -/* static */ bool -MP4Decoder::CanCreateAACDecoder() -{ -#ifdef XP_WIN - static bool haveCachedResult = false; - static bool result = false; - if (haveCachedResult) { - return result; - } - AudioInfo config; - config.mMimeType = "audio/mp4a-latm"; - config.mRate = 22050; - config.mChannels = 2; - config.mBitDepth = 16; - config.mProfile = 2; - config.mExtendedProfile = 2; - config.mCodecSpecificConfig->AppendElements(sTestAACConfig, - MOZ_ARRAY_LENGTH(sTestAACConfig)); - config.mExtraData->AppendElements(sTestAACExtraData, - MOZ_ARRAY_LENGTH(sTestAACExtraData)); - nsRefPtr decoder(CreateTestAACDecoder(config)); - if (decoder) { - decoder->Shutdown(); - result = true; - } - haveCachedResult = true; - return result; -#else - return IsEnabled(); -#endif -} - } // namespace mozilla diff --git a/dom/media/fmp4/MP4Decoder.h b/dom/media/fmp4/MP4Decoder.h index aceec851aec9..f207838949eb 100644 --- a/dom/media/fmp4/MP4Decoder.h +++ b/dom/media/fmp4/MP4Decoder.h @@ -38,8 +38,6 @@ public: static bool IsEnabled(); static bool IsVideoAccelerated(layers::LayersBackend aBackend, nsACString& aReason); - static bool CanCreateAACDecoder(); - static bool CanCreateH264Decoder(); }; } // namespace mozilla From 9a7c13fa7869b385f7ba661a04de5797232a661e Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 7 Oct 2015 22:38:07 +1100 Subject: [PATCH 031/189] Bug 1206977: P15. Fix FFmpeg shutdown crash should decoder not be initialised. r=me --- dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp index 84e4c24f6add..c1542bc32fa4 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp @@ -194,7 +194,7 @@ FFmpegDataDecoder::ProcessShutdown() { StaticMutexAutoLock mon(sMonitor); - if (sFFmpegInitDone) { + if (sFFmpegInitDone && mCodecContext) { avcodec_close(mCodecContext); av_freep(&mCodecContext); #if LIBAVCODEC_VERSION_MAJOR >= 55 From 9b57a7f6ebfbfe5f94b77d91d057fbe9e57e6d71 Mon Sep 17 00:00:00 2001 From: Mike Shal Date: Mon, 5 Oct 2015 13:16:56 -0400 Subject: [PATCH 032/189] Bug 1211398 - Remove Taskcluster debug messages; r=jlund --- testing/mozharness/mozharness/mozilla/building/buildbase.py | 4 ---- testing/mozharness/scripts/desktop_l10n.py | 4 ---- 2 files changed, 8 deletions(-) diff --git a/testing/mozharness/mozharness/mozilla/building/buildbase.py b/testing/mozharness/mozharness/mozilla/building/buildbase.py index d5432044afe7..f57fae23966e 100755 --- a/testing/mozharness/mozharness/mozilla/building/buildbase.py +++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py @@ -1368,10 +1368,6 @@ or run without that action (ie: --no-{action})" self.create_virtualenv() self.activate_virtualenv() - # Enable Taskcluster debug logging, so at least we get some debug - # messages while we are testing uploads. - logging.getLogger('taskcluster').setLevel(logging.DEBUG) - routes_file = os.path.join(dirs['abs_src_dir'], 'testing/taskcluster/routes.json') with open(routes_file) as f: diff --git a/testing/mozharness/scripts/desktop_l10n.py b/testing/mozharness/scripts/desktop_l10n.py index 36bf30401f12..d803ad171e7f 100755 --- a/testing/mozharness/scripts/desktop_l10n.py +++ b/testing/mozharness/scripts/desktop_l10n.py @@ -993,10 +993,6 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin, self.enable_mock() self.activate_virtualenv() - # Enable Taskcluster debug logging, so at least we get some debug - # messages while we are testing uploads. - logging.getLogger('taskcluster').setLevel(logging.DEBUG) - branch = self.config['branch'] platform = self.config['platform'] revision = self._query_revision() From 8e7070660be1551302c2f5a45e6b355a737c377a Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 7 Oct 2015 14:58:40 +0100 Subject: [PATCH 033/189] Bug 1209001 - Add test code for OOM handling in parseModule() r=terrence --- js/src/jit-test/tests/gc/bug-1209001.js | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 js/src/jit-test/tests/gc/bug-1209001.js diff --git a/js/src/jit-test/tests/gc/bug-1209001.js b/js/src/jit-test/tests/gc/bug-1209001.js new file mode 100644 index 000000000000..c652307c66c6 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1209001.js @@ -0,0 +1,2 @@ +load(libdir + 'oomTest.js'); +oomTest(() => parseModule('import v from "mod";')); From 429c516ef88fab100ea06da9db4f01195d99dc8f Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 7 Oct 2015 14:58:41 +0100 Subject: [PATCH 034/189] Bug 1212011 - Replace more uses of CrashAtUnhandlableOOM() with AutoEnterOOMUnsafeRegion r=terrence --- js/src/gc/Barrier.cpp | 3 ++- js/src/gc/Zone.h | 3 ++- js/src/vm/HelperThreads.cpp | 7 +++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/js/src/gc/Barrier.cpp b/js/src/gc/Barrier.cpp index df42dfaf9802..3ea96ff0c82e 100644 --- a/js/src/gc/Barrier.cpp +++ b/js/src/gc/Barrier.cpp @@ -125,8 +125,9 @@ MovableCellHasher::hash(const Lookup& l) l->zoneFromAnyThread()->isSelfHostingZone()); HashNumber hn; + AutoEnterOOMUnsafeRegion oomUnsafe; if (!l->zoneFromAnyThread()->getHashCode(l, &hn)) - CrashAtUnhandlableOOM("failed to get a stable hash code"); + oomUnsafe.crash("failed to get a stable hash code"); return hn; } diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 7f39d00d4e5a..9f621f7d2e85 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -370,8 +370,9 @@ struct Zone : public JS::shadow::Zone, // If the cell was in the nursery, hopefully unlikely, then we need to // tell the nursery about it so that it can sweep the uid if the thing // does not get tenured. + js::AutoEnterOOMUnsafeRegion oomUnsafe; if (!runtimeFromAnyThread()->gc.nursery.addedUniqueIdToCell(cell)) - js::CrashAtUnhandlableOOM("failed to allocate tracking data for a nursery uid"); + oomUnsafe.crash("failed to allocate tracking data for a nursery uid"); return true; } diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index d6980801352f..2388d9ba9d65 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1416,8 +1416,11 @@ HelperThread::handleParseWorkload() // FinishOffThreadScript will need to be called on the script to // migrate it into the correct compartment. - if (!HelperThreadState().parseFinishedList().append(task)) - CrashAtUnhandlableOOM("handleParseWorkload"); + { + AutoEnterOOMUnsafeRegion oomUnsafe; + if (!HelperThreadState().parseFinishedList().append(task)) + oomUnsafe.crash("handleParseWorkload"); + } currentTask.reset(); From 825deb434b3284deb0e029091adf05321e83b078 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 7 Oct 2015 14:58:41 +0100 Subject: [PATCH 035/189] Bug 1212015 - Fix an unchecked allocation in AsmJS r=terrence --- js/src/asmjs/AsmJSValidate.cpp | 3 +++ js/src/jit-test/tests/gc/oomInParseAsmJS.js | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 js/src/jit-test/tests/gc/oomInParseAsmJS.js diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 4aa283321a30..d8447470576c 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -6400,6 +6400,9 @@ CheckFunction(ModuleValidator& m, LifoAlloc& lifo, AsmFunction** funcOut) } AsmFunction* asmFunc = lifo.new_(lifo); + if (!asmFunc) + return false; + FunctionValidator f(m, *asmFunc, fn); if (!f.init()) return false; diff --git a/js/src/jit-test/tests/gc/oomInParseAsmJS.js b/js/src/jit-test/tests/gc/oomInParseAsmJS.js new file mode 100644 index 000000000000..0ae3736a13ed --- /dev/null +++ b/js/src/jit-test/tests/gc/oomInParseAsmJS.js @@ -0,0 +1,15 @@ +load(libdir + 'oomTest.js'); +function parseAsmJS() { + eval(`function m(stdlib) + { + "use asm"; + var abs = stdlib.Math.abs; + function f(d) + { + d = +d; + return (~~(5.0 - +abs(d)))|0; + } + return f; + }`); +} +oomTest(parseAsmJS); From 15bd450b04f35980c446d9e78f7b9d6e127f3156 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 7 Oct 2015 14:58:41 +0100 Subject: [PATCH 036/189] Bug 1211964 - Fix a couple of OOM handling issues in regexp code r=terrence --- js/src/irregexp/NativeRegExpMacroAssembler.cpp | 4 +++- js/src/irregexp/RegExpEngine.cpp | 4 +++- js/src/jit-test/tests/gc/oomInRegExp.js | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 js/src/jit-test/tests/gc/oomInRegExp.js diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.cpp b/js/src/irregexp/NativeRegExpMacroAssembler.cpp index ef50eeb544e1..161f7d5d114b 100644 --- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp +++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp @@ -454,8 +454,10 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only) Linker linker(masm); AutoFlushICache afc("RegExp"); JitCode* code = linker.newCode(cx, REGEXP_CODE); - if (!code) + if (!code) { + ReportOutOfMemory(cx); return RegExpCode(); + } #ifdef JS_ION_PERF writePerfSpewerJitCodeProfile(code, "RegExp"); diff --git a/js/src/irregexp/RegExpEngine.cpp b/js/src/irregexp/RegExpEngine.cpp index c08ef5020f13..ba30fc7a72d0 100644 --- a/js/src/irregexp/RegExpEngine.cpp +++ b/js/src/irregexp/RegExpEngine.cpp @@ -997,7 +997,9 @@ ChoiceNode::FilterASCII(int depth, bool ignore_case) alternatives()[i].node()->FilterASCII(depth - 1, ignore_case); if (replacement != nullptr) { alternatives()[i].set_node(replacement); - new_alternatives.append(alternatives()[i]); + AutoEnterOOMUnsafeRegion oomUnsafe; + if (!new_alternatives.append(alternatives()[i])) + oomUnsafe.crash("ChoiceNode::FilterASCII"); } } diff --git a/js/src/jit-test/tests/gc/oomInRegExp.js b/js/src/jit-test/tests/gc/oomInRegExp.js new file mode 100644 index 000000000000..01066cd997bb --- /dev/null +++ b/js/src/jit-test/tests/gc/oomInRegExp.js @@ -0,0 +1,3 @@ +load(libdir + 'oomTest.js'); +oomTest(() => assertEq("foobar\xff5baz\u1200".search(/bar\u0178\d/i), 3)); +oomTest(() => assertEq((/(?!(?!(?!6)[\Wc]))/i).test(), false)); From 295fd4fa05b4eb06041d249fa76918d30f3477ce Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Mon, 5 Oct 2015 14:11:26 -0400 Subject: [PATCH 037/189] bug 1211580 - cancel brotli failures from channel instead of converter r=bagder --- netwerk/protocol/http/HttpBaseChannel.cpp | 50 ++++++++++++++++++- netwerk/protocol/http/HttpBaseChannel.h | 1 + .../converters/nsHTTPCompressConv.cpp | 9 ++-- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 64c98de26cbd..53172dbe9dc3 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -773,6 +773,52 @@ HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener, mListenerContext); } +// create a listener chain that looks like this +// http-channel -> decompressor (n times) -> InterceptFailedOnSTop -> channel-creator-listener +// +// we need to do this because not every decompressor has fully streamed output so +// may need a call to OnStopRequest to identify its completion state.. and if it +// creates an error there the channel status code needs to be updated before calling +// the terminal listener. Having the decompress do it via cancel() means channels cannot +// effectively be used in two contexts (specifically this one and a peek context for +// sniffing) +// +class InterceptFailedOnStop : public nsIStreamListener +{ + virtual ~InterceptFailedOnStop() {} + nsCOMPtr mNext; + HttpBaseChannel *mChannel; + +public: + InterceptFailedOnStop(nsIStreamListener *arg, HttpBaseChannel *chan) + : mNext(arg) + , mChannel(chan) {} + NS_DECL_ISUPPORTS + + NS_IMETHODIMP OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) override + { + return mNext->OnStartRequest(aRequest, aContext); + } + + NS_IMETHODIMP OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatusCode) override + { + if (NS_FAILED(aStatusCode) && NS_SUCCEEDED(mChannel->mStatus)) { + LOG(("HttpBaseChannel::InterceptFailedOnStop %p seting status %x", mChannel, aStatusCode)); + mChannel->mStatus = aStatusCode; + } + return mNext->OnStopRequest(aRequest, aContext, aStatusCode); + } + + NS_IMETHODIMP OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext, + nsIInputStream *aInputStream, uint64_t aOffset, + uint32_t aCount) override + { + return mNext->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount); + } +}; + +NS_IMPL_ISUPPORTS(InterceptFailedOnStop, nsIStreamListener, nsIRequestObserver) + NS_IMETHODIMP HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener, nsIStreamListener** aNewNextListener, @@ -783,8 +829,6 @@ HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener, return NS_OK; } - nsCOMPtr nextListener = aNextListener; - LOG(("HttpBaseChannel::DoApplyContentConversions [this=%p]\n", this)); if (!mApplyConversion) { @@ -797,6 +841,8 @@ HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener, if (NS_FAILED(rv) || contentEncoding.IsEmpty()) return NS_OK; + nsCOMPtr nextListener = new InterceptFailedOnStop(aNextListener, this); + // The encodings are listed in the order they were applied // (see rfc 2616 section 14.11), so they need to removed in reverse // order. This is accomplished because the converter chain ends up diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index 07bba14af310..215559b87fee 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -321,6 +321,7 @@ protected: bool ShouldIntercept(); friend class PrivateBrowsingChannel; + friend class InterceptFailedOnStop; nsCOMPtr mURI; nsCOMPtr mOriginalURI; diff --git a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp index f13c5691cebb..8682184ecbc7 100644 --- a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp +++ b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp @@ -140,10 +140,6 @@ nsHTTPCompressConv::OnStopRequest(nsIRequest* request, nsISupports *aContext, fpChannel->ForcePending(false); } } - if (NS_FAILED(status) && status != aStatus) { - LOG(("nsHttpCompresssConv %p onstop calling cancel %x\n", this, status)); - request->Cancel(status); - } return mListener->OnStopRequest(request, aContext, status); } @@ -163,6 +159,11 @@ nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const c size_t avail = aAvail; BrotliResult res; + if (!self->mBrotli) { + *countRead = aAvail; + return NS_OK; + } + do { outSize = kOutSize; outPtr = outBuffer; From 0793f321512150b15fa048ddb2e97b2e2e183884 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Tue, 6 Oct 2015 11:03:50 -0400 Subject: [PATCH 038/189] bug 1211916 - rename brotli http coding to br r=bagder --- modules/libpref/init/all.js | 2 +- netwerk/build/nsNetModule.cpp | 2 +- netwerk/protocol/http/HttpBaseChannel.cpp | 4 ++-- netwerk/streamconv/converters/nsHTTPCompressConv.h | 2 +- netwerk/test/unit/test_content_encoding_gzip.js | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 7789ca03b74a..1204c6e4743c 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1326,7 +1326,7 @@ pref("network.http.redirection-limit", 20); // NOTE: support for "compress" has been disabled per bug 196406. // NOTE: separate values with comma+space (", "): see bug 576033 pref("network.http.accept-encoding", "gzip, deflate"); -pref("network.http.accept-encoding.secure", "gzip, deflate, brotli"); +pref("network.http.accept-encoding.secure", "gzip, deflate, br"); pref("network.http.pipelining" , false); pref("network.http.pipelining.ssl" , false); // disable pipelining over SSL diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index 520d143de4b5..c45271bdc0b4 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -443,7 +443,7 @@ nsresult NS_NewStreamConv(nsStreamConverterService **aStreamConv); #define UNKNOWN_CONTENT "?from=" UNKNOWN_CONTENT_TYPE "&to=*/*" #define GZIP_TO_UNCOMPRESSED "?from=gzip&to=uncompressed" #define XGZIP_TO_UNCOMPRESSED "?from=x-gzip&to=uncompressed" -#define BROTLI_TO_UNCOMPRESSED "?from=brotli&to=uncompressed" +#define BROTLI_TO_UNCOMPRESSED "?from=br&to=uncompressed" #define COMPRESS_TO_UNCOMPRESSED "?from=compress&to=uncompressed" #define XCOMPRESS_TO_UNCOMPRESSED "?from=x-compress&to=uncompressed" #define DEFLATE_TO_UNCOMPRESSED "?from=deflate&to=uncompressed" diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 53172dbe9dc3..7101a3dfddc1 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -894,7 +894,7 @@ HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener, mode = 1; } else if (from.Equals("deflate") || from.Equals("x-deflate")) { mode = 2; - } else if (from.Equals("brotli")) { + } else if (from.Equals("br")) { mode = 3; } Telemetry::Accumulate(Telemetry::HTTP_CONTENT_ENCODING, mode); @@ -1005,7 +1005,7 @@ HttpBaseChannel::nsContentEncodings::GetNext(nsACString& aNextEncoding) if (!haveType) { encoding.BeginReading(start); - if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("brotli"), start, end)) { + if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("br"), start, end)) { aNextEncoding.AssignLiteral(APPLICATION_BROTLI); haveType = true; } diff --git a/netwerk/streamconv/converters/nsHTTPCompressConv.h b/netwerk/streamconv/converters/nsHTTPCompressConv.h index e443f9543128..433f4159ea8c 100644 --- a/netwerk/streamconv/converters/nsHTTPCompressConv.h +++ b/netwerk/streamconv/converters/nsHTTPCompressConv.h @@ -34,7 +34,7 @@ class nsIStringInputStream; #define HTTP_X_GZIP_TYPE "x-gzip" #define HTTP_COMPRESS_TYPE "compress" #define HTTP_X_COMPRESS_TYPE "x-compress" -#define HTTP_BROTLI_TYPE "brotli" +#define HTTP_BROTLI_TYPE "br" #define HTTP_IDENTITY_TYPE "identity" #define HTTP_UNCOMPRESSED_TYPE "uncompressed" diff --git a/netwerk/test/unit/test_content_encoding_gzip.js b/netwerk/test/unit/test_content_encoding_gzip.js index 28cc89774932..e4fe346a7c1f 100644 --- a/netwerk/test/unit/test_content_encoding_gzip.js +++ b/netwerk/test/unit/test_content_encoding_gzip.js @@ -27,7 +27,7 @@ var tests = [ {url: "/test/cebrotli1", flags: CL_EXPECT_GZIP, - ce: "brotli", + ce: "br", body: [0x0B, 0x02, 0x80, 0x74, 0x65, 0x73, 0x74, 0x0A, 0x03], datalen: 5 // the data length of the uncompressed document @@ -36,7 +36,7 @@ var tests = [ // this is not a brotli document {url: "/test/cebrotli2", flags: CL_EXPECT_GZIP | CL_EXPECT_FAILURE, - ce: "brotli", + ce: "br", body: [0x0B, 0x0A, 0x09], datalen: 3 }, @@ -44,7 +44,7 @@ var tests = [ // this is brotli but should come through as identity due to prefs {url: "/test/cebrotli3", flags: 0, - ce: "brotli", + ce: "br", body: [0x0B, 0x02, 0x80, 0x74, 0x65, 0x73, 0x74, 0x0A, 0x03], datalen: 9 @@ -92,7 +92,7 @@ var cePref; function run_test() { prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); cePref = prefs.getCharPref("network.http.accept-encoding"); - prefs.setCharPref("network.http.accept-encoding", "gzip, deflate, brotli"); + prefs.setCharPref("network.http.accept-encoding", "gzip, deflate, br"); httpserver.registerPathHandler("/test/cegzip1", handler); httpserver.registerPathHandler("/test/cegzip2", handler); From fdec90f01487a9011383d6637f8451684762319f Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Wed, 7 Oct 2015 10:59:02 -0400 Subject: [PATCH 039/189] Bug 1206107 - crash beginning in nightly 0916 in mozilla::a11y::Accessible::HasGenericType, part2, r=tbsaunde --- accessible/generic/DocAccessible.cpp | 35 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp index 6461274803f0..29f4d10b96b1 100644 --- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -1364,14 +1364,15 @@ DocAccessible::ProcessInvalidationList() continue; } - if (!child->Parent()) { + Accessible* oldParent = child->Parent(); + if (!oldParent) { NS_ERROR("The accessible is in document but doesn't have a parent"); continue; } + int32_t idxInParent = child->IndexInParent(); // XXX: update context flags { - Accessible* oldParent = child->Parent(); nsRefPtr reorderEvent = new AccReorderEvent(oldParent); nsRefPtr hideEvent = new AccHideEvent(child, child->GetContent(), false); @@ -1385,21 +1386,29 @@ DocAccessible::ProcessInvalidationList() FireDelayedEvent(reorderEvent); } + bool isReinserted = false; { AutoTreeMutation mut(owner); - owner->AppendChild(child); - - nsRefPtr reorderEvent = new AccReorderEvent(owner); - nsRefPtr showEvent = - new AccShowEvent(child, child->GetContent()); - FireDelayedEvent(showEvent); - reorderEvent->AddSubMutationEvent(showEvent); - - MaybeNotifyOfValueChange(owner); - FireDelayedEvent(reorderEvent); + isReinserted = owner->AppendChild(child); } - child->SetRepositioned(true); + Accessible* newParent = owner; + if (!isReinserted) { + AutoTreeMutation mut(oldParent); + oldParent->InsertChildAt(idxInParent, child); + newParent = oldParent; + } + + nsRefPtr reorderEvent = new AccReorderEvent(newParent); + nsRefPtr showEvent = + new AccShowEvent(child, child->GetContent()); + FireDelayedEvent(showEvent); + reorderEvent->AddSubMutationEvent(showEvent); + + MaybeNotifyOfValueChange(newParent); + FireDelayedEvent(reorderEvent); + + child->SetRepositioned(isReinserted); } mARIAOwnsInvalidationList.Clear(); From 0ff7248107d5ddcb258350195b0fd179169447f5 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Wed, 7 Oct 2015 08:17:42 -0700 Subject: [PATCH 040/189] Bug 1210517 - Create nsVariant directly rather than via do_CreateInstance(). r=froydnj The goal here is to leave creation stuff mostly for JS, so we can convert it entirely over to a non-threadsafe cycle-collected version without breaking any existing C++ users. I didn't do this for a remaining use in nsGlobalWindow.h to avoid including nsVariant.h all over the place. --- dom/base/nsContentAreaDragDrop.cpp | 29 ++++++++----------- dom/events/DataTransfer.cpp | 13 ++------- dom/html/HTMLInputElement.cpp | 5 ++-- dom/html/TextTrackManager.cpp | 4 +-- dom/ipc/ContentChild.cpp | 5 ++-- dom/ipc/TabParent.cpp | 9 ++---- dom/media/MediaManager.cpp | 3 +- dom/mobilemessage/DeletedMessageInfo.cpp | 10 +++---- dom/storage/DOMStorageDBThread.cpp | 7 ++--- .../mozstumbler/UploadStumbleRunnable.cpp | 5 ++-- dom/workers/XMLHttpRequest.cpp | 6 ++-- dom/xslt/xslt/txMozillaXSLTProcessor.cpp | 5 ++-- .../nsXULTemplateQueryProcessorStorage.cpp | 4 +-- editor/composer/nsEditorSpellCheck.cpp | 5 ++-- layout/xul/tree/nsTreeBodyFrame.cpp | 11 ++----- toolkit/components/places/Database.cpp | 9 ++---- toolkit/components/places/SQLFunctions.cpp | 13 +++------ .../components/places/nsNavHistoryQuery.cpp | 7 ++--- toolkit/xre/nsUpdateDriver.cpp | 9 ++---- uriloader/exthandler/win/nsMIMEInfoWin.cpp | 8 ++--- 20 files changed, 60 insertions(+), 107 deletions(-) diff --git a/dom/base/nsContentAreaDragDrop.cpp b/dom/base/nsContentAreaDragDrop.cpp index 0256e9f4710e..f35346c42561 100644 --- a/dom/base/nsContentAreaDragDrop.cpp +++ b/dom/base/nsContentAreaDragDrop.cpp @@ -57,6 +57,7 @@ #include "TabParent.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLAreaElement.h" +#include "nsVariant.h" using namespace mozilla::dom; @@ -726,11 +727,9 @@ DragDataProducer::AddString(DataTransfer* aDataTransfer, const nsAString& aData, nsIPrincipal* aPrincipal) { - nsCOMPtr variant = do_CreateInstance(NS_VARIANT_CONTRACTID); - if (variant) { - variant->SetAsAString(aData); - aDataTransfer->SetDataWithPrincipal(aFlavor, variant, 0, aPrincipal); - } + nsRefPtr variant = new nsVariant(); + variant->SetAsAString(aData); + aDataTransfer->SetDataWithPrincipal(aFlavor, variant, 0, aPrincipal); } nsresult @@ -784,12 +783,10 @@ DragDataProducer::AddStringsToDataTransfer(nsIContent* aDragNode, // a new flavor so as not to confuse anyone who is really registered // for image/gif or image/jpg. if (mImage) { - nsCOMPtr variant = do_CreateInstance(NS_VARIANT_CONTRACTID); - if (variant) { - variant->SetAsISupports(mImage); - aDataTransfer->SetDataWithPrincipal(NS_LITERAL_STRING(kNativeImageMime), - variant, 0, principal); - } + nsRefPtr variant = new nsVariant(); + variant->SetAsISupports(mImage); + aDataTransfer->SetDataWithPrincipal(NS_LITERAL_STRING(kNativeImageMime), + variant, 0, principal); // assume the image comes from a file, and add a file promise. We // register ourselves as a nsIFlavorDataProvider, and will use the @@ -798,12 +795,10 @@ DragDataProducer::AddStringsToDataTransfer(nsIContent* aDragNode, nsCOMPtr dataProvider = new nsContentAreaDragDropDataProvider(); if (dataProvider) { - nsCOMPtr variant = do_CreateInstance(NS_VARIANT_CONTRACTID); - if (variant) { - variant->SetAsISupports(dataProvider); - aDataTransfer->SetDataWithPrincipal(NS_LITERAL_STRING(kFilePromiseMime), - variant, 0, principal); - } + nsRefPtr variant = new nsVariant(); + variant->SetAsISupports(dataProvider); + aDataTransfer->SetDataWithPrincipal(NS_LITERAL_STRING(kFilePromiseMime), + variant, 0, principal); } AddString(aDataTransfer, NS_LITERAL_STRING(kFilePromiseURLMime), diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp index 42d472d5c087..f7ffa726141b 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -10,7 +10,6 @@ #include "DataTransfer.h" #include "nsIDOMDocument.h" -#include "nsIVariant.h" #include "nsISupportsPrimitives.h" #include "nsIScriptSecurityManager.h" #include "mozilla/dom/DOMStringList.h" @@ -24,6 +23,7 @@ #include "nsIScriptContext.h" #include "nsIDocument.h" #include "nsIScriptGlobalObject.h" +#include "nsVariant.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/DataTransferBinding.h" #include "mozilla/dom/Directory.h" @@ -435,12 +435,7 @@ void DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData, ErrorResult& aRv) { - nsCOMPtr variant = do_CreateInstance(NS_VARIANT_CONTRACTID); - if (!variant) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - + nsRefPtr variant = new nsVariant(); variant->SetAsAString(aData); aRv = MozSetDataAt(aFormat, variant, 0); @@ -1350,9 +1345,7 @@ DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex) if (!data) return; - nsCOMPtr variant = do_CreateInstance(NS_VARIANT_CONTRACTID); - if (!variant) - return; + nsRefPtr variant = new nsVariant(); nsCOMPtr supportsstr = do_QueryInterface(data); if (supportsstr) { diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index eba90f613032..bb86518ca38c 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -63,6 +63,7 @@ #include "nsReadableUtils.h" #include "nsUnicharUtils.h" #include "nsLayoutUtils.h" +#include "nsVariant.h" #include "nsIDOMMutationEvent.h" #include "mozilla/ContentEvents.h" @@ -807,9 +808,7 @@ UploadLastDir::StoreLastUsedDirectory(nsIDocument* aDoc, nsIFile* aDir) aDir->GetPath(unicodePath); if (unicodePath.IsEmpty()) // nothing to do return NS_OK; - nsCOMPtr prefValue = do_CreateInstance(NS_VARIANT_CONTRACTID); - if (!prefValue) - return NS_ERROR_OUT_OF_MEMORY; + nsRefPtr prefValue = new nsVariant(); prefValue->SetAsAString(unicodePath); // Use the document's current load context to ensure that the content pref diff --git a/dom/html/TextTrackManager.cpp b/dom/html/TextTrackManager.cpp index d4e0e8d4161d..e9fed00226ee 100644 --- a/dom/html/TextTrackManager.cpp +++ b/dom/html/TextTrackManager.cpp @@ -13,6 +13,7 @@ #include "mozilla/dom/Event.h" #include "mozilla/ClearOnShutdown.h" #include "nsComponentManagerUtils.h" +#include "nsVariant.h" #include "nsVideoFrame.h" #include "nsIFrame.h" #include "nsTArrayHelpers.h" @@ -214,8 +215,7 @@ TextTrackManager::UpdateCueDisplay() mTextTracks->UpdateAndGetShowingCues(activeCues); if (activeCues.Length() > 0) { - nsCOMPtr jsCues = - do_CreateInstance("@mozilla.org/variant;1"); + nsRefPtr jsCues = new nsVariant(); jsCues->SetAsArray(nsIDataType::VTYPE_INTERFACE, &NS_GET_IID(nsIDOMEventTarget), diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index d3cc35f6d481..7a81a59a56ef 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -85,6 +85,7 @@ #include "nsMemoryInfoDumper.h" #include "nsServiceManagerUtils.h" #include "nsStyleSheetService.h" +#include "nsVariant.h" #include "nsXULAppAPI.h" #include "nsIScriptError.h" #include "nsIConsoleService.h" @@ -2864,9 +2865,7 @@ ContentChild::RecvInvokeDragSession(nsTArray&& aTransfers, auto& items = aTransfers[i].items(); for (uint32_t j = 0; j < items.Length(); ++j) { const IPCDataTransferItem& item = items[j]; - nsCOMPtr variant = - do_CreateInstance(NS_VARIANT_CONTRACTID); - NS_ENSURE_TRUE(variant, false); + nsRefPtr variant = new nsVariant(); if (item.data().type() == IPCDataTransferData::TnsString) { const nsString& data = item.data().get_nsString(); variant->SetAsAString(data); diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 5687209eb0eb..f034e64a58a8 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -63,6 +63,7 @@ #include "nsIXULWindow.h" #include "nsIRemoteBrowser.h" #include "nsViewManager.h" +#include "nsVariant.h" #include "nsIWidget.h" #include "nsIWindowMediator.h" #include "nsIWindowWatcher.h" @@ -3541,7 +3542,7 @@ TabParent::RecvInvokeDragSession(nsTArray&& aTransfers, } mDragAreaX = aDragAreaX; mDragAreaY = aDragAreaY; - + esm->BeginTrackingRemoteDragGesture(mFrameElement); return true; @@ -3554,11 +3555,7 @@ TabParent::AddInitialDnDDataTo(DataTransfer* aDataTransfer) nsTArray& itemArray = mInitialDataTransferItems[i]; for (uint32_t j = 0; j < itemArray.Length(); ++j) { DataTransferItem& item = itemArray[j]; - nsCOMPtr variant = - do_CreateInstance(NS_VARIANT_CONTRACTID); - if (!variant) { - break; - } + nsRefPtr variant = new nsVariant(); // Special case kFilePromiseMime so that we get the right // nsIFlavorDataProvider for it. if (item.mFlavor.EqualsLiteral(kFilePromiseMime)) { diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 14414e5fde6a..2e1b3643d9f0 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -50,6 +50,7 @@ #include "Latency.h" #include "nsProxyRelease.h" #include "nsNullPrincipal.h" +#include "nsVariant.h" // For PR_snprintf #include "prprf.h" @@ -2203,7 +2204,7 @@ MediaManager::AnonymizeId(nsAString& aId, const nsACString& aOriginKey) already_AddRefed MediaManager::ToJSArray(SourceSet& aDevices) { - nsCOMPtr var = do_CreateInstance("@mozilla.org/variant;1"); + nsRefPtr var = new nsVariant(); size_t len = aDevices.Length(); if (len) { nsTArray tmp(len); diff --git a/dom/mobilemessage/DeletedMessageInfo.cpp b/dom/mobilemessage/DeletedMessageInfo.cpp index d9975f2d87d3..17b708a26b3b 100644 --- a/dom/mobilemessage/DeletedMessageInfo.cpp +++ b/dom/mobilemessage/DeletedMessageInfo.cpp @@ -69,10 +69,9 @@ DeletedMessageInfo::GetDeletedMessageIds(nsIVariant** aDeletedMessageIds) return NS_OK; } - nsresult rv; - mDeletedMessageIds = do_CreateInstance(NS_VARIANT_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + mDeletedMessageIds = new nsVariant(); + nsresult rv; rv = mDeletedMessageIds->SetAsArray(nsIDataType::VTYPE_INT32, nullptr, length, @@ -103,10 +102,9 @@ DeletedMessageInfo::GetDeletedThreadIds(nsIVariant** aDeletedThreadIds) return NS_OK; } - nsresult rv; - mDeletedThreadIds = do_CreateInstance(NS_VARIANT_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + mDeletedThreadIds = new nsVariant(); + nsresult rv; rv = mDeletedThreadIds->SetAsArray(nsIDataType::VTYPE_UINT64, nullptr, length, diff --git a/dom/storage/DOMStorageDBThread.cpp b/dom/storage/DOMStorageDBThread.cpp index 27ac7a2ecc14..c04f9f0025db 100644 --- a/dom/storage/DOMStorageDBThread.cpp +++ b/dom/storage/DOMStorageDBThread.cpp @@ -20,7 +20,7 @@ #include "mozIStorageValueArray.h" #include "mozIStorageFunction.h" #include "nsIObserverService.h" -#include "nsIVariant.h" +#include "nsVariant.h" #include "mozilla/IOInterposer.h" #include "mozilla/Services.h" @@ -403,10 +403,7 @@ nsReverseStringSQLFunction::OnFunctionCall( nsAutoCString result; ReverseString(stringToReverse, result); - nsCOMPtr outVar(do_CreateInstance( - NS_VARIANT_CONTRACTID, &rv)); - NS_ENSURE_SUCCESS(rv, rv); - + nsRefPtr outVar(new nsVariant()); rv = outVar->SetAsAUTF8String(result); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/system/gonk/mozstumbler/UploadStumbleRunnable.cpp b/dom/system/gonk/mozstumbler/UploadStumbleRunnable.cpp index 963109cb5397..1d1b825dd440 100644 --- a/dom/system/gonk/mozstumbler/UploadStumbleRunnable.cpp +++ b/dom/system/gonk/mozstumbler/UploadStumbleRunnable.cpp @@ -10,9 +10,9 @@ #include "nsIInputStream.h" #include "nsIScriptSecurityManager.h" #include "nsIURLFormatter.h" -#include "nsIVariant.h" #include "nsIXMLHttpRequest.h" #include "nsNetUtil.h" +#include "nsVariant.h" UploadStumbleRunnable::UploadStumbleRunnable(nsIInputStream* aUploadData) : mUploadInputStream(aUploadData) @@ -34,8 +34,7 @@ nsresult UploadStumbleRunnable::Upload() { nsresult rv; - nsCOMPtr variant = do_CreateInstance("@mozilla.org/variant;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); + nsRefPtr variant = new nsVariant(); rv = variant->SetAsISupports(mUploadInputStream); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index fd733ae0f9e2..23336e6973c6 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -9,7 +9,6 @@ #include "nsIDOMEvent.h" #include "nsIDOMEventListener.h" #include "nsIRunnable.h" -#include "nsIVariant.h" #include "nsIXMLHttpRequest.h" #include "nsIXPConnect.h" @@ -24,6 +23,7 @@ #include "nsFormData.h" #include "nsJSUtils.h" #include "nsThreadUtils.h" +#include "nsVariant.h" #include "RuntimeService.h" #include "WorkerPrivate.h" @@ -1527,9 +1527,7 @@ SendRunnable::MainThreadRun() } } else { - nsCOMPtr wvariant = - do_CreateInstance(NS_VARIANT_CONTRACTID); - NS_ENSURE_TRUE(wvariant, NS_ERROR_UNEXPECTED); + nsRefPtr wvariant = new nsVariant(); if (NS_FAILED(wvariant->SetAsAString(mStringBody))) { MOZ_ASSERT(false, "This should never fail!"); diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp index f122e501e418..721dc7e83316 100644 --- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp @@ -34,6 +34,7 @@ #include "nsIScriptSecurityManager.h" #include "nsJSUtils.h" #include "nsIXPConnect.h" +#include "nsVariant.h" #include "mozilla/dom/DocumentFragment.h" #include "mozilla/dom/XSLTProcessorBinding.h" @@ -845,9 +846,7 @@ txMozillaXSLTProcessor::SetParameter(const nsAString & aNamespaceURI, rv = xpathResult->Clone(getter_AddRefs(clone)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr variant = - do_CreateInstance("@mozilla.org/variant;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); + nsRefPtr variant = new nsVariant(); rv = variant->SetAsISupports(clone); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/xul/templates/nsXULTemplateQueryProcessorStorage.cpp b/dom/xul/templates/nsXULTemplateQueryProcessorStorage.cpp index 52b049690bcd..363e7d4ca1ea 100644 --- a/dom/xul/templates/nsXULTemplateQueryProcessorStorage.cpp +++ b/dom/xul/templates/nsXULTemplateQueryProcessorStorage.cpp @@ -9,7 +9,7 @@ #include "nsUnicharUtils.h" #include "nsArrayUtils.h" -#include "nsIVariant.h" +#include "nsVariant.h" #include "nsAppDirectoryServiceDefs.h" #include "nsIURI.h" @@ -110,7 +110,7 @@ nsXULTemplateResultSetStorage::FillColumnValues(nsCOMArray& aArray) int32_t count = mColumnNames.Count(); for (int32_t c = 0; c < count; c++) { - nsCOMPtr value = do_CreateInstance("@mozilla.org/variant;1"); + nsRefPtr value = new nsVariant(); int32_t type; mStatement->GetTypeOfIndex(c, &type); diff --git a/editor/composer/nsEditorSpellCheck.cpp b/editor/composer/nsEditorSpellCheck.cpp index f20a66f9e538..c47d7d59f962 100644 --- a/editor/composer/nsEditorSpellCheck.cpp +++ b/editor/composer/nsEditorSpellCheck.cpp @@ -35,7 +35,7 @@ #include "nsITextServicesDocument.h" // for nsITextServicesDocument #include "nsITextServicesFilter.h" // for nsITextServicesFilter #include "nsIURI.h" // for nsIURI -#include "nsIVariant.h" // for nsIWritableVariant, etc +#include "nsVariant.h" // for nsIWritableVariant, etc #include "nsLiteralString.h" // for NS_LITERAL_STRING, etc #include "nsMemory.h" // for nsMemory #include "nsRange.h" @@ -201,8 +201,7 @@ StoreCurrentDictionary(nsIEditor* aEditor, const nsAString& aDictionary) rv = docUri->GetSpec(docUriSpec); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr prefValue = do_CreateInstance(NS_VARIANT_CONTRACTID); - NS_ENSURE_TRUE(prefValue, NS_ERROR_OUT_OF_MEMORY); + nsRefPtr prefValue = new nsVariant(); prefValue->SetAsAString(aDictionary); nsCOMPtr contentPrefService = diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp index 3b8b1cbc40da..f15bc68916eb 100644 --- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -44,6 +44,7 @@ #include "nsContainerFrame.h" #include "nsView.h" #include "nsViewManager.h" +#include "nsVariant.h" #include "nsWidgetsCID.h" #include "nsBoxFrame.h" #include "nsIURL.h" @@ -4635,10 +4636,7 @@ nsTreeBodyFrame::FireRowCountChangedEvent(int32_t aIndex, int32_t aCount) // Set 'count' data - the number of changed rows. propBag->SetPropertyAsInt32(NS_LITERAL_STRING("count"), aCount); - nsCOMPtr detailVariant( - do_CreateInstance("@mozilla.org/variant;1")); - if (!detailVariant) - return; + nsRefPtr detailVariant(new nsVariant()); detailVariant->SetAsISupports(propBag); treeEvent->InitCustomEvent(NS_LITERAL_STRING("TreeRowCountChanged"), @@ -4707,10 +4705,7 @@ nsTreeBodyFrame::FireInvalidateEvent(int32_t aStartRowIdx, int32_t aEndRowIdx, endColIdx); } - nsCOMPtr detailVariant( - do_CreateInstance("@mozilla.org/variant;1")); - if (!detailVariant) - return; + nsRefPtr detailVariant(new nsVariant()); detailVariant->SetAsISupports(propBag); treeEvent->InitCustomEvent(NS_LITERAL_STRING("TreeInvalidated"), diff --git a/toolkit/components/places/Database.cpp b/toolkit/components/places/Database.cpp index 67832cc227c8..eab128bedbc8 100644 --- a/toolkit/components/places/Database.cpp +++ b/toolkit/components/places/Database.cpp @@ -18,6 +18,7 @@ #include "nsPlacesIndexes.h" #include "nsPlacesTriggers.h" #include "nsPlacesMacros.h" +#include "nsVariant.h" #include "SQLFunctions.h" #include "Helpers.h" @@ -420,9 +421,7 @@ NS_IMETHODIMP DatabaseShutdown::GetState(nsIPropertyBag** aState) if (NS_WARN_IF(NS_FAILED(rv))) return rv; // Put `mState` in field `progress` - nsCOMPtr progress = - do_CreateInstance(NS_VARIANT_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) return rv; + nsRefPtr progress = new nsVariant(); rv = progress->SetAsUint8(mState); if (NS_WARN_IF(NS_FAILED(rv))) return rv; @@ -440,9 +439,7 @@ NS_IMETHODIMP DatabaseShutdown::GetState(nsIPropertyBag** aState) return NS_OK; } - nsCOMPtr barrier = - do_CreateInstance(NS_VARIANT_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) return rv; + nsRefPtr barrier = new nsVariant(); rv = barrier->SetAsInterface(NS_GET_IID(nsIPropertyBag), barrierState); if (NS_WARN_IF(NS_FAILED(rv))) return rv; diff --git a/toolkit/components/places/SQLFunctions.cpp b/toolkit/components/places/SQLFunctions.cpp index ad14ac97ede4..6a38d9b69ea3 100644 --- a/toolkit/components/places/SQLFunctions.cpp +++ b/toolkit/components/places/SQLFunctions.cpp @@ -16,6 +16,7 @@ #include "nsPrintfCString.h" #include "nsNavHistory.h" #include "mozilla/Likely.h" +#include "nsVariant.h" using namespace mozilla::storage; @@ -703,9 +704,7 @@ namespace places { nsAutoString src; aArguments->GetString(0, src); - nsCOMPtr result = - do_CreateInstance("@mozilla.org/variant;1"); - NS_ENSURE_STATE(result); + nsRefPtr result = new nsVariant(); if (src.Length()>1) { src.Truncate(src.Length() - 1); @@ -761,9 +760,7 @@ namespace places { nsAutoString src; aArguments->GetString(0, src); - nsCOMPtr result = - do_CreateInstance("@mozilla.org/variant;1"); - NS_ENSURE_STATE(result); + nsRefPtr result = new nsVariant(); if (StringBeginsWith(src, NS_LITERAL_STRING("http://"))) src.Cut(0, 7); @@ -835,9 +832,7 @@ namespace places { navHistory->DispatchFrecencyChangedNotification(spec, newFrecency, guid, hidden, lastVisitDate); - nsCOMPtr result = - do_CreateInstance("@mozilla.org/variant;1"); - NS_ENSURE_STATE(result); + nsRefPtr result = new nsVariant(); rv = result->SetAsInt32(newFrecency); NS_ENSURE_SUCCESS(rv, rv); result.forget(_result); diff --git a/toolkit/components/places/nsNavHistoryQuery.cpp b/toolkit/components/places/nsNavHistoryQuery.cpp index 936a53590b0c..04b21ca4179e 100644 --- a/toolkit/components/places/nsNavHistoryQuery.cpp +++ b/toolkit/components/places/nsNavHistoryQuery.cpp @@ -18,6 +18,7 @@ #include "nsNetUtil.h" #include "nsTArray.h" #include "prprf.h" +#include "nsVariant.h" using namespace mozilla; @@ -1130,13 +1131,11 @@ NS_IMETHODIMP nsNavHistoryQuery::GetTags(nsIVariant **aTags) { NS_ENSURE_ARG_POINTER(aTags); - nsresult rv; - nsCOMPtr out = do_CreateInstance(NS_VARIANT_CONTRACTID, - &rv); - NS_ENSURE_SUCCESS(rv, rv); + nsRefPtr out = new nsVariant(); uint32_t arrayLen = mTags.Length(); + nsresult rv; if (arrayLen == 0) rv = out->SetAsEmptyArray(); else { diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp index 7666623fb298..6ea803e1c85a 100644 --- a/toolkit/xre/nsUpdateDriver.cpp +++ b/toolkit/xre/nsUpdateDriver.cpp @@ -11,7 +11,7 @@ #include "nsAppRunner.h" #include "nsIWritablePropertyBag.h" #include "nsIFile.h" -#include "nsIVariant.h" +#include "nsVariant.h" #include "nsCOMPtr.h" #include "nsString.h" #include "prproces.h" @@ -691,12 +691,7 @@ SetOSApplyToDir(nsIUpdate* update, const nsACString& osApplyToDir) return; } - nsCOMPtr variant = - do_CreateInstance("@mozilla.org/variant;1", &rv); - if (NS_FAILED(rv)) { - return; - } - + nsRefPtr variant = new nsVariant(); rv = variant->SetAsACString(osApplyToDir); if (NS_FAILED(rv)) { return; diff --git a/uriloader/exthandler/win/nsMIMEInfoWin.cpp b/uriloader/exthandler/win/nsMIMEInfoWin.cpp index eaafa1abecfc..184b631c6b69 100644 --- a/uriloader/exthandler/win/nsMIMEInfoWin.cpp +++ b/uriloader/exthandler/win/nsMIMEInfoWin.cpp @@ -7,7 +7,6 @@ #include "nsArrayEnumerator.h" #include "nsCOMArray.h" #include "nsIFile.h" -#include "nsIVariant.h" #include "nsMIMEInfoWin.h" #include "nsNetUtil.h" #include @@ -22,6 +21,7 @@ #include "nsOSHelperAppService.h" #include "nsUnicharUtils.h" #include "nsITextToSubURI.h" +#include "nsVariant.h" #define RUNDLL32_EXE L"\\rundll32.exe" @@ -172,15 +172,13 @@ nsMIMEInfoWin::GetEnumerator(nsISimpleEnumerator* *_retval) static nsresult GetIconURLVariant(nsIFile* aApplication, nsIVariant* *_retval) { - nsresult rv = CallCreateInstance("@mozilla.org/variant;1", _retval); - if (NS_FAILED(rv)) - return rv; nsAutoCString fileURLSpec; NS_GetURLSpecFromFile(aApplication, fileURLSpec); nsAutoCString iconURLSpec; iconURLSpec.AssignLiteral("moz-icon://"); iconURLSpec += fileURLSpec; - nsCOMPtr writable(do_QueryInterface(*_retval)); + nsRefPtr writable(new nsVariant()); writable->SetAsAUTF8String(iconURLSpec); + writable.forget(_retval); return NS_OK; } From f12076ac2e65b02dbb27145fd3364d455dda0c48 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Wed, 7 Oct 2015 09:04:39 -0700 Subject: [PATCH 041/189] Backed out 5 changesets (bug 1209574) for android tpn bustage Backed out changeset fb1f06793a67 (bug 1209574) Backed out changeset 5f0b32b1acc4 (bug 1209574) Backed out changeset 657332ea4f59 (bug 1209574) Backed out changeset 9d2c7ed9cd87 (bug 1209574) Backed out changeset 8376124b6a0c (bug 1209574) --- build/annotationProcessors/CodeGenerator.java | 27 +- mobile/android/base/GeckoAppShell.java | 46 +++- mobile/android/base/GeckoEditable.java | 70 ++---- .../android/base/GeckoEditableListener.java | 4 - mobile/android/base/GeckoInputConnection.java | 5 +- mobile/android/base/GeckoView.java | 83 +------ .../InputConnectionHandler.java} | 7 +- mobile/android/base/gfx/LayerView.java | 65 +++++ mobile/android/base/moz.build | 2 +- widget/android/GeneratedJNIWrappers.cpp | 84 +++---- widget/android/GeneratedJNIWrappers.h | 231 ++++++------------ widget/android/nsWindow.cpp | 63 ++--- widget/android/nsWindow.h | 3 - 13 files changed, 274 insertions(+), 416 deletions(-) rename mobile/android/base/{InputConnectionListener.java => gfx/InputConnectionHandler.java} (84%) diff --git a/build/annotationProcessors/CodeGenerator.java b/build/annotationProcessors/CodeGenerator.java index b36d1602eb71..0bba34e3af0a 100644 --- a/build/annotationProcessors/CodeGenerator.java +++ b/build/annotationProcessors/CodeGenerator.java @@ -66,37 +66,15 @@ public class CodeGenerator { return (includeScope ? clsName + "::" : "") + uniqueName + "_t"; } - /** - * Return the C++ type name for this class or any class within the chain - * of declaring classes, if the target class matches the given type. - * - * Return null if the given type does not match any class searched. - */ - private String getMatchingClassType(final Class type) { - Class cls = this.cls; - String clsName = this.clsName; - - while (cls != null) { - if (type == cls) { - return clsName; - } - cls = cls.getDeclaringClass(); - clsName = clsName.substring(0, Math.max(0, clsName.lastIndexOf("::"))); - } - return null; - } - private String getNativeParameterType(Class type, AnnotationInfo info) { - final String clsName = getMatchingClassType(type); - if (clsName != null) { + if (type == cls) { return Utils.getUnqualifiedName(clsName) + "::Param"; } return Utils.getNativeParameterType(type, info); } private String getNativeReturnType(Class type, AnnotationInfo info) { - final String clsName = getMatchingClassType(type); - if (clsName != null) { + if (type == cls) { return Utils.getUnqualifiedName(clsName) + "::LocalRef"; } return Utils.getNativeReturnType(type, info); @@ -392,7 +370,6 @@ public class CodeGenerator { if (isStatic && isFinal && (type.isPrimitive() || type == String.class)) { Object val = null; try { - field.setAccessible(true); val = field.get(null); } catch (final IllegalAccessException e) { } diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 93ba98b8635c..8395f75c9b05 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -132,6 +132,8 @@ public class GeckoAppShell // We have static members only. private GeckoAppShell() { } + private static GeckoEditableListener editableListener; + private static final CrashHandler CRASH_HANDLER = new CrashHandler() { @Override protected String getAppPackageName() { @@ -315,17 +317,28 @@ public class GeckoAppShell } } - private static GeckoView sLayerView; + private static LayerView sLayerView; - public static void setLayerView(GeckoView lv) { + 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 GeckoView getLayerView() { + public static LayerView getLayerView() { return sLayerView; } @@ -406,6 +419,31 @@ public class GeckoAppShell 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; @@ -2379,7 +2417,7 @@ public class GeckoAppShell private static boolean sImeWasEnabledOnLastResize = false; public static void viewSizeChanged() { - GeckoView v = getLayerView(); + LayerView v = getLayerView(); if (v == null) { return; } diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java index be7a98f6c3ee..1d0b7203491e 100644 --- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -16,7 +16,7 @@ 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.InputConnectionHandler; import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.util.GeckoEventListener; import org.mozilla.gecko.util.ThreadUtils; @@ -348,12 +348,7 @@ final class GeckoEditable } } - @WrapForJNI GeckoEditable() { - if (DEBUG) { - // Called by nsWindow. - ThreadUtils.assertOnGeckoThread(); - } mActionQueue = new ActionQueue(); mSavedSelectionStart = -1; mUpdateGecko = true; @@ -366,41 +361,12 @@ final class GeckoEditable Editable.class.getClassLoader(), PROXY_INTERFACES, this); + LayerView v = GeckoAppShell.getLayerView(); + mListener = GeckoInputConnection.create(v, this); + mIcRunHandler = mIcPostHandler = ThreadUtils.getUiHandler(); } - @WrapForJNI - /* package */ void onViewChange(final GeckoView v) { - if (DEBUG) { - // Called by nsWindow. - ThreadUtils.assertOnGeckoThread(); - Log.d(LOGTAG, "onViewChange(" + v + ")"); - } - - final GeckoEditableListener newListener = GeckoInputConnection.create(v, this); - geckoPostToIc(new Runnable() { - @Override - public void run() { - if (DEBUG) { - Log.d(LOGTAG, "onViewChange (set listener)"); - } - // Make sure there are no other things going on - mActionQueue.syncWithGecko(); - mListener = newListener; - } - }); - - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - if (DEBUG) { - Log.d(LOGTAG, "onViewChange (set IC)"); - } - v.setInputConnectionListener((InputConnectionListener) newListener); - } - }); - } - private boolean onIcThread() { return mIcRunHandler.getLooper() == Looper.myLooper(); } @@ -803,7 +769,7 @@ final class GeckoEditable } } - @WrapForJNI @Override + @Override public void notifyIME(final int type) { if (DEBUG) { // GeckoEditableListener methods should all be called from the Gecko thread @@ -879,12 +845,12 @@ final class GeckoEditable } } - @WrapForJNI @Override + @Override public void notifyIMEContext(final int state, final String typeHint, - final String modeHint, final String actionHint) { + 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. 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 + "\")"); @@ -892,12 +858,22 @@ final class GeckoEditable geckoPostToIc(new Runnable() { @Override public void run() { - mListener.notifyIMEContext(state, typeHint, modeHint, actionHint); + // Make sure there are no other things going on + mActionQueue.syncWithGecko(); + // Set InputConnectionHandler in notifyIMEContext because + // GeckoInputConnection.notifyIMEContext calls restartInput() which will invoke + // InputConnectionHandler.onCreateInputConnection + LayerView v = GeckoAppShell.getLayerView(); + if (v != null) { + mListener = GeckoInputConnection.create(v, GeckoEditable.this); + v.setInputConnectionHandler((InputConnectionHandler)mListener); + mListener.notifyIMEContext(state, typeHint, modeHint, actionHint); + } } }); } - @WrapForJNI @Override + @Override public void onSelectionChange(final int start, final int end) { if (DEBUG) { // GeckoEditableListener methods should all be called from the Gecko thread @@ -953,9 +929,9 @@ final class GeckoEditable TextUtils.regionMatches(mText, start, newText, 0, oldEnd - start); } - @WrapForJNI @Override + @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(); diff --git a/mobile/android/base/GeckoEditableListener.java b/mobile/android/base/GeckoEditableListener.java index a68ba0d62137..f8b9daa5b781 100644 --- a/mobile/android/base/GeckoEditableListener.java +++ b/mobile/android/base/GeckoEditableListener.java @@ -5,17 +5,13 @@ 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; diff --git a/mobile/android/base/GeckoInputConnection.java b/mobile/android/base/GeckoInputConnection.java index eda840d69d63..1e4d5ff2d64c 100644 --- a/mobile/android/base/GeckoInputConnection.java +++ b/mobile/android/base/GeckoInputConnection.java @@ -11,6 +11,7 @@ import java.lang.reflect.Proxy; import java.util.concurrent.SynchronousQueue; import org.mozilla.gecko.AppConstants.Versions; +import org.mozilla.gecko.gfx.InputConnectionHandler; import org.mozilla.gecko.util.Clipboard; import org.mozilla.gecko.util.GamepadUtils; import org.mozilla.gecko.util.ThreadUtils; @@ -39,7 +40,7 @@ import android.view.inputmethod.InputMethodManager; class GeckoInputConnection extends BaseInputConnection - implements InputConnectionListener, GeckoEditableListener { + implements InputConnectionHandler, GeckoEditableListener { private static final boolean DEBUG = false; protected static final String LOGTAG = "GeckoInputConnection"; @@ -1006,7 +1007,7 @@ final class DebugGeckoInputConnection public static GeckoEditableListener create(View targetView, GeckoEditableClient editable) { final Class[] PROXY_INTERFACES = { InputConnection.class, - InputConnectionListener.class, + InputConnectionHandler.class, GeckoEditableListener.class }; DebugGeckoInputConnection dgic = new DebugGeckoInputConnection(targetView, editable); diff --git a/mobile/android/base/GeckoView.java b/mobile/android/base/GeckoView.java index e877d8d437f2..c3225d64e171 100644 --- a/mobile/android/base/GeckoView.java +++ b/mobile/android/base/GeckoView.java @@ -30,14 +30,10 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.TypedArray; import android.os.Bundle; -import android.os.Handler; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; -import android.view.KeyEvent; import android.view.View; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; public class GeckoView extends LayerView implements ContextGetter { @@ -48,8 +44,6 @@ public class GeckoView extends LayerView private ChromeDelegate mChromeDelegate; private ContentDelegate mContentDelegate; - private InputConnectionListener mInputConnectionListener; - private final GeckoEventListener mGeckoEventListener = new GeckoEventListener() { @Override public void handleMessage(final String event, final JSONObject message) { @@ -115,7 +109,7 @@ public class GeckoView extends LayerView @WrapForJNI private static final class Window extends JNIObject { - static native void open(Window instance, GeckoView view, int width, int height); + static native void open(Window instance, int width, int height); static native void setLayerClient(Object client); @Override protected native void disposeNative(); } @@ -225,11 +219,10 @@ public class GeckoView extends LayerView final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) { - Window.open(window, this, metrics.widthPixels, metrics.heightPixels); + Window.open(window, metrics.widthPixels, metrics.heightPixels); } else { GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY, Window.class, - "open", window, GeckoView.class, this, - metrics.widthPixels, metrics.heightPixels); + "open", window, metrics.widthPixels, metrics.heightPixels); } } @@ -240,76 +233,6 @@ public class GeckoView extends LayerView window.disposeNative(); } - /* package */ void setInputConnectionListener(final InputConnectionListener icl) { - mInputConnectionListener = icl; - } - - @Override - public Handler getHandler() { - if (mInputConnectionListener != null) { - return mInputConnectionListener.getHandler(super.getHandler()); - } - return super.getHandler(); - } - - @Override - public InputConnection onCreateInputConnection(EditorInfo outAttrs) { - if (mInputConnectionListener != null) { - return mInputConnectionListener.onCreateInputConnection(outAttrs); - } - return null; - } - - @Override - public boolean onKeyPreIme(int keyCode, KeyEvent event) { - if (super.onKeyPreIme(keyCode, event)) { - return true; - } - return mInputConnectionListener != null && - mInputConnectionListener.onKeyPreIme(keyCode, event); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (super.onKeyUp(keyCode, event)) { - return true; - } - return mInputConnectionListener != null && - mInputConnectionListener.onKeyUp(keyCode, event); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (super.onKeyDown(keyCode, event)) { - return true; - } - return mInputConnectionListener != null && - mInputConnectionListener.onKeyDown(keyCode, event); - } - - @Override - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - if (super.onKeyLongPress(keyCode, event)) { - return true; - } - return mInputConnectionListener != null && - mInputConnectionListener.onKeyLongPress(keyCode, event); - } - - @Override - public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { - if (super.onKeyMultiple(keyCode, repeatCount, event)) { - return true; - } - return mInputConnectionListener != null && - mInputConnectionListener.onKeyMultiple(keyCode, repeatCount, event); - } - - /* package */ boolean isIMEEnabled() { - return mInputConnectionListener != null && - mInputConnectionListener.isIMEEnabled(); - } - /** * Add a Browser to the GeckoView container. * @param url The URL resource to load into the new Browser. diff --git a/mobile/android/base/InputConnectionListener.java b/mobile/android/base/gfx/InputConnectionHandler.java similarity index 84% rename from mobile/android/base/InputConnectionListener.java rename to mobile/android/base/gfx/InputConnectionHandler.java index baddc4ed25cc..9b3ca381b5a4 100644 --- a/mobile/android/base/InputConnectionListener.java +++ b/mobile/android/base/gfx/InputConnectionHandler.java @@ -2,17 +2,14 @@ * 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; +package org.mozilla.gecko.gfx; import android.os.Handler; import android.view.KeyEvent; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; -/** - * Interface for interacting with GeckoInputConnection from GeckoView. - */ -interface InputConnectionListener +public interface InputConnectionHandler { Handler getHandler(Handler defHandler); InputConnection onCreateInputConnection(EditorInfo outAttrs); diff --git a/mobile/android/base/gfx/LayerView.java b/mobile/android/base/gfx/LayerView.java index 846a81de89ed..ecd54eecea6e 100644 --- a/mobile/android/base/gfx/LayerView.java +++ b/mobile/android/base/gfx/LayerView.java @@ -31,6 +31,7 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.SurfaceTexture; +import android.os.Handler; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; @@ -40,6 +41,8 @@ import android.view.SurfaceView; import android.view.TextureView; import android.view.View; import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; import android.view.InputDevice; import android.widget.LinearLayout; import android.widget.ScrollView; @@ -54,6 +57,7 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener private PanZoomController mPanZoomController; private DynamicToolbarAnimator mToolbarAnimator; private final GLController mGLController; + private InputConnectionHandler mInputConnectionHandler; private LayerRenderer mRenderer; /* Must be a PAINT_xxx constant */ private int mPaintState; @@ -132,6 +136,7 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener mToolbarAnimator = mLayerClient.getDynamicToolbarAnimator(); mRenderer = new LayerRenderer(this); + mInputConnectionHandler = null; setFocusable(true); setFocusableInTouchMode(true); @@ -359,11 +364,71 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener mLayerClient.setIsRTL(aIsRTL); } + public void setInputConnectionHandler(InputConnectionHandler inputConnectionHandler) { + mInputConnectionHandler = inputConnectionHandler; + } + + @Override + public Handler getHandler() { + if (mInputConnectionHandler != null) + return mInputConnectionHandler.getHandler(super.getHandler()); + return super.getHandler(); + } + + @Override + public InputConnection onCreateInputConnection(EditorInfo outAttrs) { + if (mInputConnectionHandler != null) + return mInputConnectionHandler.onCreateInputConnection(outAttrs); + return null; + } + + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyPreIme(keyCode, event)) { + return true; + } + return false; + } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mPanZoomController != null && mPanZoomController.onKeyEvent(event)) { return true; } + if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyDown(keyCode, event)) { + return true; + } + return false; + } + + @Override + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyLongPress(keyCode, event)) { + return true; + } + return false; + } + + @Override + public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { + if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyMultiple(keyCode, repeatCount, event)) { + return true; + } + return false; + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyUp(keyCode, event)) { + return true; + } + return false; + } + + public boolean isIMEEnabled() { + if (mInputConnectionHandler != null) { + return mInputConnectionHandler.isIMEEnabled(); + } return false; } diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index d393c5c928d8..8a09891e005b 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -288,6 +288,7 @@ gbjar.sources += [ 'gfx/GeckoLayerClient.java', 'gfx/GLController.java', 'gfx/ImmutableViewportMetrics.java', + 'gfx/InputConnectionHandler.java', 'gfx/IntSize.java', 'gfx/JavaPanZoomController.java', 'gfx/Layer.java', @@ -380,7 +381,6 @@ gbjar.sources += [ 'home/TopSitesThumbnailView.java', 'home/TransitionAwareCursorLoaderCallbacks.java', 'home/TwoLinePageRow.java', - 'InputConnectionListener.java', 'InputMethods.java', 'IntentHelper.java', 'javaaddons/JavaAddonManager.java', diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index a909126962f9..5b372dd7581d 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -542,6 +542,30 @@ auto GeckoAppShell::NotifyDefaultPrevented(bool a0) -> void return mozilla::jni::Method::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::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::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::Call(nullptr, nullptr, a0, a1, a2, a3); +} + constexpr char GeckoAppShell::NotifyWakeLockChanged_t::name[]; constexpr char GeckoAppShell::NotifyWakeLockChanged_t::signature[]; @@ -710,58 +734,6 @@ auto GeckoAppShell::VibrateA(mozilla::jni::LongArray::Param a0, int32_t a1) -> v return mozilla::jni::Method::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::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::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::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::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::Call(this, nullptr, a0, a1, a2, a3); -} - -constexpr char GeckoEditable::OnViewChange_t::name[]; -constexpr char GeckoEditable::OnViewChange_t::signature[]; - -auto GeckoEditable::OnViewChange(mozilla::jni::Object::Param a0) const -> void -{ - return mozilla::jni::Method::Call(this, nullptr, a0); -} - -constexpr char GeckoEditableListener::name[]; - constexpr char GeckoJavaSampler::name[]; constexpr char GeckoJavaSampler::GetFrameNameJavaProfilingWrapper_t::name[]; @@ -1535,6 +1507,14 @@ auto SQLiteBridgeException::New(mozilla::jni::String::Param a0) -> SQLiteBridgeE return mozilla::jni::Constructor::Call(nullptr, nullptr, a0); } +constexpr char SQLiteBridgeException::SerialVersionUID_t::name[]; +constexpr char SQLiteBridgeException::SerialVersionUID_t::signature[]; + +auto SQLiteBridgeException::SerialVersionUID() -> int64_t +{ + return mozilla::jni::Field::Get(nullptr, nullptr); +} + constexpr char Clipboard::name[]; constexpr char Clipboard::ClearText_t::name[]; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index 330d8785fb2e..b3f88b357732 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -1295,6 +1295,66 @@ public: 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; @@ -1686,158 +1746,6 @@ public: }; -class GeckoEditable : public mozilla::jni::Class -{ -public: - typedef mozilla::jni::Ref Ref; - typedef mozilla::jni::LocalRef LocalRef; - typedef mozilla::jni::GlobalRef GlobalRef; - typedef const mozilla::jni::Param& 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[] = ""; - 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; - -public: - struct OnViewChange_t { - typedef GeckoEditable Owner; - typedef void ReturnType; - typedef void SetterType; - typedef mozilla::jni::Args< - mozilla::jni::Object::Param> Args; - static constexpr char name[] = "onViewChange"; - static constexpr char signature[] = - "(Lorg/mozilla/gecko/GeckoView;)V"; - static const bool isStatic = false; - static const bool isMultithreaded = false; - static const mozilla::jni::ExceptionMode exceptionMode = - mozilla::jni::ExceptionMode::ABORT; - }; - - auto OnViewChange(mozilla::jni::Object::Param) const -> void; - -}; - -class GeckoEditableListener : public mozilla::jni::Class -{ -public: - typedef mozilla::jni::Ref Ref; - typedef mozilla::jni::LocalRef LocalRef; - typedef mozilla::jni::GlobalRef GlobalRef; - typedef const mozilla::jni::Param& 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 { public: @@ -2475,12 +2383,11 @@ public: typedef void SetterType; typedef mozilla::jni::Args< Window::Param, - GeckoView::Param, int32_t, int32_t> Args; static constexpr char name[] = "open"; static constexpr char signature[] = - "(Lorg/mozilla/gecko/GeckoView$Window;Lorg/mozilla/gecko/GeckoView;II)V"; + "(Lorg/mozilla/gecko/GeckoView$Window;II)V"; static const bool isStatic = true; static const bool isMultithreaded = true; static const mozilla::jni::ExceptionMode exceptionMode = @@ -3740,7 +3647,21 @@ public: static auto New(mozilla::jni::String::Param) -> SQLiteBridgeException::LocalRef; public: - static const int64_t SerialVersionUID = 1; + struct SerialVersionUID_t { + typedef SQLiteBridgeException Owner; + typedef int64_t ReturnType; + typedef int64_t SetterType; + typedef mozilla::jni::Args<> Args; + static constexpr char name[] = "serialVersionUID"; + static constexpr char signature[] = + "J"; + static const bool isStatic = true; + static const bool isMultithreaded = true; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + static auto SerialVersionUID() -> int64_t; }; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 6ac04567079c..f1e21b5376aa 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -186,7 +186,6 @@ public: // Create and attach a window. static void Open(const jni::ClassObject::LocalRef& cls, GeckoView::Window::Param gvWindow, - GeckoView::Param view, int32_t width, int32_t height); // Set the active layer client object @@ -201,7 +200,6 @@ public: void nsWindow::Natives::Open(const jni::ClassObject::LocalRef& cls, GeckoView::Window::Param gvWindow, - GeckoView::Param view, int32_t width, int32_t height) { MOZ_ASSERT(NS_IsMainThread()); @@ -212,10 +210,6 @@ nsWindow::Natives::Open(const jni::ClassObject::LocalRef& cls, if (gGeckoViewWindow) { // Should have been created the first time. MOZ_ASSERT(gGeckoViewWindow->mNatives); - - // Associate our previous GeckoEditable with the new GeckoView. - gGeckoViewWindow->mEditable->OnViewChange(view); - AttachNative(GeckoView::Window::LocalRef(cls.Env(), gvWindow), gGeckoViewWindow->mNatives.get()); return; @@ -255,11 +249,6 @@ nsWindow::Natives::Open(const jni::ClassObject::LocalRef& cls, gGeckoViewWindow = static_cast(widget.get()); gGeckoViewWindow->mNatives = mozilla::MakeUnique(gGeckoViewWindow); - - // Create GeckoEditable for the new nsWindow/GeckoView pair. - gGeckoViewWindow->mEditable = GeckoEditable::New(); - gGeckoViewWindow->mEditable->OnViewChange(view); - AttachNative(GeckoView::Window::LocalRef(cls.Env(), gvWindow), gGeckoViewWindow->mNatives.get()); } @@ -1022,8 +1011,8 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae) break; case AndroidGeckoEvent::IME_EVENT: - gGeckoViewWindow->UserActivity(); - gGeckoViewWindow->OnIMEEvent(ae); + win->UserActivity(); + win->OnIMEEvent(ae); break; case AndroidGeckoEvent::IME_KEY_EVENT: @@ -1819,7 +1808,7 @@ public: nsRefPtr nsWindow::GetIMEComposition() { - MOZ_ASSERT(this == FindTopLevel()); + MOZ_ASSERT(this == TopWindow()); return mozilla::IMEStateManager::GetTextCompositionFor(this); } @@ -1895,14 +1884,14 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) NotifyIMEOfTextChange(notification); FlushIMEChanges(); } - mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); + GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); return; } else if (ae->Action() == AndroidGeckoEvent::IME_UPDATE_CONTEXT) { - mEditable->NotifyIMEContext(mInputContext.mIMEState.mEnabled, - mInputContext.mHTMLInputType, - mInputContext.mHTMLInputInputmode, - mInputContext.mActionHint); + GeckoAppShell::NotifyIMEContext(mInputContext.mIMEState.mEnabled, + mInputContext.mHTMLInputType, + mInputContext.mHTMLInputInputmode, + mInputContext.mActionHint); mIMEUpdatingContext = false; return; } @@ -1912,7 +1901,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) if (ae->Action() == AndroidGeckoEvent::IME_SYNCHRONIZE || ae->Action() == AndroidGeckoEvent::IME_COMPOSE_TEXT || ae->Action() == AndroidGeckoEvent::IME_REPLACE_TEXT) { - mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); + GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); } return; } @@ -1927,7 +1916,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) case AndroidGeckoEvent::IME_SYNCHRONIZE: { FlushIMEChanges(); - mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); + GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); } break; @@ -1972,8 +1961,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) } mIMEKeyEvents.Clear(); FlushIMEChanges(); - mEditable->NotifyIME( - GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); + GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); // Break out of the switch block break; } @@ -2024,7 +2012,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) } FlushIMEChanges(); - mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT); + GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); } break; @@ -2188,13 +2176,13 @@ nsWindow::UserActivity() nsresult nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification) { - MOZ_ASSERT(this == FindTopLevel()); + MOZ_ASSERT(this == TopWindow()); switch (aIMENotification.mMessage) { case REQUEST_TO_COMMIT_COMPOSITION: //ALOGIME("IME: REQUEST_TO_COMMIT_COMPOSITION: s=%d", aState); RemoveIMEComposition(); - mEditable->NotifyIME(REQUEST_TO_COMMIT_COMPOSITION); + GeckoAppShell::NotifyIME(REQUEST_TO_COMMIT_COMPOSITION); return NS_OK; case REQUEST_TO_CANCEL_COMPOSITION: @@ -2212,12 +2200,12 @@ nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification) DispatchEvent(&compositionCommitEvent); } - mEditable->NotifyIME(REQUEST_TO_CANCEL_COMPOSITION); + GeckoAppShell::NotifyIME(REQUEST_TO_CANCEL_COMPOSITION); return NS_OK; case NOTIFY_IME_OF_FOCUS: ALOGIME("IME: NOTIFY_IME_OF_FOCUS"); - mEditable->NotifyIME(NOTIFY_IME_OF_FOCUS); + GeckoAppShell::NotifyIME(NOTIFY_IME_OF_FOCUS); return NS_OK; case NOTIFY_IME_OF_BLUR: @@ -2228,7 +2216,7 @@ nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification) // event back to Gecko. That is where we unmask event handling mIMEMaskEventsCount++; - mEditable->NotifyIME(NOTIFY_IME_OF_BLUR); + GeckoAppShell::NotifyIME(NOTIFY_IME_OF_BLUR); return NS_OK; case NOTIFY_IME_OF_SELECTION_CHANGE: @@ -2258,7 +2246,7 @@ nsWindow::SetInputContext(const InputContext& aContext, // Disable the Android keyboard on b2gdroid. return; #endif - nsWindow *top = FindTopLevel(); + nsWindow *top = TopWindow(); 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 @@ -2296,7 +2284,7 @@ nsWindow::SetInputContext(const InputContext& aContext, if (enabled == IMEState::ENABLED && aAction.UserMightRequestOpenVKB()) { // Don't reset keyboard when we should simply open the vkb - mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_OPEN_VKB); + GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_OPEN_VKB); return; } @@ -2312,7 +2300,7 @@ nsWindow::SetInputContext(const InputContext& aContext, NS_IMETHODIMP_(InputContext) nsWindow::GetInputContext() { - nsWindow *top = FindTopLevel(); + nsWindow *top = TopWindow(); if (top && this != top) { // We let the top window process SetInputContext, // so we should let it process GetInputContext as well. @@ -2372,8 +2360,8 @@ nsWindow::FlushIMEChanges() NS_ENSURE_TRUE_VOID(event.mReply.mContentsRoot == imeRoot.get()); } - mEditable->OnTextChange(event.mReply.mString, change.mStart, - change.mOldEnd, change.mNewEnd); + GeckoAppShell::NotifyIMEChange(event.mReply.mString, change.mStart, + change.mOldEnd, change.mNewEnd); } mIMETextChanges.Clear(); @@ -2385,8 +2373,9 @@ nsWindow::FlushIMEChanges() NS_ENSURE_TRUE_VOID(event.mSucceeded); NS_ENSURE_TRUE_VOID(event.mReply.mContentsRoot == imeRoot.get()); - mEditable->OnSelectionChange(int32_t(event.GetSelectionStart()), - int32_t(event.GetSelectionEnd())); + GeckoAppShell::NotifyIMEChange(EmptyString(), + int32_t(event.GetSelectionStart()), + int32_t(event.GetSelectionEnd()), -1); mIMESelectionChanged = false; } } @@ -2394,8 +2383,6 @@ nsWindow::FlushIMEChanges() 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"); diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h index 0247c81721a9..417562157eda 100644 --- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -49,9 +49,6 @@ public: // Object that implements native GeckoView calls; // nullptr for nsWindows that were not opened from GeckoView. mozilla::UniquePtr 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(); From d31f5415b2259723fcce2a6c7d6a0d38a9907453 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Wed, 7 Oct 2015 09:05:01 -0700 Subject: [PATCH 042/189] Backed out 2 changesets (bug 1200426) for android tpn bustage Backed out changeset 4dcc2fb45208 (bug 1200426) Backed out changeset 2dea192c7f33 (bug 1200426) --- mobile/android/base/GeckoEvent.java | 12 +++++++++++ mobile/android/base/GeckoThread.java | 27 +++++++------------------ mobile/android/base/GeckoView.java | 11 ++-------- widget/android/AndroidJavaWrappers.cpp | 9 +++++++++ widget/android/AndroidJavaWrappers.h | 10 +++++++++ widget/android/GeneratedJNINatives.h | 6 +----- widget/android/GeneratedJNIWrappers.cpp | 3 --- widget/android/GeneratedJNIWrappers.h | 16 --------------- widget/android/nsAppShell.cpp | 11 ++++++++++ widget/android/nsWindow.cpp | 8 -------- 10 files changed, 52 insertions(+), 61 deletions(-) diff --git a/mobile/android/base/GeckoEvent.java b/mobile/android/base/GeckoEvent.java index 54c7cc02cef4..e8de7251a8d4 100644 --- a/mobile/android/base/GeckoEvent.java +++ b/mobile/android/base/GeckoEvent.java @@ -73,6 +73,7 @@ public class GeckoEvent { KEY_EVENT(1), MOTION_EVENT(2), SENSOR_EVENT(3), + PROCESS_OBJECT(4), LOCATION_EVENT(5), IME_EVENT(6), SIZE_CHANGED(8), @@ -158,6 +159,8 @@ public class GeckoEvent { public static final int ACTION_GAMEPAD_BUTTON = 1; public static final int ACTION_GAMEPAD_AXES = 2; + public static final int ACTION_OBJECT_LAYER_CLIENT = 1; + private final int mType; private int mAction; private boolean mAckNeeded; @@ -219,6 +222,8 @@ public class GeckoEvent { private float mGamepadButtonValue; private float[] mGamepadValues; + private Object mObject; + private GeckoEvent(NativeGeckoEvent event) { mType = event.value; } @@ -579,6 +584,13 @@ public class GeckoEvent { return event; } + public static GeckoEvent createObjectEvent(final int action, final Object object) { + GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.PROCESS_OBJECT); + event.mAction = action; + event.mObject = object; + return event; + } + public static GeckoEvent createLocationEvent(Location l) { GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOCATION_EVENT); event.mLocation = l; diff --git a/mobile/android/base/GeckoThread.java b/mobile/android/base/GeckoThread.java index c3907e07005c..4b15a81d28ab 100644 --- a/mobile/android/base/GeckoThread.java +++ b/mobile/android/base/GeckoThread.java @@ -165,15 +165,8 @@ public class GeckoThread extends Thread implements GeckoEventListener { private static void queueNativeCallLocked(final Class cls, final String methodName, final Object obj, final Object[] args, final State state) { - final ArrayList> argTypes = new ArrayList<>(args.length); - final ArrayList argValues = new ArrayList<>(args.length); - + final Class[] argTypes = new Class[args.length]; for (int i = 0; i < args.length; i++) { - if (args[i] instanceof Class) { - argTypes.add((Class) args[i]); - argValues.add(args[++i]); - continue; - } Class argType = args[i].getClass(); if (argType == Boolean.class) argType = Boolean.TYPE; else if (argType == Byte.class) argType = Byte.TYPE; @@ -183,24 +176,20 @@ public class GeckoThread extends Thread implements GeckoEventListener { else if (argType == Integer.class) argType = Integer.TYPE; else if (argType == Long.class) argType = Long.TYPE; else if (argType == Short.class) argType = Short.TYPE; - argTypes.add(argType); - argValues.add(args[i]); + argTypes[i] = argType; } final Method method; try { - method = cls.getDeclaredMethod( - methodName, argTypes.toArray(new Class[argTypes.size()])); + method = cls.getDeclaredMethod(methodName, argTypes); } catch (final NoSuchMethodException e) { throw new UnsupportedOperationException("Cannot find method", e); } if (QUEUED_CALLS.size() == 0 && isStateAtLeast(state)) { - invokeMethod(method, obj, argValues.toArray()); + invokeMethod(method, obj, args); return; } - - QUEUED_CALLS.add(new QueuedCall( - method, obj, argValues.toArray(), state)); + QUEUED_CALLS.add(new QueuedCall(method, obj, args, state)); } /** @@ -211,8 +200,7 @@ public class GeckoThread extends Thread implements GeckoEventListener { * run when Gecko is at or after RUNNING state. * @param cls Class that declares the static method. * @param methodName Name of the static method. - * @param args Args to call the static method with; to specify a parameter type, - * pass in a Class instance first, followed by the value. + * @param args Args to call the static method with. */ public static void queueNativeCallUntil(final State state, final Class cls, final String methodName, final Object... args) { @@ -237,8 +225,7 @@ public class GeckoThread extends Thread implements GeckoEventListener { * @param state The Gecko state in which the native call could be executed. * @param obj Object that declares the instance method. * @param methodName Name of the instance method. - * @param args Args to call the instance method with; to specify a parameter type, - * pass in a Class instance first, followed by the value. + * @param args Args to call the instance method with. */ public static void queueNativeCallUntil(final State state, final Object obj, final String methodName, final Object... args) { diff --git a/mobile/android/base/GeckoView.java b/mobile/android/base/GeckoView.java index c3225d64e171..f7cbadabd192 100644 --- a/mobile/android/base/GeckoView.java +++ b/mobile/android/base/GeckoView.java @@ -110,7 +110,6 @@ public class GeckoView extends LayerView @WrapForJNI private static final class Window extends JNIObject { static native void open(Window instance, int width, int height); - static native void setLayerClient(Object client); @Override protected native void disposeNative(); } @@ -143,14 +142,8 @@ public class GeckoView extends LayerView GeckoAppShell.setLayerView(this); initializeView(EventDispatcher.getInstance()); - - if (GeckoThread.isStateAtLeast(GeckoThread.State.JNI_READY)) { - Window.setLayerClient(getLayerClientObject()); - } else { - GeckoThread.queueNativeCallUntil(GeckoThread.State.JNI_READY, - Window.class, "setLayerClient", - Object.class, getLayerClientObject()); - } + GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent( + GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, getLayerClientObject())); // TODO: Fennec currently takes care of its own initialization, so this // flag is a hack used in Fennec to prevent GeckoView initialization. diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index caeedda2ae03..91b07d54b550 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -70,6 +70,7 @@ jfieldID AndroidGeckoEvent::jGamepadButtonField = 0; jfieldID AndroidGeckoEvent::jGamepadButtonPressedField = 0; jfieldID AndroidGeckoEvent::jGamepadButtonValueField = 0; jfieldID AndroidGeckoEvent::jGamepadValuesField = 0; +jfieldID AndroidGeckoEvent::jObjectField = 0; jclass AndroidPoint::jPointClass = 0; jfieldID AndroidPoint::jXField = 0; @@ -177,6 +178,7 @@ AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv) jGamepadButtonPressedField = geckoEvent.getField("mGamepadButtonPressed", "Z"); jGamepadButtonValueField = geckoEvent.getField("mGamepadButtonValue", "F"); jGamepadValuesField = geckoEvent.getField("mGamepadValues", "[F"); + jObjectField = geckoEvent.getField("mObject", "Ljava/lang/Object;"); } void @@ -471,6 +473,13 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj) mMetaState = jenv->GetIntField(jobj, jMetaStateField); break; + case PROCESS_OBJECT: { + const jobject obj = jenv->GetObjectField(jobj, jObjectField); + mObject.Init(obj, jenv); + jenv->DeleteLocalRef(obj); + break; + } + case LOCATION_EVENT: { jobject location = jenv->GetObjectField(jobj, jLocationField); mGeoPosition = AndroidLocation::CreateGeoPosition(jenv, location); diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h index ed4e06e69ac0..a84f6a27e24c 100644 --- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -571,6 +571,7 @@ public: float GamepadButtonValue() { return mGamepadButtonValue; } const nsTArray& GamepadValues() { return mGamepadValues; } int RequestId() { return mCount; } // for convenience + const AutoGlobalWrappedJavaObject& Object() { return mObject; } bool CanCoalesceWith(AndroidGeckoEvent* ae); WidgetTouchEvent MakeTouchEvent(nsIWidget* widget); MultiTouchInput MakeMultiTouchInput(nsIWidget* widget); @@ -623,6 +624,7 @@ protected: mozilla::layers::ScrollableLayerGuid mApzGuid; uint64_t mApzInputBlockId; nsEventStatus mApzEventStatus; + AutoGlobalWrappedJavaObject mObject; void ReadIntArray(nsTArray &aVals, JNIEnv *jenv, @@ -705,12 +707,15 @@ protected: static jfieldID jGamepadButtonValueField; static jfieldID jGamepadValuesField; + static jfieldID jObjectField; + public: enum { NATIVE_POKE = 0, KEY_EVENT = 1, MOTION_EVENT = 2, SENSOR_EVENT = 3, + PROCESS_OBJECT = 4, LOCATION_EVENT = 5, IME_EVENT = 6, SIZE_CHANGED = 8, @@ -781,6 +786,11 @@ public: ACTION_GAMEPAD_BUTTON = 1, ACTION_GAMEPAD_AXES = 2 }; + + enum { + ACTION_OBJECT_LAYER_CLIENT = 1, + dummy_object_enum_list_end + }; }; class nsJNIString : public nsString diff --git a/widget/android/GeneratedJNINatives.h b/widget/android/GeneratedJNINatives.h index ee351387834b..c372a34d2b00 100644 --- a/widget/android/GeneratedJNINatives.h +++ b/widget/android/GeneratedJNINatives.h @@ -93,11 +93,7 @@ public: mozilla::jni::MakeNativeMethod( mozilla::jni::NativeStub - ::template Wrap<&Impl::Open>), - - mozilla::jni::MakeNativeMethod( - mozilla::jni::NativeStub - ::template Wrap<&Impl::SetLayerClient>) + ::template Wrap<&Impl::Open>) }; }; diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index 5b372dd7581d..3623a5365e1c 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -985,9 +985,6 @@ constexpr char GeckoView::Window::DisposeNative_t::signature[]; constexpr char GeckoView::Window::Open_t::name[]; constexpr char GeckoView::Window::Open_t::signature[]; -constexpr char GeckoView::Window::SetLayerClient_t::name[]; -constexpr char GeckoView::Window::SetLayerClient_t::signature[]; - constexpr char PrefsHelper::name[]; constexpr char PrefsHelper::GetPrefsById_t::name[]; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index b3f88b357732..79eddff3d163 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -2394,22 +2394,6 @@ public: mozilla::jni::ExceptionMode::ABORT; }; -public: - struct SetLayerClient_t { - typedef Window Owner; - typedef void ReturnType; - typedef void SetterType; - typedef mozilla::jni::Args< - mozilla::jni::Object::Param> Args; - static constexpr char name[] = "setLayerClient"; - static constexpr char signature[] = - "(Ljava/lang/Object;)V"; - static const bool isStatic = true; - static const bool isMultithreaded = true; - static const mozilla::jni::ExceptionMode exceptionMode = - mozilla::jni::ExceptionMode::ABORT; - }; - public: template class Natives; }; diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp index a0dbc7b7c39d..8dbb9144bd53 100644 --- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -434,6 +434,17 @@ nsAppShell::LegacyGeckoEvent::Run() } break; + case AndroidGeckoEvent::PROCESS_OBJECT: { + + switch (curEvent->Action()) { + case AndroidGeckoEvent::ACTION_OBJECT_LAYER_CLIENT: + AndroidBridge::Bridge()->SetLayerClient( + widget::GeckoLayerClient::Ref::From(curEvent->Object().wrappedObject())); + break; + } + break; + } + case AndroidGeckoEvent::LOCATION_EVENT: { if (!gLocationCallback) break; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index f1e21b5376aa..56a31bbd8c8c 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -187,14 +187,6 @@ public: static void Open(const jni::ClassObject::LocalRef& cls, GeckoView::Window::Param gvWindow, int32_t width, int32_t height); - - // Set the active layer client object - static void SetLayerClient(jni::Object::Param client) - { - MOZ_ASSERT(NS_IsMainThread()); - AndroidBridge::Bridge()->SetLayerClient( - widget::GeckoLayerClient::Ref::From(client.Get())); - } }; void From bcfd4709718e7cfe1cdcd07246a9483fe00315f5 Mon Sep 17 00:00:00 2001 From: Eitan Isaacson Date: Wed, 7 Oct 2015 09:57:37 -0700 Subject: [PATCH 043/189] Bug 1211974 - Implement nsIObserver in SpeechDispatcherService. r=smaug --- .../synth/speechd/SpeechDispatcherService.cpp | 14 +++++++++++++- .../synth/speechd/SpeechDispatcherService.h | 5 ++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp index 765c17f8fc38..22df4bf6b387 100644 --- a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp @@ -277,7 +277,8 @@ speechd_cb(size_t msg_id, size_t client_id, SPDNotificationType state) NS_INTERFACE_MAP_BEGIN(SpeechDispatcherService) NS_INTERFACE_MAP_ENTRY(nsISpeechService) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechService) + NS_INTERFACE_MAP_ENTRY(nsIObserver) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(SpeechDispatcherService) @@ -440,6 +441,17 @@ SpeechDispatcherService::RegisterVoices() mInitialized = true; } +// nsIObserver + +NS_IMETHODIMP +SpeechDispatcherService::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) +{ + return NS_OK; +} + +// nsISpeechService + // TODO: Support SSML NS_IMETHODIMP SpeechDispatcherService::Speak(const nsAString& aText, const nsAString& aUri, diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h index 0bfa97fe16ea..997b6211e3e3 100644 --- a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h @@ -9,6 +9,7 @@ #include "mozilla/StaticPtr.h" #include "nsAutoPtr.h" +#include "nsIObserver.h" #include "nsISpeechService.h" #include "nsIThread.h" #include "nsRefPtrHashtable.h" @@ -22,11 +23,13 @@ namespace dom { class SpeechDispatcherCallback; class SpeechDispatcherVoice; -class SpeechDispatcherService final : public nsISpeechService +class SpeechDispatcherService final : public nsIObserver, + public nsISpeechService { friend class SpeechDispatcherCallback; public: NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIOBSERVER NS_DECL_NSISPEECHSERVICE SpeechDispatcherService(); From 7a28d6ab4397ba09ae0a283302f5aab3c799b010 Mon Sep 17 00:00:00 2001 From: Armen Zambrano Gasparnian Date: Tue, 6 Oct 2015 09:15:25 -0400 Subject: [PATCH 044/189] Bug 1210945 - Multi-tiered BBB task graphs + native TC tasks. r=chmanchester We add to TaskClusterArtifactFinderMixin the ability to support normal Buildbot Bridge triggered tasks + tasks that contain the property 'parent_task_id'. This allows for tasks to depend on tasks different than the one they're going to grab artifacts from. In this patch we support both the traditional approach plus the new model. We also add support for native TC tasks where properties.json is not available. With pure TC tasks we assume ['extra']['locations']['build'] being set and pointing to the installer artifact. --HG-- extra : commitid : GKcTU68PAoZ extra : rebase_source : 6f70be2748000bd85995861bee7a54d0a6a5933b --- .../mozharness/mozilla/taskcluster_helper.py | 67 +++++++++++++++---- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/testing/mozharness/mozharness/mozilla/taskcluster_helper.py b/testing/mozharness/mozharness/mozilla/taskcluster_helper.py index f584b6bac11c..2f2d75c3de97 100644 --- a/testing/mozharness/mozharness/mozilla/taskcluster_helper.py +++ b/testing/mozharness/mozharness/mozilla/taskcluster_helper.py @@ -156,23 +156,66 @@ class TaskClusterArtifactFinderMixin(object): return parent_task_id - def set_artifacts(self, task_id): - """ Sets installer, test and symbols URLs from the artifacts of a task. - - In this case we set: - self.installer_url - self.test_url (points to test_packages.json) - self.symbols_url - """ + def set_bbb_artifacts(self, task_id): + """ Find BBB artifacts through properties.json and set them. """ # The tasks which represent a buildbot job only uploads one artifact: # the properties.json file p = self.load_json_url( self.url_to_artifact(task_id, 'public/properties.json')) # Set importants artifacts for test jobs - self.installer_url = p['packageUrl'][0] if p.get('packageUrl') else None - self.test_url = p['testPackagesUrl'][0] if p.get('testPackagesUrl') else None - self.symbols_url = p['symbolsUrl'][0] if p.get('symbolsUrl') else None + self.set_artifacts( + p['packageUrl'][0] if p.get('packageUrl') else None, + p['testPackagesUrl'][0] if p.get('testPackagesUrl') else None, + p['symbolsUrl'][0] if p.get('symbolsUrl') else None + ) + + def set_artifacts(self, installer, tests, symbols): + """ Sets installer, test and symbols URLs from the artifacts of BBB based task.""" + self.installer_url, self.test_url, self.symbols_url = installer, tests, symbols + self.info('Set installer_url: %s' % self.installer_url) + self.info('Set test_url: %s' % self.test_url) + self.info('Set symbols_url: %s' % self.symbols_url) def set_parent_artifacts(self, child_task_id): - self.set_artifacts(self.find_parent_task_id(child_task_id)) + """ Find and set installer_url, test_url and symbols_url by querying TaskCluster. + + In Buildbot Bridge's normal behaviour we can find the artifacts by inspecting + a child's taskId, determine the task in which it depends on and find the uploaded + artifacts. + + In order to support multi-tiered task graph scheduling for BBB triggered tasks, + we remove the assumption that the task which depends on is the one from which we + find the artifacts we need. Instead, we can set a parent_task_id which points to the + tasks from which to retrieve the artifacts. This decouples task dependency from task + from which to grab the artifacts. + + In-tree triggered BBB tasks do not use parent_task_id, once there is efforts to move + the scheduling into tree we can make parent_task_id as the only method. + + """ + # Task definition + child_task = self.get_task(child_task_id) + + if child_task['payload']['properties'].get('parent_task_id'): + # parent_task_id is used to point to the task from which to grab artifacts + # rather than the one we depend on + parent_id = child_task['payload']['properties']['parent_task_id'] + + # Find out where the parent task uploaded the build + parent_task = self.get_task(parent_id) + + if parent_task['extra'].get('locations'): + # Build tasks generated under TC specify where they upload their builds + installer_path = parent_task['extra']['locations']['build'] + + self.set_artifacts( + self.url_to_artifact(parent_id, installer_path), + self.url_to_artifact(parent_id, 'public/build/test_packages.json'), + self.url_to_artifact(parent_id, 'public/build/target.crashreporter-symbols.zip') + ) + else: + self.set_bbb_artifacts(parent_id) + else: + parent_id = self.find_parent_task_id(child_task_id) + self.set_bbb_artifacts(parent_id) From 1f22d8279670a3c7928df1df2ae5df6e73b1f42f Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Wed, 7 Oct 2015 18:22:25 +0100 Subject: [PATCH 045/189] Bug 1211949 - check for allocation failure. r=nbp --- js/src/vm/ObjectGroup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 17e6453a82f2..cdce0a46420c 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -1335,7 +1335,7 @@ ObjectGroup::newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_ RootedPlainObject obj(cx, NewObjectWithGroup(cx, group, allocKind, newKind)); - if (!obj->setLastProperty(cx, shape)) + if (!obj || !obj->setLastProperty(cx, shape)) return nullptr; for (size_t i = 0; i < nproperties; i++) From ffaf1cb7ccfb6164ab0b4fa137098ddbefbaba19 Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Wed, 7 Oct 2015 18:22:28 +0100 Subject: [PATCH 046/189] Bug 1209497 - OOM-crash if a consistent object table is impossible. r=jandem --- js/src/vm/ObjectGroup.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index cdce0a46420c..5d0739a79da8 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -1459,9 +1459,13 @@ ObjectGroupCompartment::replaceAllocationSiteGroup(JSScript* script, jsbytecode* key.kind = kind; AllocationSiteTable::Ptr p = allocationSiteTable->lookup(key); - MOZ_ASSERT(p); + MOZ_RELEASE_ASSERT(p); allocationSiteTable->remove(p); - allocationSiteTable->putNew(key, group); + { + AutoEnterOOMUnsafeRegion oomUnsafe; + if (!allocationSiteTable->putNew(key, group)) + oomUnsafe.crash("Inconsistent object table"); + } } /* static */ ObjectGroup* @@ -1596,7 +1600,7 @@ ObjectGroupCompartment::removeDefaultNewGroup(const Class* clasp, TaggedProto pr JSObject* associated) { NewTable::Ptr p = defaultNewTable->lookup(NewEntry::Lookup(clasp, proto, associated)); - MOZ_ASSERT(p); + MOZ_RELEASE_ASSERT(p); defaultNewTable->remove(p); } @@ -1608,9 +1612,13 @@ ObjectGroupCompartment::replaceDefaultNewGroup(const Class* clasp, TaggedProto p NewEntry::Lookup lookup(clasp, proto, associated); NewTable::Ptr p = defaultNewTable->lookup(lookup); - MOZ_ASSERT(p); + MOZ_RELEASE_ASSERT(p); defaultNewTable->remove(p); - defaultNewTable->putNew(lookup, NewEntry(group, associated)); + { + AutoEnterOOMUnsafeRegion oomUnsafe; + if (!defaultNewTable->putNew(lookup, NewEntry(group, associated))) + oomUnsafe.crash("Inconsistent object table"); + } } /* static */ From 9b75f2c0d547a6570877d764754a62affbd7c795 Mon Sep 17 00:00:00 2001 From: David Keeler Date: Tue, 29 Sep 2015 12:39:54 -0700 Subject: [PATCH 047/189] bug 975763 - move test_certificate_overrides.html to test_cert_override_bits_mismatches.js r=mgoodwin test_certificate_overrides.html didn't need to be a mochitest. --- .../ssl/tests/mochitest/bugs/chrome.ini | 1 - .../bugs/test_certificate_overrides.html | 145 ------------------ .../test_cert_override_bits_mismatches.js | 89 +++++++++++ security/manager/ssl/tests/unit/xpcshell.ini | 2 + 4 files changed, 91 insertions(+), 146 deletions(-) delete mode 100644 security/manager/ssl/tests/mochitest/bugs/test_certificate_overrides.html create mode 100644 security/manager/ssl/tests/unit/test_cert_override_bits_mismatches.js diff --git a/security/manager/ssl/tests/mochitest/bugs/chrome.ini b/security/manager/ssl/tests/mochitest/bugs/chrome.ini index fc371b5a04ca..07ba0b46a0ba 100644 --- a/security/manager/ssl/tests/mochitest/bugs/chrome.ini +++ b/security/manager/ssl/tests/mochitest/bugs/chrome.ini @@ -4,4 +4,3 @@ skip-if = buildapp == 'b2g' || os == 'android' [test_bug413909.html] skip-if = buildapp == 'mulet' -[test_certificate_overrides.html] diff --git a/security/manager/ssl/tests/mochitest/bugs/test_certificate_overrides.html b/security/manager/ssl/tests/mochitest/bugs/test_certificate_overrides.html deleted file mode 100644 index d3744272ba91..000000000000 --- a/security/manager/ssl/tests/mochitest/bugs/test_certificate_overrides.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - Test certificate overrides - - - - - - - - diff --git a/security/manager/ssl/tests/unit/test_cert_override_bits_mismatches.js b/security/manager/ssl/tests/unit/test_cert_override_bits_mismatches.js new file mode 100644 index 000000000000..83b4fdbc631d --- /dev/null +++ b/security/manager/ssl/tests/unit/test_cert_override_bits_mismatches.js @@ -0,0 +1,89 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- +// 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/. +"use strict"; + +// Test that when an override exists for a (host, certificate) pair, +// connections will succeed only if the set of error bits in the override +// contains each bit in the set of encountered error bits. +// Strangely, it is possible to store an override with an empty set of error +// bits, so this tests that too. + +do_get_profile(); + +function add_override_bits_mismatch_test(host, certPath, expectedBits, + expectedError) { + const MAX_BITS = Ci.nsICertOverrideService.ERROR_UNTRUSTED | + Ci.nsICertOverrideService.ERROR_MISMATCH | + Ci.nsICertOverrideService.ERROR_TIME; + let cert = constructCertFromFile(certPath); + let certOverrideService = Cc["@mozilla.org/security/certoverride;1"] + .getService(Ci.nsICertOverrideService); + for (let overrideBits = 0; overrideBits <= MAX_BITS; overrideBits++) { + add_test(function() { + certOverrideService.clearValidityOverride(host, 8443); + certOverrideService.rememberValidityOverride(host, 8443, cert, + overrideBits, true); + run_next_test(); + }); + // The override will succeed only if the set of error bits in the override + // contains each bit in the set of expected error bits. + let successExpected = (overrideBits | expectedBits) == overrideBits; + add_connection_test(host, successExpected ? PRErrorCodeSuccess + : expectedError); + } +} + +function run_test() { + Services.prefs.setIntPref("security.OCSP.enabled", 1); + add_tls_server_setup("BadCertServer", "bad_certs"); + + let fakeOCSPResponder = new HttpServer(); + fakeOCSPResponder.registerPrefixHandler("/", function (request, response) { + response.setStatusLine(request.httpVersion, 500, "Internal Server Error"); + }); + fakeOCSPResponder.start(8888); + + add_override_bits_mismatch_test("unknownissuer.example.com", + "bad_certs/unknownissuer.pem", + Ci.nsICertOverrideService.ERROR_UNTRUSTED, + SEC_ERROR_UNKNOWN_ISSUER); + add_override_bits_mismatch_test("mismatch.example.com", + "bad_certs/mismatch.pem", + Ci.nsICertOverrideService.ERROR_MISMATCH, + SSL_ERROR_BAD_CERT_DOMAIN); + add_override_bits_mismatch_test("expired.example.com", + "bad_certs/expired-ee.pem", + Ci.nsICertOverrideService.ERROR_TIME, + SEC_ERROR_EXPIRED_CERTIFICATE); + + add_override_bits_mismatch_test("mismatch-untrusted.example.com", + "bad_certs/mismatch-untrusted.pem", + Ci.nsICertOverrideService.ERROR_UNTRUSTED | + Ci.nsICertOverrideService.ERROR_MISMATCH, + SEC_ERROR_UNKNOWN_ISSUER); + add_override_bits_mismatch_test("untrusted-expired.example.com", + "bad_certs/untrusted-expired.pem", + Ci.nsICertOverrideService.ERROR_UNTRUSTED | + Ci.nsICertOverrideService.ERROR_TIME, + SEC_ERROR_UNKNOWN_ISSUER); + add_override_bits_mismatch_test("mismatch-expired.example.com", + "bad_certs/mismatch-expired.pem", + Ci.nsICertOverrideService.ERROR_MISMATCH | + Ci.nsICertOverrideService.ERROR_TIME, + SSL_ERROR_BAD_CERT_DOMAIN); + + add_override_bits_mismatch_test("mismatch-untrusted-expired.example.com", + "bad_certs/mismatch-untrusted-expired.pem", + Ci.nsICertOverrideService.ERROR_UNTRUSTED | + Ci.nsICertOverrideService.ERROR_MISMATCH | + Ci.nsICertOverrideService.ERROR_TIME, + SEC_ERROR_UNKNOWN_ISSUER); + + add_test(function () { + fakeOCSPResponder.stop(run_next_test); + }); + + run_next_test(); +} diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini index 5a3042b59494..b7e0c770fbff 100644 --- a/security/manager/ssl/tests/unit/xpcshell.ini +++ b/security/manager/ssl/tests/unit/xpcshell.ini @@ -74,6 +74,8 @@ run-sequentially = hardcoded ports [test_getchain.js] [test_cert_overrides.js] run-sequentially = hardcoded ports +[test_cert_override_bits_mismatches.js] +run-sequentially = hardcoded ports [test_intermediate_basic_usage_constraints.js] [test_name_constraints.js] [test_cert_trust.js] From 53d634c95b7b6ca71db99591018fa6375eaf18e0 Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Tue, 7 Jul 2015 11:54:25 -0400 Subject: [PATCH 048/189] Bug 1176031 - [taskcluster] Add x11-server-utils package to the 'tester' image, DONTBUILD (NPOTB), r=dustin --HG-- extra : commitid : HxiWJrU1XD3 extra : rebase_source : c3409f61cd47e49397bfa0aef12c6d2e5c61867b extra : amend_source : cd03503be0fec5a09dda168f0e7b2440a6731535 --- testing/docker/base-test/Dockerfile | 1 + testing/docker/base-test/VERSION | 2 +- testing/docker/base-test/sources.list | 37 +++++++++++++++++++++++++++ testing/docker/tester/Dockerfile | 2 +- 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 testing/docker/base-test/sources.list diff --git a/testing/docker/base-test/Dockerfile b/testing/docker/base-test/Dockerfile index 80045f6e3707..1a0abcdb7e53 100644 --- a/testing/docker/base-test/Dockerfile +++ b/testing/docker/base-test/Dockerfile @@ -109,6 +109,7 @@ RUN apt-get update && apt-get install -y --force-yes \ uuid \ vim \ wget \ + x11-xserver-utils \ xvfb \ yasm \ zip diff --git a/testing/docker/base-test/VERSION b/testing/docker/base-test/VERSION index bbdeab6222cb..1750564f270b 100644 --- a/testing/docker/base-test/VERSION +++ b/testing/docker/base-test/VERSION @@ -1 +1 @@ -0.0.5 +0.0.6 diff --git a/testing/docker/base-test/sources.list b/testing/docker/base-test/sources.list new file mode 100644 index 000000000000..38d9829c5461 --- /dev/null +++ b/testing/docker/base-test/sources.list @@ -0,0 +1,37 @@ +deb http://puppetagain.pub.build.mozilla.org/data/repos/apt/ubuntu/ precise main restricted universe +deb http://puppetagain.pub.build.mozilla.org/data/repos/apt/ubuntu/ precise-security main restricted universe +deb http://puppetagain.pub.build.mozilla.org/data/repos/apt/releng/ precise main +deb http://puppetagain.pub.build.mozilla.org/data/repos/apt/puppetlabs precise dependencies main + +deb http://archive.ubuntu.com/ubuntu/ precise main restricted +deb-src http://archive.ubuntu.com/ubuntu/ precise main restricted + +## Major bug fix updates produced after the final release of the +## distribution. +deb http://archive.ubuntu.com/ubuntu/ precise-updates main restricted +deb-src http://archive.ubuntu.com/ubuntu/ precise-updates main restricted + +## Uncomment the following two lines to add software from the 'universe' +## repository. +## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu +## team. Also, please note that software in universe WILL NOT receive any +## review or updates from the Ubuntu security team. +deb http://archive.ubuntu.com/ubuntu/ precise universe +deb-src http://archive.ubuntu.com/ubuntu/ precise universe +deb http://archive.ubuntu.com/ubuntu/ precise-updates universe +deb-src http://archive.ubuntu.com/ubuntu/ precise-updates universe + +## N.B. software from this repository may not have been tested as +## extensively as that contained in the main release, although it includes +## newer versions of some applications which may provide useful features. +## Also, please note that software in backports WILL NOT receive any review +## or updates from the Ubuntu security team. +# deb http://archive.ubuntu.com/ubuntu/ precise-backports main restricted +# deb-src http://archive.ubuntu.com/ubuntu/ precise-backports main restricted + +deb http://archive.ubuntu.com/ubuntu/ precise-security main restricted +deb-src http://archive.ubuntu.com/ubuntu/ precise-security main restricted +deb http://archive.ubuntu.com/ubuntu/ precise-security universe +deb-src http://archive.ubuntu.com/ubuntu/ precise-security universe +# deb http://archive.ubuntu.com/ubuntu/ precise-security multiverse +# deb-src http://archive.ubuntu.com/ubuntu/ precise-security multiverse diff --git a/testing/docker/tester/Dockerfile b/testing/docker/tester/Dockerfile index 49d99b81a9e3..9195e7c420e7 100644 --- a/testing/docker/tester/Dockerfile +++ b/testing/docker/tester/Dockerfile @@ -1,4 +1,4 @@ -FROM quay.io/mozilla/base-test:0.0.5 +FROM quay.io/mozilla/base-test:0.0.6 MAINTAINER Jonas Finnemann Jensen # Add utilities and configuration From 3ccd3e736b138d17faa3914842c79aba450012a7 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 28 Sep 2015 10:32:05 -0400 Subject: [PATCH 049/189] Bug 1199885 - Part 1: Add MouseInput InputData. r=kats --HG-- extra : commitid : Koa5TunrB2K extra : rebase_source : 982a5bb2f320dd2c55410ef53904a44de1b06db5 --- widget/InputData.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ widget/InputData.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/widget/InputData.cpp b/widget/InputData.cpp index 33a5e6c2be54..2c2e76fde086 100644 --- a/widget/InputData.cpp +++ b/widget/InputData.cpp @@ -28,6 +28,49 @@ already_AddRefed SingleTouchData::ToNewDOMTouch() const return touch.forget(); } +MouseInput::MouseInput(const WidgetMouseEventBase& aMouseEvent) + : InputData(MOUSE_INPUT, aMouseEvent.time, aMouseEvent.timeStamp, + aMouseEvent.modifiers) +{ + MOZ_ASSERT(NS_IsMainThread(), + "Can only copy from WidgetTouchEvent on main thread"); + + mButtonType = NONE; + + switch (aMouseEvent.button) { + case WidgetMouseEventBase::eLeftButton: + mButtonType = MouseInput::LEFT_BUTTON; + break; + case WidgetMouseEventBase::eMiddleButton: + mButtonType = MouseInput::MIDDLE_BUTTON; + break; + case WidgetMouseEventBase::eRightButton: + mButtonType = MouseInput::RIGHT_BUTTON; + break; + } + + switch (aMouseEvent.mMessage) { + case eMouseMove: + mType = MOUSE_MOVE; + break; + case eMouseUp: + mType = MOUSE_UP; + break; + case eMouseDown: + mType = MOUSE_DOWN; + break; + case eDragStart: + mType = MOUSE_DRAG_START; + break; + case eDragEnd: + mType = MOUSE_DRAG_END; + break; + default: + MOZ_ASSERT_UNREACHABLE("Mouse event type not supported"); + break; + } +} + MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent) : InputData(MULTITOUCH_INPUT, aTouchEvent.time, aTouchEvent.timeStamp, aTouchEvent.modifiers) diff --git a/widget/InputData.h b/widget/InputData.h index 637ffadacbed..c6fa6d093f35 100644 --- a/widget/InputData.h +++ b/widget/InputData.h @@ -30,6 +30,7 @@ class Matrix4x4; enum InputType { MULTITOUCH_INPUT, + MOUSE_INPUT, PANGESTURE_INPUT, PINCHGESTURE_INPUT, TAPGESTURE_INPUT, @@ -37,6 +38,7 @@ enum InputType }; class MultiTouchInput; +class MouseInput; class PanGestureInput; class PinchGestureInput; class TapGestureInput; @@ -76,6 +78,7 @@ public: Modifiers modifiers; INPUTDATA_AS_CHILD_TYPE(MultiTouchInput, MULTITOUCH_INPUT) + INPUTDATA_AS_CHILD_TYPE(MouseInput, MOUSE_INPUT) INPUTDATA_AS_CHILD_TYPE(PanGestureInput, PANGESTURE_INPUT) INPUTDATA_AS_CHILD_TYPE(PinchGestureInput, PINCHGESTURE_INPUT) INPUTDATA_AS_CHILD_TYPE(TapGestureInput, TAPGESTURE_INPUT) @@ -245,6 +248,47 @@ public: nsTArray mTouches; }; +class MouseInput : public InputData +{ +public: + enum MouseType + { + MOUSE_MOVE, + MOUSE_DOWN, + MOUSE_UP, + MOUSE_DRAG_START, + MOUSE_DRAG_END, + }; + + enum ButtonType + { + LEFT_BUTTON, + MIDDLE_BUTTON, + RIGHT_BUTTON, + NONE + }; + + MouseInput(MouseType aType, ButtonType aButtonType, uint32_t aTime, + TimeStamp aTimeStamp, Modifiers aModifiers) + : InputData(MOUSE_INPUT, aTime, aTimeStamp, aModifiers) + , mType(aType) + , mButtonType(aButtonType) + {} + + MouseInput() + : InputData(MOUSE_INPUT) + {} + + explicit MouseInput(const WidgetMouseEventBase& aMouseEvent); + + bool IsLeftButton() const { return mButtonType == LEFT_BUTTON; } + + MouseType mType; + ButtonType mButtonType; + ScreenPoint mOrigin; + ParentLayerPoint mLocalOrigin; +}; + /** * Encapsulation class for pan events, can be used off-main-thread. * These events are currently only used for scrolling on desktop. From fd05a3df17a4ae433b2ffb14d2abecd066d49cdc Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 28 Sep 2015 14:43:50 -0400 Subject: [PATCH 050/189] Bug 1199885 - Part 2: Add AsyncDragMetrics. r=kats --HG-- extra : commitid : Bq9QdYWF3v3 extra : rebase_source : bdd10ec82cd18811fa8fe75477d02dc862ece99b --- gfx/ipc/GfxMessageUtils.h | 35 +++++++++++++++ gfx/layers/apz/src/AsyncDragMetrics.h | 65 +++++++++++++++++++++++++++ gfx/layers/moz.build | 1 + 3 files changed, 101 insertions(+) create mode 100644 gfx/layers/apz/src/AsyncDragMetrics.h diff --git a/gfx/ipc/GfxMessageUtils.h b/gfx/ipc/GfxMessageUtils.h index 199bfab154bd..206b8a50b077 100644 --- a/gfx/ipc/GfxMessageUtils.h +++ b/gfx/ipc/GfxMessageUtils.h @@ -19,6 +19,7 @@ #include "nsRect.h" #include "nsRegion.h" #include "gfxTypes.h" +#include "mozilla/layers/AsyncDragMetrics.h" #include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/CompositorTypes.h" #include "FrameMetrics.h" @@ -1084,6 +1085,40 @@ struct ParamTraits mozilla::layers::EventRegionsOverride::ALL_BITS> {}; +template<> +struct ParamTraits + : public ContiguousEnumSerializer< + mozilla::layers::AsyncDragMetrics::DragDirection, + mozilla::layers::AsyncDragMetrics::DragDirection::NONE, + mozilla::layers::AsyncDragMetrics::DragDirection::SENTINEL> +{}; + +template<> +struct ParamTraits +{ + typedef mozilla::layers::AsyncDragMetrics paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.mViewId); + WriteParam(aMsg, aParam.mPresShellId); + WriteParam(aMsg, aParam.mDragStartSequenceNumber); + WriteParam(aMsg, aParam.mScrollbarDragOffset); + WriteParam(aMsg, aParam.mScrollTrack); + WriteParam(aMsg, aParam.mDirection); + } + + static bool Read(const Message* aMsg, void** aIter, paramType* aResult) + { + return (ReadParam(aMsg, aIter, &aResult->mViewId) && + ReadParam(aMsg, aIter, &aResult->mPresShellId) && + ReadParam(aMsg, aIter, &aResult->mDragStartSequenceNumber) && + ReadParam(aMsg, aIter, &aResult->mScrollbarDragOffset) && + ReadParam(aMsg, aIter, &aResult->mScrollTrack) && + ReadParam(aMsg, aIter, &aResult->mDirection)); + } +}; + } /* namespace IPC */ #endif /* __GFXMESSAGEUTILS_H__ */ diff --git a/gfx/layers/apz/src/AsyncDragMetrics.h b/gfx/layers/apz/src/AsyncDragMetrics.h new file mode 100644 index 000000000000..54b60f823074 --- /dev/null +++ b/gfx/layers/apz/src/AsyncDragMetrics.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* 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 mozilla_layers_DragMetrics_h +#define mozilla_layers_DragMetrics_h + +#include "FrameMetrics.h" + +namespace IPC { +template struct ParamTraits; +} // namespace IPC + +namespace mozilla { + +namespace layers { + +class AsyncDragMetrics { + friend struct IPC::ParamTraits; + +public: + enum DragDirection { + NONE, + VERTICAL, + HORIZONTAL, + SENTINEL, + }; + + // IPC constructor + AsyncDragMetrics() + : mViewId(0) + , mPresShellId(0) + , mDragStartSequenceNumber(0) + , mScrollbarDragOffset(0) + , mDirection(NONE) + {} + + AsyncDragMetrics(const FrameMetrics::ViewID& aViewId, + uint32_t aPresShellId, + uint64_t aDragStartSequenceNumber, + CSSIntCoord aScrollbarDragOffset, + const CSSIntRect& aScrollTrack, + DragDirection aDirection) + : mViewId(aViewId) + , mPresShellId(aPresShellId) + , mDragStartSequenceNumber(aDragStartSequenceNumber) + , mScrollbarDragOffset(aScrollbarDragOffset) + , mScrollTrack(aScrollTrack) + , mDirection(aDirection) + {} + + FrameMetrics::ViewID mViewId; + uint32_t mPresShellId; + uint64_t mDragStartSequenceNumber; + CSSIntCoord mScrollbarDragOffset; + CSSIntRect mScrollTrack; + DragDirection mDirection; +}; + +} +} + +#endif diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 5ce9a5863b88..447683f05005 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -97,6 +97,7 @@ EXPORTS.mozilla.layers += [ # proper interface for the code there 'apz/src/APZCTreeManager.h', 'apz/src/APZUtils.h', + 'apz/src/AsyncDragMetrics.h', 'apz/src/AsyncPanZoomAnimation.h', 'apz/src/TouchCounter.h', 'apz/testutil/APZTestData.h', From 2a2fca7ffacdf0256fe195035b52941bc459125b Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 28 Sep 2015 14:44:36 -0400 Subject: [PATCH 051/189] Bug 1199885 - Part 3: Add 'apz.drag.enabled' preference for async scrollbars. r=kats --HG-- extra : commitid : FT9vDNL0XDw extra : rebase_source : f5cd5f6e53c669f33fc628915cab1f6c57beaa11 --- gfx/thebes/gfxPlatform.cpp | 10 ++++++++++ gfx/thebes/gfxPlatform.h | 1 + gfx/thebes/gfxPrefs.h | 1 + modules/libpref/init/all.js | 1 + toolkit/content/aboutSupport.js | 2 +- .../en-US/chrome/global/aboutSupport.properties | 1 + 6 files changed, 15 insertions(+), 1 deletion(-) diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index f0d5ba61e262..06d6b877fc42 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -2124,6 +2124,10 @@ gfxPlatform::GetApzSupportInfo(mozilla::widget::InfoObject& aObj) if (SupportsApzTouchInput()) { aObj.DefineProperty("ApzTouchInput", 1); } + + if (SupportsApzDragInput()) { + aObj.DefineProperty("ApzDragInput", 1); + } } /*static*/ bool @@ -2244,3 +2248,9 @@ gfxPlatform::UpdateDeviceInitData() SetDeviceInitData(data); } + +bool +gfxPlatform::SupportsApzDragInput() const +{ + return gfxPrefs::APZDragEnabled(); +} diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 1eb4762f55e9..2a9e61dc8c36 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -597,6 +597,7 @@ public: virtual bool SupportsApzTouchInput() const { return false; } + bool SupportsApzDragInput() const; virtual void FlushContentDrawing() {} diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 96b4abe55709..c60a4956d45d 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -150,6 +150,7 @@ private: DECL_GFX_PREF(Live, "apz.cross_slide.enabled", APZCrossSlideEnabled, bool, false); DECL_GFX_PREF(Live, "apz.danger_zone_x", APZDangerZoneX, int32_t, 50); DECL_GFX_PREF(Live, "apz.danger_zone_y", APZDangerZoneY, int32_t, 100); + DECL_GFX_PREF(Live, "apz.drag.enabled", APZDragEnabled, bool, false); DECL_GFX_PREF(Live, "apz.enlarge_displayport_when_clipped", APZEnlargeDisplayPortWhenClipped, bool, false); DECL_GFX_PREF(Live, "apz.fling_accel_base_mult", APZFlingAccelBaseMultiplier, float, 1.0f); DECL_GFX_PREF(Live, "apz.fling_accel_interval_ms", APZFlingAccelInterval, int32_t, 500); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 1204c6e4743c..3eb51421aaca 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -541,6 +541,7 @@ pref("apz.axis_lock.breakout_angle", "0.3926991"); // PI / 8 (22.5 degrees) pref("apz.axis_lock.direct_pan_angle", "1.047197"); // PI / 3 (60 degrees) pref("apz.content_response_timeout", 300); pref("apz.cross_slide.enabled", false); +pref("apz.drag.enabled", false); pref("apz.danger_zone_x", 50); pref("apz.danger_zone_y", 100); pref("apz.enlarge_displayport_when_clipped", false); diff --git a/toolkit/content/aboutSupport.js b/toolkit/content/aboutSupport.js index 2e091ab687df..1b3e717a744b 100644 --- a/toolkit/content/aboutSupport.js +++ b/toolkit/content/aboutSupport.js @@ -203,7 +203,7 @@ var snapshotFormatters = { let apzInfo = []; let formatApzInfo = function (info) { let out = []; - for (let type of ['Wheel', 'Touch']) { + for (let type of ['Wheel', 'Touch', 'Drag']) { let key = 'Apz' + type + 'Input'; let warningKey = key + 'Warning'; diff --git a/toolkit/locales/en-US/chrome/global/aboutSupport.properties b/toolkit/locales/en-US/chrome/global/aboutSupport.properties index f07763dadaac..143ad12da5bf 100644 --- a/toolkit/locales/en-US/chrome/global/aboutSupport.properties +++ b/toolkit/locales/en-US/chrome/global/aboutSupport.properties @@ -104,6 +104,7 @@ asyncPanZoom = Asynchronous Pan/Zoom apzNone = none wheelEnabled = wheel input enabled touchEnabled = touch input enabled +dragEnabled = scrollbar drag enabled # LOCALIZATION NOTE %1 will be replaced with the key of a preference. wheelWarning = async wheel input disabled due to unsupported pref: %S From eb3b891bbc5513b079ed5955d3d80dda21451d18 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 28 Sep 2015 14:44:36 -0400 Subject: [PATCH 052/189] Bug 1199885 - Part 4: Let the hit testing tree know about the scroll thumb. r=kats --HG-- extra : commitid : 2sY04WntME0 extra : rebase_source : 98008b1dcc3236ef65e1809fd849fae6c31c76f7 --- gfx/layers/LayerMetricsWrapper.h | 23 ++++++++++++++++++++++ gfx/layers/apz/src/APZCTreeManager.cpp | 6 ++++++ gfx/layers/apz/src/HitTestingTreeNode.cpp | 24 +++++++++++++++++++++++ gfx/layers/apz/src/HitTestingTreeNode.h | 15 +++++++++++++- 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/gfx/layers/LayerMetricsWrapper.h b/gfx/layers/LayerMetricsWrapper.h index e00301fd9b2b..751a2c673ae2 100644 --- a/gfx/layers/LayerMetricsWrapper.h +++ b/gfx/layers/LayerMetricsWrapper.h @@ -364,6 +364,29 @@ public: return EventRegionsOverride::NoOverride; } + Layer::ScrollDirection GetScrollbarDirection() const + { + MOZ_ASSERT(IsValid()); + + return mLayer->GetScrollbarDirection(); + } + + FrameMetrics::ViewID GetScrollbarTargetContainerId() const + { + MOZ_ASSERT(IsValid()); + + return mLayer->GetScrollbarTargetContainerId(); + } + + int32_t GetScrollbarSize() const + { + if (GetScrollbarDirection() == Layer::VERTICAL) { + return mLayer->GetVisibleRegion().GetBounds().height; + } else { + return mLayer->GetVisibleRegion().GetBounds().width; + } + } + // Expose an opaque pointer to the layer. Mostly used for printf // purposes. This is not intended to be a general-purpose accessor // for the underlying layer. diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 5615a8d3847a..4c481aab2556 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -378,6 +378,9 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer, node->SetHitTestData(GetEventRegions(aLayer), aLayer.GetTransform(), aLayer.GetClipRect() ? Some(ParentLayerIntRegion(*aLayer.GetClipRect())) : Nothing(), GetEventRegionsOverride(aParent, aLayer)); + node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(), + aLayer.GetScrollbarDirection(), + aLayer.GetScrollbarSize()); return node; } @@ -543,6 +546,9 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer, GetEventRegionsOverride(aParent, aLayer)); } + node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(), + aLayer.GetScrollbarDirection(), + aLayer.GetScrollbarSize()); return node; } diff --git a/gfx/layers/apz/src/HitTestingTreeNode.cpp b/gfx/layers/apz/src/HitTestingTreeNode.cpp index cb3308e96329..551c2763fe90 100644 --- a/gfx/layers/apz/src/HitTestingTreeNode.cpp +++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp @@ -86,6 +86,30 @@ HitTestingTreeNode::SetLastChild(HitTestingTreeNode* aChild) } } +void +HitTestingTreeNode::SetScrollbarData(FrameMetrics::ViewID aScrollViewId, Layer::ScrollDirection aDir, int32_t aScrollSize) +{ + mScrollViewId = aScrollViewId; + mScrollDir = aDir; + mScrollSize = aScrollSize;; +} + +bool +HitTestingTreeNode::MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const +{ + return ((mScrollDir == Layer::HORIZONTAL && + aDragMetrics.mDirection == AsyncDragMetrics::HORIZONTAL) || + (mScrollDir == Layer::VERTICAL && + aDragMetrics.mDirection == AsyncDragMetrics::VERTICAL)) && + mScrollViewId == aDragMetrics.mViewId; +} + +int32_t +HitTestingTreeNode::GetScrollSize() const +{ + return mScrollSize; +} + void HitTestingTreeNode::SetPrevSibling(HitTestingTreeNode* aSibling) { diff --git a/gfx/layers/apz/src/HitTestingTreeNode.h b/gfx/layers/apz/src/HitTestingTreeNode.h index 4c1a9cf167ce..b34803a5c63f 100644 --- a/gfx/layers/apz/src/HitTestingTreeNode.h +++ b/gfx/layers/apz/src/HitTestingTreeNode.h @@ -9,14 +9,16 @@ #include "APZUtils.h" // for HitTestResult #include "FrameMetrics.h" // for ScrollableLayerGuid +#include "Layers.h" #include "mozilla/gfx/Matrix.h" // for Matrix4x4 #include "mozilla/layers/LayersTypes.h" // for EventRegions #include "mozilla/Maybe.h" // for Maybe -#include "mozilla/nsRefPtr.h" // for nsRefPtr +#include "mozilla/nsRefPtr.h" // for nsRefPtr namespace mozilla { namespace layers { +class AsyncDragMetrics; class AsyncPanZoomController; /** @@ -87,6 +89,13 @@ public: const Maybe& aClipRegion, const EventRegionsOverride& aOverride); bool IsOutsideClip(const ParentLayerPoint& aPoint) const; + + /* Scrollbar info */ + + void SetScrollbarData(FrameMetrics::ViewID aScrollViewId, Layer::ScrollDirection aDir, int32_t aScrollSize); + bool MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const; + int32_t GetScrollSize() const; + /* Convert aPoint into the LayerPixel space for the layer corresponding to * this node. */ Maybe Untransform(const ParentLayerPoint& aPoint) const; @@ -111,6 +120,10 @@ private: uint64_t mLayersId; + FrameMetrics::ViewID mScrollViewId; + Layer::ScrollDirection mScrollDir; + int32_t mScrollSize; + /* Let {L,M} be the {layer, scrollable metrics} pair that this node * corresponds to in the layer tree. mEventRegions contains the event regions * from L, in the case where event-regions are enabled. If event-regions are From 6803a546d59e3a0e3746d260612ac6e2bc7cc805 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 28 Sep 2015 14:44:36 -0400 Subject: [PATCH 053/189] Bug 1199885 - Part 5: Make mRootLayerTreeID const to prove that there's no data races. r=kats --HG-- extra : commitid : 5WndwzOuLdi --- gfx/layers/ipc/CompositorParent.cpp | 2 +- gfx/layers/ipc/CompositorParent.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 97137766bb6b..8b4b1bfb9f89 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -548,6 +548,7 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, , mEGLSurfaceSize(aSurfaceWidth, aSurfaceHeight) , mPauseCompositionMonitor("PauseCompositionMonitor") , mResumeCompositionMonitor("ResumeCompositionMonitor") + , mRootLayerTreeID(AllocateLayerTreeId()) , mOverrideComposeReadiness(false) , mForceCompositionTask(nullptr) , mCompositorThreadHolder(sCompositorThreadHolder) @@ -573,7 +574,6 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(SetThreadPriority)); - mRootLayerTreeID = AllocateLayerTreeId(); { // scope lock MonitorAutoLock lock(*sIndirectLayerTreesLock); diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index 711c05f441d5..69649ebcbfbc 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -474,7 +474,7 @@ protected: mozilla::Monitor mResumeCompositionMonitor; uint64_t mCompositorID; - uint64_t mRootLayerTreeID; + const uint64_t mRootLayerTreeID; bool mOverrideComposeReadiness; CancelableTask* mForceCompositionTask; From 48624c592c66cda9197bcf4b95726792ba634304 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 28 Sep 2015 14:44:37 -0400 Subject: [PATCH 054/189] Bug 1199885 - Part 8: Add FindScrollNode to locate the scrollbar thumb. r=kats --HG-- extra : commitid : 9yE7xtzOs3I --- gfx/layers/apz/src/APZCTreeManager.cpp | 29 ++++++++++++++++++++++++++ gfx/layers/apz/src/APZCTreeManager.h | 10 +++++++++ 2 files changed, 39 insertions(+) diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 4c481aab2556..2c2bb8e3f279 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -14,6 +14,7 @@ #include "mozilla/gfx/Point.h" // for Point #include "mozilla/layers/APZThreadUtils.h" // for AssertOnCompositorThread, etc #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform +#include "mozilla/layers/AsyncDragMetrics.h" // for AsyncDragMetrics #include "mozilla/layers/CompositorParent.h" // for CompositorParent, etc #include "mozilla/layers/LayerMetricsWrapper.h" #include "mozilla/MouseEvents.h" @@ -1563,6 +1564,34 @@ APZCTreeManager::FindTargetNode(HitTestingTreeNode* aNode, return nullptr; } +nsRefPtr +APZCTreeManager::FindScrollNode(const AsyncDragMetrics& aDragMetrics) +{ + MonitorAutoLock lock(mTreeLock); + + return FindScrollNode(mRootNode, aDragMetrics); +} + +HitTestingTreeNode* +APZCTreeManager::FindScrollNode(HitTestingTreeNode* aNode, + const AsyncDragMetrics& aDragMetrics) +{ + mTreeLock.AssertCurrentThreadOwns(); + + for (HitTestingTreeNode* node = aNode; node; node = node->GetPrevSibling()) { + if (node->MatchesScrollDragMetrics(aDragMetrics)) { + return node; + } + + HitTestingTreeNode* match = FindScrollNode(node->GetLastChild(), aDragMetrics); + if (match) { + return match; + } + } + + return nullptr; +} + AsyncPanZoomController* APZCTreeManager::GetAPZCAtPoint(HitTestingTreeNode* aNode, const ParentLayerPoint& aHitTestPoint, diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index 3669a7997a88..127285bf8b76 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -41,6 +41,7 @@ enum AllowedTouchBehavior { }; class Layer; +class AsyncDragMetrics; class AsyncPanZoomController; class CompositorParent; class OverscrollHandoffChain; @@ -96,6 +97,7 @@ class APZCTreeManager { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZCTreeManager) typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior; + typedef mozilla::layers::AsyncDragMetrics AsyncDragMetrics; // Helper struct to hold some state while we build the hit-testing tree. The // sole purpose of this struct is to shorten the argument list to @@ -296,6 +298,12 @@ public: */ static float GetDPI() { return sDPI; } + /** + * Find the hit testing node for the scrollbar thumb that matches these + * drag metrics. + */ + nsRefPtr FindScrollNode(const AsyncDragMetrics& aDragMetrics); + /** * Sets allowed touch behavior values for current touch-session for specific * input block (determined by aInputBlock). @@ -429,6 +437,8 @@ private: HitTestingTreeNode* FindTargetNode(HitTestingTreeNode* aNode, const ScrollableLayerGuid& aGuid, GuidComparator aComparator); + HitTestingTreeNode* FindScrollNode(HitTestingTreeNode* aNode, + const AsyncDragMetrics& aDragMetrics); AsyncPanZoomController* GetAPZCAtPoint(HitTestingTreeNode* aNode, const ParentLayerPoint& aHitTestPoint, HitTestResult* aOutHitResult); From 5e9f05f89cf77559956e3c0fb0bcf000b1a4eb58 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 28 Sep 2015 14:44:37 -0400 Subject: [PATCH 055/189] Bug 1199885 - Part 9: Let APZC handle the drag events. r=kats --HG-- extra : commitid : 5eL9kMtaPPT --- gfx/layers/apz/src/AsyncPanZoomController.cpp | 105 +++++++++++++++++- gfx/layers/apz/src/AsyncPanZoomController.h | 4 + widget/InputData.cpp | 12 ++ widget/InputData.h | 2 + 4 files changed, 122 insertions(+), 1 deletion(-) diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 836dfb5987a8..0bbe763793a6 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -13,6 +13,7 @@ #include "Compositor.h" // for Compositor #include "FrameMetrics.h" // for FrameMetrics, etc #include "GestureEventListener.h" // for GestureEventListener +#include "HitTestingTreeNode.h" // for HitTestingTreeNode #include "InputData.h" // for MultiTouchInput, etc #include "InputBlockState.h" // for InputBlockState, TouchBlockState #include "InputQueue.h" // for InputQueue @@ -952,6 +953,95 @@ AsyncPanZoomController::ArePointerEventsConsumable(TouchBlockState* aBlock, uint return true; } +template +static float GetAxisStart(AsyncDragMetrics::DragDirection aDir, T aValue) { + if (aDir == AsyncDragMetrics::HORIZONTAL) { + return aValue.x; + } else { + return aValue.y; + } +} + +template +static float GetAxisEnd(AsyncDragMetrics::DragDirection aDir, T aValue) { + if (aDir == AsyncDragMetrics::HORIZONTAL) { + return aValue.x + aValue.width; + } else { + return aValue.y + aValue.height; + } +} + +template +static float GetAxisSize(AsyncDragMetrics::DragDirection aDir, T aValue) { + if (aDir == AsyncDragMetrics::HORIZONTAL) { + return aValue.width; + } else { + return aValue.height; + } +} + +template +static float GetAxisScale(AsyncDragMetrics::DragDirection aDir, T aValue) { + if (aDir == AsyncDragMetrics::HORIZONTAL) { + return aValue.xScale; + } else { + return aValue.yScale; + } +} + +nsEventStatus AsyncPanZoomController::HandleDragEvent(const MouseInput& aEvent, + const AsyncDragMetrics& aDragMetrics) +{ + nsRefPtr node = + GetApzcTreeManager()->FindScrollNode(aDragMetrics); + if (!node) { + return nsEventStatus_eConsumeNoDefault; + } + + CSSPoint scrollFramePoint = aEvent.mLocalOrigin / GetFrameMetrics().GetZoom(); + // The scrollbar can be transformed with the frame but the pres shell + // resolution is only applied to the scroll frame. + CSSPoint scrollbarPoint = scrollFramePoint * GetFrameMetrics().GetPresShellResolution(); + CSSRect cssCompositionBound = GetFrameMetrics().GetCompositionBounds() / GetFrameMetrics().GetZoom(); + + float mousePosition = GetAxisStart(aDragMetrics.mDirection, scrollbarPoint) - + aDragMetrics.mScrollbarDragOffset - + GetAxisStart(aDragMetrics.mDirection, cssCompositionBound) - + GetAxisStart(aDragMetrics.mDirection, aDragMetrics.mScrollTrack); + + float scrollMax = GetAxisEnd(aDragMetrics.mDirection, aDragMetrics.mScrollTrack); + scrollMax -= node->GetScrollSize() / + GetAxisScale(aDragMetrics.mDirection, GetFrameMetrics().GetZoom()) * + GetFrameMetrics().GetPresShellResolution(); + + float scrollPercent = mousePosition / scrollMax; + + float minScrollPosition = + GetAxisStart(aDragMetrics.mDirection, GetFrameMetrics().GetScrollableRect().TopLeft()); + float maxScrollPosition = + GetAxisSize(aDragMetrics.mDirection, GetFrameMetrics().GetScrollableRect()) - + GetAxisSize(aDragMetrics.mDirection, GetFrameMetrics().GetCompositionBounds()); + float scrollPosition = scrollPercent * maxScrollPosition; + + scrollPosition = std::max(scrollPosition, minScrollPosition); + scrollPosition = std::min(scrollPosition, maxScrollPosition); + + CSSPoint scrollOffset; + if (aDragMetrics.mDirection == AsyncDragMetrics::HORIZONTAL) { + scrollOffset = CSSPoint(scrollPosition, 0); + } else { + scrollOffset = CSSPoint(0, scrollPosition); + } + mFrameMetrics.SetScrollOffset(scrollOffset); + ScheduleCompositeAndMaybeRepaint(); + UpdateSharedCompositorFrameMetrics(); + + // Here we consume the events. This means that the content scrollbars + // will only see the initial mouse down and the final mouse up. + // APZ will still update the scroll position. + return nsEventStatus_eConsumeNoDefault; +} + nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent, const Matrix4x4& aTransformToApzc) { APZThreadUtils::AssertOnControllerThread(); @@ -961,7 +1051,7 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent, switch (aEvent.mInputType) { case MULTITOUCH_INPUT: { MultiTouchInput multiTouchInput = aEvent.AsMultiTouchInput(); - if (!multiTouchInput.TransformToLocal(aTransformToApzc)) { + if (!multiTouchInput.TransformToLocal(aTransformToApzc)) { return rv; } @@ -1001,6 +1091,16 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent, } break; } + case MOUSE_INPUT: { + ScrollWheelInput scrollInput = aEvent.AsScrollWheelInput(); + if (!scrollInput.TransformToLocal(aTransformToApzc)) { + return rv; + } + + // TODO Need to implement blocks to properly handle this. + //rv = HandleDragEvent(scrollInput, dragMetrics); + break; + } case SCROLLWHEEL_INPUT: { ScrollWheelInput scrollInput = aEvent.AsScrollWheelInput(); if (!scrollInput.TransformToLocal(aTransformToApzc)) { @@ -2952,6 +3052,9 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri bool smoothScrollRequested = aLayerMetrics.GetDoSmoothScroll() && (aLayerMetrics.GetScrollGeneration() != mFrameMetrics.GetScrollGeneration()); + // TODO if we're in a drag and scrollOffsetUpdated is set then we want to + // ignore it + if (aIsFirstPaint || isDefault) { // Initialize our internal state to something sane when the content // that was just painted is something we knew nothing about previously diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index 88058a047d52..4d4b7d8fbe6f 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -40,6 +40,7 @@ class SharedMemoryBasic; namespace layers { +class AsyncDragMetrics; struct ScrollableLayerGuid; class CompositorParent; class GestureEventListener; @@ -266,6 +267,9 @@ public: */ void SendAsyncScrollEvent(); + nsEventStatus HandleDragEvent(const MouseInput& aEvent, + const AsyncDragMetrics& aDragMetrics); + /** * Handler for events which should not be intercepted by the touch listener. */ diff --git a/widget/InputData.cpp b/widget/InputData.cpp index 2c2e76fde086..58e036b13334 100644 --- a/widget/InputData.cpp +++ b/widget/InputData.cpp @@ -71,6 +71,18 @@ MouseInput::MouseInput(const WidgetMouseEventBase& aMouseEvent) } } +bool +MouseInput::TransformToLocal(const gfx::Matrix4x4& aTransform) +{ + Maybe point = UntransformTo(aTransform, mOrigin); + if (!point) { + return false; + } + mLocalOrigin = *point; + + return true; +} + MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent) : InputData(MULTITOUCH_INPUT, aTouchEvent.time, aTouchEvent.timeStamp, aTouchEvent.modifiers) diff --git a/widget/InputData.h b/widget/InputData.h index c6fa6d093f35..76bce2936ed5 100644 --- a/widget/InputData.h +++ b/widget/InputData.h @@ -283,6 +283,8 @@ public: bool IsLeftButton() const { return mButtonType == LEFT_BUTTON; } + bool TransformToLocal(const gfx::Matrix4x4& aTransform); + MouseType mType; ButtonType mButtonType; ScreenPoint mOrigin; From 32e75119c11020563b159356d6f68c53523b84c9 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 28 Sep 2015 14:44:37 -0400 Subject: [PATCH 056/189] Bug 1199885 - Part 9.5: Make the mouse events APZC aware. r=kats --HG-- extra : commitid : KSO4Xg8RrF1 --- dom/ipc/PBrowser.ipdl | 6 +++--- dom/ipc/TabChild.cpp | 20 +++++++++++++++----- dom/ipc/TabChild.h | 12 +++++++++--- dom/ipc/TabParent.cpp | 11 ++++++++--- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 1d4c99887e88..b2b56e1c6f3a 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -627,7 +627,7 @@ child: * When two consecutive mouse move events would be added to the message queue, * they are 'compressed' by dumping the oldest one. */ - RealMouseMoveEvent(WidgetMouseEvent event) compress; + RealMouseMoveEvent(WidgetMouseEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId) compress; /** * Mouse move events with |reason == eSynthesized| are sent via a separate * message because they do not generate DOM 'mousemove' events, and the @@ -635,8 +635,8 @@ child: * |reason == eReal| event being dropped in favour of an |eSynthesized| * event, and thus a DOM 'mousemove' event to be lost. */ - SynthMouseMoveEvent(WidgetMouseEvent event); - RealMouseButtonEvent(WidgetMouseEvent event); + SynthMouseMoveEvent(WidgetMouseEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId); + RealMouseButtonEvent(WidgetMouseEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId); RealKeyEvent(WidgetKeyboardEvent event, MaybeNativeKeyBinding keyBinding); MouseWheelEvent(WidgetWheelEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId); RealTouchEvent(WidgetTouchEvent aEvent, diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 1364ac968c67..e8778794eebc 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -33,6 +33,7 @@ #include "mozilla/layers/CompositorChild.h" #include "mozilla/layers/DoubleTapToZoom.h" #include "mozilla/layers/ImageBridgeChild.h" +#include "mozilla/layers/InputAPZContext.h" #include "mozilla/layers/ShadowLayers.h" #include "mozilla/layout/RenderFrameChild.h" #include "mozilla/LookAndFeel.h" @@ -1914,20 +1915,29 @@ TabChild::RecvMouseEvent(const nsString& aType, } bool -TabChild::RecvRealMouseMoveEvent(const WidgetMouseEvent& event) +TabChild::RecvRealMouseMoveEvent(const WidgetMouseEvent& event, + const ScrollableLayerGuid& aGuid, + const uint64_t& aInputBlockId) { - return RecvRealMouseButtonEvent(event); + return RecvRealMouseButtonEvent(event, aGuid, aInputBlockId); } bool -TabChild::RecvSynthMouseMoveEvent(const WidgetMouseEvent& event) +TabChild::RecvSynthMouseMoveEvent(const WidgetMouseEvent& event, + const ScrollableLayerGuid& aGuid, + const uint64_t& aInputBlockId) { - return RecvRealMouseButtonEvent(event); + return RecvRealMouseButtonEvent(event, aGuid, aInputBlockId); } bool -TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& event) +TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& event, + const ScrollableLayerGuid& aGuid, + const uint64_t& aInputBlockId) { + nsEventStatus unused; + InputAPZContext context(aGuid, aInputBlockId, unused); + WidgetMouseEvent localEvent(event); localEvent.widget = mPuppetWidget; APZCCallbackHelper::DispatchWidgetEvent(localEvent); diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index e7a03606c2f5..bd20bd55d4d8 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -332,9 +332,15 @@ public: const int32_t& aClickCount, const int32_t& aModifiers, const bool& aIgnoreRootScrollFrame) override; - virtual bool RecvRealMouseMoveEvent(const mozilla::WidgetMouseEvent& event) override; - virtual bool RecvSynthMouseMoveEvent(const mozilla::WidgetMouseEvent& event) override; - virtual bool RecvRealMouseButtonEvent(const mozilla::WidgetMouseEvent& event) override; + virtual bool RecvRealMouseMoveEvent(const mozilla::WidgetMouseEvent& event, + const ScrollableLayerGuid& aGuid, + const uint64_t& aInputBlockId) override; + virtual bool RecvSynthMouseMoveEvent(const mozilla::WidgetMouseEvent& event, + const ScrollableLayerGuid& aGuid, + const uint64_t& aInputBlockId) override; + virtual bool RecvRealMouseButtonEvent(const mozilla::WidgetMouseEvent& event, + const ScrollableLayerGuid& aGuid, + const uint64_t& aInputBlockId) override; virtual bool RecvRealDragEvent(const WidgetDragEvent& aEvent, const uint32_t& aDragAction, const uint32_t& aDropEffect) override; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index f034e64a58a8..2d45ae9d3b26 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -1571,14 +1571,19 @@ bool TabParent::SendRealMouseEvent(WidgetMouseEvent& event) } } + ScrollableLayerGuid guid; + uint64_t blockId; + ApzAwareEventRoutingToChild(&guid, &blockId, nullptr); + if (eMouseMove == event.mMessage) { if (event.reason == WidgetMouseEvent::eSynthesized) { - return SendSynthMouseMoveEvent(event); + return SendSynthMouseMoveEvent(event, guid, blockId); } else { - return SendRealMouseMoveEvent(event); + return SendRealMouseMoveEvent(event, guid, blockId); } } - return SendRealMouseButtonEvent(event); + + return SendRealMouseButtonEvent(event, guid, blockId); } LayoutDeviceToCSSScale From de3c5864023199e0583d41615844743e10f0cb68 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 28 Sep 2015 17:00:21 -0400 Subject: [PATCH 057/189] Bug 1199885 - Part 10: Add APZTeeManager API to start an async scroll. r=kats --HG-- extra : commitid : Bcuo2Zbt0IB --- gfx/layers/apz/src/APZCTreeManager.cpp | 71 ++++++++++++++++++++++++++ gfx/layers/apz/src/APZCTreeManager.h | 7 +++ 2 files changed, 78 insertions(+) diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 2c2bb8e3f279..be6853559414 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -351,6 +351,21 @@ GetEventRegionsOverride(HitTestingTreeNode* aParent, return result; } +void +APZCTreeManager::StartScrollbarDrag(const ScrollableLayerGuid& aGuid, + const AsyncDragMetrics& aDragMetrics) +{ + + nsRefPtr apzc = GetTargetAPZC(aGuid); + if (!apzc) { + return; + } + + // TODO Confirm the input block + //uint64_t inputBlockId = aDragMetrics.mDragStartSequenceNumber; + //mInputQueue->SetConfirmedMouseBlock(inputBlockId, apzc, aDragMetrics); +} + HitTestingTreeNode* APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer, const FrameMetrics& aMetrics, @@ -618,6 +633,18 @@ WillHandleWheelEvent(WidgetWheelEvent* aEvent) !EventStateManager::WheelEventNeedsDeltaMultipliers(aEvent); } +static bool +WillHandleMouseEvent(const WidgetMouseEventBase& aEvent) +{ + if (!gfxPrefs::APZDragEnabled()) { + return false; + } + + return aEvent.mMessage == eMouseMove || + aEvent.mMessage == eMouseDown || + aEvent.mMessage == eMouseUp; +} + template static bool WillHandleInput(const PanGestureOrScrollWheelInput& aPanInput) @@ -663,6 +690,28 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, MultiTouchInput& touchInput = aEvent.AsMultiTouchInput(); result = ProcessTouchInput(touchInput, aOutTargetGuid, aOutInputBlockId); break; + } case MOUSE_INPUT: { + MouseInput& mouseInput = aEvent.AsMouseInput(); + + nsRefPtr apzc = GetTargetAPZC(mouseInput.mOrigin, + &hitResult); + if (apzc) { + result = mInputQueue->ReceiveInputEvent( + apzc, + /* aTargetConfirmed = */ false, + mouseInput, aOutInputBlockId); + + // Update the out-parameters so they are what the caller expects. + apzc->GetGuid(aOutTargetGuid); + + // TODO Dagging on a scrollbar probably behaves differently from + // the other input types in that the gecko coordinates are the same + // as the screen coordinates even though the async transform on the APZC + // is changing. I'm not really sure at this point and it'll take some + // though to figure out properly. + //mouseInput.mOrigin = untransformedOrigin; + } + break; } case SCROLLWHEEL_INPUT: { FlushRepaintsToClearScreenToGeckoTransform(); @@ -987,6 +1036,21 @@ APZCTreeManager::ProcessEvent(WidgetInputEvent& aEvent, return result; } +nsEventStatus +APZCTreeManager::ProcessMouseEvent(WidgetMouseEventBase& aEvent, + ScrollableLayerGuid* aOutTargetGuid, + uint64_t* aOutInputBlockId) +{ + MouseInput input(aEvent); + input.mOrigin = ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y); + + nsEventStatus status = ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId); + + aEvent.refPoint.x = input.mOrigin.x; + aEvent.refPoint.y = input.mOrigin.y; + return status; +} + nsEventStatus APZCTreeManager::ProcessWheelEvent(WidgetWheelEvent& aEvent, ScrollableLayerGuid* aOutTargetGuid, @@ -1033,6 +1097,13 @@ APZCTreeManager::ReceiveInputEvent(WidgetInputEvent& aEvent, } switch (aEvent.mClass) { + case eMouseEventClass: { + WidgetMouseEventBase& mouseEvent = *aEvent.AsMouseEventBase(); + if (WillHandleMouseEvent(mouseEvent)) { + return ProcessMouseEvent(mouseEvent, aOutTargetGuid, aOutInputBlockId); + } + return ProcessEvent(aEvent, aOutTargetGuid, aOutInputBlockId); + } case eTouchEventClass: { WidgetTouchEvent& touchEvent = *aEvent.AsTouchEvent(); MultiTouchInput touchInput(touchEvent); diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index 127285bf8b76..0e94570620a0 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -18,6 +18,7 @@ #include "mozilla/layers/APZUtils.h" // for HitTestResult #include "mozilla/layers/TouchCounter.h"// for TouchCounter #include "mozilla/Monitor.h" // for Monitor +#include "mozilla/TimeStamp.h" // for mozilla::TimeStamp #include "mozilla/Vector.h" // for mozilla::Vector #include "nsAutoPtr.h" // for nsRefPtr #include "nsCOMPtr.h" // for already_AddRefed @@ -395,6 +396,9 @@ public: nsRefPtr aOverscrollHandoffChain, bool aHandoff); + void StartScrollbarDrag(const ScrollableLayerGuid& aGuid, + const AsyncDragMetrics& aDragMetrics); + /* * Build the chain of APZCs that will handle overscroll for a pan starting at |aInitialTarget|. */ @@ -457,6 +461,9 @@ private: nsEventStatus ProcessEvent(WidgetInputEvent& inputEvent, ScrollableLayerGuid* aOutTargetGuid, uint64_t* aOutInputBlockId); + nsEventStatus ProcessMouseEvent(WidgetMouseEventBase& aInput, + ScrollableLayerGuid* aOutTargetGuid, + uint64_t* aOutInputBlockId); void UpdateWheelTransaction(WidgetInputEvent& aEvent); void UpdateZoomConstraintsRecursively(HitTestingTreeNode* aNode, const ZoomConstraints& aConstraints); From 60376c4a7038df2123bd6f29ed7fe38fdea0a36f Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 28 Sep 2015 17:00:25 -0400 Subject: [PATCH 058/189] Bug 1199885 - Part 12: Add StartScrollbarDrag IPC message. r=kats --HG-- extra : commitid : 87IsjW2NpRX --- dom/ipc/PBrowser.ipdl | 4 ++++ dom/ipc/TabParent.cpp | 10 ++++++++++ dom/ipc/TabParent.h | 3 +++ layout/ipc/RenderFrameParent.cpp | 15 +++++++++++++++ layout/ipc/RenderFrameParent.h | 4 ++++ widget/PuppetWidget.cpp | 6 ++++++ widget/PuppetWidget.h | 1 + widget/nsBaseWidget.cpp | 16 ++++++++++++++++ widget/nsBaseWidget.h | 2 ++ widget/nsIWidget.h | 4 ++++ 10 files changed, 65 insertions(+) diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index b2b56e1c6f3a..8e33e89071e8 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -60,6 +60,7 @@ using mozilla::CommandInt from "mozilla/EventForwards.h"; using mozilla::Modifiers from "mozilla/EventForwards.h"; using mozilla::layers::GeckoContentController::APZStateChange from "mozilla/layers/GeckoContentController.h"; using mozilla::WritingMode from "mozilla/WritingModes.h"; +using mozilla::layers::AsyncDragMetrics from "mozilla/layers/AsyncDragMetrics.h"; using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h"; using nsIWidget::TouchPointerState from "nsIWidget.h"; using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h"; @@ -545,6 +546,9 @@ parent: prio(high) sync DispatchMouseEvent(WidgetMouseEvent event); prio(high) sync DispatchKeyboardEvent(WidgetKeyboardEvent event); + // Start an APZ drag on a scrollbar + async StartScrollbarDrag(AsyncDragMetrics aDragMetrics); + InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action, nsCString visualData, uint32_t width, uint32_t height, uint32_t stride, uint8_t format, int32_t dragAreaX, int32_t dragAreaY); diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 2d45ae9d3b26..0f36e63732a0 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -26,6 +26,7 @@ #include "mozilla/IMEStateManager.h" #include "mozilla/ipc/DocumentRendererParent.h" #include "mozilla/jsipc/CrossProcessObjectWrappers.h" +#include "mozilla/layers/AsyncDragMetrics.h" #include "mozilla/layers/CompositorParent.h" #include "mozilla/layers/InputAPZContext.h" #include "mozilla/layout/RenderFrameParent.h" @@ -3051,6 +3052,15 @@ TabParent::RecvSetTargetAPZC(const uint64_t& aInputBlockId, return true; } +bool +TabParent::RecvStartScrollbarDrag(const AsyncDragMetrics& aDragMetrics) +{ + if (RenderFrameParent* rfp = GetRenderFrame()) { + rfp->StartScrollbarDrag(aDragMetrics); + } + return true; +} + bool TabParent::RecvSetAllowedTouchBehavior(const uint64_t& aInputBlockId, nsTArray&& aFlags) diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 1d4c5cf186d5..ccd123cbd2be 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -44,6 +44,7 @@ class CpowHolder; } // namespace jsipc namespace layers { +class AsyncDragMetrics; struct FrameMetrics; struct TextureFactoryIdentifier; } // namespace layers @@ -83,6 +84,7 @@ class TabParent final : public PBrowserParent , public nsIWebBrowserPersistable { typedef mozilla::dom::ClonedMessageData ClonedMessageData; + typedef mozilla::layers::AsyncDragMetrics AsyncDragMetrics; virtual ~TabParent(); @@ -243,6 +245,7 @@ public: virtual bool RecvDispatchWheelEvent(const mozilla::WidgetWheelEvent& aEvent) override; virtual bool RecvDispatchMouseEvent(const mozilla::WidgetMouseEvent& aEvent) override; virtual bool RecvDispatchKeyboardEvent(const mozilla::WidgetKeyboardEvent& aEvent) override; + virtual bool RecvStartScrollbarDrag(const AsyncDragMetrics& aDragMetrics) override; virtual PColorPickerParent* AllocPColorPickerParent(const nsString& aTitle, const nsString& aInitialColor) override; diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp index c79f80f41726..9d937fc9faf5 100644 --- a/layout/ipc/RenderFrameParent.cpp +++ b/layout/ipc/RenderFrameParent.cpp @@ -597,6 +597,21 @@ RenderFrameParent::HitTest(const nsRect& aRect) return mTouchRegion.Contains(aRect); } +void +RenderFrameParent::StartScrollbarDrag(const AsyncDragMetrics& aDragMetrics) +{ + if (GetApzcTreeManager()) { + uint64_t layersId = GetLayersId(); + ScrollableLayerGuid guid(layersId, aDragMetrics.mPresShellId, + aDragMetrics.mViewId); + + APZThreadUtils::RunOnControllerThread( + NewRunnableMethod(GetApzcTreeManager(), + &APZCTreeManager::StartScrollbarDrag, + guid, aDragMetrics)); + } +} + void RenderFrameParent::GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier) { diff --git a/layout/ipc/RenderFrameParent.h b/layout/ipc/RenderFrameParent.h index 062bdded7b8c..21f3b53347e1 100644 --- a/layout/ipc/RenderFrameParent.h +++ b/layout/ipc/RenderFrameParent.h @@ -25,6 +25,7 @@ class InputEvent; namespace layers { class APZCTreeManager; +class AsyncDragMetrics; class TargetConfig; struct TextureFactoryIdentifier; struct ScrollableLayerGuid; @@ -36,6 +37,7 @@ class RemoteContentController; class RenderFrameParent : public PRenderFrameParent { + typedef mozilla::layers::AsyncDragMetrics AsyncDragMetrics; typedef mozilla::layers::FrameMetrics FrameMetrics; typedef mozilla::layers::ContainerLayer ContainerLayer; typedef mozilla::layers::Layer Layer; @@ -93,6 +95,8 @@ public: bool HitTest(const nsRect& aRect); + void StartScrollbarDrag(const AsyncDragMetrics& aDragMetrics); + void GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier); inline uint64_t GetLayersId() { return mLayersId; } diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp index 221d10de3334..c5ef2d0ff0e8 100644 --- a/widget/PuppetWidget.cpp +++ b/widget/PuppetWidget.cpp @@ -1141,6 +1141,12 @@ uint32_t PuppetWidget::GetMaxTouchPoints() const return sTouchPoints; } +void +PuppetWidget::StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) +{ + mTabChild->SendStartScrollbarDrag(aDragMetrics); +} + PuppetScreen::PuppetScreen(void *nativeScreen) { } diff --git a/widget/PuppetWidget.h b/widget/PuppetWidget.h index 6991f48698fa..b8b4b3f9fe59 100644 --- a/widget/PuppetWidget.h +++ b/widget/PuppetWidget.h @@ -251,6 +251,7 @@ public: virtual nsresult ClearNativeTouchSequence(nsIObserver* aObserver) override; virtual uint32_t GetMaxTouchPoints() const override; + virtual void StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) override; protected: bool mEnabled; bool mVisible; diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 59a368078d5e..7c5f760444f5 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -1674,6 +1674,22 @@ nsBaseWidget::GetRootAccessible() #endif // ACCESSIBILITY +void +nsBaseWidget::StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) +{ + if (!AsyncPanZoomEnabled()) { + return; + } + + MOZ_ASSERT(XRE_IsParentProcess() && mCompositorParent); + + int layersId = mCompositorParent->RootLayerTreeId();; + ScrollableLayerGuid guid(layersId, aDragMetrics.mPresShellId, aDragMetrics.mViewId); + + APZThreadUtils::RunOnControllerThread( + NewRunnableMethod(mAPZC.get(), &APZCTreeManager::StartScrollbarDrag, guid, aDragMetrics)); +} + nsIntRect nsBaseWidget::GetScaledScreenBounds() { diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index 91f0c368cccb..b8dc2bc914fc 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -312,6 +312,8 @@ public: return false; } + virtual void StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) override; + /** * Use this when GetLayerManager() returns a BasicLayerManager * (nsBaseWidget::GetLayerManager() does). This sets up the widget's diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 8cd47db5b560..44919ce060d9 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -49,6 +49,7 @@ namespace plugins { class PluginWidgetChild; } // namespace plugins namespace layers { +class AsyncDragMetrics; class Composer2D; class Compositor; class CompositorChild; @@ -316,6 +317,7 @@ class nsIWidget : public nsISupports { public: typedef mozilla::layers::Composer2D Composer2D; typedef mozilla::layers::CompositorChild CompositorChild; + typedef mozilla::layers::AsyncDragMetrics AsyncDragMetrics; typedef mozilla::layers::FrameMetrics FrameMetrics; typedef mozilla::layers::LayerManager LayerManager; typedef mozilla::layers::LayerManagerComposite LayerManagerComposite; @@ -1676,6 +1678,8 @@ class nsIWidget : public nsISupports { */ virtual bool CaptureWidgetOnScreen(mozilla::RefPtr aDT) = 0; + virtual void StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) = 0; + private: class LongTapInfo { From b3c256920202441a4bf366188366372d000b3e7f Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 28 Sep 2015 17:00:25 -0400 Subject: [PATCH 059/189] Bug 1199885 - Part 13: Let nsSliderFrame trigger async scrolling via StartScrollbarDrag. r=kats --HG-- extra : commitid : LMXLmzjgQ4 --- layout/xul/nsSliderFrame.cpp | 54 ++++++++++++++++++++++++++++++++++++ layout/xul/nsSliderFrame.h | 2 ++ 2 files changed, 56 insertions(+) diff --git a/layout/xul/nsSliderFrame.cpp b/layout/xul/nsSliderFrame.cpp index aaa3f9bdf814..4c0652d7b0d4 100644 --- a/layout/xul/nsSliderFrame.cpp +++ b/layout/xul/nsSliderFrame.cpp @@ -23,6 +23,7 @@ #include "nsIDOMMouseEvent.h" #include "nsScrollbarButtonFrame.h" #include "nsISliderListener.h" +#include "nsIScrollableFrame.h" #include "nsIScrollbarMediator.h" #include "nsScrollbarFrame.h" #include "nsRepeatService.h" @@ -35,9 +36,13 @@ #include "mozilla/Preferences.h" #include "mozilla/LookAndFeel.h" #include "mozilla/MouseEvents.h" +#include "mozilla/layers/AsyncDragMetrics.h" +#include "mozilla/layers/InputAPZContext.h" #include using namespace mozilla; +using mozilla::layers::AsyncDragMetrics; +using mozilla::layers::InputAPZContext; bool nsSliderFrame::gMiddlePref = false; int32_t nsSliderFrame::gSnapMultiplier; @@ -893,6 +898,53 @@ nsSliderMediator::HandleEvent(nsIDOMEvent* aEvent) return NS_OK; } +bool +nsSliderFrame::StartAPZDrag(WidgetGUIEvent* aEvent) +{ + if (!gfxPlatform::GetPlatform()->SupportsApzDragInput()) { + return false; + } + + nsContainerFrame* cf = GetScrollbar()->GetParent(); + if (!cf) { + return false; + } + + nsIContent* scrollableContent = cf->GetContent(); + if (!scrollableContent) { + return false; + } + + mozilla::layers::FrameMetrics::ViewID scrollTargetId; + bool hasID = nsLayoutUtils::FindIDFor(scrollableContent, &scrollTargetId); + bool hasAPZView = hasID && (scrollTargetId != layers::FrameMetrics::NULL_SCROLL_ID); + + if (!hasAPZView) { + return false; + } + + nsIFrame* scrollbarBox = GetScrollbar(); + nsCOMPtr scrollbar = GetContentOfBox(scrollbarBox); + + // This rect is the range in which the scroll thumb can slide in. + nsRect sliderTrack = GetRect() - scrollbarBox->GetPosition(); + CSSIntRect sliderTrackCSS = CSSIntRect::FromAppUnitsRounded(sliderTrack); + + uint64_t inputblockId = InputAPZContext::GetInputBlockId(); + uint32_t presShellId = PresContext()->PresShell()->GetPresShellId(); + AsyncDragMetrics dragMetrics(scrollTargetId, presShellId, inputblockId, + NSAppUnitsToIntPixels(mDragStart, + float(AppUnitsPerCSSPixel())), + sliderTrackCSS, + IsHorizontal() ? AsyncDragMetrics::HORIZONTAL : + AsyncDragMetrics::VERTICAL); + + // When we start an APZ drag, we wont get mouse events for the drag. + // APZ will consume them all and only notify us of the new scroll position. + this->GetNearestWidget()->StartAsyncScrollbarDrag(dragMetrics); + return true; +} + nsresult nsSliderFrame::StartDrag(nsIDOMEvent* aEvent) { @@ -960,6 +1012,8 @@ nsSliderFrame::StartDrag(nsIDOMEvent* aEvent) mDragStart = pos - mThumbStart; + StartAPZDrag(event); + #ifdef DEBUG_SLIDER printf("Pressed mDragStart=%d\n",mDragStart); #endif diff --git a/layout/xul/nsSliderFrame.h b/layout/xul/nsSliderFrame.h index 2b2a74818f74..1cbdda275f7c 100644 --- a/layout/xul/nsSliderFrame.h +++ b/layout/xul/nsSliderFrame.h @@ -100,6 +100,8 @@ public: nsresult StartDrag(nsIDOMEvent* aEvent); nsresult StopDrag(); + bool StartAPZDrag(mozilla::WidgetGUIEvent* aEvent); + static int32_t GetCurrentPosition(nsIContent* content); static int32_t GetMinPosition(nsIContent* content); static int32_t GetMaxPosition(nsIContent* content); From 49ed25ea696afa23e2d698c9e212c2530ee0ec61 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Wed, 7 Oct 2015 11:02:37 -0700 Subject: [PATCH 060/189] Bug 1210575 part 1: Rename CSS parser function "ParseWebkitPrefixedGradient()" to be more specific, now that we'll have several ways of parsing these expressions. r=heycam (This patch renames the function to "ParseWebkitPrefixedGradientWithService", indicating that this is the version that calls out to the CSSUnprefixingService.) --- layout/style/nsCSSParser.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index ff2aeb5182dc..f0001ebd7fb8 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -744,11 +744,12 @@ protected: bool aMustCallValueAppended, bool* aChanged, nsCSSContextType aContext); - // When we detect a webkit-prefixed gradient expression, this function can - // be used to parse its body into outparam |aValue|. Only call if - // ShouldUseUnprefixingService() returns true. - bool ParseWebkitPrefixedGradient(nsAString& aPrefixedFuncName, - nsCSSValue& aValue); + // When we detect a webkit-prefixed gradient expression, this function can be + // used to parse its body into outparam |aValue|, with the help of the + // CSSUnprefixingService. + // Only call if ShouldUseUnprefixingService() returns true. + bool ParseWebkitPrefixedGradientWithService(nsAString& aPrefixedFuncName, + nsCSSValue& aValue); bool ParseProperty(nsCSSProperty aPropID); bool ParsePropertyByFunction(nsCSSProperty aPropID); @@ -6757,8 +6758,9 @@ CSSParserImpl::ParsePropertyWithUnprefixingService( } bool -CSSParserImpl::ParseWebkitPrefixedGradient(nsAString& aPrefixedFuncName, - nsCSSValue& aValue) +CSSParserImpl::ParseWebkitPrefixedGradientWithService( + nsAString& aPrefixedFuncName, + nsCSSValue& aValue) { MOZ_ASSERT(ShouldUseUnprefixingService(), "Should only call if we're allowed to use unprefixing service"); @@ -7470,7 +7472,7 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue, // Copy 'tmp' into a string on the stack, since as soon as we // start parsing, its backing store (in "tk") will be overwritten nsAutoString prefixedFuncName(tmp); - return ParseWebkitPrefixedGradient(prefixedFuncName, aValue); + return ParseWebkitPrefixedGradientWithService(prefixedFuncName, aValue); } } if ((aVariantMask & VARIANT_IMAGE_RECT) != 0 && From cc6ae36a1c44a5236ea2ec1f200e58d42da2a2dc Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Wed, 7 Oct 2015 11:02:50 -0700 Subject: [PATCH 061/189] Bug 1210575 part 2: Refactor out the body of a long compound "if" expression into a helper function, IsFunctionTokenValidForBackgroundImage. r=heycam --- layout/style/nsCSSParser.cpp | 47 ++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index f0001ebd7fb8..57a8c99a9d7b 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -737,7 +737,7 @@ protected: nsCSSKeyword LookupKeywordPrefixAware(nsAString& aKeywordStr, const KTableValue aKeywordTable[]); - bool ShouldUseUnprefixingService(); + bool ShouldUseUnprefixingService() const; bool ParsePropertyWithUnprefixingService(const nsAString& aPropertyName, css::Declaration* aDeclaration, uint32_t aFlags, @@ -805,6 +805,7 @@ protected: mPosition(aPosition), mSize(aSize) {}; }; + bool IsFunctionTokenValidForBackgroundImage(const nsCSSToken& aToken) const; bool ParseBackgroundItem(BackgroundParseState& aState); bool ParseValueList(nsCSSProperty aPropID); // a single value prop-id @@ -6683,7 +6684,7 @@ CSSParserImpl::LookupKeywordPrefixAware(nsAString& aKeywordStr, } bool -CSSParserImpl::ShouldUseUnprefixingService() +CSSParserImpl::ShouldUseUnprefixingService() const { if (!sUnprefixingServiceEnabled) { // Unprefixing is globally disabled. @@ -10633,6 +10634,33 @@ CSSParserImpl::ParseBackground() return true; } +// Helper for ParseBackgroundItem. Returns true if the passed-in nsCSSToken is +// a function which is accepted for background-image. +bool +CSSParserImpl::IsFunctionTokenValidForBackgroundImage( + const nsCSSToken& aToken) const +{ + MOZ_ASSERT(aToken.mType == eCSSToken_Function, + "Should only be called for function-typed tokens"); + + const nsAString& funcName = aToken.mIdent; + + return funcName.LowerCaseEqualsLiteral("linear-gradient") || + funcName.LowerCaseEqualsLiteral("radial-gradient") || + funcName.LowerCaseEqualsLiteral("repeating-linear-gradient") || + funcName.LowerCaseEqualsLiteral("repeating-radial-gradient") || + funcName.LowerCaseEqualsLiteral("-moz-linear-gradient") || + funcName.LowerCaseEqualsLiteral("-moz-radial-gradient") || + funcName.LowerCaseEqualsLiteral("-moz-repeating-linear-gradient") || + funcName.LowerCaseEqualsLiteral("-moz-repeating-radial-gradient") || + funcName.LowerCaseEqualsLiteral("-moz-image-rect") || + funcName.LowerCaseEqualsLiteral("-moz-element") || + (ShouldUseUnprefixingService() && + (funcName.LowerCaseEqualsLiteral("-webkit-gradient") || + funcName.LowerCaseEqualsLiteral("-webkit-linear-gradient") || + funcName.LowerCaseEqualsLiteral("-webkit-radial-gradient"))); +} + // Parse one item of the background shorthand property. bool CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState& aState) @@ -10775,20 +10803,7 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState& aState) } } else if (tt == eCSSToken_URL || (tt == eCSSToken_Function && - (mToken.mIdent.LowerCaseEqualsLiteral("linear-gradient") || - mToken.mIdent.LowerCaseEqualsLiteral("radial-gradient") || - mToken.mIdent.LowerCaseEqualsLiteral("repeating-linear-gradient") || - mToken.mIdent.LowerCaseEqualsLiteral("repeating-radial-gradient") || - mToken.mIdent.LowerCaseEqualsLiteral("-moz-linear-gradient") || - mToken.mIdent.LowerCaseEqualsLiteral("-moz-radial-gradient") || - mToken.mIdent.LowerCaseEqualsLiteral("-moz-repeating-linear-gradient") || - mToken.mIdent.LowerCaseEqualsLiteral("-moz-repeating-radial-gradient") || - mToken.mIdent.LowerCaseEqualsLiteral("-moz-image-rect") || - mToken.mIdent.LowerCaseEqualsLiteral("-moz-element") || - (ShouldUseUnprefixingService() && - (mToken.mIdent.LowerCaseEqualsLiteral("-webkit-gradient") || - mToken.mIdent.LowerCaseEqualsLiteral("-webkit-linear-gradient") || - mToken.mIdent.LowerCaseEqualsLiteral("-webkit-radial-gradient")))))) { + IsFunctionTokenValidForBackgroundImage(mToken))) { if (haveImage) return false; haveImage = true; From 05977261271b859ea06ac19c5f97266265cbf997 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Wed, 7 Oct 2015 11:02:50 -0700 Subject: [PATCH 062/189] Bug 1210575 part 3: Refactor CSS gradient-parsing code to use a flags bitfield instead of multiple bool args for customizing behavior. r=heycam --- layout/style/nsCSSParser.cpp | 48 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index 57a8c99a9d7b..d0c4a7a38fdd 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -1107,10 +1107,13 @@ protected: bool ParseImageRect(nsCSSValue& aImage); bool ParseElement(nsCSSValue& aValue); bool ParseColorStop(nsCSSValueGradient* aGradient); - bool ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating, - bool aIsLegacy); - bool ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating, - bool aIsLegacy); + + enum GradientParsingFlags { + eGradient_Repeating = 1 << 0, // repeating-{linear|radial}-gradient + eGradient_MozLegacy = 1 << 1, // -moz-{linear|radial}-gradient + }; + bool ParseLinearGradient(nsCSSValue& aValue, uint8_t aFlags); + bool ParseRadialGradient(nsCSSValue& aValue, uint8_t aFlags); bool IsLegacyGradientLine(const nsCSSTokenType& aType, const nsString& aId); bool ParseGradientColorStops(nsCSSValueGradient* aGradient, @@ -6813,10 +6816,10 @@ CSSParserImpl::ParseWebkitPrefixedGradientWithService( nsAutoScannerChanger scannerChanger(this, unprefixedFuncBody); if (unprefixedFuncName.EqualsLiteral("linear-gradient")) { - return ParseLinearGradient(aValue, false, false); + return ParseLinearGradient(aValue, 0); } if (unprefixedFuncName.EqualsLiteral("radial-gradient")) { - return ParseRadialGradient(aValue, false, false); + return ParseRadialGradient(aValue, 0); } NS_ERROR("CSSUnprefixingService returned an unrecognized type of " @@ -7449,26 +7452,25 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue, eCSSToken_Function == tk->mType) { // a generated gradient nsDependentString tmp(tk->mIdent, 0); - bool isLegacy = false; + uint8_t gradientFlags = 0; if (sMozGradientsEnabled && StringBeginsWith(tmp, NS_LITERAL_STRING("-moz-"))) { tmp.Rebind(tmp, 5); - isLegacy = true; + gradientFlags |= eGradient_MozLegacy; } - bool isRepeating = false; if (StringBeginsWith(tmp, NS_LITERAL_STRING("repeating-"))) { tmp.Rebind(tmp, 10); - isRepeating = true; + gradientFlags |= eGradient_Repeating; } if (tmp.LowerCaseEqualsLiteral("linear-gradient")) { - return ParseLinearGradient(aValue, isRepeating, isLegacy); + return ParseLinearGradient(aValue, gradientFlags); } if (tmp.LowerCaseEqualsLiteral("radial-gradient")) { - return ParseRadialGradient(aValue, isRepeating, isLegacy); + return ParseRadialGradient(aValue, gradientFlags); } if (ShouldUseUnprefixingService() && - !isRepeating && !isLegacy && + !gradientFlags && StringBeginsWith(tmp, NS_LITERAL_STRING("-webkit-"))) { // Copy 'tmp' into a string on the stack, since as soon as we // start parsing, its backing store (in "tk") will be overwritten @@ -9248,11 +9250,11 @@ CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient) // // : , [, ]* bool -CSSParserImpl::ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating, - bool aIsLegacy) +CSSParserImpl::ParseLinearGradient(nsCSSValue& aValue, + uint8_t aFlags) { nsRefPtr cssGradient - = new nsCSSValueGradient(false, aIsRepeating); + = new nsCSSValueGradient(false, aFlags & eGradient_Repeating); if (!GetToken(true)) { return false; @@ -9290,7 +9292,7 @@ CSSParserImpl::ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating, return ParseGradientColorStops(cssGradient, aValue); } - if (!aIsLegacy) { + if (!(aFlags & eGradient_MozLegacy)) { UngetToken(); // , @@ -9338,11 +9340,11 @@ CSSParserImpl::ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating, } bool -CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating, - bool aIsLegacy) +CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, + uint8_t aFlags) { nsRefPtr cssGradient - = new nsCSSValueGradient(true, aIsRepeating); + = new nsCSSValueGradient(true, aFlags & eGradient_Repeating); // [ || ] bool haveShape = @@ -9350,7 +9352,7 @@ CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating, nsCSSProps::kRadialGradientShapeKTable); bool haveSize = ParseVariant(cssGradient->GetRadialSize(), VARIANT_KEYWORD, - aIsLegacy ? + (aFlags & eGradient_MozLegacy) ? nsCSSProps::kRadialGradientLegacySizeKTable : nsCSSProps::kRadialGradientSizeKTable); if (haveSize) { @@ -9359,7 +9361,7 @@ CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating, haveShape = ParseVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD, nsCSSProps::kRadialGradientShapeKTable); } - } else if (!aIsLegacy) { + } else if (!(aFlags & eGradient_MozLegacy)) { // Save RadialShape before parsing RadiusX because RadialShape and // RadiusX share the storage. int32_t shape = @@ -9410,7 +9412,7 @@ CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating, return false; } - if (!aIsLegacy) { + if (!(aFlags & eGradient_MozLegacy)) { if (mToken.mType == eCSSToken_Ident && mToken.mIdent.LowerCaseEqualsLiteral("at")) { // [ || ]? at , From 90a1ef80843ceb25c8b32f88239de779a66cc0f4 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Wed, 7 Oct 2015 11:02:50 -0700 Subject: [PATCH 063/189] Bug 1210575 part 4: Prevent CSS parser from invoking CSSUnprefixingService if native webkit prefix support is enabled. r=heycam --- layout/style/nsCSSParser.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index d0c4a7a38fdd..b460e73c56b5 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -57,6 +57,7 @@ typedef nsCSSProps::KTableValue KTableValue; // pref-backed bool values (hooked up in nsCSSParser::Startup) static bool sOpentypeSVGEnabled; +static bool sWebkitPrefixedAliasesEnabled; static bool sUnprefixingServiceEnabled; #ifdef NIGHTLY_BUILD static bool sUnprefixingServiceGloballyWhitelisted; @@ -6693,6 +6694,11 @@ CSSParserImpl::ShouldUseUnprefixingService() const // Unprefixing is globally disabled. return false; } + if (sWebkitPrefixedAliasesEnabled) { + // Native webkit-prefix support is enabled, which trumps the unprefixing + // service for handling prefixed CSS. Don't try to use both at once. + return false; + } #ifdef NIGHTLY_BUILD if (sUnprefixingServiceGloballyWhitelisted) { @@ -15727,6 +15733,8 @@ nsCSSParser::Startup() { Preferences::AddBoolVarCache(&sOpentypeSVGEnabled, "gfx.font_rendering.opentype_svg.enabled"); + Preferences::AddBoolVarCache(&sWebkitPrefixedAliasesEnabled, + "layout.css.prefixes.webkit"); Preferences::AddBoolVarCache(&sUnprefixingServiceEnabled, "layout.css.unprefixing-service.enabled"); #ifdef NIGHTLY_BUILD From c5d5457154953a19c69b76a17d0fff652b38a7be Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 7 Oct 2015 11:07:44 -0700 Subject: [PATCH 064/189] Back out bug 967873 - Proxy nsDocumentViewer::PermitUnload to the child process --- browser/base/content/browser.js | 52 ++++------ browser/base/content/chatWindow.xul | 5 - browser/base/content/sanitize.js | 27 ++++-- browser/base/content/tabbrowser.xml | 95 ++++++++----------- docshell/base/nsDocShell.cpp | 4 +- docshell/base/nsIContentViewer.idl | 21 +++- dom/base/nsGlobalWindow.cpp | 13 +-- dom/html/nsHTMLDocument.cpp | 2 +- dom/interfaces/base/nsIBrowserDOMWindow.idl | 12 +-- dom/jsurl/nsJSProtocolHandler.cpp | 2 +- layout/base/nsDocumentViewer.cpp | 47 ++++++++- mobile/android/chrome/content/browser.js | 7 -- services/fxaccounts/FxAccountsOAuthClient.jsm | 38 ++++---- toolkit/content/browser-child.js | 16 ---- toolkit/content/widgets/browser.xml | 28 +----- toolkit/content/widgets/remote-browser.xml | 83 ---------------- toolkit/modules/BrowserUtils.jsm | 18 +--- 17 files changed, 167 insertions(+), 303 deletions(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 2a1a574dec25..c40b4e6de94b 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -4970,10 +4970,6 @@ nsBrowserAccess.prototype = { isTabContentWindow: function (aWindow) { return gBrowser.browsers.some(browser => browser.contentWindow == aWindow); }, - - canClose() { - return CanCloseWindow(); - }, } function getTogglableToolbars() { @@ -6439,26 +6435,6 @@ var IndexedDBPromptHelper = { } }; -function CanCloseWindow() -{ - // Avoid redundant calls to canClose from showing multiple - // PermitUnload dialogs. - if (window.skipNextCanClose) { - return true; - } - - for (let browser of gBrowser.browsers) { - let {permitUnload, timedOut} = browser.permitUnload(); - if (timedOut) { - return true; - } - if (!permitUnload) { - return false; - } - } - return true; -} - function WindowIsClosing() { if (TabView.isVisible()) { @@ -6469,19 +6445,27 @@ function WindowIsClosing() if (!closeWindow(false, warnAboutClosingWindow)) return false; - // In theory we should exit here and the Window's internal Close - // method should trigger canClose on nsBrowserAccess. However, by - // that point it's too late to be able to show a prompt for - // PermitUnload. So we do it here, when we still can. - if (CanCloseWindow()) { - // This flag ensures that the later canClose call does nothing. - // It's only needed to make tests pass, since they detect the - // prompt even when it's not actually shown. - window.skipNextCanClose = true; + // Bug 967873 - Proxy nsDocumentViewer::PermitUnload to the child process + if (gMultiProcessBrowser) return true; + + for (let browser of gBrowser.browsers) { + let ds = browser.docShell; + // Passing true to permitUnload indicates we plan on closing the window. + // This means that once unload is permitted, all further calls to + // permitUnload will be ignored. This avoids getting multiple prompts + // to unload the page. + if (ds.contentViewer && !ds.contentViewer.permitUnload(true)) { + // ... however, if the user aborts closing, we need to undo that, + // to ensure they get prompted again when we next try to close the window. + // We do this on the window's toplevel docshell instead of on the tab, so + // that all tabs we iterated before will get this reset. + window.getInterface(Ci.nsIDocShell).contentViewer.resetCloseWindow(); + return false; + } } - return false; + return true; } /** diff --git a/browser/base/content/chatWindow.xul b/browser/base/content/chatWindow.xul index 61b87e2c9109..aab0b7005ef3 100644 --- a/browser/base/content/chatWindow.xul +++ b/browser/base/content/chatWindow.xul @@ -131,11 +131,6 @@ chatBrowserAccess.prototype = { isTabContentWindow: function (aWindow) { return this.contentWindow == aWindow; }, - - canClose() { - let {BrowserUtils} = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}); - return BrowserUtils.canCloseWindow(window); - }, }; diff --git a/browser/base/content/sanitize.js b/browser/base/content/sanitize.js index 523e9251f30f..dd2703e23664 100644 --- a/browser/base/content/sanitize.js +++ b/browser/base/content/sanitize.js @@ -1,4 +1,4 @@ -// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- +// -*- indent-tabs-mode: nil; js-indent-level: 4 -*- /* 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/. */ @@ -567,17 +567,28 @@ Sanitizer.prototype = { openWindows: { privateStateForNewWindow: "non-private", _canCloseWindow: function(aWindow) { - if (aWindow.CanCloseWindow()) { - // We already showed PermitUnload for the window, so let's - // make sure we don't do it again when we actually close the - // window. - aWindow.skipNextCanClose = true; - return true; + // Bug 967873 - Proxy nsDocumentViewer::PermitUnload to the child process + if (!aWindow.gMultiProcessBrowser) { + // Cargo-culted out of browser.js' WindowIsClosing because we don't care + // about TabView or the regular 'warn me before closing windows with N tabs' + // stuff here, and more importantly, we want to set aCallerClosesWindow to true + // when calling into permitUnload: + for (let browser of aWindow.gBrowser.browsers) { + let ds = browser.docShell; + // 'true' here means we will be closing the window soon, so please don't dispatch + // another onbeforeunload event when we do so. If unload is *not* permitted somewhere, + // we will reset the flag that this triggers everywhere so that we don't interfere + // with the browser after all: + if (ds.contentViewer && !ds.contentViewer.permitUnload(true)) { + return false; + } + } } + return true; }, _resetAllWindowClosures: function(aWindowList) { for (let win of aWindowList) { - win.skipNextCanClose = false; + win.getInterface(Ci.nsIDocShell).contentViewer.resetCloseWindow(); } }, clear: Task.async(function*() { diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 7eb4300b733d..78ec72efc60d 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -1190,29 +1190,25 @@ this._tabAttrModified(this.mCurrentTab, ["selected"]); if (oldBrowser != newBrowser && - oldBrowser.getInPermitUnload) { - oldBrowser.getInPermitUnload(inPermitUnload => { - if (!inPermitUnload) { - return; - } - // Since the user is switching away from a tab that has - // a beforeunload prompt active, we remove the prompt. - // This prevents confusing user flows like the following: - // 1. User attempts to close Firefox - // 2. User switches tabs (ingoring a beforeunload prompt) - // 3. User returns to tab, presses "Leave page" - let promptBox = this.getTabModalPromptBox(oldBrowser); - let prompts = promptBox.listPrompts(); - // There might not be any prompts here if the tab was closed - // while in an onbeforeunload prompt, which will have - // destroyed aforementioned prompt already, so check there's - // something to remove, first: - if (prompts.length) { - // NB: This code assumes that the beforeunload prompt - // is the top-most prompt on the tab. - prompts[prompts.length - 1].abortPrompt(); - } - }); + oldBrowser.docShell && + oldBrowser.docShell.contentViewer.inPermitUnload) { + // Since the user is switching away from a tab that has + // a beforeunload prompt active, we remove the prompt. + // This prevents confusing user flows like the following: + // 1. User attempts to close Firefox + // 2. User switches tabs (ingoring a beforeunload prompt) + // 3. User returns to tab, presses "Leave page" + let promptBox = this.getTabModalPromptBox(oldBrowser); + let prompts = promptBox.listPrompts(); + // There might not be any prompts here if the tab was closed + // while in an onbeforeunload prompt, which will have + // destroyed aforementioned prompt already, so check there's + // something to remove, first: + if (prompts.length) { + // NB: This code assumes that the beforeunload prompt + // is the top-most prompt on the tab. + prompts[prompts.length - 1].abortPrompt(); + } } oldBrowser._urlbarFocused = (gURLBar && gURLBar.focused); @@ -2135,7 +2131,6 @@ if (aParams) { var animate = aParams.animate; var byMouse = aParams.byMouse; - var skipPermitUnload = aParams.skipPermitUnload; } // Handle requests for synchronously removing an already @@ -2148,7 +2143,7 @@ var isLastTab = (this.tabs.length - this._removingTabs.length == 1); - if (!this._beginRemoveTab(aTab, false, null, true, skipPermitUnload)) + if (!this._beginRemoveTab(aTab, false, null, true)) return; if (!aTab.pinned && !aTab.hidden && aTab._fullyOpen && byMouse) @@ -2196,7 +2191,6 @@ - diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 16cdac503c5c..23d8e23e86c9 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -7772,7 +7772,7 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal, mTiming->NotifyBeforeUnload(); bool okToUnload; - rv = mContentViewer->PermitUnload(&okToUnload); + rv = mContentViewer->PermitUnload(false, &okToUnload); if (NS_SUCCEEDED(rv) && !okToUnload) { // The user chose not to unload the page, interrupt the load. @@ -10111,7 +10111,7 @@ nsDocShell::InternalLoad(nsIURI* aURI, // protocol handler deals with this for javascript: URLs. if (!isJavaScript && aFileName.IsVoid() && mContentViewer) { bool okToUnload; - rv = mContentViewer->PermitUnload(&okToUnload); + rv = mContentViewer->PermitUnload(false, &okToUnload); if (NS_SUCCEEDED(rv) && !okToUnload) { // The user chose not to unload the page, interrupt the diff --git a/docshell/base/nsIContentViewer.idl b/docshell/base/nsIContentViewer.idl index c35c9fd5d084..507a5f41e27f 100644 --- a/docshell/base/nsIContentViewer.idl +++ b/docshell/base/nsIContentViewer.idl @@ -31,7 +31,7 @@ class nsDOMNavigationTiming; [ptr] native nsDOMNavigationTimingPtr(nsDOMNavigationTiming); [ref] native nsIContentViewerTArray(nsTArray >); -[scriptable, builtinclass, uuid(91b6c1f3-fc5f-43a9-88f4-9286bd19387f)] +[scriptable, builtinclass, uuid(702e0a92-7d63-490e-b5ee-d247e6bd4588)] interface nsIContentViewer : nsISupports { @@ -46,8 +46,12 @@ interface nsIContentViewer : nsISupports /** * Checks if the document wants to prevent unloading by firing beforeunload on * the document, and if it does, prompts the user. The result is returned. + * + * @param aCallerClosesWindow indicates that the current caller will close the + * window. If the method returns true, all subsequent calls will be + * ignored. */ - boolean permitUnload(); + boolean permitUnload([optional] in boolean aCallerClosesWindow); /** * Exposes whether we're blocked in a call to permitUnload. @@ -59,7 +63,8 @@ interface nsIContentViewer : nsISupports * track of whether the user has responded to a prompt. * Used internally by the scriptable version to ensure we only prompt once. */ - [noscript,nostdcall] boolean permitUnloadInternal(inout boolean aShouldPrompt); + [noscript,nostdcall] boolean permitUnloadInternal(in boolean aCallerClosesWindow, + inout boolean aShouldPrompt); /** * Exposes whether we're in the process of firing the beforeunload event. @@ -67,6 +72,16 @@ interface nsIContentViewer : nsISupports */ readonly attribute boolean beforeUnloadFiring; + /** + * Works in tandem with permitUnload, if the caller decides not to close the + * window it indicated it will, it is the caller's responsibility to reset + * that with this method. + * + * @Note this method is only meant to be called on documents for which the + * caller has indicated that it will close the window. If that is not the case + * the behavior of this method is undefined. + */ + void resetCloseWindow(); void pageHide(in boolean isUnload); /** diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 27b75c741c46..71b490e21da9 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -8752,17 +8752,6 @@ nsGlobalWindow::CanClose() { MOZ_ASSERT(IsOuterWindow()); - if (mIsChrome) { - nsCOMPtr bwin; - nsIDOMChromeWindow* chromeWin = static_cast(this); - chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin)); - - bool canClose = true; - if (bwin && NS_SUCCEEDED(bwin->CanClose(&canClose))) { - return canClose; - } - } - if (!mDocShell) { return true; } @@ -8776,7 +8765,7 @@ nsGlobalWindow::CanClose() mDocShell->GetContentViewer(getter_AddRefs(cv)); if (cv) { bool canClose; - nsresult rv = cv->PermitUnload(&canClose); + nsresult rv = cv->PermitUnload(false, &canClose); if (NS_SUCCEEDED(rv) && !canClose) return false; diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index 80c136b7d110..7bb56d898df9 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -1519,7 +1519,7 @@ nsHTMLDocument::Open(JSContext* cx, if (cv) { bool okToUnload; - if (NS_SUCCEEDED(cv->PermitUnload(&okToUnload)) && !okToUnload) { + if (NS_SUCCEEDED(cv->PermitUnload(false, &okToUnload)) && !okToUnload) { // We don't want to unload, so stop here, but don't throw an // exception. nsCOMPtr ret = this; diff --git a/dom/interfaces/base/nsIBrowserDOMWindow.idl b/dom/interfaces/base/nsIBrowserDOMWindow.idl index d94ff6e0ae01..d0203f3ae9c9 100644 --- a/dom/interfaces/base/nsIBrowserDOMWindow.idl +++ b/dom/interfaces/base/nsIBrowserDOMWindow.idl @@ -17,7 +17,7 @@ interface nsIOpenURIInFrameParams : nsISupports attribute boolean isPrivate; }; -[scriptable, uuid(31da1ce2-aec4-4c26-ac66-d622935c3bf4)] +[scriptable, uuid(99f5a347-722c-4337-bd38-f14ec94801b3)] /** * The C++ source has access to the browser script source through @@ -99,14 +99,6 @@ interface nsIBrowserDOMWindow : nsISupports * @return whether the window is the main content window for any * currently open tab in this toplevel browser window. */ - boolean isTabContentWindow(in nsIDOMWindow aWindow); - - /** - * This function is responsible for calling - * nsIContentViewer::PermitUnload on each frame in the window. It - * returns true if closing the window is allowed. See canClose() in - * BrowserUtils.jsm for a simple implementation of this method. - */ - boolean canClose(); + boolean isTabContentWindow(in nsIDOMWindow aWindow); }; diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp index 0b99bb9a4079..87674c1d9f7b 100644 --- a/dom/jsurl/nsJSProtocolHandler.cpp +++ b/dom/jsurl/nsJSProtocolHandler.cpp @@ -749,7 +749,7 @@ nsJSChannel::EvaluateScript() if (cv) { bool okToUnload; - if (NS_SUCCEEDED(cv->PermitUnload(&okToUnload)) && + if (NS_SUCCEEDED(cv->PermitUnload(false, &okToUnload)) && !okToUnload) { // The user didn't want to unload the current // page, translate this into an undefined diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 0ee6c0607070..0fad98911cdc 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -410,6 +410,7 @@ protected: nsCString mForceCharacterSet; bool mIsPageMode; + bool mCallerIsClosingWindow; bool mInitializedForPrintPreview; bool mHidden; }; @@ -460,6 +461,7 @@ void nsDocumentViewer::PrepareToStartLoad() mLoaded = false; mAttachedToParent = false; mDeferredWindowClose = false; + mCallerIsClosingWindow = false; #ifdef NS_PRINTING mPrintIsPending = false; @@ -1047,15 +1049,18 @@ nsDocumentViewer::LoadComplete(nsresult aStatus) } NS_IMETHODIMP -nsDocumentViewer::PermitUnload(bool *aPermitUnload) +nsDocumentViewer::PermitUnload(bool aCallerClosesWindow, + bool *aPermitUnload) { bool shouldPrompt = true; - return PermitUnloadInternal(&shouldPrompt, aPermitUnload); + return PermitUnloadInternal(aCallerClosesWindow, &shouldPrompt, + aPermitUnload); } nsresult -nsDocumentViewer::PermitUnloadInternal(bool *aShouldPrompt, +nsDocumentViewer::PermitUnloadInternal(bool aCallerClosesWindow, + bool *aShouldPrompt, bool *aPermitUnload) { AutoDontWarnAboutSyncXHR disableSyncXHRWarning; @@ -1064,6 +1069,7 @@ nsDocumentViewer::PermitUnloadInternal(bool *aShouldPrompt, if (!mDocument || mInPermitUnload + || mCallerIsClosingWindow || mInPermitUnloadPrompt) { return NS_OK; } @@ -1239,12 +1245,16 @@ nsDocumentViewer::PermitUnloadInternal(bool *aShouldPrompt, docShell->GetContentViewer(getter_AddRefs(cv)); if (cv) { - cv->PermitUnloadInternal(aShouldPrompt, aPermitUnload); + cv->PermitUnloadInternal(aCallerClosesWindow, aShouldPrompt, + aPermitUnload); } } } } + if (aCallerClosesWindow && *aPermitUnload) + mCallerIsClosingWindow = true; + return NS_OK; } @@ -1262,6 +1272,35 @@ nsDocumentViewer::GetInPermitUnload(bool* aInEvent) return NS_OK; } +NS_IMETHODIMP +nsDocumentViewer::ResetCloseWindow() +{ + mCallerIsClosingWindow = false; + + nsCOMPtr docShell(mContainer); + if (docShell) { + int32_t childCount; + docShell->GetChildCount(&childCount); + + for (int32_t i = 0; i < childCount; ++i) { + nsCOMPtr item; + docShell->GetChildAt(i, getter_AddRefs(item)); + + nsCOMPtr docShell(do_QueryInterface(item)); + + if (docShell) { + nsCOMPtr cv; + docShell->GetContentViewer(getter_AddRefs(cv)); + + if (cv) { + cv->ResetCloseWindow(); + } + } + } + } + return NS_OK; +} + NS_IMETHODIMP nsDocumentViewer::PageHide(bool aIsUnload) { diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 08632090f2d6..bc15f2451d8e 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -61,9 +61,6 @@ if (AppConstants.MOZ_SAFE_BROWSING) { "resource://gre/modules/SafeBrowsing.jsm"); } -XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils", - "resource://gre/modules/BrowserUtils.jsm"); - XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); @@ -3439,10 +3436,6 @@ nsBrowserAccess.prototype = { isTabContentWindow: function(aWindow) { return BrowserApp.getBrowserForWindow(aWindow) != null; }, - - canClose() { - return BrowserUtils.canCloseWindow(window); - }, }; diff --git a/services/fxaccounts/FxAccountsOAuthClient.jsm b/services/fxaccounts/FxAccountsOAuthClient.jsm index c59f1a86913d..097d6eddd0ad 100644 --- a/services/fxaccounts/FxAccountsOAuthClient.jsm +++ b/services/fxaccounts/FxAccountsOAuthClient.jsm @@ -195,25 +195,6 @@ this.FxAccountsOAuthClient.prototype = { }; } - // if the message asked to close the tab - if (data.closeWindow && target) { - // for e10s reasons the best way is to use the TabBrowser to close the tab. - let tabbrowser = target.getTabBrowser(); - - if (tabbrowser) { - let tab = tabbrowser.getTabForBrowser(target); - - if (tab) { - tabbrowser.removeTab(tab); - log.debug("OAuth flow closed the tab."); - } else { - log.debug("OAuth flow failed to close the tab. Tab not found in TabBrowser."); - } - } else { - log.debug("OAuth flow failed to close the tab. TabBrowser not found."); - } - } - if (err) { log.debug(err.message); if (this.onError) { @@ -233,6 +214,25 @@ this.FxAccountsOAuthClient.prototype = { // onComplete will be called for this client only once // calling onComplete again will result in a failure of the OAuth flow this.tearDown(); + + // if the message asked to close the tab + if (data.closeWindow && target) { + // for e10s reasons the best way is to use the TabBrowser to close the tab. + let tabbrowser = target.getTabBrowser(); + + if (tabbrowser) { + let tab = tabbrowser.getTabForBrowser(target); + + if (tab) { + tabbrowser.removeTab(tab); + log.debug("OAuth flow closed the tab."); + } else { + log.debug("OAuth flow failed to close the tab. Tab not found in TabBrowser."); + } + } else { + log.debug("OAuth flow failed to close the tab. TabBrowser not found."); + } + } break; } } diff --git a/toolkit/content/browser-child.js b/toolkit/content/browser-child.js index 18c3930370e3..7d9c191056bb 100644 --- a/toolkit/content/browser-child.js +++ b/toolkit/content/browser-child.js @@ -577,22 +577,6 @@ var AutoCompletePopup = { } } -addMessageListener("InPermitUnload", msg => { - let inPermitUnload = docShell.contentViewer && docShell.contentViewer.inPermitUnload; - sendAsyncMessage("InPermitUnload", {id: msg.data.id, inPermitUnload}); -}); - -addMessageListener("PermitUnload", msg => { - sendAsyncMessage("PermitUnload", {id: msg.data.id, kind: "start"}); - - let permitUnload = true; - if (docShell && docShell.contentViewer) { - permitUnload = docShell.contentViewer.permitUnload(); - } - - sendAsyncMessage("PermitUnload", {id: msg.data.id, kind: "end", permitUnload}); -}); - // We may not get any responses to Browser:Init if the browser element // is torn down too quickly. var outerWindowID = content.QueryInterface(Ci.nsIInterfaceRequestor) diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml index 1361fc4ecba4..960645f76f82 100644 --- a/toolkit/content/widgets/browser.xml +++ b/toolkit/content/widgets/browser.xml @@ -1073,8 +1073,8 @@ window.addEventListener("keypress", this, true); window.addEventListener("keyup", this, true); ]]> - - + + @@ -1227,30 +1227,6 @@ - - - - - - - - - - - - - true diff --git a/toolkit/content/widgets/remote-browser.xml b/toolkit/content/widgets/remote-browser.xml index 246d8fdbc1fd..c80d6128e142 100644 --- a/toolkit/content/widgets/remote-browser.xml +++ b/toolkit/content/widgets/remote-browser.xml @@ -234,89 +234,6 @@ false - 0 - - - - - - - - - - - { - if (msg.data.id != id) { - return; - } - if (msg.data.kind == "start") { - responded = true; - return; - } - done(msg.data.permitUnload); - }; - - let observer = subject => { - if (subject == mm) { - done(true); - } - }; - - function done(result) { - finished = true; - permitUnload = result; - mm.removeMessageListener("PermitUnload", msgListener); - Services.obs.removeObserver(observer, "message-manager-close"); - } - - mm.sendAsyncMessage("PermitUnload", {id}); - mm.addMessageListener("PermitUnload", msgListener); - Services.obs.addObserver(observer, "message-manager-close", false); - - let timedOut = false; - function timeout() { - if (!responded) { - timedOut = true; - } - - // Dispatch something to ensure that the main thread wakes up. - Services.tm.mainThread.dispatch(function() {}, Ci.nsIThread.DISPATCH_NORMAL); - } - - let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - timer.initWithCallback(timeout, kTimeout, timer.TYPE_ONE_SHOT); - - while (!finished && !timedOut) { - Services.tm.currentThread.processNextEvent(true); - } - - return {permitUnload, timedOut}; - ]]> - - - Date: Wed, 7 Oct 2015 11:08:08 -0700 Subject: [PATCH 065/189] Back out bug 967873 - Ignore content process DOMWillOpenModalDialog event in e10s --- toolkit/components/startup/tests/browser/browser.ini | 2 ++ toolkit/components/startup/tests/browser/head.js | 8 +------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/toolkit/components/startup/tests/browser/browser.ini b/toolkit/components/startup/tests/browser/browser.ini index 0c02f73b6882..2204935bc906 100644 --- a/toolkit/components/startup/tests/browser/browser.ini +++ b/toolkit/components/startup/tests/browser/browser.ini @@ -4,5 +4,7 @@ support-files = beforeunload.html [browser_bug511456.js] +skip-if = e10s # Bug ?????? - test touches content (uses a WindowWatcher in the parent process to try and observe content created alerts etc) [browser_bug537449.js] +skip-if = e10s # Bug ?????? - test touches content (uses a WindowWatcher in the parent process to try and observe content created alerts etc) [browser_crash_detection.js] diff --git a/toolkit/components/startup/tests/browser/head.js b/toolkit/components/startup/tests/browser/head.js index 3154aeb7ea69..d9e3c9a8be21 100644 --- a/toolkit/components/startup/tests/browser/head.js +++ b/toolkit/components/startup/tests/browser/head.js @@ -15,13 +15,7 @@ function whenBrowserLoaded(browser, callback) { } function waitForOnBeforeUnloadDialog(browser, callback) { - browser.addEventListener("DOMWillOpenModalDialog", function onModalDialog(event) { - if (Cu.isCrossProcessWrapper(event.target)) { - // This event fires in both the content and chrome processes. We - // want to ignore the one in the content process. - return; - } - + browser.addEventListener("DOMWillOpenModalDialog", function onModalDialog() { browser.removeEventListener("DOMWillOpenModalDialog", onModalDialog, true); executeSoon(() => { From 919ed9ae8691f4766e37986e8ab914b517a3a42c Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 7 Oct 2015 11:08:21 -0700 Subject: [PATCH 066/189] Back out bug 967873 - browser_onbeforeunload_navigation.js fix for e10s --- docshell/test/browser/browser.ini | 1 + .../browser_onbeforeunload_navigation.js | 51 +++++++++++++++---- docshell/test/browser/file_bug1046022.html | 40 --------------- 3 files changed, 43 insertions(+), 49 deletions(-) diff --git a/docshell/test/browser/browser.ini b/docshell/test/browser/browser.ini index ca5716715289..83c0a4ef52de 100644 --- a/docshell/test/browser/browser.ini +++ b/docshell/test/browser/browser.ini @@ -103,6 +103,7 @@ skip-if = e10s skip-if = e10s # Bug ?????? - event handler checks event.target is the content document and test e10s-utils doesn't do that. [browser_multiple_pushState.js] [browser_onbeforeunload_navigation.js] +skip-if = e10s [browser_search_notification.js] [browser_timelineMarkers-01.js] [browser_timelineMarkers-02.js] diff --git a/docshell/test/browser/browser_onbeforeunload_navigation.js b/docshell/test/browser/browser_onbeforeunload_navigation.js index 5c4ff3ca5fa9..e99ffe7e791e 100644 --- a/docshell/test/browser/browser_onbeforeunload_navigation.js +++ b/docshell/test/browser/browser_onbeforeunload_navigation.js @@ -10,7 +10,6 @@ SpecialPowers.pushPrefEnv({"set": [["dom.require_user_interaction_for_beforeunlo var loadExpected = TEST_PAGE; var testTab; -var testsLength; var loadStarted = false; var tabStateListener = { @@ -41,10 +40,6 @@ function onTabLoaded(event) { return; } - if (!testsLength) { - testsLength = testTab.linkedBrowser.contentWindow.wrappedJSObject.testFns.length; - } - is(loadedPage, loadExpected, "Loaded the expected page"); if (contentWindow) { is(contentWindow.document, event.target, "Same doc"); @@ -107,9 +102,47 @@ function onTabModalDialogLoaded(node) { // Listen for the dialog being created Services.obs.addObserver(onTabModalDialogLoaded, "tabmodal-dialog-loaded", false); +var testFns = [ + function(e) { + e.target.location.href = 'otherpage-href-set.html'; + return "stop"; + }, + function(e) { + e.target.location.reload(); + return "stop"; + }, + function(e) { + e.target.location.replace('otherpage-location-replaced.html'); + return "stop"; + }, + function(e) { + var link = e.target.createElement('a'); + link.href = "otherpage.html"; + e.target.body.appendChild(link); + link.click(); + return "stop"; + }, + function(e) { + var link = e.target.createElement('a'); + link.href = "otherpage.html"; + link.setAttribute("target", "_blank"); + e.target.body.appendChild(link); + link.click(); + return "stop"; + }, + function(e) { + var link = e.target.createElement('a'); + link.href = e.target.location.href; + e.target.body.appendChild(link); + link.setAttribute("target", "somearbitrarywindow"); + link.click(); + return "stop"; + }, +]; + function runNextTest() { currentTest++; - if (currentTest >= testsLength) { + if (currentTest >= testFns.length) { if (!stayingOnPage) { finish(); return; @@ -138,10 +171,10 @@ function runCurrentTest() { contentWindow.dialogWasInvoked = false; originalLocation = contentWindow.location.href; // And run this test: - info("Running test with onbeforeunload " + contentWindow.wrappedJSObject.testFns[currentTest].toSource()); - contentWindow.onbeforeunload = contentWindow.wrappedJSObject.testFns[currentTest]; + info("Running test with onbeforeunload " + testFns[currentTest].toSource()); + contentWindow.onbeforeunload = testFns[currentTest]; loadStarted = false; - testTab.linkedBrowser.loadURI(TARGETED_PAGE); + contentWindow.location.href = TARGETED_PAGE; } var onAfterPageLoad = runNextTest; diff --git a/docshell/test/browser/file_bug1046022.html b/docshell/test/browser/file_bug1046022.html index 2de68cb43a6c..fd04e796b64d 100644 --- a/docshell/test/browser/file_bug1046022.html +++ b/docshell/test/browser/file_bug1046022.html @@ -7,44 +7,4 @@ Waiting for onbeforeunload to hit... - - From 52c284833009458001731cc9afea4db0ad39d468 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 7 Oct 2015 11:08:32 -0700 Subject: [PATCH 067/189] Back out bug 967873 - Allow RemotePrompt to be closed while it's being opened --- browser/modules/RemotePrompt.jsm | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/browser/modules/RemotePrompt.jsm b/browser/modules/RemotePrompt.jsm index 041b8a3effcc..1e142be2dab9 100644 --- a/browser/modules/RemotePrompt.jsm +++ b/browser/modules/RemotePrompt.jsm @@ -39,18 +39,11 @@ var RemotePrompt = { let tabPrompt = window.gBrowser.getTabModalPromptBox(browser) let callbackInvoked = false; let newPrompt; - let needRemove = false; let promptId = args._remoteId; function onPromptClose(forceCleanup) { - // It's possible that we removed the prompt during the - // appendPrompt call below. In that case, newPrompt will be - // undefined. We set the needRemove flag to remember to remove - // it right after we've finished adding it. if (newPrompt) tabPrompt.removePrompt(newPrompt); - else - needRemove = true; PromptUtils.fireDialogEvent(window, "DOMModalDialogClosed", browser); browser.messageManager.sendAsyncMessage("Prompt:Close", args); @@ -76,10 +69,6 @@ var RemotePrompt = { newPrompt = tabPrompt.appendPrompt(args, onPromptClose); - if (needRemove) { - tabPrompt.removePrompt(newPrompt); - } - // TODO since we don't actually open a window, need to check if // there's other stuff in nsWindowWatcher::OpenWindowInternal // that we might need to do here as well. From 1b6da7ed716856211b6ac85473e509f11c7fc093 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 7 Oct 2015 11:08:44 -0700 Subject: [PATCH 068/189] Back out bug 967873 - Test changes for async removeTab --- browser/base/content/browser.xul | 2 +- browser/base/content/tabbrowser.xml | 3 +-- browser/base/content/test/general/browser.ini | 1 + .../content/test/general/browser_bug406216.js | 8 ++++---- .../content/test/general/browser_bug432599.js | 2 +- .../content/test/general/browser_bug455852.js | 8 ++------ .../content/test/general/browser_bug521216.js | 11 ++++------- .../content/test/general/browser_bug533232.js | 10 +++++----- .../content/test/general/browser_bug676619.js | 1 - .../test/general/browser_selectTabAtIndex.js | 2 +- browser/base/content/test/social/head.js | 2 +- devtools/client/netmonitor/test/head.js | 3 +-- .../test/helper_codemirror_runner.js | 4 ++-- docshell/test/browser/head.js | 2 +- .../serviceworkers/browser_force_refresh.js | 5 ----- testing/mochitest/browser-test.js | 2 +- .../tests/browser/browser_Addons_sample.xpi | Bin 2134 -> 2133 bytes .../tests/browser/browser_compartments.js | 2 +- .../mozapps/extensions/test/xpinstall/head.js | 2 +- 19 files changed, 28 insertions(+), 42 deletions(-) diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index 69a4914e0906..50d7413ebcc5 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -119,7 +119,7 @@ accesskey="&bookmarkAllTabs.accesskey;" command="Browser:BookmarkAllTabs"/> + oncommand="gBrowser.removeTabsToTheEndFrom(TabContextMenu.contextTab);"/> diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 78ec72efc60d..2f04eab599df 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -2077,13 +2077,12 @@ - = 0; --i) { - this.removeTab(tabs[i], aParams); + this.removeTab(tabs[i], {animate: true}); } } ]]> diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 4b956cfd7122..bc149f10c581 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -147,6 +147,7 @@ skip-if = e10s # Bug 1101993 - times out for unknown reasons when run in the dir [browser_backButtonFitts.js] skip-if = os == "mac" # The Fitt's Law back button is not supported on OS X [browser_beforeunload_duplicate_dialogs.js] +skip-if = e10s # bug 967873 means permitUnload doesn't work in e10s mode [browser_blob-channelname.js] [browser_bookmark_titles.js] skip-if = buildapp == 'mulet' || toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341) diff --git a/browser/base/content/test/general/browser_bug406216.js b/browser/base/content/test/general/browser_bug406216.js index e1bd38395993..db3b1bffac9b 100644 --- a/browser/base/content/test/general/browser_bug406216.js +++ b/browser/base/content/test/general/browser_bug406216.js @@ -22,7 +22,7 @@ function test() { function addTab(aURI, aIndex) { var tab = gBrowser.addTab(aURI); if (aIndex == 0) - gBrowser.removeTab(gBrowser.tabs[0], {skipPermitUnload: true}); + gBrowser.removeTab(gBrowser.tabs[0]); tab.linkedBrowser.addEventListener("load", function (event) { event.currentTarget.removeEventListener("load", arguments.callee, true); @@ -41,14 +41,14 @@ function doTabsTest() { var scheme = closedTab.linkedBrowser.currentURI.scheme; Array.slice(gBrowser.tabs).forEach(function (aTab) { if (aTab != closedTab && aTab.linkedBrowser.currentURI.scheme == scheme) - gBrowser.removeTab(aTab, {skipPermitUnload: true}); + gBrowser.removeTab(aTab); }); }, true); - gBrowser.removeTab(gBrowser.tabs[0], {skipPermitUnload: true}); + gBrowser.removeTab(gBrowser.tabs[0]); is(gBrowser.tabs.length, 1, "Related tabs are not closed unexpectedly"); gBrowser.addTab("about:blank"); - gBrowser.removeTab(gBrowser.tabs[0], {skipPermitUnload: true}); + gBrowser.removeTab(gBrowser.tabs[0]); finish(); } diff --git a/browser/base/content/test/general/browser_bug432599.js b/browser/base/content/test/general/browser_bug432599.js index a5f7c0b5e7d0..4989faae0ca3 100644 --- a/browser/base/content/test/general/browser_bug432599.js +++ b/browser/base/content/test/general/browser_bug432599.js @@ -99,7 +99,7 @@ function checkBookmarksPanel(invoker, phase) if (currentInvoker < invokers.length) { checkBookmarksPanel(invokers[currentInvoker], 1); } else { - gBrowser.removeTab(gBrowser.selectedTab, {skipPermitUnload: true}); + gBrowser.removeCurrentTab(); PlacesUtils.bookmarks.removeItem(bookmarkId); executeSoon(finish); } diff --git a/browser/base/content/test/general/browser_bug455852.js b/browser/base/content/test/general/browser_bug455852.js index ce883b5819f6..52798f102997 100644 --- a/browser/base/content/test/general/browser_bug455852.js +++ b/browser/base/content/test/general/browser_bug455852.js @@ -1,4 +1,4 @@ -add_task(function*() { +function test() { is(gBrowser.tabs.length, 1, "one tab is open"); gBrowser.selectedBrowser.focus(); @@ -6,15 +6,11 @@ add_task(function*() { var tab = gBrowser.selectedTab; gPrefService.setBoolPref("browser.tabs.closeWindowWithLastTab", false); - - let tabClosedPromise = BrowserTestUtils.removeTab(tab, {dontRemove: true}); EventUtils.synthesizeKey("w", { accelKey: true }); - yield tabClosedPromise; - is(tab.parentNode, null, "ctrl+w removes the tab"); is(gBrowser.tabs.length, 1, "a new tab has been opened"); is(document.activeElement, gURLBar.inputField, "location bar is focused for the new tab"); if (gPrefService.prefHasUserValue("browser.tabs.closeWindowWithLastTab")) gPrefService.clearUserPref("browser.tabs.closeWindowWithLastTab"); -}); +} diff --git a/browser/base/content/test/general/browser_bug521216.js b/browser/base/content/test/general/browser_bug521216.js index 735ae92f628d..5156c4c60cf7 100644 --- a/browser/base/content/test/general/browser_bug521216.js +++ b/browser/base/content/test/general/browser_bug521216.js @@ -18,13 +18,10 @@ function record(aName) { if (actual.length == expected.length) { is(actual.toString(), expected.toString(), "got events and progress notifications in expected order"); - - executeSoon(function(tab) { - gBrowser.removeTab(tab); - gBrowser.removeTabsProgressListener(progressListener); - gBrowser.tabContainer.removeEventListener("TabOpen", TabOpen, false); - finish(); - }.bind(null, tab)); + gBrowser.removeTab(tab); + gBrowser.removeTabsProgressListener(progressListener); + gBrowser.tabContainer.removeEventListener("TabOpen", TabOpen, false); + finish(); } } diff --git a/browser/base/content/test/general/browser_bug533232.js b/browser/base/content/test/general/browser_bug533232.js index 6c7a0e51fd7c..fdee75ba266e 100644 --- a/browser/base/content/test/general/browser_bug533232.js +++ b/browser/base/content/test/general/browser_bug533232.js @@ -6,14 +6,14 @@ function test() { childTab1 = gBrowser.addTab("about:blank", { relatedToCurrent: true }); gBrowser.selectedTab = childTab1; - gBrowser.removeTab(gBrowser.selectedTab, { skipPermitUnload: true }); + gBrowser.removeCurrentTab(); is(idx(gBrowser.selectedTab), idx(tab1), "closing a tab next to its parent selects the parent"); childTab1 = gBrowser.addTab("about:blank", { relatedToCurrent: true }); gBrowser.selectedTab = tab2; gBrowser.selectedTab = childTab1; - gBrowser.removeTab(gBrowser.selectedTab, { skipPermitUnload: true }); + gBrowser.removeCurrentTab(); is(idx(gBrowser.selectedTab), idx(tab2), "closing a tab next to its parent doesn't select the parent if another tab had been selected ad interim"); @@ -21,14 +21,14 @@ function test() { childTab1 = gBrowser.addTab("about:blank", { relatedToCurrent: true }); childTab2 = gBrowser.addTab("about:blank", { relatedToCurrent: true }); gBrowser.selectedTab = childTab1; - gBrowser.removeTab(gBrowser.selectedTab, { skipPermitUnload: true }); + gBrowser.removeCurrentTab(); is(idx(gBrowser.selectedTab), idx(childTab2), "closing a tab next to its parent selects the next tab with the same parent"); - gBrowser.removeTab(gBrowser.selectedTab, { skipPermitUnload: true }); + gBrowser.removeCurrentTab(); is(idx(gBrowser.selectedTab), idx(tab2), "closing the last tab in a set of child tabs doesn't go back to the parent"); - gBrowser.removeTab(tab2, { skipPermitUnload: true }); + gBrowser.removeTab(tab2); } function idx(tab) { diff --git a/browser/base/content/test/general/browser_bug676619.js b/browser/base/content/test/general/browser_bug676619.js index f2dff376c408..03211f9698a2 100644 --- a/browser/base/content/test/general/browser_bug676619.js +++ b/browser/base/content/test/general/browser_bug676619.js @@ -1,5 +1,4 @@ function test () { - requestLongerTimeout(2); waitForExplicitFinish(); var isHTTPS = false; diff --git a/browser/base/content/test/general/browser_selectTabAtIndex.js b/browser/base/content/test/general/browser_selectTabAtIndex.js index a1306afbc838..d84682e68c50 100644 --- a/browser/base/content/test/general/browser_selectTabAtIndex.js +++ b/browser/base/content/test/general/browser_selectTabAtIndex.js @@ -18,5 +18,5 @@ function test() { "gBrowser.selectTabAtIndex(-3) selects expected tab"); for (let i = 0; i < 9; i++) - gBrowser.removeTab(gBrowser.selectedTab, {skipPermitUnload: true}); + gBrowser.removeCurrentTab(); } diff --git a/browser/base/content/test/social/head.js b/browser/base/content/test/social/head.js index 7c7aac5540b5..4de6785a2ee6 100644 --- a/browser/base/content/test/social/head.js +++ b/browser/base/content/test/social/head.js @@ -416,7 +416,7 @@ function loadIntoTab(tab, url, callback) { function ensureBrowserTabClosed(tab) { let promise = ensureEventFired(gBrowser.tabContainer, "TabClose"); - gBrowser.removeTab(tab, {skipPermitUnload: true}); + gBrowser.removeTab(tab); return promise; } diff --git a/devtools/client/netmonitor/test/head.js b/devtools/client/netmonitor/test/head.js index dd2ff36e5c07..5fec29b4a7b2 100644 --- a/devtools/client/netmonitor/test/head.js +++ b/devtools/client/netmonitor/test/head.js @@ -107,8 +107,7 @@ function removeTab(aTab, aWindow) { let targetWindow = aWindow || window; let targetBrowser = targetWindow.gBrowser; - // browser_net_pane-toggle.js relies on synchronous removeTab behavior. - targetBrowser.removeTab(aTab, {skipPermitUnload: true}); + targetBrowser.removeTab(aTab); } function waitForNavigation(aTarget) { diff --git a/devtools/client/sourceeditor/test/helper_codemirror_runner.js b/devtools/client/sourceeditor/test/helper_codemirror_runner.js index 4759c54185be..b5eba5d40e83 100644 --- a/devtools/client/sourceeditor/test/helper_codemirror_runner.js +++ b/devtools/client/sourceeditor/test/helper_codemirror_runner.js @@ -28,8 +28,8 @@ function runCodeMirrorTest(browser) { 'function check() { ' + ' var doc = content.document; var out = doc.getElementById("status"); ' + ' if (!out || !out.classList.contains("done")) { return setTimeout(check, 100); }' + - ' sendAsyncMessage("done", { failed: content.wrappedJSObject.failed });' + + ' sendSyncMessage("done", { failed: content.wrappedJSObject.failed });' + '}' + 'check();' , true); -} +} \ No newline at end of file diff --git a/docshell/test/browser/head.js b/docshell/test/browser/head.js index ae4be398142e..29df446d6c12 100644 --- a/docshell/test/browser/head.js +++ b/docshell/test/browser/head.js @@ -31,8 +31,8 @@ function makeTimelineTest(frameScriptName, url) { info(message.data.message); }); mm.addMessageListener("browser:test:finish", function(ignore) { - gBrowser.removeCurrentTab(); finish(); + gBrowser.removeCurrentTab(); }); }); } diff --git a/dom/workers/test/serviceworkers/browser_force_refresh.js b/dom/workers/test/serviceworkers/browser_force_refresh.js index 2121e1e40531..c6a7d70c3db6 100644 --- a/dom/workers/test/serviceworkers/browser_force_refresh.js +++ b/dom/workers/test/serviceworkers/browser_force_refresh.js @@ -29,11 +29,6 @@ function test() { function eventHandler(event) { if (event.type === 'base-load') { if (cachedLoad) { - removeEventListener('base-load', eventHandler, true); - removeEventListener('base-register', eventHandler, true); - removeEventListener('base-sw-ready', eventHandler, true); - removeEventListener('cached-load', eventHandler, true); - gBrowser.removeTab(tab); executeSoon(finish); } diff --git a/testing/mochitest/browser-test.js b/testing/mochitest/browser-test.js index e59adf040729..1a823b006a8a 100644 --- a/testing/mochitest/browser-test.js +++ b/testing/mochitest/browser-test.js @@ -288,7 +288,7 @@ Tester.prototype = { // Replace the last tab with a fresh one if (window.gBrowser) { gBrowser.addTab("about:blank", { skipAnimation: true }); - gBrowser.removeTab(gBrowser.selectedTab, { skipPermitUnload: true }); + gBrowser.removeCurrentTab(); gBrowser.stop(); } diff --git a/toolkit/components/perfmonitoring/tests/browser/browser_Addons_sample.xpi b/toolkit/components/perfmonitoring/tests/browser/browser_Addons_sample.xpi index 4b5ca3c1aca0464554485690c0736a6befe6d644..92e0019d6c7e9ce8cb479628fd1332ddd9d8406f 100644 GIT binary patch delta 712 zcmca6a8-akz?+#xgn?-yyM`zmH*+Wt5SLbPGcdCJU}Rtb%4~Gm#Kg!n`8$)k=*$9! zP^%qGsPdbQnOzxy3MyH&MU~bwVJeuslSP;L$>f~LFInVFqR%p7TEV~obp!(k!;y|$ zx2pMb^YnqX9|vMF2ARo%9Fp~%49p+6m_z>qF^cmT7(ypFW*>48Xnp@vwBJFoOHJv^ zqOSoutxZ7-TZ4`qPBZr0c0~5(T$3A*>ff)rdg-vinb|Yn8&3ZEF-p2$Ja4YrnVkwY zn{F#*>^p1k!QG;0>Ubj8c886q_dg@w#T&9dAA7-3tJ9-a|2nhbyvXB{DUVjRG(Eff zZ`bCi1;KLDSX)0n^0~()`l9Db;(;H^%S?O|_7rok)v*vyb=t(Dy27<=vd-;!dxOhD z#b!hnoDTZ3S)(i3-=b;jk;@vNQo5`6Z?E#ax4LUm#EH`ZqO7<5I@g`#{o1#?bEDfM z#(n&XN(%XN=dPc3Uri$CGwfx?XPl^Uz9A<^p`)tn~_P585rl2 zm$RA4fFd0&L=g&pvYE<&VjZUfFLp~MP^@EBz{LOppr~KUuA>8rdaTNTEQ$s%WR9;p2zx)BTvP)9IuFaQ<0 zd9C@~WWdP4Z~%zK7-S|3a7fm3GBAVm&cf6i+V7Zs$U&g>{cml#Mkf(pmlv+D7e;Wg zE_LEw+R=VCZBkC>?oHO28z%j~=X-UU+_c2|d%mCbu{x5y)HW{Xu}ETO@u9_~)huVt zZ?bE$MHjdx6jk#_|Ean5&HMV+Bg;-^tz~J8$gFogc9~;7=dzP32ZI?oQ~8hIKay7Jtn2mWa zUt&2N(y`)Wi`*KES=@mpZX36;MLs@L^!bk%e}RyLuT0D(L$QhpKAjtLZDzzfAPyQ;NoLl1d%{O^&7zf`_suFpA-nB?2uzF9`8J6^M0j&=AOUY(Xd)J0f<^kS}OmfV?NT0ln%}fRq z>nJe}iVm29A8e*FplHXbz?0ol2^8&E6>u?t04VO4u callback(count)); + callback(count); }, // Window open handling From b1e89d97be6b8abb22288f03cef6e5bced4ae31c Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 7 Oct 2015 11:08:59 -0700 Subject: [PATCH 069/189] Back out bug 967873 - Start TabView when starting tests that might lazily load it --- browser/base/content/test/general/browser_bug585558.js | 7 ------- browser/base/content/test/general/browser_bug597218.js | 6 ------ .../base/content/test/general/browser_hide_removing.js | 6 ------ browser/base/content/test/general/browser_visibleTabs.js | 9 ++------- .../test/general/browser_visibleTabs_bookmarkAllPages.js | 6 ------ .../test/general/browser_visibleTabs_bookmarkAllTabs.js | 6 ------ .../test/general/browser_visibleTabs_contextMenu.js | 9 ++------- .../test/general/browser_visibleTabs_tabPreview.js | 8 ++------ browser/components/sessionstore/test/browser_607016.js | 4 ---- browser/components/sessionstore/test/browser_635418.js | 6 ------ 10 files changed, 6 insertions(+), 61 deletions(-) diff --git a/browser/base/content/test/general/browser_bug585558.js b/browser/base/content/test/general/browser_bug585558.js index 0f8d5a30cdcd..772ec98bd849 100644 --- a/browser/base/content/test/general/browser_bug585558.js +++ b/browser/base/content/test/general/browser_bug585558.js @@ -14,13 +14,6 @@ function testAttrib(elem, attrib, attribValue, msg) { function test() { waitForExplicitFinish(); - - // Ensure TabView has been initialized already. Otherwise it could - // activate at an unexpected time and show/hide tabs. - TabView._initFrame(runTest); -} - -function runTest() { is(gBrowser.tabs.length, 1, "one tab is open initially"); // Add several new tabs in sequence, hiding some, to ensure that the diff --git a/browser/base/content/test/general/browser_bug597218.js b/browser/base/content/test/general/browser_bug597218.js index a0de75bedefa..f00e99f72944 100644 --- a/browser/base/content/test/general/browser_bug597218.js +++ b/browser/base/content/test/general/browser_bug597218.js @@ -5,12 +5,6 @@ function test() { waitForExplicitFinish(); - // Ensure TabView has been initialized already. Otherwise it could - // activate at an unexpected time and show/hide tabs. - TabView._initFrame(runTest); -} - -function runTest() { // establish initial state is(gBrowser.tabs.length, 1, "we start with one tab"); diff --git a/browser/base/content/test/general/browser_hide_removing.js b/browser/base/content/test/general/browser_hide_removing.js index 77bd5d6df5fc..be62e2d89e00 100644 --- a/browser/base/content/test/general/browser_hide_removing.js +++ b/browser/base/content/test/general/browser_hide_removing.js @@ -7,12 +7,6 @@ function test() { waitForExplicitFinish(); - // Ensure TabView has been initialized already. Otherwise it could - // activate at an unexpected time and show/hide tabs. - TabView._initFrame(runTest); -} - -function runTest() { // Add a tab that will get removed and hidden let testTab = gBrowser.addTab("about:blank", {skipAnimation: true}); is(gBrowser.visibleTabs.length, 2, "just added a tab, so 2 tabs"); diff --git a/browser/base/content/test/general/browser_visibleTabs.js b/browser/base/content/test/general/browser_visibleTabs.js index d2f1395cf67d..4e7410dcdce8 100644 --- a/browser/base/content/test/general/browser_visibleTabs.js +++ b/browser/base/content/test/general/browser_visibleTabs.js @@ -2,11 +2,7 @@ * 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/. */ -add_task(function* () { - // Ensure TabView has been initialized already. Otherwise it could - // activate at an unexpected time and show/hide tabs. - yield new Promise(resolve => TabView._initFrame(resolve)); - +function test() { // There should be one tab when we start the test let [origTab] = gBrowser.visibleTabs; @@ -104,5 +100,4 @@ add_task(function* () { if (tabViewWindow) tabViewWindow.GroupItems.groupItems[0].close(); -}); - +} diff --git a/browser/base/content/test/general/browser_visibleTabs_bookmarkAllPages.js b/browser/base/content/test/general/browser_visibleTabs_bookmarkAllPages.js index 67a2c5b70e4c..0d9a12067992 100644 --- a/browser/base/content/test/general/browser_visibleTabs_bookmarkAllPages.js +++ b/browser/base/content/test/general/browser_visibleTabs_bookmarkAllPages.js @@ -5,12 +5,6 @@ function test() { waitForExplicitFinish(); - // Ensure TabView has been initialized already. Otherwise it could - // activate at an unexpected time and show/hide tabs. - TabView._initFrame(runTest); -} - -function runTest() { let tabOne = gBrowser.addTab("about:blank"); let tabTwo = gBrowser.addTab("http://mochi.test:8888/"); gBrowser.selectedTab = tabTwo; diff --git a/browser/base/content/test/general/browser_visibleTabs_bookmarkAllTabs.js b/browser/base/content/test/general/browser_visibleTabs_bookmarkAllTabs.js index 5e2619c60b0e..09d790b94fd6 100644 --- a/browser/base/content/test/general/browser_visibleTabs_bookmarkAllTabs.js +++ b/browser/base/content/test/general/browser_visibleTabs_bookmarkAllTabs.js @@ -5,12 +5,6 @@ function test() { waitForExplicitFinish(); - // Ensure TabView has been initialized already. Otherwise it could - // activate at an unexpected time and show/hide tabs. - TabView._initFrame(runTest); -} - -function runTest() { // There should be one tab when we start the test let [origTab] = gBrowser.visibleTabs; is(gBrowser.visibleTabs.length, 1, "1 tab should be open"); diff --git a/browser/base/content/test/general/browser_visibleTabs_contextMenu.js b/browser/base/content/test/general/browser_visibleTabs_contextMenu.js index 50985b66c8e4..0539c8106564 100644 --- a/browser/base/content/test/general/browser_visibleTabs_contextMenu.js +++ b/browser/base/content/test/general/browser_visibleTabs_contextMenu.js @@ -2,11 +2,7 @@ * 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/. */ -add_task(function* test() { - // Ensure TabView has been initialized already. Otherwise it could - // activate at an unexpected time and show/hide tabs. - yield new Promise(resolve => TabView._initFrame(resolve)); - +function test() { // There should be one tab when we start the test let [origTab] = gBrowser.visibleTabs; is(gBrowser.visibleTabs.length, 1, "there is one visible tab"); @@ -55,5 +51,4 @@ add_task(function* test() { gBrowser.removeTab(testTab); gBrowser.removeTab(pinned); -}); - +} diff --git a/browser/base/content/test/general/browser_visibleTabs_tabPreview.js b/browser/base/content/test/general/browser_visibleTabs_tabPreview.js index ec54520264ed..9491690cb1ff 100644 --- a/browser/base/content/test/general/browser_visibleTabs_tabPreview.js +++ b/browser/base/content/test/general/browser_visibleTabs_tabPreview.js @@ -2,11 +2,7 @@ * 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/. */ -add_task(function* test() { - // Ensure TabView has been initialized already. Otherwise it could - // activate at an unexpected time and show/hide tabs. - yield new Promise(resolve => TabView._initFrame(resolve)); - +function test() { gPrefService.setBoolPref("browser.ctrlTab.previews", true); let [origTab] = gBrowser.visibleTabs; @@ -34,7 +30,7 @@ add_task(function* test() { if (gPrefService.prefHasUserValue("browser.ctrlTab.previews")) gPrefService.clearUserPref("browser.ctrlTab.previews"); -}); +} function pressCtrlTab(aShiftKey) { EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true, shiftKey: !!aShiftKey }); diff --git a/browser/components/sessionstore/test/browser_607016.js b/browser/components/sessionstore/test/browser_607016.js index 3574cc06bedc..ed4b03b9c8ae 100644 --- a/browser/components/sessionstore/test/browser_607016.js +++ b/browser/components/sessionstore/test/browser_607016.js @@ -6,10 +6,6 @@ add_task(function* () { /** Bug 607016 - If a tab is never restored, attributes (eg. hidden) aren't updated correctly **/ ignoreAllUncaughtExceptions(); - // Ensure TabView has been initialized already. Otherwise it could - // activate at an unexpected time and show/hide tabs. - yield new Promise(resolve => TabView._initFrame(resolve)); - // Set the pref to true so we know exactly how many tabs should be restoring at // any given time. This guarantees that a finishing load won't start another. Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true); diff --git a/browser/components/sessionstore/test/browser_635418.js b/browser/components/sessionstore/test/browser_635418.js index ab0a0bea743b..461ad1ee84f0 100644 --- a/browser/components/sessionstore/test/browser_635418.js +++ b/browser/components/sessionstore/test/browser_635418.js @@ -7,12 +7,6 @@ function test() { waitForExplicitFinish(); - // Ensure TabView has been initialized already. Otherwise it could - // activate at an unexpected time and show/hide tabs. - TabView._initFrame(runTest); -} - -function runTest() { // We speed up the interval between session saves to ensure that the test // runs quickly. Services.prefs.setIntPref("browser.sessionstore.interval", 2000); From 4abd7ee5d1e3b480604f241d6dcb69de45aa1faa Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 7 Oct 2015 11:09:07 -0700 Subject: [PATCH 070/189] Back out bug 967873 - Make browser_relatedTabs.js not race in e10s --- .../test/general/browser_relatedTabs.js | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/browser/base/content/test/general/browser_relatedTabs.js b/browser/base/content/test/general/browser_relatedTabs.js index 69633ac377bf..f59e0bbbb61b 100644 --- a/browser/base/content/test/general/browser_relatedTabs.js +++ b/browser/base/content/test/general/browser_relatedTabs.js @@ -2,7 +2,7 @@ * 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/. */ -add_task(function*() { +function test() { is(gBrowser.tabs.length, 1, "one tab is open initially"); // Add several new tabs in sequence, interrupted by selecting a @@ -10,29 +10,26 @@ add_task(function*() { // returning a list of opened tabs for verifying the expected order. // The new tab behaviour is documented in bug 465673 let tabs = []; - let promises = []; function addTab(aURL, aReferrer) { - let tab = gBrowser.addTab(aURL, {referrerURI: aReferrer}); - tabs.push(tab); - return BrowserTestUtils.browserLoaded(tab.linkedBrowser); + tabs.push(gBrowser.addTab(aURL, {referrerURI: aReferrer})); } - yield addTab("http://mochi.test:8888/#0"); + addTab("http://mochi.test:8888/#0"); gBrowser.selectedTab = tabs[0]; - yield addTab("http://mochi.test:8888/#1"); - yield addTab("http://mochi.test:8888/#2", gBrowser.currentURI); - yield addTab("http://mochi.test:8888/#3", gBrowser.currentURI); + addTab("http://mochi.test:8888/#1"); + addTab("http://mochi.test:8888/#2", gBrowser.currentURI); + addTab("http://mochi.test:8888/#3", gBrowser.currentURI); gBrowser.selectedTab = tabs[tabs.length - 1]; gBrowser.selectedTab = tabs[0]; - yield addTab("http://mochi.test:8888/#4", gBrowser.currentURI); + addTab("http://mochi.test:8888/#4", gBrowser.currentURI); gBrowser.selectedTab = tabs[3]; - yield addTab("http://mochi.test:8888/#5", gBrowser.currentURI); + addTab("http://mochi.test:8888/#5", gBrowser.currentURI); gBrowser.removeTab(tabs.pop()); - yield addTab("about:blank", gBrowser.currentURI); + addTab("about:blank", gBrowser.currentURI); gBrowser.moveTabTo(gBrowser.selectedTab, 1); - yield addTab("http://mochi.test:8888/#6", gBrowser.currentURI); - yield addTab(); - yield addTab("http://mochi.test:8888/#7"); + addTab("http://mochi.test:8888/#6", gBrowser.currentURI); + addTab(); + addTab("http://mochi.test:8888/#7"); function testPosition(tabNum, expectedPosition, msg) { is(Array.indexOf(gBrowser.tabs, tabs[tabNum]), expectedPosition, msg); @@ -49,4 +46,4 @@ add_task(function*() { testPosition(8, 9, "tab without referrer opens at the end"); tabs.forEach(gBrowser.removeTab, gBrowser); -}); +} From 47202f14e801d57c12f57ddbeda2e6cc347c93c7 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 7 Oct 2015 11:13:08 -0700 Subject: [PATCH 071/189] Back out bug 1191145 - Stop blocking scripts in CPOW IPCs --- dom/ipc/ContentChild.cpp | 4 ++++ ipc/glue/MessageChannel.cpp | 42 +++++++++++++++++++++++++++++++++++++ ipc/glue/MessageChannel.h | 10 +++++++++ 3 files changed, 56 insertions(+) diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 7a81a59a56ef..d5480aada19d 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -648,6 +648,10 @@ ContentChild::Init(MessageLoop* aIOLoop, } sSingleton = this; + // Make sure there's an nsAutoScriptBlocker on the stack when dispatching + // urgent messages. + GetIPCChannel()->BlockScripts(); + // If communications with the parent have broken down, take the process // down so it's not hanging around. bool abortOnError = true; diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 54d0e3c20987..ff3452204160 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -275,6 +275,31 @@ private: CxxStackFrame& operator=(const CxxStackFrame&) = delete; }; +namespace { + +class MOZ_RAII MaybeScriptBlocker { +public: + explicit MaybeScriptBlocker(MessageChannel *aChannel, bool aBlock + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mBlocked(aChannel->ShouldBlockScripts() && aBlock) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + if (mBlocked) { + nsContentUtils::AddScriptBlocker(); + } + } + ~MaybeScriptBlocker() { + if (mBlocked) { + nsContentUtils::RemoveScriptBlocker(); + } + } +private: + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + bool mBlocked; +}; + +} // namespace + MessageChannel::MessageChannel(MessageListener *aListener) : mListener(aListener), mChannelState(ChannelClosed), @@ -300,6 +325,7 @@ MessageChannel::MessageChannel(MessageListener *aListener) mSawInterruptOutMsg(false), mIsWaitingForIncoming(false), mAbortOnError(false), + mBlockScripts(false), mFlags(REQUIRE_DEFAULT), mPeerPidSet(false), mPeerPid(-1) @@ -815,6 +841,9 @@ MessageChannel::Send(Message* aMsg, Message* aReply) { nsAutoPtr msg(aMsg); + // See comment in DispatchSyncMessage. + MaybeScriptBlocker scriptBlocker(this, true); + // Sanity checks. AssertWorkerThread(); mMonitor->AssertNotCurrentThreadOwns(); @@ -1296,7 +1325,13 @@ MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply) AssertWorkerThread(); int prio = aMsg.priority(); + + // We don't want to run any code that might run a nested event loop here, so + // we avoid running event handlers. Once we've sent the response to the + // urgent message, it's okay to run event handlers again since the parent is + // no longer blocked. MOZ_ASSERT_IF(prio > IPC::Message::PRIORITY_NORMAL, NS_IsMainThread()); + MaybeScriptBlocker scriptBlocker(this, prio > IPC::Message::PRIORITY_NORMAL); MessageChannel* dummy; MessageChannel*& blockingVar = NS_IsMainThread() ? gMainThreadBlocker : dummy; @@ -1854,6 +1889,13 @@ MessageChannel::CloseWithTimeout() mChannelState = ChannelTimeout; } +void +MessageChannel::BlockScripts() +{ + MOZ_ASSERT(NS_IsMainThread()); + mBlockScripts = true; +} + void MessageChannel::Close() { diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index 128cb118aa77..3aad5d8064c1 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -107,6 +107,13 @@ class MessageChannel : HasResultCodes void SetChannelFlags(ChannelFlags aFlags) { mFlags = aFlags; } ChannelFlags GetChannelFlags() { return mFlags; } + void BlockScripts(); + + bool ShouldBlockScripts() const + { + return mBlockScripts; + } + // Asynchronously send a message to the other side of the channel bool Send(Message* aMsg); @@ -729,6 +736,9 @@ class MessageChannel : HasResultCodes // a channel error occurs? bool mAbortOnError; + // Should we prevent scripts from running while dispatching urgent messages? + bool mBlockScripts; + // See SetChannelFlags ChannelFlags mFlags; From 1b725eb6bc285e3065cb543d690f7aff93707231 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 7 Oct 2015 11:13:48 -0700 Subject: [PATCH 072/189] Back out bug 1191143 - Cancel CPOWs from both sides --- ipc/glue/MessageChannel.cpp | 20 ++++++++------------ ipc/glue/MessageChannel.h | 2 +- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index ff3452204160..9341ba5cdefd 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -106,7 +106,7 @@ struct RunnableMethodTraits DebugAbort(__FILE__, __LINE__, #_cond,## __VA_ARGS__); \ } while (0) -static MessageChannel* gMainThreadBlocker; +static MessageChannel* gParentProcessBlocker; namespace mozilla { namespace ipc { @@ -404,8 +404,8 @@ MessageChannel::Clear() // In practice, mListener owns the channel, so the channel gets deleted // before mListener. But just to be safe, mListener is a weak pointer. - if (gMainThreadBlocker == this) { - gMainThreadBlocker = nullptr; + if (gParentProcessBlocker == this) { + gParentProcessBlocker = nullptr; } mDequeueOneTask->Cancel(); @@ -1334,7 +1334,7 @@ MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply) MaybeScriptBlocker scriptBlocker(this, prio > IPC::Message::PRIORITY_NORMAL); MessageChannel* dummy; - MessageChannel*& blockingVar = NS_IsMainThread() ? gMainThreadBlocker : dummy; + MessageChannel*& blockingVar = ShouldBlockScripts() ? gParentProcessBlocker : dummy; Result rv; if (mTimedOutMessageSeqno && mTimedOutMessagePriority >= prio) { @@ -2046,26 +2046,22 @@ MessageChannel::CancelCurrentTransactionInternal() // see if mCurrentTransaction is 0 before examining DispatchSyncMessage. } -bool +void MessageChannel::CancelCurrentTransaction() { MonitorAutoLock lock(*mMonitor); - if (mCurrentTransaction && - !DispatchingAsyncMessage() && - DispatchingSyncMessagePriority() >= IPC::Message::PRIORITY_HIGH) - { + if (mCurrentTransaction) { CancelCurrentTransactionInternal(); mLink->SendMessage(new CancelMessage()); - return true; } - return false; } void CancelCPOWs() { - if (gMainThreadBlocker && gMainThreadBlocker->CancelCurrentTransaction()) { + if (gParentProcessBlocker) { mozilla::Telemetry::Accumulate(mozilla::Telemetry::IPC_TRANSACTION_CANCEL, true); + gParentProcessBlocker->CancelCurrentTransaction(); } } diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index 3aad5d8064c1..17230973340e 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -143,7 +143,7 @@ class MessageChannel : HasResultCodes return !mCxxStackFrames.empty(); } - bool CancelCurrentTransaction(); + void CancelCurrentTransaction(); /** * This function is used by hang annotation code to determine which IPDL From 5adc75d0846b5fa525500d9bd8f9159f1a11e8c2 Mon Sep 17 00:00:00 2001 From: Francois Marier Date: Wed, 7 Oct 2015 11:27:19 -0700 Subject: [PATCH 073/189] Bug 1208629 - Properly support data: and blob: URIs with an integrity atribute. r=ckerschb --- dom/base/nsScriptLoader.cpp | 9 +- dom/security/SRICheck.cpp | 103 ++++++++++++------ dom/security/SRICheck.h | 8 +- .../test/sri/iframe_script_crossdomain.html | 26 +++++ .../test/sri/iframe_script_sameorigin.html | 42 ++++++- .../test/sri/iframe_style_crossdomain.html | 55 +++++++++- .../test/sri/iframe_style_sameorigin.html | 58 +++++++++- dom/security/test/sri/mochitest.ini | 1 + dom/security/test/sri/style1.css^headers^ | 1 + layout/style/Loader.cpp | 2 +- 10 files changed, 251 insertions(+), 54 deletions(-) create mode 100644 dom/security/test/sri/style1.css^headers^ diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index ad1e992e5faa..10cb12e0b0c6 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -1425,16 +1425,9 @@ nsScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader, NS_ASSERTION(request, "null request in stream complete handler"); NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); - nsCOMPtr httpChannel; - { - nsCOMPtr req; - aLoader->GetRequest(getter_AddRefs(req)); - httpChannel = do_QueryInterface(req); - } // throw away req, we only need the channel - nsresult rv = NS_ERROR_SRI_CORRUPT; if (request->mIntegrity.IsEmpty() || - NS_SUCCEEDED(SRICheck::VerifyIntegrity(request->mIntegrity, httpChannel, + NS_SUCCEEDED(SRICheck::VerifyIntegrity(request->mIntegrity, aLoader, request->mCORSMode, aStringLen, aString, mDocument))) { rv = PrepareLoadedRequest(request, aLoader, aStatus, aStringLen, aString); diff --git a/dom/security/SRICheck.cpp b/dom/security/SRICheck.cpp index cae752600632..45797e840bae 100644 --- a/dom/security/SRICheck.cpp +++ b/dom/security/SRICheck.cpp @@ -16,6 +16,8 @@ #include "nsIProtocolHandler.h" #include "nsIScriptError.h" #include "nsIScriptSecurityManager.h" +#include "nsIStreamLoader.h" +#include "nsIUnicharStreamLoader.h" #include "nsIURI.h" #include "nsNetUtil.h" #include "nsWhitespaceTokenizer.h" @@ -45,9 +47,13 @@ static nsresult IsEligible(nsIChannel* aChannel, const CORSMode aCORSMode, const nsIDocument* aDocument) { - NS_ENSURE_ARG_POINTER(aChannel); NS_ENSURE_ARG_POINTER(aDocument); + if (!aChannel) { + SRILOG(("SRICheck::IsEligible, null channel")); + return NS_ERROR_SRI_NOT_ELIGIBLE; + } + // Was the sub-resource loaded via CORS? if (aCORSMode != CORS_NONE) { SRILOG(("SRICheck::IsEligible, CORS mode")); @@ -236,38 +242,14 @@ SRICheck::IntegrityMetadata(const nsAString& aMetadataList, return NS_OK; } -/* static */ nsresult -SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata, - nsIChannel* aChannel, - const CORSMode aCORSMode, - const nsAString& aString, - const nsIDocument* aDocument) +static nsresult +VerifyIntegrityInternal(const SRIMetadata& aMetadata, + nsIChannel* aChannel, + const CORSMode aCORSMode, + uint32_t aStringLen, + const uint8_t* aString, + const nsIDocument* aDocument) { - NS_ConvertUTF16toUTF8 utf8Hash(aString); - return VerifyIntegrity(aMetadata, aChannel, aCORSMode, utf8Hash.Length(), - (uint8_t*)utf8Hash.get(), aDocument); -} - -/* static */ nsresult -SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata, - nsIChannel* aChannel, - const CORSMode aCORSMode, - uint32_t aStringLen, - const uint8_t* aString, - const nsIDocument* aDocument) -{ - if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) { - nsAutoCString requestURL; - nsCOMPtr originalURI; - if (NS_SUCCEEDED(aChannel->GetOriginalURI(getter_AddRefs(originalURI))) && - originalURI) { - originalURI->GetAsciiSpec(requestURL); - // requestURL will be empty if GetAsciiSpec fails - } - SRILOG(("SRICheck::VerifyIntegrity, url=%s (length=%u)", - requestURL.get(), aStringLen)); - } - MOZ_ASSERT(!aMetadata.IsEmpty()); // should be checked by caller // IntegrityMetadata() checks this and returns "no metadata" if @@ -306,5 +288,62 @@ SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata, return NS_ERROR_SRI_CORRUPT; } +/* static */ nsresult +SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata, + nsIUnicharStreamLoader* aLoader, + const CORSMode aCORSMode, + const nsAString& aString, + const nsIDocument* aDocument) +{ + NS_ENSURE_ARG_POINTER(aLoader); + + NS_ConvertUTF16toUTF8 utf8Hash(aString); + nsCOMPtr channel; + aLoader->GetChannel(getter_AddRefs(channel)); + + if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) { + nsAutoCString requestURL; + nsCOMPtr originalURI; + if (channel && + NS_SUCCEEDED(channel->GetOriginalURI(getter_AddRefs(originalURI))) && + originalURI) { + originalURI->GetAsciiSpec(requestURL); + } + SRILOG(("SRICheck::VerifyIntegrity (unichar stream), url=%s (length=%u)", + requestURL.get(), utf8Hash.Length())); + } + + return VerifyIntegrityInternal(aMetadata, channel, aCORSMode, + utf8Hash.Length(), (uint8_t*)utf8Hash.get(), + aDocument); +} + +/* static */ nsresult +SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata, + nsIStreamLoader* aLoader, + const CORSMode aCORSMode, + uint32_t aStringLen, + const uint8_t* aString, + const nsIDocument* aDocument) +{ + NS_ENSURE_ARG_POINTER(aLoader); + + nsCOMPtr request; + aLoader->GetRequest(getter_AddRefs(request)); + NS_ENSURE_ARG_POINTER(request); + nsCOMPtr channel; + channel = do_QueryInterface(request); + + if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) { + nsAutoCString requestURL; + request->GetName(requestURL); + SRILOG(("SRICheck::VerifyIntegrity (stream), url=%s (length=%u)", + requestURL.get(), aStringLen)); + } + + return VerifyIntegrityInternal(aMetadata, channel, aCORSMode, + aStringLen, aString, aDocument); +} + } // namespace dom } // namespace mozilla diff --git a/dom/security/SRICheck.h b/dom/security/SRICheck.h index 6b07bed86de1..c6ac2e6b0b42 100644 --- a/dom/security/SRICheck.h +++ b/dom/security/SRICheck.h @@ -11,11 +11,9 @@ #include "nsCOMPtr.h" #include "SRIMetadata.h" -class nsIChannel; class nsIDocument; -class nsIScriptSecurityManager; class nsIStreamLoader; -class nsIURI; +class nsIUnicharStreamLoader; namespace mozilla { namespace dom { @@ -39,7 +37,7 @@ public: * must prevent the resource from loading. */ static nsresult VerifyIntegrity(const SRIMetadata& aMetadata, - nsIChannel* aChannel, + nsIUnicharStreamLoader* aLoader, const CORSMode aCORSMode, const nsAString& aString, const nsIDocument* aDocument); @@ -49,7 +47,7 @@ public: * must prevent the resource from loading. */ static nsresult VerifyIntegrity(const SRIMetadata& aMetadata, - nsIChannel* aChannel, + nsIStreamLoader* aLoader, const CORSMode aCORSMode, uint32_t aStringLen, const uint8_t* aString, diff --git a/dom/security/test/sri/iframe_script_crossdomain.html b/dom/security/test/sri/iframe_script_crossdomain.html index bcd0146f05eb..f9da6c6775ec 100644 --- a/dom/security/test/sri/iframe_script_crossdomain.html +++ b/dom/security/test/sri/iframe_script_crossdomain.html @@ -58,6 +58,19 @@ ok(false, "Non-CORS loads with correct hashes redirecting to a different origin should be blocked!"); } + function good_correctDataBlocked() { + ok(true, "A data: URL was blocked correctly."); + } + function bad_correctDataLoaded() { + ok(false, "Since data: URLs are neither same-origin nor CORS, they should be blocked!"); + } + function good_correctDataCORSBlocked() { + ok(true, "A data: URL was blocked correctly even though it was a CORS load."); + } + function bad_correctDataCORSLoaded() { + todo(false, "We should not load scripts in data: URIs regardless of CORS mode!"); + } + window.onload = function() { SimpleTest.finish() } @@ -99,6 +112,19 @@ onerror="good_correct301Blocked()" onload="bad_correct301Loaded()"> + + + + + + + + function good_validBlobLoaded() { + ok(true, "A script was loaded successfully from a blob: URL."); + } + function bad_validBlobBlocked() { + ok(false, "We should load scripts using blob: URLs with the right hash!"); + } + + function good_invalidBlobBlocked() { + ok(true, "A script was blocked successfully from a blob: URL."); + } + function bad_invalidBlobLoaded() { + ok(false, "We should not load scripts using blob: URLs with the wrong hash!"); + } + @@ -200,6 +214,32 @@ onerror="good_invalid302Blocked()" onload="bad_invalid302Loaded()"> + + + + + +

diff --git a/dom/security/test/sri/iframe_style_crossdomain.html b/dom/security/test/sri/iframe_style_crossdomain.html index ba8f7d966aa4..814c78703de1 100644 --- a/dom/security/test/sri/iframe_style_crossdomain.html +++ b/dom/security/test/sri/iframe_style_crossdomain.html @@ -6,12 +6,28 @@ - + + + + - + + + + + + + -

This should be red.

+

This should be red but + this should remain black.

diff --git a/dom/security/test/sri/iframe_style_sameorigin.html b/dom/security/test/sri/iframe_style_sameorigin.html index 5e62ec9c8c43..29d013bcbd9e 100644 --- a/dom/security/test/sri/iframe_style_sameorigin.html +++ b/dom/security/test/sri/iframe_style_sameorigin.html @@ -8,11 +8,17 @@ @@ -63,8 +82,39 @@ onload="bad_incorrectHashLoaded()"> + + + + + + +

This should be red and - this should stay black.

+ this should be blue. + However, this should stay black and + this should also stay black. +

+

diff --git a/dom/security/test/sri/mochitest.ini b/dom/security/test/sri/mochitest.ini index 21c9996ab326..18bd92331007 100644 --- a/dom/security/test/sri/mochitest.ini +++ b/dom/security/test/sri/mochitest.ini @@ -23,6 +23,7 @@ support-files = script_401.js script_401.js^headers^ style1.css + style1.css^headers^ style2.css style3.css style_301.css diff --git a/dom/security/test/sri/style1.css^headers^ b/dom/security/test/sri/style1.css^headers^ new file mode 100644 index 000000000000..3a6a85d8944f --- /dev/null +++ b/dom/security/test/sri/style1.css^headers^ @@ -0,0 +1 @@ +Access-Control-Allow-Origin: http://mochi.test:8888 diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp index 19bd6dedd46c..488b07b9aa34 100644 --- a/layout/style/Loader.cpp +++ b/layout/style/Loader.cpp @@ -965,7 +965,7 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader, SRIMetadata sriMetadata = mSheet->GetIntegrity(); if (!sriMetadata.IsEmpty() && - NS_FAILED(SRICheck::VerifyIntegrity(sriMetadata, httpChannel, + NS_FAILED(SRICheck::VerifyIntegrity(sriMetadata, aLoader, mSheet->GetCORSMode(), aBuffer, mLoader->mDocument))) { LOG((" Load was blocked by SRI")); From 1d2db38d827c41600570acfb2811fa15f5d7cbc4 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Wed, 7 Oct 2015 11:45:59 -0700 Subject: [PATCH 074/189] Backed out changeset fe1ed0ded678 (bug 1211974) for robocop orange --- .../synth/speechd/SpeechDispatcherService.cpp | 14 +------------- .../synth/speechd/SpeechDispatcherService.h | 5 +---- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp index 22df4bf6b387..765c17f8fc38 100644 --- a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp @@ -277,8 +277,7 @@ speechd_cb(size_t msg_id, size_t client_id, SPDNotificationType state) NS_INTERFACE_MAP_BEGIN(SpeechDispatcherService) NS_INTERFACE_MAP_ENTRY(nsISpeechService) - NS_INTERFACE_MAP_ENTRY(nsIObserver) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechService) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(SpeechDispatcherService) @@ -441,17 +440,6 @@ SpeechDispatcherService::RegisterVoices() mInitialized = true; } -// nsIObserver - -NS_IMETHODIMP -SpeechDispatcherService::Observe(nsISupports* aSubject, const char* aTopic, - const char16_t* aData) -{ - return NS_OK; -} - -// nsISpeechService - // TODO: Support SSML NS_IMETHODIMP SpeechDispatcherService::Speak(const nsAString& aText, const nsAString& aUri, diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h index 997b6211e3e3..0bfa97fe16ea 100644 --- a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h @@ -9,7 +9,6 @@ #include "mozilla/StaticPtr.h" #include "nsAutoPtr.h" -#include "nsIObserver.h" #include "nsISpeechService.h" #include "nsIThread.h" #include "nsRefPtrHashtable.h" @@ -23,13 +22,11 @@ namespace dom { class SpeechDispatcherCallback; class SpeechDispatcherVoice; -class SpeechDispatcherService final : public nsIObserver, - public nsISpeechService +class SpeechDispatcherService final : public nsISpeechService { friend class SpeechDispatcherCallback; public: NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIOBSERVER NS_DECL_NSISPEECHSERVICE SpeechDispatcherService(); From c593e1ed8f9cd674615d04ccba6c01df04fa0ec6 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 29 Sep 2015 09:31:42 -0700 Subject: [PATCH 075/189] Bug 1052139 - Perform proper failure handling in interfaces' CreateInterfaceObjects method, after dom::CreateInterfaceObjects has been called and possibly created the interface's constructor and prototype. r=bz --HG-- extra : rebase_source : 5d6b7cf208c690d61219baa3cb2d5bfeb471742e --- dom/bindings/Codegen.py | 42 ++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 593e422630cd..8ccab38a3c6c 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -2827,6 +2827,19 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): chromeProperties=chromeProperties, name='"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "nullptr") + # If we fail after here, we must clear interface and prototype caches + # using this code: intermediate failure must not expose the interface in + # partially-constructed state. Note that every case after here needs an + # interface prototype object. + failureCode = dedent( + """ + *protoCache = nullptr; + if (interfaceCache) { + *interfaceCache = nullptr; + } + return; + """) + aliasedMembers = [m for m in self.descriptor.interface.members if m.isMethod() and m.aliases] if aliasedMembers: assert needInterfacePrototypeObject @@ -2846,17 +2859,18 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): prop = '"%s"' % alias return CGList([ getSymbolJSID, - # XXX If we ever create non-enumerate properties that can be - # aliased, we should consider making the aliases match - # the enumerability of the property being aliased. + # XXX If we ever create non-enumerable properties that can + # be aliased, we should consider making the aliases + # match the enumerability of the property being aliased. CGGeneric(fill( """ if (!${defineFn}(aCx, proto, ${prop}, aliasedVal, JSPROP_ENUMERATE)) { - return; + $*{failureCode} } """, defineFn=defineFn, - prop=prop)) + prop=prop, + failureCode=failureCode)) ], "\n") def defineAliasesFor(m): @@ -2864,21 +2878,23 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): CGGeneric(fill( """ if (!JS_GetProperty(aCx, proto, \"${prop}\", &aliasedVal)) { - return; + $*{failureCode} } """, + failureCode=failureCode, prop=m.identifier.name)) ] + [defineAlias(alias) for alias in sorted(m.aliases)]) defineAliases = CGList([ - CGGeneric(dedent(""" + CGGeneric(fill(""" // Set up aliases on the interface prototype object we just created. JS::Handle proto = GetProtoObjectHandle(aCx, aGlobal); if (!proto) { - return; + $*{failureCode} } - """)), + """, + failureCode=failureCode)), CGGeneric("JS::Rooted aliasedVal(aCx);\n\n") ] + [defineAliasesFor(m) for m in sorted(aliasedMembers)]) else: @@ -2904,14 +2920,6 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): else: holderClass = "Class.ToJSClass()" holderProto = "*protoCache" - failureCode = dedent( - """ - *protoCache = nullptr; - if (interfaceCache) { - *interfaceCache = nullptr; - } - return; - """) createUnforgeableHolder = CGGeneric(fill( """ JS::Rooted unforgeableHolder(aCx); From c53e405b1306d7615485d22e2ea5c1124039960d Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 7 Oct 2015 20:06:47 +0100 Subject: [PATCH 076/189] Bug 1211511 - AudioChannelAgent::NotifyStartedPlaying and NotifyStoppedPlaying should use the same level of playback notification, r=roc --- dom/audiochannel/AudioChannelAgent.cpp | 8 +++++--- dom/audiochannel/AudioChannelAgent.h | 1 + dom/audiochannel/nsIAudioChannelAgent.idl | 8 ++------ dom/camera/DOMCameraControl.cpp | 2 +- dom/fmradio/FMRadio.cpp | 2 +- dom/html/HTMLMediaElement.cpp | 10 +++++----- dom/media/webaudio/AudioDestinationNode.cpp | 6 +++--- dom/media/webspeech/synth/nsSpeechTask.cpp | 4 ++-- dom/plugins/base/nsNPAPIPlugin.cpp | 2 +- dom/telephony/Telephony.cpp | 6 +++--- dom/telephony/Telephony.h | 1 - 11 files changed, 24 insertions(+), 26 deletions(-) diff --git a/dom/audiochannel/AudioChannelAgent.cpp b/dom/audiochannel/AudioChannelAgent.cpp index 7d2fc35abcd4..e33823d7e979 100644 --- a/dom/audiochannel/AudioChannelAgent.cpp +++ b/dom/audiochannel/AudioChannelAgent.cpp @@ -37,6 +37,7 @@ AudioChannelAgent::AudioChannelAgent() : mAudioChannelType(AUDIO_AGENT_CHANNEL_ERROR) , mInnerWindowID(0) , mIsRegToService(false) + , mNotifyPlayback(false) { } @@ -49,7 +50,7 @@ void AudioChannelAgent::Shutdown() { if (mIsRegToService) { - NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + NotifyStoppedPlaying(); } } @@ -162,11 +163,12 @@ NS_IMETHODIMP AudioChannelAgent::NotifyStartedPlaying(uint32_t aNotifyPlayback, service->GetState(mWindow, mAudioChannelType, aVolume, aMuted); + mNotifyPlayback = aNotifyPlayback; mIsRegToService = true; return NS_OK; } -NS_IMETHODIMP AudioChannelAgent::NotifyStoppedPlaying(uint32_t aNotifyPlayback) +NS_IMETHODIMP AudioChannelAgent::NotifyStoppedPlaying() { if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR || !mIsRegToService) { @@ -174,7 +176,7 @@ NS_IMETHODIMP AudioChannelAgent::NotifyStoppedPlaying(uint32_t aNotifyPlayback) } nsRefPtr service = AudioChannelService::GetOrCreate(); - service->UnregisterAudioChannelAgent(this, aNotifyPlayback); + service->UnregisterAudioChannelAgent(this, mNotifyPlayback); mIsRegToService = false; return NS_OK; } diff --git a/dom/audiochannel/AudioChannelAgent.h b/dom/audiochannel/AudioChannelAgent.h index 809d34f2a1e7..74271199ec8a 100644 --- a/dom/audiochannel/AudioChannelAgent.h +++ b/dom/audiochannel/AudioChannelAgent.h @@ -64,6 +64,7 @@ private: int32_t mAudioChannelType; uint64_t mInnerWindowID; bool mIsRegToService; + bool mNotifyPlayback; }; } // namespace dom diff --git a/dom/audiochannel/nsIAudioChannelAgent.idl b/dom/audiochannel/nsIAudioChannelAgent.idl index 54ca3be765c4..8692c42f5e88 100644 --- a/dom/audiochannel/nsIAudioChannelAgent.idl +++ b/dom/audiochannel/nsIAudioChannelAgent.idl @@ -34,7 +34,7 @@ interface nsIAudioChannelAgentCallback : nsISupports * 1. Changes to the playable status of this channel. */ -[uuid(62e0037c-9786-4b79-b986-27111f6e553b)] +[uuid(18222148-1b32-463d-b050-b741f43a07ba)] interface nsIAudioChannelAgent : nsISupports { const long AUDIO_AGENT_CHANNEL_NORMAL = 0; @@ -118,14 +118,10 @@ interface nsIAudioChannelAgent : nsISupports /** * Notify the agent we no longer want to play. * - * @param notifyPlaying - * Whether to send audio-playback notifications, one of AUDIO_CHANNEL_NOTIFY - * or AUDIO_CHANNEL_DONT_NOTIFY. - * * Note : even if notifyStartedPlaying() returned false, the agent would * still be registered with the audio channel service and receive callbacks * for status changes. So notifyStoppedPlaying must still eventually be * called to unregister the agent with the channel service. */ - void notifyStoppedPlaying(in unsigned long notifyPlayback); + void notifyStoppedPlaying(); }; diff --git a/dom/camera/DOMCameraControl.cpp b/dom/camera/DOMCameraControl.cpp index 969ccabde59d..88491908b491 100755 --- a/dom/camera/DOMCameraControl.cpp +++ b/dom/camera/DOMCameraControl.cpp @@ -1089,7 +1089,7 @@ nsDOMCameraControl::ReleaseAudioChannelAgent() { #ifdef MOZ_B2G if (mAudioChannelAgent) { - mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_DONT_NOTIFY); + mAudioChannelAgent->NotifyStoppedPlaying(); mAudioChannelAgent = nullptr; } #endif diff --git a/dom/fmradio/FMRadio.cpp b/dom/fmradio/FMRadio.cpp index 489946ae6acf..0e2feb459ab2 100644 --- a/dom/fmradio/FMRadio.cpp +++ b/dom/fmradio/FMRadio.cpp @@ -190,7 +190,7 @@ FMRadio::Notify(const FMRadioEventType& aType) DispatchTrustedEvent(NS_LITERAL_STRING("enabled")); } else { if (mAudioChannelAgentEnabled) { - mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + mAudioChannelAgent->NotifyStoppedPlaying(); mAudioChannelAgentEnabled = false; } diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 8bf6f3b71731..572c0b8cf8d2 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -4757,17 +4757,17 @@ HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying) // this method has some content JS in its stack. AutoNoJSAPI nojsapi; - // Don't notify playback if this element doesn't have any audio tracks. - uint32_t notify = HasAudio() ? nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY : - nsIAudioChannelAgent::AUDIO_AGENT_DONT_NOTIFY; - if (aPlaying) { + // Don't notify playback if this element doesn't have any audio tracks. + uint32_t notify = HasAudio() ? nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY : + nsIAudioChannelAgent::AUDIO_AGENT_DONT_NOTIFY; + float volume = 0.0; bool muted = true; mAudioChannelAgent->NotifyStartedPlaying(notify, &volume, &muted); WindowVolumeChanged(volume, muted); } else { - mAudioChannelAgent->NotifyStoppedPlaying(notify); + mAudioChannelAgent->NotifyStoppedPlaying(); mAudioChannelAgent = nullptr; } } diff --git a/dom/media/webaudio/AudioDestinationNode.cpp b/dom/media/webaudio/AudioDestinationNode.cpp index 1e8d9a9b3336..423beed986b9 100644 --- a/dom/media/webaudio/AudioDestinationNode.cpp +++ b/dom/media/webaudio/AudioDestinationNode.cpp @@ -388,7 +388,7 @@ void AudioDestinationNode::DestroyAudioChannelAgent() { if (mAudioChannelAgent && !Context()->IsOffline()) { - mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + mAudioChannelAgent->NotifyStoppedPlaying(); mAudioChannelAgent = nullptr; } } @@ -638,7 +638,7 @@ AudioDestinationNode::CreateAudioChannelAgent() nsresult rv = NS_OK; if (mAudioChannelAgent) { - rv = mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + rv = mAudioChannelAgent->NotifyStoppedPlaying(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -739,7 +739,7 @@ AudioDestinationNode::InputMuted(bool aMuted) } if (aMuted) { - mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + mAudioChannelAgent->NotifyStoppedPlaying(); return; } diff --git a/dom/media/webspeech/synth/nsSpeechTask.cpp b/dom/media/webspeech/synth/nsSpeechTask.cpp index bcb1e1640657..6956b960a9c6 100644 --- a/dom/media/webspeech/synth/nsSpeechTask.cpp +++ b/dom/media/webspeech/synth/nsSpeechTask.cpp @@ -672,7 +672,7 @@ nsSpeechTask::CreateAudioChannelAgent() } if (mAudioChannelAgent) { - mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + mAudioChannelAgent->NotifyStoppedPlaying(); } mAudioChannelAgent = new AudioChannelAgent(); @@ -689,7 +689,7 @@ void nsSpeechTask::DestroyAudioChannelAgent() { if (mAudioChannelAgent) { - mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + mAudioChannelAgent->NotifyStoppedPlaying(); mAudioChannelAgent = nullptr; } } diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp index b867ffb51b91..60e23a9a8ba4 100644 --- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -2283,7 +2283,7 @@ _setvalue(NPP npp, NPPVariable variable, void *result) MOZ_ASSERT(agent); if (isMuted) { - rv = agent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + rv = agent->NotifyStoppedPlaying(); if (NS_WARN_IF(NS_FAILED(rv))) { return NPERR_NO_ERROR; } diff --git a/dom/telephony/Telephony.cpp b/dom/telephony/Telephony.cpp index 1b544f394168..1e8c2327ea40 100644 --- a/dom/telephony/Telephony.cpp +++ b/dom/telephony/Telephony.cpp @@ -63,7 +63,6 @@ public: Telephony::Telephony(nsPIDOMWindow* aOwner) : DOMEventTargetHelper(aOwner), - mAudioAgentNotify(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY), mIsAudioStartPlaying(false), mHaveDispatchedInterruptBeginEvent(false), mMuted(AudioChannelService::IsAudioChannelMutedByDefault()) @@ -554,7 +553,7 @@ Telephony::HandleAudioAgentState() if ((!mCalls.Length() && !mGroup->CallsArray().Length()) && mIsAudioStartPlaying) { mIsAudioStartPlaying = false; - rv = mAudioAgent->NotifyStoppedPlaying(mAudioAgentNotify); + rv = mAudioAgent->NotifyStoppedPlaying(); mAudioAgent = nullptr; if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -563,7 +562,8 @@ Telephony::HandleAudioAgentState() mIsAudioStartPlaying = true; float volume; bool muted; - rv = mAudioAgent->NotifyStartedPlaying(mAudioAgentNotify, &volume, &muted); + rv = mAudioAgent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY, + &volume, &muted); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } diff --git a/dom/telephony/Telephony.h b/dom/telephony/Telephony.h index 8e52958a41cc..9f1fe9671578 100644 --- a/dom/telephony/Telephony.h +++ b/dom/telephony/Telephony.h @@ -59,7 +59,6 @@ class Telephony final : public DOMEventTargetHelper, nsRefPtr mReadyPromise; - uint32_t mAudioAgentNotify; bool mIsAudioStartPlaying; bool mHaveDispatchedInterruptBeginEvent; bool mMuted; From fb11b16545e2862fd5da3662649d1509f5d16489 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 7 Oct 2015 12:08:53 -0700 Subject: [PATCH 077/189] Fix inactive scroll frames sometimes creating very large, incorrect hit regions. (bug 1190112, r=tn) --- gfx/layers/apz/test/mochitest/mochitest.ini | 2 + .../test_scroll_inactive_bug1190112.html | 542 ++++++++++++++++++ layout/base/nsDisplayList.cpp | 1 + layout/base/nsDisplayList.h | 1 - layout/generic/nsFrame.cpp | 3 + 5 files changed, 548 insertions(+), 1 deletion(-) create mode 100644 gfx/layers/apz/test/mochitest/test_scroll_inactive_bug1190112.html diff --git a/gfx/layers/apz/test/mochitest/mochitest.ini b/gfx/layers/apz/test/mochitest/mochitest.ini index 6af4a619b3c4..cd3862004703 100644 --- a/gfx/layers/apz/test/mochitest/mochitest.ini +++ b/gfx/layers/apz/test/mochitest/mochitest.ini @@ -27,3 +27,5 @@ skip-if = (os == 'android') || (os == 'b2g') # uses wheel events which are not s skip-if = toolkit != 'gonk' [test_scroll_inactive_flattened_frame.html] skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet +[test_scroll_inactive_bug1190112.html] +skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet diff --git a/gfx/layers/apz/test/mochitest/test_scroll_inactive_bug1190112.html b/gfx/layers/apz/test/mochitest/test_scroll_inactive_bug1190112.html new file mode 100644 index 000000000000..b4a3a081f398 --- /dev/null +++ b/gfx/layers/apz/test/mochitest/test_scroll_inactive_bug1190112.html @@ -0,0 +1,542 @@ + + + + Test scrolling flattened inactive frames + + + + + + + +
+
+
+
+

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+ +

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+ +

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+ +

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+ +

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+ +

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+ +

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+ +

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+ +

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+ +

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+ +

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+ +

+
+ + + diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 56a60befa0c9..2370c2bf0927 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -3235,6 +3235,7 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder, void nsDisplayLayerEventRegions::AddInactiveScrollPort(const nsRect& aRect) { + mHitRegion.Or(mHitRegion, aRect); mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, aRect); } diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 898e4e35d8c1..f78db61f3d8a 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2920,7 +2920,6 @@ public: : nsDisplayItem(aBuilder, aFrame) { MOZ_COUNT_CTOR(nsDisplayLayerEventRegions); - AddFrame(aBuilder, aFrame); } #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplayLayerEventRegions() { diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 8ee469281657..ebffd6d3ca8b 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -2043,6 +2043,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, if (aBuilder->IsBuildingLayerEventRegions()) { nsDisplayLayerEventRegions* eventRegions = new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this); + eventRegions->AddFrame(aBuilder, this); aBuilder->SetLayerEventRegions(eventRegions); set.BorderBackground()->AppendNewToTop(eventRegions); } @@ -2505,6 +2506,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, if (animatedGeometryRoot != buildingForChild.GetPrevAnimatedGeometryRoot()) { nsDisplayLayerEventRegions* eventRegions = new (aBuilder) nsDisplayLayerEventRegions(aBuilder, child); + eventRegions->AddFrame(aBuilder, child); aBuilder->SetLayerEventRegions(eventRegions); aLists.BorderBackground()->AppendNewToTop(eventRegions); } @@ -2531,6 +2533,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, if (aBuilder->IsBuildingLayerEventRegions()) { nsDisplayLayerEventRegions* eventRegions = new (aBuilder) nsDisplayLayerEventRegions(aBuilder, child); + eventRegions->AddFrame(aBuilder, child); aBuilder->SetLayerEventRegions(eventRegions); pseudoStack.BorderBackground()->AppendNewToTop(eventRegions); } From 13352c21d459429a54c9e12f0790ae9ca9d155bd Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 7 Oct 2015 20:32:14 +0100 Subject: [PATCH 078/189] Bug 1212009 - ReadFullySerializableObjects() doesn't use the aIndex param and it can be removed, r=smaug --- dom/base/StructuredCloneHolder.cpp | 5 ++--- dom/base/StructuredCloneHolder.h | 3 +-- dom/indexedDB/IDBObjectStore.cpp | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp index bc375c9853ff..905ed821ad0b 100644 --- a/dom/base/StructuredCloneHolder.cpp +++ b/dom/base/StructuredCloneHolder.cpp @@ -383,8 +383,7 @@ StructuredCloneHolder::FreeBuffer(uint64_t* aBuffer, /* static */ JSObject* StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx, JSStructuredCloneReader* aReader, - uint32_t aTag, - uint32_t aIndex) + uint32_t aTag) { if (aTag == SCTAG_DOM_IMAGEDATA) { return ReadStructuredCloneImageData(aCx, aReader); @@ -928,7 +927,7 @@ StructuredCloneHolder::CustomReadHandler(JSContext* aCx, parent, GetImages(), aIndex); } - return ReadFullySerializableObjects(aCx, aReader, aTag, aIndex); + return ReadFullySerializableObjects(aCx, aReader, aTag); } bool diff --git a/dom/base/StructuredCloneHolder.h b/dom/base/StructuredCloneHolder.h index 9d77b73662b9..551831038030 100644 --- a/dom/base/StructuredCloneHolder.h +++ b/dom/base/StructuredCloneHolder.h @@ -254,8 +254,7 @@ public: static JSObject* ReadFullySerializableObjects(JSContext* aCx, JSStructuredCloneReader* aReader, - uint32_t aTag, - uint32_t aIndex); + uint32_t aTag); static bool WriteFullySerializableObjects(JSContext* aCx, JSStructuredCloneWriter* aWriter, diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index a360b8e97730..7abd6750e180 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -894,7 +894,7 @@ CommonStructuredCloneReadCallback(JSContext* aCx, } return StructuredCloneHolder::ReadFullySerializableObjects(aCx, aReader, - aTag, aData); + aTag); } // static From 50ac42f57a8eb84fc161c8ac8ded10c1c79d1bde Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 7 Oct 2015 20:35:11 +0100 Subject: [PATCH 079/189] Bug 949376 - MessageEvent::initMessageEvent, r=smaug --- dom/events/MessageEvent.cpp | 45 +++++++++++++++++++++++++- dom/events/MessageEvent.h | 11 ++++++- dom/events/test/test_messageEvent.html | 39 ++++++++++++++-------- dom/messagechannel/MessagePortList.h | 2 +- dom/webidl/MessageEvent.webidl | 6 ++++ 5 files changed, 87 insertions(+), 16 deletions(-) diff --git a/dom/events/MessageEvent.cpp b/dom/events/MessageEvent.cpp index 29cb907678d9..08fe8b54c0d4 100644 --- a/dom/events/MessageEvent.cpp +++ b/dom/events/MessageEvent.cpp @@ -199,6 +199,49 @@ MessageEvent::InitMessageEvent(const nsAString& aType, return NS_OK; } +void +MessageEvent::InitMessageEvent(JSContext* aCx, const nsAString& aType, + bool aCanBubble, bool aCancelable, + JS::Handle aData, + const nsAString& aOrigin, + const nsAString& aLastEventId, + const Nullable& aSource, + const Nullable>>& aPorts, + ErrorResult& aRv) +{ + aRv = Event::InitEvent(aType, aCanBubble, aCancelable); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + mData = aData; + mozilla::HoldJSObjects(this); + mOrigin = aOrigin; + mLastEventId = aLastEventId; + + mWindowSource = nullptr; + mPortSource = nullptr; + + if (!aSource.IsNull()) { + if (aSource.Value().IsWindowProxy()) { + mWindowSource = aSource.Value().GetAsWindowProxy(); + } else { + mPortSource = &aSource.Value().GetAsMessagePort(); + } + } + + mPorts = nullptr; + + if (!aPorts.IsNull()) { + nsTArray> ports; + for (uint32_t i = 0, len = aPorts.Value().Length(); i < len; ++i) { + ports.AppendElement(aPorts.Value()[i]); + } + + mPorts = new MessagePortList(static_cast(this), ports); + } +} + void MessageEvent::SetPorts(MessagePortList* aPorts) { @@ -227,7 +270,7 @@ using namespace mozilla::dom; already_AddRefed NS_NewDOMMessageEvent(EventTarget* aOwner, nsPresContext* aPresContext, - WidgetEvent* aEvent) + WidgetEvent* aEvent) { nsRefPtr it = new MessageEvent(aOwner, aPresContext, aEvent); return it.forget(); diff --git a/dom/events/MessageEvent.h b/dom/events/MessageEvent.h index e2b4e1afcaa0..a435f1ae798a 100644 --- a/dom/events/MessageEvent.h +++ b/dom/events/MessageEvent.h @@ -8,9 +8,10 @@ #define mozilla_dom_MessageEvent_h_ #include "mozilla/dom/Event.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/MessagePortList.h" #include "nsCycleCollectionParticipant.h" #include "nsIDOMMessageEvent.h" -#include "mozilla/dom/MessagePortList.h" namespace mozilla { namespace dom { @@ -19,6 +20,7 @@ struct MessageEventInit; class MessagePort; class MessagePortList; class OwningWindowProxyOrMessagePortOrClient; +class WindowProxyOrMessagePort; namespace workers { @@ -85,6 +87,13 @@ public: const MessageEventInit& aEventInit, ErrorResult& aRv); + void InitMessageEvent(JSContext* aCx, const nsAString& aType, bool aCanBubble, + bool aCancelable, JS::Handle aData, + const nsAString& aOrigin, const nsAString& aLastEventId, + const Nullable& aSource, + const Nullable>>& aPorts, + ErrorResult& aRv); + protected: ~MessageEvent(); diff --git a/dom/events/test/test_messageEvent.html b/dom/events/test/test_messageEvent.html index b8dc91f86645..249aa9e8c158 100644 --- a/dom/events/test/test_messageEvent.html +++ b/dom/events/test/test_messageEvent.html @@ -13,6 +13,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=848294 From 3ac14ea3a6f33148e0e21d04984e5d2316498d27 Mon Sep 17 00:00:00 2001 From: Brian Grinstead Date: Wed, 7 Oct 2015 08:19:44 -0700 Subject: [PATCH 152/189] Bug 1210954 - Move devtools variables into a single variables.css file;r=jryans;r=jsantell --HG-- extra : commitid : 3wYHIWq4LXT --- devtools/client/jar.mn | 1 + devtools/client/shared/theme.js | 47 +++++++------ devtools/client/themes/dark-theme.css | 42 +----------- devtools/client/themes/light-theme.css | 42 +----------- devtools/client/themes/variables.css | 91 ++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 103 deletions(-) create mode 100644 devtools/client/themes/variables.css diff --git a/devtools/client/jar.mn b/devtools/client/jar.mn index 23065e482e5f..ad0610a8fb7a 100644 --- a/devtools/client/jar.mn +++ b/devtools/client/jar.mn @@ -164,6 +164,7 @@ devtools.jar: * skin/themes/common.css (themes/common.css) * skin/themes/dark-theme.css (themes/dark-theme.css) * skin/themes/light-theme.css (themes/light-theme.css) + skin/themes/variables.css (themes/variables.css) skin/themes/images/add.svg (themes/images/add.svg) skin/themes/images/filters.svg (themes/images/filters.svg) skin/themes/images/filter-swatch.svg (themes/images/filter-swatch.svg) diff --git a/devtools/client/shared/theme.js b/devtools/client/shared/theme.js index 3715d1a1b8e3..4037fa91a890 100644 --- a/devtools/client/shared/theme.js +++ b/devtools/client/shared/theme.js @@ -14,12 +14,13 @@ const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {}); loader.lazyRequireGetter(this, "Services"); loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/client/framework/gDevTools.jsm"); -const themeURIs = { - light: "chrome://devtools/skin/themes/light-theme.css", - dark: "chrome://devtools/skin/themes/dark-theme.css" +const VARIABLES_URI = "chrome://devtools/skin/themes/variables.css"; +const THEME_SELECTOR_STRINGS = { + light: ":root.theme-light {", + dark: ":root.theme-dark {" } -const cachedThemes = {}; +let variableFileContents; /** * Returns a string of the file found at URI @@ -37,19 +38,29 @@ function readURI (uri) { } /** - * Takes a theme name and either returns it from the cache, - * or fetches the theme CSS file and caches it. + * Takes a theme name and returns the contents of its variable rule block. + * The first time this runs fetches the variables CSS file and caches it. */ function getThemeFile (name) { - // Use the cached theme, or generate it - let themeFile = cachedThemes[name] || readURI(themeURIs[name]).match(/--theme-.*: .*;/g).join("\n"); - - // Cache if not already cached - if (!cachedThemes[name]) { - cachedThemes[name] = themeFile; + if (!variableFileContents) { + variableFileContents = readURI(VARIABLES_URI); } - return themeFile; + // If there's no theme expected for this name, use `light` as default. + let selector = THEME_SELECTOR_STRINGS[name] || + THEME_SELECTOR_STRINGS["light"]; + + // This is a pretty naive way to find the contents between: + // selector { + // name: val; + // } + // There is test coverage for this feature (browser_theme.js) + // so if an } is introduced in the variables file it will catch that. + let theme = variableFileContents; + theme = theme.substring(theme.indexOf(selector)); + theme = theme.substring(0, theme.indexOf("}")); + + return theme; } /** @@ -66,17 +77,11 @@ const getTheme = exports.getTheme = () => Services.prefs.getCharPref("devtools.t */ const getColor = exports.getColor = (type, theme) => { let themeName = theme || getTheme(); - - // If there's no theme URIs for this theme, use `light` as default. - if (!themeURIs[themeName]) { - themeName = "light"; - } - let themeFile = getThemeFile(themeName); - let match; + let match = themeFile.match(new RegExp("--theme-" + type + ": (.*);")); // Return the appropriate variable in the theme, or otherwise, null. - return (match = themeFile.match(new RegExp("--theme-" + type + ": (.*);"))) ? match[1] : null; + return match ? match[1] : null; }; /** diff --git a/devtools/client/themes/dark-theme.css b/devtools/client/themes/dark-theme.css index 2eb5d632d51a..5bbce4041387 100644 --- a/devtools/client/themes/dark-theme.css +++ b/devtools/client/themes/dark-theme.css @@ -3,47 +3,7 @@ * 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/. */ -/* Colors are taken from: - * https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors. - * Changes should be kept in sync with commandline.css and commandline.inc.css. - */ -:root { - --theme-body-background: #14171a; - --theme-sidebar-background: #181d20; - --theme-contrast-background: #b28025; - - --theme-tab-toolbar-background: #252c33; - --theme-toolbar-background: #343c45; - --theme-selection-background: #1d4f73; - --theme-selection-background-semitransparent: rgba(29, 79, 115, .5); - --theme-selection-color: #f5f7fa; - --theme-splitter-color: black; - --theme-comment: #757873; - - --theme-body-color: #8fa1b2; - --theme-body-color-alt: #b6babf; - --theme-content-color1: #a9bacb; - --theme-content-color2: #8fa1b2; - --theme-content-color3: #5f7387; - - --theme-highlight-green: #70bf53; - --theme-highlight-blue: #46afe3; - --theme-highlight-bluegrey: #5e88b0; - --theme-highlight-purple: #6b7abb; - --theme-highlight-lightorange: #d99b28; - --theme-highlight-orange: #d96629; - --theme-highlight-red: #eb5368; - --theme-highlight-pink: #df80ff; - - /* Colors used in Graphs, like performance tools. Mostly similar to some "highlight-*" colors. */ - --theme-graphs-green: #70bf53; - --theme-graphs-blue: #46afe3; - --theme-graphs-bluegrey: #5e88b0; - --theme-graphs-purple: #df80ff; - --theme-graphs-yellow: #d99b28; - --theme-graphs-red: #eb5368; - --theme-graphs-grey: #757873; -} +@import url(variables.css); .theme-body { background: var(--theme-body-background); diff --git a/devtools/client/themes/light-theme.css b/devtools/client/themes/light-theme.css index ff4197eb4fbc..b4107ca9d5a2 100644 --- a/devtools/client/themes/light-theme.css +++ b/devtools/client/themes/light-theme.css @@ -3,47 +3,7 @@ * 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/. */ -/* Colors are taken from: - * https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors. - * Changes should be kept in sync with commandline.css and commandline.inc.css. - */ -:root { - --theme-body-background: #fcfcfc; - --theme-sidebar-background: #f7f7f7; - --theme-contrast-background: #e6b064; - - --theme-tab-toolbar-background: #ebeced; - --theme-toolbar-background: #f0f1f2; - --theme-selection-background: #4c9ed9; - --theme-selection-background-semitransparent: rgba(76, 158, 217, .23); - --theme-selection-color: #f5f7fa; - --theme-splitter-color: #aaaaaa; - --theme-comment: #757873; - - --theme-body-color: #18191a; - --theme-body-color-alt: #585959; - --theme-content-color1: #292e33; - --theme-content-color2: #8fa1b2; - --theme-content-color3: #667380; - - --theme-highlight-green: #2cbb0f; - --theme-highlight-blue: #0088cc; - --theme-highlight-bluegrey: #0072ab; - --theme-highlight-purple: #5b5fff; - --theme-highlight-lightorange: #d97e00; - --theme-highlight-orange: #f13c00; - --theme-highlight-red: #ed2655; - --theme-highlight-pink: #b82ee5; - - /* Colors used in Graphs, like performance tools. Similar colors to Chrome's timeline. */ - --theme-graphs-green: #85d175; - --theme-graphs-blue: #83b7f6; - --theme-graphs-bluegrey: #0072ab; - --theme-graphs-purple: #b693eb; - --theme-graphs-yellow: #efc052; - --theme-graphs-red: #e57180; - --theme-graphs-grey: #cccccc; -} +@import url(variables.css); .theme-body { background: var(--theme-body-background); diff --git a/devtools/client/themes/variables.css b/devtools/client/themes/variables.css new file mode 100644 index 000000000000..e35a40dfdd75 --- /dev/null +++ b/devtools/client/themes/variables.css @@ -0,0 +1,91 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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/. */ + +/* Variable declarations for light and dark devtools themes. + * Colors are taken from: + * https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors. + * Changes should be kept in sync with commandline.css and commandline.inc.css. + */ + +/* IMPORTANT NOTE: + * This file is parsed in js (see client/shared/theme.js) + * so the formatting should be consistent (i.e. no '}' inside a rule). + */ + +:root.theme-light { + --theme-body-background: #fcfcfc; + --theme-sidebar-background: #f7f7f7; + --theme-contrast-background: #e6b064; + + --theme-tab-toolbar-background: #ebeced; + --theme-toolbar-background: #f0f1f2; + --theme-selection-background: #4c9ed9; + --theme-selection-background-semitransparent: rgba(76, 158, 217, .23); + --theme-selection-color: #f5f7fa; + --theme-splitter-color: #aaaaaa; + --theme-comment: #757873; + + --theme-body-color: #18191a; + --theme-body-color-alt: #585959; + --theme-content-color1: #292e33; + --theme-content-color2: #8fa1b2; + --theme-content-color3: #667380; + + --theme-highlight-green: #2cbb0f; + --theme-highlight-blue: #0088cc; + --theme-highlight-bluegrey: #0072ab; + --theme-highlight-purple: #5b5fff; + --theme-highlight-lightorange: #d97e00; + --theme-highlight-orange: #f13c00; + --theme-highlight-red: #ed2655; + --theme-highlight-pink: #b82ee5; + + /* Colors used in Graphs, like performance tools. Similar colors to Chrome's timeline. */ + --theme-graphs-green: #85d175; + --theme-graphs-blue: #83b7f6; + --theme-graphs-bluegrey: #0072ab; + --theme-graphs-purple: #b693eb; + --theme-graphs-yellow: #efc052; + --theme-graphs-red: #e57180; + --theme-graphs-grey: #cccccc; +} + +:root.theme-dark { + --theme-body-background: #14171a; + --theme-sidebar-background: #181d20; + --theme-contrast-background: #b28025; + + --theme-tab-toolbar-background: #252c33; + --theme-toolbar-background: #343c45; + --theme-selection-background: #1d4f73; + --theme-selection-background-semitransparent: rgba(29, 79, 115, .5); + --theme-selection-color: #f5f7fa; + --theme-splitter-color: black; + --theme-comment: #757873; + + --theme-body-color: #8fa1b2; + --theme-body-color-alt: #b6babf; + --theme-content-color1: #a9bacb; + --theme-content-color2: #8fa1b2; + --theme-content-color3: #5f7387; + + --theme-highlight-green: #70bf53; + --theme-highlight-blue: #46afe3; + --theme-highlight-bluegrey: #5e88b0; + --theme-highlight-purple: #6b7abb; + --theme-highlight-lightorange: #d99b28; + --theme-highlight-orange: #d96629; + --theme-highlight-red: #eb5368; + --theme-highlight-pink: #df80ff; + + /* Colors used in Graphs, like performance tools. Mostly similar to some "highlight-*" colors. */ + --theme-graphs-green: #70bf53; + --theme-graphs-blue: #46afe3; + --theme-graphs-bluegrey: #5e88b0; + --theme-graphs-purple: #df80ff; + --theme-graphs-yellow: #d99b28; + --theme-graphs-red: #eb5368; + --theme-graphs-grey: #757873; +} From 0bb9b3343bcfb28076a11d4d7d293fcd0d19d8ca Mon Sep 17 00:00:00 2001 From: Alexandre Poirot Date: Wed, 7 Oct 2015 08:30:18 -0700 Subject: [PATCH 153/189] Bug 1211453 - Run simulator post-build task on mozilla-central. r=garndt --- .../tasks/branches/mozilla-central/job_flags.yml | 11 +++++++++++ testing/taskcluster/tasks/branches/try/job_flags.yml | 5 ----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/testing/taskcluster/tasks/branches/mozilla-central/job_flags.yml b/testing/taskcluster/tasks/branches/mozilla-central/job_flags.yml index 396e44910731..eeb336e0656f 100644 --- a/testing/taskcluster/tasks/branches/mozilla-central/job_flags.yml +++ b/testing/taskcluster/tasks/branches/mozilla-central/job_flags.yml @@ -5,6 +5,11 @@ $inherits: from: tasks/branches/base_jobs.yml +# Flags specific to this branch +flags: + post-build: + - simulator + builds: android-api-11: platforms: @@ -34,3 +39,9 @@ builds: task: tasks/builds/b2g_flame_kk_ota_opt.yml debug: task: tasks/builds/b2g_flame_kk_ota_debug.yml + +post-build: + simulator: + allowed_build_tasks: + - tasks/builds/mulet_linux.yml + task: tasks/post-builds/mulet_simulator.yml diff --git a/testing/taskcluster/tasks/branches/try/job_flags.yml b/testing/taskcluster/tasks/branches/try/job_flags.yml index a095d9307af8..00ba48697022 100644 --- a/testing/taskcluster/tasks/branches/try/job_flags.yml +++ b/testing/taskcluster/tasks/branches/try/job_flags.yml @@ -9,7 +9,6 @@ $inherits: flags: post-build: - upload-symbols - - simulator builds: linux64_gecko: @@ -225,10 +224,6 @@ post-build: - tasks/builds/dbg_linux64.yml - tasks/builds/android_api_11.yml task: tasks/post-builds/upload_symbols.yml - simulator: - allowed_build_tasks: - - tasks/builds/mulet_linux.yml - task: tasks/post-builds/mulet_simulator.yml tests: cppunit: From 824ed3e7f6261158e789c1388cbf92b85edc5bf7 Mon Sep 17 00:00:00 2001 From: Kit Cambridge Date: Wed, 7 Oct 2015 11:45:30 -0400 Subject: [PATCH 154/189] Bug 1212035 - yield on removeTab in browser_notification_open_settings.js to fix intermittent failures. r=MattN --HG-- extra : commitid : 5jcasqxnN2K extra : rebase_source : 458c24a040cfc670519398de30860241ed025377 --- .../content/test/alerts/browser_notification_open_settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/base/content/test/alerts/browser_notification_open_settings.js b/browser/base/content/test/alerts/browser_notification_open_settings.js index f339af140fb1..48a658c4601e 100644 --- a/browser/base/content/test/alerts/browser_notification_open_settings.js +++ b/browser/base/content/test/alerts/browser_notification_open_settings.js @@ -13,6 +13,6 @@ add_task(function* test_settingsOpen() { Services.obs.notifyObservers(principal, "notifications-open-settings", null); let tab = yield tabPromise; ok(tab, "The notification settings tab opened"); - BrowserTestUtils.removeTab(tab); + yield BrowserTestUtils.removeTab(tab); }); }); From 92c5a313e2561ba3dda40946a0393f081d10c715 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Tue, 6 Oct 2015 10:13:00 -0400 Subject: [PATCH 155/189] Bug 1195995 - merge css-tokenizer into css-parsing-utils; r=mratcliffe --HG-- rename : devtools/client/styleinspector/css-parsing-utils.js => devtools/client/shared/css-parsing-utils.js rename : devtools/client/styleinspector/test/unit/test_escapeCSSComment.js => devtools/client/shared/test/unit/test_escapeCSSComment.js rename : devtools/client/styleinspector/test/unit/test_parseDeclarations.js => devtools/client/shared/test/unit/test_parseDeclarations.js rename : devtools/client/styleinspector/test/unit/test_parsePseudoClassesAndAttributes.js => devtools/client/shared/test/unit/test_parsePseudoClassesAndAttributes.js rename : devtools/client/styleinspector/test/unit/test_parseSingleValue.js => devtools/client/shared/test/unit/test_parseSingleValue.js rename : devtools/client/styleinspector/test/unit/test_rewriteDeclarations.js => devtools/client/shared/test/unit/test_rewriteDeclarations.js extra : commitid : Ip6qFxTZHJb --- .../css-parsing-utils.js | 82 +++++++++++++++- devtools/client/shared/moz.build | 1 + .../test/unit/test_escapeCSSComment.js | 2 +- .../test/unit/test_parseDeclarations.js | 4 +- .../test_parsePseudoClassesAndAttributes.js | 4 +- .../test/unit/test_parseSingleValue.js | 4 +- .../test/unit/test_rewriteDeclarations.js | 2 +- devtools/client/shared/test/unit/xpcshell.ini | 5 + .../client/shared/widgets/FilterWidget.js | 2 +- .../client/sourceeditor/css-autocompleter.js | 6 +- devtools/client/sourceeditor/css-tokenizer.js | 95 ------------------- devtools/client/sourceeditor/moz.build | 1 - devtools/client/styleinspector/moz.build | 2 - devtools/client/styleinspector/rule-view.js | 2 +- .../client/styleinspector/test/unit/.eslintrc | 4 - .../styleinspector/test/unit/xpcshell.ini | 12 --- devtools/client/styleinspector/utils.js | 2 +- devtools/server/actors/styles.js | 2 +- 18 files changed, 102 insertions(+), 130 deletions(-) rename devtools/client/{styleinspector => shared}/css-parsing-utils.js (94%) rename devtools/client/{styleinspector => shared}/test/unit/test_escapeCSSComment.js (92%) rename devtools/client/{styleinspector => shared}/test/unit/test_parseDeclarations.js (98%) rename devtools/client/{styleinspector => shared}/test/unit/test_parsePseudoClassesAndAttributes.js (97%) rename devtools/client/{styleinspector => shared}/test/unit/test_parseSingleValue.js (93%) rename devtools/client/{styleinspector => shared}/test/unit/test_rewriteDeclarations.js (99%) delete mode 100644 devtools/client/sourceeditor/css-tokenizer.js delete mode 100644 devtools/client/styleinspector/test/unit/.eslintrc delete mode 100644 devtools/client/styleinspector/test/unit/xpcshell.ini diff --git a/devtools/client/styleinspector/css-parsing-utils.js b/devtools/client/shared/css-parsing-utils.js similarity index 94% rename from devtools/client/styleinspector/css-parsing-utils.js rename to devtools/client/shared/css-parsing-utils.js index 465e264561f7..6b44a7c06b71 100644 --- a/devtools/client/styleinspector/css-parsing-utils.js +++ b/devtools/client/shared/css-parsing-utils.js @@ -14,7 +14,6 @@ "use strict"; -const {cssTokenizer} = require("devtools/client/sourceeditor/css-tokenizer"); const {Cc, Ci, Cu} = require("chrome"); Cu.importGlobalProperties(["CSS"]); const promise = require("promise"); @@ -43,6 +42,85 @@ const BLANK_LINE_RX = /^[ \t]*(?:\r\n|\n|\r|\f|$)/; // bypass the property name validity heuristic. const COMMENT_PARSING_HEURISTIC_BYPASS_CHAR = "!"; +/** + * A generator function that lexes a CSS source string, yielding the + * CSS tokens. Comment tokens are dropped. + * + * @param {String} CSS source string + * @yield {CSSToken} The next CSSToken that is lexed + * @see CSSToken for details about the returned tokens + */ +function* cssTokenizer(string) { + let lexer = DOMUtils.getCSSLexer(string); + while (true) { + let token = lexer.nextToken(); + if (!token) { + break; + } + // None of the existing consumers want comments. + if (token.tokenType !== "comment") { + yield token; + } + } +} + +/** + * Pass |string| to the CSS lexer and return an array of all the + * returned tokens. Comment tokens are not included. In addition to + * the usual information, each token will have starting and ending + * line and column information attached. Specifically, each token + * has an additional "loc" attribute. This attribute is an object + * of the form {line: L, column: C}. Lines and columns are both zero + * based. + * + * It's best not to add new uses of this function. In general it is + * simpler and better to use the CSSToken offsets, rather than line + * and column. Also, this function lexes the entire input string at + * once, rather than lazily yielding a token stream. Use + * |cssTokenizer| or |DOMUtils.getCSSLexer| instead. + * + * @param{String} string The input string. + * @return {Array} An array of tokens (@see CSSToken) that have + * line and column information. + */ +function cssTokenizerWithLineColumn(string) { + let lexer = DOMUtils.getCSSLexer(string); + let result = []; + let prevToken = undefined; + while (true) { + let token = lexer.nextToken(); + let lineNumber = lexer.lineNumber; + let columnNumber = lexer.columnNumber; + + if (prevToken) { + prevToken.loc.end = { + line: lineNumber, + column: columnNumber + }; + } + + if (!token) { + break; + } + + if (token.tokenType === "comment") { + // We've already dealt with the previous token's location. + prevToken = undefined; + } else { + let startLoc = { + line: lineNumber, + column: columnNumber + }; + token.loc = {start: startLoc}; + + result.push(token); + prevToken = token; + } + } + + return result; +} + /** * Escape a comment body. Find the comment start and end strings in a * string and inserts backslashes so that the resulting text can @@ -992,6 +1070,8 @@ function parseSingleValue(value) { }; } +exports.cssTokenizer = cssTokenizer; +exports.cssTokenizerWithLineColumn = cssTokenizerWithLineColumn; exports.escapeCSSComment = escapeCSSComment; // unescapeCSSComment is exported for testing. exports._unescapeCSSComment = unescapeCSSComment; diff --git a/devtools/client/shared/moz.build b/devtools/client/shared/moz.build index 52dbdb89a4e5..b86e0d019861 100644 --- a/devtools/client/shared/moz.build +++ b/devtools/client/shared/moz.build @@ -17,6 +17,7 @@ DevToolsModules( 'AppCacheUtils.jsm', 'autocomplete-popup.js', 'browser-loader.js', + 'css-parsing-utils.js', 'Curl.jsm', 'DeveloperToolbar.jsm', 'devices.js', diff --git a/devtools/client/styleinspector/test/unit/test_escapeCSSComment.js b/devtools/client/shared/test/unit/test_escapeCSSComment.js similarity index 92% rename from devtools/client/styleinspector/test/unit/test_escapeCSSComment.js rename to devtools/client/shared/test/unit/test_escapeCSSComment.js index fa23cfc46e29..4f7d415b2f52 100644 --- a/devtools/client/styleinspector/test/unit/test_escapeCSSComment.js +++ b/devtools/client/shared/test/unit/test_escapeCSSComment.js @@ -8,7 +8,7 @@ const Cu = Components.utils; Cu.import("resource://gre/modules/devtools/Loader.jsm"); const {escapeCSSComment, _unescapeCSSComment} = - devtools.require("devtools/client/styleinspector/css-parsing-utils"); + devtools.require("devtools/client/shared/css-parsing-utils"); const TEST_DATA = [ { diff --git a/devtools/client/styleinspector/test/unit/test_parseDeclarations.js b/devtools/client/shared/test/unit/test_parseDeclarations.js similarity index 98% rename from devtools/client/styleinspector/test/unit/test_parseDeclarations.js rename to devtools/client/shared/test/unit/test_parseDeclarations.js index 0512b008ed2f..c59aa56f493e 100644 --- a/devtools/client/styleinspector/test/unit/test_parseDeclarations.js +++ b/devtools/client/shared/test/unit/test_parseDeclarations.js @@ -6,9 +6,9 @@ "use strict"; const Cu = Components.utils; -const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); +const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); const {parseDeclarations, _parseCommentDeclarations} = - require("devtools/client/styleinspector/css-parsing-utils"); + require("devtools/client/shared/css-parsing-utils"); const TEST_DATA = [ // Simple test diff --git a/devtools/client/styleinspector/test/unit/test_parsePseudoClassesAndAttributes.js b/devtools/client/shared/test/unit/test_parsePseudoClassesAndAttributes.js similarity index 97% rename from devtools/client/styleinspector/test/unit/test_parsePseudoClassesAndAttributes.js rename to devtools/client/shared/test/unit/test_parsePseudoClassesAndAttributes.js index 882bd7b14f24..25af19af34d1 100644 --- a/devtools/client/styleinspector/test/unit/test_parsePseudoClassesAndAttributes.js +++ b/devtools/client/shared/test/unit/test_parsePseudoClassesAndAttributes.js @@ -6,13 +6,13 @@ "use strict"; const Cu = Components.utils; -const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); +const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); const { parsePseudoClassesAndAttributes, SELECTOR_ATTRIBUTE, SELECTOR_ELEMENT, SELECTOR_PSEUDO_CLASS -} = require("devtools/client/styleinspector/css-parsing-utils"); +} = require("devtools/client/shared/css-parsing-utils"); const TEST_DATA = [ // Test that a null input throws an exception diff --git a/devtools/client/styleinspector/test/unit/test_parseSingleValue.js b/devtools/client/shared/test/unit/test_parseSingleValue.js similarity index 93% rename from devtools/client/styleinspector/test/unit/test_parseSingleValue.js rename to devtools/client/shared/test/unit/test_parseSingleValue.js index 7f46f9d38a6e..9cb124d8eb45 100644 --- a/devtools/client/styleinspector/test/unit/test_parseSingleValue.js +++ b/devtools/client/shared/test/unit/test_parseSingleValue.js @@ -6,8 +6,8 @@ "use strict"; const Cu = Components.utils; -const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); -const {parseSingleValue} = require("devtools/client/styleinspector/css-parsing-utils"); +const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); +const {parseSingleValue} = require("devtools/client/shared/css-parsing-utils"); const TEST_DATA = [ {input: null, throws: true}, diff --git a/devtools/client/styleinspector/test/unit/test_rewriteDeclarations.js b/devtools/client/shared/test/unit/test_rewriteDeclarations.js similarity index 99% rename from devtools/client/styleinspector/test/unit/test_rewriteDeclarations.js rename to devtools/client/shared/test/unit/test_rewriteDeclarations.js index 55a62b7a9ad8..65b308244141 100644 --- a/devtools/client/styleinspector/test/unit/test_rewriteDeclarations.js +++ b/devtools/client/shared/test/unit/test_rewriteDeclarations.js @@ -8,7 +8,7 @@ const Cu = Components.utils; Cu.import("resource://gre/modules/devtools/Loader.jsm"); const {parseDeclarations, RuleRewriter} = - devtools.require("devtools/client/styleinspector/css-parsing-utils"); + devtools.require("devtools/client/shared/css-parsing-utils"); const TEST_DATA = [ { diff --git a/devtools/client/shared/test/unit/xpcshell.ini b/devtools/client/shared/test/unit/xpcshell.ini index 5701c0fff9e0..ed059ef8c6b9 100644 --- a/devtools/client/shared/test/unit/xpcshell.ini +++ b/devtools/client/shared/test/unit/xpcshell.ini @@ -10,6 +10,11 @@ skip-if = toolkit == 'android' || toolkit == 'gonk' [test_attribute-parsing-02.js] [test_bezierCanvas.js] [test_cubicBezier.js] +[test_escapeCSSComment.js] +[test_parseDeclarations.js] +[test_parsePseudoClassesAndAttributes.js] +[test_parseSingleValue.js] +[test_rewriteDeclarations.js] [test_undoStack.js] [test_VariablesView_filtering-without-controller.js] [test_VariablesView_getString_promise.js] diff --git a/devtools/client/shared/widgets/FilterWidget.js b/devtools/client/shared/widgets/FilterWidget.js index 725c549e9442..6a47c54fe805 100644 --- a/devtools/client/shared/widgets/FilterWidget.js +++ b/devtools/client/shared/widgets/FilterWidget.js @@ -14,7 +14,7 @@ const { Cu } = require("chrome"); const { ViewHelpers } = Cu.import("resource:///modules/devtools/client/shared/widgets/ViewHelpers.jsm", {}); const STRINGS_URI = "chrome://browser/locale/devtools/filterwidget.properties"; const L10N = new ViewHelpers.L10N(STRINGS_URI); -const {cssTokenizer} = require("devtools/client/sourceeditor/css-tokenizer"); +const {cssTokenizer} = require("devtools/client/shared/css-parsing-utils"); loader.lazyGetter(this, "asyncStorage", () => require("devtools/shared/shared/async-storage")); diff --git a/devtools/client/sourceeditor/css-autocompleter.js b/devtools/client/sourceeditor/css-autocompleter.js index afdcd79794a5..a67435261e2d 100644 --- a/devtools/client/sourceeditor/css-autocompleter.js +++ b/devtools/client/sourceeditor/css-autocompleter.js @@ -4,10 +4,10 @@ const { Cc, Ci, Cu } = require('chrome'); const {cssTokenizer, cssTokenizerWithLineColumn} = - require("devtools/client/sourceeditor/css-tokenizer"); + require("devtools/client/shared/css-parsing-utils"); /** - * Here is what this file (+ ./css-tokenizer.js) do. + * Here is what this file (+ css-parsing-utils.js) do. * * The main objective here is to provide as much suggestions to the user editing * a stylesheet in Style Editor. The possible things that can be suggested are: @@ -22,7 +22,7 @@ const {cssTokenizer, cssTokenizerWithLineColumn} = * edited by the user, figure out what token or word is being written and last * but the most difficult, what is being edited. * - * The file 'css-tokenizer' helps in converting the CSS into meaningful tokens, + * The file 'css-parsing-utils' helps to convert the CSS into meaningful tokens, * each having a certain type associated with it. These tokens help us to figure * out the currently edited word and to write a CSS state machine to figure out * what the user is currently editing. By that, I mean, whether he is editing a diff --git a/devtools/client/sourceeditor/css-tokenizer.js b/devtools/client/sourceeditor/css-tokenizer.js deleted file mode 100644 index 7bbfdcc71618..000000000000 --- a/devtools/client/sourceeditor/css-tokenizer.js +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* 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/. */ - -"use strict"; - -const {Cc, Ci} = require("chrome"); -loader.lazyGetter(this, "DOMUtils", () => { - return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils); -}); - -/** - * A generator function that lexes a CSS source string, yielding the - * CSS tokens. Comment tokens are dropped. - * - * @param {String} CSS source string - * @yield {CSSToken} The next CSSToken that is lexed - * @see CSSToken for details about the returned tokens - */ -function* cssTokenizer(string) { - let lexer = DOMUtils.getCSSLexer(string); - while (true) { - let token = lexer.nextToken(); - if (!token) { - break; - } - // None of the existing consumers want comments. - if (token.tokenType !== "comment") { - yield token; - } - } -} - -exports.cssTokenizer = cssTokenizer; - -/** - * Pass |string| to the CSS lexer and return an array of all the - * returned tokens. Comment tokens are not included. In addition to - * the usual information, each token will have starting and ending - * line and column information attached. Specifically, each token - * has an additional "loc" attribute. This attribute is an object - * of the form {line: L, column: C}. Lines and columns are both zero - * based. - * - * It's best not to add new uses of this function. In general it is - * simpler and better to use the CSSToken offsets, rather than line - * and column. Also, this function lexes the entire input string at - * once, rather than lazily yielding a token stream. Use - * |cssTokenizer| or |DOMUtils.getCSSLexer| instead. - * - * @param{String} string The input string. - * @return {Array} An array of tokens (@see CSSToken) that have - * line and column information. - */ -function cssTokenizerWithLineColumn(string) { - let lexer = DOMUtils.getCSSLexer(string); - let result = []; - let prevToken = undefined; - while (true) { - let token = lexer.nextToken(); - let lineNumber = lexer.lineNumber; - let columnNumber = lexer.columnNumber; - - if (prevToken) { - prevToken.loc.end = { - line: lineNumber, - column: columnNumber - }; - } - - if (!token) { - break; - } - - if (token.tokenType === "comment") { - // We've already dealt with the previous token's location. - prevToken = undefined; - } else { - let startLoc = { - line: lineNumber, - column: columnNumber - }; - token.loc = {start: startLoc}; - - result.push(token); - prevToken = token; - } - } - - return result; -} - -exports.cssTokenizerWithLineColumn = cssTokenizerWithLineColumn; diff --git a/devtools/client/sourceeditor/moz.build b/devtools/client/sourceeditor/moz.build index a149308f0964..a34b306e1000 100644 --- a/devtools/client/sourceeditor/moz.build +++ b/devtools/client/sourceeditor/moz.build @@ -7,7 +7,6 @@ DevToolsModules( 'autocomplete.js', 'css-autocompleter.js', - 'css-tokenizer.js', 'debugger.js', 'editor.js' ) diff --git a/devtools/client/styleinspector/moz.build b/devtools/client/styleinspector/moz.build index e9074489c2d9..8de420b5febe 100644 --- a/devtools/client/styleinspector/moz.build +++ b/devtools/client/styleinspector/moz.build @@ -5,11 +5,9 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. BROWSER_CHROME_MANIFESTS += ['test/browser.ini'] -XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini'] DevToolsModules( 'computed-view.js', - 'css-parsing-utils.js', 'rule-view.js', 'style-inspector-menu.js', 'style-inspector-overlays.js', diff --git a/devtools/client/styleinspector/rule-view.js b/devtools/client/styleinspector/rule-view.js index e64cb9ffcfce..14ed5aff2c4f 100644 --- a/devtools/client/styleinspector/rule-view.js +++ b/devtools/client/styleinspector/rule-view.js @@ -33,7 +33,7 @@ const { SELECTOR_ATTRIBUTE, SELECTOR_ELEMENT, SELECTOR_PSEUDO_CLASS -} = require("devtools/client/styleinspector/css-parsing-utils"); +} = require("devtools/client/shared/css-parsing-utils"); loader.lazyRequireGetter(this, "overlays", "devtools/client/styleinspector/style-inspector-overlays"); loader.lazyRequireGetter(this, "EventEmitter", diff --git a/devtools/client/styleinspector/test/unit/.eslintrc b/devtools/client/styleinspector/test/unit/.eslintrc deleted file mode 100644 index 3fe48b834e19..000000000000 --- a/devtools/client/styleinspector/test/unit/.eslintrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - // Extend from the common devtools xpcshell eslintrc config. - "extends": "../../../../.eslintrc.xpcshell" -} \ No newline at end of file diff --git a/devtools/client/styleinspector/test/unit/xpcshell.ini b/devtools/client/styleinspector/test/unit/xpcshell.ini deleted file mode 100644 index 0702a615b467..000000000000 --- a/devtools/client/styleinspector/test/unit/xpcshell.ini +++ /dev/null @@ -1,12 +0,0 @@ -[DEFAULT] -tags = devtools -head = -tail = -firefox-appdir = browser -skip-if = toolkit == 'android' || toolkit == 'gonk' - -[test_escapeCSSComment.js] -[test_parseDeclarations.js] -[test_parsePseudoClassesAndAttributes.js] -[test_parseSingleValue.js] -[test_rewriteDeclarations.js] diff --git a/devtools/client/styleinspector/utils.js b/devtools/client/styleinspector/utils.js index 1d12a3666344..815585455fd6 100644 --- a/devtools/client/styleinspector/utils.js +++ b/devtools/client/styleinspector/utils.js @@ -10,7 +10,7 @@ const {Cc, Ci, Cu} = require("chrome"); const {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {}); const {parseDeclarations} = - require("devtools/client/styleinspector/css-parsing-utils"); + require("devtools/client/shared/css-parsing-utils"); const promise = require("promise"); loader.lazyServiceGetter(this, "domUtils", diff --git a/devtools/server/actors/styles.js b/devtools/server/actors/styles.js index 2cd991a9b261..1d021653194e 100644 --- a/devtools/server/actors/styles.js +++ b/devtools/server/actors/styles.js @@ -26,7 +26,7 @@ loader.lazyGetter(this, "DOMUtils", () => { }); loader.lazyGetter(this, "RuleRewriter", () => { - return require("devtools/client/styleinspector/css-parsing-utils").RuleRewriter; + return require("devtools/client/shared/css-parsing-utils").RuleRewriter; }); // The PageStyle actor flattens the DOM CSS objects a little bit, merging From 7ea7355828d009d39f73ff5be37640eb22888233 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Thu, 8 Oct 2015 17:47:39 +1100 Subject: [PATCH 156/189] Bug 1187801 part 1 - Rewrite nsDocument::RestorePreviousFullScreenState() to unify logic of reverting element in parent document. r=smaug --HG-- extra : source : 05122469be2b1c792d19bf2fee7abb2a9cfa9d4d --- dom/base/nsDocument.cpp | 98 +++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index d48eb3894d04..a1e9451eebd5 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -14,6 +14,7 @@ #include "mozilla/AutoRestore.h" #include "mozilla/BinarySearch.h" #include "mozilla/DebugOnly.h" +#include "mozilla/IntegerRange.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Likely.h" #include @@ -11224,15 +11225,29 @@ nsDocument::RestorePreviousFullScreenState() return; } - // Check whether we are restoring to non-fullscreen state. - bool exitingFullscreen = true; - for (nsIDocument* doc = this; doc; doc = doc->GetParentDocument()) { - if (static_cast(doc)->mFullScreenStack.Length() > 1) { - exitingFullscreen = false; + nsCOMPtr fullScreenDoc = GetFullscreenLeaf(this); + nsAutoTArray exitDocs; + + nsIDocument* doc = fullScreenDoc; + // Collect all subdocuments. + for (; doc != this; doc = doc->GetParentDocument()) { + exitDocs.AppendElement(static_cast(doc)); + } + MOZ_ASSERT(doc == this, "Must have reached this doc"); + // Collect all ancestor documents which we are going to change. + for (; doc; doc = doc->GetParentDocument()) { + nsDocument* theDoc = static_cast(doc); + MOZ_ASSERT(!theDoc->mFullScreenStack.IsEmpty(), + "Ancestor of fullscreen document must also be in fullscreen"); + exitDocs.AppendElement(theDoc); + if (theDoc->mFullScreenStack.Length() > 1) { break; } } - if (exitingFullscreen) { + + nsDocument* lastDoc = exitDocs.LastElement(); + if (!lastDoc->GetParentDocument() && + lastDoc->mFullScreenStack.Length() == 1) { // If we are fully exiting fullscreen, don't touch anything here, // just wait for the window to get out from fullscreen first. AskWindowToExitFullscreen(this); @@ -11241,50 +11256,39 @@ nsDocument::RestorePreviousFullScreenState() // If fullscreen mode is updated the pointer should be unlocked UnlockPointer(); - - nsCOMPtr fullScreenDoc = GetFullscreenLeaf(this); - - // Clear full-screen stacks in all descendant in process documents, bottom up. - nsIDocument* doc = fullScreenDoc; - while (doc != this) { - NS_ASSERTION(doc->IsFullScreenDoc(), "Should be full-screen doc"); - static_cast(doc)->CleanupFullscreenState(); - DispatchFullScreenChange(doc); - doc = doc->GetParentDocument(); + // All documents listed in the array except the last one are going to + // completely exit from the fullscreen state. + for (auto i : MakeRange(exitDocs.Length() - 1)) { + exitDocs[i]->CleanupFullscreenState(); + } + // The last document will either rollback one fullscreen element, or + // completely exit from the fullscreen state as well. + nsIDocument* newFullscreenDoc; + if (lastDoc->mFullScreenStack.Length() > 1) { + lastDoc->FullScreenStackPop(); + newFullscreenDoc = lastDoc; + } else { + lastDoc->CleanupFullscreenState(); + newFullscreenDoc = lastDoc->GetParentDocument(); + } + // Dispatch the fullscreenchange event to all document listed. + for (nsDocument* d : exitDocs) { + DispatchFullScreenChange(d); } - // Roll-back full-screen state to previous full-screen element. - NS_ASSERTION(doc == this, "Must have reached this doc."); - while (doc != nullptr) { - static_cast(doc)->FullScreenStackPop(); - DispatchFullScreenChange(doc); - if (static_cast(doc)->mFullScreenStack.IsEmpty()) { - // Full-screen stack in document is empty. Go back up to the parent - // document. We'll pop the containing element off its stack, and use - // its next full-screen element as the full-screen element. - static_cast(doc)->CleanupFullscreenState(); - doc = doc->GetParentDocument(); - } else { - // Else we popped the top of the stack, and there's still another - // element in there, so that will become the full-screen element. - if (fullScreenDoc != doc) { - // We've popped so enough off the stack that we've rolled back to - // a fullscreen element in a parent document. If this document isn't - // approved for fullscreen, or if it's cross origin, dispatch an - // event to chrome so it knows to show the authorization/warning UI. - if (!nsContentUtils::HaveEqualPrincipals(fullScreenDoc, doc)) { - DispatchCustomEventWithFlush( - doc, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"), - /* Bubbles */ true, /* ChromeOnly */ true); - } - } - break; - } + MOZ_ASSERT(newFullscreenDoc, "If we were going to exit from fullscreen on " + "all documents in this doctree, we should've asked the window to " + "exit first instead of reaching here."); + if (fullScreenDoc != newFullscreenDoc && + !nsContentUtils::HaveEqualPrincipals(fullScreenDoc, newFullscreenDoc)) { + // We've popped so enough off the stack that we've rolled back to + // a fullscreen element in a parent document. If this document is + // cross origin, dispatch an event to chrome so it knows to show + // the warning UI. + DispatchCustomEventWithFlush( + newFullscreenDoc, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"), + /* Bubbles */ true, /* ChromeOnly */ true); } - - MOZ_ASSERT(doc, "If we were going to exit from fullscreen on all documents " - "in this doctree, we should've asked the window to exit first " - "instead of reaching here."); } bool From 2d891027c22a73f8fcd007298827d93555aa149f Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Thu, 8 Oct 2015 17:47:39 +1100 Subject: [PATCH 157/189] Bug 1187801 part 2 - Put clearing fullscreen state on element into an independent function. r=smaug --HG-- extra : source : d461799695d7fe5325066d4134d0a57eac407627 --- dom/base/nsDocument.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index a1e9451eebd5..be8d91967e7c 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -11354,6 +11354,15 @@ UpdateViewportScrollbarOverrideForFullscreen(nsIDocument* aDoc) } } +static void +ClearFullscreenStateOnElement(Element* aElement) +{ + // Remove any VR state properties + aElement->DeleteProperty(nsGkAtoms::vr_state); + // Remove styles from existing top element. + EventStateManager::SetFullScreenState(aElement, false); +} + void nsDocument::CleanupFullscreenState() { @@ -11366,9 +11375,7 @@ nsDocument::CleanupFullscreenState() // after bug 1195213. for (nsWeakPtr& weakPtr : Reversed(mFullScreenStack)) { if (nsCOMPtr element = do_QueryReferent(weakPtr)) { - // Remove any VR state properties - element->DeleteProperty(nsGkAtoms::vr_state); - EventStateManager::SetFullScreenState(element, false); + ClearFullscreenStateOnElement(element); } } mFullScreenStack.Clear(); @@ -11398,13 +11405,7 @@ nsDocument::FullScreenStackPop() return; } - Element* top = FullScreenStackTop(); - - // Remove any VR state properties - top->DeleteProperty(nsGkAtoms::vr_state); - - // Remove styles from existing top element. - EventStateManager::SetFullScreenState(top, false); + ClearFullscreenStateOnElement(FullScreenStackTop()); // Remove top element. Note the remaining top element in the stack // will not have full-screen style bits set, so we will need to restore From f6fe1e11ba395fbee8239252f8998579f4b61d52 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Thu, 8 Oct 2015 17:47:39 +1100 Subject: [PATCH 158/189] Bug 1187801 part 3 - Add iframe fullscreen flag and stop auto-rollback when this flag presents. r=smaug --HG-- extra : source : f7801f9c5b8e65862ead640f7b07ad87a40c9345 --- dom/base/nsDocument.cpp | 19 +++++++++++++++++++ dom/html/HTMLIFrameElement.h | 7 +++++++ dom/html/nsGenericHTMLFrameElement.h | 5 +++++ 3 files changed, 31 insertions(+) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index be8d91967e7c..428fea7a1ea3 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -155,6 +155,7 @@ #include "nsHtml5TreeOpExecutor.h" #include "mozilla/dom/HTMLLinkElement.h" #include "mozilla/dom/HTMLMediaElement.h" +#include "mozilla/dom/HTMLIFrameElement.h" #include "mozilla/dom/HTMLImageElement.h" #include "mozilla/dom/MediaSource.h" @@ -11239,6 +11240,16 @@ nsDocument::RestorePreviousFullScreenState() nsDocument* theDoc = static_cast(doc); MOZ_ASSERT(!theDoc->mFullScreenStack.IsEmpty(), "Ancestor of fullscreen document must also be in fullscreen"); + if (doc != this) { + Element* top = theDoc->FullScreenStackTop(); + if (top->IsHTMLElement(nsGkAtoms::iframe)) { + if (static_cast(top)->FullscreenFlag()) { + // If this is an iframe, and it explicitly requested + // fullscreen, don't rollback it automatically. + break; + } + } + } exitDocs.AppendElement(theDoc); if (theDoc->mFullScreenStack.Length() > 1) { break; @@ -11361,6 +11372,10 @@ ClearFullscreenStateOnElement(Element* aElement) aElement->DeleteProperty(nsGkAtoms::vr_state); // Remove styles from existing top element. EventStateManager::SetFullScreenState(aElement, false); + // Reset iframe fullscreen flag. + if (aElement->IsHTMLElement(nsGkAtoms::iframe)) { + static_cast(aElement)->SetFullscreenFlag(false); + } } void @@ -11853,6 +11868,10 @@ nsDocument::ApplyFullscreen(const FullscreenRequest& aRequest) // in this document. DebugOnly x = FullScreenStackPush(elem); NS_ASSERTION(x, "Full-screen state of requesting doc should always change!"); + // Set the iframe fullscreen flag. + if (elem->IsHTMLElement(nsGkAtoms::iframe)) { + static_cast(elem)->SetFullscreenFlag(true); + } changed.AppendElement(this); // Propagate up the document hierarchy, setting the full-screen element as diff --git a/dom/html/HTMLIFrameElement.h b/dom/html/HTMLIFrameElement.h index e96e7508d8e7..3c07bd8f2774 100644 --- a/dom/html/HTMLIFrameElement.h +++ b/dom/html/HTMLIFrameElement.h @@ -184,6 +184,13 @@ public: // nsGenericHTMLFrameElement::GetFrameLoader is fine // nsGenericHTMLFrameElement::GetAppManifestURL is fine + // The fullscreen flag is set to true only when requestFullscreen is + // explicitly called on this + + + diff --git a/dom/html/test/file_fullscreen-utils.js b/dom/html/test/file_fullscreen-utils.js index eed4b6eee71b..0f84566c9d06 100644 --- a/dom/html/test/file_fullscreen-utils.js +++ b/dom/html/test/file_fullscreen-utils.js @@ -37,8 +37,11 @@ function addFullscreenChangeContinuation(type, callback, inDoc) { } else if (type == "exit") { // If we just revert the state to a previous fullscreen state, // the window won't back to the normal mode. Hence we check - // mozFullScreenElement first here. - return doc.mozFullScreenElement || inNormalMode(); + // mozFullScreenElement first here. Note that we need to check + // the fullscreen element of the outmost document here instead + // of the current one. + var topDoc = doc.defaultView.top.document; + return topDoc.mozFullScreenElement || inNormalMode(); } else { throw "'type' must be either 'enter', or 'exit'."; } diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini index bdfbcd37ec33..d3284a623654 100644 --- a/dom/html/test/mochitest.ini +++ b/dom/html/test/mochitest.ini @@ -57,6 +57,7 @@ support-files = file_fullscreen-multiple-inner.html file_fullscreen-multiple.html file_fullscreen-navigation.html + file_fullscreen-nested.html file_fullscreen-plugins.html file_fullscreen-rollback.html file_fullscreen-scrollbar.html diff --git a/dom/html/test/test_fullscreen-api.html b/dom/html/test/test_fullscreen-api.html index 6a3e3df7de08..47fb034e3e1d 100644 --- a/dom/html/test/test_fullscreen-api.html +++ b/dom/html/test/test_fullscreen-api.html @@ -41,7 +41,8 @@ var gTestWindows = [ "file_fullscreen-navigation.html", "file_fullscreen-scrollbar.html", "file_fullscreen-selector.html", - "file_fullscreen-top-layer.html" + "file_fullscreen-top-layer.html", + "file_fullscreen-nested.html", ]; var testWindow = null; From a83ec922618ba46fe120a8542e823328e7780fed Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 19:49:06 -0700 Subject: [PATCH 160/189] Bug 1212183 - Fix DOM getter optimizations in the JITs. --- js/src/jit/BaselineIC.cpp | 18 ++++++++++++++---- js/src/jit/BaselineInspector.cpp | 12 +++++++++++- js/src/jit/IonBuilder.cpp | 2 +- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index cac90c6e9de9..23b9d13a7871 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -4801,7 +4801,8 @@ UpdateExistingGetPropCallStubs(ICFallbackStub* fallbackStub, HandleFunction getter) { MOZ_ASSERT(kind == ICStub::GetProp_CallScripted || - kind == ICStub::GetProp_CallNative); + kind == ICStub::GetProp_CallNative || + kind == ICStub::GetProp_CallNativeGlobal); MOZ_ASSERT(fallbackStub->isGetName_Fallback() || fallbackStub->isGetProp_Fallback()); MOZ_ASSERT(holder); @@ -4822,7 +4823,9 @@ UpdateExistingGetPropCallStubs(ICFallbackStub* fallbackStub, getPropStub->receiverGuard().update(receiverGuard); MOZ_ASSERT(getPropStub->holderShape() != holder->lastProperty() || - !getPropStub->receiverGuard().matches(receiverGuard), + !getPropStub->receiverGuard().matches(receiverGuard) || + getPropStub->toGetProp_CallNativeGlobal()->globalShape() != + receiver->as().global().lastProperty(), "Why didn't we end up using this stub?"); // We want to update the holder shape to match the new one no @@ -4833,6 +4836,13 @@ UpdateExistingGetPropCallStubs(ICFallbackStub* fallbackStub, // have changed which getter we want to use. getPropStub->getter() = getter; + if (getPropStub->isGetProp_CallNativeGlobal()) { + ICGetProp_CallNativeGlobal* globalStub = + getPropStub->toGetProp_CallNativeGlobal(); + globalStub->globalShape() = + receiver->as().global().lastProperty(); + } + if (getPropStub->receiverGuard().matches(receiverGuard)) foundMatchingStub = true; } @@ -5006,8 +5016,8 @@ TryAttachGlobalNameAccessorStub(JSContext* cx, HandleScript script, jsbytecode* RootedFunction getter(cx, &shape->getterObject()->as()); JitSpew(JitSpew_BaselineIC, " Generating GetName(GlobalName/NativeGetter) stub"); - if (UpdateExistingGetPropCallStubs(stub, ICStub::GetProp_CallNative, current, global, - getter)) + if (UpdateExistingGetPropCallStubs(stub, ICStub::GetProp_CallNativeGlobal, current, + globalLexical, getter)) { *attached = true; return true; diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index 965db229869e..148a4757f816 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -594,7 +594,16 @@ GlobalShapeForGetPropFunction(ICStub* stub) if (shape->getObjectClass()->flags & JSCLASS_IS_GLOBAL) return shape; } + } else if (stub->isGetProp_CallNativeGlobal()) { + ICGetProp_CallNativeGlobal* nstub = stub->toGetProp_CallNativeGlobal(); + if (nstub->isOwnGetter()) + return nullptr; + + Shape* shape = nstub->globalShape(); + MOZ_ASSERT(shape->getObjectClass()->flags & JSCLASS_IS_GLOBAL); + return shape; } + return nullptr; } @@ -616,7 +625,8 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { if (stub->isGetProp_CallScripted() || - stub->isGetProp_CallNative()) + stub->isGetProp_CallNative() || + stub->isGetProp_CallNativeGlobal()) { ICGetPropCallGetter* nstub = static_cast(stub); bool isOwn = nstub->isOwnGetter(); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index a57fbd5cc119..c18487d90311 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -8199,7 +8199,7 @@ IonBuilder::jsop_getgname(PropertyName* name) if (!getStaticName(obj, name, &emitted) || emitted) return emitted; - if (!forceInlineCaches()) { + if (!forceInlineCaches() && obj->is()) { TemporaryTypeSet* types = bytecodeTypes(pc); MDefinition* globalObj = constant(ObjectValue(*obj)); if (!getPropTryCommonGetter(&emitted, globalObj, name, types) || emitted) From 4bff58884687aa7bd01d781c2d38b8667f8e96ae Mon Sep 17 00:00:00 2001 From: Allison Naaktgeboren Date: Wed, 7 Oct 2015 09:49:19 -0700 Subject: [PATCH 161/189] =?UTF-8?q?Bug=201201325=20-=20remove=20nightly=20?= =?UTF-8?q?only=20flag=20from=20savedsearch=20feature.r=3D=3F?= --- mobile/android/base/home/BrowserSearch.java | 12 ++++------ mobile/android/base/home/SearchEngineRow.java | 23 ++++--------------- .../base/preferences/GeckoPreferences.java | 7 ------ 3 files changed, 8 insertions(+), 34 deletions(-) diff --git a/mobile/android/base/home/BrowserSearch.java b/mobile/android/base/home/BrowserSearch.java index dddb1a7df615..425307f9c3e3 100644 --- a/mobile/android/base/home/BrowserSearch.java +++ b/mobile/android/base/home/BrowserSearch.java @@ -14,7 +14,6 @@ import java.util.Locale; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.annotation.RobocopTarget; import org.mozilla.gecko.EventDispatcher; import org.mozilla.gecko.GeckoAppShell; @@ -535,14 +534,11 @@ public class BrowserSearch extends HomeFragment } getLoaderManager().restartLoader(LOADER_ID_SUGGESTION, null, mSearchEngineSuggestionLoaderCallbacks); - // Start search history suggestions query only in nightly. Bug 1201325 - if (AppConstants.NIGHTLY_BUILD) { - // Saved suggestions - if (mSearchHistorySuggestionLoaderCallback == null) { - mSearchHistorySuggestionLoaderCallback = new SearchHistorySuggestionLoaderCallbacks(); - } - getLoaderManager().restartLoader(LOADER_ID_SAVED_SUGGESTION, null, mSearchHistorySuggestionLoaderCallback); + // Saved suggestions + if (mSearchHistorySuggestionLoaderCallback == null) { + mSearchHistorySuggestionLoaderCallback = new SearchHistorySuggestionLoaderCallbacks(); } + getLoaderManager().restartLoader(LOADER_ID_SAVED_SUGGESTION, null, mSearchHistorySuggestionLoaderCallback); } private void setSuggestions(ArrayList suggestions) { diff --git a/mobile/android/base/home/SearchEngineRow.java b/mobile/android/base/home/SearchEngineRow.java index 69c160722f11..be99b6eac38e 100644 --- a/mobile/android/base/home/SearchEngineRow.java +++ b/mobile/android/base/home/SearchEngineRow.java @@ -5,7 +5,6 @@ package org.mozilla.gecko.home; -import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.GeckoSharedPrefs; import org.mozilla.gecko.R; import org.mozilla.gecko.Telemetry; @@ -75,9 +74,6 @@ class SearchEngineRow extends AnimatedHeightLayout { private int mMaxSavedSuggestions; private int mMaxSearchSuggestions; - // Remove this default limit value in Bug 1201325 - private static final int SUGGESTIONS_MAX = 4; - public SearchEngineRow(Context context) { this(context, null); } @@ -269,14 +265,10 @@ class SearchEngineRow extends AnimatedHeightLayout { * @return the global count of how many suggestions have been bound/shown in the search engine row */ private int updateFromSearchEngine(boolean animate, int recycledSuggestionCount, int savedSuggestionCount) { - // Remove this default limit value in Bug 1201325 - int maxSuggestions = SUGGESTIONS_MAX; - if (AppConstants.NIGHTLY_BUILD) { - maxSuggestions = mMaxSearchSuggestions; - // If there are less than max saved searches on phones, fill the space with more search engine suggestions - if (!HardwareUtils.isTablet() && savedSuggestionCount < mMaxSavedSuggestions) { - maxSuggestions += mMaxSavedSuggestions - savedSuggestionCount; - } + int maxSuggestions = mMaxSearchSuggestions; + // If there are less than max saved searches on phones, fill the space with more search engine suggestions + if (!HardwareUtils.isTablet() && savedSuggestionCount < mMaxSavedSuggestions) { + maxSuggestions += mMaxSavedSuggestions - savedSuggestionCount; } int suggestionCounter = 0; @@ -320,13 +312,6 @@ class SearchEngineRow extends AnimatedHeightLayout { // Set the initial content description. setDescriptionOnSuggestion(mUserEnteredTextView, mUserEnteredTextView.getText().toString()); - if (!AppConstants.NIGHTLY_BUILD) { - if (searchSuggestionsEnabled) { - updateFromSearchEngine(animate, mSuggestionView.getChildCount(), 0); - } - return; - } - final int recycledSuggestionCount = mSuggestionView.getChildCount(); final SharedPreferences prefs = GeckoSharedPrefs.forApp(getContext()); final boolean savedSearchesEnabled = prefs.getBoolean(GeckoPreferences.PREFS_HISTORY_SAVED_SEARCH, true); diff --git a/mobile/android/base/preferences/GeckoPreferences.java b/mobile/android/base/preferences/GeckoPreferences.java index 68ee9db2fb2c..642f821e07a1 100644 --- a/mobile/android/base/preferences/GeckoPreferences.java +++ b/mobile/android/base/preferences/GeckoPreferences.java @@ -767,13 +767,6 @@ OnSharedPreferenceChangeListener i--; continue; } - } else if (PREFS_HISTORY_SAVED_SEARCH.equals(key)) { - // Remove settings UI if not on Nightly - if (!AppConstants.NIGHTLY_BUILD) { - preferences.removePreference(pref); - i--; - continue; - } } else if (PREFS_TRACKING_PROTECTION.equals(key)) { // Remove UI for global TP pref in non-Nightly builds. if (!AppConstants.NIGHTLY_BUILD) { From 219eacc1d3d520addf627801493c45d581e399ee Mon Sep 17 00:00:00 2001 From: Mark Banner Date: Wed, 7 Oct 2015 19:20:03 +0100 Subject: [PATCH 162/189] Bug 1212272 - 'make dist' for the Loop standalone doesn't update the css and supplementary files properly. r=dmose. NPOTB DONTBUILD --- browser/components/loop/standalone/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/browser/components/loop/standalone/Makefile b/browser/components/loop/standalone/Makefile index 26c3a580f392..c31553b15003 100644 --- a/browser/components/loop/standalone/Makefile +++ b/browser/components/loop/standalone/Makefile @@ -25,7 +25,8 @@ npm_install: # assets .PHONY: dist dist: - cp -pr content dist + mkdir -p dist + cp -pR content dist NODE_ENV="production" $(NODE_LOCAL_BIN)/webpack \ -p -v --display-errors sed 's#webappEntryPoint.js#js/standalone.js#' \ From 310ba9b7a312553d75cf15f25e16c1876d0b6987 Mon Sep 17 00:00:00 2001 From: David Critchley Date: Wed, 7 Oct 2015 19:48:28 +0100 Subject: [PATCH 163/189] Bug 1209632 - Removing footer from Loop Standalone, moved Logo to mediaLayoutView. r=Standard8,ui-review=Sevaan --- .../loop/content/shared/css/conversation.css | 24 +++---- .../loop/standalone/content/css/webapp.css | 67 +++---------------- .../content/js/standaloneRoomViews.js | 33 +++++---- .../content/js/standaloneRoomViews.jsx | 29 ++++---- 4 files changed, 50 insertions(+), 103 deletions(-) diff --git a/browser/components/loop/content/shared/css/conversation.css b/browser/components/loop/content/shared/css/conversation.css index 2d1f96b7f445..93e70ac7868c 100644 --- a/browser/components/loop/content/shared/css/conversation.css +++ b/browser/components/loop/content/shared/css/conversation.css @@ -15,10 +15,10 @@ button::-moz-focus-inner { z-index: 1020; /* required to have it superimposed to the video element */ border: 0; left: 1.2rem; - right: .7rem; - height: 2.6rem; + right: 1.2rem; + height: 2.4rem; position: absolute; - bottom: 1.5rem; + bottom: 1.2rem; } html[dir="rtl"] .conversation-toolbar { @@ -48,11 +48,11 @@ html[dir="rtl"] .conversation-toolbar > li { .conversation-toolbar .btn { background-position: center; - background-size: 28px; + background-size: 24px; background-repeat: no-repeat; background-color: transparent; - height: 28px; - width: 33px; + height: 24px; + width: 24px; } .conversation-toolbar-media-btn-group-box { @@ -855,8 +855,8 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item { } .standalone-room-wrapper > .media-layout { - /* 50px is the header, 3em is the footer. */ - height: calc(100% - 50px - 3em); + /* 50px is the header, 10px is the bottom margin. */ + height: calc(100% - 50px - 10px); margin: 0 10px; } @@ -977,8 +977,8 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item { @media screen and (max-width:640px) { .standalone-room-wrapper > .media-layout { - /* 50px is height of header, 25px is height of footer. */ - height: calc(100% - 50px - 25px); + /* 50px is height of header, 10px is bottom margin. */ + height: calc(100% - 50px - 10px); } .media-layout > .media-wrapper { @@ -1427,8 +1427,8 @@ html[dir="rtl"] .text-chat-entry.received .text-chat-arrow { left: 0; } .standalone .room-conversation-wrapper .video-layout-wrapper { - /* 50px: header's height; 25px: footer's height */ - height: calc(100% - 50px - 25px); + /* 50px: header's height; 10px: bottom margin */ + height: calc(100% - 50px - 10px); } .standalone .room-conversation .video_wrapper.remote_wrapper { width: 100%; diff --git a/browser/components/loop/standalone/content/css/webapp.css b/browser/components/loop/standalone/content/css/webapp.css index cd8869c4507b..fdbd2e64507a 100644 --- a/browser/components/loop/standalone/content/css/webapp.css +++ b/browser/components/loop/standalone/content/css/webapp.css @@ -57,74 +57,27 @@ body, z-index: 1000; } -/* Footer */ +/* Mozilla Logo */ -.footer-logo { - width: 100px; - margin: 0 auto; - height: 30px; +.focus-stream > .standalone-moz-logo { + width: 50px; + height: 13px; background-size: contain; background-image: url("../img/mozilla-logo.svg#logo-white"); background-repeat: no-repeat; -} - -.rooms-footer { - background: #000; - margin: 0 10px; - text-align: left; - height: 3em; - position: relative; -} - -html[dir="rtl"] .rooms-footer { - text-align: right; -} - -.rooms-footer p { - /* Right-margin offset to account for .footer-logo plus 20px. */ - /* Zero other margins due to 1em margin from reset.css. */ - margin: 0 120px 0 0; - /* Vertically align in the middle. */ position: absolute; - top: 50%; - transform: translate(0, -50%); + bottom: 1.2rem; + right: 1.2rem; + left: auto; } -html[dir="rtl"] .rooms-footer p { - margin: 0 0 0 120px; -} - -.rooms-footer a { - color: #555; -} - -.rooms-footer .footer-logo { - /* Vertically-align in the middle. */ - position: absolute; - top: 50%; - transform: translate(0, -50%); - /* Align to the right. */ - right: 0; -} - -html[dir="rtl"] .rooms-footer .footer-logo { - left: 0; +html[dir="rtl"] .focus-stream > .standalone-moz-logo { + left: 1.2rem; right: auto; } @media screen and (max-width:640px) { - .rooms-footer { - font-size: 80%; - height: 25px; - text-align: center; - } - - .rooms-footer p { - margin: 0; - width: 100%; - } - - .rooms-footer .footer-logo { + .focus-stream > .standalone-moz-logo { display: none; } } diff --git a/browser/components/loop/standalone/content/js/standaloneRoomViews.js b/browser/components/loop/standalone/content/js/standaloneRoomViews.js index 4312a107296b..2b88c5086b26 100644 --- a/browser/components/loop/standalone/content/js/standaloneRoomViews.js +++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.js @@ -416,20 +416,6 @@ loop.standaloneRoomViews = (function(mozL10n) { } }); - var StandaloneRoomFooter = React.createClass({displayName: "StandaloneRoomFooter", - propTypes: { - dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired - }, - - render: function() { - return ( - React.createElement("footer", {className: "rooms-footer"}, - React.createElement("div", {className: "footer-logo"}) - ) - ); - } - }); - var StandaloneRoomView = React.createClass({displayName: "StandaloneRoomView", mixins: [ Backbone.Events, @@ -678,14 +664,26 @@ loop.standaloneRoomViews = (function(mozL10n) { publishStream: this.publishStream, show: true, video: {enabled: !this.state.videoMuted, - visible: this._roomIsActive()}}) - ), - React.createElement(StandaloneRoomFooter, {dispatcher: this.props.dispatcher}) + visible: this._roomIsActive()}}), + React.createElement(StandaloneMozLogo, {dispatcher: this.props.dispatcher}) + ) ) ); } }); + var StandaloneMozLogo = React.createClass({displayName: "StandaloneMozLogo", + propTypes: { + dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired + }, + + render: function() { + return ( + React.createElement("div", {className: "standalone-moz-logo"}) + ); + } + }); + var StandaloneRoomControllerView = React.createClass({displayName: "StandaloneRoomControllerView", mixins: [ loop.store.StoreMixin("activeRoomStore") @@ -726,7 +724,6 @@ loop.standaloneRoomViews = (function(mozL10n) { StandaloneHandleUserAgentView: StandaloneHandleUserAgentView, StandaloneRoomControllerView: StandaloneRoomControllerView, StandaloneRoomFailureView: StandaloneRoomFailureView, - StandaloneRoomFooter: StandaloneRoomFooter, StandaloneRoomHeader: StandaloneRoomHeader, StandaloneRoomInfoArea: StandaloneRoomInfoArea, StandaloneRoomView: StandaloneRoomView, diff --git a/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx b/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx index eaf28c262072..be308bb7caff 100644 --- a/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx +++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx @@ -416,20 +416,6 @@ loop.standaloneRoomViews = (function(mozL10n) { } }); - var StandaloneRoomFooter = React.createClass({ - propTypes: { - dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired - }, - - render: function() { - return ( -
-
-
- ); - } - }); - var StandaloneRoomView = React.createClass({ mixins: [ Backbone.Events, @@ -679,13 +665,25 @@ loop.standaloneRoomViews = (function(mozL10n) { show={true} video={{enabled: !this.state.videoMuted, visible: this._roomIsActive()}} /> + - ); } }); + var StandaloneMozLogo = React.createClass({ + propTypes: { + dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired + }, + + render: function() { + return ( +
+ ); + } + }); + var StandaloneRoomControllerView = React.createClass({ mixins: [ loop.store.StoreMixin("activeRoomStore") @@ -726,7 +724,6 @@ loop.standaloneRoomViews = (function(mozL10n) { StandaloneHandleUserAgentView: StandaloneHandleUserAgentView, StandaloneRoomControllerView: StandaloneRoomControllerView, StandaloneRoomFailureView: StandaloneRoomFailureView, - StandaloneRoomFooter: StandaloneRoomFooter, StandaloneRoomHeader: StandaloneRoomHeader, StandaloneRoomInfoArea: StandaloneRoomInfoArea, StandaloneRoomView: StandaloneRoomView, From 0f65d41183d6dcc5ad503059d24ac2390ec03074 Mon Sep 17 00:00:00 2001 From: Paolo Amadini Date: Wed, 7 Oct 2015 19:51:33 +0100 Subject: [PATCH 164/189] Bug 1193341 - Detect presence of password fields in any subframe, flagging those on insecure connections. r=MattN --HG-- extra : commitid : H8aypcuVLFX extra : rebase_source : 73354a24877a4d7dcc6649f3200f9c803a6357fe --- .../passwordmgr/InsecurePasswordUtils.jsm | 6 +- .../passwordmgr/LoginManagerContent.jsm | 23 ++++- .../passwordmgr/LoginManagerParent.jsm | 20 +++- .../passwordmgr/test/browser/browser.ini | 3 + .../browser/browser_hasInsecureLoginForms.js | 93 +++++++++++++++++++ .../test/browser/insecure_test.html | 9 ++ .../test/browser/insecure_test_subframe.html | 13 +++ 7 files changed, 158 insertions(+), 9 deletions(-) create mode 100644 toolkit/components/passwordmgr/test/browser/browser_hasInsecureLoginForms.js create mode 100644 toolkit/components/passwordmgr/test/browser/insecure_test.html create mode 100644 toolkit/components/passwordmgr/test/browser/insecure_test_subframe.html diff --git a/toolkit/components/passwordmgr/InsecurePasswordUtils.jsm b/toolkit/components/passwordmgr/InsecurePasswordUtils.jsm index 6d9d10888d21..6fd4150ead07 100644 --- a/toolkit/components/passwordmgr/InsecurePasswordUtils.jsm +++ b/toolkit/components/passwordmgr/InsecurePasswordUtils.jsm @@ -75,7 +75,7 @@ this.InsecurePasswordUtils = { * both places. Look at * https://bugzilla.mozilla.org/show_bug.cgi?id=899099 for more info. */ - _checkIfURIisSecure : function(uri) { + checkIfURIisSecure : function(uri) { let isSafe = false; let netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil); let ph = Ci.nsIProtocolHandler; @@ -109,7 +109,7 @@ this.InsecurePasswordUtils = { // We are at the top, nothing to check here return false; } - if (!this._checkIfURIisSecure(uri)) { + if (!this.checkIfURIisSecure(uri)) { // We are insecure return true; } @@ -127,7 +127,7 @@ this.InsecurePasswordUtils = { checkForInsecurePasswords : function (aForm) { var domDoc = aForm.ownerDocument; let pageURI = domDoc.defaultView.top.document.documentURIObject; - let isSafePage = this._checkIfURIisSecure(pageURI); + let isSafePage = this.checkIfURIisSecure(pageURI); if (!isSafePage) { this._sendWebConsoleMessage("InsecurePasswordsPresentOnPage", domDoc); diff --git a/toolkit/components/passwordmgr/LoginManagerContent.jsm b/toolkit/components/passwordmgr/LoginManagerContent.jsm index d30354b3b6c0..52102a23b999 100644 --- a/toolkit/components/passwordmgr/LoginManagerContent.jsm +++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm @@ -15,12 +15,14 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", "resource://gre/modules/DeferredTask.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "LoginRecipesContent", - "resource://gre/modules/LoginRecipes.jsm"); - +XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", + "resource://gre/modules/DeferredTask.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "InsecurePasswordUtils", + "resource://gre/modules/InsecurePasswordUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper", "resource://gre/modules/LoginHelper.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "LoginRecipesContent", + "resource://gre/modules/LoginRecipes.jsm"); XPCOMUtils.defineLazyGetter(this, "log", () => { let logger = LoginHelper.createLogger("LoginManagerContent"); @@ -414,6 +416,18 @@ var LoginManagerContent = { return null; }; + // Returns true if this window or any subframes have insecure login forms. + let hasInsecureLoginForms = (thisWindow, parentIsInsecure) => { + let doc = thisWindow.document; + let isInsecure = + parentIsInsecure || + !InsecurePasswordUtils.checkIfURIisSecure(doc.documentURIObject); + let hasLoginForm = !!this.stateForDocument(doc).loginForm; + return (hasLoginForm && isInsecure) || + Array.some(thisWindow.frames, + frame => hasInsecureLoginForms(frame, isInsecure)); + }; + // Store the actual form to use on the state for the top-level document. let topState = this.stateForDocument(topWindow.document); topState.loginFormForFill = getFirstLoginForm(topWindow); @@ -423,6 +437,7 @@ var LoginManagerContent = { messageManager.sendAsyncMessage("RemoteLogins:updateLoginFormPresence", { loginFormOrigin, loginFormPresent: !!topState.loginFormForFill, + hasInsecureLoginForms: hasInsecureLoginForms(topWindow, false), }); }, diff --git a/toolkit/components/passwordmgr/LoginManagerParent.jsm b/toolkit/components/passwordmgr/LoginManagerParent.jsm index 6b559a7ba89a..c17f3b61981b 100644 --- a/toolkit/components/passwordmgr/LoginManagerParent.jsm +++ b/toolkit/components/passwordmgr/LoginManagerParent.jsm @@ -569,12 +569,23 @@ var LoginManagerParent = { return loginFormState; }, + /** + * Returns true if the page currently loaded in the given browser element has + * insecure login forms. This state may be updated asynchronously, in which + * case a custom event named InsecureLoginFormsStateChange will be dispatched + * on the browser element. + */ + hasInsecureLoginForms(browser) { + return !!this.stateForBrowser(browser).hasInsecureLoginForms; + }, + /** * Called to indicate whether a login form on the currently loaded page is * present or not. This is one of the factors used to control the visibility * of the password fill doorhanger. */ - updateLoginFormPresence(browser, { loginFormOrigin, loginFormPresent }) { + updateLoginFormPresence(browser, { loginFormOrigin, loginFormPresent, + hasInsecureLoginForms }) { const ANCHOR_DELAY_MS = 200; let state = this.stateForBrowser(browser); @@ -583,8 +594,13 @@ var LoginManagerParent = { // processed in order, this will always be the latest version to use. state.loginFormOrigin = loginFormOrigin; state.loginFormPresent = loginFormPresent; + state.hasInsecureLoginForms = hasInsecureLoginForms; - // Apply the data to the currently displayed icon later. + // Report the insecure login form state immediately. + browser.dispatchEvent(new browser.ownerDocument.defaultView + .CustomEvent("InsecureLoginFormsStateChange")); + + // Apply the data to the currently displayed login fill icon later. if (!state.anchorDeferredTask) { state.anchorDeferredTask = new DeferredTask( () => this.updateLoginAnchor(browser), diff --git a/toolkit/components/passwordmgr/test/browser/browser.ini b/toolkit/components/passwordmgr/test/browser/browser.ini index 03af4d55cc5a..8f459ba04bdd 100644 --- a/toolkit/components/passwordmgr/test/browser/browser.ini +++ b/toolkit/components/passwordmgr/test/browser/browser.ini @@ -2,11 +2,14 @@ support-files = authenticate.sjs form_basic.html + insecure_test.html + insecure_test_subframe.html multiple_forms.html [browser_DOMFormHasPassword.js] [browser_DOMInputPasswordAdded.js] [browser_filldoorhanger.js] +[browser_hasInsecureLoginForms.js] [browser_notifications.js] skip-if = true # Intermittent failures: Bug 1182296, bug 1148771 [browser_passwordmgr_editing.js] diff --git a/toolkit/components/passwordmgr/test/browser/browser_hasInsecureLoginForms.js b/toolkit/components/passwordmgr/test/browser/browser_hasInsecureLoginForms.js new file mode 100644 index 000000000000..039312b7d1f2 --- /dev/null +++ b/toolkit/components/passwordmgr/test/browser/browser_hasInsecureLoginForms.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +Cu.import("resource://gre/modules/LoginManagerParent.jsm", this); + +const testUrlPath = + "://example.com/browser/toolkit/components/passwordmgr/test/browser/"; + +/** + * Waits for the given number of occurrences of InsecureLoginFormsStateChange + * on the given browser element. + */ +function waitForInsecureLoginFormsStateChange(browser, count) { + return BrowserTestUtils.waitForEvent(browser, "InsecureLoginFormsStateChange", + false, () => --count == 0); +} + +/** + * Checks that hasInsecureLoginForms is true for a simple HTTP page and false + * for a simple HTTPS page. + */ +add_task(function* test_simple() { + for (let scheme of ["http", "https"]) { + let tab = gBrowser.addTab(scheme + testUrlPath + "form_basic.html"); + let browser = tab.linkedBrowser; + yield Promise.all([ + BrowserTestUtils.switchTab(gBrowser, tab), + BrowserTestUtils.browserLoaded(browser), + // One event is triggered by pageshow and one by DOMFormHasPassword. + waitForInsecureLoginFormsStateChange(browser, 2), + ]); + + Assert.equal(LoginManagerParent.hasInsecureLoginForms(browser), + scheme == "http"); + + gBrowser.removeTab(tab); + } +}); + +/** + * Checks that hasInsecureLoginForms is true if a password field is present in + * an HTTP page loaded as a subframe of a top-level HTTPS page, when mixed + * active content blocking is disabled. + * + * When the subframe is navigated to an HTTPS page, hasInsecureLoginForms should + * be set to false. + * + * Moving back in history should set hasInsecureLoginForms to true again. + */ +add_task(function* test_subframe_navigation() { + yield new Promise(resolve => SpecialPowers.pushPrefEnv({ + "set": [["security.mixed_content.block_active_content", false]], + }, resolve)); + + // Load the page with the subframe in a new tab. + let tab = gBrowser.addTab("https" + testUrlPath + "insecure_test.html"); + let browser = tab.linkedBrowser; + yield Promise.all([ + BrowserTestUtils.switchTab(gBrowser, tab), + BrowserTestUtils.browserLoaded(browser), + // Two events are triggered by pageshow and one by DOMFormHasPassword. + waitForInsecureLoginFormsStateChange(browser, 3), + ]); + + Assert.ok(LoginManagerParent.hasInsecureLoginForms(browser)); + + // Navigate the subframe to a secure page. + let promiseSubframeReady = Promise.all([ + BrowserTestUtils.browserLoaded(browser, true), + // One event is triggered by pageshow and one by DOMFormHasPassword. + waitForInsecureLoginFormsStateChange(browser, 2), + ]); + yield ContentTask.spawn(browser, null, function* () { + content.document.getElementById("test-iframe") + .contentDocument.getElementById("test-link").click(); + }); + yield promiseSubframeReady; + + Assert.ok(!LoginManagerParent.hasInsecureLoginForms(browser)); + + // Navigate back to the insecure page. We only have to wait for the + // InsecureLoginFormsStateChange event that is triggered by pageshow. + let promise = waitForInsecureLoginFormsStateChange(browser, 1); + yield ContentTask.spawn(browser, null, function* () { + content.document.getElementById("test-iframe") + .contentWindow.history.back(); + }); + yield promise; + + Assert.ok(LoginManagerParent.hasInsecureLoginForms(browser)); + + gBrowser.removeTab(tab); +}); diff --git a/toolkit/components/passwordmgr/test/browser/insecure_test.html b/toolkit/components/passwordmgr/test/browser/insecure_test.html new file mode 100644 index 000000000000..fedea1428e5c --- /dev/null +++ b/toolkit/components/passwordmgr/test/browser/insecure_test.html @@ -0,0 +1,9 @@ + + + + +