From 9904bad8e006dd71204a973f0d91d0737ec917a5 Mon Sep 17 00:00:00 2001 From: Daosheng Mu Date: Tue, 2 Apr 2019 05:13:15 +0000 Subject: [PATCH 01/46] Bug 1520339 - Part 1: adding ensure VR process ready mechanism. r=kip Differential Revision: https://phabricator.services.mozilla.com/D25320 --HG-- extra : moz-landing-system : lando --- gfx/thebes/gfxPrefs.h | 1 + gfx/vr/ipc/PVR.ipdl | 3 +++ gfx/vr/ipc/VRChild.h | 3 +++ gfx/vr/ipc/VRParent.cpp | 3 +++ gfx/vr/ipc/VRProcessManager.cpp | 31 +++++++++++++++++++++++- gfx/vr/ipc/VRProcessManager.h | 7 ++++++ gfx/vr/ipc/VRProcessParent.cpp | 43 +++++++++++++++++++++++++++++++-- gfx/vr/ipc/VRProcessParent.h | 10 ++++++++ 8 files changed, 98 insertions(+), 3 deletions(-) diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index a7ce1aaef99a..b0ab53ae669d 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -403,6 +403,7 @@ class gfxPrefs final { DECL_GFX_PREF(Live, "dom.vr.puppet.submitframe", VRPuppetSubmitFrame, uint32_t, 0); DECL_GFX_PREF(Live, "dom.vr.display.rafMaxDuration", VRDisplayRafMaxDuration, uint32_t, 50); DECL_GFX_PREF(Once, "dom.vr.process.enabled", VRProcessEnabled, bool, false); + DECL_GFX_PREF(Once, "dom.vr.process.startup_timeout_ms", VRProcessTimeoutMs, int32_t, 5000); DECL_GFX_PREF(Once, "dom.vr.service.enabled", VRServiceEnabled, bool, true); DECL_GFX_PREF(Live, "dom.w3c_pointer_events.enabled", PointerEventsEnabled, bool, false); diff --git a/gfx/vr/ipc/PVR.ipdl b/gfx/vr/ipc/PVR.ipdl index 0628918a1178..52ccfdb61bca 100644 --- a/gfx/vr/ipc/PVR.ipdl +++ b/gfx/vr/ipc/PVR.ipdl @@ -29,6 +29,9 @@ parent: async OpenVRControllerManifestPathToVR(OpenVRControllerType aType, nsCString aPath); child: + // Sent when the GPU process has initialized devices. This occurs once, after + // Init(). + async InitComplete(); async OpenVRControllerActionPathToParent(nsCString aPath); async OpenVRControllerManifestPathToParent(OpenVRControllerType aType, nsCString aPath); async InitCrashReporter(Shmem shmem, NativeThreadId threadId); diff --git a/gfx/vr/ipc/VRChild.h b/gfx/vr/ipc/VRChild.h index 9b2c2c77f3ec..7e7e2a5ff8e1 100644 --- a/gfx/vr/ipc/VRChild.h +++ b/gfx/vr/ipc/VRChild.h @@ -30,6 +30,7 @@ class VRChild final : public PVRChild, public gfxVarReceiver { static void Destroy(UniquePtr&& aChild); void Init(); + bool EnsureVRReady(); virtual void OnVarChanged(const GfxVarUpdate& aVar) override; protected: @@ -38,12 +39,14 @@ class VRChild final : public PVRChild, public gfxVarReceiver { const nsCString& aPath); mozilla::ipc::IPCResult RecvOpenVRControllerManifestPathToParent( const OpenVRControllerType& aType, const nsCString& aPath); + mozilla::ipc::IPCResult RecvInitComplete(); mozilla::ipc::IPCResult RecvInitCrashReporter( Shmem&& shmem, const NativeThreadId& aThreadId); private: VRProcessParent* mHost; UniquePtr mCrashReporter; + bool mVRReady; }; } // namespace gfx diff --git a/gfx/vr/ipc/VRParent.cpp b/gfx/vr/ipc/VRParent.cpp index 1118154befa8..08266462ccc5 100644 --- a/gfx/vr/ipc/VRParent.cpp +++ b/gfx/vr/ipc/VRParent.cpp @@ -39,6 +39,8 @@ IPCResult VRParent::RecvNewGPUVRManager(Endpoint&& aEndpoint) { IPCResult VRParent::RecvInit(nsTArray&& prefs, nsTArray&& vars, const DevicePrefs& devicePrefs) { + Unused << SendInitComplete(); + const nsTArray& globalPrefs = gfxPrefs::all(); for (auto& setting : prefs) { gfxPrefs::Pref* pref = globalPrefs[setting.index()]; @@ -161,6 +163,7 @@ bool VRParent::Init(base::ProcessId aParentPid, const char* aParentBuildID, return false; } + mozilla::ipc::SetThisProcessName("VR Process"); return true; } diff --git a/gfx/vr/ipc/VRProcessManager.cpp b/gfx/vr/ipc/VRProcessManager.cpp index 6ea88b87af4d..c38e862244e9 100644 --- a/gfx/vr/ipc/VRProcessManager.cpp +++ b/gfx/vr/ipc/VRProcessManager.cpp @@ -30,7 +30,7 @@ void VRProcessManager::Initialize() { /* static */ void VRProcessManager::Shutdown() { sSingleton = nullptr; } -VRProcessManager::VRProcessManager() : mProcess(nullptr) { +VRProcessManager::VRProcessManager() : mProcess(nullptr), mVRChild(nullptr) { MOZ_COUNT_CTOR(VRProcessManager); mObserver = new Observer(this); @@ -79,14 +79,43 @@ void VRProcessManager::DestroyProcess() { mProcess->Shutdown(); mProcess = nullptr; + mVRChild = nullptr; CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::VRProcessStatus, NS_LITERAL_CSTRING("Destroyed")); } +bool VRProcessManager::EnsureVRReady() { + if (mProcess && !mProcess->IsConnected()) { + if (!mProcess->WaitForLaunch()) { + // If this fails, we should have fired OnProcessLaunchComplete and + // removed the process. + MOZ_ASSERT(!mProcess && !mVRChild); + return false; + } + } + + if (mVRChild) { + if (mVRChild->EnsureVRReady()) { + return true; + } + + // If the initialization above fails, we likely have a GPU process teardown + // waiting in our message queue (or will soon). We need to ensure we don't + // restart it later because if we fail here, our callers assume they should + // fall back to a combined UI/GPU process. This also ensures our internal + // state is consistent (e.g. process token is reset). + DisableVRProcess("Failed to initialize VR process"); + } + + return false; +} + void VRProcessManager::OnProcessLaunchComplete(VRProcessParent* aParent) { MOZ_ASSERT(mProcess && mProcess == aParent); + mVRChild = mProcess->GetActor(); + if (!mProcess->IsConnected()) { DestroyProcess(); return; diff --git a/gfx/vr/ipc/VRProcessManager.h b/gfx/vr/ipc/VRProcessManager.h index 1cde3c1ada52..6708c3196f3c 100644 --- a/gfx/vr/ipc/VRProcessManager.h +++ b/gfx/vr/ipc/VRProcessManager.h @@ -27,6 +27,12 @@ class VRProcessManager final : public VRProcessParent::Listener { // If not using a VR process, launch a new VR process asynchronously. void LaunchVRProcess(); + + // Ensure that VR-bound methods can be used. If no VR process is being + // used, or one is launched and ready, this function returns immediately. + // Otherwise it blocks until the VR process has finished launching. + bool EnsureVRReady(); + bool CreateGPUBridges(base::ProcessId aOtherProcess, mozilla::ipc::Endpoint* aOutVRBridge); @@ -65,6 +71,7 @@ class VRProcessManager final : public VRProcessParent::Listener { RefPtr mObserver; VRProcessParent* mProcess; + VRChild* mVRChild; }; } // namespace gfx diff --git a/gfx/vr/ipc/VRProcessParent.cpp b/gfx/vr/ipc/VRProcessParent.cpp index a7d3ba5dd4e9..af09cc911b15 100644 --- a/gfx/vr/ipc/VRProcessParent.cpp +++ b/gfx/vr/ipc/VRProcessParent.cpp @@ -33,6 +33,7 @@ VRProcessParent::VRProcessParent(Listener* aListener) : GeckoChildProcessHost(GeckoProcessType_VR), mTaskFactory(this), mListener(aListener), + mLaunchPhase(LaunchPhase::Unlaunched), mChannelClosed(false), mShutdownRequested(false) { MOZ_COUNT_CTOR(VRProcessParent); @@ -49,19 +50,47 @@ VRProcessParent::~VRProcessParent() { } bool VRProcessParent::Launch() { + MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched); + MOZ_ASSERT(!mVRChild); mLaunchThread = NS_GetCurrentThread(); + mLaunchPhase = LaunchPhase::Waiting; + std::vector extraArgs; nsCString parentBuildID(mozilla::PlatformBuildID()); extraArgs.push_back("-parentBuildID"); extraArgs.push_back(parentBuildID.get()); if (!GeckoChildProcessHost::AsyncLaunch(extraArgs)) { + mLaunchPhase = LaunchPhase::Complete; return false; } return true; } +bool VRProcessParent::WaitForLaunch() { + if (mLaunchPhase == LaunchPhase::Complete) { + return !!mVRChild; + } + + int32_t timeoutMs = gfxPrefs::VRProcessTimeoutMs(); + + // If one of the following environment variables are set we can effectively + // ignore the timeout - as we can guarantee the compositor process will be + // terminated + if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS") || + PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) { + timeoutMs = 0; + } + + // Our caller expects the connection to be finished after we return, so we + // immediately set up the IPDL actor and fire callbacks. The IO thread will + // still dispatch a notification to the main thread - we'll just ignore it. + bool result = GeckoChildProcessHost::WaitUntilConnected(timeoutMs); + InitAfterConnect(result); + return result; +} + void VRProcessParent::Shutdown() { MOZ_ASSERT(!mShutdownRequested); mListener = nullptr; @@ -101,6 +130,10 @@ void VRProcessParent::DestroyProcess() { } void VRProcessParent::InitAfterConnect(bool aSucceeded) { + MOZ_ASSERT(mLaunchPhase == LaunchPhase::Waiting); + MOZ_ASSERT(!mVRChild); + + mLaunchPhase = LaunchPhase::Complete; if (aSucceeded) { mVRChild = MakeUnique(this); @@ -157,10 +190,16 @@ void VRProcessParent::OnChannelConnected(int32_t peer_pid) { NS_DispatchToMainThread(runnable); } -void VRProcessParent::OnChannelConnectedTask() { InitAfterConnect(true); } +void VRProcessParent::OnChannelConnectedTask() { + if (mLaunchPhase == LaunchPhase::Waiting) { + InitAfterConnect(true); + } +} void VRProcessParent::OnChannelErrorTask() { - MOZ_ASSERT(false, "VR process channel error."); + if (mLaunchPhase == LaunchPhase::Waiting) { + InitAfterConnect(false); + } } void VRProcessParent::OnChannelClosed() { diff --git a/gfx/vr/ipc/VRProcessParent.h b/gfx/vr/ipc/VRProcessParent.h index 434bcf3eb7a8..22d3c7339766 100644 --- a/gfx/vr/ipc/VRProcessParent.h +++ b/gfx/vr/ipc/VRProcessParent.h @@ -32,6 +32,11 @@ class VRProcessParent final : public mozilla::ipc::GeckoChildProcessHost { explicit VRProcessParent(Listener* aListener); bool Launch(); + // If the process is being launched, block until it has launched and + // connected. If a launch task is pending, it will fire immediately. + // + // Returns true if the process is successfully connected; false otherwise. + bool WaitForLaunch(); void Shutdown(); void DestroyProcess(); bool CanShutdown() override { return true; } @@ -45,6 +50,9 @@ class VRProcessParent final : public mozilla::ipc::GeckoChildProcessHost { base::ProcessId OtherPid(); VRChild* GetActor() const { return mVRChild.get(); } + // Return a unique id for this process, guaranteed not to be shared with any + // past or future instance of VRProcessParent. + uint64_t GetProcessToken() const; private: ~VRProcessParent(); @@ -59,6 +67,8 @@ class VRProcessParent final : public mozilla::ipc::GeckoChildProcessHost { nsCOMPtr mLaunchThread; Listener* mListener; + enum class LaunchPhase { Unlaunched, Waiting, Complete }; + LaunchPhase mLaunchPhase; bool mChannelClosed; bool mShutdownRequested; }; From 0965abeaa72a8c9912cd0ac0c06b3bc6ed991c06 Mon Sep 17 00:00:00 2001 From: Daosheng Mu Date: Tue, 2 Apr 2019 05:13:17 +0000 Subject: [PATCH 02/46] Bug 1520339 - Part 2: handling memory reporting for VR process. r=kip,erahm Differential Revision: https://phabricator.services.mozilla.com/D25321 --HG-- extra : moz-landing-system : lando --- gfx/vr/ipc/PVR.ipdl | 8 +++- gfx/vr/ipc/VRChild.cpp | 46 +++++++++++++++++++++- gfx/vr/ipc/VRChild.h | 12 ++++++ gfx/vr/ipc/VRParent.cpp | 19 +++++++++ gfx/vr/ipc/VRParent.h | 4 ++ gfx/vr/ipc/VRProcessManager.cpp | 53 ++++++++++++++++++++++++++ gfx/vr/ipc/VRProcessManager.h | 4 ++ xpcom/base/nsMemoryReporterManager.cpp | 7 ++++ xpcom/build/components.conf | 2 +- 9 files changed, 152 insertions(+), 3 deletions(-) diff --git a/gfx/vr/ipc/PVR.ipdl b/gfx/vr/ipc/PVR.ipdl index 52ccfdb61bca..e81a2851d64c 100644 --- a/gfx/vr/ipc/PVR.ipdl +++ b/gfx/vr/ipc/PVR.ipdl @@ -9,6 +9,7 @@ using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h"; include "VRMessageUtils.h"; include GraphicsMessages; +include MemoryReportTypes; include protocol PVRGPU; include "VRMessageUtils.h"; @@ -27,7 +28,10 @@ parent: async UpdateVar(GfxVarUpdate var); async OpenVRControllerActionPathToVR(nsCString aPath); async OpenVRControllerManifestPathToVR(OpenVRControllerType aType, nsCString aPath); - + async RequestMemoryReport(uint32_t generation, + bool anonymize, + bool minimizeMemoryUsage, + FileDescriptor? DMDFile); child: // Sent when the GPU process has initialized devices. This occurs once, after // Init(). @@ -35,6 +39,8 @@ child: async OpenVRControllerActionPathToParent(nsCString aPath); async OpenVRControllerManifestPathToParent(OpenVRControllerType aType, nsCString aPath); async InitCrashReporter(Shmem shmem, NativeThreadId threadId); + async AddMemoryReport(MemoryReport aReport); + async FinishMemoryReport(uint32_t aGeneration); }; } // namespace gfx diff --git a/gfx/vr/ipc/VRChild.cpp b/gfx/vr/ipc/VRChild.cpp index 97982de34708..aaf00a6045a5 100644 --- a/gfx/vr/ipc/VRChild.cpp +++ b/gfx/vr/ipc/VRChild.cpp @@ -12,6 +12,7 @@ #include "mozilla/SystemGroup.h" #include "mozilla/Telemetry.h" #include "mozilla/VsyncDispatcher.h" +#include "mozilla/dom/MemoryReportRequest.h" #include "mozilla/ipc/CrashReporterHost.h" namespace mozilla { @@ -66,10 +67,29 @@ class OpenVRControllerManifestManager { StaticRefPtr sOpenVRControllerManifestManager; -VRChild::VRChild(VRProcessParent* aHost) : mHost(aHost) { +VRChild::VRChild(VRProcessParent* aHost) + : mHost(aHost), + mVRReady(false) { MOZ_ASSERT(XRE_IsParentProcess()); } +mozilla::ipc::IPCResult VRChild::RecvAddMemoryReport( + const MemoryReport& aReport) { + if (mMemoryReportRequest) { + mMemoryReportRequest->RecvReport(aReport); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult VRChild::RecvFinishMemoryReport( + const uint32_t& aGeneration) { + if (mMemoryReportRequest) { + mMemoryReportRequest->Finish(aGeneration); + mMemoryReportRequest = nullptr; + } + return IPC_OK(); +} + void VRChild::ActorDestroy(ActorDestroyReason aWhy) { if (aWhy == AbnormalShutdown) { if (mCrashReporter) { @@ -144,6 +164,14 @@ void VRChild::Init() { gfxVars::AddReceiver(this); } +bool VRChild::EnsureVRReady() { + if (!mVRReady) { + return false; + } + + return true; +} + mozilla::ipc::IPCResult VRChild::RecvOpenVRControllerActionPathToParent( const nsCString& aPath) { sOpenVRControllerManifestManager->SetOpenVRControllerActionPath(aPath); @@ -157,6 +185,12 @@ mozilla::ipc::IPCResult VRChild::RecvOpenVRControllerManifestPathToParent( return IPC_OK(); } +mozilla::ipc::IPCResult VRChild::RecvInitComplete() { + // We synchronously requested VR parameters before this arrived. + mVRReady = true; + return IPC_OK(); +} + mozilla::ipc::IPCResult VRChild::RecvInitCrashReporter( Shmem&& aShmem, const NativeThreadId& aThreadId) { mCrashReporter = MakeUnique(GeckoProcessType_VR, @@ -165,6 +199,16 @@ mozilla::ipc::IPCResult VRChild::RecvInitCrashReporter( return IPC_OK(); } +bool VRChild::SendRequestMemoryReport(const uint32_t& aGeneration, + const bool& aAnonymize, + const bool& aMinimizeMemoryUsage, + const Maybe& aDMDFile) { + mMemoryReportRequest = MakeUnique(aGeneration); + Unused << PVRChild::SendRequestMemoryReport(aGeneration, aAnonymize, + aMinimizeMemoryUsage, aDMDFile); + return true; +} + void VRChild::OnVarChanged(const GfxVarUpdate& aVar) { SendUpdateVar(aVar); } class DeferredDeleteVRChild : public Runnable { diff --git a/gfx/vr/ipc/VRChild.h b/gfx/vr/ipc/VRChild.h index 7e7e2a5ff8e1..2396abea2aca 100644 --- a/gfx/vr/ipc/VRChild.h +++ b/gfx/vr/ipc/VRChild.h @@ -16,12 +16,16 @@ namespace mozilla { namespace ipc { class CrashReporterHost; } // namespace ipc +namespace dom { +class MemoryReportRequestHost; +} // namespace dom namespace gfx { class VRProcessParent; class VRChild; class VRChild final : public PVRChild, public gfxVarReceiver { + typedef mozilla::dom::MemoryReportRequestHost MemoryReportRequestHost; friend class PVRChild; public: @@ -32,6 +36,10 @@ class VRChild final : public PVRChild, public gfxVarReceiver { void Init(); bool EnsureVRReady(); virtual void OnVarChanged(const GfxVarUpdate& aVar) override; + bool SendRequestMemoryReport(const uint32_t& aGeneration, + const bool& aAnonymize, + const bool& aMinimizeMemoryUsage, + const Maybe& aDMDFile); protected: virtual void ActorDestroy(ActorDestroyReason aWhy) override; @@ -43,9 +51,13 @@ class VRChild final : public PVRChild, public gfxVarReceiver { mozilla::ipc::IPCResult RecvInitCrashReporter( Shmem&& shmem, const NativeThreadId& aThreadId); + mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport); + mozilla::ipc::IPCResult RecvFinishMemoryReport(const uint32_t& aGeneration); + private: VRProcessParent* mHost; UniquePtr mCrashReporter; + UniquePtr mMemoryReportRequest; bool mVRReady; }; diff --git a/gfx/vr/ipc/VRParent.cpp b/gfx/vr/ipc/VRParent.cpp index 08266462ccc5..1401b94abd55 100644 --- a/gfx/vr/ipc/VRParent.cpp +++ b/gfx/vr/ipc/VRParent.cpp @@ -9,12 +9,14 @@ #include "VRManager.h" #include "gfxConfig.h" #include "nsDebugImpl.h" +#include "ProcessUtils.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/ipc/CrashReporterClient.h" #include "mozilla/ipc/ProcessChild.h" #if defined(XP_WIN) +# include # include "mozilla/gfx/DeviceManagerDx.h" #endif @@ -95,6 +97,23 @@ mozilla::ipc::IPCResult VRParent::RecvOpenVRControllerManifestPathToVR( return IPC_OK(); } +mozilla::ipc::IPCResult VRParent::RecvRequestMemoryReport( + const uint32_t& aGeneration, const bool& aAnonymize, + const bool& aMinimizeMemoryUsage, const Maybe& aDMDFile) { + MOZ_ASSERT(XRE_IsVRProcess()); + nsPrintfCString processName("VR (pid %u)", (unsigned)getpid()); + + mozilla::dom::MemoryReportRequestClient::Start( + aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName, + [&](const MemoryReport& aReport) { + Unused << SendAddMemoryReport(aReport); + }, + [&](const uint32_t& aGeneration) { + return SendFinishMemoryReport(aGeneration); + }); + return IPC_OK(); +} + void VRParent::ActorDestroy(ActorDestroyReason aWhy) { if (AbnormalShutdown == aWhy) { NS_WARNING("Shutting down VR process early due to a crash!"); diff --git a/gfx/vr/ipc/VRParent.h b/gfx/vr/ipc/VRParent.h index 999b94a244b6..fe88a6630e25 100644 --- a/gfx/vr/ipc/VRParent.h +++ b/gfx/vr/ipc/VRParent.h @@ -46,6 +46,10 @@ class VRParent final : public PVRParent { const nsCString& aPath); mozilla::ipc::IPCResult RecvOpenVRControllerManifestPathToVR( const OpenVRControllerType& aType, const nsCString& aPath); + mozilla::ipc::IPCResult RecvRequestMemoryReport( + const uint32_t& generation, const bool& anonymize, + const bool& minimizeMemoryUsage, + const Maybe& DMDFile); private: nsCString mOpenVRControllerAction; diff --git a/gfx/vr/ipc/VRProcessManager.cpp b/gfx/vr/ipc/VRProcessManager.cpp index c38e862244e9..fd3ac1d0f2ce 100644 --- a/gfx/vr/ipc/VRProcessManager.cpp +++ b/gfx/vr/ipc/VRProcessManager.cpp @@ -10,6 +10,7 @@ #include "VRChild.h" #include "VRGPUChild.h" #include "VRGPUParent.h" +#include "mozilla/MemoryReportingProcess.h" namespace mozilla { namespace gfx { @@ -195,5 +196,57 @@ void VRProcessManager::OnXPCOMShutdown() { VRChild* VRProcessManager::GetVRChild() { return mProcess->GetActor(); } +class VRMemoryReporter : public MemoryReportingProcess { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRMemoryReporter, override) + + bool IsAlive() const override { + if (VRProcessManager* vpm = VRProcessManager::Get()) { + return !!vpm->GetVRChild(); + } + return false; + } + + bool SendRequestMemoryReport(const uint32_t& aGeneration, + const bool& aAnonymize, + const bool& aMinimizeMemoryUsage, + const Maybe& aDMDFile) override { + VRChild* child = GetChild(); + if (!child) { + return false; + } + + return child->SendRequestMemoryReport(aGeneration, aAnonymize, + aMinimizeMemoryUsage, aDMDFile); + } + + int32_t Pid() const override { + if (VRChild* child = GetChild()) { + return (int32_t)child->OtherPid(); + } + return 0; + } + + private: + VRChild* GetChild() const { + if (VRProcessManager* vpm = VRProcessManager::Get()) { + if (VRChild* child = vpm->GetVRChild()) { + return child; + } + } + return nullptr; + } + + protected: + ~VRMemoryReporter() = default; +}; + +RefPtr VRProcessManager::GetProcessMemoryReporter() { + if (!EnsureVRReady()) { + return nullptr; + } + return new VRMemoryReporter(); +} + } // namespace gfx } // namespace mozilla \ No newline at end of file diff --git a/gfx/vr/ipc/VRProcessManager.h b/gfx/vr/ipc/VRProcessManager.h index 6708c3196f3c..0640ebee6fbe 100644 --- a/gfx/vr/ipc/VRProcessManager.h +++ b/gfx/vr/ipc/VRProcessManager.h @@ -9,6 +9,7 @@ #include "VRProcessParent.h" namespace mozilla { +class MemoryReportingProcess; namespace gfx { class VRManagerChild; @@ -37,6 +38,9 @@ class VRProcessManager final : public VRProcessParent::Listener { mozilla::ipc::Endpoint* aOutVRBridge); VRChild* GetVRChild(); + // If a VR process is present, create a MemoryReportingProcess object. + // Otherwise, return null. + RefPtr GetProcessMemoryReporter(); virtual void OnProcessLaunchComplete(VRProcessParent* aParent) override; virtual void OnProcessUnexpectedShutdown(VRProcessParent* aParent) override; diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 1ef57a007bac..7344f190d50b 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -27,6 +27,7 @@ #endif #include "nsNetCID.h" #include "nsThread.h" +#include "VRProcessManager.h" #include "mozilla/Attributes.h" #include "mozilla/MemoryReportingProcess.h" #include "mozilla/PodOperations.h" @@ -1814,6 +1815,12 @@ nsresult nsMemoryReporterManager::StartGettingReports() { } } + if (gfx::VRProcessManager* vr = gfx::VRProcessManager::Get()) { + if (RefPtr proc = vr->GetProcessMemoryReporter()) { + s->mChildrenPending.AppendElement(proc.forget()); + } + } + if (!mIsRegistrationBlocked && net::gIOService) { if (RefPtr proc = net::gIOService->GetSocketProcessMemoryReporter()) { diff --git a/xpcom/build/components.conf b/xpcom/build/components.conf index 9f2deda27ab5..cb25e5f5ae2b 100644 --- a/xpcom/build/components.conf +++ b/xpcom/build/components.conf @@ -67,7 +67,7 @@ Classes = [ 'type': 'nsMemoryReporterManager', 'headers': ['/xpcom/base/nsMemoryReporterManager.h'], 'init_method': 'Init', - 'processes': ProcessSelector.ALLOW_IN_GPU_AND_SOCKET_PROCESS, + 'processes': ProcessSelector.ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS, }, { 'cid': '{7b4eeb20-d781-11d4-8a83-0010a4e0c9ca}', From 901af55a559631776177057cafe312622299855e Mon Sep 17 00:00:00 2001 From: David Walsh Date: Tue, 2 Apr 2019 06:16:25 +0000 Subject: [PATCH 03/46] Bug 1540172 - Align close button at top for expressions r=nchevobbe Corrects the vertical alignment of the close button for watch expressions. Differential Revision: https://phabricator.services.mozilla.com/D25465 --HG-- extra : moz-landing-system : lando --- .../debugger/new/src/components/SecondaryPanes/Expressions.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.css b/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.css index 866bd2d11de2..e57035f641e7 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.css +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.css @@ -101,7 +101,7 @@ .expression-container:hover .expression-container__close-btn, .expression-container__close-btn:focus-within { - top: calc(50% - 8px); + top: 0; } [dir="ltr"] .expression-container__close-btn { From b04078973edf07066746a7e3967a5ab1fd54a832 Mon Sep 17 00:00:00 2001 From: Camil Staps Date: Tue, 2 Apr 2019 06:22:35 +0000 Subject: [PATCH 04/46] Bug 1513492 - Add support for a number of new (2018/12) text versions of WebAssembly instructions r=lth The text format of the instructions wrap, extend, trunc, convert, demote, promote, and reinterpret was changed recently to make them more consistent. Signedness now appears after the type; e.g. trunc_f32_s instead of trunc_s/f32. Also, local.tee can now be used besides tee_local. See https://github.com/WebAssembly/wabt/issues/933 for reference. Differential Revision: https://phabricator.services.mozilla.com/D25540 --HG-- extra : moz-landing-system : lando --- js/src/wasm/WasmTextToBinary.cpp | 139 ++++++++++++++++--------------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/js/src/wasm/WasmTextToBinary.cpp b/js/src/wasm/WasmTextToBinary.cpp index 212bed94468a..5933566b4c65 100644 --- a/js/src/wasm/WasmTextToBinary.cpp +++ b/js/src/wasm/WasmTextToBinary.cpp @@ -1065,19 +1065,19 @@ WasmToken WasmTokenStream::next() { if (consume(u"const")) { return WasmToken(WasmToken::Const, ValType::F32, begin, cur_); } - if (consume(u"convert_s/i32")) { + if (consume(u"convert_i32_s") || consume(u"convert_s/i32")) { return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertSI32, begin, cur_); } - if (consume(u"convert_u/i32")) { + if (consume(u"convert_i32_u") || consume(u"convert_u/i32")) { return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertUI32, begin, cur_); } - if (consume(u"convert_s/i64")) { + if (consume(u"convert_i64_s") || consume(u"convert_s/i64")) { return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertSI64, begin, cur_); } - if (consume(u"convert_u/i64")) { + if (consume(u"convert_i64_u") || consume(u"convert_u/i64")) { return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertUI64, begin, cur_); } @@ -1087,7 +1087,7 @@ WasmToken WasmTokenStream::next() { } break; case 'd': - if (consume(u"demote/f64")) { + if (consume(u"demote_f64") || consume(u"demote/f64")) { return WasmToken(WasmToken::ConversionOpcode, Op::F32DemoteF64, begin, cur_); } @@ -1159,7 +1159,7 @@ WasmToken WasmTokenStream::next() { } break; case 'r': - if (consume(u"reinterpret/i32")) { + if (consume(u"reinterpret_i32") || consume(u"reinterpret/i32")) { return WasmToken(WasmToken::ConversionOpcode, Op::F32ReinterpretI32, begin, cur_); } @@ -1209,19 +1209,19 @@ WasmToken WasmTokenStream::next() { if (consume(u"const")) { return WasmToken(WasmToken::Const, ValType::F64, begin, cur_); } - if (consume(u"convert_s/i32")) { + if (consume(u"convert_i32_s") || consume(u"convert_s/i32")) { return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertSI32, begin, cur_); } - if (consume(u"convert_u/i32")) { + if (consume(u"convert_i32_u") || consume(u"convert_u/i32")) { return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertUI32, begin, cur_); } - if (consume(u"convert_s/i64")) { + if (consume(u"convert_i64_s") || consume(u"convert_s/i64")) { return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertSI64, begin, cur_); } - if (consume(u"convert_u/i64")) { + if (consume(u"convert_i64_u") || consume(u"convert_u/i64")) { return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertUI64, begin, cur_); } @@ -1299,13 +1299,13 @@ WasmToken WasmTokenStream::next() { } break; case 'p': - if (consume(u"promote/f32")) { + if (consume(u"promote_f32") || consume(u"promote/f32")) { return WasmToken(WasmToken::ConversionOpcode, Op::F64PromoteF32, begin, cur_); } break; case 'r': - if (consume(u"reinterpret/i64")) { + if (consume(u"reinterpret_i64") || consume(u"reinterpret/i64")) { return WasmToken(WasmToken::UnaryOpcode, Op::F64ReinterpretI64, begin, cur_); } @@ -1377,11 +1377,11 @@ WasmToken WasmTokenStream::next() { cur_); } if (consume(u"atomic.")) { - if (consume(u"rmw8_u.add")) { + if (consume(u"rmw8.add_u") || consume(u"rmw8_u.add")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicAdd8U, begin, cur_); } - if (consume(u"rmw16_u.add")) { + if (consume(u"rmw16.add_u") || consume(u"rmw16_u.add")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicAdd16U, begin, cur_); } @@ -1389,11 +1389,11 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicAdd, begin, cur_); } - if (consume(u"rmw8_u.and")) { + if (consume(u"rmw8.and_u") || consume(u"rmw8_u.and")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicAnd8U, begin, cur_); } - if (consume(u"rmw16_u.and")) { + if (consume(u"rmw16.and_u") || consume(u"rmw16_u.and")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicAnd16U, begin, cur_); } @@ -1401,11 +1401,11 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicAnd, begin, cur_); } - if (consume(u"rmw8_u.cmpxchg")) { + if (consume(u"rmw8.cmpxchg_u") || consume(u"rmw8_u.cmpxchg")) { return WasmToken(WasmToken::AtomicCmpXchg, ThreadOp::I32AtomicCmpXchg8U, begin, cur_); } - if (consume(u"rmw16_u.cmpxchg")) { + if (consume(u"rmw16.cmpxchg_u") || consume(u"rmw16_u.cmpxchg")) { return WasmToken(WasmToken::AtomicCmpXchg, ThreadOp::I32AtomicCmpXchg16U, begin, cur_); } @@ -1425,11 +1425,11 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicLoad, ThreadOp::I32AtomicLoad, begin, cur_); } - if (consume(u"rmw8_u.or")) { + if (consume(u"rmw8.or_u") || consume(u"rmw8_u.or")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicOr8U, begin, cur_); } - if (consume(u"rmw16_u.or")) { + if (consume(u"rmw16.or_u") || consume(u"rmw16_u.or")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicOr16U, begin, cur_); } @@ -1449,11 +1449,11 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicStore, ThreadOp::I32AtomicStore, begin, cur_); } - if (consume(u"rmw8_u.sub")) { + if (consume(u"rmw8.sub_u") || consume(u"rmw8_u.sub")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicSub8U, begin, cur_); } - if (consume(u"rmw16_u.sub")) { + if (consume(u"rmw16.sub_u") || consume(u"rmw16_u.sub")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicSub16U, begin, cur_); } @@ -1461,11 +1461,11 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicSub, begin, cur_); } - if (consume(u"rmw8_u.xor")) { + if (consume(u"rmw8.xor_u") || consume(u"rmw8_u.xor")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicXor8U, begin, cur_); } - if (consume(u"rmw16_u.xor")) { + if (consume(u"rmw16.xor_u") || consume(u"rmw16_u.xor")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicXor16U, begin, cur_); } @@ -1473,11 +1473,11 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicXor, begin, cur_); } - if (consume(u"rmw8_u.xchg")) { + if (consume(u"rmw8.xchg_u") || consume(u"rmw8_u.xchg")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicXchg8U, begin, cur_); } - if (consume(u"rmw16_u.xchg")) { + if (consume(u"rmw16.xchg_u") || consume(u"rmw16_u.xchg")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicXchg16U, begin, cur_); } @@ -1607,7 +1607,7 @@ WasmToken WasmTokenStream::next() { } break; case 'r': - if (consume(u"reinterpret/f32")) { + if (consume(u"reinterpret_f32") || consume(u"reinterpret/f32")) { return WasmToken(WasmToken::UnaryOpcode, Op::I32ReinterpretF32, begin, cur_); } @@ -1659,41 +1659,41 @@ WasmToken WasmTokenStream::next() { } break; case 't': - if (consume(u"trunc_s/f32")) { + if (consume(u"trunc_f32_s") || consume(u"trunc_s/f32")) { return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncSF32, begin, cur_); } - if (consume(u"trunc_s/f64")) { + if (consume(u"trunc_f64_s") || consume(u"trunc_s/f64")) { return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncSF64, begin, cur_); } - if (consume(u"trunc_u/f32")) { + if (consume(u"trunc_f32_u") || consume(u"trunc_u/f32")) { return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncUF32, begin, cur_); } - if (consume(u"trunc_u/f64")) { + if (consume(u"trunc_f64_u") || consume(u"trunc_u/f64")) { return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncUF64, begin, cur_); } - if (consume(u"trunc_s:sat/f32")) { + if (consume(u"trunc_sat_f32_s") || consume(u"trunc_s:sat/f32")) { return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I32TruncSSatF32, begin, cur_); } - if (consume(u"trunc_s:sat/f64")) { + if (consume(u"trunc_sat_f64_s") || consume(u"trunc_s:sat/f64")) { return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I32TruncSSatF64, begin, cur_); } - if (consume(u"trunc_u:sat/f32")) { + if (consume(u"trunc_sat_f32_u") || consume(u"trunc_u:sat/f32")) { return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I32TruncUSatF32, begin, cur_); } - if (consume(u"trunc_u:sat/f64")) { + if (consume(u"trunc_sat_f64_u") || consume(u"trunc_u:sat/f64")) { return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I32TruncUSatF64, begin, cur_); } break; case 'w': - if (consume(u"wrap/i64")) { + if (consume(u"wrap_i64") || consume(u"wrap/i64")) { return WasmToken(WasmToken::ConversionOpcode, Op::I32WrapI64, begin, cur_); } @@ -1723,15 +1723,15 @@ WasmToken WasmTokenStream::next() { cur_); } if (consume(u"atomic.")) { - if (consume(u"rmw8_u.add")) { + if (consume(u"rmw8.add_u") || consume(u"rmw8_u.add")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAdd8U, begin, cur_); } - if (consume(u"rmw16_u.add")) { + if (consume(u"rmw16.add_u") || consume(u"rmw16_u.add")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAdd16U, begin, cur_); } - if (consume(u"rmw32_u.add")) { + if (consume(u"rmw32.add_u") || consume(u"rmw32_u.add")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAdd32U, begin, cur_); } @@ -1739,15 +1739,15 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAdd, begin, cur_); } - if (consume(u"rmw8_u.and")) { + if (consume(u"rmw8.and_u") || consume(u"rmw8_u.and")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAnd8U, begin, cur_); } - if (consume(u"rmw16_u.and")) { + if (consume(u"rmw16.and_u") || consume(u"rmw16_u.and")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAnd16U, begin, cur_); } - if (consume(u"rmw32_u.and")) { + if (consume(u"rmw32.and_u") || consume(u"rmw32_u.and")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAnd32U, begin, cur_); } @@ -1755,15 +1755,15 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAnd, begin, cur_); } - if (consume(u"rmw8_u.cmpxchg")) { + if (consume(u"rmw8.cmpxchg_u") || consume(u"rmw8_u.cmpxchg")) { return WasmToken(WasmToken::AtomicCmpXchg, ThreadOp::I64AtomicCmpXchg8U, begin, cur_); } - if (consume(u"rmw16_u.cmpxchg")) { + if (consume(u"rmw16.cmpxchg_u") || consume(u"rmw16_u.cmpxchg")) { return WasmToken(WasmToken::AtomicCmpXchg, ThreadOp::I64AtomicCmpXchg16U, begin, cur_); } - if (consume(u"rmw32_u.cmpxchg")) { + if (consume(u"rmw32.cmpxchg_u") || consume(u"rmw32_u.cmpxchg")) { return WasmToken(WasmToken::AtomicCmpXchg, ThreadOp::I64AtomicCmpXchg32U, begin, cur_); } @@ -1787,15 +1787,15 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicLoad, ThreadOp::I64AtomicLoad, begin, cur_); } - if (consume(u"rmw8_u.or")) { + if (consume(u"rmw8.or_u") || consume(u"rmw8_u.or")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicOr8U, begin, cur_); } - if (consume(u"rmw16_u.or")) { + if (consume(u"rmw16.or_u") || consume(u"rmw16_u.or")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicOr16U, begin, cur_); } - if (consume(u"rmw32_u.or")) { + if (consume(u"rmw32.or_u") || consume(u"rmw32_u.or")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicOr32U, begin, cur_); } @@ -1819,15 +1819,15 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicStore, ThreadOp::I64AtomicStore, begin, cur_); } - if (consume(u"rmw8_u.sub")) { + if (consume(u"rmw8.sub_u") || consume(u"rmw8_u.sub")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicSub8U, begin, cur_); } - if (consume(u"rmw16_u.sub")) { + if (consume(u"rmw16.sub_u") || consume(u"rmw16_u.sub")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicSub16U, begin, cur_); } - if (consume(u"rmw32_u.sub")) { + if (consume(u"rmw32.sub_u") || consume(u"rmw32_u.sub")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicSub32U, begin, cur_); } @@ -1835,15 +1835,15 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicSub, begin, cur_); } - if (consume(u"rmw8_u.xor")) { + if (consume(u"rmw8.xor_u") || consume(u"rmw8_u.xor")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicXor8U, begin, cur_); } - if (consume(u"rmw16_u.xor")) { + if (consume(u"rmw16.xor_u") || consume(u"rmw16_u.xor")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicXor16U, begin, cur_); } - if (consume(u"rmw32_u.xor")) { + if (consume(u"rmw32.xor_u") || consume(u"rmw32_u.xor")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicXor32U, begin, cur_); } @@ -1851,15 +1851,15 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicXor, begin, cur_); } - if (consume(u"rmw8_u.xchg")) { + if (consume(u"rmw8.xchg_u") || consume(u"rmw8_u.xchg")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicXchg8U, begin, cur_); } - if (consume(u"rmw16_u.xchg")) { + if (consume(u"rmw16.xchg_u") || consume(u"rmw16_u.xchg")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicXchg16U, begin, cur_); } - if (consume(u"rmw32_u.xchg")) { + if (consume(u"rmw32.xchg_u") || consume(u"rmw32_u.xchg")) { return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicXchg32U, begin, cur_); } @@ -1902,11 +1902,11 @@ WasmToken WasmTokenStream::next() { return WasmToken(WasmToken::ComparisonOpcode, Op::I64Eq, begin, cur_); } - if (consume(u"extend_s/i32")) { + if (consume(u"extend_i32_s") || consume(u"extend_s/i32")) { return WasmToken(WasmToken::ConversionOpcode, Op::I64ExtendSI32, begin, cur_); } - if (consume(u"extend_u/i32")) { + if (consume(u"extend_i32_u") || consume(u"extend_u/i32")) { return WasmToken(WasmToken::ConversionOpcode, Op::I64ExtendUI32, begin, cur_); } @@ -2007,7 +2007,7 @@ WasmToken WasmTokenStream::next() { } break; case 'r': - if (consume(u"reinterpret/f64")) { + if (consume(u"reinterpret_f64") || consume(u"reinterpret/f64")) { return WasmToken(WasmToken::UnaryOpcode, Op::I64ReinterpretF64, begin, cur_); } @@ -2062,35 +2062,35 @@ WasmToken WasmTokenStream::next() { } break; case 't': - if (consume(u"trunc_s/f32")) { + if (consume(u"trunc_f32_s") || consume(u"trunc_s/f32")) { return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncSF32, begin, cur_); } - if (consume(u"trunc_s/f64")) { + if (consume(u"trunc_f64_s") || consume(u"trunc_s/f64")) { return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncSF64, begin, cur_); } - if (consume(u"trunc_u/f32")) { + if (consume(u"trunc_f32_u") || consume(u"trunc_u/f32")) { return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncUF32, begin, cur_); } - if (consume(u"trunc_u/f64")) { + if (consume(u"trunc_f64_u") || consume(u"trunc_u/f64")) { return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncUF64, begin, cur_); } - if (consume(u"trunc_s:sat/f32")) { + if (consume(u"trunc_sat_f32_s") || consume(u"trunc_s:sat/f32")) { return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I64TruncSSatF32, begin, cur_); } - if (consume(u"trunc_s:sat/f64")) { + if (consume(u"trunc_sat_f64_s") || consume(u"trunc_s:sat/f64")) { return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I64TruncSSatF64, begin, cur_); } - if (consume(u"trunc_u:sat/f32")) { + if (consume(u"trunc_sat_f32_u") || consume(u"trunc_u:sat/f32")) { return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I64TruncUSatF32, begin, cur_); } - if (consume(u"trunc_u:sat/f64")) { + if (consume(u"trunc_sat_f64_u") || consume(u"trunc_u:sat/f64")) { return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I64TruncUSatF64, begin, cur_); } @@ -2125,6 +2125,9 @@ WasmToken WasmTokenStream::next() { if (consume(u".set")) { return WasmToken(WasmToken::SetLocal, begin, cur_); } + if (consume(u".tee")) { + return WasmToken(WasmToken::TeeLocal, begin, cur_); + } return WasmToken(WasmToken::Local, begin, cur_); } if (consume(u"loop")) { From df730bd21e8dca6e72d17341f6b27b448846ac6e Mon Sep 17 00:00:00 2001 From: Alex Chronopoulos Date: Mon, 1 Apr 2019 22:05:48 +0000 Subject: [PATCH 05/46] Bug 1540231 - Stop dispatching a task to the TaskQueue when we are already in it. r=jya Differential Revision: https://phabricator.services.mozilla.com/D25576 --HG-- extra : moz-landing-system : lando --- dom/media/platforms/agnostic/DAV1DDecoder.cpp | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/dom/media/platforms/agnostic/DAV1DDecoder.cpp b/dom/media/platforms/agnostic/DAV1DDecoder.cpp index b57d5e47c950..f2da2fb61dec 100644 --- a/dom/media/platforms/agnostic/DAV1DDecoder.cpp +++ b/dom/media/platforms/agnostic/DAV1DDecoder.cpp @@ -62,19 +62,24 @@ void ReleaseDataBuffer_s(const uint8_t* buf, void* user_data) { } void DAV1DDecoder::ReleaseDataBuffer(const uint8_t* buf) { - // The release callback may be called on a - // different thread defined by third party - // dav1d execution. Post a task into TaskQueue - // to ensure mDecodingBuffers is only ever - // accessed on the TaskQueue + // The release callback may be called on a different thread defined by the + // third party dav1d execution. In that case post a task into TaskQueue to + // ensure that mDecodingBuffers is only ever accessed on the TaskQueue. RefPtr self = this; - nsresult rv = mTaskQueue->Dispatch( - NS_NewRunnableFunction("DAV1DDecoder::ReleaseDataBuffer", [self, buf]() { - DebugOnly found = self->mDecodingBuffers.Remove(buf); - MOZ_ASSERT(found); - })); - MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); - Unused << rv; + auto releaseBuffer = [self, buf] { + MOZ_ASSERT(self->mTaskQueue->IsCurrentThreadIn()); + DebugOnly found = self->mDecodingBuffers.Remove(buf); + MOZ_ASSERT(found); + }; + + if (mTaskQueue->IsCurrentThreadIn()) { + releaseBuffer(); + } else { + nsresult rv = mTaskQueue->Dispatch(NS_NewRunnableFunction( + "DAV1DDecoder::ReleaseDataBuffer", std::move(releaseBuffer))); + MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); + Unused << rv; + } } RefPtr DAV1DDecoder::InvokeDecode( From cde6cfbbf810112291e8252919feee6d72b6de79 Mon Sep 17 00:00:00 2001 From: Daisuke Akatsuka Date: Tue, 2 Apr 2019 06:21:23 +0000 Subject: [PATCH 06/46] Bug 1505131: Change the label and status of connection button when start to connect. r=jdescottes,flod Differential Revision: https://phabricator.services.mozilla.com/D25032 --HG-- extra : moz-landing-system : lando --- .../aboutdebugging-new/src/actions/runtimes.js | 13 ++++++++++--- .../src/components/sidebar/Sidebar.js | 1 + .../src/components/sidebar/SidebarRuntimeItem.js | 10 ++++++++-- .../src/reducers/runtimes-state.js | 14 +++++++++++++- .../client/aboutdebugging-new/src/types/runtime.js | 4 ++++ devtools/client/locales/en-US/aboutdebugging.ftl | 3 +++ 6 files changed, 39 insertions(+), 6 deletions(-) diff --git a/devtools/client/aboutdebugging-new/src/actions/runtimes.js b/devtools/client/aboutdebugging-new/src/actions/runtimes.js index 6a6032ef5da0..a2e9570065be 100644 --- a/devtools/client/aboutdebugging-new/src/actions/runtimes.js +++ b/devtools/client/aboutdebugging-new/src/actions/runtimes.js @@ -69,7 +69,7 @@ function onMultiE10sUpdated() { function connectRuntime(id) { return async (dispatch, getState) => { - dispatch({ type: CONNECT_RUNTIME_START }); + dispatch({ type: CONNECT_RUNTIME_START, id }); try { const runtime = findRuntimeById(id, getState().runtimes); const clientWrapper = await createClientForRuntime(runtime); @@ -135,7 +135,7 @@ function connectRuntime(id) { }, }); } catch (e) { - dispatch({ type: CONNECT_RUNTIME_FAILURE, error: e }); + dispatch({ type: CONNECT_RUNTIME_FAILURE, id, error: e }); } }; } @@ -144,6 +144,7 @@ function createThisFirefoxRuntime() { return (dispatch, getState) => { const thisFirefoxRuntime = { id: RUNTIMES.THIS_FIREFOX, + isConnecting: false, isUnknown: false, name: l10n.getString("about-debugging-this-firefox-runtime-name"), type: RUNTIMES.THIS_FIREFOX, @@ -302,6 +303,7 @@ function updateNetworkRuntimes(locations) { extra: { connectionParameters: { host, port: parseInt(port, 10) }, }, + isConnecting: false, isUnknown: false, name: location, type: RUNTIMES.NETWORK, @@ -322,6 +324,7 @@ function updateUSBRuntimes(adbRuntimes) { connectionParameters, deviceName: adbRuntime.deviceName, }, + isConnecting: false, isUnknown: adbRuntime.isUnknown(), name: adbRuntime.shortName, type: RUNTIMES.USB, @@ -363,12 +366,16 @@ function updateRemoteRuntimes(runtimes, type) { await dispatch(Actions.selectPage(PAGE_TYPES.RUNTIME, RUNTIMES.THIS_FIREFOX)); } - // Retrieve runtimeDetails from existing runtimes. + // For existing runtimes, transfer all properties that are not available in the + // runtime objects passed to this method: + // - runtimeDetails (set by about:debugging after a successful connection) + // - isConnecting (set by about:debugging during the connection) runtimes.forEach(runtime => { const existingRuntime = findRuntimeById(runtime.id, getState().runtimes); const isConnectionValid = existingRuntime && existingRuntime.runtimeDetails && !existingRuntime.runtimeDetails.clientWrapper.isClosed(); runtime.runtimeDetails = isConnectionValid ? existingRuntime.runtimeDetails : null; + runtime.isConnecting = existingRuntime ? existingRuntime.isConnecting : false; }); const existingRuntimes = getAllRuntimes(getState().runtimes); diff --git a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js index be5e2d70ee06..46af3693a0dc 100644 --- a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js +++ b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js @@ -113,6 +113,7 @@ class Sidebar extends PureComponent { icon, key: keyId, isConnected: runtimeHasDetails, + isConnecting: runtime.isConnecting, isSelected, isUnknown: runtime.isUnknown, name, diff --git a/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js b/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js index 8f9cce79afbb..960fe546dd31 100644 --- a/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js +++ b/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js @@ -26,6 +26,7 @@ class SidebarRuntimeItem extends PureComponent { getString: PropTypes.func.isRequired, icon: PropTypes.string.isRequired, isConnected: PropTypes.bool.isRequired, + isConnecting: PropTypes.bool.isRequired, isSelected: PropTypes.bool.isRequired, isUnknown: PropTypes.bool.isRequired, name: PropTypes.string.isRequired, @@ -34,19 +35,24 @@ class SidebarRuntimeItem extends PureComponent { } renderConnectButton() { + const { isConnecting } = this.props; + const localizationId = isConnecting + ? "about-debugging-sidebar-item-connect-button-connecting" + : "about-debugging-sidebar-item-connect-button"; return Localized( { - id: "about-debugging-sidebar-item-connect-button", + id: localizationId, }, dom.button( { className: "default-button default-button--micro js-connect-button", + disabled: isConnecting, onClick: () => { const { dispatch, runtimeId } = this.props; dispatch(Actions.connectRuntime(runtimeId)); }, }, - "Connect" + localizationId ) ); } diff --git a/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js b/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js index 4edd479bae33..3a2d853d19c1 100644 --- a/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js +++ b/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js @@ -5,6 +5,8 @@ "use strict"; const { + CONNECT_RUNTIME_FAILURE, + CONNECT_RUNTIME_START, CONNECT_RUNTIME_SUCCESS, DISCONNECT_RUNTIME_SUCCESS, RUNTIMES, @@ -72,10 +74,20 @@ function _updateRuntimeById(runtimeId, updatedRuntime, state) { function runtimesReducer(state = RuntimesState(), action) { switch (action.type) { + case CONNECT_RUNTIME_START: { + const { id } = action; + return _updateRuntimeById(id, { isConnecting: true }, state); + } + case CONNECT_RUNTIME_SUCCESS: { const { id, runtimeDetails, type } = action.runtime; remoteClientManager.setClient(id, type, runtimeDetails.clientWrapper.client); - return _updateRuntimeById(id, { runtimeDetails }, state); + return _updateRuntimeById(id, { isConnecting: false, runtimeDetails }, state); + } + + case CONNECT_RUNTIME_FAILURE: { + const { id } = action; + return _updateRuntimeById(id, { isConnecting: false }, state); } case DISCONNECT_RUNTIME_SUCCESS: { diff --git a/devtools/client/aboutdebugging-new/src/types/runtime.js b/devtools/client/aboutdebugging-new/src/types/runtime.js index b1e56289ec5a..da626c89f51e 100644 --- a/devtools/client/aboutdebugging-new/src/types/runtime.js +++ b/devtools/client/aboutdebugging-new/src/types/runtime.js @@ -115,6 +115,10 @@ const runtime = { // unavailable on this-firefox runtime extra: PropTypes.shape(runtimeExtra), + // this flag will be true when start to connect to the runtime, will be false after + // connected or has failures. + isConnecting: PropTypes.bool.isRequired, + // unknown runtimes are placeholders for devices where the runtime has not been started // yet. For instance an ADB device connected without a compatible runtime running. isUnknown: PropTypes.bool.isRequired, diff --git a/devtools/client/locales/en-US/aboutdebugging.ftl b/devtools/client/locales/en-US/aboutdebugging.ftl index 39fc48c8a09c..f4ccb4f7c42f 100644 --- a/devtools/client/locales/en-US/aboutdebugging.ftl +++ b/devtools/client/locales/en-US/aboutdebugging.ftl @@ -46,6 +46,9 @@ about-debugging-sidebar-no-devices = No devices discovered # Clicking on the button will attempt to connect to the runtime. about-debugging-sidebar-item-connect-button = Connect +# Text displayed in buttons found in sidebar items when the runtime is connecting. +about-debugging-sidebar-item-connect-button-connecting = Connecting… + # Temporary text displayed in sidebar items representing remote runtimes after # successfully connecting to them. Temporary UI, do not localize. about-debugging-sidebar-item-connected-label = Connected From 5783c1a3397bffc8a60e993d98d5e448d5d2c160 Mon Sep 17 00:00:00 2001 From: Daisuke Akatsuka Date: Tue, 2 Apr 2019 06:44:34 +0000 Subject: [PATCH 07/46] Bug 1505131: Show error message when the connecting was failed. r=jdescottes,flod Depends on D25032 Differential Revision: https://phabricator.services.mozilla.com/D25033 --HG-- extra : moz-landing-system : lando --- .../src/actions/runtimes.js | 6 ++ .../client/aboutdebugging-new/src/base.css | 5 ++ .../src/components/sidebar/Sidebar.js | 1 + .../components/sidebar/SidebarRuntimeItem.js | 67 ++++++++++++++----- .../src/reducers/runtimes-state.js | 9 ++- .../aboutdebugging-new/src/types/runtime.js | 3 + .../client/locales/en-US/aboutdebugging.ftl | 3 + 7 files changed, 73 insertions(+), 21 deletions(-) diff --git a/devtools/client/aboutdebugging-new/src/actions/runtimes.js b/devtools/client/aboutdebugging-new/src/actions/runtimes.js index a2e9570065be..d5fde9f63366 100644 --- a/devtools/client/aboutdebugging-new/src/actions/runtimes.js +++ b/devtools/client/aboutdebugging-new/src/actions/runtimes.js @@ -145,6 +145,7 @@ function createThisFirefoxRuntime() { const thisFirefoxRuntime = { id: RUNTIMES.THIS_FIREFOX, isConnecting: false, + isConnectionFailed: false, isUnknown: false, name: l10n.getString("about-debugging-this-firefox-runtime-name"), type: RUNTIMES.THIS_FIREFOX, @@ -304,6 +305,7 @@ function updateNetworkRuntimes(locations) { connectionParameters: { host, port: parseInt(port, 10) }, }, isConnecting: false, + isConnectionFailed: false, isUnknown: false, name: location, type: RUNTIMES.NETWORK, @@ -325,6 +327,7 @@ function updateUSBRuntimes(adbRuntimes) { deviceName: adbRuntime.deviceName, }, isConnecting: false, + isConnectionFailed: false, isUnknown: adbRuntime.isUnknown(), name: adbRuntime.shortName, type: RUNTIMES.USB, @@ -370,12 +373,15 @@ function updateRemoteRuntimes(runtimes, type) { // runtime objects passed to this method: // - runtimeDetails (set by about:debugging after a successful connection) // - isConnecting (set by about:debugging during the connection) + // - isConnectionFailed (set by about:debugging if connection was failed) runtimes.forEach(runtime => { const existingRuntime = findRuntimeById(runtime.id, getState().runtimes); const isConnectionValid = existingRuntime && existingRuntime.runtimeDetails && !existingRuntime.runtimeDetails.clientWrapper.isClosed(); runtime.runtimeDetails = isConnectionValid ? existingRuntime.runtimeDetails : null; runtime.isConnecting = existingRuntime ? existingRuntime.isConnecting : false; + runtime.isConnectionFailed = + existingRuntime ? existingRuntime.isConnectionFailed : false; }); const existingRuntimes = getAllRuntimes(getState().runtimes); diff --git a/devtools/client/aboutdebugging-new/src/base.css b/devtools/client/aboutdebugging-new/src/base.css index 191b416d4f8d..7ef56663ad6d 100644 --- a/devtools/client/aboutdebugging-new/src/base.css +++ b/devtools/client/aboutdebugging-new/src/base.css @@ -163,6 +163,11 @@ p, h1 { color: currentColor; } +/* Text needs to wrap anywhere */ +.word-wrap-anywhere { + word-wrap: anywhere; +} + /* * Typography */ diff --git a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js index 46af3693a0dc..4b91e0c546b6 100644 --- a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js +++ b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js @@ -114,6 +114,7 @@ class Sidebar extends PureComponent { key: keyId, isConnected: runtimeHasDetails, isConnecting: runtime.isConnecting, + isConnectionFailed: runtime.isConnectionFailed, isSelected, isUnknown: runtime.isUnknown, name, diff --git a/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js b/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js index 960fe546dd31..b971d8cf1cf1 100644 --- a/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js +++ b/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js @@ -11,8 +11,10 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const FluentReact = require("devtools/client/shared/vendor/fluent-react"); const Localized = createFactory(FluentReact.Localized); +const Message = createFactory(require("../shared/Message")); const SidebarItem = createFactory(require("./SidebarItem")); const Actions = require("../../actions/index"); +const { MESSAGE_LEVEL } = require("../../constants"); /** * This component displays a runtime item of the Sidebar component. @@ -27,6 +29,7 @@ class SidebarRuntimeItem extends PureComponent { icon: PropTypes.string.isRequired, isConnected: PropTypes.bool.isRequired, isConnecting: PropTypes.bool.isRequired, + isConnectionFailed: PropTypes.bool.isRequired, isSelected: PropTypes.bool.isRequired, isUnknown: PropTypes.bool.isRequired, name: PropTypes.string.isRequired, @@ -57,6 +60,30 @@ class SidebarRuntimeItem extends PureComponent { ); } + renderConnectionError() { + const { isConnectionFailed } = this.props; + + if (!isConnectionFailed) { + return null; + } + + const localizationId = + "about-debugging-sidebar-item-connect-button-connection-failed"; + + return Message( + { + level: MESSAGE_LEVEL.ERROR, + key: "connection-error", + }, + Localized( + { + id: localizationId, + }, + dom.p({ className: "word-wrap-anywhere" }, localizationId) + ) + ); + } + renderName() { const { deviceName, getString, isUnknown, name } = this.props; @@ -121,28 +148,32 @@ class SidebarRuntimeItem extends PureComponent { getString("aboutdebugging-sidebar-runtime-connection-status-connected") : getString("aboutdebugging-sidebar-runtime-connection-status-disconnected"); - return SidebarItem( - { - className: "sidebar-item--tall", - isSelected, - to: isConnected ? `/runtime/${encodeURIComponent(runtimeId)}` : null, - }, - dom.section( + return [ + SidebarItem( { - className: "sidebar-runtime-item__container", + className: "sidebar-item--tall", + key: "sidebar-item", + isSelected, + to: isConnected ? `/runtime/${encodeURIComponent(runtimeId)}` : null, }, - dom.img( + dom.section( { - className: "sidebar-runtime-item__icon ", - src: icon, - alt: connectionStatus, - title: connectionStatus, - } + className: "sidebar-runtime-item__container", + }, + dom.img( + { + className: "sidebar-runtime-item__icon ", + src: icon, + alt: connectionStatus, + title: connectionStatus, + } + ), + this.renderName(), + !isUnknown && !isConnected ? this.renderConnectButton() : null ), - this.renderName(), - !isUnknown && !isConnected ? this.renderConnectButton() : null - ) - ); + ), + this.renderConnectionError(), + ]; } } diff --git a/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js b/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js index 3a2d853d19c1..ad9e1be26531 100644 --- a/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js +++ b/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js @@ -76,18 +76,21 @@ function runtimesReducer(state = RuntimesState(), action) { switch (action.type) { case CONNECT_RUNTIME_START: { const { id } = action; - return _updateRuntimeById(id, { isConnecting: true }, state); + return _updateRuntimeById( + id, { isConnecting: true, isConnectionFailed: false }, state); } case CONNECT_RUNTIME_SUCCESS: { const { id, runtimeDetails, type } = action.runtime; remoteClientManager.setClient(id, type, runtimeDetails.clientWrapper.client); - return _updateRuntimeById(id, { isConnecting: false, runtimeDetails }, state); + return _updateRuntimeById( + id, { isConnecting: false, isConnectionFailed: false, runtimeDetails }, state); } case CONNECT_RUNTIME_FAILURE: { const { id } = action; - return _updateRuntimeById(id, { isConnecting: false }, state); + return _updateRuntimeById( + id, { isConnecting: false, isConnectionFailed: true }, state); } case DISCONNECT_RUNTIME_SUCCESS: { diff --git a/devtools/client/aboutdebugging-new/src/types/runtime.js b/devtools/client/aboutdebugging-new/src/types/runtime.js index da626c89f51e..a0c966e50f3a 100644 --- a/devtools/client/aboutdebugging-new/src/types/runtime.js +++ b/devtools/client/aboutdebugging-new/src/types/runtime.js @@ -119,6 +119,9 @@ const runtime = { // connected or has failures. isConnecting: PropTypes.bool.isRequired, + // this flag will be true when the connection failed. + isConnectionFailed: PropTypes.bool.isRequired, + // unknown runtimes are placeholders for devices where the runtime has not been started // yet. For instance an ADB device connected without a compatible runtime running. isUnknown: PropTypes.bool.isRequired, diff --git a/devtools/client/locales/en-US/aboutdebugging.ftl b/devtools/client/locales/en-US/aboutdebugging.ftl index f4ccb4f7c42f..8d0ea5ae0095 100644 --- a/devtools/client/locales/en-US/aboutdebugging.ftl +++ b/devtools/client/locales/en-US/aboutdebugging.ftl @@ -49,6 +49,9 @@ about-debugging-sidebar-item-connect-button = Connect # Text displayed in buttons found in sidebar items when the runtime is connecting. about-debugging-sidebar-item-connect-button-connecting = Connecting… +# Text displayed in buttons found in sidebar items when the connection failed. +about-debugging-sidebar-item-connect-button-connection-failed = Connection failed + # Temporary text displayed in sidebar items representing remote runtimes after # successfully connecting to them. Temporary UI, do not localize. about-debugging-sidebar-item-connected-label = Connected From 9439d08d5ccc86ac9cea4837a1ce34c6d22cf54e Mon Sep 17 00:00:00 2001 From: Daisuke Akatsuka Date: Tue, 2 Apr 2019 06:22:33 +0000 Subject: [PATCH 08/46] Bug 1505131: Show warning when the connecting is taking time. r=jdescottes,flod Depends on D25033 Differential Revision: https://phabricator.services.mozilla.com/D25034 --HG-- extra : moz-landing-system : lando --- .../src/actions/runtimes.js | 19 ++++++++++++ .../src/components/sidebar/Sidebar.js | 1 + .../components/sidebar/SidebarRuntimeItem.js | 26 ++++++++++++++++ .../aboutdebugging-new/src/constants.js | 1 + .../src/reducers/runtimes-state.js | 31 +++++++++++++++---- .../aboutdebugging-new/src/types/runtime.js | 4 +++ .../client/locales/en-US/aboutdebugging.ftl | 4 +++ 7 files changed, 80 insertions(+), 6 deletions(-) diff --git a/devtools/client/aboutdebugging-new/src/actions/runtimes.js b/devtools/client/aboutdebugging-new/src/actions/runtimes.js index d5fde9f63366..71457ac26dd1 100644 --- a/devtools/client/aboutdebugging-new/src/actions/runtimes.js +++ b/devtools/client/aboutdebugging-new/src/actions/runtimes.js @@ -24,6 +24,7 @@ const { remoteClientManager } = const { CONNECT_RUNTIME_FAILURE, + CONNECT_RUNTIME_NOT_RESPONDING, CONNECT_RUNTIME_START, CONNECT_RUNTIME_SUCCESS, DEBUG_TARGET_PANE, @@ -52,6 +53,8 @@ const { WATCH_RUNTIME_SUCCESS, } = require("../constants"); +const CONNECTION_TIMING_OUT_DELAY = 3000; + async function getRuntimeIcon(channel) { return (channel === "release" || channel === "beta" || channel === "aurora") ? `chrome://devtools/skin/images/aboutdebugging-firefox-${ channel }.svg` @@ -70,6 +73,13 @@ function onMultiE10sUpdated() { function connectRuntime(id) { return async (dispatch, getState) => { dispatch({ type: CONNECT_RUNTIME_START, id }); + const connectionNotRespondingTimer = setTimeout(() => { + // If connecting to the runtime takes time over CONNECTION_TIMING_OUT_DELAY, + // we assume the connection prompt is showing on the runtime, show a dialog + // to let user know that. + dispatch({ type: CONNECT_RUNTIME_NOT_RESPONDING, id }); + }, CONNECTION_TIMING_OUT_DELAY); + try { const runtime = findRuntimeById(id, getState().runtimes); const clientWrapper = await createClientForRuntime(runtime); @@ -136,6 +146,8 @@ function connectRuntime(id) { }); } catch (e) { dispatch({ type: CONNECT_RUNTIME_FAILURE, id, error: e }); + } finally { + clearTimeout(connectionNotRespondingTimer); } }; } @@ -146,6 +158,7 @@ function createThisFirefoxRuntime() { id: RUNTIMES.THIS_FIREFOX, isConnecting: false, isConnectionFailed: false, + isConnectionNotResponding: false, isUnknown: false, name: l10n.getString("about-debugging-this-firefox-runtime-name"), type: RUNTIMES.THIS_FIREFOX, @@ -306,6 +319,7 @@ function updateNetworkRuntimes(locations) { }, isConnecting: false, isConnectionFailed: false, + isConnectionNotResponding: false, isUnknown: false, name: location, type: RUNTIMES.NETWORK, @@ -328,6 +342,7 @@ function updateUSBRuntimes(adbRuntimes) { }, isConnecting: false, isConnectionFailed: false, + isConnectionNotResponding: false, isUnknown: adbRuntime.isUnknown(), name: adbRuntime.shortName, type: RUNTIMES.USB, @@ -374,6 +389,8 @@ function updateRemoteRuntimes(runtimes, type) { // - runtimeDetails (set by about:debugging after a successful connection) // - isConnecting (set by about:debugging during the connection) // - isConnectionFailed (set by about:debugging if connection was failed) + // - isConnectionNotResponding + // (set by about:debugging if connection is taking too much time) runtimes.forEach(runtime => { const existingRuntime = findRuntimeById(runtime.id, getState().runtimes); const isConnectionValid = existingRuntime && existingRuntime.runtimeDetails && @@ -382,6 +399,8 @@ function updateRemoteRuntimes(runtimes, type) { runtime.isConnecting = existingRuntime ? existingRuntime.isConnecting : false; runtime.isConnectionFailed = existingRuntime ? existingRuntime.isConnectionFailed : false; + runtime.isConnectionNotResponding = + existingRuntime ? existingRuntime.isConnectionNotResponding : false; }); const existingRuntimes = getAllRuntimes(getState().runtimes); diff --git a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js index 4b91e0c546b6..380e27752889 100644 --- a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js +++ b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js @@ -115,6 +115,7 @@ class Sidebar extends PureComponent { isConnected: runtimeHasDetails, isConnecting: runtime.isConnecting, isConnectionFailed: runtime.isConnectionFailed, + isConnectionNotResponding: runtime.isConnectionNotResponding, isSelected, isUnknown: runtime.isUnknown, name, diff --git a/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js b/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js index b971d8cf1cf1..e8061664a1c4 100644 --- a/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js +++ b/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js @@ -30,6 +30,7 @@ class SidebarRuntimeItem extends PureComponent { isConnected: PropTypes.bool.isRequired, isConnecting: PropTypes.bool.isRequired, isConnectionFailed: PropTypes.bool.isRequired, + isConnectionNotResponding: PropTypes.bool.isRequired, isSelected: PropTypes.bool.isRequired, isUnknown: PropTypes.bool.isRequired, name: PropTypes.string.isRequired, @@ -84,6 +85,30 @@ class SidebarRuntimeItem extends PureComponent { ); } + renderConnectionNotResponding() { + const { isConnectionNotResponding } = this.props; + + if (!isConnectionNotResponding) { + return null; + } + + const localizationId = + "about-debugging-sidebar-item-connect-button-connection-not-responding"; + + return Message( + { + level: MESSAGE_LEVEL.WARNING, + key: "connection-not-responding", + }, + Localized( + { + id: localizationId, + }, + dom.p({ className: "word-wrap-anywhere" }, localizationId) + ) + ); + } + renderName() { const { deviceName, getString, isUnknown, name } = this.props; @@ -173,6 +198,7 @@ class SidebarRuntimeItem extends PureComponent { ), ), this.renderConnectionError(), + this.renderConnectionNotResponding(), ]; } } diff --git a/devtools/client/aboutdebugging-new/src/constants.js b/devtools/client/aboutdebugging-new/src/constants.js index 2b41ff791fbd..444eb84a6b81 100644 --- a/devtools/client/aboutdebugging-new/src/constants.js +++ b/devtools/client/aboutdebugging-new/src/constants.js @@ -16,6 +16,7 @@ const actionTypes = { ADB_ADDON_UNINSTALL_FAILURE: "ADB_ADDON_UNINSTALL_FAILURE", ADB_ADDON_STATUS_UPDATED: "ADB_ADDON_STATUS_UPDATED", CONNECT_RUNTIME_FAILURE: "CONNECT_RUNTIME_FAILURE", + CONNECT_RUNTIME_NOT_RESPONDING: "CONNECT_RUNTIME_NOT_RESPONDING", CONNECT_RUNTIME_START: "CONNECT_RUNTIME_START", CONNECT_RUNTIME_SUCCESS: "CONNECT_RUNTIME_SUCCESS", DEBUG_TARGET_COLLAPSIBILITY_UPDATED: "DEBUG_TARGET_COLLAPSIBILITY_UPDATED", diff --git a/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js b/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js index ad9e1be26531..0580e28248d8 100644 --- a/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js +++ b/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js @@ -6,6 +6,7 @@ const { CONNECT_RUNTIME_FAILURE, + CONNECT_RUNTIME_NOT_RESPONDING, CONNECT_RUNTIME_START, CONNECT_RUNTIME_SUCCESS, DISCONNECT_RUNTIME_SUCCESS, @@ -76,21 +77,39 @@ function runtimesReducer(state = RuntimesState(), action) { switch (action.type) { case CONNECT_RUNTIME_START: { const { id } = action; - return _updateRuntimeById( - id, { isConnecting: true, isConnectionFailed: false }, state); + const updatedState = { + isConnecting: true, + isConnectionFailed: false, + isConnectionNotResponding: false, + }; + return _updateRuntimeById(id, updatedState, state); + } + + case CONNECT_RUNTIME_NOT_RESPONDING: { + const { id } = action; + return _updateRuntimeById(id, { isConnectionNotResponding: true }, state); } case CONNECT_RUNTIME_SUCCESS: { const { id, runtimeDetails, type } = action.runtime; remoteClientManager.setClient(id, type, runtimeDetails.clientWrapper.client); - return _updateRuntimeById( - id, { isConnecting: false, isConnectionFailed: false, runtimeDetails }, state); + const updatedState = { + isConnecting: false, + isConnectionFailed: false, + isConnectionNotResponding: false, + runtimeDetails, + }; + return _updateRuntimeById(id, updatedState, state); } case CONNECT_RUNTIME_FAILURE: { const { id } = action; - return _updateRuntimeById( - id, { isConnecting: false, isConnectionFailed: true }, state); + const updatedState = { + isConnecting: false, + isConnectionFailed: true, + isConnectionNotResponding: false, + }; + return _updateRuntimeById(id, updatedState, state); } case DISCONNECT_RUNTIME_SUCCESS: { diff --git a/devtools/client/aboutdebugging-new/src/types/runtime.js b/devtools/client/aboutdebugging-new/src/types/runtime.js index a0c966e50f3a..4aeec1b9b266 100644 --- a/devtools/client/aboutdebugging-new/src/types/runtime.js +++ b/devtools/client/aboutdebugging-new/src/types/runtime.js @@ -122,6 +122,10 @@ const runtime = { // this flag will be true when the connection failed. isConnectionFailed: PropTypes.bool.isRequired, + // will be true if connecting to runtime is taking time, will be false after connecting + // or failing. + isConnectionNotResponding: PropTypes.bool.isRequired, + // unknown runtimes are placeholders for devices where the runtime has not been started // yet. For instance an ADB device connected without a compatible runtime running. isUnknown: PropTypes.bool.isRequired, diff --git a/devtools/client/locales/en-US/aboutdebugging.ftl b/devtools/client/locales/en-US/aboutdebugging.ftl index 8d0ea5ae0095..4fdb863bf9c2 100644 --- a/devtools/client/locales/en-US/aboutdebugging.ftl +++ b/devtools/client/locales/en-US/aboutdebugging.ftl @@ -52,6 +52,10 @@ about-debugging-sidebar-item-connect-button-connecting = Connecting… # Text displayed in buttons found in sidebar items when the connection failed. about-debugging-sidebar-item-connect-button-connection-failed = Connection failed +# Text displayed in connection warning on sidebar item of the runtime when connecting to +# the runtime is taking too much time. +about-debugging-sidebar-item-connect-button-connection-not-responding = Connection still pending, check for messages on the target browser + # Temporary text displayed in sidebar items representing remote runtimes after # successfully connecting to them. Temporary UI, do not localize. about-debugging-sidebar-item-connected-label = Connected From 6e1f56419f97f675ad8cf0e795c1f93b3723652c Mon Sep 17 00:00:00 2001 From: Daisuke Akatsuka Date: Tue, 2 Apr 2019 06:44:32 +0000 Subject: [PATCH 09/46] Bug 1505131: Add a test for connection state on sidebar. r=jdescottes Depends on D25033 Differential Revision: https://phabricator.services.mozilla.com/D25565 --HG-- extra : moz-landing-system : lando --- .../components/sidebar/SidebarRuntimeItem.js | 2 + .../test/browser/browser.ini | 1 + ...aboutdebugging_sidebar_connection_state.js | 78 +++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_connection_state.js diff --git a/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js b/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js index e8061664a1c4..1690a4a44ffb 100644 --- a/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js +++ b/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js @@ -75,6 +75,7 @@ class SidebarRuntimeItem extends PureComponent { { level: MESSAGE_LEVEL.ERROR, key: "connection-error", + className: "qa-connection-error", }, Localized( { @@ -99,6 +100,7 @@ class SidebarRuntimeItem extends PureComponent { { level: MESSAGE_LEVEL.WARNING, key: "connection-not-responding", + className: "qa-connection-not-responding", }, Localized( { diff --git a/devtools/client/aboutdebugging-new/test/browser/browser.ini b/devtools/client/aboutdebugging-new/test/browser/browser.ini index 303c09cc72ed..71bf45b43abf 100644 --- a/devtools/client/aboutdebugging-new/test/browser/browser.ini +++ b/devtools/client/aboutdebugging-new/test/browser/browser.ini @@ -86,6 +86,7 @@ skip-if = debug || asan || serviceworker_e10s # Frequent intermittent failures, [browser_aboutdebugging_serviceworker_timeout.js] skip-if = debug || asan # Frequent intermittent failures, Bug 1522800 [browser_aboutdebugging_serviceworker_unregister.js] +[browser_aboutdebugging_sidebar_connection_state.js] [browser_aboutdebugging_sidebar_network_runtimes.js] [browser_aboutdebugging_sidebar_usb_runtime.js] [browser_aboutdebugging_sidebar_usb_runtime_connect.js] diff --git a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_connection_state.js b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_connection_state.js new file mode 100644 index 000000000000..0fe82b8051de --- /dev/null +++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_connection_state.js @@ -0,0 +1,78 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const RUNTIME_ID = "test-runtime-id"; +const RUNTIME_NAME = "test runtime name"; +const RUNTIME_DEVICE_NAME = "test device name"; +const RUNTIME_SHORT_NAME = "test short name"; + +// Test following connection state tests. +// * Connect button label and state will change during connecting. +// * Show error message if connection failed. +// * Show warninng if connection has been taken time. +add_task(async function() { + const mocks = new Mocks(); + + const { document, tab } = await openAboutDebugging(); + + mocks.createUSBRuntime(RUNTIME_ID, { + name: RUNTIME_NAME, + deviceName: RUNTIME_DEVICE_NAME, + shortName: RUNTIME_SHORT_NAME, + }); + mocks.emitUSBUpdate(); + + info("Wait until the USB sidebar item appears"); + await waitUntil(() => findSidebarItemByText(RUNTIME_DEVICE_NAME, document)); + const usbRuntimeSidebarItem = findSidebarItemByText(RUNTIME_DEVICE_NAME, document); + const connectButton = usbRuntimeSidebarItem.querySelector(".js-connect-button"); + + info("Simulate to happen connection error"); + mocks.runtimeClientFactoryMock.createClientForRuntime = async (runtime) => { + throw new Error("Dummy connection error"); + }; + + info("Check whether the error message displayed after clicking connect button"); + connectButton.click(); + await waitUntil(() => document.querySelector(".qa-connection-error")); + ok(true, "Error message displays when connection failed"); + + info("Simulate to wait for the connection prompt on remote runtime"); + let resumeConnection; + const resumeConnectionPromise = new Promise(r => { + resumeConnection = r; + }); + mocks.runtimeClientFactoryMock.createClientForRuntime = async (runtime) => { + await resumeConnectionPromise; + return mocks._clients[runtime.type][runtime.id]; + }; + + info("Click on the connect button and wait until it disappears"); + connectButton.click(); + info("Check whether a warning of connection not responding displays after 3sec"); + await waitUntil(() => document.querySelector(".qa-connection-not-responding")); + ok(document.querySelector(".qa-connection-not-responding"), + "A warning of connection not responding displays"); + ok(connectButton.disabled, "State of the connect button displays"); + ok(connectButton.textContent.startsWith("Connecting"), + "Label of the connect button changes"); + ok(!document.querySelector(".qa-connection-error"), "Error message disappears"); + + info("Unblock the connection and check the message and connect button disappear"); + resumeConnection(); + await waitUntil(() => !usbRuntimeSidebarItem.querySelector(".js-connect-button")); + ok(!document.querySelector(".qa-connection-error"), "Error disappears"); + ok(!document.querySelector(".qa-connection-not-responding"), "Warning disappears"); + + info("Remove a USB runtime"); + mocks.removeUSBRuntime(RUNTIME_ID); + mocks.emitUSBUpdate(); + + info("Wait until the USB sidebar item disappears"); + await waitUntil(() => !findSidebarItemByText(RUNTIME_DEVICE_NAME, document) && + !findSidebarItemByText(RUNTIME_SHORT_NAME, document)); + + await removeTab(tab); +}); From fa6e04c6668b13cd56e2418914fb9503a185dc3c Mon Sep 17 00:00:00 2001 From: violet Date: Tue, 2 Apr 2019 06:08:23 +0000 Subject: [PATCH 10/46] Bug 1540703 - Should also reflow SVGTextFrame for non-display active child of switch element r=longsonr When happens to have an active child that is non-display, we should still reflow all its descendant SVGTextFrame for consistency. Differential Revision: https://phabricator.services.mozilla.com/D25699 --HG-- extra : moz-landing-system : lando --- layout/svg/crashtests/951904-1.html | 9 +++++++++ layout/svg/nsSVGSwitchFrame.cpp | 17 ++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/layout/svg/crashtests/951904-1.html b/layout/svg/crashtests/951904-1.html index 55cfa7f83664..7a1d1d4dd4fa 100644 --- a/layout/svg/crashtests/951904-1.html +++ b/layout/svg/crashtests/951904-1.html @@ -21,6 +21,14 @@ + + + + Vendredi + + + + diff --git a/layout/svg/nsSVGSwitchFrame.cpp b/layout/svg/nsSVGSwitchFrame.cpp index a62a387da62b..a473bc9e3ef5 100644 --- a/layout/svg/nsSVGSwitchFrame.cpp +++ b/layout/svg/nsSVGSwitchFrame.cpp @@ -139,20 +139,23 @@ nsIFrame* nsSVGSwitchFrame::GetFrameForPoint(const gfxPoint& aPoint) { return nullptr; } +static bool shouldReflowSVGTextFrameInside(nsIFrame* aFrame) { + return aFrame->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer) || + aFrame->IsSVGForeignObjectFrame() || + !aFrame->IsFrameOfType(nsIFrame::eSVG); +} + void nsSVGSwitchFrame::AlwaysReflowSVGTextFrameDoForOneKid(nsIFrame* aKid) { if (!NS_SUBTREE_DIRTY(aKid)) { return; } - LayoutFrameType type = aKid->Type(); - if (type == LayoutFrameType::SVGText) { + if (aKid->IsSVGTextFrame()) { MOZ_ASSERT(!aKid->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY), "A non-display SVGTextFrame directly contained in a display " "container?"); static_cast(aKid)->ReflowSVG(); - } else if (aKid->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer) || - type == LayoutFrameType::SVGForeignObject || - !aKid->IsFrameOfType(nsIFrame::eSVG)) { + } else if (shouldReflowSVGTextFrameInside(aKid)) { if (!aKid->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) { for (nsIFrame* kid : aKid->PrincipalChildList()) { AlwaysReflowSVGTextFrameDoForOneKid(kid); @@ -222,6 +225,10 @@ void nsSVGSwitchFrame::ReflowSVG() { // nsLayoutUtils::UnionChildOverflow since SVG frame's all use the same // frame list, and we're iterating over that list now anyway. ConsiderChildOverflow(overflowRects, child); + } else if (child && shouldReflowSVGTextFrameInside(child)) { + MOZ_ASSERT(child->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY), + "Check for this explicitly in the |if|, then"); + ReflowSVGNonDisplayText(child); } if (isFirstReflow) { From a4d168a04fab18b3839ee5d75a364fa921f66a72 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 2 Apr 2019 03:31:26 +0000 Subject: [PATCH 11/46] Bug 1540788 - Make mach bootstrap choose arm target depending on the rust version. r=nalexander Bootstrap is happy with rust version 1.32, but that version of rust doesn't support the thumbv7neon target that we're trying to install since bug 1539005. So install the armv7 target when rust is version 1.32. Differential Revision: https://phabricator.services.mozilla.com/D25683 --HG-- extra : moz-landing-system : lando --- python/mozboot/mozboot/base.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/python/mozboot/mozboot/base.py b/python/mozboot/mozboot/base.py index 630b0472ef62..1f5316d62f8d 100644 --- a/python/mozboot/mozboot/base.py +++ b/python/mozboot/mozboot/base.py @@ -673,7 +673,7 @@ class BaseBootstrapper(object): print('Your version of Rust (%s) is new enough.' % version) rustup = self.which('rustup', cargo_bin) if rustup: - self.ensure_rust_targets(rustup) + self.ensure_rust_targets(rustup, version) return if version: @@ -697,7 +697,7 @@ class BaseBootstrapper(object): print('Will try to install Rust.') self.install_rust() - def ensure_rust_targets(self, rustup): + def ensure_rust_targets(self, rustup, rust_version): """Make sure appropriate cross target libraries are installed.""" target_list = subprocess.check_output([rustup, 'target', 'list']) targets = [line.split()[0] for line in target_list.splitlines() @@ -712,7 +712,11 @@ class BaseBootstrapper(object): if 'mobile_android' in self.application: # Let's add the most common targets. - android_targets = ('thumbv7neon-linux-androideabi', + if LooseVersion(rust_version) < '1.33': + arm_target = 'armv7-linux-androideabi' + else: + arm_target = 'thumbv7neon-linux-androideabi' + android_targets = (arm_target, 'aarch64-linux-android', 'i686-linux-android', 'x86_64-linux-android', ) From 0d09d08c72a275732ccfc1885e3a20f34142dd76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarek=20Ziad=C3=A9?= Date: Tue, 2 Apr 2019 07:38:41 +0000 Subject: [PATCH 12/46] Bug 1527620 - Add youtube streaming tests - r=whimboo This patch introduces a new marionette media test along with a Youtube test. To run the Youtube streaming test locally: ./mach marionette-test dom/media/test/marionette/test_youtube.py -vv --gecko-log - Differential Revision: https://phabricator.services.mozilla.com/D23644 --HG-- extra : moz-landing-system : lando --- dom/media/moz.build | 4 + dom/media/test/marionette/manifest.ini | 4 + dom/media/test/marionette/test_youtube.py | 27 + .../marionette/yttest/BZP1rYjoBgI.manifest | 10 + dom/media/test/marionette/yttest/__init__.py | 1 + .../test/marionette/yttest/debug_info.js | 18 + dom/media/test/marionette/yttest/download.py | 17 + .../test/marionette/yttest/duration_test.js | 21 + dom/media/test/marionette/yttest/force_hd.js | 73 ++ dom/media/test/marionette/yttest/playback.py | 636 ++++++++++++++++++ dom/media/test/marionette/yttest/record.py | 34 + dom/media/test/marionette/yttest/support.py | 88 +++ .../test/marionette/yttest/until_end_test.js | 18 + .../yttest/video_playback_quality.js | 7 + dom/media/test/marionette/yttest/ytpage.py | 82 +++ .../mozbuild/mozbuild/action/test_archive.py | 3 +- python/mozbuild/mozbuild/frontend/context.py | 4 + taskcluster/ci/test/marionette.yml | 9 + taskcluster/ci/test/test-platforms.yml | 4 + taskcluster/ci/test/test-sets.yml | 3 + .../marionette_harness/tests/stream-tests.ini | 2 + .../mozproxy/mozproxy/backends/mitm.py | 37 +- testing/mozbase/mozproxy/mozproxy/utils.py | 26 +- 23 files changed, 1105 insertions(+), 23 deletions(-) create mode 100644 dom/media/test/marionette/manifest.ini create mode 100644 dom/media/test/marionette/test_youtube.py create mode 100644 dom/media/test/marionette/yttest/BZP1rYjoBgI.manifest create mode 100644 dom/media/test/marionette/yttest/__init__.py create mode 100644 dom/media/test/marionette/yttest/debug_info.js create mode 100644 dom/media/test/marionette/yttest/download.py create mode 100644 dom/media/test/marionette/yttest/duration_test.js create mode 100644 dom/media/test/marionette/yttest/force_hd.js create mode 100644 dom/media/test/marionette/yttest/playback.py create mode 100644 dom/media/test/marionette/yttest/record.py create mode 100644 dom/media/test/marionette/yttest/support.py create mode 100644 dom/media/test/marionette/yttest/until_end_test.js create mode 100644 dom/media/test/marionette/yttest/video_playback_quality.js create mode 100644 dom/media/test/marionette/yttest/ytpage.py create mode 100644 testing/marionette/harness/marionette_harness/tests/stream-tests.ini diff --git a/dom/media/moz.build b/dom/media/moz.build index ed6e8063aef4..5c076d7a6e02 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -359,3 +359,7 @@ if CONFIG['CC_TYPE'] in ('clang', 'gcc'): ] FINAL_LIBRARY = 'xul' + +MARIONETTE_DOM_MEDIA_MANIFESTS += [ + 'test/marionette/manifest.ini' +] diff --git a/dom/media/test/marionette/manifest.ini b/dom/media/test/marionette/manifest.ini new file mode 100644 index 000000000000..687a7f50da34 --- /dev/null +++ b/dom/media/test/marionette/manifest.ini @@ -0,0 +1,4 @@ +[DEFAULT] +run-if = buildapp == 'browser' + +[test_youtube.py] diff --git a/dom/media/test/marionette/test_youtube.py b/dom/media/test/marionette/test_youtube.py new file mode 100644 index 000000000000..a90d14e0c725 --- /dev/null +++ b/dom/media/test/marionette/test_youtube.py @@ -0,0 +1,27 @@ +# 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/. +import sys +import os + +sys.path.append(os.path.dirname(__file__)) +from yttest.support import VideoStreamTestCase + + +class YoutubeTest(VideoStreamTestCase): + + # bug 1513511 + def test_stream_30_seconds(self): + # XXX use the V9 video we will settle on. + with self.youtube_video("BZP1rYjoBgI") as page: + res = page.run_test() + self.assertLess(res["droppedVideoFrames"], res["totalVideoFrames"] * 0.04) + # extracting in/out from the debugInfo + video_state = res["debugInfo"][7] + video_in = int(video_state.split(" ")[10].split("=")[-1]) + video_out = int(video_state.split(" ")[11].split("=")[-1]) + # what's the ratio ? we want 99%+ + if video_out == video_in: + return + in_out_ratio = float(video_out) / float(video_in) * 100 + self.assertMore(in_out_ratio, 99.0) diff --git a/dom/media/test/marionette/yttest/BZP1rYjoBgI.manifest b/dom/media/test/marionette/yttest/BZP1rYjoBgI.manifest new file mode 100644 index 000000000000..30ab8e83a3f8 --- /dev/null +++ b/dom/media/test/marionette/yttest/BZP1rYjoBgI.manifest @@ -0,0 +1,10 @@ +[ + { + "size": 20396656, + "visibility": "public", + "digest": "ccdecb515cadd243608898f38d74c23162fccb9246fee3084834c23d3a57710ed24c7c5dcc9b8bc6f5c3acb5fc0f3be144de08aa14d93e7dbbd372ec6166c138", + "algorithm": "sha512", + "filename": "BZP1rYjoBgI.tar.gz", + "unpack": true + } +] diff --git a/dom/media/test/marionette/yttest/__init__.py b/dom/media/test/marionette/yttest/__init__.py new file mode 100644 index 000000000000..792d6005489e --- /dev/null +++ b/dom/media/test/marionette/yttest/__init__.py @@ -0,0 +1 @@ +# diff --git a/dom/media/test/marionette/yttest/debug_info.js b/dom/media/test/marionette/yttest/debug_info.js new file mode 100644 index 000000000000..2009e3ff4028 --- /dev/null +++ b/dom/media/test/marionette/yttest/debug_info.js @@ -0,0 +1,18 @@ +video.mozRequestDebugInfo().then(debugInfo => { + try { + debugInfo = debugInfo.replace(/\t/g, '').split(/\n/g); + var JSONDebugInfo = "{"; + for(let g =0; g { + if (video.currentTime >= %(duration)s) { + video.pause(); + %(video_playback_quality)s + %(debug_info)s + } + } +); + +video.play(); + diff --git a/dom/media/test/marionette/yttest/force_hd.js b/dom/media/test/marionette/yttest/force_hd.js new file mode 100644 index 000000000000..ab3d2b54db48 --- /dev/null +++ b/dom/media/test/marionette/yttest/force_hd.js @@ -0,0 +1,73 @@ +// This parts forces the highest definition +// https://addons.mozilla.org/en-US/firefox/addon/youtube-auto-hd-lq/ +// licence: MPL 2.0 +var config = { + "HD": true, + "LQ": false, + "ID": "auto-hd-lq-for-ytb", + "type": function (t) { + config.HD = t === 'hd'; + config.LQ = t === 'lq'; + }, + "quality": function () { + if (config.HD || config.LQ) { + var youtubePlayerListener = function (LQ, HD) { + return function youtubePlayerListener (e) { + if (e === 1) { + var player = document.getElementById('movie_player'); + if (player) { + var levels = player.getAvailableQualityLevels(); + if (levels.length) { + var q = (HD && levels[0]) ? levels[0] : ((LQ && levels[levels.length - 2]) ? levels[levels.length - 2] : null); + if (q) { + player.setPlaybackQuality(q); + player.setPlaybackQualityRange(q, q); + } + } + } + } + } + } + /* */ + var inject = function () { + var action = function () { + var player = document.getElementById('movie_player'); + if (player && player.addEventListener && player.getPlayerState) { + player.addEventListener("onStateChange", "youtubePlayerListener"); + } else window.setTimeout(action, 1000); + }; + /* */ + action(); + }; + var script = document.getElementById(config.ID); + if (!script) { + script = document.createElement("script"); + script.setAttribute("type", "text/javascript"); + script.setAttribute("id", config.ID); + document.documentElement.appendChild(script); + } + /* */ + script.textContent = "var youtubePlayerListener = (" + youtubePlayerListener + ')(' + config.LQ + ',' + config.HD + ');(' + inject + ')();'; + } + } +}; + + if (/^https?:\/\/www\.youtube.com\/watch\?/.test(document.location.href)) config.quality(); + var content = document.getElementById('content'); + if (content) { + var observer = new window.MutationObserver(function (e) { + e.forEach(function (m) { + if (m.addedNodes !== null) { + for (var i = 0; i < m.addedNodes.length; i++) { + if (m.addedNodes[i].id === 'movie_player') { + config.quality(); + return; + } + } + } + }); + }); + /* */ + observer.observe(content, {"childList": true, "subtree": true}); + } + diff --git a/dom/media/test/marionette/yttest/playback.py b/dom/media/test/marionette/yttest/playback.py new file mode 100644 index 000000000000..ffdba72c1d27 --- /dev/null +++ b/dom/media/test/marionette/yttest/playback.py @@ -0,0 +1,636 @@ +# 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/. +""" +MITM Script used to play back media files when a YT video is played. + +This is a self-contained script that should not import anything else +except modules from the standard library and mitmproxy modules. +""" +import os +import sys +import datetime +import time + + +itags = { + "5": { + "Extension": "flv", + "Resolution": "240p", + "VideoEncoding": "Sorenson H.283", + "AudioEncoding": "mp3", + "Itag": 5, + "AudioBitrate": 64, + }, + "6": { + "Extension": "flv", + "Resolution": "270p", + "VideoEncoding": "Sorenson H.263", + "AudioEncoding": "mp3", + "Itag": 6, + "AudioBitrate": 64, + }, + "13": { + "Extension": "3gp", + "Resolution": "", + "VideoEncoding": "MPEG-4 Visual", + "AudioEncoding": "aac", + "Itag": 13, + "AudioBitrate": 0, + }, + "17": { + "Extension": "3gp", + "Resolution": "144p", + "VideoEncoding": "MPEG-4 Visual", + "AudioEncoding": "aac", + "Itag": 17, + "AudioBitrate": 24, + }, + "18": { + "Extension": "mp4", + "Resolution": "360p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 18, + "AudioBitrate": 96, + }, + "22": { + "Extension": "mp4", + "Resolution": "720p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 22, + "AudioBitrate": 192, + }, + "34": { + "Extension": "flv", + "Resolution": "480p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 34, + "AudioBitrate": 128, + }, + "35": { + "Extension": "flv", + "Resolution": "360p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 35, + "AudioBitrate": 128, + }, + "36": { + "Extension": "3gp", + "Resolution": "240p", + "VideoEncoding": "MPEG-4 Visual", + "AudioEncoding": "aac", + "Itag": 36, + "AudioBitrate": 36, + }, + "37": { + "Extension": "mp4", + "Resolution": "1080p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 37, + "AudioBitrate": 192, + }, + "38": { + "Extension": "mp4", + "Resolution": "3072p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 38, + "AudioBitrate": 192, + }, + "43": { + "Extension": "webm", + "Resolution": "360p", + "VideoEncoding": "VP8", + "AudioEncoding": "vorbis", + "Itag": 43, + "AudioBitrate": 128, + }, + "44": { + "Extension": "webm", + "Resolution": "480p", + "VideoEncoding": "VP8", + "AudioEncoding": "vorbis", + "Itag": 44, + "AudioBitrate": 128, + }, + "45": { + "Extension": "webm", + "Resolution": "720p", + "VideoEncoding": "VP8", + "AudioEncoding": "vorbis", + "Itag": 45, + "AudioBitrate": 192, + }, + "46": { + "Extension": "webm", + "Resolution": "1080p", + "VideoEncoding": "VP8", + "AudioEncoding": "vorbis", + "Itag": 46, + "AudioBitrate": 192, + }, + "82": { + "Extension": "mp4", + "Resolution": "360p", + "VideoEncoding": "H.264", + "Itag": 82, + "AudioBitrate": 96, + }, + "83": { + "Extension": "mp4", + "Resolution": "240p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 83, + "AudioBitrate": 96, + }, + "84": { + "Extension": "mp4", + "Resolution": "720p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 84, + "AudioBitrate": 192, + }, + "85": { + "Extension": "mp4", + "Resolution": "1080p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 85, + "AudioBitrate": 192, + }, + "100": { + "Extension": "webm", + "Resolution": "360p", + "VideoEncoding": "VP8", + "AudioEncoding": "vorbis", + "Itag": 100, + "AudioBitrate": 128, + }, + "101": { + "Extension": "webm", + "Resolution": "360p", + "VideoEncoding": "VP8", + "AudioEncoding": "vorbis", + "Itag": 101, + "AudioBitrate": 192, + }, + "102": { + "Extension": "webm", + "Resolution": "720p", + "VideoEncoding": "VP8", + "AudioEncoding": "vorbis", + "Itag": 102, + "AudioBitrate": 192, + }, + "133": { + "Extension": "mp4", + "Resolution": "240p", + "VideoEncoding": "H.264", + "AudioEncoding": "", + "Itag": 133, + "AudioBitrate": 0, + }, + "134": { + "Extension": "mp4", + "Resolution": "360p", + "VideoEncoding": "H.264", + "AudioEncoding": "", + "Itag": 134, + "AudioBitrate": 0, + }, + "135": { + "Extension": "mp4", + "Resolution": "480p", + "VideoEncoding": "H.264", + "AudioEncoding": "", + "Itag": 135, + "AudioBitrate": 0, + }, + "136": { + "Extension": "mp4", + "Resolution": "720p", + "VideoEncoding": "H.264", + "AudioEncoding": "", + "Itag": 136, + "AudioBitrate": 0, + }, + "137": { + "Extension": "mp4", + "Resolution": "1080p", + "VideoEncoding": "H.264", + "AudioEncoding": "", + "Itag": 137, + "AudioBitrate": 0, + }, + "138": { + "Extension": "mp4", + "Resolution": "2160p", + "VideoEncoding": "H.264", + "AudioEncoding": "", + "Itag": 138, + "AudioBitrate": 0, + }, + "160": { + "Extension": "mp4", + "Resolution": "144p", + "VideoEncoding": "H.264", + "AudioEncoding": "", + "Itag": 160, + "AudioBitrate": 0, + }, + "242": { + "Extension": "webm", + "Resolution": "240p", + "VideoEncoding": "VP9", + "AudioEncoding": "", + "Itag": 242, + "AudioBitrate": 0, + }, + "243": { + "Extension": "webm", + "Resolution": "360p", + "VideoEncoding": "VP9", + "AudioEncoding": "", + "Itag": 243, + "AudioBitrate": 0, + }, + "244": { + "Extension": "webm", + "Resolution": "480p", + "VideoEncoding": "VP9", + "AudioEncoding": "", + "Itag": 244, + "AudioBitrate": 0, + }, + "247": { + "Extension": "webm", + "Resolution": "720p", + "VideoEncoding": "VP9", + "AudioEncoding": "", + "Itag": 247, + "AudioBitrate": 0, + }, + "248": { + "Extension": "webm", + "Resolution": "1080p", + "VideoEncoding": "VP9", + "AudioEncoding": "", + "Itag": 248, + "AudioBitrate": 9, + }, + "264": { + "Extension": "mp4", + "Resolution": "1440p", + "VideoEncoding": "H.264", + "AudioEncoding": "", + "Itag": 264, + "AudioBitrate": 0, + }, + "266": { + "Extension": "mp4", + "Resolution": "2160p", + "VideoEncoding": "H.264", + "AudioEncoding": "", + "Itag": 266, + "AudioBitrate": 0, + }, + "271": { + "Extension": "webm", + "Resolution": "1440p", + "VideoEncoding": "VP9", + "AudioEncoding": "", + "Itag": 271, + "AudioBitrate": 0, + }, + "272": { + "Extension": "webm", + "Resolution": "2160p", + "VideoEncoding": "VP9", + "AudioEncoding": "", + "Itag": 272, + "AudioBitrate": 0, + }, + "278": { + "Extension": "webm", + "Resolution": "144p", + "VideoEncoding": "VP9", + "AudioEncoding": "", + "Itag": 278, + "AudioBitrate": 0, + }, + "298": { + "Extension": "mp4", + "Resolution": "720p", + "VideoEncoding": "H.264", + "AudioEncoding": "", + "Itag": 298, + "AudioBitrate": 0, + }, + "299": { + "Extension": "mp4", + "Resolution": "1080p", + "VideoEncoding": "H.264", + "AudioEncoding": "", + "Itag": 299, + "AudioBitrate": 0, + }, + "302": { + "Extension": "webm", + "Resolution": "720p", + "VideoEncoding": "VP9", + "AudioEncoding": "", + "Itag": 302, + "AudioBitrate": 0, + }, + "303": { + "Extension": "webm", + "Resolution": "1080p", + "VideoEncoding": "VP9", + "AudioEncoding": "", + "Itag": 303, + "AudioBitrate": 0, + }, + "139": { + "Extension": "mp4", + "Resolution": "", + "VideoEncoding": "", + "AudioEncoding": "aac", + "Itag": 139, + "AudioBitrate": 48, + }, + "140": { + "Extension": "mp4", + "Resolution": "", + "VideoEncoding": "", + "AudioEncoding": "aac", + "Itag": 140, + "AudioBitrate": 128, + }, + "141": { + "Extension": "mp4", + "Resolution": "", + "VideoEncoding": "", + "AudioEncoding": "aac", + "Itag": 141, + "AudioBitrate": 256, + }, + "171": { + "Extension": "webm", + "Resolution": "", + "VideoEncoding": "", + "AudioEncoding": "vorbis", + "Itag": 171, + "AudioBitrate": 128, + }, + "172": { + "Extension": "webm", + "Resolution": "", + "VideoEncoding": "", + "AudioEncoding": "vorbis", + "Itag": 172, + "AudioBitrate": 192, + }, + "249": { + "Extension": "webm", + "Resolution": "", + "VideoEncoding": "", + "AudioEncoding": "opus", + "Itag": 249, + "AudioBitrate": 50, + }, + "250": { + "Extension": "webm", + "Resolution": "", + "VideoEncoding": "", + "AudioEncoding": "opus", + "Itag": 250, + "AudioBitrate": 70, + }, + "251": { + "Extension": "webm", + "Resolution": "", + "VideoEncoding": "", + "AudioEncoding": "opus", + "Itag": 251, + "AudioBitrate": 160, + }, + "92": { + "Extension": "ts", + "Resolution": "240p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 92, + "AudioBitrate": 48, + }, + "93": { + "Extension": "ts", + "Resolution": "480p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 93, + "AudioBitrate": 128, + }, + "94": { + "Extension": "ts", + "Resolution": "720p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 94, + "AudioBitrate": 128, + }, + "95": { + "Extension": "ts", + "Resolution": "1080p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 95, + "AudioBitrate": 256, + }, + "96": { + "Extension": "ts", + "Resolution": "720p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 96, + "AudioBitrate": 256, + }, + "120": { + "Extension": "flv", + "Resolution": "720p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 120, + "AudioBitrate": 128, + }, + "127": { + "Extension": "ts", + "Resolution": "", + "VideoEncoding": "", + "AudioEncoding": "aac", + "Itag": 127, + "AudioBitrate": 96, + }, + "128": { + "Extension": "ts", + "Resolution": "", + "VideoEncoding": "", + "AudioEncoding": "aac", + "Itag": 128, + "AudioBitrate": 96, + }, + "132": { + "Extension": "ts", + "Resolution": "240p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 132, + "AudioBitrate": 48, + }, + "151": { + "Extension": "ts", + "Resolution": "720p", + "VideoEncoding": "H.264", + "AudioEncoding": "aac", + "Itag": 151, + "AudioBitrate": 24, + }, +} + + +def repr_itag(itag): + itag_info = [" %s: %s" % (k, v) for k, v in get_itag_info(itag).items()] + return "\n".join(itag_info) + + +def get_itag_info(itag): + return itags[itag] + + +def log(msg): + print(msg) + + +_HERE = os.path.dirname(__file__) +if "MOZPROXY_DIR" in os.environ: + _DEFAULT_DATA_DIR = os.environ["MOZPROXY_DIR"] +else: + _DEFAULT_DATA_DIR = os.path.join(_HERE, "..", "data") + +_HEADERS = { + b"Last-Modified": b"Mon, 10 Dec 2018 19:39:24 GMT", + b"Content-Type": b"video/webm", + b"Date": b"Wed, 02 Jan 2019 15:14:06 GMT", + b"Expires": b"Wed, 02 Jan 2019 15:14:06 GMT", + b"Cache-Control": b"private, max-age=21292", + b"Accept-Ranges": b"bytes", + b"Content-Length": b"173448", + b"Connection": b"keep-alive", + b"Alt-Svc": b'quic=":443"; ma=2592000; v="44,43,39,35"', + b"Access-Control-Allow-Origin": b"https://www.youtube.com", + b"Access-Control-Allow-Credentials": b"true", + b"Timing-Allow-Origin": b"https://www.youtube.com", + b"Access-Control-Expose-Headers": ( + b"Client-Protocol, Content-Length, " + b"Content-Type, X-Bandwidth-Est, " + b"X-Bandwidth-Est2, X-Bandwidth-Est3, " + b"X-Bandwidth-App-Limited, " + b"X-Bandwidth-Est-App-Limited, " + b"X-Bandwidth-Est-Comp, X-Bandwidth-Avg, " + b"X-Head-Time-Millis, X-Head-Time-Sec, " + b"X-Head-Seqnum, X-Response-Itag, " + b"X-Restrict-Formats-Hint, " + b"X-Sequence-Num, X-Segment-Lmt, " + b"X-Walltime-Ms" + ), + b"X-Restrict-Formats-Hint": b"None", + b"X-Content-Type-Options": b"nosniff", + b"Server": b"gvs 1.0", +} + + +def get_cached_data(request, datadir=_DEFAULT_DATA_DIR): + query_args = dict(request.query) + mime = query_args["mime"] + file_id = query_args["id"] + file_range = query_args["range"] + itag = query_args["itag"] + log("Request File %s - %s" % (file_id, mime)) + log("Requested range %s" % file_range) + log("Requested quality\n%s" % repr_itag(itag)) + frange = file_range.split("-") + range_start, range_end = int(frange[0]), int(frange[1]) + video_id = sys.argv[-1].split(".")[0] + fn = "%s-%s-%s.%s" % (video_id, itag, mime.replace("/", ""), mime.split("/")[-1]) + fn = os.path.join(datadir, fn) + if not os.path.exists(fn): + raise Exception("no file at %s" % fn) + with open(fn, "rb") as f: + data = f.read() + data = data[range_start : range_end + 1] # noqa: E203 + headers = dict(_HEADERS) + headers[b"Content-Type"] = bytes(mime, "utf8") + headers[b"Content-Length"] = bytes(str(len(data)), "utf8") + return headers.items(), data + + +def OK(flow, code=204): + """ Sending back a dummy response. + + 204 is the default in most cases on YT requests. + """ + from mitmproxy import http + + flow.error = None + flow.response = http.HTTPResponse(b"HTTP/1.1", code, b"OK", {}, b"") + + +def request(flow): + # All requests made for stats purposes can be discarded and + # a 204 sent back to the client. + if flow.request.url.startswith("https://www.youtube.com/ptracking"): + OK(flow) + return + if flow.request.url.startswith("https://www.youtube.com/api/stats/playback"): + OK(flow) + return + if flow.request.url.startswith("https://www.youtube.com/api/stats/watchtime"): + OK(flow) + return + # disable a few trackers, sniffers, etc + if "push.services.mozilla.com" in flow.request.url: + OK(flow, code=200) + return + if "gen_204" in flow.request.url: + OK(flow) + return + + # we don't want to post back any data, discarding. + if flow.request.method == "POST": + OK(flow) + return + if "googlevideo.com/videoplayback" in flow.request.url: + from mitmproxy import http + + query_args = dict(flow.request.query) + file_id = query_args["id"] + file_range = query_args["range"] + headers, data = get_cached_data(flow.request) + headers = list(headers) + flow.error = None + flow.response = http.HTTPResponse(b"HTTP/1.1", 200, b"OK", headers, data) + now = datetime.datetime.now() + then = now - datetime.timedelta(hours=1) + flow.response.timestamp_start = time.mktime(then.timetuple()) + flow.response.refresh() + log("SENT FILE %s IN CACHE - range %s" % (file_id, file_range)) + + +def error(flow): + print("\n\n\n\nERROR %s\n\n\n\n" % flow.error.msg) diff --git a/dom/media/test/marionette/yttest/record.py b/dom/media/test/marionette/yttest/record.py new file mode 100644 index 000000000000..b0bde6f01efa --- /dev/null +++ b/dom/media/test/marionette/yttest/record.py @@ -0,0 +1,34 @@ +""" +MITM Script used to collect media files when a YT video is played. + +This is a self-contained script that should not import anything else +except modules from the standard library and mitmproxy modules. +""" +import os + + +_HERE = os.path.dirname(__file__) +if "MOZPROXY_DIR" in os.environ: + _DEFAULT_DATA_DIR = os.environ["MOZPROXY_DIR"] +else: + _DEFAULT_DATA_DIR = os.path.join(_HERE, "..", "data") + + +def response(flow): + print(flow.request.url) + if "googlevideo.com/videoplayback" in flow.request.url: + itag = flow.request.query["itag"] + mime = flow.request.query["mime"].replace("/", "-") + query_args = dict(flow.request.query) + file_id = query_args["id"] + file_range = query_args["range"] + print("Writing %s:%s" % (file_id, file_range)) + # changing the host so the MITM recording file + # does not rely on a specific YT server + flow.request.host = "googlevideo.com" + if len(flow.response.content) == 0: + return + path = "%s-%s-%s.%s" % (file_id, itag, file_range, mime) + path = os.path.join(_DEFAULT_DATA_DIR, path) + with open(path, "wb") as f: + f.write(flow.response.content) diff --git a/dom/media/test/marionette/yttest/support.py b/dom/media/test/marionette/yttest/support.py new file mode 100644 index 000000000000..3a7dd90de512 --- /dev/null +++ b/dom/media/test/marionette/yttest/support.py @@ -0,0 +1,88 @@ +# 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/. +import sys +import os +from contextlib import contextmanager + +from mozproxy import get_playback +import mozinfo +import mozlog +from marionette_harness.marionette_test import MarionetteTestCase +from yttest.ytpage import using_page + + +mozlog.commandline.setup_logging("mozproxy", {}, {"tbpl": sys.stdout}) +here = os.path.dirname(__file__) +playback_script = os.path.join(here, "playback.py") + + +class VideoStreamTestCase(MarionetteTestCase): + def setUp(self): + MarionetteTestCase.setUp(self) + if "MOZ_UPLOAD_DIR" not in os.environ: + os.environ["OBJ_PATH"] = "/tmp/" + self.marionette.set_pref("media.autoplay.default", 1) + + @contextmanager + def using_proxy(self, video_id): + config = {} + config["binary"] = self.marionette.bin + config["app"] = "firefox" + config["platform"] = mozinfo.os + config["processor"] = mozinfo.processor + config["run_local"] = "MOZ_UPLOAD_DIR" not in os.environ + + if "MOZ_UPLOAD_DIR" not in os.environ: + config["obj_path"] = os.environ["OBJ_PATH"] + playback_dir = os.path.join(config["obj_path"], "testing", "mozproxy") + else: + root_dir = os.path.dirname(os.path.dirname(os.environ["MOZ_UPLOAD_DIR"])) + playback_dir = os.path.join(root_dir, "testing", "mozproxy") + + config["host"] = "localhost" + config["playback_tool"] = "mitmproxy" + config["playback_artifacts"] = os.path.join(here, "%s.manifest" % video_id) + + # XXX once Bug 1540622 lands, we can use the version here + # config["playback_version"] = "4.0.4" + # and have playback_binary_manifest default to + # mitmproxy-rel-bin-{playback_version}-{platform}.manifest + # so we don't have to ask amozproxy tool user to provide this: + config[ + "playback_binary_manifest" + ] = "mitmproxy-rel-bin-4.0.4-{platform}.manifest" + + playback_file = os.path.join(playback_dir, "%s.playback" % video_id) + + config["playback_tool_args"] = [ + "--ssl-insecure", + "--server-replay-nopop", + "--set", + "upstream_cert=false", + "-S", + playback_file, + "-s", + playback_script, + video_id, + ] + + proxy = get_playback(config) + if proxy is None: + raise Exception("Could not start Proxy") + proxy.start() + try: + yield proxy + finally: + proxy.stop() + + @contextmanager + def youtube_video(self, video_id, **options): + proxy = options.get("proxy", True) + if proxy: + with self.using_proxy(video_id): + with using_page(video_id, self.marionette, **options) as page: + yield page + else: + with using_page(video_id, self.marionette, **options) as page: + yield page diff --git a/dom/media/test/marionette/yttest/until_end_test.js b/dom/media/test/marionette/yttest/until_end_test.js new file mode 100644 index 000000000000..61f56c94c797 --- /dev/null +++ b/dom/media/test/marionette/yttest/until_end_test.js @@ -0,0 +1,18 @@ +%(force_hd)s + +const resolve = arguments[arguments.length - 1]; + +// this script is injected by marionette to collect metrics +var video = document.getElementsByTagName("video")[0]; +if (!video) { + return "Can't find the video tag"; +} + +video.addEventListener("ended", () => { + video.pause(); + %(video_playback_quality)s + %(debug_info)s + }, {once: true} +); + +video.play(); diff --git a/dom/media/test/marionette/yttest/video_playback_quality.js b/dom/media/test/marionette/yttest/video_playback_quality.js new file mode 100644 index 000000000000..fd02a776134e --- /dev/null +++ b/dom/media/test/marionette/yttest/video_playback_quality.js @@ -0,0 +1,7 @@ +var vpq = video.getVideoPlaybackQuality(); +var result = {"currentTime": video.currentTime}; +result["creationTime"] = vpq.creationTime; +result["corruptedVideoFrames"] = vpq.corruptedVideoFrames; +result["droppedVideoFrames"] = vpq.droppedVideoFrames; +result["totalVideoFrames"] = vpq.totalVideoFrames; +result["defaultPlaybackRate"] = video.playbackRate; diff --git a/dom/media/test/marionette/yttest/ytpage.py b/dom/media/test/marionette/yttest/ytpage.py new file mode 100644 index 000000000000..bb9282047fd2 --- /dev/null +++ b/dom/media/test/marionette/yttest/ytpage.py @@ -0,0 +1,82 @@ +# 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/. +""" +Drives the browser during the playback test. +""" +import contextlib +import os + + +here = os.path.dirname(__file__) +js = os.path.join(here, "until_end_test.js") +with open(js) as f: + UNTIL_END_TEST = f.read() + +js = os.path.join(here, "duration_test.js") +with open(js) as f: + DURATION_TEST = f.read() + +JS_MACROS = {"video_playback_quality": "", "debug_info": "", "force_hd": ""} +for script in JS_MACROS: + js = os.path.join(here, "%s.js" % script) + with open(js) as f: + JS_MACROS[script] = f.read() + + +class YoutubePage: + def __init__(self, video_id, marionette, **options): + self.video_id = video_id + self.marionette = marionette + self.url = "https://www.youtube.com/watch?v=%s" % self.video_id + self.started = False + self.capabilities = { + # We're not using upstream cert sniffing, let's make sure + # the browser accepts mitmproxy ones for all requests + # even if they are incorrect. + "acceptInsecureCerts": True + } + self.options = options + if options.get("proxy", True): + self.capabilities["proxy"] = { + "proxyType": "manual", + "httpProxy": "localhost:8080", + "sslProxy": "localhost:8080", + "noProxy": ["localhost"], + } + + def start_video(self): + self.marionette.start_session(self.capabilities) + self.marionette.timeout.script = 600 + self.marionette.navigate(self.url) + self.started = True + + def run_test(self): + self.start_video() + options = dict(JS_MACROS) + options.update(self.options) + if "duration" in options: + script = DURATION_TEST % options + else: + script = UNTIL_END_TEST % options + self.marionette.set_pref("media.autoplay.default", 0) + return self.execute_async_script(script) + + def execute_async_script(self, script, context=None): + if context is None: + context = self.marionette.CONTEXT_CONTENT + with self.marionette.using_context(context): + return self.marionette.execute_async_script(script, sandbox="system") + + def close(self): + if self.started: + self.marionette.delete_session() + + +@contextlib.contextmanager +def using_page(video_id, marionette, **options): + page = YoutubePage(video_id, marionette, **options) + try: + yield page + finally: + page.close() diff --git a/python/mozbuild/mozbuild/action/test_archive.py b/python/mozbuild/mozbuild/action/test_archive.py index ffb3edfc5d46..4c098737b392 100644 --- a/python/mozbuild/mozbuild/action/test_archive.py +++ b/python/mozbuild/mozbuild/action/test_archive.py @@ -138,8 +138,9 @@ ARCHIVE_FILES = { 'source': buildconfig.topsrcdir, 'base': '', 'manifests': [ + 'dom/media/test/marionette/manifest.ini', 'testing/marionette/harness/marionette_harness/tests/unit-tests.ini', - 'gfx/tests/marionette/manifest.ini', + 'gfx/tests/marionette/manifest.ini' ], # We also need the manifests and harness_unit tests 'pattern': 'testing/marionette/harness/marionette_harness/tests/**', diff --git a/python/mozbuild/mozbuild/frontend/context.py b/python/mozbuild/mozbuild/frontend/context.py index f6cbcb0764e7..a557219290f0 100644 --- a/python/mozbuild/mozbuild/frontend/context.py +++ b/python/mozbuild/mozbuild/frontend/context.py @@ -1872,6 +1872,10 @@ VARIABLES = { """List of manifest files defining mochitest chrome tests. """), + 'MARIONETTE_DOM_MEDIA_MANIFESTS': (ManifestparserManifestList, list, + """List of manifest files defining marionette-media tests. + """), + 'MOCHITEST_MANIFESTS': (ManifestparserManifestList, list, """List of manifest files defining mochitest tests. """), diff --git a/taskcluster/ci/test/marionette.yml b/taskcluster/ci/test/marionette.yml index e0532e56d070..f977453bdb01 100644 --- a/taskcluster/ci/test/marionette.yml +++ b/taskcluster/ci/test/marionette.yml @@ -47,3 +47,12 @@ marionette-gpu: by-test-platform: windows10-64.*: virtual-with-gpu default: virtual + +marionette-media: + description: "Marionette DOM media test run" + treeherder-symbol: MnM + max-run-time: 5400 + instance-size: default + mozharness: + extra-options: + - --test-manifest=stream-tests.ini diff --git a/taskcluster/ci/test/test-platforms.yml b/taskcluster/ci/test/test-platforms.yml index 625622914d62..798a8a226966 100644 --- a/taskcluster/ci/test/test-platforms.yml +++ b/taskcluster/ci/test/test-platforms.yml @@ -36,6 +36,7 @@ linux64/debug: - common-tests - web-platform-tests - mochitest-headless + - marionette-media-tests linux64/opt: build-platform: linux64/opt test-sets: @@ -135,6 +136,7 @@ windows7-32/debug: - windows-reftest-gpu - windows-tests - web-platform-tests + - marionette-media-tests windows7-32/opt: build-platform: win32/opt @@ -187,6 +189,7 @@ windows10-64/debug: - windows-tests - web-platform-tests - mochitest-headless + - marionette-media-tests windows10-64/opt: build-platform: win64/opt @@ -278,6 +281,7 @@ macosx64/debug: build-platform: macosx64/debug test-sets: - macosx64-tests + - marionette-media-tests macosx64-shippable/opt: build-platform: macosx64-shippable/opt diff --git a/taskcluster/ci/test/test-sets.yml b/taskcluster/ci/test/test-sets.yml index 2bde8be3ba47..3d881eb17441 100644 --- a/taskcluster/ci/test/test-sets.yml +++ b/taskcluster/ci/test/test-sets.yml @@ -274,6 +274,9 @@ windows-talos: marionette-gpu-tests: - marionette-gpu +marionette-media-tests: + - marionette-media + macosx64-tests: - cppunit - crashtest diff --git a/testing/marionette/harness/marionette_harness/tests/stream-tests.ini b/testing/marionette/harness/marionette_harness/tests/stream-tests.ini new file mode 100644 index 000000000000..1e099c9fd9c4 --- /dev/null +++ b/testing/marionette/harness/marionette_harness/tests/stream-tests.ini @@ -0,0 +1,2 @@ +# stream tests +[include:../../../../../dom/media/test/marionette/manifest.ini] diff --git a/testing/mozbase/mozproxy/mozproxy/backends/mitm.py b/testing/mozbase/mozproxy/mozproxy/backends/mitm.py index c8e9ddcb2995..a1539b250eee 100644 --- a/testing/mozbase/mozproxy/mozproxy/backends/mitm.py +++ b/testing/mozbase/mozproxy/mozproxy/backends/mitm.py @@ -79,7 +79,8 @@ class Mitmproxy(Playback): self.browser_path = config.get("binary") self.policies_dir = None self.ignore_mitmdump_exit_failure = config.get( - "ignore_mitmdump_exit_failure", False) + "ignore_mitmdump_exit_failure", False + ) # mozproxy_dir is where we will download all mitmproxy required files # when running locally it comes from obj_path via mozharness/mach @@ -149,8 +150,13 @@ class Mitmproxy(Playback): if not artifact: continue artifact_name = artifact.split("/")[-1] - dest = os.path.join(self.mozproxy_dir, artifact_name) - download_file_from_url(artifact, dest, extract=True) + if artifact_name.endswith(".manifest"): + tooltool_download( + artifact, self.config["run_local"], self.mozproxy_dir + ) + else: + dest = os.path.join(self.mozproxy_dir, artifact_name) + download_file_from_url(artifact, dest, extract=True) def stop(self): self.stop_mitmproxy_playback() @@ -174,10 +180,9 @@ class Mitmproxy(Playback): LOG.info("Starting mitmproxy playback using command: %s" % " ".join(command)) # to turn off mitmproxy log output, use these params for Popen: # Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) - self.mitmproxy_proc = ProcessHandler(command, - logfile=os.path.join(self.upload_dir, - "mitmproxy.log"), - env=env) + self.mitmproxy_proc = ProcessHandler( + command, logfile=os.path.join(self.upload_dir, "mitmproxy.log"), env=env + ) self.mitmproxy_proc.run() end_time = time.time() + MITMDUMP_COMMAND_TIMEOUT ready = False @@ -348,7 +353,7 @@ class MitmproxyAndroid(Mitmproxy): @property def certutil_sleep_seconds(self): """Time to sleep, in seconds, after issuing a `certutil` command.""" - return 10 if not self.config['run_local'] else 1 + return 10 if not self.config["run_local"] else 1 def setup(self): """For geckoview we need to install the generated mitmproxy CA cert""" @@ -372,14 +377,18 @@ class MitmproxyAndroid(Mitmproxy): 2. Import the mitmproxy certificate into the database, i.e.: `certutil -A -d sql: -n "some nickname" -t TC,, -a -i ` """ - if self.config['run_local']: + if self.config["run_local"]: # when running locally, it is found in the Firefox desktop build (..obj../dist/bin) - self.certutil = os.path.join(os.environ['MOZ_HOST_BIN'], 'certutil') - if not (os.path.isfile(self.certutil) and os.access(self.certutil, os.X_OK)): - LOG.critical("Abort: unable to execute certutil: {}".format(self.certutil)) + self.certutil = os.path.join(os.environ["MOZ_HOST_BIN"], "certutil") + if not ( + os.path.isfile(self.certutil) and os.access(self.certutil, os.X_OK) + ): + LOG.critical( + "Abort: unable to execute certutil: {}".format(self.certutil) + ) raise - self.certutil = os.environ['MOZ_HOST_BIN'] - os.environ['LD_LIBRARY_PATH'] = self.certutil + self.certutil = os.environ["MOZ_HOST_BIN"] + os.environ["LD_LIBRARY_PATH"] = self.certutil else: # must download certutil inside hostutils via tooltool; use this manifest: # mozilla-central/testing/config/tooltool-manifests/linux64/hostutils.manifest diff --git a/testing/mozbase/mozproxy/mozproxy/utils.py b/testing/mozbase/mozproxy/mozproxy/utils.py index 96829995c739..282809632b6c 100644 --- a/testing/mozbase/mozproxy/mozproxy/utils.py +++ b/testing/mozbase/mozproxy/mozproxy/utils.py @@ -30,10 +30,15 @@ from mozproxy import mozharness_dir LOG = get_proxy_logger(component="mozproxy") -external_tools_path = os.environ.get("EXTERNALTOOLSPATH", None) -if external_tools_path is not None: - # running in production via mozharness - TOOLTOOL_PATH = os.path.join(external_tools_path, "tooltool.py") +if "MOZ_UPLOAD_DIR" in os.environ: + TOOLTOOL_PATH = os.path.join( + os.environ["MOZ_UPLOAD_DIR"], + "..", + "..", + "mozharness", + "external_tools", + "tooltool.py", + ) else: # running locally via mach TOOLTOOL_PATH = os.path.join(mozharness_dir, "external_tools", "tooltool.py") @@ -80,10 +85,15 @@ def tooltool_download(manifest, run_local, raptor_dir): # - TOOLTOOLCACHE is used by Raptor tests # - TOOLTOOL_CACHE is automatically set for taskcluster jobs # - fallback to a hardcoded path - _cache = next(x for x in ( - os.environ.get("TOOLTOOLCACHE"), - os.environ.get("TOOLTOOL_CACHE"), - "/builds/tooltool_cache") if x is not None) + _cache = next( + x + for x in ( + os.environ.get("TOOLTOOLCACHE"), + os.environ.get("TOOLTOOL_CACHE"), + "/builds/tooltool_cache", + ) + if x is not None + ) command = [ sys.executable, From 091278a83ce8726a9d6fcbd22b0b6ad1f1bd5aa9 Mon Sep 17 00:00:00 2001 From: Dhyey Thakore Date: Tue, 2 Apr 2019 07:39:55 +0000 Subject: [PATCH 13/46] Bug 1539423 - Netmonitor docs: http/2 response headers are in small case r=Honza Add comment in HeadersPanel Differential Revision: https://phabricator.services.mozilla.com/D25704 --HG-- extra : moz-landing-system : lando --- devtools/client/netmonitor/src/components/HeadersPanel.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/devtools/client/netmonitor/src/components/HeadersPanel.js b/devtools/client/netmonitor/src/components/HeadersPanel.js index 08991233ec9c..10449a4d8173 100644 --- a/devtools/client/netmonitor/src/components/HeadersPanel.js +++ b/devtools/client/netmonitor/src/components/HeadersPanel.js @@ -63,6 +63,10 @@ const SUMMARY_REFERRER_POLICY = L10N.getStr("netmonitor.summary.referrerPolicy") /** * Headers panel component * Lists basic information about the request + * + * In http/2 all response headers are in small case. + * See: https://developer.mozilla.org/en-US/docs/Tools/Network_Monitor/request_details#Headers + * RFC: https://tools.ietf.org/html/rfc7540#section-8.1.2 */ class HeadersPanel extends Component { static get propTypes() { From 5cb90343fee7db1bf88451913cb534e71ce6c34e Mon Sep 17 00:00:00 2001 From: dlee Date: Tue, 2 Apr 2019 08:00:37 +0000 Subject: [PATCH 14/46] Bug 1539150 - Use window.open instead of setting iframe src in test_classify_by_default.html. ?baku r=baku In the test_classify_by_default.html, we use "network.cookie.cookieBehavior" to test if a channel is correctly classified. Cookie restriction is only enabled in nightly and early beta so the default preference is not always set. Although we set the preference in the testcase, it is too late because that the channel's cookie setting might inherit from it's parent and may end up with getting the old(default) value. In this patch, we use window.open to test the tracker frame to make sure we use the udpated prefrence. Differential Revision: https://phabricator.services.mozilla.com/D25657 --HG-- extra : moz-landing-system : lando --- .../url-classifier/tests/mochitest/mochitest.ini | 1 - .../tests/mochitest/test_classify_by_default.html | 14 ++++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/toolkit/components/url-classifier/tests/mochitest/mochitest.ini b/toolkit/components/url-classifier/tests/mochitest/mochitest.ini index 0c07dba7f9cf..b316aea44ff2 100644 --- a/toolkit/components/url-classifier/tests/mochitest/mochitest.ini +++ b/toolkit/components/url-classifier/tests/mochitest/mochitest.ini @@ -41,7 +41,6 @@ skip-if = (os == 'linux' && debug) #Bug 1199778 [test_classifier_match.html] [test_classifier_worker.html] [test_classify_by_default.html] -skip-if = (os == 'android') #Bug 1538662 [test_classify_ping.html] skip-if = (verify && debug && (os == 'win' || os == 'mac')) [test_classify_track.html] diff --git a/toolkit/components/url-classifier/tests/mochitest/test_classify_by_default.html b/toolkit/components/url-classifier/tests/mochitest/test_classify_by_default.html index 1bfd4d1d9245..68d718eb1833 100644 --- a/toolkit/components/url-classifier/tests/mochitest/test_classify_by_default.html +++ b/toolkit/components/url-classifier/tests/mochitest/test_classify_by_default.html @@ -14,9 +14,6 @@
 
-
-
-
 `,
+    tree: `
+      test-component
+        #shadow-root
+        ::before`,
+    anonTree: `
+      test-component
+        #shadow-root
+        _moz_generated_content_marker
+        ::before`,
+
+  }, {
+    // Test ::before on a shadow host with content is displayed when the host
+    // has a ::marker.
+    title: "::before after ::marker, non-empty node",
+    url: `data:text/html;charset=utf-8,
+      
+
+      
+        
+
+ + `, + tree: ` + test-component + #shadow-root + slot + div!slotted + ::before + class="light-dom"`, + anonTree: ` + test-component + #shadow-root + slot + div!slotted + _moz_generated_content_marker + ::before + class="light-dom"`, + }, { + // Test just ::marker on a shadow host + title: "just ::marker, no ::before", + url: `data:text/html;charset=utf-8, + + + + + `, + tree: ` + test-component + #shadow-root`, + anonTree: ` + test-component + #shadow-root + _moz_generated_content_marker`, + }, +]; + +for (const {url, tree, anonTree, title} of TEST_DATA) { + // Test each configuration in both open and closed modes + add_task(async function() { + info(`Testing: [${title}] in OPEN mode`); + const {inspector, tab} = await openInspectorForURL(url.replace(/#MODE#/g, "open")); + await assertMarkupViewAsTree(tree, "test-component", inspector); + await removeTab(tab); + }); + add_task(async function() { + info(`Testing: [${title}] in CLOSED mode`); + const {inspector, tab} = await openInspectorForURL(url.replace(/#MODE#/g, "closed")); + await assertMarkupViewAsTree(tree, "test-component", inspector); + await removeTab(tab); + }); + add_task(async function() { + await pushPref(SHOWANON_PREF, true); + info(`Testing: [${title}] in OPEN mode with showAllAnonymousContent`); + const {inspector, tab} = await openInspectorForURL(url.replace(/#MODE#/g, "open")); + await assertMarkupViewAsTree(anonTree, "test-component", inspector); + await removeTab(tab); + await pushPref(SHOWANON_PREF, false); + }); + add_task(async function() { + await pushPref(SHOWANON_PREF, true); + info(`Testing: [${title}] in CLOSED mode with showAllAnonymousContent`); + const {inspector, tab} = await openInspectorForURL(url.replace(/#MODE#/g, "closed")); + await assertMarkupViewAsTree(anonTree, "test-component", inspector); + await removeTab(tab); + await pushPref(SHOWANON_PREF, false); + }); +} diff --git a/devtools/server/actors/inspector/walker.js b/devtools/server/actors/inspector/walker.js index db8573e5cfca..012c097f9ab5 100644 --- a/devtools/server/actors/inspector/walker.js +++ b/devtools/server/actors/inspector/walker.js @@ -865,10 +865,14 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, { } if (shadowHost) { - // Use anonymous walkers to fetch ::before / ::after pseudo elements + // Use anonymous walkers to fetch ::marker / ::before / ::after pseudo + // elements const firstChildWalker = this.getDocumentWalker(node.rawNode); const first = firstChildWalker.firstChild(); - const hasBefore = first && first.nodeName === "_moz_generated_content_before"; + const hasMarker = first && first.nodeName === "_moz_generated_content_marker"; + const maybeBeforeNode = hasMarker ? firstChildWalker.nextSibling() : first; + const hasBefore = maybeBeforeNode && + maybeBeforeNode.nodeName === "_moz_generated_content_before"; const lastChildWalker = this.getDocumentWalker(node.rawNode); const last = lastChildWalker.lastChild(); @@ -877,8 +881,10 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, { nodes = [ // #shadow-root ...(hideShadowRoot ? [] : [node.rawNode.openOrClosedShadowRoot]), + // ::marker + ...(hasMarker ? [first] : []), // ::before - ...(hasBefore ? [first] : []), + ...(hasBefore ? [maybeBeforeNode] : []), // shadow host direct children ...nodes, // native anonymous content for UA widgets From 00591e61ad04499127f968259a2cf4c8a62713ba Mon Sep 17 00:00:00 2001 From: Ian Moody Date: Tue, 2 Apr 2019 07:45:23 +0000 Subject: [PATCH 18/46] Bug 1539265 - Add a test for ::marker displaying in the markup view. r=jdescottes Differential Revision: https://phabricator.services.mozilla.com/D25070 --HG-- extra : moz-landing-system : lando --- .../test/browser_rules_pseudo-element_02.js | 16 ++++++++++++++++ .../inspector/rules/test/doc_pseudoelement.html | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_02.js b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_02.js index 2a95ec3c0a1d..d984d7c3f038 100644 --- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_02.js @@ -7,9 +7,11 @@ // Test that pseudoelements are displayed correctly in the markup view. const TEST_URI = URL_ROOT + "doc_pseudoelement.html"; +const SHOWANON_PREF = "devtools.inspector.showAllAnonymousContent"; add_task(async function() { await addTab(TEST_URI); + await pushPref(SHOWANON_PREF, true); const {inspector} = await openRuleView(); const node = await getNodeFront("#topleft", inspector); @@ -26,4 +28,18 @@ add_task(async function() { is(afterElement.tagName, "_moz_generated_content_after", "tag name is correct"); await selectNode(afterElement, inspector); + + const listNode = await getNodeFront("#list", inspector); + const listChildren = await inspector.markup.walker.children(listNode); + + is(listChildren.nodes.length, 4, "
  • has correct number of children"); + const markerElement = listChildren.nodes[0]; + is(markerElement.tagName, "_moz_generated_content_marker", + "tag name is correct"); + await selectNode(markerElement, inspector); + + const listBeforeElement = listChildren.nodes[1]; + is(listBeforeElement.tagName, "_moz_generated_content_before", + "tag name is correct"); + await selectNode(listBeforeElement, inspector); }); diff --git a/devtools/client/inspector/rules/test/doc_pseudoelement.html b/devtools/client/inspector/rules/test/doc_pseudoelement.html index 6145d4bf1ba9..ad61b5d94129 100644 --- a/devtools/client/inspector/rules/test/doc_pseudoelement.html +++ b/devtools/client/inspector/rules/test/doc_pseudoelement.html @@ -127,5 +127,9 @@ p:first-letter {

    Bottom Left
    Position

    +
      +
    1. List element
    2. +
    + From 71b7e1fa5d39a1876bbb591f42a23b30daad4723 Mon Sep 17 00:00:00 2001 From: Ian Moody Date: Tue, 2 Apr 2019 07:45:31 +0000 Subject: [PATCH 19/46] Bug 1539265 - Handle ::marker pseudo-elements in css-logic.js, so their rules show in the rule view. r=jdescottes Differential Revision: https://phabricator.services.mozilla.com/D25071 --HG-- extra : moz-landing-system : lando --- .../test/browser_rules_pseudo-element_01.js | 26 +++++++++++++++++++ .../rules/test/doc_pseudoelement.html | 4 +++ devtools/server/actors/inspector/css-logic.js | 2 +- devtools/shared/inspector/css-logic.js | 9 ++++--- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js index 8631e72325e8..705696adaa69 100644 --- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js @@ -8,9 +8,11 @@ const TEST_URI = URL_ROOT + "doc_pseudoelement.html"; const PSEUDO_PREF = "devtools.inspector.show_pseudo_elements"; +const SHOWANON_PREF = "devtools.inspector.showAllAnonymousContent"; add_task(async function() { await pushPref(PSEUDO_PREF, true); + await pushPref(SHOWANON_PREF, true); await addTab(TEST_URI); const {inspector, view} = await openRuleView(); @@ -21,6 +23,7 @@ add_task(async function() { await testBottomLeft(inspector, view); await testParagraph(inspector, view); await testBody(inspector, view); + await testList(inspector, view); }); async function testTopLeft(inspector, view) { @@ -31,6 +34,7 @@ async function testTopLeft(inspector, view) { firstLineRulesNb: 2, firstLetterRulesNb: 1, selectionRulesNb: 1, + markerRulesNb: 0, afterRulesNb: 1, beforeRulesNb: 2, } @@ -123,6 +127,7 @@ async function testTopRight(inspector, view) { firstLineRulesNb: 1, firstLetterRulesNb: 1, selectionRulesNb: 0, + markerRulesNb: 0, beforeRulesNb: 2, afterRulesNb: 1, }); @@ -145,6 +150,7 @@ async function testBottomRight(inspector, view) { firstLineRulesNb: 1, firstLetterRulesNb: 1, selectionRulesNb: 0, + markerRulesNb: 0, beforeRulesNb: 3, afterRulesNb: 1, }); @@ -156,6 +162,7 @@ async function testBottomLeft(inspector, view) { firstLineRulesNb: 1, firstLetterRulesNb: 1, selectionRulesNb: 0, + markerRulesNb: 0, beforeRulesNb: 2, afterRulesNb: 1, }); @@ -168,6 +175,7 @@ async function testParagraph(inspector, view) { firstLineRulesNb: 1, firstLetterRulesNb: 1, selectionRulesNb: 2, + markerRulesNb: 0, beforeRulesNb: 0, afterRulesNb: 0, }); @@ -197,6 +205,20 @@ async function testBody(inspector, view) { is(gutters.length, 0, "There are no gutter headings"); } +async function testList(inspector, view) { + await assertPseudoElementRulesNumbers("#list", inspector, view, { + elementRulesNb: 4, + firstLineRulesNb: 1, + firstLetterRulesNb: 1, + selectionRulesNb: 0, + markerRulesNb: 1, + beforeRulesNb: 1, + afterRulesNb: 1, + }); + + assertGutters(view); +} + function convertTextPropsToString(textProps) { return textProps.map(t => t.name + ": " + t.value).join("; "); } @@ -218,6 +240,8 @@ async function assertPseudoElementRulesNumbers(selector, inspector, view, ruleNb rule.pseudoElement === ":first-letter"), selectionRules: elementStyle.rules.filter(rule => rule.pseudoElement === ":selection"), + markerRules: elementStyle.rules.filter(rule => + rule.pseudoElement === ":marker"), beforeRules: elementStyle.rules.filter(rule => rule.pseudoElement === ":before"), afterRules: elementStyle.rules.filter(rule => @@ -232,6 +256,8 @@ async function assertPseudoElementRulesNumbers(selector, inspector, view, ruleNb selector + " has the correct number of :first-letter rules"); is(rules.selectionRules.length, ruleNbs.selectionRulesNb, selector + " has the correct number of :selection rules"); + is(rules.markerRules.length, ruleNbs.markerRulesNb, + selector + " has the correct number of :marker rules"); is(rules.beforeRules.length, ruleNbs.beforeRulesNb, selector + " has the correct number of :before rules"); is(rules.afterRules.length, ruleNbs.afterRulesNb, diff --git a/devtools/client/inspector/rules/test/doc_pseudoelement.html b/devtools/client/inspector/rules/test/doc_pseudoelement.html index ad61b5d94129..6c85c5560308 100644 --- a/devtools/client/inspector/rules/test/doc_pseudoelement.html +++ b/devtools/client/inspector/rules/test/doc_pseudoelement.html @@ -106,6 +106,10 @@ p:first-letter { left:0; } +#list::marker { + color: purple; +} + diff --git a/devtools/server/actors/inspector/css-logic.js b/devtools/server/actors/inspector/css-logic.js index e16580198e1d..b9afb49fe3fb 100644 --- a/devtools/server/actors/inspector/css-logic.js +++ b/devtools/server/actors/inspector/css-logic.js @@ -665,7 +665,7 @@ CssLogic.getSelectors = function(domRule) { * * @returns {Object} * - {DOMNode} node The non-anonymous node - * - {string} pseudo One of ':before', ':after', or null. + * - {string} pseudo One of ':marker', ':before', ':after', or null. */ CssLogic.getBindingElementAndPseudo = getBindingElementAndPseudo; diff --git a/devtools/shared/inspector/css-logic.js b/devtools/shared/inspector/css-logic.js index 7521ebafaedd..1facbb6ae6e0 100644 --- a/devtools/shared/inspector/css-logic.js +++ b/devtools/shared/inspector/css-logic.js @@ -456,19 +456,22 @@ exports.getCssPath = getCssPath; exports.getXPath = getXPath; /** - * Given a node, check to see if it is a ::before or ::after element. + * Given a node, check to see if it is a ::marker, ::before, or ::after element. * If so, return the node that is accessible from within the document * (the parent of the anonymous node), along with which pseudo element * it was. Otherwise, return the node itself. * * @returns {Object} * - {DOMNode} node The non-anonymous node - * - {string} pseudo One of ':before', ':after', or null. + * - {string} pseudo One of ':marker', ':before', ':after', or null. */ function getBindingElementAndPseudo(node) { let bindingElement = node; let pseudo = null; - if (node.nodeName == "_moz_generated_content_before") { + if (node.nodeName == "_moz_generated_content_marker") { + bindingElement = node.parentNode; + pseudo = ":marker"; + } else if (node.nodeName == "_moz_generated_content_before") { bindingElement = node.parentNode; pseudo = ":before"; } else if (node.nodeName == "_moz_generated_content_after") { From 53e960c394a288a993a03252571a4537d8b2322d Mon Sep 17 00:00:00 2001 From: Ian Moody Date: Tue, 2 Apr 2019 07:45:38 +0000 Subject: [PATCH 20/46] Bug 1539265 - Add isMarkerPseudoElement function to layout/utils.js. r=jdescottes Differential Revision: https://phabricator.services.mozilla.com/D25105 --HG-- extra : moz-landing-system : lando --- devtools/server/actors/inspector/node.js | 2 ++ devtools/shared/fronts/node.js | 3 +++ devtools/shared/layout/utils.js | 11 +++++++++++ 3 files changed, 16 insertions(+) diff --git a/devtools/server/actors/inspector/node.js b/devtools/server/actors/inspector/node.js index 64a7a8ec63c3..eb405d5099e7 100644 --- a/devtools/server/actors/inspector/node.js +++ b/devtools/server/actors/inspector/node.js @@ -18,6 +18,7 @@ loader.lazyRequireGetter(this, "isAfterPseudoElement", "devtools/shared/layout/u loader.lazyRequireGetter(this, "isAnonymous", "devtools/shared/layout/utils", true); loader.lazyRequireGetter(this, "isBeforePseudoElement", "devtools/shared/layout/utils", true); loader.lazyRequireGetter(this, "isDirectShadowHostChild", "devtools/shared/layout/utils", true); +loader.lazyRequireGetter(this, "isMarkerPseudoElement", "devtools/shared/layout/utils", true); loader.lazyRequireGetter(this, "isNativeAnonymous", "devtools/shared/layout/utils", true); loader.lazyRequireGetter(this, "isShadowAnonymous", "devtools/shared/layout/utils", true); loader.lazyRequireGetter(this, "isShadowHost", "devtools/shared/layout/utils", true); @@ -127,6 +128,7 @@ const NodeActor = protocol.ActorClassWithSpec(nodeSpec, { attrs: this.writeAttrs(), customElementLocation: this.getCustomElementLocation(), + isMarkerPseudoElement: isMarkerPseudoElement(this.rawNode), isBeforePseudoElement: isBeforePseudoElement(this.rawNode), isAfterPseudoElement: isAfterPseudoElement(this.rawNode), isAnonymous: isAnonymous(this.rawNode), diff --git a/devtools/shared/fronts/node.js b/devtools/shared/fronts/node.js index f73e1467c40e..4edacb199e5a 100644 --- a/devtools/shared/fronts/node.js +++ b/devtools/shared/fronts/node.js @@ -267,6 +267,9 @@ class NodeFront extends FrontClassWithSpec(nodeSpec) { return this._form.hasEventListeners; } + get isMarkerPseudoElement() { + return this._form.isMarkerPseudoElement; + } get isBeforePseudoElement() { return this._form.isBeforePseudoElement; } diff --git a/devtools/shared/layout/utils.js b/devtools/shared/layout/utils.js index fc988aee233c..abb9b6f9a284 100644 --- a/devtools/shared/layout/utils.js +++ b/devtools/shared/layout/utils.js @@ -649,6 +649,17 @@ function isDirectShadowHostChild(node) { } exports.isDirectShadowHostChild = isDirectShadowHostChild; +/** + * Determine whether a node is a ::marker pseudo. + * + * @param {DOMNode} node + * @return {Boolean} + */ +function isMarkerPseudoElement(node) { + return node.nodeName === "_moz_generated_content_marker"; +} +exports.isMarkerPseudoElement = isMarkerPseudoElement; + /** * Determine whether a node is a ::before pseudo. * From 7e5567449ae60349c523728d38ca9459f67ff2d1 Mon Sep 17 00:00:00 2001 From: Ian Moody Date: Tue, 2 Apr 2019 07:45:45 +0000 Subject: [PATCH 21/46] Bug 1539265 - Handle ::marker pseudos during drag & drop of nodes in the markup view. r=jdescottes Prior to this the tab would crash with signature [@ nsINode::InsertChildBefore ] if trying to insert before the ::marker. Differential Revision: https://phabricator.services.mozilla.com/D25106 --HG-- extra : moz-landing-system : lando --- devtools/client/inspector/markup/markup.js | 16 +++-- .../client/inspector/markup/test/browser.ini | 1 + ...er_markup_dragdrop_before_marker_pseudo.js | 64 +++++++++++++++++++ .../markup/test/doc_markup_dragdrop.html | 6 ++ 4 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 devtools/client/inspector/markup/test/browser_markup_dragdrop_before_marker_pseudo.js diff --git a/devtools/client/inspector/markup/markup.js b/devtools/client/inspector/markup/markup.js index 0c081aada250..6126ddb0b360 100644 --- a/devtools/client/inspector/markup/markup.js +++ b/devtools/client/inspector/markup/markup.js @@ -2180,12 +2180,16 @@ MarkupView.prototype = { nextSibling = target.parentNode.container.node; } - if (nextSibling && nextSibling.isBeforePseudoElement) { - nextSibling = target.parentNode.parentNode.children[1].container.node; - } - if (nextSibling && nextSibling.isAfterPseudoElement) { - parent = target.parentNode.container.node.parentNode(); - nextSibling = null; + if (nextSibling) { + while ( + nextSibling.isMarkerPseudoElement || nextSibling.isBeforePseudoElement + ) { + nextSibling = this.getContainer(nextSibling).elt.nextSibling.container.node; + } + if (nextSibling.isAfterPseudoElement) { + parent = target.parentNode.container.node.parentNode(); + nextSibling = null; + } } if (parent.nodeType !== nodeConstants.ELEMENT_NODE) { diff --git a/devtools/client/inspector/markup/test/browser.ini b/devtools/client/inspector/markup/test/browser.ini index 028f2efbbf80..0173258f7d38 100644 --- a/devtools/client/inspector/markup/test/browser.ini +++ b/devtools/client/inspector/markup/test/browser.ini @@ -115,6 +115,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) || (os == "win" && processor == [browser_markup_display_node_02.js] [browser_markup_dragdrop_autoscroll_01.js] [browser_markup_dragdrop_autoscroll_02.js] +[browser_markup_dragdrop_before_marker_pseudo.js] [browser_markup_dragdrop_distance.js] [browser_markup_dragdrop_draggable.js] [browser_markup_dragdrop_dragRootNode.js] diff --git a/devtools/client/inspector/markup/test/browser_markup_dragdrop_before_marker_pseudo.js b/devtools/client/inspector/markup/test/browser_markup_dragdrop_before_marker_pseudo.js new file mode 100644 index 000000000000..04690d4720f3 --- /dev/null +++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_before_marker_pseudo.js @@ -0,0 +1,64 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test drag and dropping a node before a ::marker pseudo. + +const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html"; +const SHOWANON_PREF = "devtools.inspector.showAllAnonymousContent"; + +add_task(async function() { + await pushPref(SHOWANON_PREF, true); + const {inspector} = await openInspectorForURL(TEST_URL); + + info("Expand #list node"); + const parentFront = await getNodeFront("#list", inspector); + await inspector.markup.expandNode(parentFront.parentNode()); + await inspector.markup.expandNode(parentFront); + await waitForMultipleChildrenUpdates(inspector); + + info("Scroll #list into view"); + const parentContainer = await getContainerForNodeFront(parentFront, inspector); + parentContainer.elt.scrollIntoView(true); + + info("Test placing an element before a ::marker psuedo"); + await moveElementBeforeMarker("#last-list-child", parentFront, inspector); + const childNodes = await getChildrenOf(parentFront, inspector); + is(childNodes[0], "_moz_generated_content_marker", + "::marker is still the first child of #list"); + is(childNodes[1], "last-list-child", + "#last-list-child is now the second child of #list"); + is(childNodes[2], "first-list-child", + "#first-list-child is now the last child of #list"); +}); + +async function moveElementBeforeMarker(selector, parentFront, inspector) { + info(`Placing ${selector} before its parent's ::marker`); + + const container = await getContainerForSelector(selector, inspector); + const parentContainer = await getContainerForNodeFront(parentFront, inspector); + const offsetY = (parentContainer.tagLine.offsetTop + + parentContainer.tagLine.offsetHeight) - container.tagLine.offsetTop; + + const onMutated = inspector.once("markupmutation"); + const uiUpdate = inspector.once("inspector-updated"); + + await simulateNodeDragAndDrop(inspector, selector, 0, offsetY); + + const mutations = await onMutated; + await uiUpdate; + + is(mutations.length, 2, "2 mutations were received"); +} + +async function getChildrenOf(parentFront, {walker}) { + const {nodes} = await walker.children(parentFront); + return nodes.map(node => { + if (node.isMarkerPseudoElement) { + return node.displayName; + } + return node.id; + }); +} diff --git a/devtools/client/inspector/markup/test/doc_markup_dragdrop.html b/devtools/client/inspector/markup/test/doc_markup_dragdrop.html index 25b9707e2007..a13d42cbceb0 100644 --- a/devtools/client/inspector/markup/test/doc_markup_dragdrop.html +++ b/devtools/client/inspector/markup/test/doc_markup_dragdrop.html @@ -25,6 +25,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=858038
    slot1-2
    +
      +
    1. List item startList item end
    2. +
    + `, tree: ` - test-component - #shadow-root - ::before`, - anonTree: ` test-component #shadow-root ::marker @@ -68,13 +62,6 @@ const TEST_DATA = [ }); `, tree: ` - test-component - #shadow-root - slot - div!slotted - ::before - class="light-dom"`, - anonTree: ` test-component #shadow-root slot @@ -102,16 +89,13 @@ const TEST_DATA = [ }); `, tree: ` - test-component - #shadow-root`, - anonTree: ` test-component #shadow-root ::marker`, }, ]; -for (const {url, tree, anonTree, title} of TEST_DATA) { +for (const {url, tree, title} of TEST_DATA) { // Test each configuration in both open and closed modes add_task(async function() { info(`Testing: [${title}] in OPEN mode`); @@ -125,20 +109,4 @@ for (const {url, tree, anonTree, title} of TEST_DATA) { await assertMarkupViewAsTree(tree, "test-component", inspector); await removeTab(tab); }); - add_task(async function() { - await pushPref(SHOWANON_PREF, true); - info(`Testing: [${title}] in OPEN mode with showAllAnonymousContent`); - const {inspector, tab} = await openInspectorForURL(url.replace(/#MODE#/g, "open")); - await assertMarkupViewAsTree(anonTree, "test-component", inspector); - await removeTab(tab); - await pushPref(SHOWANON_PREF, false); - }); - add_task(async function() { - await pushPref(SHOWANON_PREF, true); - info(`Testing: [${title}] in CLOSED mode with showAllAnonymousContent`); - const {inspector, tab} = await openInspectorForURL(url.replace(/#MODE#/g, "closed")); - await assertMarkupViewAsTree(anonTree, "test-component", inspector); - await removeTab(tab); - await pushPref(SHOWANON_PREF, false); - }); } diff --git a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js index 705696adaa69..a9f876a06837 100644 --- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js @@ -8,11 +8,9 @@ const TEST_URI = URL_ROOT + "doc_pseudoelement.html"; const PSEUDO_PREF = "devtools.inspector.show_pseudo_elements"; -const SHOWANON_PREF = "devtools.inspector.showAllAnonymousContent"; add_task(async function() { await pushPref(PSEUDO_PREF, true); - await pushPref(SHOWANON_PREF, true); await addTab(TEST_URI); const {inspector, view} = await openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_02.js b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_02.js index d984d7c3f038..bef7dfe1a667 100644 --- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_02.js @@ -7,11 +7,9 @@ // Test that pseudoelements are displayed correctly in the markup view. const TEST_URI = URL_ROOT + "doc_pseudoelement.html"; -const SHOWANON_PREF = "devtools.inspector.showAllAnonymousContent"; add_task(async function() { await addTab(TEST_URI); - await pushPref(SHOWANON_PREF, true); const {inspector} = await openRuleView(); const node = await getNodeFront("#topleft", inspector); diff --git a/devtools/server/actors/inspector/utils.js b/devtools/server/actors/inspector/utils.js index 3b3ffdc4d723..7a8f1cf5d78d 100644 --- a/devtools/server/actors/inspector/utils.js +++ b/devtools/server/actors/inspector/utils.js @@ -60,13 +60,14 @@ function isInXULDocument(el) { /** * This DeepTreeWalker filter skips whitespace text nodes and anonymous - * content with the exception of ::before and ::after and anonymous content - * in XUL document (needed to show all elements in the browser toolbox). + * content with the exception of ::marker, ::before, and ::after, plus anonymous + * content in XUL document (needed to show all elements in the browser toolbox). */ function standardTreeWalkerFilter(node) { - // ::before and ::after are native anonymous content, but we always + // ::marker, ::before, and ::after are native anonymous content, but we always // want to show them - if (node.nodeName === "_moz_generated_content_before" || + if (node.nodeName === "_moz_generated_content_marker" || + node.nodeName === "_moz_generated_content_before" || node.nodeName === "_moz_generated_content_after") { return nodeFilterConstants.FILTER_ACCEPT; } From c52ebc3ea9a12cd7f428dbd05380720cf493b40d Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 2 Apr 2019 06:07:39 +0000 Subject: [PATCH 28/46] Bug 1540769 - Enable readability-redundant-preprocessor r=andi Differential Revision: https://phabricator.services.mozilla.com/D25630 --HG-- extra : moz-landing-system : lando --- tools/clang-tidy/config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/clang-tidy/config.yaml b/tools/clang-tidy/config.yaml index 69d80c57571e..869c0a84ac42 100644 --- a/tools/clang-tidy/config.yaml +++ b/tools/clang-tidy/config.yaml @@ -134,6 +134,7 @@ clang_checkers: - name: readability-misleading-indentation - name: readability-non-const-parameter - name: readability-redundant-control-flow + - name: readability-redundant-preprocessor - name: readability-redundant-smartptr-get - name: readability-redundant-string-cstr - name: readability-redundant-string-init From 8f65480f36e4f9147923685d6025065ac87bf97d Mon Sep 17 00:00:00 2001 From: Bastien Abadie Date: Tue, 2 Apr 2019 08:30:05 +0000 Subject: [PATCH 29/46] Bug 1540325 - Run clang tools tasks only on try & code-review, r=glandium,sylvestre Differential Revision: https://phabricator.services.mozilla.com/D25562 --HG-- extra : moz-landing-system : lando --- taskcluster/ci/source-test/clang.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/taskcluster/ci/source-test/clang.yml b/taskcluster/ci/source-test/clang.yml index 646f0861605c..6476b5c9ae23 100644 --- a/taskcluster/ci/source-test/clang.yml +++ b/taskcluster/ci/source-test/clang.yml @@ -1,4 +1,9 @@ job-defaults: + # Run only on try and code-review tasks + # to avoid running clang tools on the whole codebase + run-on-projects: + - try + platform: linux64/opt attributes: code-review: true From 3c8351815ed1c14dd8c633ee0186e8419a5916d2 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Tue, 2 Apr 2019 08:53:28 +0000 Subject: [PATCH 30/46] Bug 1539408 Pass referrerInfo to gContextMenuContentData in non-remote r=Gijs Differential Revision: https://phabricator.services.mozilla.com/D25419 --HG-- extra : moz-landing-system : lando --- browser/actors/ContextMenuChild.jsm | 14 ++++++++++++++ browser/base/content/utilityOverlay.js | 3 +-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/browser/actors/ContextMenuChild.jsm b/browser/actors/ContextMenuChild.jsm index 88e260528281..9755dfc78c8c 100644 --- a/browser/actors/ContextMenuChild.jsm +++ b/browser/actors/ContextMenuChild.jsm @@ -32,6 +32,11 @@ XPCOMUtils.defineLazyGetter(this, "PageMenuChild", () => { return new tmp.PageMenuChild(); }); +XPCOMUtils.defineLazyGetter(this, "ReferrerInfo", () => + Components.Constructor("@mozilla.org/referrer-info;1", + "nsIReferrerInfo", + "init")); + const messageListeners = { "ContextMenu:BookmarkFrame": function(aMessage) { let frame = this.getTarget(aMessage).ownerDocument; @@ -602,6 +607,15 @@ class ContextMenuChild extends ActorChild { data.context.targetAsCPOW = targetAsCPOW; + data.referrerInfo = new ReferrerInfo( + referrerPolicy, + !context.linkHasNoReferrer, + data.documentURIObject); + data.frameReferrerInfo = new ReferrerInfo( + referrerPolicy, + !context.linkHasNoReferrer, + referrer ? Services.io.newURI(referrer) : null); + mainWin.setContextMenuContentData(data); } } diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index 953bbca243a3..2369f20a32bb 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -314,8 +314,7 @@ function openLinkIn(url, where, params) { var aAllowThirdPartyFixup = params.allowThirdPartyFixup; var aPostData = params.postData; var aCharset = params.charset; - var aReferrerInfo = ("referrerInfo" in params) - ? params.referrerInfo + var aReferrerInfo = params.referrerInfo ? params.referrerInfo : new ReferrerInfo(Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true, null); var aRelatedToCurrent = params.relatedToCurrent; var aAllowInheritPrincipal = !!params.allowInheritPrincipal; From a99fa2c128cd6c863b4cd6dae562a25df72b47cd Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Tue, 2 Apr 2019 12:29:16 +0300 Subject: [PATCH 31/46] Backed out changeset 9b9c50876092 (bug 1540325) for Linting failure on clang.yml. CLOSED TREE --- taskcluster/ci/source-test/clang.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/taskcluster/ci/source-test/clang.yml b/taskcluster/ci/source-test/clang.yml index 6476b5c9ae23..646f0861605c 100644 --- a/taskcluster/ci/source-test/clang.yml +++ b/taskcluster/ci/source-test/clang.yml @@ -1,9 +1,4 @@ job-defaults: - # Run only on try and code-review tasks - # to avoid running clang tools on the whole codebase - run-on-projects: - - try - platform: linux64/opt attributes: code-review: true From df684f89db62fbc2bc557f83457a41acdb1a203f Mon Sep 17 00:00:00 2001 From: Jonas Allmann Date: Tue, 2 Apr 2019 08:56:25 +0000 Subject: [PATCH 32/46] Bug 1498569, Replace wizard.xml attributes with event listeners, r=Gijs * Removed all occurences of custom onwizard* attributes. * Removed custom handler code from wizard.xml. * Updated eval()-usage whitelist. Differential Revision: https://phabricator.services.mozilla.com/D24033 --HG-- extra : moz-landing-system : lando --- .../components/migration/content/migration.js | 19 ++++++++-- .../migration/content/migration.xul | 21 +++------- modules/libpref/init/all.js | 2 +- toolkit/content/widgets/wizard.xml | 13 +------ toolkit/mozapps/update/content/updates.js | 24 ++++++++++++ toolkit/mozapps/update/content/updates.xul | 38 ++++++------------- .../profile/content/createProfileWizard.js | 11 +++--- .../profile/content/createProfileWizard.xul | 5 +-- 8 files changed, 66 insertions(+), 67 deletions(-) diff --git a/browser/components/migration/content/migration.js b/browser/components/migration/content/migration.js index 10f9b487cd57..fdc5324dd7ac 100644 --- a/browser/components/migration/content/migration.js +++ b/browser/components/migration/content/migration.js @@ -50,6 +50,20 @@ var MigrationWizard = { /* exported MigrationWizard */ } } + document.addEventListener("wizardcancel", function() { MigrationWizard.onWizardCancel(); }); + + document.getElementById("selectProfile").addEventListener("pageshow", function() { MigrationWizard.onSelectProfilePageShow(); }); + document.getElementById("importItems").addEventListener("pageshow", function() { MigrationWizard.onImportItemsPageShow(); }); + document.getElementById("migrating").addEventListener("pageshow", function() { MigrationWizard.onMigratingPageShow(); }); + document.getElementById("done").addEventListener("pageshow", function() { MigrationWizard.onDonePageShow(); }); + + document.getElementById("selectProfile").addEventListener("pagerewound", function() { MigrationWizard.onSelectProfilePageRewound(); }); + document.getElementById("importItems").addEventListener("pagerewound", function() { MigrationWizard.onImportItemsPageRewound(); }); + + document.getElementById("selectProfile").addEventListener("pageadvanced", function() { MigrationWizard.onSelectProfilePageAdvanced(); }); + document.getElementById("importItems").addEventListener("pageadvanced", function() { MigrationWizard.onImportItemsPageAdvanced(); }); + document.getElementById("importSource").addEventListener("pageadvanced", function(e) { MigrationWizard.onImportSourcePageAdvanced(e); }); + this.onImportSourcePageShow(); }, @@ -145,7 +159,7 @@ var MigrationWizard = { /* exported MigrationWizard */ } }, - onImportSourcePageAdvanced() { + onImportSourcePageAdvanced(event) { var newSource = document.getElementById("importSourceGroup").selectedItem.id; if (newSource == "nothing") { @@ -155,7 +169,7 @@ var MigrationWizard = { /* exported MigrationWizard */ Services.telemetry.getHistogramById("FX_MIGRATION_SOURCE_BROWSER") .add(MigrationUtils.getSourceIdForTelemetry("nothing")); document.documentElement.cancel(); - return false; + event.preventDefault(); } if (!this._migrator || (newSource != this._source)) { @@ -184,7 +198,6 @@ var MigrationWizard = { /* exported MigrationWizard */ else this._selectedProfile = null; } - return undefined; }, // 2 - [Profile Selection] diff --git a/browser/components/migration/content/migration.xul b/browser/components/migration/content/migration.xul index 3f7a88dfaaa8..088853bf4390 100644 --- a/browser/components/migration/content/migration.xul +++ b/browser/components/migration/content/migration.xul @@ -15,15 +15,13 @@ onunload="MigrationWizard.uninit()" style="width: 40em;" buttons="accept,cancel" - branded="true" - onwizardcancel="return MigrationWizard.onWizardCancel();"> + branded="true">