From 02681a282be1bd7f93e482736b426ea6b80d316c Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Mon, 5 Jan 2015 09:37:43 +1100 Subject: [PATCH 01/12] Bug 1105596 - Simplify aboutNetError_alert.svg a little. r=gijs --- browser/themes/shared/aboutNetError_info.svg | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/browser/themes/shared/aboutNetError_info.svg b/browser/themes/shared/aboutNetError_info.svg index 5b586334345..20010c16671 100644 --- a/browser/themes/shared/aboutNetError_info.svg +++ b/browser/themes/shared/aboutNetError_info.svg @@ -1,7 +1,5 @@ - - - + + - From 84e37c2a69e2080d14cd3b533d9ce297bf9d4ebb Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Sat, 3 Jan 2015 20:08:17 -0500 Subject: [PATCH 02/12] Debugging patch for bug 1111137 --- netwerk/test/mochitests/test_user_agent_overrides.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/netwerk/test/mochitests/test_user_agent_overrides.html b/netwerk/test/mochitests/test_user_agent_overrides.html index 0541b64b89e..5944022c530 100644 --- a/netwerk/test/mochitests/test_user_agent_overrides.html +++ b/netwerk/test/mochitests/test_user_agent_overrides.html @@ -239,6 +239,9 @@ SpecialPowers.Cu.import('resource://gre/modules/UserAgentOverrides.jsm', window) SpecialPowers.wrap(UserAgentOverrides).init(); SimpleTest.waitForExplicitFinish(); +SimpleTest.requestCompleteLog(); + +info(SpecialPowers.Cc["@mozilla.org/dom/site-specific-user-agent;1"].number); testOverrides(function () testInactive(function () From 87bc3fd5d5827be7997b9169496c27c445fb8af1 Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Mon, 5 Jan 2015 01:18:11 +0100 Subject: [PATCH 03/12] Bug 1084450: Disable subpixelAA text when requested for header/footer drawing code. r=mattwoodrow --- layout/base/nsDisplayList.h | 8 ------ layout/generic/nsPageFrame.cpp | 47 ++++++++++++++++++++++++++-------- layout/generic/nsPageFrame.h | 2 +- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 040383a8ac8..c57304e00f2 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -1959,14 +1959,6 @@ public: } NS_DISPLAY_DECL_NAME(mName, mType) - virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE { - if (mType == nsDisplayItem::TYPE_HEADER_FOOTER) { - bool snap; - return GetBounds(aBuilder, &snap); - } - return nsRect(); - } - protected: PaintCallback mPaint; const char* mName; diff --git a/layout/generic/nsPageFrame.cpp b/layout/generic/nsPageFrame.cpp index 525a5172a09..132f10ec378 100644 --- a/layout/generic/nsPageFrame.cpp +++ b/layout/generic/nsPageFrame.cpp @@ -470,18 +470,45 @@ GetNextPage(nsIFrame* aPageContentFrame) return f; } -static void PaintHeaderFooter(nsIFrame* aFrame, nsRenderingContext* aCtx, - const nsRect& aDirtyRect, nsPoint aPt) -{ - static_cast(aFrame)->PaintHeaderFooter(*aCtx, aPt); -} - static gfx::Matrix4x4 ComputePageTransform(nsIFrame* aFrame, float aAppUnitsPerPixel) { float scale = aFrame->PresContext()->GetPageScale(); return gfx::Matrix4x4::Scaling(scale, scale, 1); } +class nsDisplayHeaderFooter : public nsDisplayItem { +public: + nsDisplayHeaderFooter(nsDisplayListBuilder* aBuilder, nsPageFrame *aFrame) + : nsDisplayItem(aBuilder, aFrame), mFrame(aFrame) + , mDisableSubpixelAA(false) + { + MOZ_COUNT_CTOR(nsDisplayHeaderFooter); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayHeaderFooter() { + MOZ_COUNT_DTOR(nsDisplayHeaderFooter); + } +#endif + + virtual void Paint(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx) MOZ_OVERRIDE { + mFrame->PaintHeaderFooter(*aCtx, ToReferenceFrame(), mDisableSubpixelAA); + } + NS_DISPLAY_DECL_NAME("HeaderFooter", nsDisplayItem::TYPE_HEADER_FOOTER) + + virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE { + bool snap; + return GetBounds(aBuilder, &snap); + } + + virtual void DisableComponentAlpha() MOZ_OVERRIDE { + mDisableSubpixelAA = true; + } +protected: + nsPageFrame* mFrame; + bool mDisableSubpixelAA; +}; + //------------------------------------------------------------------------------ void nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, @@ -563,9 +590,7 @@ nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, if (PresContext()->IsRootPaginatedDocument()) { set.Content()->AppendNewToTop(new (aBuilder) - nsDisplayGeneric(aBuilder, this, ::PaintHeaderFooter, - "HeaderFooter", - nsDisplayItem::TYPE_HEADER_FOOTER)); + nsDisplayHeaderFooter(aBuilder, this)); } set.MoveTo(aLists); @@ -582,7 +607,7 @@ nsPageFrame::SetPageNumInfo(int32_t aPageNumber, int32_t aTotalPages) void nsPageFrame::PaintHeaderFooter(nsRenderingContext& aRenderingContext, - nsPoint aPt) + nsPoint aPt, bool aDisableSubpixelAA) { nsPresContext* pc = PresContext(); @@ -596,6 +621,8 @@ nsPageFrame::PaintHeaderFooter(nsRenderingContext& aRenderingContext, nsRect rect(aPt, mRect.Size()); aRenderingContext.ThebesContext()->SetColor(NS_RGB(0,0,0)); + gfxContextAutoDisableSubpixelAntialiasing disable(aRenderingContext.ThebesContext(), aDisableSubpixelAA); + // Get the FontMetrics to determine width.height of strings nsRefPtr fontMet; pc->DeviceContext()->GetMetricsFor(mPD->mHeadFootFont, nullptr, false, diff --git a/layout/generic/nsPageFrame.h b/layout/generic/nsPageFrame.h index 73b058d5fb8..9d578ec65d7 100644 --- a/layout/generic/nsPageFrame.h +++ b/layout/generic/nsPageFrame.h @@ -55,7 +55,7 @@ public: virtual bool HonorPrintBackgroundSettings() MOZ_OVERRIDE { return false; } void PaintHeaderFooter(nsRenderingContext& aRenderingContext, - nsPoint aPt); + nsPoint aPt, bool aSubpixelAA); protected: explicit nsPageFrame(nsStyleContext* aContext); From ce936251a48c71d945a05e66a5a5336405f90dea Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Sun, 4 Jan 2015 17:46:49 -0800 Subject: [PATCH 04/12] Bug 1088268 - Use a switch statement in DOMGCSliceCallback. r=smaug --- dom/base/nsJSEnvironment.cpp | 158 +++++++++++++++++++---------------- 1 file changed, 88 insertions(+), 70 deletions(-) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index fdd5a37ba25..fa422ff8708 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2334,86 +2334,104 @@ DOMGCSliceCallback(JSRuntime *aRt, JS::GCProgress aProgress, const JS::GCDescrip { NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread"); - if (aProgress == JS::GC_CYCLE_END) { - PRTime delta = GetCollectionTimeDelta(); + switch (aProgress) { + case JS::GC_CYCLE_BEGIN: { + // Prevent cycle collections and shrinking during incremental GC. + sCCLockedOut = true; - if (sPostGCEventsToConsole) { - NS_NAMED_LITERAL_STRING(kFmt, "GC(T+%.1f) "); - nsString prefix, gcstats; - gcstats.Adopt(aDesc.formatMessage(aRt)); - prefix.Adopt(nsTextFormatter::smprintf(kFmt.get(), + nsJSContext::KillShrinkGCBuffersTimer(); + + break; + } + + case JS::GC_CYCLE_END: { + PRTime delta = GetCollectionTimeDelta(); + + if (sPostGCEventsToConsole) { + NS_NAMED_LITERAL_STRING(kFmt, "GC(T+%.1f) "); + nsString prefix, gcstats; + gcstats.Adopt(aDesc.formatMessage(aRt)); + prefix.Adopt(nsTextFormatter::smprintf(kFmt.get(), double(delta) / PR_USEC_PER_SEC)); - nsString msg = prefix + gcstats; - nsCOMPtr cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID); - if (cs) { - cs->LogStringMessage(msg.get()); + nsString msg = prefix + gcstats; + nsCOMPtr cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + if (cs) { + cs->LogStringMessage(msg.get()); + } } - } - if (sPostGCEventsToObserver) { - nsString json; - json.Adopt(aDesc.formatJSON(aRt, PR_Now())); - nsRefPtr notify = new NotifyGCEndRunnable(json); - NS_DispatchToMainThread(notify); - } - } - - // Prevent cycle collections and shrinking during incremental GC. - if (aProgress == JS::GC_CYCLE_BEGIN) { - sCCLockedOut = true; - nsJSContext::KillShrinkGCBuffersTimer(); - } else if (aProgress == JS::GC_CYCLE_END) { - sCCLockedOut = false; - } - - // The GC has more work to do, so schedule another GC slice. - if (aProgress == JS::GC_SLICE_END) { - nsJSContext::KillInterSliceGCTimer(); - if (!sShuttingDown) { - CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer); - sInterSliceGCTimer->InitWithFuncCallback(InterSliceGCTimerFired, - nullptr, - NS_INTERSLICE_GC_DELAY, - nsITimer::TYPE_ONE_SHOT); - } - } - - if (aProgress == JS::GC_CYCLE_END) { - // May need to kill the inter-slice GC timer - nsJSContext::KillInterSliceGCTimer(); - - sCCollectedWaitingForGC = 0; - sCCollectedZonesWaitingForGC = 0; - sLikelyShortLivingObjectsNeedingGC = 0; - sCleanupsSinceLastGC = 0; - sNeedsFullCC = true; - sHasRunGC = true; - nsJSContext::MaybePokeCC(); - - if (aDesc.isCompartment_) { - if (!sFullGCTimer && !sShuttingDown) { - CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer); - sFullGCTimer->InitWithFuncCallback(FullGCTimerFired, - nullptr, - NS_FULL_GC_DELAY, - nsITimer::TYPE_ONE_SHOT); + if (sPostGCEventsToObserver) { + nsString json; + json.Adopt(aDesc.formatJSON(aRt, PR_Now())); + nsRefPtr notify = new NotifyGCEndRunnable(json); + NS_DispatchToMainThread(notify); } - } else { - nsJSContext::KillFullGCTimer(); - // Avoid shrinking during heavy activity, which is suggested by - // compartment GC. - nsJSContext::PokeShrinkGCBuffers(); + sCCLockedOut = false; + + // May need to kill the inter-slice GC timer + nsJSContext::KillInterSliceGCTimer(); + + sCCollectedWaitingForGC = 0; + sCCollectedZonesWaitingForGC = 0; + sLikelyShortLivingObjectsNeedingGC = 0; + sCleanupsSinceLastGC = 0; + sNeedsFullCC = true; + sHasRunGC = true; + nsJSContext::MaybePokeCC(); + + if (aDesc.isCompartment_) { + if (!sFullGCTimer && !sShuttingDown) { + CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer); + sFullGCTimer->InitWithFuncCallback(FullGCTimerFired, + nullptr, + NS_FULL_GC_DELAY, + nsITimer::TYPE_ONE_SHOT); + } + } else { + nsJSContext::KillFullGCTimer(); + + // Avoid shrinking during heavy activity, which is suggested by + // compartment GC. + nsJSContext::PokeShrinkGCBuffers(); + } + + if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) { + nsCycleCollector_dispatchDeferredDeletion(); + } + + break; } + + case JS::GC_SLICE_BEGIN: + break; + + case JS::GC_SLICE_END: + + // The GC has more work to do, so schedule another GC slice. + nsJSContext::KillInterSliceGCTimer(); + if (!sShuttingDown) { + CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer); + sInterSliceGCTimer->InitWithFuncCallback(InterSliceGCTimerFired, + nullptr, + NS_INTERSLICE_GC_DELAY, + nsITimer::TYPE_ONE_SHOT); + } + + if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) { + nsCycleCollector_dispatchDeferredDeletion(); + } + + break; + + default: + MOZ_CRASH("Unexpected GCProgress value"); } - if ((aProgress == JS::GC_SLICE_END || aProgress == JS::GC_CYCLE_END) && - ShouldTriggerCC(nsCycleCollector_suspectedCount())) { - nsCycleCollector_dispatchDeferredDeletion(); - } - - if (sPrevGCSliceCallback) + if (sPrevGCSliceCallback) { (*sPrevGCSliceCallback)(aRt, aProgress, aDesc); + } + } void From 80929ad07e5970d66d03b723e7a3ca1e9c1a006a Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Sun, 4 Jan 2015 17:46:49 -0800 Subject: [PATCH 05/12] Bug 1116821 - Don't PokeGC in SetNewDocument. r=smaug --- dom/base/nsGlobalWindow.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 7bb08d31ed1..b539ce182aa 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -2680,7 +2680,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, newInnerWindow->mChromeEventHandler = mChromeEventHandler; } - nsJSContext::PokeGC(JS::gcreason::SET_NEW_DOCUMENT); mContext->DidInitializeContext(); // We wait to fire the debugger hook until the window is all set up and hooked From a8c632a6f8bedb9ca94003fe6c6b6f5a21a9f022 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Sun, 4 Jan 2015 17:46:50 -0800 Subject: [PATCH 06/12] Bug 1110928, part 1 - Hoist the LOAD_END PokeGC out of nsJSContext::LoadEnd. r=smaug nsDocumentViewer knows which document is involved which will help us later. Also, fix a typo in the comment. --- dom/base/nsJSEnvironment.cpp | 2 -- layout/base/nsDocumentViewer.cpp | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index fa422ff8708..f7d6b184141 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2089,9 +2089,7 @@ nsJSContext::LoadEnd() return; } - // Its probably a good idea to GC soon since we have finished loading. sLoadingInProgress = false; - PokeGC(JS::gcreason::LOAD_END); } // Only trigger expensive timers when they have been checked a number of times. diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 4b32c6397e2..d4b39394c5b 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -1039,6 +1039,9 @@ nsDocumentViewer::LoadComplete(nsresult aStatus) nsJSContext::LoadEnd(); + // It's probably a good idea to GC soon since we have finished loading. + nsJSContext::PokeGC(JS::gcreason::LOAD_END); + #ifdef NS_PRINTING // Check to see if someone tried to print during the load if (mPrintIsPending) { From d541b6c4278497e0cc540f4ad08f123561e08bb5 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Sun, 4 Jan 2015 17:46:50 -0800 Subject: [PATCH 07/12] Bug 1110928, part 2 - Call PokeGC in nsDocumentViewer::PageHide before the call to OnPageHide. r=smaug This ensures that the document isn't destroyed when we call PokeGC, which will be useful later. --- layout/base/nsDocumentViewer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index d4b39394c5b..a8b16390c96 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -1314,6 +1314,11 @@ nsDocumentViewer::PageHide(bool aIsUnload) return NS_ERROR_NULL_POINTER; } + if (aIsUnload) { + // Poke the GC. The window might be collectable garbage now. + nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE, NS_GC_DELAY * 2); + } + mDocument->OnPageHide(!aIsUnload, nullptr); // inform the window so that the focus state is reset. @@ -1323,9 +1328,6 @@ nsDocumentViewer::PageHide(bool aIsUnload) window->PageHidden(); if (aIsUnload) { - // Poke the GC. The window might be collectable garbage now. - nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE, NS_GC_DELAY * 2); - // if Destroy() was called during OnPageHide(), mDocument is nullptr. NS_ENSURE_STATE(mDocument); From 23afe7c9b0badcec12419391a7b4c99e010a5d06 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Sun, 4 Jan 2015 17:46:50 -0800 Subject: [PATCH 08/12] Bug 1110928, part 3 - Try to pass a relevant zone to PokeGC. r=smaug This means the browser will do less full GCs. --- dom/base/nsGlobalWindow.cpp | 2 +- dom/base/nsJSEnvironment.cpp | 30 +++++++++++++++++++++++------- dom/base/nsJSEnvironment.h | 3 ++- layout/base/nsDocumentViewer.cpp | 7 +++++-- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index b539ce182aa..7fd39ce5a34 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -2902,7 +2902,7 @@ nsGlobalWindow::DetachFromDocShell() mChromeEventHandler = nullptr; // force release now if (mContext) { - nsJSContext::PokeGC(JS::gcreason::SET_DOC_SHELL); + nsJSContext::PokeGC(JS::gcreason::SET_DOC_SHELL, GetWrapperPreserveColor()); mContext = nullptr; } diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index f7d6b184141..c00e1af349e 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -654,7 +654,7 @@ nsJSContext::DestroyJSContext() js_options_dot_str, this); if (mGCOnDestruction) { - PokeGC(JS::gcreason::NSJSCONTEXT_DESTROY); + PokeGC(JS::gcreason::NSJSCONTEXT_DESTROY, mWindowProxy); } JS_DestroyContextNoGC(mContext); @@ -1463,8 +1463,11 @@ nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason, return; } - if (sNeedsFullGC || aReason != JS::gcreason::CC_WAITING) { - sNeedsFullGC = false; + if (aIncremental == NonIncrementalGC || aReason == JS::gcreason::FULL_GC_TIMER) { + sNeedsFullGC = true; + } + + if (sNeedsFullGC) { JS::PrepareForFullGC(sRuntime); } else { CycleCollectedJSRuntime::Get()->PrepareWaitingZonesForGC(); @@ -1825,7 +1828,7 @@ nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults) uint32_t ccNowDuration = TimeBetween(gCCStats.mBeginTime, endCCTimeStamp); if (NeedsGCAfterCC()) { - PokeGC(JS::gcreason::CC_WAITING, + PokeGC(JS::gcreason::CC_WAITING, nullptr, NS_GC_DELAY - std::min(ccNowDuration, kMaxICCDuration)); } @@ -2152,11 +2155,20 @@ nsJSContext::RunNextCollectorTimer() // static void -nsJSContext::PokeGC(JS::gcreason::Reason aReason, int aDelay) +nsJSContext::PokeGC(JS::gcreason::Reason aReason, JSObject* aObj, int aDelay) { - sNeedsFullGC = sNeedsFullGC || aReason != JS::gcreason::CC_WAITING; + if (sShuttingDown) { + return; + } - if (sGCTimer || sInterSliceGCTimer || sShuttingDown) { + if (aObj) { + JS::Zone* zone = JS::GetTenuredGCThingZone(aObj); + CycleCollectedJSRuntime::Get()->AddZoneWaitingForGC(zone); + } else if (aReason != JS::gcreason::CC_WAITING) { + sNeedsFullGC = true; + } + + if (sGCTimer || sInterSliceGCTimer) { // There's already a timer for GC'ing, just return return; } @@ -2339,6 +2351,10 @@ DOMGCSliceCallback(JSRuntime *aRt, JS::GCProgress aProgress, const JS::GCDescrip nsJSContext::KillShrinkGCBuffersTimer(); + if (!aDesc.isCompartment_) { + sNeedsFullGC = false; + } + break; } diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index d090549d360..9b0bd6c2696 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -110,7 +110,8 @@ public: static void RunNextCollectorTimer(); - static void PokeGC(JS::gcreason::Reason aReason, int aDelay = 0); + // The GC should probably run soon, in the zone of object aObj (if given). + static void PokeGC(JS::gcreason::Reason aReason, JSObject* aObj, int aDelay = 0); static void KillGCTimer(); static void PokeShrinkGCBuffers(); diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index a8b16390c96..6f40db81fca 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -1040,7 +1040,8 @@ nsDocumentViewer::LoadComplete(nsresult aStatus) nsJSContext::LoadEnd(); // It's probably a good idea to GC soon since we have finished loading. - nsJSContext::PokeGC(JS::gcreason::LOAD_END); + nsJSContext::PokeGC(JS::gcreason::LOAD_END, + mDocument ? mDocument->GetWrapperPreserveColor() : nullptr); #ifdef NS_PRINTING // Check to see if someone tried to print during the load @@ -1316,7 +1317,9 @@ nsDocumentViewer::PageHide(bool aIsUnload) if (aIsUnload) { // Poke the GC. The window might be collectable garbage now. - nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE, NS_GC_DELAY * 2); + nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE, + mDocument->GetWrapperPreserveColor(), + NS_GC_DELAY * 2); } mDocument->OnPageHide(!aIsUnload, nullptr); From 88c83107b43252f9f051ebb136b7996dca5f8e9e Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Tue, 30 Dec 2014 15:54:59 -0800 Subject: [PATCH 09/12] Bug 1116624 - Move CORS into dom/security (r=sicking) --HG-- rename : dom/base/nsCrossSiteListenerProxy.cpp => dom/security/nsCORSListenerProxy.cpp rename : dom/base/nsCrossSiteListenerProxy.h => dom/security/nsCORSListenerProxy.h --- dom/base/EventSource.cpp | 2 +- dom/base/ImportManager.cpp | 2 +- dom/base/Navigator.cpp | 2 +- dom/base/moz.build | 2 -- dom/base/nsScriptLoader.cpp | 2 +- dom/base/nsSyncLoadService.cpp | 2 +- dom/base/nsXMLHttpRequest.cpp | 2 +- dom/html/HTMLMediaElement.cpp | 2 +- dom/media/MediaResource.cpp | 2 +- dom/security/moz.build | 5 +++++ .../nsCORSListenerProxy.cpp} | 2 +- .../nsCORSListenerProxy.h} | 0 dom/xslt/xslt/txMozillaStylesheetCompiler.cpp | 2 +- image/src/imgLoader.cpp | 2 +- layout/build/nsLayoutStatics.cpp | 2 +- layout/style/FontFaceSet.cpp | 2 +- layout/style/Loader.cpp | 2 +- 17 files changed, 19 insertions(+), 16 deletions(-) rename dom/{base/nsCrossSiteListenerProxy.cpp => security/nsCORSListenerProxy.cpp} (99%) rename dom/{base/nsCrossSiteListenerProxy.h => security/nsCORSListenerProxy.h} (100%) diff --git a/dom/base/EventSource.cpp b/dom/base/EventSource.cpp index 3a4dc5c06aa..a910ed21f18 100644 --- a/dom/base/EventSource.cpp +++ b/dom/base/EventSource.cpp @@ -31,7 +31,7 @@ #include "nsContentUtils.h" #include "mozilla/Preferences.h" #include "xpcpublic.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsWrapperCacheInlines.h" #include "mozilla/Attributes.h" #include "nsError.h" diff --git a/dom/base/ImportManager.cpp b/dom/base/ImportManager.cpp index 7c0db43fe50..f8e48008ff2 100644 --- a/dom/base/ImportManager.cpp +++ b/dom/base/ImportManager.cpp @@ -10,7 +10,7 @@ #include "HTMLLinkElement.h" #include "nsContentPolicyUtils.h" #include "nsContentUtils.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsIChannel.h" #include "nsIContentPolicy.h" #include "nsIContentSecurityPolicy.h" diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index bafb53ba05f..8ece24377d6 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -20,7 +20,7 @@ #include "nsIContentPolicy.h" #include "nsIContentSecurityPolicy.h" #include "nsContentPolicyUtils.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsISupportsPriority.h" #include "nsICachingChannel.h" #include "nsIWebContentHandlerRegistrar.h" diff --git a/dom/base/moz.build b/dom/base/moz.build index 5a8c803d452..4b2485611cb 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -61,7 +61,6 @@ EXPORTS += [ 'nsContentTypeParser.h', 'nsContentUtils.h', 'nsCopySupport.h', - 'nsCrossSiteListenerProxy.h', 'nsDeprecatedOperationList.h', 'nsDocElementCreatedNotificationRunner.h', 'nsDocumentWarningList.h', @@ -245,7 +244,6 @@ UNIFIED_SOURCES += [ 'nsContentPolicy.cpp', 'nsContentSink.cpp', 'nsCopySupport.cpp', - 'nsCrossSiteListenerProxy.cpp', 'nsDataDocumentContentPolicy.cpp', 'nsDocument.cpp', 'nsDocumentEncoder.cpp', diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index f1f66db2f04..93c9d4c2fa2 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -43,7 +43,7 @@ #include "prlog.h" #include "nsCRT.h" #include "nsContentCreatorFunctions.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsSandboxFlags.h" #include "nsContentTypeParser.h" #include "nsINetworkPredictor.h" diff --git a/dom/base/nsSyncLoadService.cpp b/dom/base/nsSyncLoadService.cpp index 42094f9de37..f1749a3a6d6 100644 --- a/dom/base/nsSyncLoadService.cpp +++ b/dom/base/nsSyncLoadService.cpp @@ -23,7 +23,7 @@ #include "nsNetUtil.h" #include "nsAutoPtr.h" #include "nsStreamUtils.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include using mozilla::net::ReferrerPolicy; diff --git a/dom/base/nsXMLHttpRequest.cpp b/dom/base/nsXMLHttpRequest.cpp index 92f20ed8ebb..d9883419ff7 100644 --- a/dom/base/nsXMLHttpRequest.cpp +++ b/dom/base/nsXMLHttpRequest.cpp @@ -46,7 +46,7 @@ #include "nsIContentPolicy.h" #include "nsContentPolicyUtils.h" #include "nsError.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsIHTMLDocument.h" #include "nsIStorageStream.h" #include "nsIPromptFactory.h" diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index cdf4c46e2cc..13499e293e7 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -52,7 +52,7 @@ #include "nsIContentPolicy.h" #include "nsContentPolicyUtils.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsCycleCollectionParticipant.h" #include "nsICachingChannel.h" #include "nsLayoutUtils.h" diff --git a/dom/media/MediaResource.cpp b/dom/media/MediaResource.cpp index f8aba90b2ed..8028420b388 100644 --- a/dom/media/MediaResource.cpp +++ b/dom/media/MediaResource.cpp @@ -22,7 +22,7 @@ #include "nsIRequestObserver.h" #include "nsIStreamListener.h" #include "nsIScriptSecurityManager.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "mozilla/dom/HTMLMediaElement.h" #include "nsError.h" #include "nsICachingChannel.h" diff --git a/dom/security/moz.build b/dom/security/moz.build index b471e3033ea..92e3c28af4e 100644 --- a/dom/security/moz.build +++ b/dom/security/moz.build @@ -11,7 +11,12 @@ EXPORTS.mozilla.dom += [ 'nsMixedContentBlocker.h', ] +EXPORTS += [ + 'nsCORSListenerProxy.h' +] + UNIFIED_SOURCES += [ + 'nsCORSListenerProxy.cpp', 'nsCSPContext.cpp', 'nsCSPParser.cpp', 'nsCSPService.cpp', diff --git a/dom/base/nsCrossSiteListenerProxy.cpp b/dom/security/nsCORSListenerProxy.cpp similarity index 99% rename from dom/base/nsCrossSiteListenerProxy.cpp rename to dom/security/nsCORSListenerProxy.cpp index 5a983199c00..9738183a5f7 100644 --- a/dom/base/nsCrossSiteListenerProxy.cpp +++ b/dom/security/nsCORSListenerProxy.cpp @@ -6,7 +6,7 @@ #include "mozilla/Assertions.h" #include "mozilla/LinkedList.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsIChannel.h" #include "nsIHttpChannel.h" #include "nsError.h" diff --git a/dom/base/nsCrossSiteListenerProxy.h b/dom/security/nsCORSListenerProxy.h similarity index 100% rename from dom/base/nsCrossSiteListenerProxy.h rename to dom/security/nsCORSListenerProxy.h diff --git a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp index a929282accf..822f6f71101 100644 --- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp +++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp @@ -34,7 +34,7 @@ #include "nsAttrName.h" #include "nsIScriptError.h" #include "nsIURL.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsError.h" #include "mozilla/Attributes.h" #include "mozilla/dom/Element.h" diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp index 901d6bc7e12..666c0c19b5b 100644 --- a/image/src/imgLoader.cpp +++ b/image/src/imgLoader.cpp @@ -16,7 +16,7 @@ #include "nsCOMPtr.h" #include "nsContentUtils.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsNetUtil.h" #include "nsMimeTypes.h" #include "nsStreamUtils.h" diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index 67c421559d3..3103644b237 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -46,7 +46,7 @@ #include "nsCCUncollectableMarker.h" #include "nsTextFragment.h" #include "nsCSSRuleProcessor.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsHTMLDNSPrefetch.h" #include "nsHtml5Module.h" #include "mozilla/dom/FallbackEncoding.h" diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index 385b9c7e9f3..d344f9888cb 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -15,7 +15,7 @@ #include "mozilla/dom/Promise.h" #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/Preferences.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsFontFaceLoader.h" #include "nsIConsoleService.h" #include "nsIContentPolicy.h" diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp index acf6db2675b..357f9d5ca5b 100644 --- a/layout/style/Loader.cpp +++ b/layout/style/Loader.cpp @@ -47,7 +47,7 @@ #include "nsThreadUtils.h" #include "nsGkAtoms.h" #include "nsIThreadInternal.h" -#include "nsCrossSiteListenerProxy.h" +#include "nsCORSListenerProxy.h" #include "nsINetworkPredictor.h" #include "mozilla/dom/ShadowRoot.h" #include "mozilla/dom/URL.h" From 4153cc397240bc89e3cb234b433027a1a42b0829 Mon Sep 17 00:00:00 2001 From: Mark Hammond Date: Mon, 5 Jan 2015 09:05:14 +1100 Subject: [PATCH 10/12] Bug 972196 - copy signedInUser.json on Firefox reset to keep sync working. r=MattN --- browser/components/migration/FirefoxProfileMigrator.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/browser/components/migration/FirefoxProfileMigrator.js b/browser/components/migration/FirefoxProfileMigrator.js index 6e9966b21f5..daf0ff8601f 100644 --- a/browser/components/migration/FirefoxProfileMigrator.js +++ b/browser/components/migration/FirefoxProfileMigrator.js @@ -96,7 +96,8 @@ FirefoxProfileMigrator.prototype._getResourcesInternal = function(sourceProfileD let places = getFileResource(types.HISTORY, ["places.sqlite"]); let cookies = getFileResource(types.COOKIES, ["cookies.sqlite"]); let passwords = getFileResource(types.PASSWORDS, - ["signons.sqlite", "logins.json", "key3.db"]); + ["signons.sqlite", "logins.json", "key3.db", + "signedInUser.json"]); let formData = getFileResource(types.FORMDATA, ["formhistory.sqlite"]); let bookmarksBackups = getFileResource(types.OTHERDATA, [PlacesBackups.profileRelativeFolderPath]); From 7673673608617083389c79a5d1c1ad78cc12cff2 Mon Sep 17 00:00:00 2001 From: Paul Rouget Date: Mon, 5 Jan 2015 03:06:20 +0100 Subject: [PATCH 11/12] Bug 1087877 - [timeline] User should be able to filter out any type of marker. r=vporof --- browser/app/profile/firefox.js | 1 + browser/devtools/shared/widgets/Graphs.jsm | 11 +- browser/devtools/timeline/test/browser.ini | 1 + .../timeline/test/browser_timeline_filters.js | 93 ++++++++++++++ browser/devtools/timeline/test/head.js | 41 +++++++ browser/devtools/timeline/timeline.js | 115 +++++++++++++++++- browser/devtools/timeline/timeline.xul | 8 ++ .../timeline/widgets/markers-overview.js | 26 ++-- .../devtools/timeline/widgets/waterfall.js | 20 ++- .../chrome/browser/devtools/timeline.dtd | 8 +- browser/themes/linux/jar.mn | 1 + browser/themes/osx/jar.mn | 1 + .../devtools/images/timeline-filter.svg | 37 ++++++ .../themes/shared/devtools/timeline.inc.css | 31 ++++- .../themes/shared/devtools/toolbars.inc.css | 24 ++-- browser/themes/windows/jar.mn | 2 + 16 files changed, 384 insertions(+), 36 deletions(-) create mode 100644 browser/devtools/timeline/test/browser_timeline_filters.js create mode 100644 browser/themes/shared/devtools/images/timeline-filter.svg diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index b5b727c6bf3..030dd91772d 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1439,6 +1439,7 @@ pref("devtools.timeline.enabled", true); #else pref("devtools.timeline.enabled", false); #endif +pref("devtools.timeline.hiddenMarkers", "[]"); // Enable perftools via build command #ifdef MOZ_DEVTOOLS_PERFTOOLS diff --git a/browser/devtools/shared/widgets/Graphs.jsm b/browser/devtools/shared/widgets/Graphs.jsm index ec80948677c..826ab553630 100644 --- a/browser/devtools/shared/widgets/Graphs.jsm +++ b/browser/devtools/shared/widgets/Graphs.jsm @@ -616,14 +616,19 @@ AbstractCanvasGraph.prototype = { /** * Updates this graph to reflect the new dimensions of the parent node. + * + * @param boolean options.force + * Force redrawing everything */ - refresh: function() { + refresh: function(options={}) { let bounds = this._parent.getBoundingClientRect(); let newWidth = this.fixedWidth || bounds.width; let newHeight = this.fixedHeight || bounds.height; - // Prevent redrawing everything if the graph's width & height won't change. - if (this._width == newWidth * this._pixelRatio && + // Prevent redrawing everything if the graph's width & height won't change, + // except if force=true. + if (!options.force && + this._width == newWidth * this._pixelRatio && this._height == newHeight * this._pixelRatio) { this.emit("refresh-cancelled"); return; diff --git a/browser/devtools/timeline/test/browser.ini b/browser/devtools/timeline/test/browser.ini index 691cc330408..baf7dfd1058 100644 --- a/browser/devtools/timeline/test/browser.ini +++ b/browser/devtools/timeline/test/browser.ini @@ -6,6 +6,7 @@ support-files = [browser_timeline_aaa_run_first_leaktest.js] [browser_timeline_blueprint.js] +[browser_timeline_filters.js] [browser_timeline_overview-initial-selection-01.js] [browser_timeline_overview-initial-selection-02.js] [browser_timeline_overview-update.js] diff --git a/browser/devtools/timeline/test/browser_timeline_filters.js b/browser/devtools/timeline/test/browser_timeline_filters.js new file mode 100644 index 00000000000..933c7e9dd38 --- /dev/null +++ b/browser/devtools/timeline/test/browser_timeline_filters.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests markers filtering mechanism. + */ + +add_task(function*() { + let { target, panel } = yield initTimelinePanel(SIMPLE_URL); + let { $, $$, TimelineController, TimelineView } = panel.panelWin; + + yield TimelineController.toggleRecording(); + ok(true, "Recording has started."); + + yield waitUntil(() => { + // Wait until we get 3 different markers. + let markers = TimelineController.getMarkers(); + return markers.some(m => m.name == "Styles") && + markers.some(m => m.name == "Reflow") && + markers.some(m => m.name == "Paint"); + }); + + yield TimelineController.toggleRecording(); + + let overview = TimelineView.markersOverview; + let waterfall = TimelineView.waterfall; + + // Select everything + overview.setSelection({ start: 0, end: overview.width }) + + $("#filter-button").click(); + + yield waitUntil(() => !waterfall._outstandingMarkers.length); + + let menuItem1 = $("menuitem[marker-type=Styles]"); + let menuItem2 = $("menuitem[marker-type=Reflow]"); + let menuItem3 = $("menuitem[marker-type=Paint]"); + + let originalHeight = overview.fixedHeight; + + ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (1)"); + ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (1)"); + ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (1)"); + + let heightBefore = overview.fixedHeight; + EventUtils.synthesizeMouseAtCenter(menuItem1, {type: "mouseup"}, panel.panelWin); + yield once(menuItem1, "command"); + + yield waitUntil(() => !waterfall._outstandingMarkers.length); + + // A row is 11px. See markers-overview.js + is(overview.fixedHeight, heightBefore - 11, "Overview is smaller"); + ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (2)"); + ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (2)"); + ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (2)"); + + heightBefore = overview.fixedHeight; + EventUtils.synthesizeMouseAtCenter(menuItem2, {type: "mouseup"}, panel.panelWin); + yield once(menuItem2, "command"); + + yield waitUntil(() => !waterfall._outstandingMarkers.length); + + is(overview.fixedHeight, heightBefore - 11, "Overview is smaller"); + ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (3)"); + ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (3)"); + ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (3)"); + + heightBefore = overview.fixedHeight; + EventUtils.synthesizeMouseAtCenter(menuItem3, {type: "mouseup"}, panel.panelWin); + yield once(menuItem3, "command"); + + yield waitUntil(() => !waterfall._outstandingMarkers.length); + + is(overview.fixedHeight, heightBefore - 11, "Overview is smaller"); + ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (4)"); + ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (4)"); + ok(!$(".waterfall-marker-bar[type=Paint]"), "No 'Paint' marker (4)"); + + for (let item of [menuItem1, menuItem2, menuItem3]) { + EventUtils.synthesizeMouseAtCenter(item, {type: "mouseup"}, panel.panelWin); + yield once(item, "command"); + } + + yield waitUntil(() => !waterfall._outstandingMarkers.length); + + ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (5)"); + ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (5)"); + ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (5)"); + + is(overview.fixedHeight, originalHeight, "Overview restored"); + + $(".waterfall-marker-bar[type=Styles]"); +}); diff --git a/browser/devtools/timeline/test/head.js b/browser/devtools/timeline/test/head.js index 3ac9624e26b..74b185aa361 100644 --- a/browser/devtools/timeline/test/head.js +++ b/browser/devtools/timeline/test/head.js @@ -104,4 +104,45 @@ function waitUntil(predicate, interval = 10) { waitUntil(predicate).then(() => deferred.resolve(true)); }, interval); return deferred.promise; + +} + +/** + * Wait until next tick. + */ +function nextTick() { + let def = promise.defer(); + executeSoon(() => def.resolve()) + return def.promise; +} + +/** + * Wait for eventName on target. + * @param {Object} target An observable object that either supports on/off or + * addEventListener/removeEventListener + * @param {String} eventName + * @param {Boolean} useCapture Optional, for addEventListener/removeEventListener + * @return A promise that resolves when the event has been handled + */ +function once(target, eventName, useCapture=false) { + info("Waiting for event: '" + eventName + "' on " + target + "."); + + let deferred = promise.defer(); + + for (let [add, remove] of [ + ["addEventListener", "removeEventListener"], + ["addListener", "removeListener"], + ["on", "off"] + ]) { + if ((add in target) && (remove in target)) { + target[add](eventName, function onEvent(...aArgs) { + info("Got event: '" + eventName + "' on " + target + "."); + target[remove](eventName, onEvent, useCapture); + deferred.resolve.apply(deferred, aArgs); + }, useCapture); + break; + } + } + + return deferred.promise; } diff --git a/browser/devtools/timeline/timeline.js b/browser/devtools/timeline/timeline.js index ea94dac0c44..68fc4e7fb95 100644 --- a/browser/devtools/timeline/timeline.js +++ b/browser/devtools/timeline/timeline.js @@ -7,6 +7,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/devtools/Loader.jsm"); +Cu.import("resource:///modules/devtools/ViewHelpers.jsm"); devtools.lazyRequireGetter(this, "promise"); devtools.lazyRequireGetter(this, "EventEmitter", @@ -20,6 +21,8 @@ devtools.lazyRequireGetter(this, "Waterfall", "devtools/timeline/waterfall", true); devtools.lazyRequireGetter(this, "MarkerDetails", "devtools/timeline/marker-details", true); +devtools.lazyRequireGetter(this, "TIMELINE_BLUEPRINT", + "devtools/timeline/global", true); devtools.lazyImporter(this, "CanvasGraphUtils", "resource:///modules/devtools/Graphs.jsm"); @@ -30,6 +33,14 @@ devtools.lazyImporter(this, "PluralForm", const OVERVIEW_UPDATE_INTERVAL = 200; const OVERVIEW_INITIAL_SELECTION_RATIO = 0.15; +/** + * Preference for devtools.timeline.hiddenMarkers. + * Stores which markers should be hidden. + */ +const Prefs = new ViewHelpers.Prefs("devtools.timeline", { + hiddenMarkers: ["Json", "hiddenMarkers"] +}); + // The panel's window global is an EventEmitter firing the following events: const EVENTS = { // When a recording is started or stopped, via the `stopwatch` button. @@ -277,8 +288,9 @@ let TimelineView = { * Initialization function, called when the tool is started. */ initialize: Task.async(function*() { - this.markersOverview = new MarkersOverview($("#markers-overview")); - this.waterfall = new Waterfall($("#timeline-waterfall"), $("#timeline-pane")); + let blueprint = this._getFilteredBluePrint(); + this.markersOverview = new MarkersOverview($("#markers-overview"), blueprint); + this.waterfall = new Waterfall($("#timeline-waterfall"), $("#timeline-pane"), blueprint); this.markerDetails = new MarkerDetails($("#timeline-waterfall-details"), $("#timeline-waterfall-container > splitter")); this._onSelecting = this._onSelecting.bind(this); @@ -292,7 +304,10 @@ let TimelineView = { this.waterfall.on("unselected", this._onMarkerSelected); yield this.markersOverview.ready(); + yield this.waterfall.recalculateBounds(); + + this._buildFilterPopup(); }), /** @@ -465,7 +480,101 @@ let TimelineView = { _onRefresh: function() { this.waterfall.recalculateBounds(); this.updateWaterfall(); - } + }, + + /** + * Rebuild a blueprint without hidden markers. + */ + _getFilteredBluePrint: function() { + let hiddenMarkers = Prefs.hiddenMarkers; + let filteredBlueprint = Cu.cloneInto(TIMELINE_BLUEPRINT, {}); + let maybeRemovedGroups = new Set(); + let removedGroups = new Set(); + + // 1. Remove hidden markers from the blueprint. + + for (let hiddenMarkerName of hiddenMarkers) { + maybeRemovedGroups.add(filteredBlueprint[hiddenMarkerName].group); + delete filteredBlueprint[hiddenMarkerName]; + } + + // 2. Get a list of all the groups that will be removed. + + for (let removedGroup of maybeRemovedGroups) { + let markerNames = Object.keys(filteredBlueprint); + let allGroupsRemoved = markerNames.every(e => filteredBlueprint[e].group != removedGroup); + if (allGroupsRemoved) { + removedGroups.add(removedGroup); + } + } + + // 3. Offset groups. + + for (let removedGroup of removedGroups) { + for (let [, markerDetails] of Iterator(filteredBlueprint)) { + if (markerDetails.group > removedGroup) { + markerDetails.group--; + } + } + } + + return filteredBlueprint; + + }, + + /** + * When the list of hidden markers changes, update waterfall + * and overview. + */ + _onHiddenMarkersChanged: function(e) { + let menuItems = $$("#timelineFilterPopup menuitem[marker-type]:not([checked])"); + let hiddenMarkers = Array.map(menuItems, e => e.getAttribute("marker-type")); + + Prefs.hiddenMarkers = hiddenMarkers; + let blueprint = this._getFilteredBluePrint(); + + this.waterfall.setBlueprint(blueprint); + this.updateWaterfall(); + + this.markersOverview.setBlueprint(blueprint); + this.markersOverview.refresh({ force: true }); + }, + + /** + * Creates the filter popup. + */ + _buildFilterPopup: function() { + let popup = $("#timelineFilterPopup"); + let button = $("#filter-button"); + + popup.addEventListener("popupshowing", () => button.setAttribute("open", "true")); + popup.addEventListener("popuphiding", () => button.removeAttribute("open")); + + this._onHiddenMarkersChanged = this._onHiddenMarkersChanged.bind(this); + + for (let [markerName, markerDetails] of Iterator(TIMELINE_BLUEPRINT)) { + let menuitem = document.createElement("menuitem"); + menuitem.setAttribute("closemenu", "none"); + menuitem.setAttribute("type", "checkbox"); + menuitem.setAttribute("marker-type", markerName); + menuitem.setAttribute("label", markerDetails.label); + menuitem.setAttribute("flex", "1"); + menuitem.setAttribute("align", "center"); + + menuitem.addEventListener("command", this._onHiddenMarkersChanged); + + if (Prefs.hiddenMarkers.indexOf(markerName) == -1) { + menuitem.setAttribute("checked", "true"); + } + + // Style used by pseudo element ::before in timeline.css.in + let bulletStyle = `--bullet-bg: ${markerDetails.fill};` + bulletStyle += `--bullet-border: ${markerDetails.stroke}`; + menuitem.setAttribute("style", bulletStyle); + + popup.appendChild(menuitem); + } + }, }; /** diff --git a/browser/devtools/timeline/timeline.xul b/browser/devtools/timeline/timeline.xul index 56df912b0a3..2d4b8e1939e 100644 --- a/browser/devtools/timeline/timeline.xul +++ b/browser/devtools/timeline/timeline.xul @@ -17,6 +17,10 @@