From 3c51e3c572c994efbbf11d7150cf6865853f9226 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 20 Apr 2015 11:14:57 -0700 Subject: [PATCH 01/80] Bug 1151974 P1 Delay Cache Context start until previous Context has completed. r=ehsan --- dom/cache/Context.cpp | 68 ++++++++++++++++++++++++++++++++++++------- dom/cache/Context.h | 8 ++++- dom/cache/Manager.cpp | 48 ++++++++++++++++++------------ dom/cache/Manager.h | 13 +++++++-- 4 files changed, 103 insertions(+), 34 deletions(-) diff --git a/dom/cache/Context.cpp b/dom/cache/Context.cpp index 9b4d30061ca..2b5c92959ad 100644 --- a/dom/cache/Context.cpp +++ b/dom/cache/Context.cpp @@ -701,18 +701,19 @@ Context::ThreadsafeHandle::ContextDestroyed(Context* aContext) // static already_AddRefed -Context::Create(Manager* aManager, Action* aQuotaIOThreadAction) +Context::Create(Manager* aManager, Action* aQuotaIOThreadAction, + Context* aOldContext) { nsRefPtr context = new Context(aManager); + // Do this here to avoid doing an AddRef() in the constructor context->mInitRunnable = new QuotaInitRunnable(context, aManager, aQuotaIOThreadAction); - nsresult rv = context->mInitRunnable->Dispatch(); - if (NS_FAILED(rv)) { - // Shutdown must be delayed until all Contexts are destroyed. Shutdown - // must also prevent any new Contexts from being constructed. Crash - // for this invariant violation. - MOZ_CRASH("Failed to dispatch QuotaInitRunnable."); + + if (aOldContext) { + aOldContext->SetNextContext(context); + } else { + context->Start(); } return context.forget(); @@ -720,7 +721,7 @@ Context::Create(Manager* aManager, Action* aQuotaIOThreadAction) Context::Context(Manager* aManager) : mManager(aManager) - , mState(STATE_CONTEXT_INIT) + , mState(STATE_CONTEXT_PREINIT) { MOZ_ASSERT(mManager); } @@ -735,7 +736,8 @@ Context::Dispatch(nsIEventTarget* aTarget, Action* aAction) MOZ_ASSERT(mState != STATE_CONTEXT_CANCELED); if (mState == STATE_CONTEXT_CANCELED) { return; - } else if (mState == STATE_CONTEXT_INIT) { + } else if (mState == STATE_CONTEXT_INIT || + mState == STATE_CONTEXT_PREINIT) { PendingAction* pending = mPendingActions.AppendElement(); pending->mTarget = aTarget; pending->mAction = aAction; @@ -751,8 +753,15 @@ Context::CancelAll() { NS_ASSERT_OWNINGTHREAD(Context); - if (mInitRunnable) { - MOZ_ASSERT(mState == STATE_CONTEXT_INIT); + // In PREINIT state we have not dispatch the init runnable yet. Just + // forget it. + if (mState == STATE_CONTEXT_PREINIT) { + mInitRunnable = nullptr; + + // In INIT state we have dispatched the runnable, but not received the + // async completion yet. Cancel the runnable, but don't forget about it + // until we get OnQuotaInit() callback. + } else if (mState == STATE_CONTEXT_INIT) { mInitRunnable->Cancel(); } @@ -823,6 +832,34 @@ Context::~Context() } mManager->RemoveContext(this); + + if (mNextContext) { + mNextContext->Start(); + } +} + +void +Context::Start() +{ + NS_ASSERT_OWNINGTHREAD(Context); + + // Previous context closing delayed our start, but then we were canceled. + // In this case, just do nothing here. + if (mState == STATE_CONTEXT_CANCELED) { + MOZ_ASSERT(!mInitRunnable); + return; + } + + MOZ_ASSERT(mState == STATE_CONTEXT_PREINIT); + mState = STATE_CONTEXT_INIT; + + nsresult rv = mInitRunnable->Dispatch(); + if (NS_FAILED(rv)) { + // Shutdown must be delayed until all Contexts are destroyed. Shutdown + // must also prevent any new Contexts from being constructed. Crash + // for this invariant violation. + MOZ_CRASH("Failed to dispatch QuotaInitRunnable."); + } } void @@ -905,6 +942,15 @@ Context::CreateThreadsafeHandle() return ref.forget(); } +void +Context::SetNextContext(Context* aNextContext) +{ + NS_ASSERT_OWNINGTHREAD(Context); + MOZ_ASSERT(aNextContext); + MOZ_ASSERT(!mNextContext); + mNextContext = aNextContext; +} + } // namespace cache } // namespace dom } // namespace mozilla diff --git a/dom/cache/Context.h b/dom/cache/Context.h index f2abf02e953..b626468514d 100644 --- a/dom/cache/Context.h +++ b/dom/cache/Context.h @@ -111,7 +111,7 @@ public: // will run on the QuotaManager IO thread. Note, this Action must // be execute synchronously. static already_AddRefed - Create(Manager* aManager, Action* aQuotaIOThreadAction); + Create(Manager* aManager, Action* aQuotaIOThreadAction, Context* aOldContext); // Execute given action on the target once the quota manager has been // initialized. @@ -157,6 +157,7 @@ private: enum State { + STATE_CONTEXT_PREINIT, STATE_CONTEXT_INIT, STATE_CONTEXT_READY, STATE_CONTEXT_CANCELED @@ -170,6 +171,7 @@ private: explicit Context(Manager* aManager); ~Context(); + void Start(); void DispatchAction(nsIEventTarget* aTarget, Action* aAction); void OnQuotaInit(nsresult aRv, const QuotaInfo& aQuotaInfo, nsMainThreadPtrHandle& aOfflineStorage); @@ -177,6 +179,9 @@ private: already_AddRefed CreateThreadsafeHandle(); + void + SetNextContext(Context* aNextContext); + nsRefPtr mManager; State mState; QuotaInfo mQuotaInfo; @@ -194,6 +199,7 @@ private: nsRefPtr mThreadsafeHandle; nsMainThreadPtrHandle mOfflineStorage; + nsRefPtr mNextContext; public: NS_INLINE_DECL_REFCOUNTING(cache::Context) diff --git a/dom/cache/Manager.cpp b/dom/cache/Manager.cpp index 4ddde199735..ff779a2f355 100644 --- a/dom/cache/Manager.cpp +++ b/dom/cache/Manager.cpp @@ -157,7 +157,12 @@ public: if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } ref = new Manager(aManagerId, ioThread); - ref->Init(); + + // There may be an old manager for this origin in the process of + // cleaning up. We need to tell the new manager about this so + // that it won't actually start until the old manager is done. + nsRefPtr oldManager = Get(aManagerId, Closing); + ref->Init(oldManager); MOZ_ASSERT(!sFactory->mManagerList.Contains(ref)); sFactory->mManagerList.AppendElement(ref); @@ -169,20 +174,20 @@ public: } static already_AddRefed - Get(ManagerId* aManagerId) + Get(ManagerId* aManagerId, State aState = Open) { mozilla::ipc::AssertIsOnBackgroundThread(); nsresult rv = MaybeCreateInstance(); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } - ManagerList::ForwardIterator iter(sFactory->mManagerList); + // Iterate in reverse to find the most recent, matching Manager. This + // is important when looking for a Closing Manager. If a new Manager + // chains to an old Manager we want it to be the most recent one. + ManagerList::BackwardIterator iter(sFactory->mManagerList); while (iter.HasMore()) { nsRefPtr manager = iter.GetNext(); - // If there is an invalid Manager finishing up and a new Manager - // is created for the same origin, then the new Manager will - // be blocked until QuotaManager finishes clearing the origin. - if (!manager->IsClosing() && *manager->mManagerId == *aManagerId) { + if (aState == manager->GetState() && *manager->mManagerId == *aManagerId) { return manager.forget(); } } @@ -1450,7 +1455,7 @@ Manager::RemoveContext(Context* aContext) // Whether the Context destruction was triggered from the Manager going // idle or the underlying storage being invalidated, we should know we // are closing before the Conext is destroyed. - MOZ_ASSERT(mClosing); + MOZ_ASSERT(mState == Closing); mContext = nullptr; @@ -1465,14 +1470,14 @@ Manager::NoteClosing() { NS_ASSERT_OWNINGTHREAD(Manager); // This can be called more than once legitimately through different paths. - mClosing = true; + mState = Closing; } -bool -Manager::IsClosing() const +Manager::State +Manager::GetState() const { NS_ASSERT_OWNINGTHREAD(Manager); - return mClosing; + return mState; } void @@ -1593,7 +1598,7 @@ Manager::ExecuteCacheOp(Listener* aListener, CacheId aCacheId, MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCacheAddAllArgs); MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCachePutAllArgs); - if (mClosing) { + if (mState == Closing) { aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t()); return; } @@ -1637,7 +1642,7 @@ Manager::ExecuteStorageOp(Listener* aListener, Namespace aNamespace, NS_ASSERT_OWNINGTHREAD(Manager); MOZ_ASSERT(aListener); - if (mClosing) { + if (mState == Closing) { aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t()); return; } @@ -1686,7 +1691,7 @@ Manager::ExecutePutAll(Listener* aListener, CacheId aCacheId, NS_ASSERT_OWNINGTHREAD(Manager); MOZ_ASSERT(aListener); - if (mClosing) { + if (mState == Closing) { aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), CachePutAllResult()); return; } @@ -1708,7 +1713,7 @@ Manager::Manager(ManagerId* aManagerId, nsIThread* aIOThread) , mIOThread(aIOThread) , mContext(nullptr) , mShuttingDown(false) - , mClosing(false) + , mState(Open) { MOZ_ASSERT(mManagerId); MOZ_ASSERT(mIOThread); @@ -1717,7 +1722,7 @@ Manager::Manager(ManagerId* aManagerId, nsIThread* aIOThread) Manager::~Manager() { NS_ASSERT_OWNINGTHREAD(Manager); - MOZ_ASSERT(mClosing); + MOZ_ASSERT(mState == Closing); MOZ_ASSERT(!mContext); nsCOMPtr ioThread; @@ -1731,15 +1736,20 @@ Manager::~Manager() } void -Manager::Init() +Manager::Init(Manager* aOldManager) { NS_ASSERT_OWNINGTHREAD(Manager); + nsRefPtr oldContext; + if (aOldManager) { + oldContext = aOldManager->mContext; + } + // Create the context immediately. Since there can at most be one Context // per Manager now, this lets us cleanly call Factory::Remove() once the // Context goes away. nsRefPtr setupAction = new SetupAction(); - nsRefPtr ref = Context::Create(this, setupAction); + nsRefPtr ref = Context::Create(this, setupAction, oldContext); mContext = ref; } diff --git a/dom/cache/Manager.h b/dom/cache/Manager.h index f07d5e07b2d..e27d2c09e7f 100644 --- a/dom/cache/Manager.h +++ b/dom/cache/Manager.h @@ -119,6 +119,12 @@ public: ~Listener() { } }; + enum State + { + Open, + Closing + }; + static nsresult GetOrCreate(ManagerId* aManagerId, Manager** aManagerOut); static already_AddRefed Get(ManagerId* aManagerId); @@ -134,7 +140,8 @@ public: // Marks the Manager "invalid". Once the Context completes no new operations // will be permitted with this Manager. New actors will get a new Manager. void NoteClosing(); - bool IsClosing() const; + + State GetState() const; // If an actor represents a long term reference to a cache or body stream, // then they must call AddRefCacheId() or AddRefBodyId(). This will @@ -185,7 +192,7 @@ private: Manager(ManagerId* aManagerId, nsIThread* aIOThread); ~Manager(); - void Init(); + void Init(Manager* aOldManager); void Shutdown(); already_AddRefed CurrentContext(); @@ -249,7 +256,7 @@ private: nsTArray mStreamLists; bool mShuttingDown; - bool mClosing; + State mState; struct CacheIdRefCounter { From e78b452a980fff1b5379831e95c281af777dbf09 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 20 Apr 2015 11:14:57 -0700 Subject: [PATCH 02/80] Bug 1151974 P2 Re-enable serviceworkers/test_periodic_update.html. r=ehsan --- dom/workers/test/serviceworkers/mochitest.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/dom/workers/test/serviceworkers/mochitest.ini b/dom/workers/test/serviceworkers/mochitest.ini index 88cbc58d6d8..beaaa6d0ee3 100644 --- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -103,4 +103,3 @@ skip-if = os != "linux" # Bug 1136780 [test_bug1151916.html] [test_empty_serviceworker.html] [test_periodic_update.html] -skip-if = true # bug 1151974 From 6d5738d702cdee800ac972b5c58bca4f83162be5 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Mon, 20 Apr 2015 11:33:40 -0700 Subject: [PATCH 03/80] Bug 1155468 - Fix Register::GetName typedef issue with clang. r=jandem --- js/src/jit/arm/Architecture-arm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/jit/arm/Architecture-arm.h b/js/src/jit/arm/Architecture-arm.h index a4675ceb919..a3f70dd4e52 100644 --- a/js/src/jit/arm/Architecture-arm.h +++ b/js/src/jit/arm/Architecture-arm.h @@ -83,12 +83,12 @@ class Registers }; static const char* GetName(Code code) { + MOZ_ASSERT(code < Total); static const char * const Names[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "r14", "pc"}; return Names[code]; } - static const char* GetName(uint32_t i) { - MOZ_ASSERT(i < Total); + static const char* GetName(Encoding i) { return GetName(Code(i)); } From a35f9ad8089a5944951c913a58d31e8aaa4b432a Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Tue, 14 Apr 2015 13:28:39 -0700 Subject: [PATCH 04/80] Bug 1154085 - Move eager scanning under the ambit of GCMarker::traverse; r=sfink --- js/src/gc/Marking.cpp | 164 ++++++++++++++++-------------------------- js/src/gc/Tracer.cpp | 2 +- js/src/gc/Tracer.h | 21 ++++-- js/src/jsgc.h | 27 ++++--- 4 files changed, 97 insertions(+), 117 deletions(-) diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 3bef6454b6d..8b8f38c8f4a 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -42,15 +42,11 @@ void * const js::NullPtr::constNullValue = nullptr; JS_PUBLIC_DATA(void * const) JS::NullPtr::constNullValue = nullptr; -static inline void +static void PushMarkStack(GCMarker* gcmarker, JSObject* thing) { gcmarker->traverse(thing); } -static inline void -PushMarkStack(GCMarker* gcmarker, JSFunction* thing) { - gcmarker->traverse(static_cast(thing)); -} -static inline void +static void PushMarkStack(GCMarker* gcmarker, ObjectGroup* thing) { gcmarker->traverse(thing); } @@ -58,23 +54,38 @@ static void PushMarkStack(GCMarker* gcmarker, jit::JitCode* thing) { gcmarker->traverse(thing); } -static inline void +static void PushMarkStack(GCMarker* gcmarker, JSScript* thing) { gcmarker->traverse(thing); } -static inline void +static void PushMarkStack(GCMarker* gcmarker, LazyScript* thing) { gcmarker->traverse(thing); } +static void +PushMarkStack(GCMarker* gcmarker, Shape* thing) { + gcmarker->traverse(thing); +} +static void +PushMarkStack(GCMarker* gcmarker, BaseShape* thing) { + gcmarker->traverse(thing); +} +static void +PushMarkStack(GCMarker* gcmarker, JSString* str) { + // Permanent atoms might not be associated with this runtime. + if (str->isPermanentAtom()) + return; -static inline void -PushMarkStack(GCMarker* gcmarker, Shape* thing); -static inline void -PushMarkStack(GCMarker* gcmarker, BaseShape* thing); -static inline void -PushMarkStack(GCMarker* gcmarker, JSString* thing); -static inline void -PushMarkStack(GCMarker* gcmarker, JS::Symbol* thing); + gcmarker->traverse(str); +} +static void +PushMarkStack(GCMarker* gcmarker, JS::Symbol* sym) { + // Well-known symbols might not be associated with this runtime. + if (sym->isWellKnownSymbol()) + return; + + gcmarker->traverse(sym); +} /*** Object Marking ***/ @@ -236,7 +247,7 @@ CheckMarkedThing(JSTracer* trc, jsid id) // A C++ version of JSGCTraceKind enum class TraceKind { -#define NAMES(name, _) name, +#define NAMES(name, _, __) name, FOR_EACH_GC_LAYOUT(NAMES) #undef NAMES }; @@ -298,7 +309,7 @@ template ::value ? TraceKind::LazyScript : TraceKind::ObjectGroup> struct BaseGCType; -#define IMPL_BASE_GC_TYPE(name, type_) \ +#define IMPL_BASE_GC_TYPE(name, type_, _) \ template struct BaseGCType { typedef type_ type; }; FOR_EACH_GC_LAYOUT(IMPL_BASE_GC_TYPE); #undef IMPL_BASE_GC_TYPE @@ -412,7 +423,7 @@ template void DispatchToTracer(JSTracer* trc, T* thingp, const char* name) { -#define IS_SAME_TYPE_OR(name, type) mozilla::IsSame::value || +#define IS_SAME_TYPE_OR(name, type, _) mozilla::IsSame::value || static_assert( FOR_EACH_GC_LAYOUT(IS_SAME_TYPE_OR) mozilla::IsSame::value || @@ -550,7 +561,7 @@ template static inline void CheckIsMarkedThing(T* thingp) { -#define IS_SAME_TYPE_OR(name, type) mozilla::IsSame::value || +#define IS_SAME_TYPE_OR(name, type, _) mozilla::IsSame::value || static_assert( FOR_EACH_GC_LAYOUT(IS_SAME_TYPE_OR) false, "Only the base cell layout types are allowed into marking/tracing internals"); @@ -930,23 +941,6 @@ MaybePushMarkStackBetweenSlices(GCMarker* gcmarker, JSObject* thing) gcmarker->traverse(thing); } -static void -ScanShape(GCMarker* gcmarker, Shape* shape); - -static void -PushMarkStack(GCMarker* gcmarker, Shape* thing) -{ - JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing); - MOZ_ASSERT(!IsInsideNursery(thing)); - - /* We mark shapes directly rather than pushing on the stack. */ - if (thing->markIfUnmarked(gcmarker->markColor())) - ScanShape(gcmarker, thing); -} - -static inline void -ScanBaseShape(GCMarker* gcmarker, BaseShape* base); - void BaseShape::traceChildren(JSTracer* trc) { @@ -958,49 +952,38 @@ BaseShape::traceChildren(JSTracer* trc) TraceManuallyBarrieredEdge(trc, &global, "global"); } -static void -PushMarkStack(GCMarker* gcmarker, BaseShape* thing) -{ - JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing); - MOZ_ASSERT(!IsInsideNursery(thing)); - - /* We mark base shapes directly rather than pushing on the stack. */ - if (thing->markIfUnmarked(gcmarker->markColor())) - ScanBaseShape(gcmarker, thing); -} - -static void -ScanShape(GCMarker* gcmarker, Shape* shape) +inline void +GCMarker::eagerlyMarkChildren(Shape* shape) { restart: - PushMarkStack(gcmarker, shape->base()); + PushMarkStack(this, shape->base()); const BarrieredBase& id = shape->propidRef(); if (JSID_IS_STRING(id)) - PushMarkStack(gcmarker, JSID_TO_STRING(id)); + PushMarkStack(this, JSID_TO_STRING(id)); else if (JSID_IS_SYMBOL(id)) - PushMarkStack(gcmarker, JSID_TO_SYMBOL(id)); + PushMarkStack(this, JSID_TO_SYMBOL(id)); if (shape->hasGetterObject()) - MaybePushMarkStackBetweenSlices(gcmarker, shape->getterObject()); + MaybePushMarkStackBetweenSlices(this, shape->getterObject()); if (shape->hasSetterObject()) - MaybePushMarkStackBetweenSlices(gcmarker, shape->setterObject()); + MaybePushMarkStackBetweenSlices(this, shape->setterObject()); shape = shape->previous(); - if (shape && shape->markIfUnmarked(gcmarker->markColor())) + if (shape && shape->markIfUnmarked(this->markColor())) goto restart; } -static inline void -ScanBaseShape(GCMarker* gcmarker, BaseShape* base) +inline void +GCMarker::eagerlyMarkChildren(BaseShape* base) { base->assertConsistency(); base->compartment()->mark(); if (GlobalObject* global = base->compartment()->unsafeUnbarrieredMaybeGlobal()) - gcmarker->traverse(global); + traverse(global); /* * All children of the owned base shape are consistent with its @@ -1010,7 +993,7 @@ ScanBaseShape(GCMarker* gcmarker, BaseShape* base) if (base->isOwned()) { UnownedBaseShape* unowned = base->baseUnowned(); MOZ_ASSERT(base->compartment() == unowned->compartment()); - unowned->markIfUnmarked(gcmarker->markColor()); + unowned->markIfUnmarked(markColor()); } } @@ -1091,52 +1074,20 @@ ScanRope(GCMarker* gcmarker, JSRope* rope) MOZ_ASSERT(savedPos == gcmarker->stack.position()); } -static inline void -ScanString(GCMarker* gcmarker, JSString* str) +inline void +GCMarker::eagerlyMarkChildren(JSString* str) { if (str->isLinear()) - ScanLinearString(gcmarker, &str->asLinear()); + ScanLinearString(this, &str->asLinear()); else - ScanRope(gcmarker, &str->asRope()); + ScanRope(this, &str->asRope()); } -static inline void -PushMarkStack(GCMarker* gcmarker, JSString* str) -{ - // Permanent atoms might not be associated with this runtime. - if (str->isPermanentAtom()) - return; - - JS_COMPARTMENT_ASSERT(gcmarker->runtime(), str); - - /* - * As string can only refer to other strings we fully scan its GC graph - * using the explicit stack when navigating the rope tree to avoid - * dealing with strings on the stack in drainMarkStack. - */ - if (str->markIfUnmarked()) - ScanString(gcmarker, str); -} - -static inline void -ScanSymbol(GCMarker* gcmarker, JS::Symbol* sym) +inline void +GCMarker::eagerlyMarkChildren(JS::Symbol* sym) { if (JSString* desc = sym->description()) - PushMarkStack(gcmarker, desc); -} - -static inline void -PushMarkStack(GCMarker* gcmarker, JS::Symbol* sym) -{ - // Well-known symbols might not be associated with this runtime. - if (sym->isWellKnownSymbol()) - return; - - JS_COMPARTMENT_ASSERT(gcmarker->runtime(), sym); - MOZ_ASSERT(!IsInsideNursery(sym)); - - if (sym->markIfUnmarked()) - ScanSymbol(gcmarker, sym); + PushMarkStack(this, desc); } /* @@ -1441,7 +1392,7 @@ GCMarker::markAndScanString(JSObject* source, JSString* str) JS_COMPARTMENT_ASSERT(runtime(), str); MOZ_ASSERT(runtime()->isAtomsZone(str->zone()) || str->zone() == source->zone()); if (str->markIfUnmarked()) - ScanString(this, str); + eagerlyMarkChildren(str); } } @@ -1452,7 +1403,7 @@ GCMarker::markAndScanSymbol(JSObject* source, JS::Symbol* sym) JS_COMPARTMENT_ASSERT(runtime(), sym); MOZ_ASSERT(runtime()->isAtomsZone(sym->zone()) || sym->zone() == source->zone()); if (sym->markIfUnmarked()) - ScanSymbol(this, sym); + eagerlyMarkChildren(sym); } } @@ -1698,6 +1649,17 @@ GCMarker::dispatchToTraceChildren(T* thing) thing->traceChildren(this); } +template +bool +GCMarker::mark(T* thing) +{ + JS_COMPARTMENT_ASSERT(runtime(), thing); + MOZ_ASSERT(!IsInsideNursery(gc::TenuredCell::fromPointer(thing))); + return gc::ParticipatesInCC::value + ? gc::TenuredCell::fromPointer(thing)->markIfUnmarked(markColor()) + : gc::TenuredCell::fromPointer(thing)->markIfUnmarked(gc::BLACK); +} + struct TraceChildrenFunctor { template void operator()(JSTracer* trc, void* thing) { diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp index 36f47094544..de63796d3f7 100644 --- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -37,7 +37,7 @@ DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name) JS::AutoTracingName ctx(trc, name); trc->invoke((void**)thingp, kind); } -#define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(name, type) \ +#define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(name, type, _) \ template void DoCallback(JS::CallbackTracer*, type**, const char*); FOR_EACH_GC_LAYOUT(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS); #undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS diff --git a/js/src/gc/Tracer.h b/js/src/gc/Tracer.h index b75cb2f5f35..e7dd4cda268 100644 --- a/js/src/gc/Tracer.h +++ b/js/src/gc/Tracer.h @@ -161,6 +161,11 @@ class GCMarker : public JSTracer void traverse(JSObject* thing) { markAndPush(ObjectTag, thing); } void traverse(ObjectGroup* thing) { markAndPush(GroupTag, thing); } void traverse(jit::JitCode* thing) { markAndPush(JitCodeTag, thing); } + // Mark the given GC thing and then eagerly mark all children. + void traverse(Shape* thing) { markAndScan(thing); } + void traverse(BaseShape* thing) { markAndScan(thing); } + void traverse(JSString* thing) { markAndScan(thing); } + void traverse(JS::Symbol* thing) { markAndScan(thing); } // The following traverse methods traverse immediately, go out-of-line to do so. void traverse(JSScript* thing) { markAndTraverse(thing); } void traverse(LazyScript* thing) { markAndTraverse(thing); } @@ -250,6 +255,16 @@ class GCMarker : public JSTracer pushTaggedPtr(tag, thing); } + template + void markAndScan(T* thing) { + if (mark(thing)) + eagerlyMarkChildren(thing); + } + void eagerlyMarkChildren(Shape* shape); + void eagerlyMarkChildren(BaseShape* base); + void eagerlyMarkChildren(JSString* str); + void eagerlyMarkChildren(JS::Symbol* sym); + template void markAndTraverse(T* thing) { if (mark(thing)) @@ -263,11 +278,7 @@ class GCMarker : public JSTracer // Mark the given GC thing, but do not trace its children. Return true // if the thing became marked. template - bool mark(T* thing) { - JS_COMPARTMENT_ASSERT(runtime(), thing); - MOZ_ASSERT(!IsInsideNursery(gc::TenuredCell::fromPointer(thing))); - return gc::TenuredCell::fromPointer(thing)->markIfUnmarked(markColor()); - } + bool mark(T* thing); void pushTaggedPtr(StackTag tag, void* ptr) { checkZone(ptr); diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 4165ce8920f..8f18d2bad05 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -24,16 +24,17 @@ #include "vm/NativeObject.h" #define FOR_EACH_GC_LAYOUT(D) \ - D(Object, JSObject) \ - D(String, JSString) \ - D(Symbol, JS::Symbol) \ - D(Script, JSScript) \ - D(AccessorShape, js::AccessorShape) \ - D(Shape, js::Shape) \ - D(BaseShape, js::BaseShape) \ - D(JitCode, js::jit::JitCode) \ - D(LazyScript, js::LazyScript) \ - D(ObjectGroup, js::ObjectGroup) + /* PrettyName TypeName AddToCCKind */ \ + D(AccessorShape, js::AccessorShape, true) \ + D(BaseShape, js::BaseShape, true) \ + D(JitCode, js::jit::JitCode, true) \ + D(LazyScript, js::LazyScript, true) \ + D(Object, JSObject, true) \ + D(ObjectGroup, js::ObjectGroup, true) \ + D(Script, JSScript, true) \ + D(Shape, js::Shape, true) \ + D(String, JSString, false) \ + D(Symbol, JS::Symbol, false) namespace js { @@ -84,6 +85,12 @@ template <> struct MapTypeToFinalizeKind { static const Alloc template <> struct MapTypeToFinalizeKind { static const AllocKind kind = AllocKind::SYMBOL; }; template <> struct MapTypeToFinalizeKind { static const AllocKind kind = AllocKind::JITCODE; }; +template struct ParticipatesInCC {}; +#define EXPAND_PARTICIPATES_IN_CC(_, type, addToCCKind) \ + template <> struct ParticipatesInCC { static const bool value = addToCCKind; }; +FOR_EACH_GC_LAYOUT(EXPAND_PARTICIPATES_IN_CC) +#undef EXPAND_PARTICIPATES_IN_CC + static inline bool IsNurseryAllocable(AllocKind kind) { From 2acdc40b3daba09505bf704b4a8a2139b8ce78b7 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Sat, 18 Apr 2015 15:50:21 -0400 Subject: [PATCH 05/80] Bug 1156010 - Mark nsINode::mParent as MOZ_OWNING_REF; r=smaug --- dom/base/nsINode.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h index 9ee36c14e78..077e09e93db 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -1971,7 +1971,10 @@ protected: nsRefPtr mNodeInfo; - nsINode* mParent; + // mParent is an owning ref most of the time, except for the case of document + // nodes, so it cannot be represented by nsCOMPtr, so mark is as + // MOZ_OWNING_REF. + nsINode* MOZ_OWNING_REF mParent; private: // Boolean flags. From 6736041d5aac761eb9ad0f33bc7466719858dbbf Mon Sep 17 00:00:00 2001 From: Kai Engert Date: Mon, 20 Apr 2015 21:46:19 +0200 Subject: [PATCH 06/80] Bug 1144055, Upgrade Firefox 39 to use NSS 3.19, NSS_3_19_BETA4 to pick up bug 1155279 --- security/nss/TAG-INFO | 2 +- security/nss/coreconf/coreconf.dep | 1 - security/nss/lib/ckfw/builtins/certdata.txt | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/security/nss/TAG-INFO b/security/nss/TAG-INFO index 3c288e6386f..a82a9f3c94e 100644 --- a/security/nss/TAG-INFO +++ b/security/nss/TAG-INFO @@ -1 +1 @@ -NSS_3_19_BETA3 +NSS_3_19_BETA4 diff --git a/security/nss/coreconf/coreconf.dep b/security/nss/coreconf/coreconf.dep index 590d1bfaeee..5182f75552c 100644 --- a/security/nss/coreconf/coreconf.dep +++ b/security/nss/coreconf/coreconf.dep @@ -10,4 +10,3 @@ */ #error "Do not include this header file." - diff --git a/security/nss/lib/ckfw/builtins/certdata.txt b/security/nss/lib/ckfw/builtins/certdata.txt index 1ea27c4fa0d..d3209db50f0 100644 --- a/security/nss/lib/ckfw/builtins/certdata.txt +++ b/security/nss/lib/ckfw/builtins/certdata.txt @@ -187,9 +187,9 @@ END CKA_SERIAL_NUMBER MULTILINE_OCTAL \002\004\065\336\364\317 END -CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR -CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST +CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_TRUSTED_DELEGATOR CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE # Distrust "Distrust a pb.com certificate that does not comply with the baseline requirements." From 068cbb1f828c3eda88a094e60713d93547ca7d7e Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 9 Apr 2015 08:41:49 +0100 Subject: [PATCH 07/80] Bug 1141867 - patch 1 - Use the proper writing mode to return the inline-size from FloatMarginISize. r=smontagu --- layout/generic/nsBlockReflowState.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index 119a770dcc5..836675f781c 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -642,6 +642,8 @@ nsBlockReflowState::CanPlaceFloat(nscoord aFloatISize, aFloatISize; } +// Return the inline-size that the float (including margins) will take up +// in the writing mode of the containing block. static nscoord FloatMarginISize(const nsHTMLReflowState& aCBReflowState, nscoord aFloatAvailableISize, @@ -663,9 +665,11 @@ FloatMarginISize(const nsHTMLReflowState& aCBReflowState, aFloatOffsetState.ComputedLogicalPadding().Size(wm), nsIFrame::ComputeSizeFlags::eShrinkWrap); - return floatSize.ISize(wm) + - aFloatOffsetState.ComputedLogicalMargin().IStartEnd(wm) + - aFloatOffsetState.ComputedLogicalBorderPadding().IStartEnd(wm); + floatSize += aFloatOffsetState.ComputedLogicalMargin().Size(wm); + floatSize += aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm); + + WritingMode cbwm = aCBReflowState.GetWritingMode(); + return floatSize.ConvertTo(cbwm, wm).ISize(cbwm); } bool From fc77be1f6fb855c76b799e2208846c5ebcb58d28 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 9 Apr 2015 10:08:17 +0100 Subject: [PATCH 08/80] Bug 1141867 - patch 2 - If FloatMarginISize returns unconstrained, we need to do an early reflow on the orthogonal float to find out its real size. r=smontagu --- layout/generic/nsBlockReflowState.cpp | 35 +++++++++++++++++++-------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index 836675f781c..dec4dd337cd 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -643,7 +643,10 @@ nsBlockReflowState::CanPlaceFloat(nscoord aFloatISize, } // Return the inline-size that the float (including margins) will take up -// in the writing mode of the containing block. +// in the writing mode of the containing block. If this returns +// NS_UNCONSTRAINEDSIZE, we're dealing with an orthogonal block that +// has block-size:auto, and we'll need to actually reflow it to find out +// how much inline-size it will occupy in the containing block's mode. static nscoord FloatMarginISize(const nsHTMLReflowState& aCBReflowState, nscoord aFloatAvailableISize, @@ -665,11 +668,17 @@ FloatMarginISize(const nsHTMLReflowState& aCBReflowState, aFloatOffsetState.ComputedLogicalPadding().Size(wm), nsIFrame::ComputeSizeFlags::eShrinkWrap); - floatSize += aFloatOffsetState.ComputedLogicalMargin().Size(wm); - floatSize += aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm); - WritingMode cbwm = aCBReflowState.GetWritingMode(); - return floatSize.ConvertTo(cbwm, wm).ISize(cbwm); + nscoord floatISize = floatSize.ConvertTo(cbwm, wm).ISize(cbwm); + if (floatISize == NS_UNCONSTRAINEDSIZE) { + return NS_UNCONSTRAINEDSIZE; // reflow is needed to get the true size + } + + return floatISize + + aFloatOffsetState.ComputedLogicalMargin().Size(wm). + ConvertTo(cbwm, wm).ISize(cbwm) + + aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm). + ConvertTo(cbwm, wm).ISize(cbwm); } bool @@ -725,14 +734,20 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat) // If it's a floating first-letter, we need to reflow it before we // know how wide it is (since we don't compute which letters are part // of the first letter until reflow!). - bool isLetter = aFloat->GetType() == nsGkAtoms::letterFrame; - if (isLetter) { + // We also need to do this early reflow if FloatMarginISize returned + // an unconstrained inline-size, which can occur if the float had an + // orthogonal writing mode and 'auto' block-size (in its mode). + bool earlyFloatReflow = + aFloat->GetType() == nsGkAtoms::letterFrame || + floatMarginISize == NS_UNCONSTRAINEDSIZE; + if (earlyFloatReflow) { mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat, floatMargin, floatOffsets, false, reflowStatus); floatMarginISize = aFloat->ISize(wm) + floatMargin.IStartEnd(wm); NS_ASSERTION(NS_FRAME_IS_COMPLETE(reflowStatus), - "letter frames shouldn't break, and if they do now, " - "then they're breaking at the wrong point"); + "letter frames and orthogonal floats with auto block-size " + "shouldn't break, and if they do now, then they're breaking " + "at the wrong point"); } // Find a place to place the float. The CSS2 spec doesn't want @@ -857,7 +872,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat) // Reflow the float after computing its vertical position so it knows // where to break. - if (!isLetter) { + if (!earlyFloatReflow) { bool pushedDown = mBCoord != saveBCoord; mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat, floatMargin, floatOffsets, pushedDown, reflowStatus); From d0f6f3bedca8513c0faa72b9d309fecc33a99477 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 9 Apr 2015 14:40:54 +0100 Subject: [PATCH 09/80] Bug 1141867 - patch 3 - Reftests for contiguous orthogonal floats. r=smontagu --- .../floats/orthogonal-floats-1-ref.html | 39 +++++++++++++ .../reftests/floats/orthogonal-floats-1a.html | 54 ++++++++++++++++++ .../reftests/floats/orthogonal-floats-1b.html | 54 ++++++++++++++++++ .../reftests/floats/orthogonal-floats-1c.html | 56 +++++++++++++++++++ .../reftests/floats/orthogonal-floats-1d.html | 56 +++++++++++++++++++ layout/reftests/floats/reftest.list | 4 ++ 6 files changed, 263 insertions(+) create mode 100644 layout/reftests/floats/orthogonal-floats-1-ref.html create mode 100644 layout/reftests/floats/orthogonal-floats-1a.html create mode 100644 layout/reftests/floats/orthogonal-floats-1b.html create mode 100644 layout/reftests/floats/orthogonal-floats-1c.html create mode 100644 layout/reftests/floats/orthogonal-floats-1d.html diff --git a/layout/reftests/floats/orthogonal-floats-1-ref.html b/layout/reftests/floats/orthogonal-floats-1-ref.html new file mode 100644 index 00000000000..a5ccc8a3c85 --- /dev/null +++ b/layout/reftests/floats/orthogonal-floats-1-ref.html @@ -0,0 +1,39 @@ + + + + Bug 1141867 - Contiguous right-floating boxes with vertical writing mode + + + + + + + +
+ +
+ +

Test passes if there is a filled green square and no red.

+ + + diff --git a/layout/reftests/floats/orthogonal-floats-1a.html b/layout/reftests/floats/orthogonal-floats-1a.html new file mode 100644 index 00000000000..87aa34da588 --- /dev/null +++ b/layout/reftests/floats/orthogonal-floats-1a.html @@ -0,0 +1,54 @@ + + + + Bug 1141867 - Contiguous right-floating boxes with vertical writing mode + + + + + + + +
abcde
+ +
fghijk
+ +
lmnopq
+ +
rstuv
+ +
wxyz!
+ +
+ +

Test passes if there is a filled green square and no red.

+ + + diff --git a/layout/reftests/floats/orthogonal-floats-1b.html b/layout/reftests/floats/orthogonal-floats-1b.html new file mode 100644 index 00000000000..f4890f32d1a --- /dev/null +++ b/layout/reftests/floats/orthogonal-floats-1b.html @@ -0,0 +1,54 @@ + + + + Bug 1141867 - Contiguous right-floating boxes with vertical writing mode + + + + + + + +
abcde
+ +
fghijk
+ +
lmnopq
+ +
rstuv
+ +
wxyz!
+ +
+ +

Test passes if there is a filled green square and no red.

+ + + diff --git a/layout/reftests/floats/orthogonal-floats-1c.html b/layout/reftests/floats/orthogonal-floats-1c.html new file mode 100644 index 00000000000..4d8f77b032c --- /dev/null +++ b/layout/reftests/floats/orthogonal-floats-1c.html @@ -0,0 +1,56 @@ + + + + Bug 1141867 - Contiguous right-floating boxes with vertical writing mode + + + + + + +
abcde
+ +
fghij
+ +
klmno
+ +
qrstu
+ +
vwxyz
+ +
+ +

Test passes if there is a filled green square and no red.

+ + + diff --git a/layout/reftests/floats/orthogonal-floats-1d.html b/layout/reftests/floats/orthogonal-floats-1d.html new file mode 100644 index 00000000000..97a22e1a666 --- /dev/null +++ b/layout/reftests/floats/orthogonal-floats-1d.html @@ -0,0 +1,56 @@ + + + + Bug 1141867 - Contiguous right-floating boxes with vertical writing mode + + + + + + + +
abcde
+ +
fghij
+ +
klmno
+ +
qrstu
+ +
vwxyz
+ +
+ +

Test passes if there is a filled green square and no red.

+ + + diff --git a/layout/reftests/floats/reftest.list b/layout/reftests/floats/reftest.list index c915e365d5b..fb7a8fa0c33 100644 --- a/layout/reftests/floats/reftest.list +++ b/layout/reftests/floats/reftest.list @@ -35,3 +35,7 @@ fails == 345369-2.html 345369-2-ref.html == float-in-rtl-4b.html float-in-rtl-4-ref.html == float-in-rtl-4c.html float-in-rtl-4-ref.html == float-in-rtl-4d.html float-in-rtl-4-ref.html +fuzzy-if(Android,16,2) == orthogonal-floats-1a.html orthogonal-floats-1-ref.html +== orthogonal-floats-1b.html orthogonal-floats-1-ref.html +fuzzy-if(winWidget,116,700) HTTP(..) == orthogonal-floats-1c.html orthogonal-floats-1-ref.html +fuzzy-if(winWidget,116,700) HTTP(..) == orthogonal-floats-1d.html orthogonal-floats-1-ref.html From fdc89d08f832c4a337cb4a320ef16e2520a9e70f Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 20 Apr 2015 12:47:20 -0700 Subject: [PATCH 10/80] Bug 1126010 - XULContentSinkImpl::mParser should be an nsRefPtr. r=smaug --- dom/xul/nsXULContentSink.cpp | 13 ++++--------- dom/xul/nsXULContentSink.h | 3 +-- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/dom/xul/nsXULContentSink.cpp b/dom/xul/nsXULContentSink.cpp index 3444fd5a9c2..2f728d366db 100644 --- a/dom/xul/nsXULContentSink.cpp +++ b/dom/xul/nsXULContentSink.cpp @@ -162,8 +162,7 @@ XULContentSinkImpl::XULContentSinkImpl() mTextLength(0), mTextSize(0), mConstrainSize(true), - mState(eInProlog), - mParser(nullptr) + mState(eInProlog) { #ifdef PR_LOGGING @@ -175,8 +174,6 @@ XULContentSinkImpl::XULContentSinkImpl() XULContentSinkImpl::~XULContentSinkImpl() { - NS_IF_RELEASE(mParser); // XXX should've been released by now, unless error. - // The context stack _should_ be empty, unless something has gone wrong. NS_ASSERTION(mContextStack.Depth() == 0, "Context stack not empty?"); mContextStack.Clear(); @@ -193,14 +190,14 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XULContentSinkImpl) NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager) tmp->mContextStack.Clear(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototype) - NS_IF_RELEASE(tmp->mParser); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XULContentSinkImpl) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager) tmp->mContextStack.Traverse(cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototype) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mParser) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULContentSinkImpl) @@ -241,7 +238,7 @@ XULContentSinkImpl::DidBuildModel(bool aTerminated) // Drop our reference to the parser to get rid of a circular // reference. - NS_IF_RELEASE(mParser); + mParser = nullptr; return NS_OK; } @@ -262,9 +259,7 @@ XULContentSinkImpl::WillResume(void) NS_IMETHODIMP XULContentSinkImpl::SetParser(nsParserBase* aParser) { - NS_IF_RELEASE(mParser); mParser = aParser; - NS_IF_ADDREF(mParser); return NS_OK; } diff --git a/dom/xul/nsXULContentSink.h b/dom/xul/nsXULContentSink.h index 793685ddd4f..377609cd7f6 100644 --- a/dom/xul/nsXULContentSink.h +++ b/dom/xul/nsXULContentSink.h @@ -144,8 +144,7 @@ protected: nsRefPtr mPrototype; // [OWNER] - // We use regular pointer b/c of funky exports on nsIParser: - nsParserBase* mParser; // [OWNER] + nsRefPtr mParser; nsCOMPtr mSecMan; }; From f8dbc523b462bfbd9e21af93db66f65839b1a65c Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 20 Apr 2015 12:48:15 -0700 Subject: [PATCH 11/80] Bug 1144298 - Eliminate gratuitous gotos from Directory::RemoveInternal(). r=baku --- dom/filesystem/Directory.cpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/dom/filesystem/Directory.cpp b/dom/filesystem/Directory.cpp index 3bdacc0017e..916d243df43 100644 --- a/dom/filesystem/Directory.cpp +++ b/dom/filesystem/Directory.cpp @@ -198,29 +198,20 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive, if (aPath.IsFile()) { file = aPath.GetAsFile().Impl(); - goto parameters_check_done; - } - - if (aPath.IsString()) { + } else if (aPath.IsString()) { if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) { error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR; } - goto parameters_check_done; - } - - if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) { + } else if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) { error = NS_ERROR_DOM_SECURITY_ERR; - goto parameters_check_done; + } else { + realPath = aPath.GetAsDirectory().mPath; + // The target must be a descendant of this directory. + if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) { + error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR; + } } - realPath = aPath.GetAsDirectory().mPath; - // The target must be a descendant of this directory. - if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) { - error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR; - } - -parameters_check_done: - nsRefPtr task = new RemoveTask(mFileSystem, mPath, file, realPath, aRecursive, aRv); if (aRv.Failed()) { From f5d120a4c2632897492a8bbb2bcbce3f34a9eb4e Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Mon, 20 Apr 2015 12:50:33 -0700 Subject: [PATCH 12/80] Bug 1141661 - No need to manually convert this URI anymore. r=mossop --- .../components/processsingleton/MainProcessSingleton.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/toolkit/components/processsingleton/MainProcessSingleton.js b/toolkit/components/processsingleton/MainProcessSingleton.js index 0a57996593e..76a0c14330b 100644 --- a/toolkit/components/processsingleton/MainProcessSingleton.js +++ b/toolkit/components/processsingleton/MainProcessSingleton.js @@ -12,13 +12,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); -// Temporary workaround for bug 1141661 -function convertURL(url) { - let chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"]. - getService(Ci.nsIChromeRegistry); - return chromeRegistry.convertChromeURL(Services.io.newURI(url, null, null)).spec; -} - function MainProcessSingleton() {} MainProcessSingleton.prototype = { classID: Components.ID("{0636a680-45cb-11e4-916c-0800200c9a66}"), @@ -85,7 +78,7 @@ MainProcessSingleton.prototype = { // Load this script early so that console.* is initialized // before other frame scripts. Services.mm.loadFrameScript("chrome://global/content/browser-content.js", true); - Services.ppmm.loadProcessScript(convertURL("chrome://global/content/process-content.js"), true); + Services.ppmm.loadProcessScript("chrome://global/content/process-content.js", true); Services.ppmm.addMessageListener("Console:Log", this.logConsoleMessage); Services.mm.addMessageListener("Search:AddEngine", this.addSearchEngine); break; From 3265550b1283d38f96e3ed1bc3b8686ba29cd703 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Mon, 20 Apr 2015 12:50:34 -0700 Subject: [PATCH 13/80] Bug 1141661 - Load chrome before processing delayed frame scripts. r=smaug --- dom/ipc/ContentParent.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index bc234c21b6d..fdda2ce021e 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -2360,6 +2360,13 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority, bool aSetupOffMainThreadCompositing, bool aSendRegisteredChrome) { + if (aSendRegisteredChrome) { + nsCOMPtr registrySvc = nsChromeRegistry::GetService(); + nsChromeRegistryChrome* chromeRegistry = + static_cast(registrySvc.get()); + chromeRegistry->SendRegisteredChrome(this); + } + // Initialize the message manager (and load delayed scripts) now that we // have established communications with the child. mMessageManager->InitWithCallback(this); @@ -2402,13 +2409,6 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority, #endif } - if (aSendRegisteredChrome) { - nsCOMPtr registrySvc = nsChromeRegistry::GetService(); - nsChromeRegistryChrome* chromeRegistry = - static_cast(registrySvc.get()); - chromeRegistry->SendRegisteredChrome(this); - } - if (gAppData) { nsCString version(gAppData->version); nsCString buildID(gAppData->buildID); From aa63c446659f3c9c9754bc79b03d86955783a6dd Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Mon, 20 Apr 2015 14:15:27 -0600 Subject: [PATCH 14/80] Bug 1133833 - Disable xpcshell test_async_notification.js on Android 4.3 for frequent failures; r=trivial,test-only --- image/test/unit/xpcshell.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/image/test/unit/xpcshell.ini b/image/test/unit/xpcshell.ini index 6dc229e0323..c3332743410 100644 --- a/image/test/unit/xpcshell.ini +++ b/image/test/unit/xpcshell.ini @@ -34,6 +34,8 @@ support-files = [test_async_notification.js] +# Bug 1156452: frequent crash on Android 4.3 +skip-if = android_version == "18" [test_async_notification_404.js] [test_async_notification_animated.js] [test_encoder_apng.js] From d12ff3819077ba098a4c9477e55f2e5f0090b47d Mon Sep 17 00:00:00 2001 From: Danilo Cesar Lemes de Paula Date: Mon, 20 Apr 2015 16:16:17 -0400 Subject: [PATCH 15/80] Bug 1146024 - Fix up input routing for APZ on Fennec. r=kats nsWindow::ProcessUntransformedAPZEvent is the method that deals with APZ Input, so it should receive it's events --- gfx/layers/apz/util/APZThreadUtils.cpp | 12 ++++++++++++ layout/generic/nsGfxScrollFrame.cpp | 4 ++-- widget/android/AndroidJNI.cpp | 2 +- widget/android/AndroidJavaWrappers.cpp | 7 +++++++ widget/android/AndroidJavaWrappers.h | 5 ++++- widget/android/nsWindow.cpp | 15 ++++++++++++++- widget/android/nsWindow.h | 2 ++ 7 files changed, 42 insertions(+), 5 deletions(-) diff --git a/gfx/layers/apz/util/APZThreadUtils.cpp b/gfx/layers/apz/util/APZThreadUtils.cpp index 9c4ddc35a2f..1b77f0a5781 100644 --- a/gfx/layers/apz/util/APZThreadUtils.cpp +++ b/gfx/layers/apz/util/APZThreadUtils.cpp @@ -6,6 +6,7 @@ #include "mozilla/layers/APZThreadUtils.h" #include "mozilla/layers/Compositor.h" +#include "AndroidBridge.h" namespace mozilla { namespace layers { @@ -52,6 +53,16 @@ APZThreadUtils::AssertOnCompositorThread() /*static*/ void APZThreadUtils::RunOnControllerThread(Task* aTask) { +#ifdef MOZ_ANDROID_APZ + // This is needed while nsWindow::ConfigureAPZControllerThread is not propper + // implemented. + if (AndroidBridge::IsJavaUiThread()) { + aTask->Run(); + delete aTask; + } else { + AndroidBridge::Bridge()->PostTaskToUiThread(aTask, 0); + } +#else if (!sControllerThread) { // Could happen on startup NS_WARNING("Dropping task posted to controller thread\n"); @@ -65,6 +76,7 @@ APZThreadUtils::RunOnControllerThread(Task* aTask) } else { sControllerThread->PostTask(FROM_HERE, aTask); } +#endif } } // namespace layers diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index ae84492ffec..2c5e4f0a82c 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1074,7 +1074,7 @@ ScrollFrameHelper::HandleScrollbarStyleSwitching() } } -#if defined(MOZ_B2G) || defined(MOZ_WIDGET_ANDROID) +#if defined(MOZ_B2G) || (defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_ANDROID_APZ)) static bool IsFocused(nsIContent* aContent) { // Some content elements, like the GetContent() of a scroll frame @@ -1099,7 +1099,7 @@ ScrollFrameHelper::WantAsyncScroll() const bool isHScrollable = !!(directions & nsIScrollableFrame::HORIZONTAL) && (styles.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN); -#if defined(MOZ_B2G) || defined(MOZ_WIDGET_ANDROID) +#if defined(MOZ_B2G) || (defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_ANDROID_APZ)) // Mobile platforms need focus to scroll. bool canScrollWithoutScrollbars = IsFocused(mOuter->GetContent()); #else diff --git a/widget/android/AndroidJNI.cpp b/widget/android/AndroidJNI.cpp index 3200c8c7942..ce152336eb1 100644 --- a/widget/android/AndroidJNI.cpp +++ b/widget/android/AndroidJNI.cpp @@ -949,7 +949,7 @@ Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(JNIEnv* env, uint64_t blockId; nsEventStatus status = controller->ReceiveInputEvent(input, &guid, &blockId); if (status != nsEventStatus_eConsumeNoDefault) { - nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeApzInputEvent(input, guid, blockId)); + nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeApzInputEvent(input, guid, blockId, status)); } return true; } diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index 829aa3916c9..5662fac8d06 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -672,6 +672,13 @@ AndroidGeckoEvent::ApzInputBlockId() return mApzInputBlockId; } +nsEventStatus +AndroidGeckoEvent::ApzEventStatus() +{ + MOZ_ASSERT(Type() == APZ_INPUT_EVENT); + return mApzEventStatus; +} + WidgetTouchEvent AndroidGeckoEvent::MakeTouchEvent(nsIWidget* widget) { diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h index 7ef13ec8db5..9f71e217a58 100644 --- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -495,12 +495,13 @@ public: return event; } - static AndroidGeckoEvent* MakeApzInputEvent(const MultiTouchInput& aInput, const mozilla::layers::ScrollableLayerGuid& aGuid, uint64_t aInputBlockId) { + static AndroidGeckoEvent* MakeApzInputEvent(const MultiTouchInput& aInput, const mozilla::layers::ScrollableLayerGuid& aGuid, uint64_t aInputBlockId, nsEventStatus aEventStatus) { AndroidGeckoEvent* event = new AndroidGeckoEvent(); event->Init(APZ_INPUT_EVENT); event->mApzInput = aInput; event->mApzGuid = aGuid; event->mApzInputBlockId = aInputBlockId; + event->mApzEventStatus = aEventStatus; return event; } @@ -570,6 +571,7 @@ public: nsIObserver *Observer() { return mObserver; } mozilla::layers::ScrollableLayerGuid ApzGuid(); uint64_t ApzInputBlockId(); + nsEventStatus ApzEventStatus(); protected: int mAction; @@ -612,6 +614,7 @@ protected: MultiTouchInput mApzInput; mozilla::layers::ScrollableLayerGuid mApzGuid; uint64_t mApzInputBlockId; + nsEventStatus mApzEventStatus; AutoGlobalWrappedJavaObject mObject; void ReadIntArray(nsTArray &aVals, diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index c7717032fb0..0e93f7bd0d8 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -46,6 +46,7 @@ using mozilla::unused; #include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/layers/AsyncCompositionManager.h" #include "mozilla/layers/APZCTreeManager.h" +#include "mozilla/layers/APZThreadUtils.h" #include "GLContext.h" #include "GLContextProvider.h" #include "ScopedGLHelpers.h" @@ -837,7 +838,13 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae) break; } - case AndroidGeckoEvent::APZ_INPUT_EVENT: + case AndroidGeckoEvent::APZ_INPUT_EVENT: { + win->UserActivity(); + + WidgetTouchEvent touchEvent = ae->MakeTouchEvent(win); + win->ProcessUntransformedAPZEvent(&touchEvent, ae->ApzGuid(), ae->ApzInputBlockId(), ae->ApzEventStatus()); + break; + } case AndroidGeckoEvent::MOTION_EVENT: { win->UserActivity(); bool preventDefaultActions = win->OnMultitouchEvent(ae); @@ -2513,6 +2520,12 @@ nsWindow::ConfigureAPZCTreeManager() } } +void +nsWindow::ConfigureAPZControllerThread() +{ + APZThreadUtils::SetControllerThread(nullptr); +} + already_AddRefed nsWindow::CreateRootContentController() { diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h index 04d63bc7c91..8a12eb55771 100644 --- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -203,6 +203,8 @@ protected: void FlushIMEChanges(); void ConfigureAPZCTreeManager() override; + void ConfigureAPZControllerThread() override; + already_AddRefed CreateRootContentController() override; // Call this function when the users activity is the direct cause of an From 0b7d9a127391d5d5f6f68d1da9bf6639bc2dc92b Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 20 Apr 2015 16:25:52 -0400 Subject: [PATCH 16/80] Bug 1146024 - Followup to fix non-android bustage on a CLOSED TREE. r=bustage --- gfx/layers/apz/util/APZThreadUtils.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gfx/layers/apz/util/APZThreadUtils.cpp b/gfx/layers/apz/util/APZThreadUtils.cpp index 1b77f0a5781..7f3dd5eb864 100644 --- a/gfx/layers/apz/util/APZThreadUtils.cpp +++ b/gfx/layers/apz/util/APZThreadUtils.cpp @@ -6,7 +6,9 @@ #include "mozilla/layers/APZThreadUtils.h" #include "mozilla/layers/Compositor.h" +#ifdef MOZ_ANDROID_APZ #include "AndroidBridge.h" +#endif namespace mozilla { namespace layers { From 0b2707c91ef43c4058ac50e5a2f017367c7c1121 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 20 Apr 2015 16:54:46 -0400 Subject: [PATCH 17/80] Bug 1155942. Treat USVString and ByteString as serializable values. r=bkelly --- dom/bindings/parser/WebIDL.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 868542018ae..15e1700d9f1 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -2776,7 +2776,7 @@ class IDLBuiltinType(IDLType): self._typeTag == IDLBuiltinType.Types.unrestricted_double def isSerializable(self): - return self.isPrimitive() or self.isDOMString() or self.isDate() + return self.isPrimitive() or self.isString() or self.isDate() def includesRestrictedFloat(self): return self.isFloat() and not self.isUnrestricted() From 91607f83e63c4bb8f4d4fe38072bc5c0eba6c9e9 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 20 Apr 2015 16:54:46 -0400 Subject: [PATCH 18/80] Bug 1156197. Just use the return value of the cols DOM property for determining the default number of rendered columns for a textarea. r=ms2ger --- dom/html/HTMLTextAreaElement.cpp | 10 +--------- layout/reftests/forms/textarea/reftest.list | 1 + layout/reftests/forms/textarea/various-cols-ref.html | 4 ++++ layout/reftests/forms/textarea/various-cols.html | 4 ++++ 4 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 layout/reftests/forms/textarea/various-cols-ref.html create mode 100644 layout/reftests/forms/textarea/various-cols.html diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp index 6ca702af05f..bd2be22edb1 100644 --- a/dom/html/HTMLTextAreaElement.cpp +++ b/dom/html/HTMLTextAreaElement.cpp @@ -1461,15 +1461,7 @@ HTMLTextAreaElement::IsPasswordTextControl() const NS_IMETHODIMP_(int32_t) HTMLTextAreaElement::GetCols() { - const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::cols); - if (attr) { - int32_t cols = attr->Type() == nsAttrValue::eInteger ? - attr->GetIntegerValue() : 0; - // XXX why a default of 1 char, why hide it - return (cols <= 0) ? 1 : cols; - } - - return DEFAULT_COLS; + return Cols(); } NS_IMETHODIMP_(int32_t) diff --git a/layout/reftests/forms/textarea/reftest.list b/layout/reftests/forms/textarea/reftest.list index 4bf945578fe..866304435f8 100644 --- a/layout/reftests/forms/textarea/reftest.list +++ b/layout/reftests/forms/textarea/reftest.list @@ -11,3 +11,4 @@ skip-if(B2G||Mulet) fails-if(Android) fails-if(gtk2Widget) != rtl.html no-resize == rtl.html in-dynamic-rtl-doc.html == setvalue-framereconstruction-1.html setvalue-framereconstruction-ref.html == padding-scrollbar-placement.html padding-scrollbar-placement-ref.html +== various-cols.html various-cols-ref.html diff --git a/layout/reftests/forms/textarea/various-cols-ref.html b/layout/reftests/forms/textarea/various-cols-ref.html new file mode 100644 index 00000000000..7ba962e61d8 --- /dev/null +++ b/layout/reftests/forms/textarea/various-cols-ref.html @@ -0,0 +1,4 @@ + +
+
+ diff --git a/layout/reftests/forms/textarea/various-cols.html b/layout/reftests/forms/textarea/various-cols.html new file mode 100644 index 00000000000..dc62941d8f6 --- /dev/null +++ b/layout/reftests/forms/textarea/various-cols.html @@ -0,0 +1,4 @@ + +
+
+ From a9824af70a7e987fb1163c9ca232760de6f56f62 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 17 Apr 2015 22:01:02 -0400 Subject: [PATCH 19/80] Bug 1152902 part 1. Add a way to flag a method in webidl as being identity-testable, so we'll expose such an identity test from bindings to other C++ code. r=peterv --- dom/bindings/Codegen.py | 22 ++++++++++++++++++++++ dom/bindings/parser/WebIDL.py | 3 ++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index ca6cbeb9c56..758cf62369c 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -8604,6 +8604,26 @@ class CGStaticMethodJitinfo(CGGeneric): IDLToCIdentifier(method.identifier.name)))) +class CGMethodIdentityTest(CGAbstractMethod): + """ + A class to generate a method-identity test for a given IDL operation. + """ + def __init__(self, descriptor, method): + self.method = method + name = "Is%sMethod" % MakeNativeName(method.identifier.name) + CGAbstractMethod.__init__(self, descriptor, name, 'bool', + [Argument('JS::Handle', 'aObj')]) + + def definition_body(self): + return dedent( + """ + MOZ_ASSERT(aObj); + return js::IsFunctionObject(aObj) && + js::FunctionObjectIsNative(aObj) && + FUNCTION_VALUE_TO_JITINFO(JS::ObjectValue(*aObj)) == &%s_methodinfo; + """ % IDLToCIdentifier(self.method.identifier.name)) + + def getEnumValueName(value): # Some enum values can be empty strings. Others might have weird # characters in them. Deal with the former by returning "_empty", @@ -11200,6 +11220,8 @@ class CGDescriptor(CGThing): cgThings.append(CGMemberJITInfo(descriptor, m)) if props.isCrossOriginMethod: crossOriginMethods.add(m.identifier.name) + if m.getExtendedAttribute("MethodIdentityTestable"): + cgThings.append(CGMethodIdentityTest(descriptor, m)) elif m.isAttr(): if m.stringifier: raise TypeError("Stringifier attributes not supported yet. " diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 15e1700d9f1..5825063b628 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -4163,7 +4163,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope): identifier == "Func" or identifier == "AvailableIn" or identifier == "CheckPermissions" or - identifier == "BinaryName"): + identifier == "BinaryName" or + identifier == "MethodIdentityTestable"): # Known attributes that we don't need to do anything with here pass else: From f9d2845925e078dde834ac24b0a4b46e0505b21a Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 17 Apr 2015 22:01:02 -0400 Subject: [PATCH 20/80] Bug 1152902 part 2. Add a fast path for the case when a Promise is resolved with another Promise. r=nsm --- dom/promise/Promise.cpp | 77 ++++++++++++++++++- dom/promise/Promise.h | 1 + dom/promise/tests/mochitest.ini | 1 + .../test_thenable_vs_promise_ordering.html | 27 +++++++ dom/webidl/Promise.webidl | 2 +- 5 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 dom/promise/tests/test_thenable_vs_promise_ordering.html diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 8b5cf161c71..b323e78491c 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -170,7 +170,7 @@ GetPromise(JSContext* aCx, JS::Handle aFunc) } }; -// Main thread runnable to resolve thenables. +// Runnable to resolve thenables. // Equivalent to the specification's ResolvePromiseViaThenableTask. class ThenableResolverTask final : public nsRunnable { @@ -201,6 +201,8 @@ protected: ThreadsafeAutoJSContext cx; JS::Rooted wrapper(cx, mPromise->GetWrapper()); MOZ_ASSERT(wrapper); // It was preserved! + // If we ever change which compartment we're working in here, make sure to + // fix the fast-path for resolved-with-a-Promise in ResolveInternal. JSAutoCompartment ac(cx, wrapper); JS::Rooted resolveFunc(cx, @@ -271,6 +273,48 @@ private: NS_DECL_OWNINGTHREAD; }; +// Fast version of ThenableResolverTask for use in the cases when we know we're +// calling the canonical Promise.prototype.then on an actual DOM Promise. In +// that case we can just bypass the jumping into and out of JS and call +// AppendCallbacks on that promise directly. +class FastThenableResolverTask final : public nsRunnable +{ +public: + FastThenableResolverTask(PromiseCallback* aResolveCallback, + PromiseCallback* aRejectCallback, + Promise* aNextPromise) + : mResolveCallback(aResolveCallback) + , mRejectCallback(aRejectCallback) + , mNextPromise(aNextPromise) + { + MOZ_ASSERT(aResolveCallback); + MOZ_ASSERT(aRejectCallback); + MOZ_ASSERT(aNextPromise); + MOZ_COUNT_CTOR(FastThenableResolverTask); + } + + virtual + ~FastThenableResolverTask() + { + NS_ASSERT_OWNINGTHREAD(FastThenableResolverTask); + MOZ_COUNT_DTOR(FastThenableResolverTask); + } + +protected: + NS_IMETHOD + Run() override + { + NS_ASSERT_OWNINGTHREAD(FastThenableResolverTask); + mNextPromise->AppendCallbacks(mResolveCallback, mRejectCallback); + return NS_OK; + } + +private: + nsRefPtr mResolveCallback; + nsRefPtr mRejectCallback; + nsRefPtr mNextPromise; +}; + // Promise NS_IMPL_CYCLE_COLLECTION_CLASS(Promise) @@ -1198,6 +1242,37 @@ Promise::ResolveInternal(JSContext* aCx, if (then.isObject() && JS::IsCallable(&then.toObject())) { // This is the then() function of the thenable aValueObj. JS::Rooted thenObj(aCx, &then.toObject()); + + // Add a fast path for the case when we're resolved with an actual + // Promise. This has two requirements: + // + // 1) valueObj is a Promise. + // 2) thenObj is a JSFunction backed by our actual Promise::Then + // implementation. + // + // If those requirements are satisfied, then we know exactly what + // thenObj.call(valueObj) will do, so we can optimize a bit and avoid ever + // entering JS for this stuff. + Promise* nextPromise; + if (PromiseBinding::IsThenMethod(thenObj) && + NS_SUCCEEDED(UNWRAP_OBJECT(Promise, valueObj, nextPromise))) { + // If we were taking the codepath that involves ThenableResolverTask and + // PromiseInit below, then eventually, in ThenableResolverTask::Run, we + // would create some JSFunctions in the compartment of + // this->GetWrapper() and pass them to the PromiseInit. So by the time + // we'd see the resolution value it would be wrapped into the + // compartment of this->GetWrapper(). The global of that compartment is + // this->GetGlobalJSObject(), so use that as the global for + // ResolvePromiseCallback/RejectPromiseCallback. + JS::Rooted glob(aCx, GlobalJSObject()); + nsRefPtr resolveCb = new ResolvePromiseCallback(this, glob); + nsRefPtr rejectCb = new RejectPromiseCallback(this, glob); + nsRefPtr task = + new FastThenableResolverTask(resolveCb, rejectCb, nextPromise); + DispatchToMicroTask(task); + return; + } + nsRefPtr thenCallback = new PromiseInit(thenObj, mozilla::dom::GetIncumbentGlobal()); nsRefPtr task = diff --git a/dom/promise/Promise.h b/dom/promise/Promise.h index e74d923782a..28bf5c957b4 100644 --- a/dom/promise/Promise.h +++ b/dom/promise/Promise.h @@ -85,6 +85,7 @@ class Promise : public nsISupports, friend class RejectPromiseCallback; friend class ResolvePromiseCallback; friend class ThenableResolverTask; + friend class FastThenableResolverTask; friend class WrapperPromiseCallback; public: diff --git a/dom/promise/tests/mochitest.ini b/dom/promise/tests/mochitest.ini index 019353ba567..3b621b1e196 100644 --- a/dom/promise/tests/mochitest.ini +++ b/dom/promise/tests/mochitest.ini @@ -6,3 +6,4 @@ [test_promise_utils.html] [test_resolve.html] [test_resolver_return_value.html] +[test_thenable_vs_promise_ordering.html] diff --git a/dom/promise/tests/test_thenable_vs_promise_ordering.html b/dom/promise/tests/test_thenable_vs_promise_ordering.html new file mode 100644 index 00000000000..161e95d75bd --- /dev/null +++ b/dom/promise/tests/test_thenable_vs_promise_ordering.html @@ -0,0 +1,27 @@ + + +Test for promise resolution ordering with thenables and promises + + +
+ diff --git a/dom/webidl/Promise.webidl b/dom/webidl/Promise.webidl index 1f22f58e208..a98bca780c9 100644 --- a/dom/webidl/Promise.webidl +++ b/dom/webidl/Promise.webidl @@ -34,7 +34,7 @@ interface _Promise { // The [TreatNonCallableAsNull] annotation is required since then() should do // nothing instead of throwing errors when non-callable arguments are passed. - [NewObject] + [NewObject, MethodIdentityTestable] Promise then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null, [TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null); From a0c28e17ff8406b2a5ec1602d49821b0ff4b084f Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Mon, 20 Apr 2015 18:05:47 +0100 Subject: [PATCH 21/80] Bug 1153510 - Improve handling of vertical writing mode in SVG text frames. r=longsonr --- layout/svg/SVGTextFrame.cpp | 220 ++++++++++++++++++++++++++---------- 1 file changed, 161 insertions(+), 59 deletions(-) diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp index 3b8c2f6f3ec..f44fc508c01 100644 --- a/layout/svg/SVGTextFrame.cpp +++ b/layout/svg/SVGTextFrame.cpp @@ -340,13 +340,17 @@ GetBaselinePosition(nsTextFrame* aFrame, uint8_t aDominantBaseline, float aFontSizeScaleFactor) { - // use a dummy WritingMode, because nsTextFrame::GetLogicalBaseLine - // doesn't use it anyway - WritingMode writingMode; + WritingMode writingMode = aFrame->GetWritingMode(); + gfxTextRun::Metrics metrics = + aTextRun->MeasureText(0, aTextRun->GetLength(), gfxFont::LOOSE_INK_EXTENTS, + nullptr, nullptr); + switch (aDominantBaseline) { case NS_STYLE_DOMINANT_BASELINE_HANGING: case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE: - return 0; + return writingMode.IsVerticalRL() + ? metrics.mAscent + metrics.mDescent : 0; + case NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT: case NS_STYLE_DOMINANT_BASELINE_NO_CHANGE: case NS_STYLE_DOMINANT_BASELINE_RESET_SIZE: @@ -354,23 +358,24 @@ GetBaselinePosition(nsTextFrame* aFrame, // support the complex baseline model that SVG 1.1 has and which // css3-linebox now defines. // (fall through) + case NS_STYLE_DOMINANT_BASELINE_AUTO: case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC: - return aFrame->GetLogicalBaseline(writingMode); + return writingMode.IsVerticalRL() + ? metrics.mAscent + metrics.mDescent - + aFrame->GetLogicalBaseline(writingMode) + : aFrame->GetLogicalBaseline(writingMode); + case NS_STYLE_DOMINANT_BASELINE_MIDDLE: return aFrame->GetLogicalBaseline(writingMode) - SVGContentUtils::GetFontXHeight(aFrame) / 2.0 * aFrame->PresContext()->AppUnitsPerCSSPixel() * aFontSizeScaleFactor; - } - gfxTextRun::Metrics metrics = - aTextRun->MeasureText(0, aTextRun->GetLength(), gfxFont::LOOSE_INK_EXTENTS, - nullptr, nullptr); - - switch (aDominantBaseline) { case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE: case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC: - return metrics.mAscent + metrics.mDescent; + return writingMode.IsVerticalLR() + ? 0 : metrics.mAscent + metrics.mDescent; + case NS_STYLE_DOMINANT_BASELINE_CENTRAL: case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL: return (metrics.mAscent + metrics.mDescent) / 2.0; @@ -526,6 +531,14 @@ struct TextRenderedRun return GetTextRun()->IsRightToLeft(); } + /** + * Returns whether this rendered run is vertical. + */ + bool IsVertical() const + { + return GetTextRun()->IsVertical(); + } + /** * Returns the transform that converts from a element's user space into * the coordinate space that rendered runs can be painted directly in. @@ -746,8 +759,12 @@ struct TextRenderedRun /** * The point in user space that the text is positioned at. * + * For a horizontal run: * The x coordinate is the left edge of a LTR run of text or the right edge of * an RTL run. The y coordinate is the baseline of the text. + * For a vertical run: + * The x coordinate is the baseline of the text. + * The y coordinate is the top edge of a LTR run, or bottom of RTL. */ gfxPoint mPosition; @@ -770,7 +787,7 @@ struct TextRenderedRun /** * The baseline in app units of this text run. The measurement is from the - * top of the text frame. + * top of the text frame. (From the left edge if vertical.) */ nscoord mBaseline; @@ -816,10 +833,18 @@ TextRenderedRun::GetTransformFromUserSpaceForPainting( m.Scale(mLengthAdjustScaleFactor, 1.0); // Translation to get the text frame in the right place. - nsPoint t(IsRightToLeft() ? - -mFrame->GetRect().width + aItem.mRightEdge : - -aItem.mLeftEdge, - -mBaseline); + nsPoint t; + if (IsVertical()) { + t = nsPoint(-mBaseline, + IsRightToLeft() + ? -mFrame->GetRect().height + aItem.mRightEdge + : -aItem.mLeftEdge); + } else { + t = nsPoint(IsRightToLeft() + ? -mFrame->GetRect().width + aItem.mRightEdge + : -aItem.mLeftEdge, + -mBaseline); + } m.Translate(AppUnitsToGfxUnits(t, aContext)); return m; @@ -850,10 +875,18 @@ TextRenderedRun::GetTransformFromRunUserSpaceToUserSpace( m.Scale(mLengthAdjustScaleFactor, 1.0); // Translation to get the text frame in the right place. - nsPoint t(IsRightToLeft() ? - -mFrame->GetRect().width + left + right : - 0, - -mBaseline); + nsPoint t; + if (IsVertical()) { + t = nsPoint(-mBaseline, + IsRightToLeft() + ? -mFrame->GetRect().height + left + right + : 0); + } else { + t = nsPoint(IsRightToLeft() + ? -mFrame->GetRect().width + left + right + : 0, + -mBaseline); + } m.Translate(AppUnitsToGfxUnits(t, aContext) * cssPxPerDevPx / mFontSizeScaleFactor); @@ -874,8 +907,10 @@ TextRenderedRun::GetTransformFromRunUserSpaceToFrameUserSpace( // Translate by the horizontal distance into the text frame this // rendered run is. - return m.Translate(gfxPoint(gfxFloat(left) / aContext->AppUnitsPerCSSPixel(), - 0)); + gfxFloat appPerCssPx = aContext->AppUnitsPerCSSPixel(); + gfxPoint t = IsVertical() ? gfxPoint(0, left / appPerCssPx) + : gfxPoint(left / appPerCssPx, 0); + return m.Translate(t); } SVGBBox @@ -895,8 +930,10 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext, // horizontally. nsRect self = mFrame->GetVisualOverflowRectRelativeToSelf(); nsRect rect = mFrame->GetRect(); - nscoord above = -self.y; - nscoord below = self.YMost() - rect.height; + bool vertical = IsVertical(); + nscoord above = vertical ? -self.x : -self.y; + nscoord below = vertical ? self.XMost() - rect.width + : self.YMost() - rect.height; gfxSkipCharsIterator it = mFrame->EnsureTextRun(nsTextFrame::eInflated); gfxTextRun* textRun = mFrame->GetTextRun(nsTextFrame::eInflated); @@ -932,6 +969,11 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext, } nsRect fillInAppUnits(x, baseline - above, width, metrics.mBoundingBox.height + above + below); + if (textRun->IsVertical()) { + // Swap line-relative textMetrics dimensions to physical coordinates. + Swap(fillInAppUnits.x, fillInAppUnits.y); + Swap(fillInAppUnits.width, fillInAppUnits.height); + } // Account for text-shadow. if (aFlags & eIncludeTextShadow) { @@ -949,7 +991,9 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext, // Scale the rectangle up due to any mFontSizeScaleFactor. We scale // it around the text's origin. ScaleAround(fill, - gfxPoint(0.0, aContext->AppUnitsToFloatCSSPixels(baseline)), + textRun->IsVertical() + ? gfxPoint(aContext->AppUnitsToFloatCSSPixels(baseline), 0.0) + : gfxPoint(0.0, aContext->AppUnitsToFloatCSSPixels(baseline)), 1.0 / mFontSizeScaleFactor); // Include the fill if requested. @@ -1091,12 +1135,23 @@ TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext, gfxFloat ascent, descent; GetAscentAndDescentInAppUnits(mFrame, ascent, descent); - gfxFloat topEdge = mFrame->GetLogicalBaseline(mFrame->GetWritingMode()) - ascent; - gfxFloat bottomEdge = topEdge + ascent + descent; - - if (p.y < aContext->AppUnitsToGfxUnits(topEdge) || - p.y >= aContext->AppUnitsToGfxUnits(bottomEdge)) { - return -1; + WritingMode writingMode = mFrame->GetWritingMode(); + if (writingMode.IsVertical()) { + gfxFloat leftEdge = + mFrame->GetLogicalBaseline(writingMode) - + (writingMode.IsVerticalRL() ? ascent : descent); + gfxFloat rightEdge = leftEdge + ascent + descent; + if (p.x < aContext->AppUnitsToGfxUnits(leftEdge) || + p.x > aContext->AppUnitsToGfxUnits(rightEdge)) { + return -1; + } + } else { + gfxFloat topEdge = mFrame->GetLogicalBaseline(writingMode) - ascent; + gfxFloat bottomEdge = topEdge + ascent + descent; + if (p.y < aContext->AppUnitsToGfxUnits(topEdge) || + p.y > aContext->AppUnitsToGfxUnits(bottomEdge)) { + return -1; + } } gfxSkipCharsIterator it = mFrame->EnsureTextRun(nsTextFrame::eInflated); @@ -1111,7 +1166,8 @@ TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext, aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(offset, length, nullptr)); - if (p.x < 0 || p.x >= runAdvance) { + gfxFloat pos = writingMode.IsVertical() ? p.y : p.x; + if (pos < 0 || pos >= runAdvance) { return -1; } @@ -1124,8 +1180,8 @@ TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext, gfxFloat advance = aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(offset, length, nullptr)); - if ((rtl && p.x < runAdvance - advance) || - (!rtl && p.x >= advance)) { + if ((rtl && pos < runAdvance - advance) || + (!rtl && pos >= advance)) { return i; } } @@ -4303,9 +4359,18 @@ SVGTextFrame::GetExtentOfChar(nsIContent* aContent, m.Rotate(mPositions[startIndex].mAngle); m.Scale(1 / mFontSizeScaleFactor, 1 / mFontSizeScaleFactor); - gfxRect glyphRect - (x, -presContext->AppUnitsToGfxUnits(ascent) * cssPxPerDevPx, - advance, presContext->AppUnitsToGfxUnits(ascent + descent) * cssPxPerDevPx); + gfxRect glyphRect; + if (it.TextRun()->IsVertical()) { + glyphRect = + gfxRect(-presContext->AppUnitsToGfxUnits(descent) * cssPxPerDevPx, x, + presContext->AppUnitsToGfxUnits(ascent + descent) * cssPxPerDevPx, + advance); + } else { + glyphRect = + gfxRect(x, -presContext->AppUnitsToGfxUnits(ascent) * cssPxPerDevPx, + advance, + presContext->AppUnitsToGfxUnits(ascent + descent) * cssPxPerDevPx); + } // Transform the glyph's rect into user space. gfxRect r = m.TransformBounds(glyphRect); @@ -4609,11 +4674,21 @@ SVGTextFrame::DetermineCharPositions(nsTArray& aPositions) // Reset the position to the new frame's position. position = frit.Position(); - if (textRun->IsRightToLeft()) { - position.x += frame->GetRect().width; + if (textRun->IsVertical()) { + if (textRun->IsRightToLeft()) { + position.y += frame->GetRect().height; + } + position.x += GetBaselinePosition(frame, textRun, + frit.DominantBaseline(), + mFontSizeScaleFactor); + } else { + if (textRun->IsRightToLeft()) { + position.x += frame->GetRect().width; + } + position.y += GetBaselinePosition(frame, textRun, + frit.DominantBaseline(), + mFontSizeScaleFactor); } - position.y += GetBaselinePosition(frame, textRun, frit.DominantBaseline(), - mFontSizeScaleFactor); // Any characters not in a frame, e.g. when display:none. for (uint32_t i = 0; i < frit.UndisplayedCharacters(); i++) { @@ -4636,7 +4711,8 @@ SVGTextFrame::DetermineCharPositions(nsTArray& aPositions) !textRun->IsClusterStart(it.GetSkippedOffset()))) { nscoord advance = textRun->GetAdvanceWidth(it.GetSkippedOffset(), 1, nullptr); - position.x += textRun->IsRightToLeft() ? -advance : advance; + (textRun->IsVertical() ? position.y : position.x) += + textRun->IsRightToLeft() ? -advance : advance; aPositions.AppendElement(lastPosition); it.AdvanceOriginal(1); } @@ -4651,7 +4727,8 @@ SVGTextFrame::DetermineCharPositions(nsTArray& aPositions) uint32_t length = ClusterLength(textRun, it); nscoord advance = textRun->GetAdvanceWidth(it.GetSkippedOffset(), length, nullptr); - position.x += textRun->IsRightToLeft() ? -advance : advance; + (textRun->IsVertical() ? position.y : position.x) += + textRun->IsRightToLeft() ? -advance : advance; lastPosition = position; } it.AdvanceOriginal(1); @@ -4706,13 +4783,15 @@ ShiftAnchoredChunk(nsTArray& aCharPositions, uint32_t aChunkEnd, gfxFloat aLeftEdge, gfxFloat aRightEdge, - TextAnchorSide aAnchorSide) + TextAnchorSide aAnchorSide, + bool aVertical) { NS_ASSERTION(aLeftEdge <= aRightEdge, "unexpected anchored chunk edges"); NS_ASSERTION(aChunkStart < aChunkEnd, "unexpected values for aChunkStart and " "aChunkEnd"); - gfxFloat shift = aCharPositions[aChunkStart].mPosition.x; + gfxFloat shift = aVertical ? aCharPositions[aChunkStart].mPosition.y + : aCharPositions[aChunkStart].mPosition.x; switch (aAnchorSide) { case eAnchorLeft: shift -= aLeftEdge; @@ -4728,8 +4807,14 @@ ShiftAnchoredChunk(nsTArray& aCharPositions, } if (shift != 0.0) { - for (uint32_t i = aChunkStart; i < aChunkEnd; i++) { - aCharPositions[i].mPosition.x += shift; + if (aVertical) { + for (uint32_t i = aChunkStart; i < aChunkEnd; i++) { + aCharPositions[i].mPosition.y += shift; + } + } else { + for (uint32_t i = aChunkStart; i < aChunkEnd; i++) { + aCharPositions[i].mPosition.x += shift; + } } } } @@ -4781,6 +4866,9 @@ SVGTextFrame::AdjustPositionsForClusters() it.GetGlyphPartialAdvance(partLength, presContext) / mFontSizeScaleFactor; gfxPoint direction = gfxPoint(cos(angle), sin(angle)) * (it.TextRun()->IsRightToLeft() ? -1.0 : 1.0); + if (it.TextRun()->IsVertical()) { + Swap(direction.x, direction.y); + } mPositions[charIndex].mPosition = mPositions[startIndex].mPosition + direction * advance; @@ -4923,7 +5011,9 @@ SVGTextFrame::DoTextPathLayout() gfxFloat halfAdvance = it.GetGlyphAdvance(context) / mFontSizeScaleFactor / 2.0; gfxFloat sign = it.TextRun()->IsRightToLeft() ? -1.0 : 1.0; - gfxFloat midx = mPositions[i].mPosition.x + sign * halfAdvance + offset; + gfxFloat midx = (it.TextRun()->IsVertical() ? mPositions[i].mPosition.y + : mPositions[i].mPosition.x) + + sign * halfAdvance + offset; // Hide the character if it falls off the end of the path. mPositions[i].mHidden = midx < 0 || midx > pathLength; @@ -4969,6 +5059,7 @@ SVGTextFrame::DoAnchoring() it.Next(); } + bool vertical = GetWritingMode().IsVertical(); uint32_t start = it.TextElementCharIndex(); while (start < mPositions.Length()) { it.AdvanceToCharacter(start); @@ -4983,12 +5074,15 @@ SVGTextFrame::DoAnchoring() do { if (!it.IsOriginalCharSkipped() && !it.IsOriginalCharTrimmed()) { gfxFloat advance = it.GetAdvance(presContext) / mFontSizeScaleFactor; + gfxFloat pos = + it.TextRun()->IsVertical() ? mPositions[index].mPosition.y + : mPositions[index].mPosition.x; if (it.TextRun()->IsRightToLeft()) { - left = std::min(left, mPositions[index].mPosition.x - advance); - right = std::max(right, mPositions[index].mPosition.x); + left = std::min(left, pos - advance); + right = std::max(right, pos); } else { - left = std::min(left, mPositions[index].mPosition.x); - right = std::max(right, mPositions[index].mPosition.x + advance); + left = std::min(left, pos); + right = std::max(right, pos + advance); } } it.Next(); @@ -5002,7 +5096,8 @@ SVGTextFrame::DoAnchoring() ConvertLogicalTextAnchorToPhysical(chunkFrame->StyleSVG()->mTextAnchor, isRTL); - ShiftAnchoredChunk(mPositions, start, end, left, right, anchor); + ShiftAnchoredChunk(mPositions, start, end, left, right, anchor, + vertical); } start = it.TextElementCharIndex(); @@ -5073,6 +5168,7 @@ SVGTextFrame::DoGlyphPositioning() } nsPresContext* presContext = PresContext(); + bool vertical = GetWritingMode().IsVertical(); float cssPxPerDevPx = presContext-> AppUnitsToFloatCSSPixels(presContext->AppUnitsPerDevPixel()); @@ -5083,9 +5179,10 @@ SVGTextFrame::DoGlyphPositioning() double adjustment = 0.0; mLengthAdjustScaleFactor = 1.0f; if (adjustingTextLength) { - nscoord frameWidth = GetFirstPrincipalChild()->GetRect().width; + nscoord frameLength = vertical ? GetFirstPrincipalChild()->GetRect().height + : GetFirstPrincipalChild()->GetRect().width; float actualTextLength = - static_cast(presContext->AppUnitsToGfxUnits(frameWidth) * factor); + static_cast(presContext->AppUnitsToGfxUnits(frameLength) * factor); nsRefPtr lengthAdjustEnum = element->LengthAdjust(); uint16_t lengthAdjust = lengthAdjustEnum->AnimVal(); @@ -5119,14 +5216,16 @@ SVGTextFrame::DoGlyphPositioning() mPositions[0].mPosition += deltas[0]; } + gfxFloat xLengthAdjustFactor = vertical ? 1.0 : mLengthAdjustScaleFactor; + gfxFloat yLengthAdjustFactor = vertical ? mLengthAdjustScaleFactor : 1.0; for (uint32_t i = 1; i < mPositions.Length(); i++) { // Fill in unspecified x position. if (!mPositions[i].IsXSpecified()) { nscoord d = charPositions[i].x - charPositions[i - 1].x; mPositions[i].mPosition.x = mPositions[i - 1].mPosition.x + - presContext->AppUnitsToGfxUnits(d) * factor * mLengthAdjustScaleFactor; - if (!mPositions[i].mUnaddressable) { + presContext->AppUnitsToGfxUnits(d) * factor * xLengthAdjustFactor; + if (!vertical && !mPositions[i].mUnaddressable) { mPositions[i].mPosition.x += adjustment; } } @@ -5135,7 +5234,10 @@ SVGTextFrame::DoGlyphPositioning() nscoord d = charPositions[i].y - charPositions[i - 1].y; mPositions[i].mPosition.y = mPositions[i - 1].mPosition.y + - presContext->AppUnitsToGfxUnits(d) * factor; + presContext->AppUnitsToGfxUnits(d) * factor * yLengthAdjustFactor; + if (vertical && !mPositions[i].mUnaddressable) { + mPositions[i].mPosition.y += adjustment; + } } // Add in dx/dy. if (i < deltas.Length()) { From 201d731d72be80bcd24af84a8e74d45175411d0d Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 20 Apr 2015 16:17:00 -0400 Subject: [PATCH 22/80] Bug 1095098 - followup - add back some static analysis attributes lost in a rebase; r=me --- xpcom/base/nsQueryObject.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/xpcom/base/nsQueryObject.h b/xpcom/base/nsQueryObject.h index dceabeb69a9..31e842bfd2e 100644 --- a/xpcom/base/nsQueryObject.h +++ b/xpcom/base/nsQueryObject.h @@ -7,13 +7,15 @@ #ifndef nsQueryObject_h #define nsQueryObject_h +#include "mozilla/Attributes.h" + #include "nsCOMPtr.h" #include "nsRefPtr.h" /*****************************************************************************/ template -class nsQueryObject : public nsCOMPtr_helper +class MOZ_STACK_CLASS nsQueryObject : public nsCOMPtr_helper { public: explicit nsQueryObject(T* aRawPtr) @@ -29,11 +31,11 @@ public: return status; } private: - T* mRawPtr; + T* MOZ_NON_OWNING_REF mRawPtr; }; template -class nsQueryObjectWithError : public nsCOMPtr_helper +class MOZ_STACK_CLASS nsQueryObjectWithError : public nsCOMPtr_helper { public: nsQueryObjectWithError(T* aRawPtr, nsresult* aErrorPtr) @@ -52,7 +54,7 @@ public: return status; } private: - T* mRawPtr; + T* MOZ_NON_OWNING_REF mRawPtr; nsresult* mErrorPtr; }; From fe6fabf75f5a1a23e873977a2c60eaa2be713c59 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 15 Apr 2015 16:24:28 -0600 Subject: [PATCH 23/80] Bug 1155241: Check mInstanceOwner for nullptr in nsObjectLoadingContent::PluginDestroyed; r=smaug --- dom/base/nsObjectLoadingContent.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index ae0cf344fdf..ef0da898391 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -2733,8 +2733,10 @@ nsObjectLoadingContent::PluginDestroyed() // plugins in plugin host. Invalidate instance owner / prototype but otherwise // don't take any action. TeardownProtoChain(); - mInstanceOwner->Destroy(); - mInstanceOwner = nullptr; + if (mInstanceOwner) { + mInstanceOwner->Destroy(); + mInstanceOwner = nullptr; + } return NS_OK; } From 69abaadedfc0fd5ec1e30ffe4146902d933cd47f Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 20 Apr 2015 14:12:41 -0700 Subject: [PATCH 24/80] Backed out 3 changesets (bug 1141867) for reftest orange CLOSED TREE Backed out changeset 8dcfc3ace301 (bug 1141867) Backed out changeset aeaa345b9aeb (bug 1141867) Backed out changeset b1091955192c (bug 1141867) --- layout/generic/nsBlockReflowState.cpp | 35 +++--------- .../floats/orthogonal-floats-1-ref.html | 39 ------------- .../reftests/floats/orthogonal-floats-1a.html | 54 ------------------ .../reftests/floats/orthogonal-floats-1b.html | 54 ------------------ .../reftests/floats/orthogonal-floats-1c.html | 56 ------------------- .../reftests/floats/orthogonal-floats-1d.html | 56 ------------------- layout/reftests/floats/reftest.list | 4 -- 7 files changed, 8 insertions(+), 290 deletions(-) delete mode 100644 layout/reftests/floats/orthogonal-floats-1-ref.html delete mode 100644 layout/reftests/floats/orthogonal-floats-1a.html delete mode 100644 layout/reftests/floats/orthogonal-floats-1b.html delete mode 100644 layout/reftests/floats/orthogonal-floats-1c.html delete mode 100644 layout/reftests/floats/orthogonal-floats-1d.html diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index dec4dd337cd..119a770dcc5 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -642,11 +642,6 @@ nsBlockReflowState::CanPlaceFloat(nscoord aFloatISize, aFloatISize; } -// Return the inline-size that the float (including margins) will take up -// in the writing mode of the containing block. If this returns -// NS_UNCONSTRAINEDSIZE, we're dealing with an orthogonal block that -// has block-size:auto, and we'll need to actually reflow it to find out -// how much inline-size it will occupy in the containing block's mode. static nscoord FloatMarginISize(const nsHTMLReflowState& aCBReflowState, nscoord aFloatAvailableISize, @@ -668,17 +663,9 @@ FloatMarginISize(const nsHTMLReflowState& aCBReflowState, aFloatOffsetState.ComputedLogicalPadding().Size(wm), nsIFrame::ComputeSizeFlags::eShrinkWrap); - WritingMode cbwm = aCBReflowState.GetWritingMode(); - nscoord floatISize = floatSize.ConvertTo(cbwm, wm).ISize(cbwm); - if (floatISize == NS_UNCONSTRAINEDSIZE) { - return NS_UNCONSTRAINEDSIZE; // reflow is needed to get the true size - } - - return floatISize + - aFloatOffsetState.ComputedLogicalMargin().Size(wm). - ConvertTo(cbwm, wm).ISize(cbwm) + - aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm). - ConvertTo(cbwm, wm).ISize(cbwm); + return floatSize.ISize(wm) + + aFloatOffsetState.ComputedLogicalMargin().IStartEnd(wm) + + aFloatOffsetState.ComputedLogicalBorderPadding().IStartEnd(wm); } bool @@ -734,20 +721,14 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat) // If it's a floating first-letter, we need to reflow it before we // know how wide it is (since we don't compute which letters are part // of the first letter until reflow!). - // We also need to do this early reflow if FloatMarginISize returned - // an unconstrained inline-size, which can occur if the float had an - // orthogonal writing mode and 'auto' block-size (in its mode). - bool earlyFloatReflow = - aFloat->GetType() == nsGkAtoms::letterFrame || - floatMarginISize == NS_UNCONSTRAINEDSIZE; - if (earlyFloatReflow) { + bool isLetter = aFloat->GetType() == nsGkAtoms::letterFrame; + if (isLetter) { mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat, floatMargin, floatOffsets, false, reflowStatus); floatMarginISize = aFloat->ISize(wm) + floatMargin.IStartEnd(wm); NS_ASSERTION(NS_FRAME_IS_COMPLETE(reflowStatus), - "letter frames and orthogonal floats with auto block-size " - "shouldn't break, and if they do now, then they're breaking " - "at the wrong point"); + "letter frames shouldn't break, and if they do now, " + "then they're breaking at the wrong point"); } // Find a place to place the float. The CSS2 spec doesn't want @@ -872,7 +853,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat) // Reflow the float after computing its vertical position so it knows // where to break. - if (!earlyFloatReflow) { + if (!isLetter) { bool pushedDown = mBCoord != saveBCoord; mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat, floatMargin, floatOffsets, pushedDown, reflowStatus); diff --git a/layout/reftests/floats/orthogonal-floats-1-ref.html b/layout/reftests/floats/orthogonal-floats-1-ref.html deleted file mode 100644 index a5ccc8a3c85..00000000000 --- a/layout/reftests/floats/orthogonal-floats-1-ref.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - Bug 1141867 - Contiguous right-floating boxes with vertical writing mode - - - - - - - -
- -
- -

Test passes if there is a filled green square and no red.

- - - diff --git a/layout/reftests/floats/orthogonal-floats-1a.html b/layout/reftests/floats/orthogonal-floats-1a.html deleted file mode 100644 index 87aa34da588..00000000000 --- a/layout/reftests/floats/orthogonal-floats-1a.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - Bug 1141867 - Contiguous right-floating boxes with vertical writing mode - - - - - - - -
abcde
- -
fghijk
- -
lmnopq
- -
rstuv
- -
wxyz!
- -
- -

Test passes if there is a filled green square and no red.

- - - diff --git a/layout/reftests/floats/orthogonal-floats-1b.html b/layout/reftests/floats/orthogonal-floats-1b.html deleted file mode 100644 index f4890f32d1a..00000000000 --- a/layout/reftests/floats/orthogonal-floats-1b.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - Bug 1141867 - Contiguous right-floating boxes with vertical writing mode - - - - - - - -
abcde
- -
fghijk
- -
lmnopq
- -
rstuv
- -
wxyz!
- -
- -

Test passes if there is a filled green square and no red.

- - - diff --git a/layout/reftests/floats/orthogonal-floats-1c.html b/layout/reftests/floats/orthogonal-floats-1c.html deleted file mode 100644 index 4d8f77b032c..00000000000 --- a/layout/reftests/floats/orthogonal-floats-1c.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - Bug 1141867 - Contiguous right-floating boxes with vertical writing mode - - - - - - -
abcde
- -
fghij
- -
klmno
- -
qrstu
- -
vwxyz
- -
- -

Test passes if there is a filled green square and no red.

- - - diff --git a/layout/reftests/floats/orthogonal-floats-1d.html b/layout/reftests/floats/orthogonal-floats-1d.html deleted file mode 100644 index 97a22e1a666..00000000000 --- a/layout/reftests/floats/orthogonal-floats-1d.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - Bug 1141867 - Contiguous right-floating boxes with vertical writing mode - - - - - - - -
abcde
- -
fghij
- -
klmno
- -
qrstu
- -
vwxyz
- -
- -

Test passes if there is a filled green square and no red.

- - - diff --git a/layout/reftests/floats/reftest.list b/layout/reftests/floats/reftest.list index fb7a8fa0c33..c915e365d5b 100644 --- a/layout/reftests/floats/reftest.list +++ b/layout/reftests/floats/reftest.list @@ -35,7 +35,3 @@ fails == 345369-2.html 345369-2-ref.html == float-in-rtl-4b.html float-in-rtl-4-ref.html == float-in-rtl-4c.html float-in-rtl-4-ref.html == float-in-rtl-4d.html float-in-rtl-4-ref.html -fuzzy-if(Android,16,2) == orthogonal-floats-1a.html orthogonal-floats-1-ref.html -== orthogonal-floats-1b.html orthogonal-floats-1-ref.html -fuzzy-if(winWidget,116,700) HTTP(..) == orthogonal-floats-1c.html orthogonal-floats-1-ref.html -fuzzy-if(winWidget,116,700) HTTP(..) == orthogonal-floats-1d.html orthogonal-floats-1-ref.html From 75a0893034a38a33400237299574f52b17d6ca85 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Mon, 6 Apr 2015 23:48:55 +0100 Subject: [PATCH 25/80] Bug 1149990 - Support replaying of finished CSS transitions by supporting setting of currentTime/startTime. r=birtles --- dom/animation/AnimationPlayer.cpp | 3 +++ dom/animation/KeyframeEffect.h | 4 ++-- layout/style/nsTransitionManager.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dom/animation/AnimationPlayer.cpp b/dom/animation/AnimationPlayer.cpp index 6ac038b75ab..5e3037247d9 100644 --- a/dom/animation/AnimationPlayer.cpp +++ b/dom/animation/AnimationPlayer.cpp @@ -697,6 +697,9 @@ AnimationPlayer::UpdateFinishedState(bool aSeekFlag) } else if (!currentFinishedState && mIsPreviousStateFinished) { // Clear finished promise. We'll create a new one lazily. mFinished = nullptr; + if (mEffect->AsTransition()) { + mEffect->SetIsFinishedTransition(false); + } } mIsPreviousStateFinished = currentFinishedState; // We must recalculate the current time to take account of any mHoldTime diff --git a/dom/animation/KeyframeEffect.h b/dom/animation/KeyframeEffect.h index 24f71f12f47..2531b41452b 100644 --- a/dom/animation/KeyframeEffect.h +++ b/dom/animation/KeyframeEffect.h @@ -300,10 +300,10 @@ public: return mIsFinishedTransition; } - void SetIsFinishedTransition() { + void SetIsFinishedTransition(bool aIsFinished) { MOZ_ASSERT(AsTransition(), "Calling SetIsFinishedTransition but it's not a transition"); - mIsFinishedTransition = true; + mIsFinishedTransition = aIsFinished; } bool IsInPlay(const AnimationPlayer& aPlayer) const; diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index 6061e8e4400..63eaae79e06 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -831,7 +831,7 @@ nsTransitionManager::FlushTransitions(FlushFlags aFlags) // a non-animation style change that would affect it, we need // to know not to start a new transition for the transition // from the almost-completed value to the final value. - player->GetEffect()->SetIsFinishedTransition(); + player->GetEffect()->SetIsFinishedTransition(true); collection->UpdateAnimationGeneration(mPresContext); transitionStartedOrEnded = true; } else if ((computedTiming.mPhase == From 15f78f02f99520639fbcda6c3da6f0d332220f37 Mon Sep 17 00:00:00 2001 From: Martyn Haigh Date: Mon, 20 Apr 2015 08:33:10 -0700 Subject: [PATCH 26/80] Bug 1156093 - Make sure service stops when Tab Queue open now button is pressed (r=rnewman) --- mobile/android/base/tabqueue/TabQueueService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/mobile/android/base/tabqueue/TabQueueService.java b/mobile/android/base/tabqueue/TabQueueService.java index be585ecbd50..f6a2fb90d1a 100644 --- a/mobile/android/base/tabqueue/TabQueueService.java +++ b/mobile/android/base/tabqueue/TabQueueService.java @@ -138,6 +138,7 @@ public class TabQueueService extends Service { startActivity(forwardIntent); removeView(); + stopSelfResult(startId); } }); From 3abab099e17314f49a7d5c4d333dc7f08bcadd57 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Mon, 20 Apr 2015 12:29:37 +0200 Subject: [PATCH 27/80] Bug 1129498 - Replace remove_all_bookmarks() with .eraseEverything() r=mak --- .../unit/test_leftpane_corruption_handling.js | 24 +- .../test_417228-exclude-from-backup.js | 2 +- .../components/places/tests/head_common.js | 14 -- .../places/tests/inline/head_autocomplete.js | 6 +- .../places/tests/queries/test_async.js | 4 +- .../places/tests/queries/test_redirects.js | 4 +- .../places/tests/queries/test_sorting.js | 2 +- .../places/tests/queries/test_tags.js | 2 +- .../unifiedcomplete/head_autocomplete.js | 2 +- .../places/tests/unit/test_412132.js | 8 +- .../tests/unit/test_adaptive_bug527311.js | 7 +- .../unit/test_asyncExecuteLegacyQueries.js | 9 +- .../places/tests/unit/test_bookmarks_html.js | 14 +- .../tests/unit/test_bookmarks_html_corrupt.js | 2 +- .../places/tests/unit/test_bookmarks_json.js | 6 +- .../test_bookmarks_restore_notification.js | 9 +- .../places/tests/unit/test_frecency.js | 2 +- .../tests/unit/test_pageGuid_bookmarkGuid.js | 12 +- .../unit/test_removeVisitsByTimeframe.js | 2 +- .../unit/test_update_frecency_after_delete.js | 222 +++++++++--------- .../test_utils_getURLsForContainerNode.js | 15 +- 21 files changed, 173 insertions(+), 195 deletions(-) diff --git a/browser/components/places/tests/unit/test_leftpane_corruption_handling.js b/browser/components/places/tests/unit/test_leftpane_corruption_handling.js index 144a732e03e..4d665096e57 100644 --- a/browser/components/places/tests/unit/test_leftpane_corruption_handling.js +++ b/browser/components/places/tests/unit/test_leftpane_corruption_handling.js @@ -8,9 +8,16 @@ * Tests that we build a working leftpane in various corruption situations. */ -function run_test() { +// Used to store the original leftPaneFolderId getter. +let gLeftPaneFolderIdGetter; +let gAllBookmarksFolderIdGetter; +// Used to store the original left Pane status as a JSON string. +let gReferenceHierarchy; +let gLeftPaneFolderId; + +add_task(function* () { // We want empty roots. - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); // Sanity check. Assert.ok(!!PlacesUIUtils); @@ -21,17 +28,8 @@ function run_test() { gAllBookmarksFolderIdGetter = Object.getOwnPropertyDescriptor(PlacesUIUtils, "allBookmarksFolderId"); Assert.equal(typeof(gAllBookmarksFolderIdGetter.get), "function"); - run_next_test(); -} - -do_register_cleanup(remove_all_bookmarks); - -// Used to store the original leftPaneFolderId getter. -let gLeftPaneFolderIdGetter; -let gAllBookmarksFolderIdGetter; -// Used to store the original left Pane status as a JSON string. -let gReferenceHierarchy; -let gLeftPaneFolderId; + do_register_cleanup(() => PlacesUtils.bookmarks.eraseEverything()); +}); add_task(function* () { // Add a third party bogus annotated item. Should not be removed. diff --git a/toolkit/components/places/tests/bookmarks/test_417228-exclude-from-backup.js b/toolkit/components/places/tests/bookmarks/test_417228-exclude-from-backup.js index 48c597a9c8d..7e155b15cf0 100644 --- a/toolkit/components/places/tests/bookmarks/test_417228-exclude-from-backup.js +++ b/toolkit/components/places/tests/bookmarks/test_417228-exclude-from-backup.js @@ -127,7 +127,7 @@ add_task(function() { test.validate(false); // cleanup - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); // manually remove the excluded root PlacesUtils.bookmarks.removeItem(test._excludeRootId); // restore json file diff --git a/toolkit/components/places/tests/head_common.js b/toolkit/components/places/tests/head_common.js index 9e27e30c72e..238687b10f2 100644 --- a/toolkit/components/places/tests/head_common.js +++ b/toolkit/components/places/tests/head_common.js @@ -330,20 +330,6 @@ function visits_in_database(aURI) } } -/** - * Removes all bookmarks and checks for correct cleanup - */ -function remove_all_bookmarks() { - let PU = PlacesUtils; - // Clear all bookmarks - PU.bookmarks.removeFolderChildren(PU.bookmarks.bookmarksMenuFolder); - PU.bookmarks.removeFolderChildren(PU.bookmarks.toolbarFolder); - PU.bookmarks.removeFolderChildren(PU.bookmarks.unfiledBookmarksFolder); - // Check for correct cleanup - check_no_bookmarks(); -} - - /** * Checks that we don't have any bookmark */ diff --git a/toolkit/components/places/tests/inline/head_autocomplete.js b/toolkit/components/places/tests/inline/head_autocomplete.js index 71c44183456..787902cc0b2 100644 --- a/toolkit/components/places/tests/inline/head_autocomplete.js +++ b/toolkit/components/places/tests/inline/head_autocomplete.js @@ -140,8 +140,10 @@ function ensure_results(aSearchString, aExpectedValue) { } // Cleanup. - remove_all_bookmarks(); - PlacesTestUtils.clearHistory().then(resolve); + Promise.all([ + PlacesUtils.bookmarks.eraseEverything(), + PlacesTestUtils.clearHistory() + ]).then(resolve); }; }); diff --git a/toolkit/components/places/tests/queries/test_async.js b/toolkit/components/places/tests/queries/test_async.js index b3eeba1a790..a419664ea42 100644 --- a/toolkit/components/places/tests/queries/test_async.js +++ b/toolkit/components/places/tests/queries/test_async.js @@ -353,7 +353,7 @@ function run_test() add_task(function* test_async() { for (let [, test] in Iterator(tests)) { - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); test.__proto__ = new Test(); yield test.setup(); @@ -362,6 +362,6 @@ add_task(function* test_async() yield test.run(); } - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); print("All tests done, exiting"); }); diff --git a/toolkit/components/places/tests/queries/test_redirects.js b/toolkit/components/places/tests/queries/test_redirects.js index 1abf152b9bc..597de8e4b9c 100644 --- a/toolkit/components/places/tests/queries/test_redirects.js +++ b/toolkit/components/places/tests/queries/test_redirects.js @@ -187,7 +187,7 @@ function run_test() */ add_task(function test_add_visits_to_database() { - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); // We don't really bother on this, but we need a time to add visits. let timeInMicroseconds = Date.now() * 1000; @@ -298,7 +298,7 @@ add_task(function test_redirects() cartProd([includeHidden_options, maxResults_options, sorting_options], check_results_callback); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield PlacesTestUtils.clearHistory(); }); diff --git a/toolkit/components/places/tests/queries/test_sorting.js b/toolkit/components/places/tests/queries/test_sorting.js index a5ca67586ce..c92f2524568 100644 --- a/toolkit/components/places/tests/queries/test_sorting.js +++ b/toolkit/components/places/tests/queries/test_sorting.js @@ -1278,7 +1278,7 @@ add_task(function test_sorting() // sorting reversed, usually SORT_BY have ASC and DESC test.check_reverse(); // Execute cleanup tasks - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield PlacesTestUtils.clearHistory(); } }); diff --git a/toolkit/components/places/tests/queries/test_tags.js b/toolkit/components/places/tests/queries/test_tags.js index b4d2b8c75c1..7974ae26aa1 100644 --- a/toolkit/components/places/tests/queries/test_tags.js +++ b/toolkit/components/places/tests/queries/test_tags.js @@ -554,7 +554,7 @@ function addBookmark(aURI) { * Asynchronous task that removes all pages from history and bookmarks. */ function* task_cleanDatabase(aCallback) { - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield PlacesTestUtils.clearHistory(); } diff --git a/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js index 8ade81ef3d6..7dab8e51400 100644 --- a/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js +++ b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js @@ -32,7 +32,7 @@ function* cleanup() { for (let type of ["history", "bookmark", "history.onlyTyped", "openpage"]) { Services.prefs.clearUserPref("browser.urlbar.suggest." + type); } - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield PlacesTestUtils.clearHistory(); } do_register_cleanup(cleanup); diff --git a/toolkit/components/places/tests/unit/test_412132.js b/toolkit/components/places/tests/unit/test_412132.js index f839904985c..7a72e97de76 100644 --- a/toolkit/components/places/tests/unit/test_412132.js +++ b/toolkit/components/places/tests/unit/test_412132.js @@ -33,7 +33,7 @@ add_task(function changeuri_unvisited_bookmark() do_print("Unvisited URI no longer bookmarked => frecency should = 0"); do_check_eq(frecencyForUrl(TEST_URI), 0); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield PlacesTestUtils.clearHistory(); }); @@ -63,7 +63,7 @@ add_task(function changeuri_visited_bookmark() do_print("*Visited* URI no longer bookmarked => frecency should != 0"); do_check_neq(frecencyForUrl(TEST_URI), 0); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield PlacesTestUtils.clearHistory(); }); @@ -94,7 +94,7 @@ add_task(function changeuri_bookmark_still_bookmarked() do_print("URI still bookmarked => frecency should != 0"); do_check_neq(frecencyForUrl(TEST_URI), 0); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield PlacesTestUtils.clearHistory(); }); @@ -126,7 +126,7 @@ add_task(function changeuri_nonexistent_bookmark() PlacesUtils.bookmarks.removeItem(id); tryChange(id); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield PlacesTestUtils.clearHistory(); }); diff --git a/toolkit/components/places/tests/unit/test_adaptive_bug527311.js b/toolkit/components/places/tests/unit/test_adaptive_bug527311.js index e8621146b3f..348add2c7b8 100644 --- a/toolkit/components/places/tests/unit/test_adaptive_bug527311.js +++ b/toolkit/components/places/tests/unit/test_adaptive_bug527311.js @@ -89,9 +89,10 @@ function check_results() { Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH); do_check_eq(controller.matchCount, 0); - remove_all_bookmarks(); - cleanup(); - do_test_finished(); + PlacesUtils.bookmarks.eraseEverything().then(() => { + cleanup(); + do_test_finished(); + }); }; controller.startSearch(SEARCH_STRING); diff --git a/toolkit/components/places/tests/unit/test_asyncExecuteLegacyQueries.js b/toolkit/components/places/tests/unit/test_asyncExecuteLegacyQueries.js index 7d76c1464d0..43f121c07f1 100644 --- a/toolkit/components/places/tests/unit/test_asyncExecuteLegacyQueries.js +++ b/toolkit/components/places/tests/unit/test_asyncExecuteLegacyQueries.js @@ -88,9 +88,8 @@ function run_next_test() { return; } - let test = tests.shift(); - PlacesTestUtils.clearHistory().then(function() { - remove_all_bookmarks(); - do_execute_soon(test); - }); + Promise.all([ + PlacesTestUtils.clearHistory(), + PlacesUtils.bookmarks.eraseEverything() + ]).then(tests.shift()); } diff --git a/toolkit/components/places/tests/unit/test_bookmarks_html.js b/toolkit/components/places/tests/unit/test_bookmarks_html.js index 34efc095d8a..e55f580b09e 100644 --- a/toolkit/components/places/tests/unit/test_bookmarks_html.js +++ b/toolkit/components/places/tests/unit/test_bookmarks_html.js @@ -104,7 +104,7 @@ add_task(function* setup() { yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew); yield PlacesTestUtils.promiseAsyncUpdates(); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); add_task(function* test_import_new() @@ -118,7 +118,7 @@ add_task(function* test_import_new() yield testImportedBookmarks(); yield PlacesTestUtils.promiseAsyncUpdates(); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); add_task(function* test_emptytitle_export() @@ -146,7 +146,7 @@ add_task(function* test_emptytitle_export() yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew); yield PlacesTestUtils.promiseAsyncUpdates(); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true); yield PlacesTestUtils.promiseAsyncUpdates(); @@ -158,7 +158,7 @@ add_task(function* test_emptytitle_export() yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew); yield PlacesTestUtils.promiseAsyncUpdates(); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); add_task(function* test_import_chromefavicon() @@ -214,7 +214,7 @@ add_task(function* test_import_chromefavicon() deferred.resolve); yield deferred.promise; - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true); yield PlacesTestUtils.promiseAsyncUpdates(); @@ -226,7 +226,7 @@ add_task(function* test_import_chromefavicon() yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew); yield PlacesTestUtils.promiseAsyncUpdates(); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); add_task(function* test_import_ontop() @@ -248,7 +248,7 @@ add_task(function* test_import_ontop() yield PlacesTestUtils.promiseAsyncUpdates(); yield testImportedBookmarks(); yield PlacesTestUtils.promiseAsyncUpdates(); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); function* testImportedBookmarks() diff --git a/toolkit/components/places/tests/unit/test_bookmarks_html_corrupt.js b/toolkit/components/places/tests/unit/test_bookmarks_html_corrupt.js index 91ad65a28db..c302615f954 100644 --- a/toolkit/components/places/tests/unit/test_bookmarks_html_corrupt.js +++ b/toolkit/components/places/tests/unit/test_bookmarks_html_corrupt.js @@ -41,7 +41,7 @@ add_task(function* test_corrupt_database() { yield BookmarkHTMLUtils.exportToFile(bookmarksFile); // Import again and check for correctness. - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield BookmarkHTMLUtils.importFromFile(bookmarksFile, true); yield PlacesTestUtils.promiseAsyncUpdates(); yield database_check(); diff --git a/toolkit/components/places/tests/unit/test_bookmarks_json.js b/toolkit/components/places/tests/unit/test_bookmarks_json.js index 20b121342b0..7dc490807cf 100644 --- a/toolkit/components/places/tests/unit/test_bookmarks_json.js +++ b/toolkit/components/places/tests/unit/test_bookmarks_json.js @@ -90,14 +90,14 @@ add_task(function test_export_bookmarks() { }); add_task(function test_import_exported_bookmarks() { - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield BookmarkJSONUtils.importFromFile(bookmarksExportedFile, true); yield PlacesTestUtils.promiseAsyncUpdates(); yield testImportedBookmarks(); }); add_task(function test_import_ontop() { - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield BookmarkJSONUtils.importFromFile(bookmarksExportedFile, true); yield PlacesTestUtils.promiseAsyncUpdates(); yield BookmarkJSONUtils.exportToFile(bookmarksExportedFile); @@ -108,7 +108,7 @@ add_task(function test_import_ontop() { }); add_task(function test_clean() { - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); function testImportedBookmarks() { diff --git a/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js b/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js index 51f2cbe3b04..11963eae0a6 100644 --- a/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js +++ b/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js @@ -53,7 +53,7 @@ var tests = [ addBookmarks(); yield BookmarkJSONUtils.exportToFile(this.file); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); try { yield BookmarkJSONUtils.importFromFile(this.file, true); } @@ -114,7 +114,7 @@ var tests = [ this.file = yield promiseFile("bookmarks-test_restoreNotification.html"); addBookmarks(); yield BookmarkHTMLUtils.exportToFile(this.file); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); try { BookmarkHTMLUtils.importFromFile(this.file, false) .then(null, do_report_unexpected_exception); @@ -174,7 +174,7 @@ var tests = [ this.file = yield promiseFile("bookmarks-test_restoreNotification.init.html"); addBookmarks(); yield BookmarkHTMLUtils.exportToFile(this.file); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); try { BookmarkHTMLUtils.importFromFile(this.file, true) .then(null, do_report_unexpected_exception); @@ -269,8 +269,7 @@ var successAndFailedObserver = { else do_check_eq(test.folderId, null); - remove_all_bookmarks(); - do_execute_soon(doNextTest); + PlacesUtils.bookmarks.eraseEverything().then(doNextTest); } }; diff --git a/toolkit/components/places/tests/unit/test_frecency.js b/toolkit/components/places/tests/unit/test_frecency.js index 6fb6df245b0..edf5805e761 100644 --- a/toolkit/components/places/tests/unit/test_frecency.js +++ b/toolkit/components/places/tests/unit/test_frecency.js @@ -286,7 +286,7 @@ add_task(function test_frecency() prefs.setBoolPref("browser.urlbar.suggest.bookmark", true); prefs.setBoolPref("browser.urlbar.suggest.openpage", false); for (let [, test] in Iterator(tests)) { - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); yield PlacesTestUtils.clearHistory(); deferEnsureResults = Promise.defer(); diff --git a/toolkit/components/places/tests/unit/test_pageGuid_bookmarkGuid.js b/toolkit/components/places/tests/unit/test_pageGuid_bookmarkGuid.js index e84ac1952cf..2237441e427 100644 --- a/toolkit/components/places/tests/unit/test_pageGuid_bookmarkGuid.js +++ b/toolkit/components/places/tests/unit/test_pageGuid_bookmarkGuid.js @@ -56,7 +56,7 @@ add_task(function test_addBookmarksAndCheckGuids() { root.containerOpen = false; - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); add_task(function test_updateBookmarksAndCheckGuids() { @@ -85,7 +85,7 @@ add_task(function test_updateBookmarksAndCheckGuids() { root.containerOpen = false; - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); add_task(function test_addVisitAndCheckGuid() { @@ -133,7 +133,7 @@ add_task(function test_addItemsWithInvalidGUIDsFails() { } catch(ex) { } - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); add_task(function test_addItemsWithGUIDs() { @@ -154,7 +154,7 @@ add_task(function test_addItemsWithGUIDs() { do_check_eq(root.getChild(1).bookmarkGuid, SEPARATOR_GUID); root.containerOpen = false; - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); add_task(function test_emptyGUIDIgnored() { @@ -162,7 +162,7 @@ add_task(function test_emptyGUIDIgnored() { bmsvc.DEFAULT_INDEX, ""); do_check_valid_places_guid(PlacesUtils.getFolderContents(folder) .root.bookmarkGuid); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); add_task(function test_usingSameGUIDFails() { @@ -176,5 +176,5 @@ add_task(function test_usingSameGUIDFails() { } catch(ex) { } - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); }); diff --git a/toolkit/components/places/tests/unit/test_removeVisitsByTimeframe.js b/toolkit/components/places/tests/unit/test_removeVisitsByTimeframe.js index 88d36cc0d22..261109639b5 100644 --- a/toolkit/components/places/tests/unit/test_removeVisitsByTimeframe.js +++ b/toolkit/components/places/tests/unit/test_removeVisitsByTimeframe.js @@ -10,7 +10,7 @@ const PLACE_URI = uri("place:queryType=0&sort=8&maxResults=10"); function* cleanup() { yield PlacesTestUtils.clearHistory(); - remove_all_bookmarks(); + yield PlacesUtils.bookmarks.eraseEverything(); // This is needed to remove place: entries. DBConn().executeSimpleSQL("DELETE FROM moz_places"); } diff --git a/toolkit/components/places/tests/unit/test_update_frecency_after_delete.js b/toolkit/components/places/tests/unit/test_update_frecency_after_delete.js index e325a565c04..e2fa8574fbf 100644 --- a/toolkit/components/places/tests/unit/test_update_frecency_after_delete.js +++ b/toolkit/components/places/tests/unit/test_update_frecency_after_delete.js @@ -12,148 +12,140 @@ * bookmark is deleted. */ -add_test(function removed_bookmark() -{ +add_task(function* removed_bookmark() { do_print("After removing bookmark, frecency of bookmark's URI should be " + "zero if URI is unvisited and no longer bookmarked."); const TEST_URI = NetUtil.newURI("http://example.com/1"); - let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark title"); - PlacesTestUtils.promiseAsyncUpdates().then(() => { - do_print("Bookmarked => frecency of URI should be != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - PlacesUtils.bookmarks.removeItem(id); - - PlacesTestUtils.promiseAsyncUpdates().then(() => { - do_print("Unvisited URI no longer bookmarked => frecency should = 0"); - do_check_eq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - PlacesTestUtils.clearHistory().then(run_next_test); - }); + let bm = yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: "bookmark title", + url: TEST_URI }); + + yield PlacesTestUtils.promiseAsyncUpdates(); + do_print("Bookmarked => frecency of URI should be != 0"); + do_check_neq(frecencyForUrl(TEST_URI), 0); + + yield PlacesUtils.bookmarks.remove(bm); + + yield PlacesTestUtils.promiseAsyncUpdates(); + do_print("Unvisited URI no longer bookmarked => frecency should = 0"); + do_check_eq(frecencyForUrl(TEST_URI), 0); + + yield PlacesUtils.bookmarks.eraseEverything(); + yield PlacesTestUtils.clearHistory(); }); -add_test(function removed_but_visited_bookmark() -{ +add_task(function* removed_but_visited_bookmark() { do_print("After removing bookmark, frecency of bookmark's URI should " + "not be zero if URI is visited."); const TEST_URI = NetUtil.newURI("http://example.com/1"); - let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark title"); - PlacesTestUtils.promiseAsyncUpdates().then(() => { - do_print("Bookmarked => frecency of URI should be != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - PlacesTestUtils.addVisits(TEST_URI).then(function () { - PlacesUtils.bookmarks.removeItem(id); - - PlacesTestUtils.promiseAsyncUpdates().then(() => { - do_print("*Visited* URI no longer bookmarked => frecency should != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - PlacesTestUtils.clearHistory().then(run_next_test); - }); - }); + let bm = yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: "bookmark title", + url: TEST_URI }); + + yield PlacesTestUtils.promiseAsyncUpdates(); + do_print("Bookmarked => frecency of URI should be != 0"); + do_check_neq(frecencyForUrl(TEST_URI), 0); + + yield PlacesTestUtils.addVisits(TEST_URI); + yield PlacesUtils.bookmarks.remove(bm); + + yield PlacesTestUtils.promiseAsyncUpdates(); + do_print("*Visited* URI no longer bookmarked => frecency should != 0"); + do_check_neq(frecencyForUrl(TEST_URI), 0); + + yield PlacesUtils.bookmarks.eraseEverything(); + yield PlacesTestUtils.clearHistory(); }); -add_test(function remove_bookmark_still_bookmarked() -{ +add_task(function* remove_bookmark_still_bookmarked() { do_print("After removing bookmark, frecency of bookmark's URI should " + "not be zero if URI is still bookmarked."); const TEST_URI = NetUtil.newURI("http://example.com/1"); - let id1 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark 1 title"); - let id2 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark 2 title"); - PlacesTestUtils.promiseAsyncUpdates().then(() => { - do_print("Bookmarked => frecency of URI should be != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - PlacesUtils.bookmarks.removeItem(id1); - - PlacesTestUtils.promiseAsyncUpdates().then(() => { - do_print("URI still bookmarked => frecency should != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - PlacesTestUtils.clearHistory().then(run_next_test); - }); + let bm1 = yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: "bookmark 1 title", + url: TEST_URI }); + let bm2 = yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: "bookmark 2 title", + url: TEST_URI + }); + + yield PlacesTestUtils.promiseAsyncUpdates(); + do_print("Bookmarked => frecency of URI should be != 0"); + do_check_neq(frecencyForUrl(TEST_URI), 0); + + yield PlacesUtils.bookmarks.remove(bm1); + + yield PlacesTestUtils.promiseAsyncUpdates(); + do_print("URI still bookmarked => frecency should != 0"); + do_check_neq(frecencyForUrl(TEST_URI), 0); + + yield PlacesUtils.bookmarks.eraseEverything(); + yield PlacesTestUtils.clearHistory(); }); -add_test(function cleared_parent_of_visited_bookmark() -{ +add_task(function* cleared_parent_of_visited_bookmark() { do_print("After removing all children from bookmark's parent, frecency " + "of bookmark's URI should not be zero if URI is visited."); const TEST_URI = NetUtil.newURI("http://example.com/1"); - let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark title"); - PlacesTestUtils.promiseAsyncUpdates().then(() => { - do_print("Bookmarked => frecency of URI should be != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - PlacesTestUtils.addVisits(TEST_URI).then(function () { - PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId); - - PlacesTestUtils.promiseAsyncUpdates().then(() => { - do_print("*Visited* URI no longer bookmarked => frecency should != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - PlacesTestUtils.clearHistory().then(run_next_test); - }); - }); + let bm = yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: "bookmark title", + url: TEST_URI }); + + yield PlacesTestUtils.promiseAsyncUpdates(); + do_print("Bookmarked => frecency of URI should be != 0"); + do_check_neq(frecencyForUrl(TEST_URI), 0); + + yield PlacesTestUtils.addVisits(TEST_URI); + PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId); + + yield PlacesTestUtils.promiseAsyncUpdates(); + do_print("*Visited* URI no longer bookmarked => frecency should != 0"); + do_check_neq(frecencyForUrl(TEST_URI), 0); + + yield PlacesUtils.bookmarks.eraseEverything(); + yield PlacesTestUtils.clearHistory(); }); -add_test(function cleared_parent_of_bookmark_still_bookmarked() -{ +add_task(function* cleared_parent_of_bookmark_still_bookmarked() { do_print("After removing all children from bookmark's parent, frecency " + "of bookmark's URI should not be zero if URI is still " + "bookmarked."); const TEST_URI = NetUtil.newURI("http://example.com/1"); - let id1 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.toolbarFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark 1 title"); - - let id2 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark 2 title"); - PlacesTestUtils.promiseAsyncUpdates().then(() => { - do_print("Bookmarked => frecency of URI should be != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId); - - PlacesTestUtils.promiseAsyncUpdates().then(() => { - // URI still bookmarked => frecency should != 0. - do_check_neq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - PlacesTestUtils.clearHistory().then(run_next_test); - }); + let bm1 = yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + title: "bookmark 1 title", + url: TEST_URI }); + + let folder = yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + type: PlacesUtils.bookmarks.TYPE_FOLDER, + title: "bookmark 2 folder" + }); + let bm2 = yield PlacesUtils.bookmarks.insert({ + title: "bookmark 2 title", + parentGuid: folder.guid, + url: TEST_URI + }); + + yield PlacesTestUtils.promiseAsyncUpdates(); + do_print("Bookmarked => frecency of URI should be != 0"); + do_check_neq(frecencyForUrl(TEST_URI), 0); + + yield PlacesUtils.bookmarks.remove(folder); + yield PlacesTestUtils.promiseAsyncUpdates(); + // URI still bookmarked => frecency should != 0. + do_check_neq(frecencyForUrl(TEST_URI), 0); + + yield PlacesUtils.bookmarks.eraseEverything(); + yield PlacesTestUtils.clearHistory(); }); - -/////////////////////////////////////////////////////////////////////////////// - -function run_test() -{ - run_next_test(); -} diff --git a/toolkit/components/places/tests/unit/test_utils_getURLsForContainerNode.js b/toolkit/components/places/tests/unit/test_utils_getURLsForContainerNode.js index 2581ffaf6ad..27bc2010460 100644 --- a/toolkit/components/places/tests/unit/test_utils_getURLsForContainerNode.js +++ b/toolkit/components/places/tests/unit/test_utils_getURLsForContainerNode.js @@ -169,11 +169,12 @@ function check_uri_nodes(aQuery, aOptions, aExpectedURINodes) { root.containerOpen = false; } -function run_test() { - tests.forEach(function(aTest) { - remove_all_bookmarks(); - aTest(); - }); +add_task(function* () { + for (let test of tests) { + yield PlacesUtils.bookmarks.eraseEverything(); + test(); + } + // Cleanup. - remove_all_bookmarks(); -} + yield PlacesUtils.bookmarks.eraseEverything(); +}); From 1be8159308dc720912af98bf39cfca9726d23938 Mon Sep 17 00:00:00 2001 From: Dave Townsend Date: Mon, 20 Apr 2015 08:53:00 -0700 Subject: [PATCH 28/80] Bug 1140221: Attempt to fix intermittent test-tabs.js.testIgnoreClosing by waiting for focus directly. r=erikvold --- .../source/test/tabs/test-firefox-tabs.js | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/addon-sdk/source/test/tabs/test-firefox-tabs.js b/addon-sdk/source/test/tabs/test-firefox-tabs.js index d7c8016bbe7..b11bb20e754 100644 --- a/addon-sdk/source/test/tabs/test-firefox-tabs.js +++ b/addon-sdk/source/test/tabs/test-firefox-tabs.js @@ -371,29 +371,30 @@ exports.testTabMove = function(assert, done) { }; exports.testIgnoreClosing = function(assert, done) { - let originalWindow = browserWindows.activeWindow; + let originalWindow = viewFor(browserWindows.activeWindow); openBrowserWindow(function(window, browser) { - let url = "data:text/html;charset=utf-8,foobar"; + onFocus(window).then(() => { + let url = "data:text/html;charset=utf-8,foobar"; - assert.equal(tabs.length, 2, "should be two windows open each with one tab"); + assert.equal(tabs.length, 2, "should be two windows open each with one tab"); - tabs.on('ready', function onReady(tab) { - tabs.removeListener('ready', onReady); + tabs.on('ready', function onReady(tab) { + tabs.removeListener('ready', onReady); - let win = tab.window; - assert.equal(win.tabs.length, 2, "should be two tabs in the new window"); - assert.equal(tabs.length, 3, "should be three tabs in total"); + let win = tab.window; + assert.equal(win.tabs.length, 2, "should be two tabs in the new window"); + assert.equal(tabs.length, 3, "should be three tabs in total"); - tab.close(function() { - assert.equal(win.tabs.length, 1, "should be one tab in the new window"); - assert.equal(tabs.length, 2, "should be two tabs in total"); + tab.close(function() { + assert.equal(win.tabs.length, 1, "should be one tab in the new window"); + assert.equal(tabs.length, 2, "should be two tabs in total"); - originalWindow.once("activate", done); - close(window); + close(window).then(onFocus(originalWindow)).then(done).then(null, assert.fail); + }); }); - }); - tabs.open(url); + tabs.open(url); + }); }); }; From b2f4baac33f371fe2cc21cb4854abf6914765431 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Mon, 20 Apr 2015 11:09:34 -0700 Subject: [PATCH 29/80] Bug 1096908 - forward network security messages to the content process; r=hurley --- browser/devtools/webconsole/test/browser.ini | 1 - netwerk/protocol/http/HttpBaseChannel.h | 2 +- netwerk/protocol/http/HttpChannelChild.cpp | 8 ++++++++ netwerk/protocol/http/HttpChannelChild.h | 3 +++ netwerk/protocol/http/HttpChannelParent.cpp | 16 ++++++++++++++++ netwerk/protocol/http/HttpChannelParent.h | 6 +++++- netwerk/protocol/http/PHttpChannel.ipdl | 4 ++++ netwerk/protocol/http/nsHttpChannel.cpp | 14 ++++++++++++++ netwerk/protocol/http/nsHttpChannel.h | 17 +++++++++++++++++ 9 files changed, 68 insertions(+), 3 deletions(-) diff --git a/browser/devtools/webconsole/test/browser.ini b/browser/devtools/webconsole/test/browser.ini index ea8f809f892..e05e8ae8423 100644 --- a/browser/devtools/webconsole/test/browser.ini +++ b/browser/devtools/webconsole/test/browser.ini @@ -307,7 +307,6 @@ skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug intermittent) [browser_webconsole_certificate_messages.js] skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_show_subresource_security_errors.js] -skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_cached_autocomplete.js] [browser_webconsole_change_font_size.js] [browser_webconsole_chrome.js] diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index a87531fafe4..353e41dfe18 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -182,7 +182,7 @@ public: NS_IMETHOD GetAllowAltSvc(bool *aAllowAltSvc) override; NS_IMETHOD SetAllowAltSvc(bool aAllowAltSvc) override; NS_IMETHOD GetApiRedirectToURI(nsIURI * *aApiRedirectToURI) override; - nsresult AddSecurityMessage(const nsAString &aMessageTag, const nsAString &aMessageCategory); + virtual nsresult AddSecurityMessage(const nsAString &aMessageTag, const nsAString &aMessageCategory); NS_IMETHOD TakeAllSecurityMessages(nsCOMArray &aMessages) override; NS_IMETHOD GetResponseTimeoutEnabled(bool *aEnable) override; NS_IMETHOD SetResponseTimeoutEnabled(bool aEnable) override; diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index a47c1e71778..21e32f52dd0 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -991,6 +991,14 @@ HttpChannelChild::DeleteSelf() Send__delete__(this); } +bool +HttpChannelChild::RecvReportSecurityMessage(const nsString& messageTag, + const nsString& messageCategory) +{ + AddSecurityMessage(messageTag, messageCategory); + return true; +} + class Redirect1Event : public ChannelEvent { public: diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index 6f54013dace..fcd61efbdea 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -140,6 +140,9 @@ protected: bool RecvDivertMessages() override; bool RecvDeleteSelf() override; + bool RecvReportSecurityMessage(const nsString& messageTag, + const nsString& messageCategory) override; + bool GetAssociatedContentSecurity(nsIAssociatedContentSecurity** res = nullptr); virtual void DoNotifyListenerCleanup() override; diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index f6625084528..b2dd903d47e 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -329,6 +329,7 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, return SendFailedAsyncOpen(rv); mChannel = static_cast(channel.get()); + mChannel->SetWarningReporter(this); mChannel->SetTimingEnabled(true); if (mPBOverride != kPBOverride_Unset) { mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false); @@ -1264,4 +1265,19 @@ HttpChannelParent::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid, return NS_OK; } +//----------------------------------------------------------------------------- +// HttpChannelSecurityWarningReporter +//----------------------------------------------------------------------------- + +nsresult +HttpChannelParent::ReportSecurityMessage(const nsAString& aMessageTag, + const nsAString& aMessageCategory) +{ + if (NS_WARN_IF(!SendReportSecurityMessage(nsString(aMessageTag), + nsString(aMessageCategory)))) { + return NS_ERROR_UNEXPECTED; + } + return NS_OK; +} + }} // mozilla::net diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h index 4f481b18dd1..c5ceb56d711 100644 --- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -43,7 +43,8 @@ class HttpChannelParent final : public PHttpChannelParent , public ADivertableParentChannel , public nsIAuthPromptProvider , public nsINetworkInterceptController - , public DisconnectableParent + , public DisconnectableParent, + , public HttpChannelSecurityWarningReporter { virtual ~HttpChannelParent(); @@ -154,6 +155,9 @@ protected: void OfflineDisconnect() override; uint32_t GetAppId() override; + nsresult ReportSecurityMessage(const nsAString& aMessageTag, + const nsAString& aMessageCategory) override; + private: nsRefPtr mChannel; nsCOMPtr mCacheEntry; diff --git a/netwerk/protocol/http/PHttpChannel.ipdl b/netwerk/protocol/http/PHttpChannel.ipdl index a0edc6a32d5..3b6db8676a0 100644 --- a/netwerk/protocol/http/PHttpChannel.ipdl +++ b/netwerk/protocol/http/PHttpChannel.ipdl @@ -139,6 +139,10 @@ child: // OnDataAvailable and OnStopRequest messages in the queue back to the parent. DivertMessages(); + // Report a security message to the console associated with this + // channel. + ReportSecurityMessage(nsString messageTag, nsString messageCategory); + // Tell child to delete channel (all IPDL deletes must be done from child to // avoid races: see bug 591708). DeleteSelf(); diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 5fd28278dd3..3bcc7ad5672 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -244,6 +244,7 @@ nsHttpChannel::nsHttpChannel() , mHasAutoRedirectVetoNotifier(0) , mPushedStream(nullptr) , mLocalBlocklist(false) + , mWarningReporter(nullptr) , mDidReval(false) { LOG(("Creating nsHttpChannel [this=%p]\n", this)); @@ -281,6 +282,19 @@ nsHttpChannel::Init(nsIURI *uri, return rv; } + +nsresult +nsHttpChannel::AddSecurityMessage(const nsAString& aMessageTag, + const nsAString& aMessageCategory) +{ + if (mWarningReporter) { + return mWarningReporter->ReportSecurityMessage(aMessageTag, + aMessageCategory); + } + return HttpBaseChannel::AddSecurityMessage(aMessageTag, + aMessageCategory); +} + //----------------------------------------------------------------------------- // nsHttpChannel //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index 9010e4a5c55..58ee0f9c0dc 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -33,6 +33,14 @@ class nsISSLStatus; namespace mozilla { namespace net { class Http2PushedStream; + +class HttpChannelSecurityWarningReporter +{ +public: + virtual nsresult ReportSecurityMessage(const nsAString& aMessageTag, + const nsAString& aMessageCategory) = 0; +}; + //----------------------------------------------------------------------------- // nsHttpChannel //----------------------------------------------------------------------------- @@ -141,6 +149,12 @@ public: NS_IMETHOD GetResponseStart(mozilla::TimeStamp *aResponseStart) override; NS_IMETHOD GetResponseEnd(mozilla::TimeStamp *aResponseEnd) override; + nsresult AddSecurityMessage(const nsAString& aMessageTag, + const nsAString& aMessageCategory) override; + + void SetWarningReporter(HttpChannelSecurityWarningReporter* aReporter) + { mWarningReporter = aReporter; } + public: /* internal necko use only */ void InternalSetUploadStream(nsIInputStream *uploadStream) @@ -477,6 +491,9 @@ private: nsCString mUsername; + // If non-null, warnings should be reported to this object. + HttpChannelSecurityWarningReporter* mWarningReporter; + protected: virtual void DoNotifyListenerCleanup() override; From a730d85efe8375a9b2a09ad98fd505b19e709b80 Mon Sep 17 00:00:00 2001 From: Michael Ratcliffe Date: Thu, 16 Apr 2015 10:17:26 +0100 Subject: [PATCH 30/80] Bug 1098374 - Telemetry: Stop all monkey patching in devtools telemetry tests r=harth,bgrins --- .../devtools/canvasdebugger/canvasdebugger.js | 4 - browser/devtools/shadereditor/shadereditor.js | 4 - browser/devtools/shared/telemetry.js | 17 +- browser/devtools/shared/test/browser.ini | 1 + .../shared/test/browser_observableobject.js | 4 +- .../shared/test/browser_options-view-01.js | 1 - .../shared/test/browser_outputparser.js | 2 - .../browser_telemetry_button_eyedropper.js | 36 +--- .../browser_telemetry_button_paintflashing.js | 49 ++--- .../browser_telemetry_button_responsive.js | 49 ++--- .../browser_telemetry_button_scratchpad.js | 48 +---- .../test/browser_telemetry_button_tilt.js | 51 ++--- .../shared/test/browser_telemetry_misc.js | 24 +++ .../shared/test/browser_telemetry_sidebar.js | 51 ++--- .../shared/test/browser_telemetry_toolbox.js | 20 +- ...er_telemetry_toolboxtabs_canvasdebugger.js | 17 +- ...browser_telemetry_toolboxtabs_inspector.js | 20 +- ...rowser_telemetry_toolboxtabs_jsdebugger.js | 20 +- ...rowser_telemetry_toolboxtabs_jsprofiler.js | 13 +- ...rowser_telemetry_toolboxtabs_netmonitor.js | 13 +- .../browser_telemetry_toolboxtabs_options.js | 14 +- ...wser_telemetry_toolboxtabs_shadereditor.js | 14 +- .../browser_telemetry_toolboxtabs_storage.js | 14 +- ...owser_telemetry_toolboxtabs_styleeditor.js | 13 +- ...er_telemetry_toolboxtabs_webaudioeditor.js | 14 +- ...rowser_telemetry_toolboxtabs_webconsole.js | 14 +- browser/devtools/shared/test/head.js | 183 +++++++++++------- browser/devtools/storage/ui.js | 6 - browser/devtools/webaudioeditor/controller.js | 2 - browser/devtools/webaudioeditor/includes.js | 5 +- browser/devtools/webide/test/head.js | 113 +++++++++++ .../devtools/webide/test/test_telemetry.html | 91 ++------- 32 files changed, 501 insertions(+), 426 deletions(-) create mode 100644 browser/devtools/shared/test/browser_telemetry_misc.js diff --git a/browser/devtools/canvasdebugger/canvasdebugger.js b/browser/devtools/canvasdebugger/canvasdebugger.js index aaa9ae00985..537cda761e5 100644 --- a/browser/devtools/canvasdebugger/canvasdebugger.js +++ b/browser/devtools/canvasdebugger/canvasdebugger.js @@ -17,8 +17,6 @@ const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise; const EventEmitter = require("devtools/toolkit/event-emitter"); const { CallWatcherFront } = require("devtools/server/actors/call-watcher"); const { CanvasFront } = require("devtools/server/actors/canvas"); -const Telemetry = require("devtools/shared/telemetry"); -const telemetry = new Telemetry(); const CANVAS_ACTOR_RECORDING_ATTEMPT = gDevTools.testing ? 500 : 5000; @@ -129,7 +127,6 @@ let EventsHandler = { * Listen for events emitted by the current tab target. */ initialize: function() { - telemetry.toolOpened("canvasdebugger"); this._onTabNavigated = this._onTabNavigated.bind(this); gTarget.on("will-navigate", this._onTabNavigated); gTarget.on("navigate", this._onTabNavigated); @@ -139,7 +136,6 @@ let EventsHandler = { * Remove events emitted by the current tab target. */ destroy: function() { - telemetry.toolClosed("canvasdebugger"); gTarget.off("will-navigate", this._onTabNavigated); gTarget.off("navigate", this._onTabNavigated); }, diff --git a/browser/devtools/shadereditor/shadereditor.js b/browser/devtools/shadereditor/shadereditor.js index 93019876eb2..c28a2246b64 100644 --- a/browser/devtools/shadereditor/shadereditor.js +++ b/browser/devtools/shadereditor/shadereditor.js @@ -17,8 +17,6 @@ const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise; const EventEmitter = require("devtools/toolkit/event-emitter"); const {Tooltip} = require("devtools/shared/widgets/Tooltip"); const Editor = require("devtools/sourceeditor/editor"); -const Telemetry = require("devtools/shared/telemetry"); -const telemetry = new Telemetry(); // The panel's window global is an EventEmitter firing the following events: const EVENTS = { @@ -86,7 +84,6 @@ let EventsHandler = { * Listen for events emitted by the current tab target. */ initialize: function() { - telemetry.toolOpened("shadereditor"); this._onHostChanged = this._onHostChanged.bind(this); this._onTabNavigated = this._onTabNavigated.bind(this); this._onProgramLinked = this._onProgramLinked.bind(this); @@ -102,7 +99,6 @@ let EventsHandler = { * Remove events emitted by the current tab target. */ destroy: function() { - telemetry.toolClosed("shadereditor"); gToolbox.off("host-changed", this._onHostChanged); gTarget.off("will-navigate", this._onTabNavigated); gTarget.off("navigate", this._onTabNavigated); diff --git a/browser/devtools/shared/telemetry.js b/browser/devtools/shared/telemetry.js index 0193ccee19a..05118aa6c7d 100644 --- a/browser/devtools/shared/telemetry.js +++ b/browser/devtools/shared/telemetry.js @@ -19,17 +19,8 @@ * timerHistogram: "DEVTOOLS_MYTOOLNAME_TIME_ACTIVE_SECONDS" * }, * - * 3. Include this module at the top of your tool. Use: - * let Telemetry = require("devtools/shared/telemetry") - * - * 4. Create a telemetry instance in your tool's constructor: - * this._telemetry = new Telemetry(); - * - * 5. When your tool is opened call: - * this._telemetry.toolOpened("mytoolname"); - * - * 6. When your tool is closed call: - * this._telemetry.toolClosed("mytoolname"); + * 3. toolbox.js will automatically ping telemetry with your tools opening and + * timing information. * * Note: * You can view telemetry stats for your local Firefox instance via @@ -303,6 +294,10 @@ Telemetry.prototype = { } }, + clearToolsOpenedPref: function() { + Services.prefs.clearUserPref(TOOLS_OPENED_PREF); + }, + destroy: function() { for (let histogramId of this._timers.keys()) { this.stopTimer(histogramId); diff --git a/browser/devtools/shared/test/browser.ini b/browser/devtools/shared/test/browser.ini index b5da569d968..4d352ac3bf5 100644 --- a/browser/devtools/shared/test/browser.ini +++ b/browser/devtools/shared/test/browser.ini @@ -90,6 +90,7 @@ skip-if = e10s # Bug 1067145 - e10s responsiveview [browser_telemetry_button_tilt.js] skip-if = e10s # Bug 1086492 - Disable tilt for e10s # Bug 937166 - Make tilt work in E10S mode +[browser_telemetry_misc.js] [browser_telemetry_sidebar.js] [browser_telemetry_toolbox.js] [browser_telemetry_toolboxtabs_canvasdebugger.js] diff --git a/browser/devtools/shared/test/browser_observableobject.js b/browser/devtools/shared/test/browser_observableobject.js index 8bd1d516944..5c1cdc69acc 100644 --- a/browser/devtools/shared/test/browser_observableobject.js +++ b/browser/devtools/shared/test/browser_observableobject.js @@ -2,9 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ function test() { - let tmp = {}; - Cu.import("resource://gre/modules/devtools/Loader.jsm", tmp); - let ObservableObject = tmp.devtools.require("devtools/shared/observable-object"); + let ObservableObject = devtools.require("devtools/shared/observable-object"); let rawObject = {}; let oe = new ObservableObject(rawObject); diff --git a/browser/devtools/shared/test/browser_options-view-01.js b/browser/devtools/shared/test/browser_options-view-01.js index b64cce36841..147da903403 100644 --- a/browser/devtools/shared/test/browser_options-view-01.js +++ b/browser/devtools/shared/test/browser_options-view-01.js @@ -4,7 +4,6 @@ // Tests that options-view OptionsView responds to events correctly. const {OptionsView} = devtools.require("devtools/shared/options-view"); -const {Services} = devtools.require("resource://gre/modules/Services.jsm"); const BRANCH = "devtools.debugger."; const BLACK_BOX_PREF = "auto-black-box"; diff --git a/browser/devtools/shared/test/browser_outputparser.js b/browser/devtools/shared/test/browser_outputparser.js index 583f74fad4f..47fe9685a00 100644 --- a/browser/devtools/shared/test/browser_outputparser.js +++ b/browser/devtools/shared/test/browser_outputparser.js @@ -1,8 +1,6 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); -let {Loader} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {}); let {OutputParser} = devtools.require("devtools/output-parser"); add_task(function*() { diff --git a/browser/devtools/shared/test/browser_telemetry_button_eyedropper.js b/browser/devtools/shared/test/browser_telemetry_button_eyedropper.js index 946e4174ebf..ca429ea02bc 100644 --- a/browser/devtools/shared/test/browser_telemetry_button_eyedropper.js +++ b/browser/devtools/shared/test/browser_telemetry_button_eyedropper.js @@ -8,50 +8,34 @@ let {EyedropperManager} = require("devtools/eyedropper/eyedropper"); add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); info("inspector opened"); info("testing the eyedropper button"); - testButton(toolbox, Telemetry); + testButton(toolbox); - stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); -function testButton(toolbox, Telemetry) { +function testButton(toolbox) { let button = toolbox.doc.querySelector("#command-button-eyedropper"); ok(button, "Captain, we have the eyedropper button"); info("clicking the button to open the eyedropper"); button.click(); - checkResults("_EYEDROPPER_", Telemetry); + checkResults(); } -function checkResults(histIdFocus, Telemetry) { - let result = Telemetry.prototype.telemetryInfo; +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. - for (let [histId, value] of Iterator(result)) { - if (histId.startsWith("DEVTOOLS_INSPECTOR_") || - !histId.contains(histIdFocus)) { - // Inspector stats are tested in - // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here - // because we only open the inspector once for this test. - continue; - } - - if (histId.endsWith("OPENED_PER_USER_FLAG")) { - ok(value.length === 1 && value[0] === true, - "Per user value " + histId + " has a single value of true"); - } else if (histId.endsWith("OPENED_BOOLEAN")) { - is(value.length, 1, histId + " has one entry"); - - let okay = value.every(element => element === true); - ok(okay, "All " + histId + " entries are === true"); - } - } + checkTelemetry("DEVTOOLS_EYEDROPPER_OPENED_BOOLEAN", [0,1,0]); + checkTelemetry("DEVTOOLS_EYEDROPPER_OPENED_PER_USER_FLAG", [0,1,0]); } diff --git a/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js b/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js index 692df44c457..d05b9d15fbf 100644 --- a/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js +++ b/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js @@ -10,28 +10,28 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); info("inspector opened"); info("testing the paintflashing button"); - yield testButton(toolbox, Telemetry); + yield testButton(toolbox); - stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); -function* testButton(toolbox, Telemetry) { +function* testButton(toolbox) { info("Testing command-button-paintflashing"); let button = toolbox.doc.querySelector("#command-button-paintflashing"); ok(button, "Captain, we have the button"); yield delayedClicks(button, 4); - checkResults("_PAINTFLASHING_", Telemetry); + checkResults(); } function delayedClicks(node, clicks) { @@ -53,37 +53,10 @@ function delayedClicks(node, clicks) { }); } -function checkResults(histIdFocus, Telemetry) { - let result = Telemetry.prototype.telemetryInfo; - - for (let [histId, value] of Iterator(result)) { - if (histId.startsWith("DEVTOOLS_INSPECTOR_") || - !histId.contains(histIdFocus)) { - // Inspector stats are tested in - // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here - // because we only open the inspector once for this test. - continue; - } - - if (histId.endsWith("OPENED_PER_USER_FLAG")) { - ok(value.length === 1 && value[0] === true, - "Per user value " + histId + " has a single value of true"); - } else if (histId.endsWith("OPENED_BOOLEAN")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element === true; - }); - - ok(okay, "All " + histId + " entries are === true"); - } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element > 0; - }); - - ok(okay, "All " + histId + " entries have time > 0"); - } - } +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_PAINTFLASHING_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_PAINTFLASHING_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_PAINTFLASHING_TIME_ACTIVE_SECONDS", null, "hasentries"); } diff --git a/browser/devtools/shared/test/browser_telemetry_button_responsive.js b/browser/devtools/shared/test/browser_telemetry_button_responsive.js index fd9a33460cb..bb5598d8337 100644 --- a/browser/devtools/shared/test/browser_telemetry_button_responsive.js +++ b/browser/devtools/shared/test/browser_telemetry_button_responsive.js @@ -10,28 +10,28 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); info("inspector opened"); info("testing the responsivedesign button"); - yield testButton(toolbox, Telemetry); + yield testButton(toolbox); - stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); -function* testButton(toolbox, Telemetry) { +function* testButton(toolbox) { info("Testing command-button-responsive"); let button = toolbox.doc.querySelector("#command-button-responsive"); ok(button, "Captain, we have the button"); yield delayedClicks(button, 4); - checkResults("_RESPONSIVE_", Telemetry); + checkResults(); } function delayedClicks(node, clicks) { @@ -53,37 +53,10 @@ function delayedClicks(node, clicks) { }); } -function checkResults(histIdFocus, Telemetry) { - let result = Telemetry.prototype.telemetryInfo; - - for (let [histId, value] of Iterator(result)) { - if (histId.startsWith("DEVTOOLS_INSPECTOR_") || - !histId.contains(histIdFocus)) { - // Inspector stats are tested in - // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here - // because we only open the inspector once for this test. - continue; - } - - if (histId.endsWith("OPENED_PER_USER_FLAG")) { - ok(value.length === 1 && value[0] === true, - "Per user value " + histId + " has a single value of true"); - } else if (histId.endsWith("OPENED_BOOLEAN")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element === true; - }); - - ok(okay, "All " + histId + " entries are === true"); - } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element > 0; - }); - - ok(okay, "All " + histId + " entries have time > 0"); - } - } +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_RESPONSIVE_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_RESPONSIVE_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_RESPONSIVE_TIME_ACTIVE_SECONDS", null, "hasentries"); } diff --git a/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js b/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js index f96755fcf8e..e1a5b137fc6 100644 --- a/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js +++ b/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js @@ -10,7 +10,8 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); @@ -19,12 +20,11 @@ add_task(function*() { let onAllWindowsOpened = trackScratchpadWindows(); info("testing the scratchpad button"); - yield testButton(toolbox, Telemetry); + yield testButton(toolbox); yield onAllWindowsOpened; - checkResults("_SCRATCHPAD_", Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); @@ -64,7 +64,7 @@ function trackScratchpadWindows() { }); } -function* testButton(toolbox, Telemetry) { +function* testButton(toolbox) { info("Testing command-button-scratchpad"); let button = toolbox.doc.querySelector("#command-button-scratchpad"); ok(button, "Captain, we have the button"); @@ -91,37 +91,9 @@ function delayedClicks(node, clicks) { }); } -function checkResults(histIdFocus, Telemetry) { - let result = Telemetry.prototype.telemetryInfo; - - for (let [histId, value] of Iterator(result)) { - if (histId.startsWith("DEVTOOLS_INSPECTOR_") || - !histId.contains(histIdFocus)) { - // Inspector stats are tested in - // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here - // because we only open the inspector once for this test. - continue; - } - - if (histId.endsWith("OPENED_PER_USER_FLAG")) { - ok(value.length === 1 && value[0] === true, - "Per user value " + histId + " has a single value of true"); - } else if (histId.endsWith("OPENED_BOOLEAN")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element === true; - }); - - ok(okay, "All " + histId + " entries are === true"); - } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element > 0; - }); - - ok(okay, "All " + histId + " entries have time > 0"); - } - } +function checkResults(histIdFocus) { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_SCRATCHPAD_OPENED_BOOLEAN", [0,4,0]); + checkTelemetry("DEVTOOLS_SCRATCHPAD_OPENED_PER_USER_FLAG", [0,1,0]); } diff --git a/browser/devtools/shared/test/browser_telemetry_button_tilt.js b/browser/devtools/shared/test/browser_telemetry_button_tilt.js index 4e36618ca5e..b5cd3b30c70 100644 --- a/browser/devtools/shared/test/browser_telemetry_button_tilt.js +++ b/browser/devtools/shared/test/browser_telemetry_button_tilt.js @@ -10,28 +10,28 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); info("inspector opened"); info("testing the tilt button"); - yield testButton(toolbox, Telemetry); + yield testButton(toolbox); - stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); -function* testButton(toolbox, Telemetry) { +function* testButton(toolbox) { info("Testing command-button-tilt"); let button = toolbox.doc.querySelector("#command-button-tilt"); ok(button, "Captain, we have the button"); - yield delayedClicks(button, 4) - checkResults("_TILT_", Telemetry); + yield delayedClicks(button, 4); + checkResults(); } function delayedClicks(node, clicks) { @@ -53,37 +53,10 @@ function delayedClicks(node, clicks) { }); } -function checkResults(histIdFocus, Telemetry) { - let result = Telemetry.prototype.telemetryInfo; - - for (let [histId, value] of Iterator(result)) { - if (histId.startsWith("DEVTOOLS_INSPECTOR_") || - !histId.contains(histIdFocus)) { - // Inspector stats are tested in - // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here - // because we only open the inspector once for this test. - continue; - } - - if (histId.endsWith("OPENED_PER_USER_FLAG")) { - ok(value.length === 1 && value[0] === true, - "Per user value " + histId + " has a single value of true"); - } else if (histId.endsWith("OPENED_BOOLEAN")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element === true; - }); - - ok(okay, "All " + histId + " entries are === true"); - } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element > 0; - }); - - ok(okay, "All " + histId + " entries have time > 0"); - } - } +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_TILT_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_TILT_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_TILT_TIME_ACTIVE_SECONDS", null, "hasentries"); } diff --git a/browser/devtools/shared/test/browser_telemetry_misc.js b/browser/devtools/shared/test/browser_telemetry_misc.js new file mode 100644 index 00000000000..f5859d5629d --- /dev/null +++ b/browser/devtools/shared/test/browser_telemetry_misc.js @@ -0,0 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const TEST_URI = "data:text/html;charset=utf-8,

browser_telemetry_misc.js

"; +const TOOL_DELAY = 0; + +add_task(function*() { + yield promiseTab(TEST_URI); + + startTelemetry(); + + yield openAndCloseToolbox(1, TOOL_DELAY, "inspector"); + checkResults(); + + gBrowser.removeCurrentTab(); +}); + +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_OS_ENUMERATED_PER_USER", null, "hasentries"); + checkTelemetry("DEVTOOLS_OS_IS_64_BITS_PER_USER", null, "hasentries"); + checkTelemetry("DEVTOOLS_SCREEN_RESOLUTION_ENUMERATED_PER_USER", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_sidebar.js b/browser/devtools/shared/test/browser_telemetry_sidebar.js index b80930e0e6c..a975090ec0b 100644 --- a/browser/devtools/shared/test/browser_telemetry_sidebar.js +++ b/browser/devtools/shared/test/browser_telemetry_sidebar.js @@ -9,16 +9,16 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); info("inspector opened"); yield testSidebar(toolbox); - checkResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); @@ -49,37 +49,16 @@ function* testSidebar(toolbox) { }); } -function checkResults(Telemetry) { - let result = Telemetry.prototype.telemetryInfo; - - for (let [histId, value] of Iterator(result)) { - if (histId.startsWith("DEVTOOLS_INSPECTOR_")) { - // Inspector stats are tested in browser_telemetry_toolboxtabs.js so we - // skip them here because we only open the inspector once for this test. - continue; - } - - if (histId.endsWith("OPENED_PER_USER_FLAG")) { - ok(value.length === 1 && value[0] === true, - "Per user value " + histId + " has a single value of true"); - } else if (histId === "DEVTOOLS_TOOLBOX_OPENED_BOOLEAN") { - is(value.length, 1, histId + " has only one entry"); - } else if (histId.endsWith("OPENED_BOOLEAN")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element === true; - }); - - ok(okay, "All " + histId + " entries are === true"); - } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element > 0; - }); - - ok(okay, "All " + histId + " entries have time > 0"); - } - } +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_ANIMATIONINSPECTOR_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_ANIMATIONINSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_ANIMATIONINSPECTOR_TIME_ACTIVE_SECONDS", null, "hasentries"); + checkTelemetry("DEVTOOLS_COMPUTEDVIEW_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_COMPUTEDVIEW_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS", null, "hasentries"); + checkTelemetry("DEVTOOLS_FONTINSPECTOR_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_FONTINSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS", null, "hasentries"); } diff --git a/browser/devtools/shared/test/browser_telemetry_toolbox.js b/browser/devtools/shared/test/browser_telemetry_toolbox.js index 366f64699ab..724fdd129e5 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolbox.js +++ b/browser/devtools/shared/test/browser_telemetry_toolbox.js @@ -10,11 +10,25 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); yield openAndCloseToolbox(3, TOOL_DELAY, "inspector"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); + +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_BOOLEAN", [0,3,0]); + checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_INSPECTOR_TIME_ACTIVE_SECONDS", null, "hasentries"); + checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_BOOLEAN", [0,3,0]); + checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS", null, "hasentries"); + checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,3,0]); + checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js index c9c07099a59..bae88ab26c0 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js @@ -14,14 +14,25 @@ add_task(function*() { Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", true); yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); yield openAndCloseToolbox(2, TOOL_DELAY, "canvasdebugger"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); info("De-activate the canvasdebugger"); Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", originalPref); }); + +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_CANVASDEBUGGER_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_CANVASDEBUGGER_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_CANVASDEBUGGER_TIME_ACTIVE_SECONDS", null, "hasentries"); + checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js index 61dff980af2..236faf6e469 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js @@ -10,11 +10,25 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); yield openAndCloseToolbox(2, TOOL_DELAY, "inspector"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); + +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_INSPECTOR_TIME_ACTIVE_SECONDS", null, "hasentries"); + checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS", null, "hasentries"); + checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js index a8625518351..cc70eda3e39 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js @@ -10,11 +10,25 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); yield openAndCloseToolbox(2, TOOL_DELAY, "jsdebugger"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); + +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries"); + checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETHREAD_MS", null, "hasentries"); + checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RESUME_MS", null, "hasentries"); + checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_SOURCES_MS", null, "hasentries"); + checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries"); + checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_THREADDETACH_MS", null, "hasentries"); + checkTelemetry("DEVTOOLS_JSDEBUGGER_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_JSDEBUGGER_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_JSDEBUGGER_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js index e2131feb2df..d3db7fad406 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js @@ -9,11 +9,18 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + startTelemetry(); yield openAndCloseToolbox(2, TOOL_DELAY, "performance"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); + +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_JSPROFILER_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_JSPROFILER_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_JSPROFILER_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js index e7554e5492a..a0fa1abd97a 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js @@ -9,12 +9,19 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); yield openAndCloseToolbox(2, TOOL_DELAY, "netmonitor"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_NETMONITOR_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_NETMONITOR_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_NETMONITOR_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js index 14256814e49..b0ed00e6266 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js @@ -9,11 +9,19 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); yield openAndCloseToolbox(2, TOOL_DELAY, "options"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); + +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_OPTIONS_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_OPTIONS_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_OPTIONS_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js index 476fbd320d9..7f25e08a4c3 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js @@ -20,14 +20,22 @@ add_task(function*() { Services.prefs.setBoolPref("devtools.shadereditor.enabled", true); yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); yield openAndCloseToolbox(2, TOOL_DELAY, "shadereditor"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); info("De-activate the sharer editor"); Services.prefs.setBoolPref("devtools.shadereditor.enabled", originalPref); }); + +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_SHADEREDITOR_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_SHADEREDITOR_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_SHADEREDITOR_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js index 93348b96df7..b935204c68c 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js @@ -12,14 +12,22 @@ add_task(function*() { Services.prefs.setBoolPref("devtools.storage.enabled", true); yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); yield openAndCloseToolbox(2, TOOL_DELAY, "storage"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); info("De-activating the storage inspector"); Services.prefs.clearUserPref("devtools.storage.enabled"); }); + +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_STORAGE_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_STORAGE_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_STORAGE_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js index 15c4a9c08ac..968b328eecf 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js @@ -9,12 +9,19 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); yield openAndCloseToolbox(2, TOOL_DELAY, "styleeditor"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_STYLEEDITOR_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_STYLEEDITOR_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_STYLEEDITOR_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js index 033791a7235..435b5711563 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js @@ -13,14 +13,22 @@ add_task(function*() { Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", true); yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); yield openAndCloseToolbox(2, TOOL_DELAY, "webaudioeditor"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); info("De-activating the webaudioeditor"); Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", originalPref); }); + +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_WEBAUDIOEDITOR_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_WEBAUDIOEDITOR_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_WEBAUDIOEDITOR_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js index b989a14269a..693790522fd 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js @@ -9,11 +9,19 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - let Telemetry = loadTelemetryAndRecordLogs(); + + startTelemetry(); yield openAndCloseToolbox(2, TOOL_DELAY, "webconsole"); - checkTelemetryResults(Telemetry); + checkResults(); - stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); + +function checkResults() { + // For help generating these tests use generateTelemetryTests("DEVTOOLS_") + // here. + checkTelemetry("DEVTOOLS_WEBCONSOLE_OPENED_BOOLEAN", [0,2,0]); + checkTelemetry("DEVTOOLS_WEBCONSOLE_OPENED_PER_USER_FLAG", [0,1,0]); + checkTelemetry("DEVTOOLS_WEBCONSOLE_TIME_ACTIVE_SECONDS", null, "hasentries"); +} diff --git a/browser/devtools/shared/test/head.js b/browser/devtools/shared/test/head.js index 121f75f6900..a6542217f82 100644 --- a/browser/devtools/shared/test/head.js +++ b/browser/devtools/shared/test/head.js @@ -6,12 +6,22 @@ let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); let {TargetFactory, require} = devtools; let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {}); let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); +let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); const {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {}); const {Hosts} = require("devtools/framework/toolbox-hosts"); +let oldCanRecord = Services.telemetry.canRecordExtended; + gDevTools.testing = true; -SimpleTest.registerCleanupFunction(() => { +registerCleanupFunction(() => { + _stopTelemetry(); gDevTools.testing = false; + + while (gBrowser.tabs.length > 1) { + gBrowser.removeCurrentTab(); + } + + console = undefined; }); const TEST_URI_ROOT = "http://example.com/browser/browser/devtools/shared/test/"; @@ -43,14 +53,6 @@ function promiseTab(aURL) { addTab(aURL, resolve)); } -registerCleanupFunction(function tearDown() { - while (gBrowser.tabs.length > 1) { - gBrowser.removeCurrentTab(); - } - - console = undefined; -}); - function catchFail(func) { return function() { try { @@ -150,75 +152,126 @@ let createHost = Task.async(function*(type = "bottom", src = "data:text/html;cha return [host, iframe.contentWindow, iframe.contentDocument]; }); -/** - * Load the Telemetry utils, then stub Telemetry.prototype.log in order to - * record everything that's logged in it. - * Store all recordings on Telemetry.telemetryInfo. - * @return {Telemetry} - */ -function loadTelemetryAndRecordLogs() { - info("Mock the Telemetry log function to record logged information"); +function reportError(error) { + let stack = " " + error.stack.replace(/\n?.*?@/g, "\n JS frame :: "); - let Telemetry = require("devtools/shared/telemetry"); - Telemetry.prototype.telemetryInfo = {}; - Telemetry.prototype._oldlog = Telemetry.prototype.log; - Telemetry.prototype.log = function(histogramId, value) { - if (!this.telemetryInfo) { - // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10) - return; - } - if (histogramId) { - if (!this.telemetryInfo[histogramId]) { - this.telemetryInfo[histogramId] = []; - } + ok(false, "ERROR: " + error + " at " + error.fileName + ":" + + error.lineNumber + "\n\nStack trace:" + stack); - this.telemetryInfo[histogramId].push(value); - } - }; + if (finishUp) { + finishUp(); + } +} - return Telemetry; +function startTelemetry() { + Services.telemetry.canRecordExtended = true; } /** - * Stop recording the Telemetry logs and put back the utils as it was before. + * This method is automatically called on teardown. */ -function stopRecordingTelemetryLogs(Telemetry) { - Telemetry.prototype.log = Telemetry.prototype._oldlog; - delete Telemetry.prototype._oldlog; - delete Telemetry.prototype.telemetryInfo; -} +function _stopTelemetry() { + let Telemetry = devtools.require("devtools/shared/telemetry"); + let telemetry = new Telemetry(); -/** - * Check the correctness of the data recorded in Telemetry after - * loadTelemetryAndRecordLogs was called. - */ -function checkTelemetryResults(Telemetry) { - let result = Telemetry.prototype.telemetryInfo; + telemetry.clearToolsOpenedPref(); - for (let [histId, value] of Iterator(result)) { - if (histId.endsWith("OPENED_PER_USER_FLAG")) { - ok(value.length === 1 && value[0] === true, - "Per user value " + histId + " has a single value of true"); - } else if (histId.endsWith("OPENED_BOOLEAN")) { - ok(value.length > 1, histId + " has more than one entry"); + Services.telemetry.canRecordExtended = oldCanRecord; - let okay = value.every(function(element) { - return element === true; - }); - - ok(okay, "All " + histId + " entries are === true"); - } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element > 0; - }); - - ok(okay, "All " + histId + " entries have time > 0"); + // Clean up telemetry histogram changes + for (let histId in Services.telemetry.histogramSnapshots) { + try { + let histogram = Services.telemetry.getHistogramById(histId); + histogram.clear(); + } catch(e) { + // Histograms is not listed in histograms.json, do nothing. } } } +/** + * Check the value of a given telemetry histogram. + * + * @param {String} histId + * Histogram id + * @param {Array|Number} expected + * Expected value + * @param {String} checkType + * "array" (default) - Check that an array matches the histogram data. + * "hasentries" - For non-enumerated linear and exponential + * histograms. This checks for at least one entry. + */ +function checkTelemetry(histId, expected, checkType="array") { + let actual = Services.telemetry.getHistogramById(histId).snapshot().counts; + + switch (checkType) { + case "array": + is(JSON.stringify(actual), JSON.stringify(expected), histId + " correct."); + break; + case "hasentries": + let hasEntry = actual.some(num => num > 0); + ok(hasEntry, histId + " has at least one entry."); + break; + } +} + +/** + * Generate telemetry tests. You should call generateTelemetryTests("DEVTOOLS_") + * from your result checking code in telemetry tests. It logs checkTelemetry + * calls for all changed telemetry values. + * + * @param {String} prefix + * Optionally limits results to histogram ids starting with prefix. + */ +function generateTelemetryTests(prefix="") { + dump("=".repeat(80) + "\n"); + for (let histId in Services.telemetry.histogramSnapshots) { + if (!histId.startsWith(prefix)) { + continue; + } + + let snapshot = Services.telemetry.histogramSnapshots[histId]; + let actual = snapshot.counts; + + switch (snapshot.histogram_type) { + case Services.telemetry.HISTOGRAM_EXPONENTIAL: + case Services.telemetry.HISTOGRAM_LINEAR: + let total = 0; + for (let val of actual) { + total += val; + } + + if (histId.endsWith("_ENUMERATED")) { + if (total > 0) { + dump("checkTelemetry(\"" + histId + "\", " + JSON.stringify(actual) + ");\n"); + } + continue; + } + + dump("checkTelemetry(\"" + histId + "\", null, \"hasentries\");\n"); + break; + case Services.telemetry.HISTOGRAM_BOOLEAN: + actual = JSON.stringify(actual); + + if (actual !== "[0,0,0]") { + dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); + } + break; + case Services.telemetry.HISTOGRAM_FLAG: + actual = JSON.stringify(actual); + + if (actual !== "[1,0,0]") { + dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); + } + break; + case Services.telemetry.HISTOGRAM_COUNT: + dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); + break; + } + } + dump("=".repeat(80) + "\n"); +} + /** * Open and close the toolbox in the current browser tab, several times, waiting * some amount of time in between. @@ -230,7 +283,7 @@ function* openAndCloseToolbox(nbOfTimes, usageTime, toolId) { for (let i = 0; i < nbOfTimes; i ++) { info("Opening toolbox " + (i + 1)); let target = TargetFactory.forTab(gBrowser.selectedTab); - yield gDevTools.showToolbox(target, toolId) + yield gDevTools.showToolbox(target, toolId); // We use a timeout to check the toolbox's active time yield new Promise(resolve => setTimeout(resolve, usageTime)); diff --git a/browser/devtools/storage/ui.js b/browser/devtools/storage/ui.js index 52a0ca12b3d..1e1ee0ce974 100644 --- a/browser/devtools/storage/ui.js +++ b/browser/devtools/storage/ui.js @@ -21,8 +21,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "ViewHelpers", XPCOMUtils.defineLazyModuleGetter(this, "VariablesView", "resource:///modules/devtools/VariablesView.jsm"); -let Telemetry = require("devtools/shared/telemetry"); - /** * Localization convenience methods. */ @@ -87,9 +85,6 @@ this.StorageUI = function StorageUI(front, target, panelWin) { this.handleKeypress = this.handleKeypress.bind(this); this._panelDoc.addEventListener("keypress", this.handleKeypress); - - this._telemetry = new Telemetry(); - this._telemetry.toolOpened("storage"); } exports.StorageUI = StorageUI; @@ -102,7 +97,6 @@ StorageUI.prototype = { destroy: function() { this.front.off("stores-update", this.onUpdate); this._panelDoc.removeEventListener("keypress", this.handleKeypress); - this._telemetry.toolClosed("storage"); }, /** diff --git a/browser/devtools/webaudioeditor/controller.js b/browser/devtools/webaudioeditor/controller.js index 544650a9104..5f9755f4832 100644 --- a/browser/devtools/webaudioeditor/controller.js +++ b/browser/devtools/webaudioeditor/controller.js @@ -42,7 +42,6 @@ let WebAudioEditorController = { * Listen for events emitted by the current tab target. */ initialize: Task.async(function* () { - telemetry.toolOpened("webaudioeditor"); this._onTabNavigated = this._onTabNavigated.bind(this); this._onThemeChange = this._onThemeChange.bind(this); @@ -76,7 +75,6 @@ let WebAudioEditorController = { * Remove events emitted by the current tab target. */ destroy: function() { - telemetry.toolClosed("webaudioeditor"); gTarget.off("will-navigate", this._onTabNavigated); gTarget.off("navigate", this._onTabNavigated); gFront.off("start-context", this._onStartContext); diff --git a/browser/devtools/webaudioeditor/includes.js b/browser/devtools/webaudioeditor/includes.js index 2e6b8ece4ea..acfbe87278c 100644 --- a/browser/devtools/webaudioeditor/includes.js +++ b/browser/devtools/webaudioeditor/includes.js @@ -19,10 +19,9 @@ let { EventTarget } = require("sdk/event/target"); const { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); const { Class } = require("sdk/core/heritage"); const EventEmitter = require("devtools/toolkit/event-emitter"); -const STRINGS_URI = "chrome://browser/locale/devtools/webaudioeditor.properties" +const STRINGS_URI = "chrome://browser/locale/devtools/webaudioeditor.properties"; const L10N = new ViewHelpers.L10N(STRINGS_URI); -const Telemetry = require("devtools/shared/telemetry"); -const telemetry = new Telemetry(); + devtools.lazyImporter(this, "LineGraphWidget", "resource:///modules/devtools/Graphs.jsm"); diff --git a/browser/devtools/webide/test/head.js b/browser/devtools/webide/test/head.js index 71d6697c863..309dbc61262 100644 --- a/browser/devtools/webide/test/head.js +++ b/browser/devtools/webide/test/head.js @@ -14,6 +14,8 @@ const {require} = devtools; const promise = require("promise"); const {AppProjects} = require("devtools/app-manager/app-projects"); +let oldCanRecord = Services.telemetry.canRecordExtended; + let TEST_BASE; if (window.location === "chrome://browser/content/browser.xul") { TEST_BASE = "chrome://mochitests/content/browser/browser/devtools/webide/test/"; @@ -33,6 +35,8 @@ Services.prefs.setCharPref("devtools.webide.templatesURL", TEST_BASE + "template Services.prefs.setCharPref("devtools.devices.url", TEST_BASE + "browser_devices.json"); SimpleTest.registerCleanupFunction(() => { + _stopTelemetry(); + Services.prefs.clearUserPref("devtools.webide.enabled"); Services.prefs.clearUserPref("devtools.webide.enableLocalRuntime"); Services.prefs.clearUserPref("devtools.webide.autoinstallADBHelper"); @@ -207,3 +211,112 @@ function handleError(aError) { ok(false, "Got an error: " + aError.message + "\n" + aError.stack); finish(); } + +function startTelemetry() { + Services.telemetry.canRecordExtended = true; +} + +/** + * This method is automatically called on teardown. + */ +function _stopTelemetry() { + let Telemetry = devtools.require("devtools/shared/telemetry"); + let telemetry = new Telemetry(); + + telemetry.clearToolsOpenedPref(); + + Services.telemetry.canRecordExtended = oldCanRecord; + + // Clean up telemetry histogram changes + for (let histId in Services.telemetry.histogramSnapshots) { + try { + let histogram = Services.telemetry.getHistogramById(histId); + histogram.clear(); + } catch(e) { + // Histograms is not listed in histograms.json, do nothing. + } + } +} + +/** + * Check the value of a given telemetry histogram. + * + * @param {String} histId + * Histogram id + * @param {Array|Number} expected + * Expected value + * @param {String} checkType + * "array" (default) - Check that an array matches the histogram data. + * "hasentries" - For non-enumerated linear and exponential + * histograms. This checks for at least one entry. + */ +function checkTelemetry(histId, expected, checkType="array") { + let actual = Services.telemetry.getHistogramById(histId).snapshot().counts; + + switch (checkType) { + case "array": + is(JSON.stringify(actual), JSON.stringify(expected), histId + " correct."); + break; + case "hasentries": + let hasEntry = actual.some(num => num > 0); + ok(hasEntry, histId + " has at least one entry."); + break; + } +} + +/** + * Generate telemetry tests. You should call generateTelemetryTests("DEVTOOLS_") + * from your result checking code in telemetry tests. It logs checkTelemetry + * calls for all changed telemetry values. + * + * @param {String} prefix + * Optionally limits results to histogram ids starting with prefix. + */ +function generateTelemetryTests(prefix="") { + dump("=".repeat(80) + "\n"); + for (let histId in Services.telemetry.histogramSnapshots) { + if (!histId.startsWith(prefix)) { + continue; + } + + let snapshot = Services.telemetry.histogramSnapshots[histId]; + let actual = snapshot.counts; + + switch (snapshot.histogram_type) { + case Services.telemetry.HISTOGRAM_EXPONENTIAL: + case Services.telemetry.HISTOGRAM_LINEAR: + let total = 0; + for (let val of actual) { + total += val; + } + + if (histId.endsWith("_ENUMERATED")) { + if (total > 0) { + dump("checkTelemetry(\"" + histId + "\", " + JSON.stringify(actual) + ");\n"); + } + continue; + } + + dump("checkTelemetry(\"" + histId + "\", null, \"hasentries\");\n"); + break; + case Services.telemetry.HISTOGRAM_BOOLEAN: + actual = JSON.stringify(actual); + + if (actual !== "[0,0,0]") { + dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); + } + break; + case Services.telemetry.HISTOGRAM_FLAG: + actual = JSON.stringify(actual); + + if (actual !== "[1,0,0]") { + dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); + } + break; + case Services.telemetry.HISTOGRAM_COUNT: + dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); + break; + } + } + dump("=".repeat(80) + "\n"); +} diff --git a/browser/devtools/webide/test/test_telemetry.html b/browser/devtools/webide/test/test_telemetry.html index 72eb4d51fed..4133cb65831 100644 --- a/browser/devtools/webide/test/test_telemetry.html +++ b/browser/devtools/webide/test/test_telemetry.html @@ -15,7 +15,6 @@ " + + "" + + ""; + +add_task(function*() { + let tab = yield addTab(TEST_URL); + let {inspector} = yield openInspector(); + let domContentLoaded = waitForLinkedBrowserEvent(tab, "DOMContentLoaded"); + let pageLoaded = waitForLinkedBrowserEvent(tab, "load"); + + ok (inspector.markup, "There is a markup view"); + + // Select an element while the tab is in the middle of a slow reload. + reloadTab(); + yield domContentLoaded; + yield chooseWithInspectElementContextMenu("img"); + yield pageLoaded; + + yield inspector.once("markuploaded"); + ok (inspector.markup, "There is a markup view"); + is (inspector.markup._elt.children.length, 1, "The markup view is rendering"); +}); + +function* chooseWithInspectElementContextMenu(selector) { + yield executeInContent("Test:SynthesizeMouse", { + center: true, + selector: selector, + options: {type: "contextmenu", button: 2} + }); + executeInContent("Test:SynthesizeKey", {key: "Q", options: {}}); +} + +function waitForLinkedBrowserEvent(tab, event) { + let def = promise.defer(); + tab.linkedBrowser.addEventListener(event, function cb() { + tab.linkedBrowser.removeEventListener(event, cb, true); + def.resolve(); + }, true); + return def.promise; +} diff --git a/browser/devtools/markupview/test/head.js b/browser/devtools/markupview/test/head.js index a79c1e165e8..2ee7e4976aa 100644 --- a/browser/devtools/markupview/test/head.js +++ b/browser/devtools/markupview/test/head.js @@ -172,6 +172,13 @@ function executeInContent(name, data={}, objects={}, expectResponse=true) { } } +/** + * Reload the current tab location. + */ +function reloadTab() { + return executeInContent("devtools:test:reload", {}, {}, false); +} + /** * Simple DOM node accesor function that takes either a node or a string css * selector as argument and returns the corresponding node @@ -647,3 +654,34 @@ function* waitForMultipleChildrenUpdates(inspector) { return yield waitForMultipleChildrenUpdates(inspector); } } + +/** + * Create an HTTP server that can be used to simulate custom requests within + * a test. It is automatically cleaned up when the test ends, so no need to + * call `destroy`. + * + * See https://developer.mozilla.org/en-US/docs/Httpd.js/HTTP_server_for_unit_tests + * for more information about how to register handlers. + * + * The server can be accessed like: + * + * const server = createTestHTTPServer(); + * let url = "http://localhost: " + server.identity.primaryPort + "/path"; + * + * @returns {HttpServer} + */ +function createTestHTTPServer() { + const {HttpServer} = Cu.import("resource://testing-common/httpd.js", {}); + let server = new HttpServer(); + + registerCleanupFunction(function* cleanup() { + let destroyed = promise.defer(); + server.stop(() => { + destroyed.resolve(); + }); + yield destroyed.promise; + }); + + server.start(-1); + return server; +} diff --git a/browser/devtools/shared/frame-script-utils.js b/browser/devtools/shared/frame-script-utils.js index 4c0f1d4850d..aeee2a63c8c 100644 --- a/browser/devtools/shared/frame-script-utils.js +++ b/browser/devtools/shared/frame-script-utils.js @@ -3,11 +3,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -const Cu = Components.utils; - +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); devtools.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise"); devtools.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm", "Task"); +const loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader); +let EventUtils = {}; +loader.loadSubScript("chrome://marionette/content/EventUtils.js", EventUtils); addMessageListener("devtools:test:history", function ({ data }) { content.history[data.direction](); @@ -189,6 +192,55 @@ addMessageListener("devtools:test:setAttribute", function(msg) { sendAsyncMessage("devtools:test:setAttribute"); }); +/** + * Synthesize a mouse event on an element. This handler doesn't send a message + * back. Consumers should listen to specific events on the inspector/highlighter + * to know when the event got synthesized. + * @param {Object} msg The msg.data part expects the following properties: + * - {Number} x + * - {Number} y + * - {Boolean} center If set to true, x/y will be ignored and + * synthesizeMouseAtCenter will be used instead + * - {Object} options Other event options + * - {String} selector An optional selector that will be used to find the node to + * synthesize the event on, if msg.objects doesn't contain the CPOW. + * The msg.objects part should be the element. + * @param {Object} data Event detail properties: + */ +addMessageListener("Test:SynthesizeMouse", function(msg) { + let {x, y, center, options, selector} = msg.data; + let {node} = msg.objects; + + if (!node && selector) { + node = superQuerySelector(selector); + } + + if (center) { + EventUtils.synthesizeMouseAtCenter(node, options, node.ownerDocument.defaultView); + } else { + EventUtils.synthesizeMouse(node, x, y, options, node.ownerDocument.defaultView); + } + + // Most consumers won't need to listen to this message, unless they want to + // wait for the mouse event to be synthesized and don't have another event + // to listen to instead. + sendAsyncMessage("Test:SynthesizeMouse"); +}); + +/** + * Synthesize a key event for an element. This handler doesn't send a message + * back. Consumers should listen to specific events on the inspector/highlighter + * to know when the event got synthesized. + * @param {Object} msg The msg.data part expects the following properties: + * - {String} key + * - {Object} options + */ +addMessageListener("Test:SynthesizeKey", function(msg) { + let {key, options} = msg.data; + + EventUtils.synthesizeKey(key, options, content); +}); + /** * Like document.querySelector but can go into iframes too. * ".container iframe || .sub-container div" will first try to find the node diff --git a/toolkit/devtools/server/actors/inspector.js b/toolkit/devtools/server/actors/inspector.js index 01ff79207f8..29dd47f5ca4 100644 --- a/toolkit/devtools/server/actors/inspector.js +++ b/toolkit/devtools/server/actors/inspector.js @@ -1410,6 +1410,8 @@ var WalkerActor = protocol.ActorClass({ * Named options, including: * `sameDocument`: If true, parents will be restricted to the same * document as the node. + * `sameTypeRootTreeItem`: If true, this will not traverse across + * different types of docshells. */ parents: method(function(node, options={}) { if (isNodeDead(node)) { @@ -1420,16 +1422,23 @@ var WalkerActor = protocol.ActorClass({ let parents = []; let cur; while((cur = walker.parentNode())) { - if (options.sameDocument && cur.ownerDocument != node.rawNode.ownerDocument) { + if (options.sameDocument && nodeDocument(cur) != nodeDocument(node.rawNode)) { break; } + + if (options.sameTypeRootTreeItem && + nodeDocshell(cur).sameTypeRootTreeItem != nodeDocshell(node.rawNode).sameTypeRootTreeItem) { + break; + } + parents.push(this._ref(cur)); } return parents; }, { request: { node: Arg(0, "domnode"), - sameDocument: Option(1) + sameDocument: Option(1), + sameTypeRootTreeItem: Option(1) }, response: { nodes: RetVal("array:domnode") @@ -3226,7 +3235,7 @@ var WalkerFront = exports.WalkerFront = protocol.FrontClass(WalkerActor, { let nodeType = types.getType("domnode"); let returnNode = nodeType.read(nodeType.write(nodeActor, walkerActor), this); let top = returnNode; - let extras = walkerActor.parents(nodeActor); + let extras = walkerActor.parents(nodeActor, {sameTypeRootTreeItem: true}); for (let extraActor of extras) { top = nodeType.read(nodeType.write(extraActor, walkerActor), this); } @@ -3519,6 +3528,16 @@ function nodeDocument(node) { return node.ownerDocument || (node.nodeType == Ci.nsIDOMNode.DOCUMENT_NODE ? node : null); } +function nodeDocshell(node) { + let doc = node ? nodeDocument(node) : null; + let win = doc ? doc.defaultView : null; + if (win) { + return win. + QueryInterface(Ci.nsIInterfaceRequestor). + getInterface(Ci.nsIDocShell); + } +} + function isNodeDead(node) { return !node || !node.rawNode || Cu.isDeadWrapper(node.rawNode); } diff --git a/toolkit/devtools/server/actors/styles.js b/toolkit/devtools/server/actors/styles.js index 5e4b28cc366..39a6da7aa2f 100644 --- a/toolkit/devtools/server/actors/styles.js +++ b/toolkit/devtools/server/actors/styles.js @@ -1020,7 +1020,8 @@ var StyleRuleActor = protocol.ActorClass({ // Elements don't have a parent stylesheet, and therefore // don't have an associated URI. Provide a URI for // those. - form.href = this.rawNode.ownerDocument.location.href; + let doc = this.rawNode.ownerDocument; + form.href = doc.location ? doc.location.href : ""; form.cssText = this.rawStyle.cssText || ""; break; case Ci.nsIDOMCSSRule.CHARSET_RULE: @@ -1231,7 +1232,7 @@ var StyleRuleFront = protocol.FrontClass(StyleRuleActor, { return this._form.href; } let sheet = this.parentStyleSheet; - return sheet.href; + return sheet ? sheet.href : ""; }, get nodeHref() { From 95d0e9c971e8f7c26dc64b6e613194251ed79125 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 20 Apr 2015 13:28:17 -0700 Subject: [PATCH 44/80] Backed out changeset 0352b6fb976f (bug 1155766) because the newly fixed assertion is busting xpcshell tests --- dom/quota/QuotaManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/quota/QuotaManager.cpp b/dom/quota/QuotaManager.cpp index c29c9afb30a..426906f9468 100644 --- a/dom/quota/QuotaManager.cpp +++ b/dom/quota/QuotaManager.cpp @@ -5002,7 +5002,7 @@ OriginParser::HandleToken(const nsDependentCSubstring& aToken) void OriginParser::HandleTrailingSeparator() { - MOZ_ASSERT(mState == eComplete); + MOZ_ASSERT(mState = eComplete); MOZ_ASSERT(mSchemaType == eFile); mPathnameComponents.AppendElement(EmptyCString()); From a5feb8f0c5f5e5384b7923d2c14f03e9c238f7d9 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 20 Apr 2015 13:42:48 -0700 Subject: [PATCH 45/80] Backed out changeset d321fbee8cd8 (bug 1136257) for being the probably cause of e10s-dt orange --- .../devtools/shared/test/browser_css_color.js | 15 +++- browser/devtools/shared/widgets/Tooltip.js | 5 -- .../devtools/styleinspector/computed-view.js | 75 +------------------ .../styleinspector/computedview.xhtml | 33 ++++++++ .../devtools/styleinspector/test/browser.ini | 2 - .../test/browser_computedview_cycle_color.js | 68 ----------------- .../test/browser_ruleview_cycle-color.js | 60 --------------- toolkit/devtools/css-color.js | 36 +-------- toolkit/devtools/output-parser.js | 21 +----- 9 files changed, 51 insertions(+), 264 deletions(-) delete mode 100644 browser/devtools/styleinspector/test/browser_computedview_cycle_color.js delete mode 100644 browser/devtools/styleinspector/test/browser_ruleview_cycle-color.js diff --git a/browser/devtools/shared/test/browser_css_color.js b/browser/devtools/shared/test/browser_css_color.js index f1dd1d53744..4f4f29be5f0 100644 --- a/browser/devtools/shared/test/browser_css_color.js +++ b/browser/devtools/shared/test/browser_css_color.js @@ -1,6 +1,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ +const COLOR_UNIT_PREF = "devtools.defaultColorUnit"; const TEST_URI = "data:text/html;charset=utf-8,browser_css_color.js"; let {colorUtils} = devtools.require("devtools/css-color"); let origColorUnit; @@ -8,6 +9,7 @@ let origColorUnit; add_task(function*() { yield promiseTab("about:blank"); let [host, win, doc] = yield createHost("bottom", TEST_URI); + origColorUnit = Services.prefs.getCharPref(COLOR_UNIT_PREF); info("Creating a test canvas element to test colors"); let canvas = createTestCanvas(doc); @@ -47,19 +49,23 @@ function testColorUtils(canvas) { } function testToString(color, name, hex, hsl, rgb) { - color.colorUnit = colorUtils.CssColor.COLORUNIT.name; + switchColorUnit(colorUtils.CssColor.COLORUNIT.name); is(color.toString(), name, "toString() with authored type"); - color.colorUnit = colorUtils.CssColor.COLORUNIT.hex; + switchColorUnit(colorUtils.CssColor.COLORUNIT.hex); is(color.toString(), hex, "toString() with hex type"); - color.colorUnit = colorUtils.CssColor.COLORUNIT.hsl; + switchColorUnit(colorUtils.CssColor.COLORUNIT.hsl); is(color.toString(), hsl, "toString() with hsl type"); - color.colorUnit = colorUtils.CssColor.COLORUNIT.rgb; + switchColorUnit(colorUtils.CssColor.COLORUNIT.rgb); is(color.toString(), rgb, "toString() with rgb type"); } +function switchColorUnit(unit) { + Services.prefs.setCharPref(COLOR_UNIT_PREF, unit); +} + function testColorMatch(name, hex, hsl, rgb, rgba, canvas) { let target; let ctx = canvas.getContext("2d"); @@ -104,6 +110,7 @@ function testColorMatch(name, hex, hsl, rgb, rgba, canvas) { test(hex, "hex"); test(hsl, "hsl"); test(rgb, "rgb"); + switchColorUnit(origColorUnit); } function testProcessCSSString() { diff --git a/browser/devtools/shared/widgets/Tooltip.js b/browser/devtools/shared/widgets/Tooltip.js index abe8a818c85..bc58325e73c 100644 --- a/browser/devtools/shared/widgets/Tooltip.js +++ b/browser/devtools/shared/widgets/Tooltip.js @@ -1020,11 +1020,6 @@ SwatchBasedEditorTooltip.prototype = { _onSwatchClick: function(event) { let swatch = this.swatches.get(event.target); - - if (event.shiftKey) { - event.stopPropagation(); - return; - } if (swatch) { this.activeSwatch = event.target; this.show(); diff --git a/browser/devtools/styleinspector/computed-view.js b/browser/devtools/styleinspector/computed-view.js index 07eb0cad159..2cc5a7747bc 100644 --- a/browser/devtools/styleinspector/computed-view.js +++ b/browser/devtools/styleinspector/computed-view.js @@ -980,6 +980,7 @@ function PropertyView(aTree, aName) this.link = "https://developer.mozilla.org/CSS/" + aName; + this.templateMatchedSelectors = aTree.styleDocument.getElementById("templateMatchedSelectors"); this._propertyInfo = new PropertyInfo(aTree, aName); } @@ -1191,7 +1192,6 @@ PropertyView.prototype = { this.propertyInfo.value, { colorSwatchClass: "computedview-colorswatch", - colorClass: "computedview-color", urlClass: "theme-link" // No need to use baseURI here as computed URIs are never relative. }); @@ -1222,10 +1222,9 @@ PropertyView.prototype = { } this._matchedSelectorResponse = matched; - - this._buildMatchedSelectors(); + CssHtmlTree.processTemplate(this.templateMatchedSelectors, + this.matchedSelectorsContainer, this); this.matchedExpander.setAttribute("open", ""); - this.tree.inspector.emit("computed-view-property-expanded"); }).then(null, console.error); } else { @@ -1241,40 +1240,6 @@ PropertyView.prototype = { return this._matchedSelectorResponse; }, - _buildMatchedSelectors: function() { - let frag = this.element.ownerDocument.createDocumentFragment(); - - for (let selector of this.matchedSelectorViews) { - let p = createChild(frag, "p"); - let span = createChild(p, "span", { - class: "rule-link" - }); - let link = createChild(span, "a", { - target: "_blank", - class: "link theme-link", - title: selector.href, - sourcelocation: selector.source, - tabindex: "0", - textContent: selector.source - }); - link.addEventListener("click", selector.openStyleEditor, false); - link.addEventListener("keydown", selector.maybeOpenStyleEditor, false); - - let status = createChild(p, "span", { - dir: "ltr", - class: "rule-text theme-fg-color3 " + selector.statusClass, - title: selector.statusText, - textContent: selector.sourceText - }); - let valueSpan = createChild(status, "span", { - class: "other-property-value theme-fg-color1" - }); - valueSpan.appendChild(selector.outputFragment); - } - - this.matchedSelectorsContainer.appendChild(frag); - }, - /** * Provide access to the matched SelectorViews that we are currently * displaying. @@ -1314,9 +1279,6 @@ PropertyView.prototype = { */ onMatchedToggle: function PropertyView_onMatchedToggle(aEvent) { - if (aEvent.shiftKey) { - return; - } this.matchedExpanded = !this.matchedExpanded; this.refreshMatchedSelectors(); aEvent.preventDefault(); @@ -1366,9 +1328,6 @@ function SelectorView(aTree, aSelectorInfo) this.selectorInfo = aSelectorInfo; this._cacheStatusNames(); - this.openStyleEditor = this.openStyleEditor.bind(this); - this.maybeOpenStyleEditor = this.maybeOpenStyleEditor.bind(this); - this.updateSourceLink(); } @@ -1459,7 +1418,6 @@ SelectorView.prototype = { this.selectorInfo.name, this.selectorInfo.value, { colorSwatchClass: "computedview-colorswatch", - colorClass: "computedview-color", urlClass: "theme-link", baseURI: this.selectorInfo.rule.href }); @@ -1582,32 +1540,5 @@ SelectorView.prototype = { } }; -/** - * Create a child element with a set of attributes. - * - * @param {Element} aParent - * The parent node. - * @param {string} aTag - * The tag name. - * @param {object} aAttributes - * A set of attributes to set on the node. - */ -function createChild(aParent, aTag, aAttributes={}) { - let elt = aParent.ownerDocument.createElementNS(HTML_NS, aTag); - for (let attr in aAttributes) { - if (aAttributes.hasOwnProperty(attr)) { - if (attr === "textContent") { - elt.textContent = aAttributes[attr]; - } else if(attr === "child") { - elt.appendChild(aAttributes[attr]); - } else { - elt.setAttribute(attr, aAttributes[attr]); - } - } - } - aParent.appendChild(elt); - return elt; -} - exports.CssHtmlTree = CssHtmlTree; exports.PropertyView = PropertyView; diff --git a/browser/devtools/styleinspector/computedview.xhtml b/browser/devtools/styleinspector/computedview.xhtml index 121475537c5..c922f3979a7 100644 --- a/browser/devtools/styleinspector/computedview.xhtml +++ b/browser/devtools/styleinspector/computedview.xhtml @@ -72,5 +72,38 @@ &noPropertiesFound; + +
+ +
+ +

+ + ${selector.source} + + + ${selector.sourceText} + ${selector.outputFragment} + +

+
+
+
+ diff --git a/browser/devtools/styleinspector/test/browser.ini b/browser/devtools/styleinspector/test/browser.ini index 824fd85bfbd..ff074ef9df8 100644 --- a/browser/devtools/styleinspector/test/browser.ini +++ b/browser/devtools/styleinspector/test/browser.ini @@ -27,7 +27,6 @@ support-files = head.js [browser_computedview_browser-styles.js] -[browser_computedview_cycle_color.js] [browser_computedview_getNodeInfo.js] [browser_computedview_keybindings_01.js] [browser_computedview_keybindings_02.js] @@ -100,7 +99,6 @@ skip-if = (os == "win" && debug) || e10s # bug 963492: win. bug 1040653: e10s. [browser_ruleview_multiple_properties_01.js] [browser_ruleview_multiple_properties_02.js] [browser_ruleview_original-source-link.js] -[browser_ruleview_cycle-color.js] [browser_ruleview_override.js] [browser_ruleview_pseudo-element_01.js] [browser_ruleview_pseudo-element_02.js] diff --git a/browser/devtools/styleinspector/test/browser_computedview_cycle_color.js b/browser/devtools/styleinspector/test/browser_computedview_cycle_color.js deleted file mode 100644 index 9aef6629b6c..00000000000 --- a/browser/devtools/styleinspector/test/browser_computedview_cycle_color.js +++ /dev/null @@ -1,68 +0,0 @@ -/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -// Computed view color cycling test. - -const PAGE_CONTENT = [ - "", - "Some styled text", - "" -].join("\n"); - -add_task(function*() { - yield addTab("data:text/html;charset=utf-8," + - "Computed view color cycling test."); - content.document.body.innerHTML = PAGE_CONTENT; - - info("Opening the computed view"); - let {toolbox, inspector, view} = yield openComputedView(); - - info("Selecting the test node"); - yield selectNode("#matches", inspector); - - info("Checking the property itself"); - let container = getComputedViewPropertyView(view, "color").valueNode; - checkColorCycling(container, inspector); - - info("Checking matched selectors"); - container = yield getComputedViewMatchedRules(view, "color"); - checkColorCycling(container, inspector); -}); - -function checkColorCycling(container, inspector) { - let swatch = container.querySelector(".computedview-colorswatch"); - let valueNode = container.querySelector(".computedview-color"); - let win = inspector.sidebar.getWindowForTab("computedview"); - - // Hex (default) - is(valueNode.textContent, "#F00", "Color displayed as a hex value."); - - // HSL - EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "hsl(0, 100%, 50%)", - "Color displayed as an HSL value."); - - // RGB - EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "rgb(255, 0, 0)", - "Color displayed as an RGB value."); - - // Color name - EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "red", - "Color displayed as a color name."); - - // "Authored" (currently the computed value) - EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "rgb(255, 0, 0)", - "Color displayed as an RGB value."); - - // Back to hex - EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "#F00", - "Color displayed as hex again."); -} diff --git a/browser/devtools/styleinspector/test/browser_ruleview_cycle-color.js b/browser/devtools/styleinspector/test/browser_ruleview_cycle-color.js deleted file mode 100644 index 1124cfe02b2..00000000000 --- a/browser/devtools/styleinspector/test/browser_ruleview_cycle-color.js +++ /dev/null @@ -1,60 +0,0 @@ -/* vim: set ft=javascript 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 cycling color types in the rule view. - -const PAGE_CONTENT = [ - "", - "Test cycling color types in the rule view!" -].join("\n"); - -add_task(function*() { - yield addTab("data:text/html;charset=utf-8,Test cycling color types in the " + - "rule view."); - content.document.body.innerHTML = PAGE_CONTENT; - let {toolbox, inspector, view} = yield openRuleView(); - - let container = getRuleViewProperty(view, "body", "color").valueSpan; - checkColorCycling(container, inspector); -}); - -function checkColorCycling(container, inspector) { - let swatch = container.querySelector(".ruleview-colorswatch"); - let valueNode = container.querySelector(".ruleview-color"); - let win = inspector.sidebar.getWindowForTab("ruleview"); - - // Hex (default) - is(valueNode.textContent, "#F00", "Color displayed as a hex value."); - - // HSL - EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "hsl(0, 100%, 50%)", - "Color displayed as an HSL value."); - - // RGB - EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "rgb(255, 0, 0)", - "Color displayed as an RGB value."); - - // Color name - EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "red", - "Color displayed as a color name."); - - // "Authored" (currently the computed value) - EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "rgb(255, 0, 0)", - "Color displayed as an RGB value."); - - // Back to hex - EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "#F00", - "Color displayed as hex again."); -} diff --git a/toolkit/devtools/css-color.js b/toolkit/devtools/css-color.js index 4451ecb4f51..4cfabd66711 100644 --- a/toolkit/devtools/css-color.js +++ b/toolkit/devtools/css-color.js @@ -95,22 +95,8 @@ CssColor.COLORUNIT = { }; CssColor.prototype = { - _colorUnit: null, - authored: null, - get colorUnit() { - if (this._colorUnit === null) { - let defaultUnit = Services.prefs.getCharPref(COLOR_UNIT_PREF); - this._colorUnit = CssColor.COLORUNIT[defaultUnit]; - } - return this._colorUnit; - }, - - set colorUnit(unit) { - this._colorUnit = unit; - }, - get hasAlpha() { if (!this.valid) { return false; @@ -283,31 +269,15 @@ CssColor.prototype = { return this; }, - nextColorUnit: function() { - // Reorder the formats array to have the current format at the - // front so we can cycle through. - let formats = ["authored", "hex", "hsl", "rgb", "name"]; - let putOnEnd = formats.splice(0, formats.indexOf(this.colorUnit)); - formats = formats.concat(putOnEnd); - let currentDisplayedColor = this[formats[0]]; - - for (let format of formats) { - if (this[format].toLowerCase() !== currentDisplayedColor.toLowerCase()) { - this.colorUnit = CssColor.COLORUNIT[format]; - break; - } - } - - return this.toString(); - }, - /** * Return a string representing a color of type defined in COLOR_UNIT_PREF. */ toString: function() { let color; + let defaultUnit = Services.prefs.getCharPref(COLOR_UNIT_PREF); + let unit = CssColor.COLORUNIT[defaultUnit]; - switch(this.colorUnit) { + switch(unit) { case CssColor.COLORUNIT.authored: color = this.authored; break; diff --git a/toolkit/devtools/output-parser.js b/toolkit/devtools/output-parser.js index 0ed2e2ded18..fa501c33279 100644 --- a/toolkit/devtools/output-parser.js +++ b/toolkit/devtools/output-parser.js @@ -77,8 +77,6 @@ loader.lazyGetter(this, "REGEX_ALL_CSS_PROPERTIES", function () { */ function OutputParser() { this.parsed = []; - this.colorSwatches = new WeakMap(); - this._onSwatchMouseDown = this._onSwatchMouseDown.bind(this); } exports.OutputParser = OutputParser; @@ -398,14 +396,12 @@ OutputParser.prototype = { class: options.colorSwatchClass, style: "background-color:" + color }); - this.colorSwatches.set(swatch, colorObj); - swatch.addEventListener("mousedown", this._onSwatchMouseDown, false); container.appendChild(swatch); } if (options.defaultColorType) { color = colorObj.toString(); - container.dataset.color = color; + container.dataset["color"] = color; } let value = this._createNode("span", { @@ -439,21 +435,6 @@ OutputParser.prototype = { this.parsed.push(container); }, - _onSwatchMouseDown: function(event) { - // Prevent text selection in the case of shift-click or double-click. - event.preventDefault(); - - if (!event.shiftKey) { - return; - } - - let swatch = event.target; - let color = this.colorSwatches.get(swatch); - let val = color.nextColorUnit(); - - swatch.nextElementSibling.textContent = val; - }, - /** * Append a URL to the output. * From 7931411ee64afe2566254e80ead2ff8ab92b6b19 Mon Sep 17 00:00:00 2001 From: Chenxia Liu Date: Fri, 17 Apr 2015 17:08:26 -0700 Subject: [PATCH 46/80] Bug 1155819 - Clean up phone code more. r=ally --- mobile/android/base/widget/AnchoredPopup.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mobile/android/base/widget/AnchoredPopup.java b/mobile/android/base/widget/AnchoredPopup.java index 699d07c9f4f..05631b56845 100644 --- a/mobile/android/base/widget/AnchoredPopup.java +++ b/mobile/android/base/widget/AnchoredPopup.java @@ -102,11 +102,9 @@ public abstract class AnchoredPopup extends PopupWindow { // If the anchor is null or out of the window bounds, just show the popup at the top of the // root view. - if (mAnchor == null || anchorLocation[1] < 0) { - showAtLocation(decorView, Gravity.NO_GRAVITY, 0, offsetY); - return; - } + final boolean validAnchor = (mAnchor != null) && (anchorLocation[1] > 0); + final View anchor = validAnchor ? mAnchor : decorView; - showAtLocation(mAnchor, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, offsetY); + showAtLocation(anchor, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, offsetY); } } From 7a461140589a029d2a90b9075ff9df5a2500aff7 Mon Sep 17 00:00:00 2001 From: Chenxia Liu Date: Fri, 17 Apr 2015 17:56:10 -0700 Subject: [PATCH 47/80] Bug 1155819 - Set anchor as back button for tablets. r=ally --- .../base/toolbar/BrowserToolbarTabletBase.java | 5 +++++ mobile/android/base/widget/AnchoredPopup.java | 14 +++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/mobile/android/base/toolbar/BrowserToolbarTabletBase.java b/mobile/android/base/toolbar/BrowserToolbarTabletBase.java index 0fdf665412a..b80bb2173fc 100644 --- a/mobile/android/base/toolbar/BrowserToolbarTabletBase.java +++ b/mobile/android/base/toolbar/BrowserToolbarTabletBase.java @@ -127,6 +127,11 @@ abstract class BrowserToolbarTabletBase extends BrowserToolbar { } } + @Override + public View getDoorHangerAnchor() { + return backButton; + } + protected boolean canDoBack(final Tab tab) { return (tab.canDoBack() && !isEditing()); } diff --git a/mobile/android/base/widget/AnchoredPopup.java b/mobile/android/base/widget/AnchoredPopup.java index 05631b56845..6cfee365577 100644 --- a/mobile/android/base/widget/AnchoredPopup.java +++ b/mobile/android/base/widget/AnchoredPopup.java @@ -100,11 +100,15 @@ public abstract class AnchoredPopup extends PopupWindow { return; } - // If the anchor is null or out of the window bounds, just show the popup at the top of the - // root view. - final boolean validAnchor = (mAnchor != null) && (anchorLocation[1] > 0); - final View anchor = validAnchor ? mAnchor : decorView; + if (HardwareUtils.isTablet()) { + showAsDropDown(mAnchor, 0, 0); + } else { + // If the anchor is null or out of the window bounds, just show the popup at the top of the + // root view. + final boolean validAnchor = (mAnchor != null) && (anchorLocation[1] > 0); + final View anchor = validAnchor ? mAnchor : decorView; - showAtLocation(anchor, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, offsetY); + showAtLocation(anchor, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, offsetY); + } } } From c2f1cb6182e37b1313daefd1b52fde293086536e Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 20 Apr 2015 15:40:48 -0700 Subject: [PATCH 48/80] Backed out changeset b09423cfc86b (bug 1098374) for dt orange --- .../devtools/canvasdebugger/canvasdebugger.js | 4 + browser/devtools/shadereditor/shadereditor.js | 4 + browser/devtools/shared/telemetry.js | 17 +- browser/devtools/shared/test/browser.ini | 1 - .../shared/test/browser_observableobject.js | 4 +- .../shared/test/browser_options-view-01.js | 1 + .../shared/test/browser_outputparser.js | 2 + .../browser_telemetry_button_eyedropper.js | 36 +++- .../browser_telemetry_button_paintflashing.js | 49 +++-- .../browser_telemetry_button_responsive.js | 49 +++-- .../browser_telemetry_button_scratchpad.js | 48 ++++- .../test/browser_telemetry_button_tilt.js | 51 ++++-- .../shared/test/browser_telemetry_misc.js | 24 --- .../shared/test/browser_telemetry_sidebar.js | 51 ++++-- .../shared/test/browser_telemetry_toolbox.js | 20 +- ...er_telemetry_toolboxtabs_canvasdebugger.js | 17 +- ...browser_telemetry_toolboxtabs_inspector.js | 20 +- ...rowser_telemetry_toolboxtabs_jsdebugger.js | 20 +- ...rowser_telemetry_toolboxtabs_jsprofiler.js | 13 +- ...rowser_telemetry_toolboxtabs_netmonitor.js | 13 +- .../browser_telemetry_toolboxtabs_options.js | 14 +- ...wser_telemetry_toolboxtabs_shadereditor.js | 14 +- .../browser_telemetry_toolboxtabs_storage.js | 14 +- ...owser_telemetry_toolboxtabs_styleeditor.js | 13 +- ...er_telemetry_toolboxtabs_webaudioeditor.js | 14 +- ...rowser_telemetry_toolboxtabs_webconsole.js | 14 +- browser/devtools/shared/test/head.js | 171 ++++++------------ browser/devtools/storage/ui.js | 6 + browser/devtools/webaudioeditor/controller.js | 2 + browser/devtools/webaudioeditor/includes.js | 5 +- browser/devtools/webide/test/head.js | 113 ------------ .../devtools/webide/test/test_telemetry.html | 91 ++++++++-- 32 files changed, 420 insertions(+), 495 deletions(-) delete mode 100644 browser/devtools/shared/test/browser_telemetry_misc.js diff --git a/browser/devtools/canvasdebugger/canvasdebugger.js b/browser/devtools/canvasdebugger/canvasdebugger.js index 537cda761e5..aaa9ae00985 100644 --- a/browser/devtools/canvasdebugger/canvasdebugger.js +++ b/browser/devtools/canvasdebugger/canvasdebugger.js @@ -17,6 +17,8 @@ const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise; const EventEmitter = require("devtools/toolkit/event-emitter"); const { CallWatcherFront } = require("devtools/server/actors/call-watcher"); const { CanvasFront } = require("devtools/server/actors/canvas"); +const Telemetry = require("devtools/shared/telemetry"); +const telemetry = new Telemetry(); const CANVAS_ACTOR_RECORDING_ATTEMPT = gDevTools.testing ? 500 : 5000; @@ -127,6 +129,7 @@ let EventsHandler = { * Listen for events emitted by the current tab target. */ initialize: function() { + telemetry.toolOpened("canvasdebugger"); this._onTabNavigated = this._onTabNavigated.bind(this); gTarget.on("will-navigate", this._onTabNavigated); gTarget.on("navigate", this._onTabNavigated); @@ -136,6 +139,7 @@ let EventsHandler = { * Remove events emitted by the current tab target. */ destroy: function() { + telemetry.toolClosed("canvasdebugger"); gTarget.off("will-navigate", this._onTabNavigated); gTarget.off("navigate", this._onTabNavigated); }, diff --git a/browser/devtools/shadereditor/shadereditor.js b/browser/devtools/shadereditor/shadereditor.js index c28a2246b64..93019876eb2 100644 --- a/browser/devtools/shadereditor/shadereditor.js +++ b/browser/devtools/shadereditor/shadereditor.js @@ -17,6 +17,8 @@ const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise; const EventEmitter = require("devtools/toolkit/event-emitter"); const {Tooltip} = require("devtools/shared/widgets/Tooltip"); const Editor = require("devtools/sourceeditor/editor"); +const Telemetry = require("devtools/shared/telemetry"); +const telemetry = new Telemetry(); // The panel's window global is an EventEmitter firing the following events: const EVENTS = { @@ -84,6 +86,7 @@ let EventsHandler = { * Listen for events emitted by the current tab target. */ initialize: function() { + telemetry.toolOpened("shadereditor"); this._onHostChanged = this._onHostChanged.bind(this); this._onTabNavigated = this._onTabNavigated.bind(this); this._onProgramLinked = this._onProgramLinked.bind(this); @@ -99,6 +102,7 @@ let EventsHandler = { * Remove events emitted by the current tab target. */ destroy: function() { + telemetry.toolClosed("shadereditor"); gToolbox.off("host-changed", this._onHostChanged); gTarget.off("will-navigate", this._onTabNavigated); gTarget.off("navigate", this._onTabNavigated); diff --git a/browser/devtools/shared/telemetry.js b/browser/devtools/shared/telemetry.js index 05118aa6c7d..0193ccee19a 100644 --- a/browser/devtools/shared/telemetry.js +++ b/browser/devtools/shared/telemetry.js @@ -19,8 +19,17 @@ * timerHistogram: "DEVTOOLS_MYTOOLNAME_TIME_ACTIVE_SECONDS" * }, * - * 3. toolbox.js will automatically ping telemetry with your tools opening and - * timing information. + * 3. Include this module at the top of your tool. Use: + * let Telemetry = require("devtools/shared/telemetry") + * + * 4. Create a telemetry instance in your tool's constructor: + * this._telemetry = new Telemetry(); + * + * 5. When your tool is opened call: + * this._telemetry.toolOpened("mytoolname"); + * + * 6. When your tool is closed call: + * this._telemetry.toolClosed("mytoolname"); * * Note: * You can view telemetry stats for your local Firefox instance via @@ -294,10 +303,6 @@ Telemetry.prototype = { } }, - clearToolsOpenedPref: function() { - Services.prefs.clearUserPref(TOOLS_OPENED_PREF); - }, - destroy: function() { for (let histogramId of this._timers.keys()) { this.stopTimer(histogramId); diff --git a/browser/devtools/shared/test/browser.ini b/browser/devtools/shared/test/browser.ini index 4d352ac3bf5..b5da569d968 100644 --- a/browser/devtools/shared/test/browser.ini +++ b/browser/devtools/shared/test/browser.ini @@ -90,7 +90,6 @@ skip-if = e10s # Bug 1067145 - e10s responsiveview [browser_telemetry_button_tilt.js] skip-if = e10s # Bug 1086492 - Disable tilt for e10s # Bug 937166 - Make tilt work in E10S mode -[browser_telemetry_misc.js] [browser_telemetry_sidebar.js] [browser_telemetry_toolbox.js] [browser_telemetry_toolboxtabs_canvasdebugger.js] diff --git a/browser/devtools/shared/test/browser_observableobject.js b/browser/devtools/shared/test/browser_observableobject.js index 5c1cdc69acc..8bd1d516944 100644 --- a/browser/devtools/shared/test/browser_observableobject.js +++ b/browser/devtools/shared/test/browser_observableobject.js @@ -2,7 +2,9 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ function test() { - let ObservableObject = devtools.require("devtools/shared/observable-object"); + let tmp = {}; + Cu.import("resource://gre/modules/devtools/Loader.jsm", tmp); + let ObservableObject = tmp.devtools.require("devtools/shared/observable-object"); let rawObject = {}; let oe = new ObservableObject(rawObject); diff --git a/browser/devtools/shared/test/browser_options-view-01.js b/browser/devtools/shared/test/browser_options-view-01.js index 147da903403..b64cce36841 100644 --- a/browser/devtools/shared/test/browser_options-view-01.js +++ b/browser/devtools/shared/test/browser_options-view-01.js @@ -4,6 +4,7 @@ // Tests that options-view OptionsView responds to events correctly. const {OptionsView} = devtools.require("devtools/shared/options-view"); +const {Services} = devtools.require("resource://gre/modules/Services.jsm"); const BRANCH = "devtools.debugger."; const BLACK_BOX_PREF = "auto-black-box"; diff --git a/browser/devtools/shared/test/browser_outputparser.js b/browser/devtools/shared/test/browser_outputparser.js index 47fe9685a00..583f74fad4f 100644 --- a/browser/devtools/shared/test/browser_outputparser.js +++ b/browser/devtools/shared/test/browser_outputparser.js @@ -1,6 +1,8 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ +let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); +let {Loader} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {}); let {OutputParser} = devtools.require("devtools/output-parser"); add_task(function*() { diff --git a/browser/devtools/shared/test/browser_telemetry_button_eyedropper.js b/browser/devtools/shared/test/browser_telemetry_button_eyedropper.js index ca429ea02bc..946e4174ebf 100644 --- a/browser/devtools/shared/test/browser_telemetry_button_eyedropper.js +++ b/browser/devtools/shared/test/browser_telemetry_button_eyedropper.js @@ -8,34 +8,50 @@ let {EyedropperManager} = require("devtools/eyedropper/eyedropper"); add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); info("inspector opened"); info("testing the eyedropper button"); - testButton(toolbox); + testButton(toolbox, Telemetry); + stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); -function testButton(toolbox) { +function testButton(toolbox, Telemetry) { let button = toolbox.doc.querySelector("#command-button-eyedropper"); ok(button, "Captain, we have the eyedropper button"); info("clicking the button to open the eyedropper"); button.click(); - checkResults(); + checkResults("_EYEDROPPER_", Telemetry); } -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. +function checkResults(histIdFocus, Telemetry) { + let result = Telemetry.prototype.telemetryInfo; - checkTelemetry("DEVTOOLS_EYEDROPPER_OPENED_BOOLEAN", [0,1,0]); - checkTelemetry("DEVTOOLS_EYEDROPPER_OPENED_PER_USER_FLAG", [0,1,0]); + for (let [histId, value] of Iterator(result)) { + if (histId.startsWith("DEVTOOLS_INSPECTOR_") || + !histId.contains(histIdFocus)) { + // Inspector stats are tested in + // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here + // because we only open the inspector once for this test. + continue; + } + + if (histId.endsWith("OPENED_PER_USER_FLAG")) { + ok(value.length === 1 && value[0] === true, + "Per user value " + histId + " has a single value of true"); + } else if (histId.endsWith("OPENED_BOOLEAN")) { + is(value.length, 1, histId + " has one entry"); + + let okay = value.every(element => element === true); + ok(okay, "All " + histId + " entries are === true"); + } + } } diff --git a/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js b/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js index d05b9d15fbf..692df44c457 100644 --- a/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js +++ b/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js @@ -10,28 +10,28 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); info("inspector opened"); info("testing the paintflashing button"); - yield testButton(toolbox); + yield testButton(toolbox, Telemetry); + stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); -function* testButton(toolbox) { +function* testButton(toolbox, Telemetry) { info("Testing command-button-paintflashing"); let button = toolbox.doc.querySelector("#command-button-paintflashing"); ok(button, "Captain, we have the button"); yield delayedClicks(button, 4); - checkResults(); + checkResults("_PAINTFLASHING_", Telemetry); } function delayedClicks(node, clicks) { @@ -53,10 +53,37 @@ function delayedClicks(node, clicks) { }); } -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_PAINTFLASHING_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_PAINTFLASHING_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_PAINTFLASHING_TIME_ACTIVE_SECONDS", null, "hasentries"); +function checkResults(histIdFocus, Telemetry) { + let result = Telemetry.prototype.telemetryInfo; + + for (let [histId, value] of Iterator(result)) { + if (histId.startsWith("DEVTOOLS_INSPECTOR_") || + !histId.contains(histIdFocus)) { + // Inspector stats are tested in + // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here + // because we only open the inspector once for this test. + continue; + } + + if (histId.endsWith("OPENED_PER_USER_FLAG")) { + ok(value.length === 1 && value[0] === true, + "Per user value " + histId + " has a single value of true"); + } else if (histId.endsWith("OPENED_BOOLEAN")) { + ok(value.length > 1, histId + " has more than one entry"); + + let okay = value.every(function(element) { + return element === true; + }); + + ok(okay, "All " + histId + " entries are === true"); + } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { + ok(value.length > 1, histId + " has more than one entry"); + + let okay = value.every(function(element) { + return element > 0; + }); + + ok(okay, "All " + histId + " entries have time > 0"); + } + } } diff --git a/browser/devtools/shared/test/browser_telemetry_button_responsive.js b/browser/devtools/shared/test/browser_telemetry_button_responsive.js index bb5598d8337..fd9a33460cb 100644 --- a/browser/devtools/shared/test/browser_telemetry_button_responsive.js +++ b/browser/devtools/shared/test/browser_telemetry_button_responsive.js @@ -10,28 +10,28 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); info("inspector opened"); info("testing the responsivedesign button"); - yield testButton(toolbox); + yield testButton(toolbox, Telemetry); + stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); -function* testButton(toolbox) { +function* testButton(toolbox, Telemetry) { info("Testing command-button-responsive"); let button = toolbox.doc.querySelector("#command-button-responsive"); ok(button, "Captain, we have the button"); yield delayedClicks(button, 4); - checkResults(); + checkResults("_RESPONSIVE_", Telemetry); } function delayedClicks(node, clicks) { @@ -53,10 +53,37 @@ function delayedClicks(node, clicks) { }); } -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_RESPONSIVE_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_RESPONSIVE_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_RESPONSIVE_TIME_ACTIVE_SECONDS", null, "hasentries"); +function checkResults(histIdFocus, Telemetry) { + let result = Telemetry.prototype.telemetryInfo; + + for (let [histId, value] of Iterator(result)) { + if (histId.startsWith("DEVTOOLS_INSPECTOR_") || + !histId.contains(histIdFocus)) { + // Inspector stats are tested in + // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here + // because we only open the inspector once for this test. + continue; + } + + if (histId.endsWith("OPENED_PER_USER_FLAG")) { + ok(value.length === 1 && value[0] === true, + "Per user value " + histId + " has a single value of true"); + } else if (histId.endsWith("OPENED_BOOLEAN")) { + ok(value.length > 1, histId + " has more than one entry"); + + let okay = value.every(function(element) { + return element === true; + }); + + ok(okay, "All " + histId + " entries are === true"); + } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { + ok(value.length > 1, histId + " has more than one entry"); + + let okay = value.every(function(element) { + return element > 0; + }); + + ok(okay, "All " + histId + " entries have time > 0"); + } + } } diff --git a/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js b/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js index e1a5b137fc6..f96755fcf8e 100644 --- a/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js +++ b/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js @@ -10,8 +10,7 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); @@ -20,11 +19,12 @@ add_task(function*() { let onAllWindowsOpened = trackScratchpadWindows(); info("testing the scratchpad button"); - yield testButton(toolbox); + yield testButton(toolbox, Telemetry); yield onAllWindowsOpened; - checkResults(); + checkResults("_SCRATCHPAD_", Telemetry); + stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); @@ -64,7 +64,7 @@ function trackScratchpadWindows() { }); } -function* testButton(toolbox) { +function* testButton(toolbox, Telemetry) { info("Testing command-button-scratchpad"); let button = toolbox.doc.querySelector("#command-button-scratchpad"); ok(button, "Captain, we have the button"); @@ -91,9 +91,37 @@ function delayedClicks(node, clicks) { }); } -function checkResults(histIdFocus) { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_SCRATCHPAD_OPENED_BOOLEAN", [0,4,0]); - checkTelemetry("DEVTOOLS_SCRATCHPAD_OPENED_PER_USER_FLAG", [0,1,0]); +function checkResults(histIdFocus, Telemetry) { + let result = Telemetry.prototype.telemetryInfo; + + for (let [histId, value] of Iterator(result)) { + if (histId.startsWith("DEVTOOLS_INSPECTOR_") || + !histId.contains(histIdFocus)) { + // Inspector stats are tested in + // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here + // because we only open the inspector once for this test. + continue; + } + + if (histId.endsWith("OPENED_PER_USER_FLAG")) { + ok(value.length === 1 && value[0] === true, + "Per user value " + histId + " has a single value of true"); + } else if (histId.endsWith("OPENED_BOOLEAN")) { + ok(value.length > 1, histId + " has more than one entry"); + + let okay = value.every(function(element) { + return element === true; + }); + + ok(okay, "All " + histId + " entries are === true"); + } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { + ok(value.length > 1, histId + " has more than one entry"); + + let okay = value.every(function(element) { + return element > 0; + }); + + ok(okay, "All " + histId + " entries have time > 0"); + } + } } diff --git a/browser/devtools/shared/test/browser_telemetry_button_tilt.js b/browser/devtools/shared/test/browser_telemetry_button_tilt.js index b5cd3b30c70..4e36618ca5e 100644 --- a/browser/devtools/shared/test/browser_telemetry_button_tilt.js +++ b/browser/devtools/shared/test/browser_telemetry_button_tilt.js @@ -10,28 +10,28 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); info("inspector opened"); info("testing the tilt button"); - yield testButton(toolbox); + yield testButton(toolbox, Telemetry); + stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); -function* testButton(toolbox) { +function* testButton(toolbox, Telemetry) { info("Testing command-button-tilt"); let button = toolbox.doc.querySelector("#command-button-tilt"); ok(button, "Captain, we have the button"); - yield delayedClicks(button, 4); - checkResults(); + yield delayedClicks(button, 4) + checkResults("_TILT_", Telemetry); } function delayedClicks(node, clicks) { @@ -53,10 +53,37 @@ function delayedClicks(node, clicks) { }); } -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_TILT_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_TILT_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_TILT_TIME_ACTIVE_SECONDS", null, "hasentries"); +function checkResults(histIdFocus, Telemetry) { + let result = Telemetry.prototype.telemetryInfo; + + for (let [histId, value] of Iterator(result)) { + if (histId.startsWith("DEVTOOLS_INSPECTOR_") || + !histId.contains(histIdFocus)) { + // Inspector stats are tested in + // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here + // because we only open the inspector once for this test. + continue; + } + + if (histId.endsWith("OPENED_PER_USER_FLAG")) { + ok(value.length === 1 && value[0] === true, + "Per user value " + histId + " has a single value of true"); + } else if (histId.endsWith("OPENED_BOOLEAN")) { + ok(value.length > 1, histId + " has more than one entry"); + + let okay = value.every(function(element) { + return element === true; + }); + + ok(okay, "All " + histId + " entries are === true"); + } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { + ok(value.length > 1, histId + " has more than one entry"); + + let okay = value.every(function(element) { + return element > 0; + }); + + ok(okay, "All " + histId + " entries have time > 0"); + } + } } diff --git a/browser/devtools/shared/test/browser_telemetry_misc.js b/browser/devtools/shared/test/browser_telemetry_misc.js deleted file mode 100644 index f5859d5629d..00000000000 --- a/browser/devtools/shared/test/browser_telemetry_misc.js +++ /dev/null @@ -1,24 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -const TEST_URI = "data:text/html;charset=utf-8,

browser_telemetry_misc.js

"; -const TOOL_DELAY = 0; - -add_task(function*() { - yield promiseTab(TEST_URI); - - startTelemetry(); - - yield openAndCloseToolbox(1, TOOL_DELAY, "inspector"); - checkResults(); - - gBrowser.removeCurrentTab(); -}); - -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_OS_ENUMERATED_PER_USER", null, "hasentries"); - checkTelemetry("DEVTOOLS_OS_IS_64_BITS_PER_USER", null, "hasentries"); - checkTelemetry("DEVTOOLS_SCREEN_RESOLUTION_ENUMERATED_PER_USER", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_sidebar.js b/browser/devtools/shared/test/browser_telemetry_sidebar.js index a975090ec0b..b80930e0e6c 100644 --- a/browser/devtools/shared/test/browser_telemetry_sidebar.js +++ b/browser/devtools/shared/test/browser_telemetry_sidebar.js @@ -9,16 +9,16 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target, "inspector"); info("inspector opened"); yield testSidebar(toolbox); - checkResults(); + checkResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); yield gDevTools.closeToolbox(target); gBrowser.removeCurrentTab(); }); @@ -49,16 +49,37 @@ function* testSidebar(toolbox) { }); } -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_ANIMATIONINSPECTOR_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_ANIMATIONINSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_ANIMATIONINSPECTOR_TIME_ACTIVE_SECONDS", null, "hasentries"); - checkTelemetry("DEVTOOLS_COMPUTEDVIEW_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_COMPUTEDVIEW_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS", null, "hasentries"); - checkTelemetry("DEVTOOLS_FONTINSPECTOR_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_FONTINSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS", null, "hasentries"); +function checkResults(Telemetry) { + let result = Telemetry.prototype.telemetryInfo; + + for (let [histId, value] of Iterator(result)) { + if (histId.startsWith("DEVTOOLS_INSPECTOR_")) { + // Inspector stats are tested in browser_telemetry_toolboxtabs.js so we + // skip them here because we only open the inspector once for this test. + continue; + } + + if (histId.endsWith("OPENED_PER_USER_FLAG")) { + ok(value.length === 1 && value[0] === true, + "Per user value " + histId + " has a single value of true"); + } else if (histId === "DEVTOOLS_TOOLBOX_OPENED_BOOLEAN") { + is(value.length, 1, histId + " has only one entry"); + } else if (histId.endsWith("OPENED_BOOLEAN")) { + ok(value.length > 1, histId + " has more than one entry"); + + let okay = value.every(function(element) { + return element === true; + }); + + ok(okay, "All " + histId + " entries are === true"); + } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { + ok(value.length > 1, histId + " has more than one entry"); + + let okay = value.every(function(element) { + return element > 0; + }); + + ok(okay, "All " + histId + " entries have time > 0"); + } + } } diff --git a/browser/devtools/shared/test/browser_telemetry_toolbox.js b/browser/devtools/shared/test/browser_telemetry_toolbox.js index 724fdd129e5..366f64699ab 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolbox.js +++ b/browser/devtools/shared/test/browser_telemetry_toolbox.js @@ -10,25 +10,11 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(3, TOOL_DELAY, "inspector"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); - -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_BOOLEAN", [0,3,0]); - checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_INSPECTOR_TIME_ACTIVE_SECONDS", null, "hasentries"); - checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_BOOLEAN", [0,3,0]); - checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS", null, "hasentries"); - checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,3,0]); - checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js index bae88ab26c0..c9c07099a59 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_canvasdebugger.js @@ -14,25 +14,14 @@ add_task(function*() { Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", true); yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(2, TOOL_DELAY, "canvasdebugger"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); info("De-activate the canvasdebugger"); Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", originalPref); }); - -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_CANVASDEBUGGER_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_CANVASDEBUGGER_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_CANVASDEBUGGER_TIME_ACTIVE_SECONDS", null, "hasentries"); - checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js index 236faf6e469..61dff980af2 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js @@ -10,25 +10,11 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(2, TOOL_DELAY, "inspector"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); - -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_INSPECTOR_TIME_ACTIVE_SECONDS", null, "hasentries"); - checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS", null, "hasentries"); - checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js index cc70eda3e39..a8625518351 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js @@ -10,25 +10,11 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(2, TOOL_DELAY, "jsdebugger"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); - -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS", null, "hasentries"); - checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETHREAD_MS", null, "hasentries"); - checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_RESUME_MS", null, "hasentries"); - checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_SOURCES_MS", null, "hasentries"); - checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS", null, "hasentries"); - checkTelemetry("DEVTOOLS_DEBUGGER_RDP_LOCAL_THREADDETACH_MS", null, "hasentries"); - checkTelemetry("DEVTOOLS_JSDEBUGGER_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_JSDEBUGGER_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_JSDEBUGGER_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js index d3db7fad406..e2131feb2df 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js @@ -9,18 +9,11 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(2, TOOL_DELAY, "performance"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); - -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_JSPROFILER_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_JSPROFILER_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_JSPROFILER_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js index a0fa1abd97a..e7554e5492a 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js @@ -9,19 +9,12 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(2, TOOL_DELAY, "netmonitor"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_NETMONITOR_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_NETMONITOR_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_NETMONITOR_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js index b0ed00e6266..14256814e49 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js @@ -9,19 +9,11 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(2, TOOL_DELAY, "options"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); - -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_OPTIONS_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_OPTIONS_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_OPTIONS_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js index 7f25e08a4c3..476fbd320d9 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_shadereditor.js @@ -20,22 +20,14 @@ add_task(function*() { Services.prefs.setBoolPref("devtools.shadereditor.enabled", true); yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(2, TOOL_DELAY, "shadereditor"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); info("De-activate the sharer editor"); Services.prefs.setBoolPref("devtools.shadereditor.enabled", originalPref); }); - -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_SHADEREDITOR_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_SHADEREDITOR_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_SHADEREDITOR_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js index b935204c68c..93348b96df7 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_storage.js @@ -12,22 +12,14 @@ add_task(function*() { Services.prefs.setBoolPref("devtools.storage.enabled", true); yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(2, TOOL_DELAY, "storage"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); info("De-activating the storage inspector"); Services.prefs.clearUserPref("devtools.storage.enabled"); }); - -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_STORAGE_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_STORAGE_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_STORAGE_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js index 968b328eecf..15c4a9c08ac 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js @@ -9,19 +9,12 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(2, TOOL_DELAY, "styleeditor"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_STYLEEDITOR_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_STYLEEDITOR_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_STYLEEDITOR_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js index 435b5711563..033791a7235 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webaudioeditor.js @@ -13,22 +13,14 @@ add_task(function*() { Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", true); yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(2, TOOL_DELAY, "webaudioeditor"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); info("De-activating the webaudioeditor"); Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", originalPref); }); - -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_WEBAUDIOEDITOR_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_WEBAUDIOEDITOR_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_WEBAUDIOEDITOR_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js index 693790522fd..b989a14269a 100644 --- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js +++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js @@ -9,19 +9,11 @@ const TOOL_DELAY = 200; add_task(function*() { yield promiseTab(TEST_URI); - - startTelemetry(); + let Telemetry = loadTelemetryAndRecordLogs(); yield openAndCloseToolbox(2, TOOL_DELAY, "webconsole"); - checkResults(); + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); gBrowser.removeCurrentTab(); }); - -function checkResults() { - // For help generating these tests use generateTelemetryTests("DEVTOOLS_") - // here. - checkTelemetry("DEVTOOLS_WEBCONSOLE_OPENED_BOOLEAN", [0,2,0]); - checkTelemetry("DEVTOOLS_WEBCONSOLE_OPENED_PER_USER_FLAG", [0,1,0]); - checkTelemetry("DEVTOOLS_WEBCONSOLE_TIME_ACTIVE_SECONDS", null, "hasentries"); -} diff --git a/browser/devtools/shared/test/head.js b/browser/devtools/shared/test/head.js index a6542217f82..121f75f6900 100644 --- a/browser/devtools/shared/test/head.js +++ b/browser/devtools/shared/test/head.js @@ -6,22 +6,12 @@ let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); let {TargetFactory, require} = devtools; let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {}); let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); -let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); const {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {}); const {Hosts} = require("devtools/framework/toolbox-hosts"); -let oldCanRecord = Services.telemetry.canRecordExtended; - gDevTools.testing = true; -registerCleanupFunction(() => { - _stopTelemetry(); +SimpleTest.registerCleanupFunction(() => { gDevTools.testing = false; - - while (gBrowser.tabs.length > 1) { - gBrowser.removeCurrentTab(); - } - - console = undefined; }); const TEST_URI_ROOT = "http://example.com/browser/browser/devtools/shared/test/"; @@ -53,6 +43,14 @@ function promiseTab(aURL) { addTab(aURL, resolve)); } +registerCleanupFunction(function tearDown() { + while (gBrowser.tabs.length > 1) { + gBrowser.removeCurrentTab(); + } + + console = undefined; +}); + function catchFail(func) { return function() { try { @@ -152,124 +150,73 @@ let createHost = Task.async(function*(type = "bottom", src = "data:text/html;cha return [host, iframe.contentWindow, iframe.contentDocument]; }); -function reportError(error) { - let stack = " " + error.stack.replace(/\n?.*?@/g, "\n JS frame :: "); +/** + * Load the Telemetry utils, then stub Telemetry.prototype.log in order to + * record everything that's logged in it. + * Store all recordings on Telemetry.telemetryInfo. + * @return {Telemetry} + */ +function loadTelemetryAndRecordLogs() { + info("Mock the Telemetry log function to record logged information"); - ok(false, "ERROR: " + error + " at " + error.fileName + ":" + - error.lineNumber + "\n\nStack trace:" + stack); + let Telemetry = require("devtools/shared/telemetry"); + Telemetry.prototype.telemetryInfo = {}; + Telemetry.prototype._oldlog = Telemetry.prototype.log; + Telemetry.prototype.log = function(histogramId, value) { + if (!this.telemetryInfo) { + // Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10) + return; + } + if (histogramId) { + if (!this.telemetryInfo[histogramId]) { + this.telemetryInfo[histogramId] = []; + } - if (finishUp) { - finishUp(); - } -} + this.telemetryInfo[histogramId].push(value); + } + }; -function startTelemetry() { - Services.telemetry.canRecordExtended = true; + return Telemetry; } /** - * This method is automatically called on teardown. + * Stop recording the Telemetry logs and put back the utils as it was before. */ -function _stopTelemetry() { - let Telemetry = devtools.require("devtools/shared/telemetry"); - let telemetry = new Telemetry(); - - telemetry.clearToolsOpenedPref(); - - Services.telemetry.canRecordExtended = oldCanRecord; - - // Clean up telemetry histogram changes - for (let histId in Services.telemetry.histogramSnapshots) { - try { - let histogram = Services.telemetry.getHistogramById(histId); - histogram.clear(); - } catch(e) { - // Histograms is not listed in histograms.json, do nothing. - } - } +function stopRecordingTelemetryLogs(Telemetry) { + Telemetry.prototype.log = Telemetry.prototype._oldlog; + delete Telemetry.prototype._oldlog; + delete Telemetry.prototype.telemetryInfo; } /** - * Check the value of a given telemetry histogram. - * - * @param {String} histId - * Histogram id - * @param {Array|Number} expected - * Expected value - * @param {String} checkType - * "array" (default) - Check that an array matches the histogram data. - * "hasentries" - For non-enumerated linear and exponential - * histograms. This checks for at least one entry. + * Check the correctness of the data recorded in Telemetry after + * loadTelemetryAndRecordLogs was called. */ -function checkTelemetry(histId, expected, checkType="array") { - let actual = Services.telemetry.getHistogramById(histId).snapshot().counts; +function checkTelemetryResults(Telemetry) { + let result = Telemetry.prototype.telemetryInfo; - switch (checkType) { - case "array": - is(JSON.stringify(actual), JSON.stringify(expected), histId + " correct."); - break; - case "hasentries": - let hasEntry = actual.some(num => num > 0); - ok(hasEntry, histId + " has at least one entry."); - break; - } -} + for (let [histId, value] of Iterator(result)) { + if (histId.endsWith("OPENED_PER_USER_FLAG")) { + ok(value.length === 1 && value[0] === true, + "Per user value " + histId + " has a single value of true"); + } else if (histId.endsWith("OPENED_BOOLEAN")) { + ok(value.length > 1, histId + " has more than one entry"); -/** - * Generate telemetry tests. You should call generateTelemetryTests("DEVTOOLS_") - * from your result checking code in telemetry tests. It logs checkTelemetry - * calls for all changed telemetry values. - * - * @param {String} prefix - * Optionally limits results to histogram ids starting with prefix. - */ -function generateTelemetryTests(prefix="") { - dump("=".repeat(80) + "\n"); - for (let histId in Services.telemetry.histogramSnapshots) { - if (!histId.startsWith(prefix)) { - continue; - } + let okay = value.every(function(element) { + return element === true; + }); - let snapshot = Services.telemetry.histogramSnapshots[histId]; - let actual = snapshot.counts; + ok(okay, "All " + histId + " entries are === true"); + } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) { + ok(value.length > 1, histId + " has more than one entry"); - switch (snapshot.histogram_type) { - case Services.telemetry.HISTOGRAM_EXPONENTIAL: - case Services.telemetry.HISTOGRAM_LINEAR: - let total = 0; - for (let val of actual) { - total += val; - } + let okay = value.every(function(element) { + return element > 0; + }); - if (histId.endsWith("_ENUMERATED")) { - if (total > 0) { - dump("checkTelemetry(\"" + histId + "\", " + JSON.stringify(actual) + ");\n"); - } - continue; - } - - dump("checkTelemetry(\"" + histId + "\", null, \"hasentries\");\n"); - break; - case Services.telemetry.HISTOGRAM_BOOLEAN: - actual = JSON.stringify(actual); - - if (actual !== "[0,0,0]") { - dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); - } - break; - case Services.telemetry.HISTOGRAM_FLAG: - actual = JSON.stringify(actual); - - if (actual !== "[1,0,0]") { - dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); - } - break; - case Services.telemetry.HISTOGRAM_COUNT: - dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); - break; + ok(okay, "All " + histId + " entries have time > 0"); } } - dump("=".repeat(80) + "\n"); } /** @@ -283,7 +230,7 @@ function* openAndCloseToolbox(nbOfTimes, usageTime, toolId) { for (let i = 0; i < nbOfTimes; i ++) { info("Opening toolbox " + (i + 1)); let target = TargetFactory.forTab(gBrowser.selectedTab); - yield gDevTools.showToolbox(target, toolId); + yield gDevTools.showToolbox(target, toolId) // We use a timeout to check the toolbox's active time yield new Promise(resolve => setTimeout(resolve, usageTime)); diff --git a/browser/devtools/storage/ui.js b/browser/devtools/storage/ui.js index 1e1ee0ce974..52a0ca12b3d 100644 --- a/browser/devtools/storage/ui.js +++ b/browser/devtools/storage/ui.js @@ -21,6 +21,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "ViewHelpers", XPCOMUtils.defineLazyModuleGetter(this, "VariablesView", "resource:///modules/devtools/VariablesView.jsm"); +let Telemetry = require("devtools/shared/telemetry"); + /** * Localization convenience methods. */ @@ -85,6 +87,9 @@ this.StorageUI = function StorageUI(front, target, panelWin) { this.handleKeypress = this.handleKeypress.bind(this); this._panelDoc.addEventListener("keypress", this.handleKeypress); + + this._telemetry = new Telemetry(); + this._telemetry.toolOpened("storage"); } exports.StorageUI = StorageUI; @@ -97,6 +102,7 @@ StorageUI.prototype = { destroy: function() { this.front.off("stores-update", this.onUpdate); this._panelDoc.removeEventListener("keypress", this.handleKeypress); + this._telemetry.toolClosed("storage"); }, /** diff --git a/browser/devtools/webaudioeditor/controller.js b/browser/devtools/webaudioeditor/controller.js index 5f9755f4832..544650a9104 100644 --- a/browser/devtools/webaudioeditor/controller.js +++ b/browser/devtools/webaudioeditor/controller.js @@ -42,6 +42,7 @@ let WebAudioEditorController = { * Listen for events emitted by the current tab target. */ initialize: Task.async(function* () { + telemetry.toolOpened("webaudioeditor"); this._onTabNavigated = this._onTabNavigated.bind(this); this._onThemeChange = this._onThemeChange.bind(this); @@ -75,6 +76,7 @@ let WebAudioEditorController = { * Remove events emitted by the current tab target. */ destroy: function() { + telemetry.toolClosed("webaudioeditor"); gTarget.off("will-navigate", this._onTabNavigated); gTarget.off("navigate", this._onTabNavigated); gFront.off("start-context", this._onStartContext); diff --git a/browser/devtools/webaudioeditor/includes.js b/browser/devtools/webaudioeditor/includes.js index acfbe87278c..2e6b8ece4ea 100644 --- a/browser/devtools/webaudioeditor/includes.js +++ b/browser/devtools/webaudioeditor/includes.js @@ -19,9 +19,10 @@ let { EventTarget } = require("sdk/event/target"); const { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); const { Class } = require("sdk/core/heritage"); const EventEmitter = require("devtools/toolkit/event-emitter"); -const STRINGS_URI = "chrome://browser/locale/devtools/webaudioeditor.properties"; +const STRINGS_URI = "chrome://browser/locale/devtools/webaudioeditor.properties" const L10N = new ViewHelpers.L10N(STRINGS_URI); - +const Telemetry = require("devtools/shared/telemetry"); +const telemetry = new Telemetry(); devtools.lazyImporter(this, "LineGraphWidget", "resource:///modules/devtools/Graphs.jsm"); diff --git a/browser/devtools/webide/test/head.js b/browser/devtools/webide/test/head.js index 309dbc61262..71d6697c863 100644 --- a/browser/devtools/webide/test/head.js +++ b/browser/devtools/webide/test/head.js @@ -14,8 +14,6 @@ const {require} = devtools; const promise = require("promise"); const {AppProjects} = require("devtools/app-manager/app-projects"); -let oldCanRecord = Services.telemetry.canRecordExtended; - let TEST_BASE; if (window.location === "chrome://browser/content/browser.xul") { TEST_BASE = "chrome://mochitests/content/browser/browser/devtools/webide/test/"; @@ -35,8 +33,6 @@ Services.prefs.setCharPref("devtools.webide.templatesURL", TEST_BASE + "template Services.prefs.setCharPref("devtools.devices.url", TEST_BASE + "browser_devices.json"); SimpleTest.registerCleanupFunction(() => { - _stopTelemetry(); - Services.prefs.clearUserPref("devtools.webide.enabled"); Services.prefs.clearUserPref("devtools.webide.enableLocalRuntime"); Services.prefs.clearUserPref("devtools.webide.autoinstallADBHelper"); @@ -211,112 +207,3 @@ function handleError(aError) { ok(false, "Got an error: " + aError.message + "\n" + aError.stack); finish(); } - -function startTelemetry() { - Services.telemetry.canRecordExtended = true; -} - -/** - * This method is automatically called on teardown. - */ -function _stopTelemetry() { - let Telemetry = devtools.require("devtools/shared/telemetry"); - let telemetry = new Telemetry(); - - telemetry.clearToolsOpenedPref(); - - Services.telemetry.canRecordExtended = oldCanRecord; - - // Clean up telemetry histogram changes - for (let histId in Services.telemetry.histogramSnapshots) { - try { - let histogram = Services.telemetry.getHistogramById(histId); - histogram.clear(); - } catch(e) { - // Histograms is not listed in histograms.json, do nothing. - } - } -} - -/** - * Check the value of a given telemetry histogram. - * - * @param {String} histId - * Histogram id - * @param {Array|Number} expected - * Expected value - * @param {String} checkType - * "array" (default) - Check that an array matches the histogram data. - * "hasentries" - For non-enumerated linear and exponential - * histograms. This checks for at least one entry. - */ -function checkTelemetry(histId, expected, checkType="array") { - let actual = Services.telemetry.getHistogramById(histId).snapshot().counts; - - switch (checkType) { - case "array": - is(JSON.stringify(actual), JSON.stringify(expected), histId + " correct."); - break; - case "hasentries": - let hasEntry = actual.some(num => num > 0); - ok(hasEntry, histId + " has at least one entry."); - break; - } -} - -/** - * Generate telemetry tests. You should call generateTelemetryTests("DEVTOOLS_") - * from your result checking code in telemetry tests. It logs checkTelemetry - * calls for all changed telemetry values. - * - * @param {String} prefix - * Optionally limits results to histogram ids starting with prefix. - */ -function generateTelemetryTests(prefix="") { - dump("=".repeat(80) + "\n"); - for (let histId in Services.telemetry.histogramSnapshots) { - if (!histId.startsWith(prefix)) { - continue; - } - - let snapshot = Services.telemetry.histogramSnapshots[histId]; - let actual = snapshot.counts; - - switch (snapshot.histogram_type) { - case Services.telemetry.HISTOGRAM_EXPONENTIAL: - case Services.telemetry.HISTOGRAM_LINEAR: - let total = 0; - for (let val of actual) { - total += val; - } - - if (histId.endsWith("_ENUMERATED")) { - if (total > 0) { - dump("checkTelemetry(\"" + histId + "\", " + JSON.stringify(actual) + ");\n"); - } - continue; - } - - dump("checkTelemetry(\"" + histId + "\", null, \"hasentries\");\n"); - break; - case Services.telemetry.HISTOGRAM_BOOLEAN: - actual = JSON.stringify(actual); - - if (actual !== "[0,0,0]") { - dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); - } - break; - case Services.telemetry.HISTOGRAM_FLAG: - actual = JSON.stringify(actual); - - if (actual !== "[1,0,0]") { - dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); - } - break; - case Services.telemetry.HISTOGRAM_COUNT: - dump("checkTelemetry(\"" + histId + "\", " + actual + ");\n"); - break; - } - } - dump("=".repeat(80) + "\n"); -} diff --git a/browser/devtools/webide/test/test_telemetry.html b/browser/devtools/webide/test/test_telemetry.html index 4133cb65831..72eb4d51fed 100644 --- a/browser/devtools/webide/test/test_telemetry.html +++ b/browser/devtools/webide/test/test_telemetry.html @@ -15,6 +15,7 @@ diff --git a/dom/workers/test/serviceworkers/fetch/https/clonedresponse/register.html b/dom/workers/test/serviceworkers/fetch/https/clonedresponse/register.html index d2f168b8bd6..41774f70d18 100644 --- a/dom/workers/test/serviceworkers/fetch/https/clonedresponse/register.html +++ b/dom/workers/test/serviceworkers/fetch/https/clonedresponse/register.html @@ -4,23 +4,11 @@ window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*"); } - var isDone = false; function done(reg) { - if (!isDone) { - ok(reg.waiting || reg.active, "Either active or waiting worker should be available."); - window.parent.postMessage({status: "registrationdone"}, "*"); - isDone = true; - } + ok(reg.active, "The active worker should be available."); + window.parent.postMessage({status: "registrationdone"}, "*"); } - navigator.serviceWorker.register("https_test.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - done(registration); - }; - } else { - done(registration); - } - }); + navigator.serviceWorker.ready.then(done); + navigator.serviceWorker.register("https_test.js", {scope: "."}); diff --git a/dom/workers/test/serviceworkers/fetch/https/register.html b/dom/workers/test/serviceworkers/fetch/https/register.html index d2f168b8bd6..41774f70d18 100644 --- a/dom/workers/test/serviceworkers/fetch/https/register.html +++ b/dom/workers/test/serviceworkers/fetch/https/register.html @@ -4,23 +4,11 @@ window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*"); } - var isDone = false; function done(reg) { - if (!isDone) { - ok(reg.waiting || reg.active, "Either active or waiting worker should be available."); - window.parent.postMessage({status: "registrationdone"}, "*"); - isDone = true; - } + ok(reg.active, "The active worker should be available."); + window.parent.postMessage({status: "registrationdone"}, "*"); } - navigator.serviceWorker.register("https_test.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - done(registration); - }; - } else { - done(registration); - } - }); + navigator.serviceWorker.ready.then(done); + navigator.serviceWorker.register("https_test.js", {scope: "."}); diff --git a/dom/workers/test/serviceworkers/fetch/sandbox/register.html b/dom/workers/test/serviceworkers/fetch/sandbox/register.html index 9f742274c4b..427b1a8da97 100644 --- a/dom/workers/test/serviceworkers/fetch/sandbox/register.html +++ b/dom/workers/test/serviceworkers/fetch/sandbox/register.html @@ -4,23 +4,11 @@ window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*"); } - var isDone = false; function done(reg) { - if (!isDone) { - ok(reg.waiting || reg.active, "Either active or waiting worker should be available."); - window.parent.postMessage({status: "registrationdone"}, "*"); - isDone = true; - } + ok(reg.active, "The active worker should be available."); + window.parent.postMessage({status: "registrationdone"}, "*"); } - navigator.serviceWorker.register("sandbox_test.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - done(registration); - }; - } else { - done(registration); - } - }); + navigator.serviceWorker.ready.then(done); + navigator.serviceWorker.register("sandbox_test.js", {scope: "."}); diff --git a/dom/workers/test/serviceworkers/periodic/register.html b/dom/workers/test/serviceworkers/periodic/register.html index a5e73c130b6..1db75bea8ac 100644 --- a/dom/workers/test/serviceworkers/periodic/register.html +++ b/dom/workers/test/serviceworkers/periodic/register.html @@ -1,21 +1,9 @@ diff --git a/dom/workers/test/serviceworkers/test_close.html b/dom/workers/test/serviceworkers/test_close.html index 04c9402d784..78057a88181 100644 --- a/dom/workers/test/serviceworkers/test_close.html +++ b/dom/workers/test/serviceworkers/test_close.html @@ -19,17 +19,8 @@ var iframe; function runTest() { - navigator.serviceWorker.register("close_test.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - setupSW(registration); - e.target.onstatechange = null; - }; - } else { - setupSW(registration); - } - }); + navigator.serviceWorker.ready.then(setupSW); + navigator.serviceWorker.register("close_test.js", {scope: "."}); function setupSW(registration) { var worker = registration.waiting || diff --git a/dom/workers/test/serviceworkers/test_empty_serviceworker.html b/dom/workers/test/serviceworkers/test_empty_serviceworker.html index 242a267d124..c93906a2758 100644 --- a/dom/workers/test/serviceworkers/test_empty_serviceworker.html +++ b/dom/workers/test/serviceworkers/test_empty_serviceworker.html @@ -17,17 +17,8 @@ diff --git a/dom/workers/test/serviceworkers/fetch/https/clonedresponse/unregister.html b/dom/workers/test/serviceworkers/fetch/https/clonedresponse/unregister.html index f811dd3c00a..1f13508fa70 100644 --- a/dom/workers/test/serviceworkers/fetch/https/clonedresponse/unregister.html +++ b/dom/workers/test/serviceworkers/fetch/https/clonedresponse/unregister.html @@ -5,6 +5,8 @@ if (success) { window.parent.postMessage({status: "unregistrationdone"}, "*"); } + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); }); diff --git a/dom/workers/test/serviceworkers/fetch/https/unregister.html b/dom/workers/test/serviceworkers/fetch/https/unregister.html index f811dd3c00a..1f13508fa70 100644 --- a/dom/workers/test/serviceworkers/fetch/https/unregister.html +++ b/dom/workers/test/serviceworkers/fetch/https/unregister.html @@ -5,6 +5,8 @@ if (success) { window.parent.postMessage({status: "unregistrationdone"}, "*"); } + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); }); diff --git a/dom/workers/test/serviceworkers/fetch/sandbox/unregister.html b/dom/workers/test/serviceworkers/fetch/sandbox/unregister.html index f811dd3c00a..1f13508fa70 100644 --- a/dom/workers/test/serviceworkers/fetch/sandbox/unregister.html +++ b/dom/workers/test/serviceworkers/fetch/sandbox/unregister.html @@ -5,6 +5,8 @@ if (success) { window.parent.postMessage({status: "unregistrationdone"}, "*"); } + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); }); diff --git a/dom/workers/test/serviceworkers/periodic/unregister.html b/dom/workers/test/serviceworkers/periodic/unregister.html index b8aac2b2d2e..e2b94799a7e 100644 --- a/dom/workers/test/serviceworkers/periodic/unregister.html +++ b/dom/workers/test/serviceworkers/periodic/unregister.html @@ -7,6 +7,8 @@ } else { dump("Unregister failed\n"); } + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); }); diff --git a/dom/workers/test/serviceworkers/test_client_focus.html b/dom/workers/test/serviceworkers/test_client_focus.html index 81a3c73ea78..e1b08c7ca38 100644 --- a/dom/workers/test/serviceworkers/test_client_focus.html +++ b/dom/workers/test/serviceworkers/test_client_focus.html @@ -30,6 +30,8 @@ function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } diff --git a/dom/workers/test/serviceworkers/test_close.html b/dom/workers/test/serviceworkers/test_close.html index 78057a88181..d2f72b9ef93 100644 --- a/dom/workers/test/serviceworkers/test_close.html +++ b/dom/workers/test/serviceworkers/test_close.html @@ -38,7 +38,11 @@ ok(e.data.result, e.data.message); } else if (e.data.status == "done") { navigator.serviceWorker.getRegistration().then(function(registration) { - registration.unregister().then(function() { + registration.unregister().then(function(result) { + ok(result, "Unregistering the service worker should succeed"); + SimpleTest.finish(); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); SimpleTest.finish(); }); }); diff --git a/dom/workers/test/serviceworkers/test_empty_serviceworker.html b/dom/workers/test/serviceworkers/test_empty_serviceworker.html index c93906a2758..e4295189618 100644 --- a/dom/workers/test/serviceworkers/test_empty_serviceworker.html +++ b/dom/workers/test/serviceworkers/test_empty_serviceworker.html @@ -26,6 +26,9 @@ registration.unregister().then(function(success) { ok(success, "unregister worked"); SimpleTest.finish(); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); + SimpleTest.finish(); }); } diff --git a/dom/workers/test/serviceworkers/test_importscript.html b/dom/workers/test/serviceworkers/test_importscript.html index b1f04c85ece..45e50642565 100644 --- a/dom/workers/test/serviceworkers/test_importscript.html +++ b/dom/workers/test/serviceworkers/test_importscript.html @@ -21,6 +21,8 @@ function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } diff --git a/dom/workers/test/serviceworkers/test_match_all.html b/dom/workers/test/serviceworkers/test_match_all.html index c6d3bdbee9c..f4e65a730e9 100644 --- a/dom/workers/test/serviceworkers/test_match_all.html +++ b/dom/workers/test/serviceworkers/test_match_all.html @@ -31,6 +31,8 @@ return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } diff --git a/dom/workers/test/serviceworkers/test_match_all_advanced.html b/dom/workers/test/serviceworkers/test_match_all_advanced.html index 3d9823192d8..a458ed70ba4 100644 --- a/dom/workers/test/serviceworkers/test_match_all_advanced.html +++ b/dom/workers/test/serviceworkers/test_match_all_advanced.html @@ -33,6 +33,8 @@ function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } diff --git a/dom/workers/test/serviceworkers/test_match_all_client_id.html b/dom/workers/test/serviceworkers/test_match_all_client_id.html index 5d79f4053fd..c3cc5756a23 100644 --- a/dom/workers/test/serviceworkers/test_match_all_client_id.html +++ b/dom/workers/test/serviceworkers/test_match_all_client_id.html @@ -25,6 +25,8 @@ function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } diff --git a/dom/workers/test/serviceworkers/test_match_all_client_properties.html b/dom/workers/test/serviceworkers/test_match_all_client_properties.html index 830c8ef6297..14e3445a4b7 100644 --- a/dom/workers/test/serviceworkers/test_match_all_client_properties.html +++ b/dom/workers/test/serviceworkers/test_match_all_client_properties.html @@ -25,6 +25,8 @@ function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } diff --git a/dom/workers/test/serviceworkers/test_post_message.html b/dom/workers/test/serviceworkers/test_post_message.html index 2a1bf99c33f..7df4bef1fcc 100644 --- a/dom/workers/test/serviceworkers/test_post_message.html +++ b/dom/workers/test/serviceworkers/test_post_message.html @@ -25,6 +25,8 @@ function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } diff --git a/dom/workers/test/serviceworkers/test_post_message_advanced.html b/dom/workers/test/serviceworkers/test_post_message_advanced.html index 7d4c9ba2774..ca769586159 100644 --- a/dom/workers/test/serviceworkers/test_post_message_advanced.html +++ b/dom/workers/test/serviceworkers/test_post_message_advanced.html @@ -55,6 +55,8 @@ function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } diff --git a/dom/workers/test/serviceworkers/test_post_message_source.html b/dom/workers/test/serviceworkers/test_post_message_source.html index 3cf6c45abc2..4353e59b498 100644 --- a/dom/workers/test/serviceworkers/test_post_message_source.html +++ b/dom/workers/test/serviceworkers/test_post_message_source.html @@ -25,6 +25,8 @@ function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.html b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.html index ff0ecb68568..3ba95a4f4b4 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.html +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.html @@ -19,6 +19,9 @@ registration.unregister().then(function(success) { ok(success, "The service worker should be unregistered successfully"); + SimpleTest.finish(); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); SimpleTest.finish(); }); } else if (event.data.type == 'status') { diff --git a/dom/workers/test/serviceworkers/test_serviceworker_not_sharedworker.html b/dom/workers/test/serviceworkers/test_serviceworker_not_sharedworker.html index e76613dace6..96dd9f15992 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_not_sharedworker.html +++ b/dom/workers/test/serviceworkers/test_serviceworker_not_sharedworker.html @@ -41,6 +41,9 @@ registration.unregister().then(function(success) { ok(success, "unregister should succeed"); SimpleTest.finish(); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); + SimpleTest.finish(); }); }; worker.port.postMessage({msg: "whoareyou"}); From 0068905cda8d8556a91ada48096c1af8453fc9ef Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 20 Apr 2015 11:17:06 -0400 Subject: [PATCH 75/80] Bug 1156432 - Part 1: Unregister the service worker when we are done with it; r=nsm This lets us for example use the --run-until-failure mochitest option. --- dom/workers/test/serviceworkers/test_fetch_event.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dom/workers/test/serviceworkers/test_fetch_event.html b/dom/workers/test/serviceworkers/test_fetch_event.html index 354d5677c70..764be87b131 100644 --- a/dom/workers/test/serviceworkers/test_fetch_event.html +++ b/dom/workers/test/serviceworkers/test_fetch_event.html @@ -16,15 +16,25 @@