From be9968f4d62b30102d4694c903b0316f2bde1abf Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Fri, 20 Jan 2017 12:53:41 -0800 Subject: [PATCH 01/67] Bug 1331444 - Keep iterators alive in Ion in for-of loops for IteratorClose due to exceptions. (r=jandem) --- js/src/jit-test/tests/for-of/bug-1331444.js | 7 +++++++ js/src/jit/IonBuilder.cpp | 22 +++++++++++++++------ js/src/jit/IonBuilder.h | 2 +- 3 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 js/src/jit-test/tests/for-of/bug-1331444.js diff --git a/js/src/jit-test/tests/for-of/bug-1331444.js b/js/src/jit-test/tests/for-of/bug-1331444.js new file mode 100644 index 000000000000..9770c584bc97 --- /dev/null +++ b/js/src/jit-test/tests/for-of/bug-1331444.js @@ -0,0 +1,7 @@ +// |jit-test| error: ReferenceError + +symbols = [Symbol]; +for (comparator of[, ]) + for (a of symbols) + for (;;) + expect; diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 5c2d6f830392..6b909adee707 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -866,11 +866,16 @@ IonBuilder::processIterators() // Find phis that must directly hold an iterator live. Vector worklist; for (size_t i = 0; i < iterators_.length(); i++) { - MInstruction* ins = iterators_[i]; - for (MUseDefIterator iter(ins); iter; iter++) { - if (iter.def()->isPhi()) { - if (!worklist.append(iter.def()->toPhi())) - return abort(AbortReason::Alloc); + MDefinition* def = iterators_[i]; + if (def->isPhi()) { + if (!worklist.append(def->toPhi())) + return abort(AbortReason::Alloc); + } else { + for (MUseDefIterator iter(def); iter; iter++) { + if (iter.def()->isPhi()) { + if (!worklist.append(iter.def()->toPhi())) + return abort(AbortReason::Alloc); + } } } } @@ -1999,7 +2004,12 @@ IonBuilder::inspectOpcode(JSOp op) case JSOP_CALLITER: case JSOP_NEW: case JSOP_SUPERCALL: - return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL); + MOZ_TRY(jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL)); + if (op == JSOP_CALLITER) { + if (!outermostBuilder()->iterators_.append(current->peek(-1))) + return abort(AbortReason::Alloc); + } + return Ok(); case JSOP_EVAL: case JSOP_STRICTEVAL: diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 4a84c4efd13c..39e7cb552cbc 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -1036,7 +1036,7 @@ class IonBuilder {} }; - Vector iterators_; + Vector iterators_; Vector loopHeaders_; Vector loopHeaderStack_; #ifdef DEBUG From 6f6c2650826cee6c1f83fecb55eb4f9294fa15d6 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Fri, 20 Jan 2017 12:53:41 -0800 Subject: [PATCH 02/67] Bug 1332155 - Skip non-try-related trynotes when asserting jump targets. (r=arai) --- js/src/jsscript.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 0d47328450e5..97f100f16d99 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2800,9 +2800,10 @@ JSScript::assertValidJumpTargets() const for (; tn < tnlimit; tn++) { jsbytecode* tryStart = mainEntry + tn->start; jsbytecode* tryPc = tryStart - 1; - if (JSOp(*tryPc) != JSOP_TRY) + if (tn->kind != JSTRY_CATCH && tn->kind != JSTRY_FINALLY) continue; + MOZ_ASSERT(JSOp(*tryPc) == JSOP_TRY); jsbytecode* tryTarget = tryStart + tn->length; MOZ_ASSERT(mainEntry <= tryTarget && tryTarget < end); MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*tryTarget))); From ba92b03b05b3c03847fb36590d235f5439663999 Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Wed, 27 Jul 2016 07:47:56 -0600 Subject: [PATCH 03/67] Bug 1287720 - Enable dom/browser-element mochitest-chrome tests on Android; r=me --- dom/browser-element/mochitest/chrome.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/browser-element/mochitest/chrome.ini b/dom/browser-element/mochitest/chrome.ini index 2745eb654bc7..acfc08a0d23c 100644 --- a/dom/browser-element/mochitest/chrome.ini +++ b/dom/browser-element/mochitest/chrome.ini @@ -1,5 +1,5 @@ [DEFAULT] -skip-if = e10s || toolkit == 'android' # Bug 1287720: takes too long on android +skip-if = e10s support-files = audio.ogg From 1eb20054a85c581f163ddb83fe0f51bfe9a73baa Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Fri, 20 Jan 2017 16:37:35 -0500 Subject: [PATCH 04/67] Bug 1332648 - remove bogus string radix/case #defines; r=erahm Nothing uses these defines, so we should remove them lest anybody get confused. I would have also removed kAutoDetect (who would want to do this?!), but kAutoDetect is used in one place in the tree, and I didn't want to hold up the deletion of these two items with trying to fix that one place. --- xpcom/string/nsString.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/xpcom/string/nsString.h b/xpcom/string/nsString.h index 580e4113d306..cfec6b9f13f7 100644 --- a/xpcom/string/nsString.h +++ b/xpcom/string/nsString.h @@ -25,8 +25,6 @@ #define kRadix10 (10) #define kRadix16 (16) #define kAutoDetect (100) -#define kRadixUnknown (kAutoDetect+1) -#define IGNORE_CASE (true) #endif From 28f29930efb702020d1640499a801a1ae14d1a5f Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Fri, 20 Jan 2017 16:38:12 -0500 Subject: [PATCH 05/67] Bug 1324894 - use standard Monitor APIs rather than PR_Interrupt in BackgroundHangMonitor; r=darchons Using PR_Interrupt here makes life difficult for other things, such as moving away from NSPR synchronization primitives. --- xpcom/threads/BackgroundHangMonitor.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/xpcom/threads/BackgroundHangMonitor.cpp b/xpcom/threads/BackgroundHangMonitor.cpp index cc16973752fa..dd270adb92d3 100644 --- a/xpcom/threads/BackgroundHangMonitor.cpp +++ b/xpcom/threads/BackgroundHangMonitor.cpp @@ -95,13 +95,11 @@ public: autoLock.Notify(); } + // Attempt to wakeup the hang monitor thread. void Wakeup() { - // PR_CreateThread could have failed earlier - if (mHangMonitorThread) { - // Use PR_Interrupt to avoid potentially taking a lock - PR_Interrupt(mHangMonitorThread); - } + mLock.AssertCurrentThreadOwns(); + mLock.NotifyAll(); } BackgroundHangManager(); @@ -275,8 +273,6 @@ BackgroundHangManager::RunMonitorThread() PRIntervalTime recheckTimeout = PR_INTERVAL_NO_WAIT; while (!mShutdown) { - - PR_ClearInterrupt(); nsresult rv = autoLock.Wait(waitTime); PRIntervalTime newTime = PR_IntervalNow(); @@ -291,9 +287,9 @@ BackgroundHangManager::RunMonitorThread() mIntervalNow += systemInterval; } - /* If it's before the next recheck timeout, and our wait did not - get interrupted (either through Notify or PR_Interrupt), we can - keep the current waitTime and skip iterating through hang monitors. */ + /* If it's before the next recheck timeout, and our wait did not get + interrupted, we can keep the current waitTime and skip iterating + through hang monitors. */ if (MOZ_LIKELY(systemInterval < recheckTimeout && systemInterval >= waitTime && rv == NS_OK)) { From 9951d0cd88138d7bc879868bd059783fbaf40a06 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 20 Jan 2017 18:29:26 +0100 Subject: [PATCH 06/67] Bug 1332584 - Append last frame on EOS in VideoTrackEncoder. r=jesup MozReview-Commit-ID: LARhY0LAEtG --HG-- extra : rebase_source : 9f08a9a7fab52f14a8f140711fb9355d8039cd79 extra : source : 72bcbe049bcbca33e613508f5a63e691c0110ee4 --- dom/media/encoder/TrackEncoder.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/dom/media/encoder/TrackEncoder.cpp b/dom/media/encoder/TrackEncoder.cpp index 79e4ed85067a..505d2400c251 100644 --- a/dom/media/encoder/TrackEncoder.cpp +++ b/dom/media/encoder/TrackEncoder.cpp @@ -277,6 +277,11 @@ VideoTrackEncoder::AppendVideoSegment(const VideoSegment& aSegment) { ReentrantMonitorAutoEnter mon(mReentrantMonitor); + if (mEndOfStream) { + MOZ_ASSERT(false); + return NS_OK; + } + // Append all video segments from MediaStreamGraph, including null an // non-null frames. VideoSegment::ConstChunkIterator iter(aSegment); @@ -330,6 +335,9 @@ VideoTrackEncoder::AppendVideoSegment(const VideoSegment& aSegment) // to the encoder to make sure there is some output. chunk.mTimeStamp = mLastChunk.mTimeStamp + TimeDuration::FromSeconds(1); + // chunk's duration has already been accounted for. + chunk.mDuration = 0; + if (chunk.IsNull()) { // Ensure that we don't pass null to the encoder by making mLastChunk // null later on. @@ -353,14 +361,16 @@ VideoTrackEncoder::AppendVideoSegment(const VideoSegment& aSegment) TRACK_LOG(LogLevel::Verbose, ("[VideoTrackEncoder]: Appending video frame %p, duration=%.5f", lastImage.get(), diff.ToSeconds())); - mRawSegment.AppendFrame(lastImage.forget(), - RateConvertTicksRoundUp( - mTrackRate, PR_USEC_PER_SEC, - diff.ToMicroseconds()), - mLastChunk.mFrame.GetIntrinsicSize(), - PRINCIPAL_HANDLE_NONE, - mLastChunk.mFrame.GetForceBlack(), - mLastChunk.mTimeStamp); + CheckedInt64 duration = UsecsToFrames(diff.ToMicroseconds(), mTrackRate); + MOZ_ASSERT(duration.isValid()); + if (duration.isValid()) { + mRawSegment.AppendFrame(lastImage.forget(), + duration.value(), + mLastChunk.mFrame.GetIntrinsicSize(), + PRINCIPAL_HANDLE_NONE, + mLastChunk.mFrame.GetForceBlack(), + mLastChunk.mTimeStamp); + } } mLastChunk = chunk; From 5f2b360d48a0bdf5a8e7cd0af589794245306c05 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 20 Jan 2017 18:59:46 +0100 Subject: [PATCH 07/67] Bug 1332584 - Use time conversion utils from VideoUtils. r=jesup MozReview-Commit-ID: 7AVeGp5akfx --HG-- extra : rebase_source : 5c514995c65ffcc0d7b23298260a5ca322d9d356 extra : source : ea6b4f40dcbeaec6f81f26ec95483f844a37b2ca --- dom/media/encoder/TrackEncoder.cpp | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/dom/media/encoder/TrackEncoder.cpp b/dom/media/encoder/TrackEncoder.cpp index 505d2400c251..241fd7d33c06 100644 --- a/dom/media/encoder/TrackEncoder.cpp +++ b/dom/media/encoder/TrackEncoder.cpp @@ -307,9 +307,12 @@ VideoTrackEncoder::AppendVideoSegment(const VideoSegment& aSegment) nullDuration)); // Adapt to the time before the first frame. This extends the first frame // from [start, end] to [0, end], but it'll do for now. - mLastChunk.mTimeStamp -= - TimeDuration::FromMicroseconds( - RateConvertTicksRoundUp(PR_USEC_PER_SEC, mTrackRate, nullDuration)); + CheckedInt64 diff = FramesToUsecs(nullDuration, mTrackRate); + MOZ_ASSERT(diff.isValid()); + if (diff.isValid()) { + mLastChunk.mTimeStamp -= TimeDuration::FromMicroseconds(diff.value()); + mLastChunk.mDuration += nullDuration; + } } MOZ_ASSERT(!mLastChunk.IsNull()); @@ -394,7 +397,28 @@ VideoTrackEncoder::NotifyEndOfStream() } ReentrantMonitorAutoEnter mon(mReentrantMonitor); + + if (mEndOfStream) { + // We have already been notified. + return; + } + mEndOfStream = true; + TRACK_LOG(LogLevel::Info, ("[VideoTrackEncoder]: Reached end of stream")); + + if (!mLastChunk.IsNull() && mLastChunk.mDuration > 0) { + RefPtr lastImage = mLastChunk.mFrame.GetImage(); + TRACK_LOG(LogLevel::Debug, + ("[VideoTrackEncoder]: Appending last video frame %p, " + "duration=%.5f", lastImage.get(), + FramesToTimeUnit(mLastChunk.mDuration, mTrackRate).ToSeconds())); + mRawSegment.AppendFrame(lastImage.forget(), + mLastChunk.mDuration, + mLastChunk.mFrame.GetIntrinsicSize(), + PRINCIPAL_HANDLE_NONE, + mLastChunk.mFrame.GetForceBlack(), + mLastChunk.mTimeStamp); + } mReentrantMonitor.NotifyAll(); } From 152163deeb7ef9ca9c1b683e1efa6468ed81d047 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 20 Jan 2017 11:48:59 +0100 Subject: [PATCH 08/67] Bug 1332585 - Make VP8TrackEncoderTest's buffer generator more explicit. r=jesup MozReview-Commit-ID: DZbF6vRMug6 --HG-- extra : rebase_source : 508ed10df6594101d068b6363f1258d6b4d8692b extra : source : 41debe52a3e32820eb33a18ad86e794a3efdc6c6 --- dom/media/gtest/TestVideoTrackEncoder.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/dom/media/gtest/TestVideoTrackEncoder.cpp b/dom/media/gtest/TestVideoTrackEncoder.cpp index a5882066f45a..73c39bfeb86c 100644 --- a/dom/media/gtest/TestVideoTrackEncoder.cpp +++ b/dom/media/gtest/TestVideoTrackEncoder.cpp @@ -46,11 +46,19 @@ public: return mImageSize; } - void Generate(nsTArray > &aImages) + already_AddRefed GenerateI420Image() { - aImages.AppendElement(CreateI420Image()); - aImages.AppendElement(CreateNV12Image()); - aImages.AppendElement(CreateNV21Image()); + return do_AddRef(CreateI420Image()); + } + + already_AddRefed GenerateNV12Image() + { + return do_AddRef(CreateNV12Image()); + } + + already_AddRefed GenerateNV21Image() + { + return do_AddRef(CreateNV21Image()); } private: @@ -260,7 +268,9 @@ TEST(VP8VideoTrackEncoder, FrameEncode) nsTArray> images; YUVBufferGenerator generator; generator.Init(mozilla::gfx::IntSize(640, 480)); - generator.Generate(images); + images.AppendElement(generator.GenerateI420Image()); + images.AppendElement(generator.GenerateNV12Image()); + images.AppendElement(generator.GenerateNV21Image()); // Put generated YUV frame into video segment. // Duration of each frame is 1 second. From 50321cf6067e930129acd426e73fc2c9621345b5 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 20 Jan 2017 12:24:36 +0100 Subject: [PATCH 09/67] Bug 1332585 - Add gtest for encoding a single frame. r=jesup MozReview-Commit-ID: DAEG4hO34G6 --HG-- extra : rebase_source : 7655cd44597ea01e3702cfb6e30128570a555475 extra : source : d3480dc22e30c6a0aa28a9122b9289bf50703985 --- dom/media/gtest/TestVideoTrackEncoder.cpp | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/dom/media/gtest/TestVideoTrackEncoder.cpp b/dom/media/gtest/TestVideoTrackEncoder.cpp index 73c39bfeb86c..04fc890d44cb 100644 --- a/dom/media/gtest/TestVideoTrackEncoder.cpp +++ b/dom/media/gtest/TestVideoTrackEncoder.cpp @@ -295,6 +295,46 @@ TEST(VP8VideoTrackEncoder, FrameEncode) EXPECT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container))); } +// Test that encoding a single frame gives useful output. +TEST(VP8VideoTrackEncoder, SingleFrameEncode) +{ + // Initiate VP8 encoder + TestVP8TrackEncoder encoder; + InitParam param = {true, 640, 480}; + encoder.TestInit(param); + + // Pass a half-second frame to the encoder. + YUVBufferGenerator generator; + generator.Init(mozilla::gfx::IntSize(640, 480)); + VideoSegment segment; + segment.AppendFrame(generator.GenerateI420Image(), + mozilla::StreamTime(45000), // 1/2 second + generator.GetSize(), + PRINCIPAL_HANDLE_NONE); + + encoder.SetCurrentFrames(segment); + + // End the track. + segment.Clear(); + encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, TrackEventCommand::TRACK_EVENT_ENDED, segment); + + EncodedFrameContainer container; + ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container))); + + EXPECT_TRUE(encoder.IsEncodingComplete()); + + // Read out encoded data, and verify. + const nsTArray>& frames = container.GetEncodedFrames(); + const size_t oneElement = 1; + ASSERT_EQ(oneElement, frames.Length()); + + EXPECT_EQ(EncodedFrame::VP8_I_FRAME, frames[0]->GetFrameType()) << + "We only have one frame, so it should be a keyframe"; + + const uint64_t halfSecond = PR_USEC_PER_SEC / 2; + EXPECT_EQ(halfSecond, frames[0]->GetDuration()); +} + // EOS test TEST(VP8VideoTrackEncoder, EncodeComplete) { From 192e6bf31bcab6decd21aa4885127f179c04e89a Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 20 Jan 2017 11:50:07 +0100 Subject: [PATCH 10/67] Bug 1332585 - Fix first frame duration being counted twice. r=jesup MozReview-Commit-ID: HdHs1rpVUJK --HG-- extra : rebase_source : eb44c91e3a80f0210d461adebe2c623799422bf9 extra : source : b4b284c0bce5f2eb6844eef78f1f7d445057b84b --- dom/media/encoder/TrackEncoder.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dom/media/encoder/TrackEncoder.cpp b/dom/media/encoder/TrackEncoder.cpp index 241fd7d33c06..1417c40c0f30 100644 --- a/dom/media/encoder/TrackEncoder.cpp +++ b/dom/media/encoder/TrackEncoder.cpp @@ -301,6 +301,7 @@ VideoTrackEncoder::AppendVideoSegment(const VideoSegment& aSegment) MOZ_ASSERT(!chunk.mTimeStamp.IsNull()); const StreamTime nullDuration = mLastChunk.mDuration; mLastChunk = chunk; + chunk.mDuration = 0; TRACK_LOG(LogLevel::Verbose, ("[VideoTrackEncoder]: Got first video chunk after %lld ticks.", From 9197ca6ccc20e7e5557b5d3042c656f3c63a1357 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 20 Jan 2017 12:25:48 +0100 Subject: [PATCH 11/67] Bug 1332585 - Check that encoder completed after EOS in existing test. r=jesup MozReview-Commit-ID: FFLyGhggDyM --HG-- extra : rebase_source : 0ef19f642b65dbfc502a116449de78c5fde67a9f extra : source : 3b4820bc1fc83dba9f621cb0ba0bafe09c2f303f --- dom/media/gtest/TestVideoTrackEncoder.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dom/media/gtest/TestVideoTrackEncoder.cpp b/dom/media/gtest/TestVideoTrackEncoder.cpp index 04fc890d44cb..416da7a90292 100644 --- a/dom/media/gtest/TestVideoTrackEncoder.cpp +++ b/dom/media/gtest/TestVideoTrackEncoder.cpp @@ -352,4 +352,6 @@ TEST(VP8VideoTrackEncoder, EncodeComplete) // NS_OK immidiately. EncodedFrameContainer container; EXPECT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container))); + + EXPECT_TRUE(encoder.IsEncodingComplete()); } From c42cf251e0e9c6249bbdf329cc522cd6e5728683 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 20 Jan 2017 12:26:56 +0100 Subject: [PATCH 12/67] Bug 1332585 - Add gtest for passing multiple instances of one frame to the vp8 encoder. r=jesup MozReview-Commit-ID: ellNhSDWGh --HG-- extra : rebase_source : e224edbec125e39e7175fffb3d8ff933fdf48a02 extra : source : e369214fb173e8325c352075dd10466a9f90b03f --- dom/media/gtest/TestVideoTrackEncoder.cpp | 43 +++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/dom/media/gtest/TestVideoTrackEncoder.cpp b/dom/media/gtest/TestVideoTrackEncoder.cpp index 416da7a90292..fcb5cf637f26 100644 --- a/dom/media/gtest/TestVideoTrackEncoder.cpp +++ b/dom/media/gtest/TestVideoTrackEncoder.cpp @@ -335,6 +335,49 @@ TEST(VP8VideoTrackEncoder, SingleFrameEncode) EXPECT_EQ(halfSecond, frames[0]->GetDuration()); } +// Test that encoding a couple of identical images gives useful output. +TEST(VP8VideoTrackEncoder, SameFrameEncode) +{ + // Initiate VP8 encoder + TestVP8TrackEncoder encoder; + InitParam param = {true, 640, 480}; + encoder.TestInit(param); + + // Pass 15 100ms frames to the encoder. + YUVBufferGenerator generator; + generator.Init(mozilla::gfx::IntSize(640, 480)); + RefPtr image = generator.GenerateI420Image(); + TimeStamp now = TimeStamp::Now(); + VideoSegment segment; + for (uint32_t i = 0; i < 15; ++i) { + segment.AppendFrame(do_AddRef(image), + mozilla::StreamTime(9000), // 100ms + generator.GetSize(), + PRINCIPAL_HANDLE_NONE, + false, + now + TimeDuration::FromSeconds(i * 0.1)); + } + + encoder.SetCurrentFrames(segment); + + // End the track. + segment.Clear(); + encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, TrackEventCommand::TRACK_EVENT_ENDED, segment); + + EncodedFrameContainer container; + ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container))); + + EXPECT_TRUE(encoder.IsEncodingComplete()); + + // Verify total duration being 1.5s. + uint64_t totalDuration = 0; + for (auto& frame : container.GetEncodedFrames()) { + totalDuration += frame->GetDuration(); + } + const uint64_t oneAndAHalf = (PR_USEC_PER_SEC / 2) * 3; + EXPECT_EQ(oneAndAHalf, totalDuration); +} + // EOS test TEST(VP8VideoTrackEncoder, EncodeComplete) { From 2bca25c1dadb2af0378ee6868555323e4cfe06a2 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 20 Jan 2017 12:27:32 +0100 Subject: [PATCH 13/67] Bug 1332585 - Add gtest for starting a track with null frames. r=jesup MozReview-Commit-ID: FxJUFNZ3TDn --HG-- extra : rebase_source : caf2c39e07d8e1664e419ef83971f7b1a5eee73b extra : source : 42db20a8898443376c0e0aeea62befa23eb52e93 --- dom/media/gtest/TestVideoTrackEncoder.cpp | 51 +++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/dom/media/gtest/TestVideoTrackEncoder.cpp b/dom/media/gtest/TestVideoTrackEncoder.cpp index fcb5cf637f26..e61863e8cb53 100644 --- a/dom/media/gtest/TestVideoTrackEncoder.cpp +++ b/dom/media/gtest/TestVideoTrackEncoder.cpp @@ -378,6 +378,57 @@ TEST(VP8VideoTrackEncoder, SameFrameEncode) EXPECT_EQ(oneAndAHalf, totalDuration); } +// Test encoding a track that starts with null data +TEST(VP8VideoTrackEncoder, NullFrameFirst) +{ + // Initiate VP8 encoder + TestVP8TrackEncoder encoder; + InitParam param = {true, 640, 480}; + encoder.TestInit(param); + YUVBufferGenerator generator; + generator.Init(mozilla::gfx::IntSize(640, 480)); + RefPtr image = generator.GenerateI420Image(); + TimeStamp now = TimeStamp::Now(); + VideoSegment segment; + + // Pass 2 100ms null frames to the encoder. + for (uint32_t i = 0; i < 2; ++i) { + segment.AppendFrame(nullptr, + mozilla::StreamTime(9000), // 100ms + generator.GetSize(), + PRINCIPAL_HANDLE_NONE, + false, + now + TimeDuration::FromSeconds(i * 0.1)); + } + + // Pass a real 100ms frame to the encoder. + segment.AppendFrame(image.forget(), + mozilla::StreamTime(9000), // 100ms + generator.GetSize(), + PRINCIPAL_HANDLE_NONE, + false, + now + TimeDuration::FromSeconds(0.3)); + + encoder.SetCurrentFrames(segment); + + // End the track. + segment.Clear(); + encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, TrackEventCommand::TRACK_EVENT_ENDED, segment); + + EncodedFrameContainer container; + ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container))); + + EXPECT_TRUE(encoder.IsEncodingComplete()); + + // Verify total duration being 0.3s. + uint64_t totalDuration = 0; + for (auto& frame : container.GetEncodedFrames()) { + totalDuration += frame->GetDuration(); + } + const uint64_t pointThree = (PR_USEC_PER_SEC / 10) * 3; + EXPECT_EQ(pointThree, totalDuration); +} + // EOS test TEST(VP8VideoTrackEncoder, EncodeComplete) { From 94d46cd57d9113f17906f568d03c736b2c32fa29 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 20 Jan 2017 17:00:02 +0100 Subject: [PATCH 14/67] Bug 1332585 - Protect TrackEncoder members from races. r=jesup mCanceled is one member which is protected only in a couple of places. I hit a MOZ_CRASH without this in a gtest, but I'm not sure if we haven't seen it in release by chance or by design. MozReview-Commit-ID: 61KpjaBDyhB --HG-- extra : rebase_source : 4ab032ee2963cd7e94d19b8428e6405ffa59332e extra : source : 06b2f8307ad0c96197e75d2e147e660d8085afc7 --- dom/media/encoder/TrackEncoder.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/dom/media/encoder/TrackEncoder.cpp b/dom/media/encoder/TrackEncoder.cpp index 1417c40c0f30..189163609edd 100644 --- a/dom/media/encoder/TrackEncoder.cpp +++ b/dom/media/encoder/TrackEncoder.cpp @@ -57,6 +57,8 @@ AudioTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, uint32_t aTrackEvents, const MediaSegment& aQueuedMedia) { + ReentrantMonitorAutoEnter mon(mReentrantMonitor); + if (mCanceled) { return; } @@ -109,13 +111,14 @@ AudioTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, void AudioTrackEncoder::NotifyEndOfStream() { + ReentrantMonitorAutoEnter mon(mReentrantMonitor); + // If source audio track is completely silent till the end of encoding, // initialize the encoder with default channel counts and sampling rate. if (!mCanceled && !mInitialized) { Init(DEFAULT_CHANNELS, DEFAULT_SAMPLING_RATE); } - ReentrantMonitorAutoEnter mon(mReentrantMonitor); mEndOfStream = true; mReentrantMonitor.NotifyAll(); } @@ -195,6 +198,8 @@ AudioTrackEncoder::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) cons void VideoTrackEncoder::Init(const VideoSegment& aSegment) { + ReentrantMonitorAutoEnter mon(mReentrantMonitor); + if (mInitialized) { return; } @@ -227,12 +232,13 @@ VideoTrackEncoder::Init(const VideoSegment& aSegment) NotifyEndOfStream(); return; } - } void VideoTrackEncoder::SetCurrentFrames(const VideoSegment& aSegment) { + ReentrantMonitorAutoEnter mon(mReentrantMonitor); + if (mCanceled) { return; } @@ -248,6 +254,8 @@ VideoTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, uint32_t aTrackEvents, const MediaSegment& aQueuedMedia) { + ReentrantMonitorAutoEnter mon(mReentrantMonitor); + if (mCanceled) { return; } @@ -390,6 +398,8 @@ VideoTrackEncoder::AppendVideoSegment(const VideoSegment& aSegment) void VideoTrackEncoder::NotifyEndOfStream() { + ReentrantMonitorAutoEnter mon(mReentrantMonitor); + // If source video track is muted till the end of encoding, initialize the // encoder with default frame width, frame height, and track rate. if (!mCanceled && !mInitialized) { @@ -397,8 +407,6 @@ VideoTrackEncoder::NotifyEndOfStream() DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT); } - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - if (mEndOfStream) { // We have already been notified. return; From c6a18105227adeb2398b78d09a5ca2a6a4ecda71 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Wed, 18 Jan 2017 15:01:47 +0100 Subject: [PATCH 15/67] Bug 1332598 - Make per-frame logs in VP8TrackEncoder verbose. r=jesup MozReview-Commit-ID: HzpUlWjnAEW --HG-- extra : rebase_source : 1b261b4c160f65cc0262460f0654d635e1aae78c extra : source : 3c7a9fca1a5703e3ca6349a5da625ec87c2755c5 --- dom/media/encoder/VP8TrackEncoder.cpp | 51 +++++++++++++++------------ 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/dom/media/encoder/VP8TrackEncoder.cpp b/dom/media/encoder/VP8TrackEncoder.cpp index 5313132134ae..5078de6658a2 100644 --- a/dom/media/encoder/VP8TrackEncoder.cpp +++ b/dom/media/encoder/VP8TrackEncoder.cpp @@ -19,9 +19,9 @@ namespace mozilla { LazyLogModule gVP8TrackEncoderLog("VP8TrackEncoder"); -#define VP8LOG(msg, ...) MOZ_LOG(gVP8TrackEncoderLog, mozilla::LogLevel::Debug, \ - (msg, ##__VA_ARGS__)) -// Debug logging macro with object pointer and class name. +#define VP8LOG(level, msg, ...) MOZ_LOG(gVP8TrackEncoderLog, \ + level, \ + (msg, ##__VA_ARGS__)) #define DEFAULT_BITRATE_BPS 2500000 @@ -229,9 +229,10 @@ VP8TrackEncoder::GetEncodedPartitions(EncodedFrameContainer& aData) videoData->SetDuration((uint64_t)duration.value()); } videoData->SwapInFrameData(frameData); - VP8LOG("GetEncodedPartitions TimeStamp %lld Duration %lld\n", - videoData->GetTimeStamp(), videoData->GetDuration()); - VP8LOG("frameType %d\n", videoData->GetFrameType()); + VP8LOG(LogLevel::Verbose, + "GetEncodedPartitions TimeStamp %lld, Duration %lld, FrameType %d", + videoData->GetTimeStamp(), videoData->GetDuration(), + videoData->GetFrameType()); aData.AppendEncodedFrame(videoData); } @@ -277,7 +278,8 @@ nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk) } if (img->GetSize() != IntSize(mFrameWidth, mFrameHeight)) { - VP8LOG("Dynamic resolution changes (was %dx%d, now %dx%d) are unsupported\n", + VP8LOG(LogLevel::Error, + "Dynamic resolution changes (was %dx%d, now %dx%d) are unsupported", mFrameWidth, mFrameHeight, img->GetSize().width, img->GetSize().height); return NS_ERROR_FAILURE; } @@ -370,29 +372,29 @@ nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk) mFrameWidth, mFrameHeight); yuvFormat = "I422"; } else { - VP8LOG("Unsupported planar format\n"); + VP8LOG(LogLevel::Error, "Unsupported planar format"); NS_ASSERTION(false, "Unsupported planar format"); return NS_ERROR_NOT_IMPLEMENTED; } if (rv != 0) { - VP8LOG("Converting an %s frame to I420 failed\n", yuvFormat.c_str()); + VP8LOG(LogLevel::Error, "Converting an %s frame to I420 failed", yuvFormat.c_str()); return NS_ERROR_FAILURE; } - VP8LOG("Converted an %s frame to I420\n", yuvFormat.c_str()); + VP8LOG(LogLevel::Verbose, "Converted an %s frame to I420", yuvFormat.c_str()); } else { // Not YCbCr at all. Try to get access to the raw data and convert. RefPtr surf = GetSourceSurface(img.forget()); if (!surf) { - VP8LOG("Getting surface from %s image failed\n", Stringify(format).c_str()); + VP8LOG(LogLevel::Error, "Getting surface from %s image failed", Stringify(format).c_str()); return NS_ERROR_FAILURE; } RefPtr data = surf->GetDataSurface(); if (!data) { - VP8LOG("Getting data surface from %s image with %s (%s) surface failed\n", + VP8LOG(LogLevel::Error, "Getting data surface from %s image with %s (%s) surface failed", Stringify(format).c_str(), Stringify(surf->GetType()).c_str(), Stringify(surf->GetFormat()).c_str()); return NS_ERROR_FAILURE; @@ -400,7 +402,7 @@ nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk) DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ); if (!map.IsMapped()) { - VP8LOG("Reading DataSourceSurface from %s image with %s (%s) surface failed\n", + VP8LOG(LogLevel::Error, "Reading DataSourceSurface from %s image with %s (%s) surface failed", Stringify(format).c_str(), Stringify(surf->GetType()).c_str(), Stringify(surf->GetFormat()).c_str()); return NS_ERROR_FAILURE; @@ -426,20 +428,20 @@ nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk) mFrameWidth, mFrameHeight); break; default: - VP8LOG("Unsupported SourceSurface format %s\n", + VP8LOG(LogLevel::Error, "Unsupported SourceSurface format %s", Stringify(surf->GetFormat()).c_str()); NS_ASSERTION(false, "Unsupported SourceSurface format"); return NS_ERROR_NOT_IMPLEMENTED; } if (rv != 0) { - VP8LOG("%s to I420 conversion failed\n", + VP8LOG(LogLevel::Error, "%s to I420 conversion failed", Stringify(surf->GetFormat()).c_str()); return NS_ERROR_FAILURE; } - VP8LOG("Converted a %s frame to I420\n", - Stringify(surf->GetFormat()).c_str()); + VP8LOG(LogLevel::Verbose, "Converted a %s frame to I420", + Stringify(surf->GetFormat()).c_str()); } mVPXImageWrapper->planes[VPX_PLANE_Y] = y; @@ -527,8 +529,8 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData) for (VideoSegment::ChunkIterator iter(mSourceSegment); !iter.IsEnded(); iter.Next()) { VideoChunk &chunk = *iter; - VP8LOG("nextEncodeOperation is %d for frame of duration %lld\n", - nextEncodeOperation, chunk.GetDuration()); + VP8LOG(LogLevel::Verbose, "nextEncodeOperation is %d for frame of duration %lld", + nextEncodeOperation, chunk.GetDuration()); // Encode frame. if (nextEncodeOperation != SKIP_FRAME) { @@ -536,8 +538,11 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData) NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); // Encode the data with VP8 encoder - int flags = (nextEncodeOperation == ENCODE_NORMAL_FRAME) ? - 0 : VPX_EFLAG_FORCE_KF; + int flags = 0; + if (nextEncodeOperation == ENCODE_I_FRAME) { + VP8LOG(LogLevel::Warning, "MediaRecorder lagging behind. Encoding keyframe."); + flags |= VPX_EFLAG_FORCE_KF; + } if (vpx_codec_encode(mVPXContext, mVPXImageWrapper, mEncodedTimestamp, (unsigned long)chunk.GetDuration(), flags, VPX_DL_REALTIME)) { @@ -549,7 +554,7 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData) // SKIP_FRAME // Extend the duration of the last encoded data in aData // because this frame will be skip. - NS_WARNING("MediaRecorder lagging behind. Skipping a frame."); + VP8LOG(LogLevel::Warning, "MediaRecorder lagging behind. Skipping a frame."); RefPtr last = aData.GetEncodedFrames().LastElement(); if (last) { last->SetDuration(last->GetDuration() + chunk.GetDuration()); @@ -571,7 +576,7 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData) // End of stream, pull the rest frames in encoder. if (EOS) { - VP8LOG("mEndOfStream is true\n"); + VP8LOG(LogLevel::Debug, "mEndOfStream is true"); mEncodingComplete = true; // Bug 1243611, keep calling vpx_codec_encode and vpx_codec_get_cx_data // until vpx_codec_get_cx_data return null. From 12bae8d7f94abf78ac6af1cb118ac85f324d7401 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 20 Jan 2017 15:30:29 +0100 Subject: [PATCH 16/67] Bug 1332619 - Add gtest for skipped frames. r=jesup MozReview-Commit-ID: G5BkNVayJOV --HG-- extra : rebase_source : 522a754f70bff7525c5f9e8fdc4343360783c356 extra : source : f06f4ff1d49007e0d6a2506f87df3c365f3a2c5f --- dom/media/gtest/TestVideoTrackEncoder.cpp | 43 +++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/dom/media/gtest/TestVideoTrackEncoder.cpp b/dom/media/gtest/TestVideoTrackEncoder.cpp index e61863e8cb53..274a05cb5e68 100644 --- a/dom/media/gtest/TestVideoTrackEncoder.cpp +++ b/dom/media/gtest/TestVideoTrackEncoder.cpp @@ -429,6 +429,49 @@ TEST(VP8VideoTrackEncoder, NullFrameFirst) EXPECT_EQ(pointThree, totalDuration); } +// Test encoding a track that has to skip frames. +TEST(VP8VideoTrackEncoder, SkippedFrames) +{ + // Initiate VP8 encoder + TestVP8TrackEncoder encoder; + InitParam param = {true, 640, 480}; + encoder.TestInit(param); + YUVBufferGenerator generator; + generator.Init(mozilla::gfx::IntSize(640, 480)); + TimeStamp now = TimeStamp::Now(); + VideoSegment segment; + + // Pass 100 frames of the shortest possible duration where we don't get + // rounding errors between input/output rate. + for (uint32_t i = 0; i < 100; ++i) { + segment.AppendFrame(generator.GenerateI420Image(), + mozilla::StreamTime(9), // 0.1ms + generator.GetSize(), + PRINCIPAL_HANDLE_NONE, + false, + now + TimeDuration::FromMilliseconds(i * 0.1)); + } + + encoder.SetCurrentFrames(segment); + + // End the track. + segment.Clear(); + encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, TrackEventCommand::TRACK_EVENT_ENDED, segment); + + EncodedFrameContainer container; + ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container))); + + EXPECT_TRUE(encoder.IsEncodingComplete()); + + // Verify total duration being 100 * 0.1ms = 10ms. + uint64_t totalDuration = 0; + for (auto& frame : container.GetEncodedFrames()) { + totalDuration += frame->GetDuration(); + } + const uint64_t tenMillis = PR_USEC_PER_SEC / 100; + EXPECT_EQ(tenMillis, totalDuration); +} + // EOS test TEST(VP8VideoTrackEncoder, EncodeComplete) { From 151590b2b2c605528fa31aaa8a5c5845881ed65f Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 20 Jan 2017 15:47:04 +0100 Subject: [PATCH 17/67] Bug 1332619 - Fix missed duration when skipping a frame in VP8TrackEncoder. r=jesup MozReview-Commit-ID: GpXUHfUj5v2 --HG-- extra : rebase_source : 07871e9be0a8f67fe986f6caf63c336f65eec1fe extra : source : 146fbe89eafb1b57e33bc1e1eb675512c971d532 --- dom/media/encoder/VP8TrackEncoder.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dom/media/encoder/VP8TrackEncoder.cpp b/dom/media/encoder/VP8TrackEncoder.cpp index 5078de6658a2..4e4e95032766 100644 --- a/dom/media/encoder/VP8TrackEncoder.cpp +++ b/dom/media/encoder/VP8TrackEncoder.cpp @@ -553,11 +553,15 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData) } else { // SKIP_FRAME // Extend the duration of the last encoded data in aData - // because this frame will be skip. + // because this frame will be skipped. VP8LOG(LogLevel::Warning, "MediaRecorder lagging behind. Skipping a frame."); RefPtr last = aData.GetEncodedFrames().LastElement(); if (last) { - last->SetDuration(last->GetDuration() + chunk.GetDuration()); + CheckedInt64 skippedDuration = FramesToUsecs(chunk.mDuration, mTrackRate); + if (skippedDuration.isValid() && skippedDuration.value() > 0) { + last->SetDuration(last->GetDuration() + + (static_cast(skippedDuration.value()))); + } } } From ce691838f0894998625ae54db82b749950c51126 Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Wed, 11 Jan 2017 11:10:39 -0800 Subject: [PATCH 18/67] Bug 1321865 - Enable IntersectionObserver. r=smaug --HG-- extra : rebase_source : 9a72845f93fc4a11f0fda0b30b936dae2df303f6 extra : histedit_source : a153d18b9cfa85afd1d2e41e36995e4b1a9b8b75 --- modules/libpref/init/all.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 10e98013d703..2ca625dd41dc 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5553,4 +5553,4 @@ pref("prompts.authentication_dialog_abuse_limit", 3); // Enable the Storage management in about:preferences and persistent-storage permission request // To enable the DOM implementation, turn on "dom.storageManager.enabled" pref("browser.storageManager.enabled", false); -pref("dom.IntersectionObserver.enabled", false); +pref("dom.IntersectionObserver.enabled", true); From cc595edfbf0ac419bdc24afd2af7023c63c747fd Mon Sep 17 00:00:00 2001 From: Tobias Schneider Date: Wed, 11 Jan 2017 13:07:18 -0800 Subject: [PATCH 19/67] Bug 1321865 - Enable IntersectionObserver Tests. r=smaug --HG-- extra : rebase_source : 677470bff8e880d5b732fb6f43a2374243f3f0e6 extra : histedit_source : 4672008861ada5dcc4602b1910017517c6495046 --- dom/base/test/mochitest.ini | 2 +- dom/tests/mochitest/general/test_interfaces.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index c399d6fd5f74..834529cfaf87 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -656,7 +656,7 @@ skip-if = (toolkit == 'android') # Android: Bug 775227 [test_innersize_scrollport.html] [test_integer_attr_with_leading_zero.html] [test_intersectionobservers.html] -skip-if = true # Track Bug 1320704 +skip-if = (os == "android") # Timing issues [test_link_prefetch.html] skip-if = !e10s # Track Bug 1281415 [test_link_stylesheet.html] diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 5c15aa716bc4..c881f9bd5e20 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -621,9 +621,9 @@ var interfaceNamesInGlobalScope = // IMPORTANT: Do not change this list without review from a DOM peer! "InstallTrigger", // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "IntersectionObserver", disabled: true}, + "IntersectionObserver", // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "IntersectionObserverEntry", disabled: true}, + "IntersectionObserverEntry", // IMPORTANT: Do not change this list without review from a DOM peer! "KeyEvent", // IMPORTANT: Do not change this list without review from a DOM peer! From f6645c7c90b0a5a4df5f23e78413dc8a34ad62ae Mon Sep 17 00:00:00 2001 From: Emanuel Hoogeveen Date: Fri, 20 Jan 2017 08:05:00 -0500 Subject: [PATCH 20/67] Bug 1332594 - Check for poison and other corruption during realloc. r=jandem --- js/src/ds/PageProtectingVector.h | 51 +++++++++---------- .../x86-shared/AssemblerBuffer-x86-shared.h | 30 +---------- 2 files changed, 25 insertions(+), 56 deletions(-) diff --git a/js/src/ds/PageProtectingVector.h b/js/src/ds/PageProtectingVector.h index fdb6eb6ff879..04f5e7f0b94a 100644 --- a/js/src/ds/PageProtectingVector.h +++ b/js/src/ds/PageProtectingVector.h @@ -8,6 +8,7 @@ #define ds_PageProtectingVector_h #include "mozilla/Atomics.h" +#include "mozilla/PodOperations.h" #include "mozilla/Vector.h" #include "ds/MemoryProtectionExceptionHandler.h" @@ -539,10 +540,7 @@ PageProtectingVector::lockSlow() const class ProtectedReallocPolicy { - /* We hardcode the page size here to minimize administrative overhead. */ - static const size_t pageShift = 12; - static const size_t pageSize = 1 << pageShift; - static const size_t pageMask = pageSize - 1; + static const uint8_t PoisonPattern = 0xe5; public: template T* maybe_pod_malloc(size_t numElems) { @@ -553,35 +551,34 @@ class ProtectedReallocPolicy } template T* maybe_pod_realloc(T* oldAddr, size_t oldSize, size_t newSize) { MOZ_ASSERT_IF(oldAddr, oldSize); - MOZ_ASSERT(gc::SystemPageSize() == pageSize); if (MOZ_UNLIKELY(!newSize)) return nullptr; if (MOZ_UNLIKELY(!oldAddr)) return js_pod_malloc(newSize); - T* newAddr = nullptr; - size_t initPage = (uintptr_t(oldAddr - 1) >> pageShift) + 1; - size_t lastPage = (uintptr_t(oldAddr + oldSize) >> pageShift) - 1; - size_t toCopy = (newSize >= oldSize ? oldSize : newSize) * sizeof(T); - if (MOZ_UNLIKELY(oldSize >= 32 * 1024 && lastPage >= initPage)) { - T* protectAddr = reinterpret_cast(initPage << pageShift); - size_t protectSize = (lastPage - initPage + 1) << pageShift; - MemoryProtectionExceptionHandler::addRegion(protectAddr, protectSize); - gc::MakePagesReadOnly(protectAddr, protectSize); - newAddr = js_pod_malloc(newSize); - if (MOZ_LIKELY(newAddr)) - memcpy(newAddr, oldAddr, toCopy); - gc::UnprotectPages(protectAddr, protectSize); - MemoryProtectionExceptionHandler::removeRegion(protectAddr); - if (MOZ_LIKELY(newAddr)) - js_free(oldAddr); - } else { - newAddr = js_pod_malloc(newSize); - if (MOZ_LIKELY(newAddr)) { - memcpy(newAddr, oldAddr, toCopy); - js_free(oldAddr); - } + T* tmpAddr = js_pod_malloc(newSize); + if (MOZ_UNLIKELY(!tmpAddr)) + return js_pod_realloc(oldAddr, oldSize, newSize); + + size_t bytes = (newSize >= oldSize ? oldSize : newSize) * sizeof(T); + memcpy(tmpAddr, oldAddr, bytes); + + T* newAddr = js_pod_realloc(oldAddr, oldSize, newSize); + if (MOZ_UNLIKELY(!newAddr)) { + js_free(tmpAddr); + return js_pod_realloc(oldAddr, oldSize, newSize); } + + const uint8_t* newAddrBytes = reinterpret_cast(newAddr); + const uint8_t* tmpAddrBytes = reinterpret_cast(tmpAddr); + if (!mozilla::PodEqual(tmpAddrBytes, newAddrBytes, bytes)) { + if (oldAddr == newAddr) + MOZ_CRASH("New buffer doesn't match the old buffer (newAddr == oldAddr)!"); + else + MOZ_CRASH("New buffer doesn't match the old buffer (newAddr != oldAddr)!"); + } + + js_free(tmpAddr); return newAddr; } diff --git a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h index 492d02155b97..89928f6ff0a9 100644 --- a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h +++ b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h @@ -126,30 +126,6 @@ namespace jit { return m_oom; } -#ifndef RELEASE_OR_BETA - const unsigned char* acquireBuffer() const - { - MOZ_RELEASE_ASSERT(!m_oom); - return m_buffer.acquire(); - } - void releaseBuffer() const { m_buffer.release(); } - unsigned char* acquireData() { return m_buffer.acquire(); } - void releaseData() const { m_buffer.release(); } - void disableProtection() { m_buffer.disableProtection(); } - void enableProtection() { m_buffer.enableProtection(); } - void setLowerBoundForProtection(size_t size) - { - m_buffer.setLowerBoundForProtection(size); - } - void unprotectRegion(unsigned char* first, size_t size) - { - m_buffer.unprotectRegion(first, size); - } - void reprotectRegion(unsigned char* first, size_t size) - { - m_buffer.reprotectRegion(first, size); - } -#else const unsigned char* acquireBuffer() const { MOZ_RELEASE_ASSERT(!m_oom); @@ -163,7 +139,6 @@ namespace jit { void setLowerBoundForProtection(size_t) {} void unprotectRegion(unsigned char*, size_t) {} void reprotectRegion(unsigned char*, size_t) {} -#endif protected: /* @@ -186,10 +161,7 @@ namespace jit { } #ifndef RELEASE_OR_BETA - PageProtectingVector m_buffer; + mozilla::Vector m_buffer; #else mozilla::Vector m_buffer; #endif From 173553c4a82562fda82e00f2b1a715b6efa7788b Mon Sep 17 00:00:00 2001 From: Jason Laster Date: Thu, 19 Jan 2017 22:24:32 +0100 Subject: [PATCH 21/67] Bug 1331654 - Bump Debugger. r=jdescottes * Add update tools * Bump with the latest changes MozReview-Commit-ID: 65Ca3SbMQ2e --- devtools/client/debugger/new/debugger.css | 1044 +- devtools/client/debugger/new/debugger.js | 63483 +++++++--------- .../debugger/new/pretty-print-worker.js | 145 +- .../client/debugger/new/source-map-worker.js | 1407 +- .../test/mochitest/browser_dbg-breakpoints.js | 3 +- .../new/test/mochitest/browser_dbg-console.js | 10 +- .../new/test/mochitest/browser_dbg-scopes.js | 5 - .../new/test/mochitest/browser_dbg-sources.js | 2 + .../new/test/mochitest/examples/bundle.js | 96 - .../new/test/mochitest/examples/bundle.js.map | 1 - .../debugger/new/test/mochitest/head.js | 8 +- devtools/client/jar.mn | 1 + .../client/locales/en-US/debugger.properties | 151 +- devtools/client/package.json | 11 + devtools/client/preferences/devtools.js | 6 + .../sourceeditor/codemirror/mozilla.css | 72 +- .../sourceeditor/codemirror/old-debugger.css | 23 + devtools/client/sourceeditor/editor.js | 4 + devtools/client/update-tools.js | 104 + 19 files changed, 27469 insertions(+), 39107 deletions(-) delete mode 100644 devtools/client/debugger/new/test/mochitest/examples/bundle.js delete mode 100644 devtools/client/debugger/new/test/mochitest/examples/bundle.js.map create mode 100644 devtools/client/package.json create mode 100644 devtools/client/sourceeditor/codemirror/old-debugger.css create mode 100644 devtools/client/update-tools.js diff --git a/devtools/client/debugger/new/debugger.css b/devtools/client/debugger/new/debugger.css index 479bee363e04..6a08291a3134 100644 --- a/devtools/client/debugger/new/debugger.css +++ b/devtools/client/debugger/new/debugger.css @@ -20,7 +20,6 @@ body { height: 100%; } - ::-webkit-scrollbar { width: 8px; height: 8px; @@ -34,7 +33,7 @@ body { ::-webkit-scrollbar-thumb { border-radius: 8px; - background: rgba(113,113,113,0.5); + background: rgba(113, 113, 113, 0.5); } :root.theme-dark .CodeMirror-scrollbar-filler { @@ -43,89 +42,110 @@ body { .landing-page { flex: 1; display: flex; - width: 100%; - height: 100%; + width: 100vw; + height: 100vh; flex-direction: row; + align-items: stretch; + /* Customs properties */ + --title-font-size: 24px; + --ui-element-font-size: 16px; + --primary-line-height: 30px; + --secondary-line-height: 25px; + --base-spacing: 20px; + --base-transition: all 0.25s ease; } .landing-page .sidebar { display: flex; background-color: var(--theme-tab-toolbar-background); width: 200px; - height: 100%; flex-direction: column; + border-right: 1px solid var(--theme-splitter-color); } .landing-page .sidebar h1 { color: var(--theme-body-color); - font-size: 24px; + font-size: var(--title-font-size); margin: 0; - line-height: 30px; + line-height: var(--primary-line-height); font-weight: normal; - padding: 40px 20px; + padding: calc(2 * var(--base-spacing)) var(--base-spacing); } .landing-page .sidebar ul { list-style: none; padding: 0; - line-height: 30px; - font-size: 18px; + line-height: var(--primary-line-height); + font-size: var(--ui-element-font-size); } .landing-page .sidebar li { - padding: 5px 20px; -} - -.landing-page .sidebar li.selected { - background: var(--theme-search-overlays-semitransparent); - transition: all 0.25s ease; -} - -.landing-page .sidebar li:hover { - background: var(--theme-selection-background); - cursor: pointer; + padding: calc(var(--base-spacing) / 4) var(--base-spacing); } .landing-page .sidebar li a { color: var(--theme-body-color); } -.landing-page .sidebar li:hover a { +.landing-page .sidebar li.selected { + background: var(--theme-highlight-bluegrey); color: var(--theme-selection-color); + transition: var(--base-transition); +} + +.landing-page .sidebar li.selected a { + color: inherit; +} + +.landing-page .sidebar li:hover, +.landing-page .sidebar li:focus { + background: var(--theme-selection-background); + color: var(--theme-selection-color); + cursor: pointer; +} + +.landing-page .sidebar li:hover a, +.landing-page .sidebar li:focus a { + color: inherit; } .landing-page .panel { display: flex; flex: 1; - height: 100%; - overflow: auto; flex-direction: column; + justify-content: space-between; } -.landing-page .panel .title { - margin: 20px 40px; - width: calc(100% - 80px); - font-size: 16px; - border-bottom: 1px solid var(--theme-splitter-color); - height: 54px; -} - -.landing-page .panel h2 { - color: var(--theme-body-color); - font-weight: normal; -} - -.landing-page .panel .center { - flex: 1; +.landing-page .panel header { display: flex; - flex-direction: column; + align-items: baseline; + margin: calc(2 * var(--base-spacing)) 0 0; + padding-bottom: var(--base-spacing); } -.landing-page .panel .center .center-message { - margin: 40px; - font-size: 16px; - line-height: 25px; - padding: 10px; +.landing-page .panel header input { + flex: 1; + background-color: var(--theme-tab-toolbar-background); + color: var(--theme-comment); + font-size: var(--ui-element-font-size); + border: 1px solid var(--theme-splitter-color); + padding: calc(var(--base-spacing) / 2); + margin: 0 var(--base-spacing); + transition: var(--base-transition); +} + +.landing-page .panel header input::placeholder { + color: var(--theme-body-color-inactive); +} + +.landing-page .panel header input:focus { + border: 1px solid var(--theme-selection-background); +} + +.landing-page .panel .center-message { + font-size: var(--ui-element-font-size); + line-height: var(--secondary-line-height); + padding: calc(var(--base-spacing) / 2); } .landing-page .center a { @@ -134,43 +154,57 @@ body { } .landing-page .tab-group { - margin: 40px; + flex: 1; + overflow-y: auto; } .landing-page .tab-list { list-style: none; - padding: 0px; - margin: 0px; + padding: 0; + margin: 0; } .landing-page .tab { border-bottom: 1px solid var(--theme-splitter-color); - padding: 10px; + padding: calc(var(--base-spacing) / 2) var(--base-spacing); font-family: sans-serif; } -.landing-page .tab:hover { - background-color: var(--theme-toolbar-background); - cursor: pointer; -} - .landing-page .tab-title { - line-height: 25px; - font-size: 16px; + line-height: var(--secondary-line-height); + font-size: var(--ui-element-font-size); color: var(--theme-highlight-bluegrey); + word-break: break-all; } .landing-page .tab-url { color: var(--theme-comment); + word-break: break-all; } -.landing-page .panel .center .footer-note { - flex: 1; - padding: 50px; +.landing-page .tab:focus, +.landing-page .tab.active { + background: var(--theme-selection-background); + color: var(--theme-selection-color); + cursor: pointer; + transition: var(--base-transition); +} + +.landing-page .tab:focus .tab-title, +.landing-page .tab.active .tab-title { + color: inherit; +} + +.landing-page .tab:focus .tab-url, +.landing-page .tab.active .tab-url { + color: var(--theme-highlight-gray); +} + +.landing-page .panel .footer-note { + padding: var(--base-spacing) 0; + text-align: center; font-size: 14px; color: var(--theme-comment); - bottom: 0; - position: absolute; } /* vim:set ts=2 sw=2 sts=2 et: */ @@ -212,11 +246,12 @@ body { height: 100%; } -.center-pane { +.editor-pane { display: flex; position: relative; flex: 1; background-color: var(--theme-tab-toolbar-background); + height: calc(100% - 1px); overflow: hidden; } @@ -249,23 +284,6 @@ body { margin-top: 25px; margin-right: 20px; } - -.welcomebox { - width: calc(100% - 1px); - - /* Offsetting it by 30px for the sources-header area */ - height: calc(100% - 30px); - position: absolute; - top: 30px; - left: 0; - padding: 50px 0; - text-align: center; - font-size: 1.25em; - color: var(--theme-comment-alt); - background-color: var(--theme-tab-toolbar-background); - font-weight: lighter; - z-index: 100; -} menupopup { position: fixed; z-index: 10000; @@ -285,6 +303,8 @@ menuitem { line-height: 20px; font-weight: 500; font-size: 13px; + -moz-user-select: none; + user-select: none; } menuitem:hover { @@ -293,6 +313,15 @@ menuitem:hover { cursor: pointer; } +menuitem[disabled=true] { + color: #cccccc; +} + +menuitem[disabled=true]:hover { + background-color: transparent; + cursor: default; +} + menuseparator { border-bottom: 1px solid #cacdd3; width: 100%; @@ -607,107 +636,75 @@ menuseparator { border-bottom: 1px solid var(--theme-splitter-color); } -.autocomplete { - width: 100%; +.arrow, +.folder, +.domain, +.file, +.worker, +.refresh, +.add-button { + fill: var(--theme-splitter-color); } -.autocomplete .results * { - -moz-user-select: none; - user-select: none; +.worker, +.folder { + position: relative; + top: 2px; } -.autocomplete .results-summary { - margin: 10px; +.domain, +.file, +.worker, +.refresh, +.add-button { + position: relative; + top: 1px; } -.autocomplete ul { - list-style: none; - width: 100%; - max-height: calc(100% - 32px); - margin: 0px; - padding: 0px; - overflow: auto; +.domain svg, +.folder svg, +.worker svg, +.refresh svg, +.add-button svg { + width: 15px; } -.autocomplete li { - border: 2px solid var(--theme-splitter-color); - background-color: var(--theme-tab-toolbar-background); - padding: 10px; - margin: 10px; +.file svg { + width: 13px; } -.autocomplete li:hover { - background: var(--theme-tab-toolbar-background); - cursor: pointer; +.file svg, +.domain svg, +.folder svg, +.refresh svg, +.worker svg { + margin-inline-end: 5px; } -.autocomplete li.selected { - border: 2px solid var(--theme-selection-background); +.arrow svg { + fill: var(--theme-splitter-color); + margin-top: 3px; + transition: transform 0.25s ease; + width: 10px; } -.autocomplete li .title { - line-height: 1.5em; - word-break: break-all; +html:not([dir="rtl"]) .arrow svg { + margin-right: 5px; + transform: rotate(-90deg); } -.autocomplete li .subtitle { - line-height: 1.5em; - color: grey; - word-break: break-all; +html[dir="rtl"] .arrow svg { + margin-left: 5px; + transform: rotate(90deg); } -.autocomplete input { - width: 100%; - border: none; - background-color: var(--theme-body-background); - color: var(--theme-comment); - border-bottom: 1px solid var(--theme-splitter-color); - outline: none; - line-height: 30px; - font-size: 14px; - height: 40px; - padding-left: 30px; +/* TODO (Amit): html is just for specificity. keep it like this? */ +html .arrow.expanded svg { + transform: rotate(0deg); } -.autocomplete input::placeholder { - color: var(--theme-body-color-inactive); -} - -.autocomplete .magnifying-glass svg { - width: 16px; - position: absolute; - top: 12px; - left: 10px; -} - -.autocomplete.focused .magnifying-glass path, -.autocomplete.focused .magnifying-glass ellipse { - stroke: var(--theme-highlight-blue); -} - -.autocomplete .magnifying-glass path, -.autocomplete .magnifying-glass ellipse { - stroke: var(--theme-splitter-color); -} - -.autocomplete .no-result-msg { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - color: var(--theme-graphs-full-red); - font-size: 24px; -} - -.autocomplete .no-result-msg .sad-face { - width: 24px; - margin-right: 4px; - line-height: 0; -} - -.autocomplete .no-result-msg .sad-face svg { - fill: var(--theme-graphs-full-red); +.arrow.hidden { + visibility: hidden; } .close-btn path { fill: var(--theme-body-color); @@ -771,6 +768,113 @@ menuseparator { .close-btn-big .close:hover path { fill: white; } + +.autocomplete { + width: 100%; +} + +.autocomplete .results * { + -moz-user-select: none; + user-select: none; +} + +.autocomplete .results-summary { + margin: 10px; + text-align: start; +} + +.autocomplete ul { + list-style: none; + width: 100%; + max-height: calc(100% - 32px); + margin: 0px; + padding: 0px; + overflow: auto; +} + +.autocomplete li { + border: 2px solid var(--theme-splitter-color); + background-color: var(--theme-tab-toolbar-background); + padding: 10px; + margin: 10px; +} + +.autocomplete li:hover { + background: var(--theme-tab-toolbar-background); + cursor: pointer; +} + +.autocomplete li.selected { + border: 2px solid var(--theme-selection-background); +} + +.autocomplete li .title { + line-height: 1.5em; + word-break: break-all; +} + +.autocomplete li .subtitle { + line-height: 1.5em; + color: grey; + word-break: break-all; +} + +.autocomplete input { + width: 100%; + border: none; + background-color: var(--theme-body-background); + color: var(--theme-comment); + border-bottom: 1px solid var(--theme-splitter-color); + outline: none; + line-height: 30px; + font-size: 14px; + height: 40px; + padding-inline-start: 30px; +} + +.autocomplete input::placeholder { + color: var(--theme-body-color-inactive); +} + +.autocomplete .magnifying-glass svg { + width: 16px; + position: absolute; + top: 12px; + offset-inline-start: 10px; +} + +.autocomplete.focused .magnifying-glass path, +.autocomplete.focused .magnifying-glass ellipse { + stroke: var(--theme-highlight-blue); +} + +.autocomplete .magnifying-glass path, +.autocomplete .magnifying-glass ellipse { + stroke: var(--theme-splitter-color); +} + +.autocomplete .no-result-msg { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + color: var(--theme-graphs-full-red); + font-size: 24px; + padding: 4px; + word-break: break-all; +} + +.autocomplete .no-result-msg .sad-face { + width: 24px; + margin: 0 4px; + line-height: 0; + flex-shrink: 0; +} + +.autocomplete .no-result-msg .sad-face svg { + fill: var(--theme-graphs-full-red); +} .tree { -webkit-user-select: none; -moz-user-select: none; @@ -833,17 +937,13 @@ html[dir="rtl"] .tree .node > div { font-size: 1.2em; display: flex; align-items: baseline; - justify-content: space-between; -moz-user-select: none; user-select: none; + justify-content: flex-end; } -html:not([dir="rtl"]) .sources-header { - padding-left: 10px; -} - -html[dir="rtl"] .sources-header { - padding-right: 10px; +.sources-header { + padding-inline-start: 10px; } .sources-header-info { @@ -851,16 +951,8 @@ html[dir="rtl"] .sources-header { color: var(--theme-comment-alt); font-weight: lighter; white-space: nowrap; -} - -html:not([dir="rtl"]) .sources-header-info { - padding-right: 10px; - float: right; -} - -html[dir="rtl"] .sources-header-info { - padding-left: 10px; - float: left; + padding-inline-end: 10px; + cursor: pointer; } .sources-list { @@ -869,51 +961,6 @@ html[dir="rtl"] .sources-header-info { overflow: hidden; } -.arrow, -.folder, -.domain, -.file, -.worker { - fill: var(--theme-splitter-color); -} - -.domain, -.file, -.worker { - position: relative; - top: 1px; -} - -.worker, -.folder { - position: relative; - top: 2px; -} - -.domain svg, -.folder svg, -.worker svg { - width: 15px; -} - -.file svg { - width: 13px; -} - -html:not([dir="rtl"]) .file svg, -html:not([dir="rtl"]) .domain svg, -html:not([dir="rtl"]) .folder svg, -html:not([dir="rtl"]) .worker svg { - margin-right: 5px; -} - -html[dir="rtl"] .file svg, -html[dir="rtl"] .domain svg, -html[dir="rtl"] .folder svg, -html[dir="rtl"] .worker svg { - margin-left: 5px; -} - .tree { -webkit-user-select: none; -moz-user-select: none; @@ -936,7 +983,7 @@ html[dir="rtl"] .worker svg { cursor: pointer; } -.tree .node:hover { +.tree-node:hover { background: var(--theme-tab-toolbar-background); } @@ -956,6 +1003,46 @@ html[dir="rtl"] .worker svg { .sources-list .tree-node button { position: fixed; } +.toggle-button-start, +.toggle-button-end { + position: absolute; + width: 16px; + height: 16px; + transition: transform 0.25s ease-in-out; + margin: 0 4px; +} + +.toggle-button-start svg, +.toggle-button-end svg { + fill: var(--theme-comment); +} + +.toggle-button-end svg { + transform: rotate(180deg); +} + +.toggle-button-start.vertical svg { + transform: rotate(-90deg); +} + +.toggle-button-end.vertical svg { + transform: rotate(90deg); +} + +.toggle-button-start { + top: 7px; + left: 0; +} + +.toggle-button-end { + top: 7px; + right: 0; +} + +.toggle-button-start.collapsed, +.toggle-button-end.collapsed { + transform: rotate(180deg); +} .source-footer { background: var(--theme-body-background); @@ -970,64 +1057,73 @@ html[dir="rtl"] .worker svg { user-select: none; } -html:not([dir="rtl"]) .source-footer .command-bar { - float: right; +.source-footer .commands { + display: flex; + padding: 8px 0.7em; } -html[dir="rtl"] .source-footer .command-bar { - float: left; -} - -.source-footer .command-bar * { +.source-footer .commands * { -moz-user-select: none; user-select: none; } -.command-bar > span { +.source-footer > .commands > .action { cursor: pointer; - width: 1em; - height: 1.1em; - display: inline-block; - text-align: center; + display: flex; + justify-content: center; + align-items: center; transition: opacity 200ms; + border: none; + background: transparent; } -html:not([dir="rtl"]) .command-bar > span { - margin-right: 0.7em; +:root.theme-dark .source-footer > .commands > .action { + fill: var(--theme-body-color); } -html[dir="rtl"] .command-bar > span { - margin-left: 0.7em; +:root.theme-dark .source-footer > .commands > .action:hover { + fill: var(--theme-selection-color); } -.source-footer .prettyPrint.pretty { - stroke: var(--theme-highlight-blue); +.source-footer > .commands > .action svg { + height: 1em; + width: 1em; } -.source-footer input:focus { - border-color: var(--theme-highlight-blue); +.source-footer .commands .coverage { + border: none; outline: none; + background: transparent; + color: var(--theme-content-color3); + font-weight: 600; + padding: 1px; + width: 16px; + height: 16px; } -.source-footer input { - line-height: 16px; - margin: 7px; +.source-footer .commands .coverage:hover { + border: 1px solid var(--theme-body-color-inactive); + border-radius: 2px; + padding: 0px; + cursor: pointer; +} + +.coverage-on .source-footer .commands .coverage { + color: var(--theme-highlight-blue); + border: 1px solid var(--theme-body-color-inactive); border-radius: 2px; - border: 1px solid var(--theme-splitter-color); - padding-left: 4px; - font-size: 10px; } .search-bar { width: calc(100% - 1px); height: 40px; - background: white; + background-color: var(--theme-body-background); border-bottom: 1px solid var(--theme-splitter-color); display: flex; } .search-bar i { display: block; - padding: 13px 0 0 13px; + padding: 13px; width: 40px; } @@ -1047,7 +1143,6 @@ html[dir="rtl"] .command-bar > span { .search-bar .magnifying-glass { background-color: var(--theme-body-background); - width: 40px; } .search-bar .magnifying-glass path, @@ -1100,6 +1195,15 @@ html[dir="rtl"] .editor-mount { left: 0; } +.editor.hit-marker { + height: 14px; +} + +.coverage-on .CodeMirror-code :not(.hit-marker) .CodeMirror-line, +.coverage-on .CodeMirror-code :not(.hit-marker) .CodeMirror-gutter-wrapper { + opacity: 0.5; +} + .editor.new-breakpoint svg { fill: var(--theme-selection-background); width: 60px; @@ -1212,6 +1316,22 @@ html[dir="rtl"] .editor-mount { .conditional-breakpoint-panel input:focus { outline-width: 0; } + +.why-paused { + background-color: var(--breakpoint-active-color); + border: 1.7px solid var(--breakpoint-active-color); + color: var(--theme-highlight-blue); + padding: 10px 10px 10px 20px; + white-space: normal; + opacity: 0.9; + font-size: 12px; + text-align: center; + font-weight: bold; +} + +.theme-dark .secondary-panes .why-paused { + color: white; +} .breakpoints-list * { -moz-user-select: none; user-select: none; @@ -1223,15 +1343,30 @@ html[dir="rtl"] .editor-mount { padding: 0.5em 1px; line-height: 1em; position: relative; - border-left: 4px solid transparent; transition: all 0.25s ease; } +html[dir="rtl"] .breakpoints-list .breakpoint { + border-right: 4px solid transparent; +} + +html:not([dir="rtl"]) .breakpoints-list .breakpoint { + border-left: 4px solid transparent; +} + .breakpoints-list .breakpoint:last-of-type { padding-bottom: 0.45em; } -.breakpoints-list .breakpoint.paused { +html:not([dir="rtl"]) .breakpoints-list .breakpoint.is-conditional { + border-left-color: var(--theme-graphs-yellow); +} + +html[dir="rtl"] .breakpoints-list .breakpoint.is-conditional { + border-right-color: var(--theme-graphs-yellow); +} + +html .breakpoints-list .breakpoint.paused { background-color: var(--theme-toolbar-background-alt); border-color: var(--breakpoint-active-color); } @@ -1251,12 +1386,12 @@ html[dir="rtl"] .editor-mount { } .breakpoints-list .breakpoint-checkbox { - margin-left: 0; + margin-inline-start: 0; } .breakpoints-list .breakpoint-label { display: inline-block; - padding-left: 2px; + padding-inline-start: 2px; padding-bottom: 4px; } @@ -1265,14 +1400,23 @@ html[dir="rtl"] .editor-mount { order: 3; } -.breakpoint-snippet { +:root.theme-light .breakpoint-snippet, +:root.theme-firebug .breakpoint-snippet { color: var(--theme-comment); - padding-left: 18px; +} + +:root.theme-dark .breakpoint-snippet { + color: var(--theme-body-color); + opacity: 0.6; +} + +.breakpoint-snippet { + padding-inline-start: 18px; } .breakpoint .close-btn { position: absolute; - right: 6px; + offset-inline-end: 6px; top: 12px; } @@ -1285,31 +1429,56 @@ html[dir="rtl"] .editor-mount { } .input-expression { width: 100%; - padding: 5px; + padding: 8px 10px; margin: 0px; - border: none; - cursor: hand; + border: 1px; + cursor: pointer; + color: var(--theme-body-color); + background-color: var(--theme-body-background); + line-height: 12px; +} + +.input-expression::-webkit-input-placeholder { + text-align: center; + font-style: italic; +} + +.input-expression:focus { + outline-color: var(--theme-selection-background-semitransparent); + outline-width: 2px; + cursor: text; } .expression-container { border: 1px; - padding: 5px 2px 5px 5px; - margin: 1px; + padding: 8px 5px 0px 10px; width: 100%; - color: var(--theme-body-color) !important; + color: var(--theme-body-color); + background-color: var(--theme-body-background); + display: flex; +} + +.expression-container .tree { + overflow: hidden; +} + +:root.theme-light .expression-container:hover { background-color: var(--theme-tab-toolbar-background); } -.expression-container:hover { - background-color: var(--theme-selection-background); - color: var(--theme-body-background) !important; +:root.theme-dark .expression-container:hover { + background-color: var(--theme-search-overlays-semitransparent); } -.expression-output-container .close-btn { - width: 6px; - height: 6px; - float: right; - margin-right: 6px; +.expression-container .close-btn { + display: none; +} + +.expression-container:hover .close-btn { + width: 8px; + height: 8px; + margin-left: auto; + margin-right: 8px; display: block; cursor: pointer; } @@ -1319,6 +1488,10 @@ html[dir="rtl"] .editor-mount { max-width: 50%; } +.expression-separator { + padding: 0px 5px; +} + .expression-value { overflow-x: scroll; color: var(--theme-content-color2); @@ -1328,30 +1501,9 @@ html[dir="rtl"] .editor-mount { .expression-error { color: var(--theme-highlight-red); } -.arrow svg { - fill: var(--theme-splitter-color); - margin-top: 3px; - transition: transform 0.25s ease; - width: 10px; -} -html:not([dir="rtl"]) .arrow svg { - margin-right: 5px; - transform: rotate(-90deg); -} - -html[dir="rtl"] .arrow svg { - margin-left: 5px; - transform: rotate(90deg); -} - -/* TODO (Amit): html is just for specificity. keep it like this? */ -html .arrow.expanded svg { - transform: rotate(0deg); -} - -.arrow.hidden { - visibility: hidden; +.object-node.not-enumerable { + opacity: 0.6; } .object-label { @@ -1385,8 +1537,9 @@ html .arrow.expanded svg { .frames ul li { cursor: pointer; padding: 7px 10px 7px 21px; - clear: both; overflow: hidden; + display: flex; + justify-content: space-between; } /* Style the focused call frame like so: @@ -1405,13 +1558,20 @@ html .arrow.expanded svg { } .frames .location { - float: right; - color: var(--theme-comment); font-weight: lighter; } +:root.theme-light .frames .location, +:root.theme-firebug .frames .location { + color: var(--theme-comment); +} + +:root.theme-dark .frames .location { + color: var(--theme-body-color); + opacity: 0.6; +} + .frames .title { - float: left; text-overflow: ellipsis; overflow: hidden; margin-right: 1em; @@ -1434,6 +1594,52 @@ html .arrow.expanded svg { .show-more:hover { background-color: var(--theme-search-overlays-semitransparent); } +.event-listeners { + list-style: none; + margin: 0; + padding: 0; +} + +.event-listeners .listener { + cursor: pointer; + padding: 7px 10px 7px 21px; + clear: both; + overflow: hidden; +} + +.event-listeners .listener * { + -moz-user-select: none; + user-select: none; +} + +.event-listeners .listener:nth-of-type(2n) { + background-color: var(--theme-tab-toolbar-background); +} + +.event-listeners .listener .type { + color: var(--theme-highlight-bluegrey); + padding-right: 5px; +} + +.event-listeners .listener .selector { + color: var(--theme-content-color2); +} + +.event-listeners .listener-checkbox { + margin-left: 0; +} + +.event-listeners .listener .close-btn { + float: right; +} + +.event-listeners .listener .close { + display: none; +} + +.event-listeners .listener:hover .close { + display: block; +} .accordion { background-color: var(--theme-body-background); width: 100%; @@ -1455,49 +1661,53 @@ html .arrow.expanded svg { user-select: none; } +.accordion ._header { + display: flex; +} + .accordion ._header:hover { background-color: var(--theme-search-overlays-semitransparent); } -.accordion ._header:hover svg { - fill: var(--theme-comment-alt); +.accordion ._header button svg, +.accordion ._header:hover button svg { + fill: currentColor; } .accordion ._content { border-bottom: 1px solid var(--theme-splitter-color); font-size: 12px; } -.right-sidebar { + +.accordion ._header .header-buttons { display: flex; - flex-direction: column; - flex: 1; - white-space: nowrap; + margin-left: auto; + padding-right: 5px; } -.right-siderbar * { - -moz-user-select: none; - user-select: none; +.accordion .header-buttons .add-button { + font-size: 180%; + text-align: center; + line-height: 16px; } -.right-sidebar .accordion { - overflow-y: auto; - overflow-x: hidden; +.accordion .header-buttons button { + color: var(--theme-body-color); + border: none; + background: none; + outline: 0; + padding: 0; + width: 16px; + height: 16px; } -.right-sidebar .command-bar { - border-bottom: 1px solid var(--theme-splitter-color); +.accordion .header-buttons button::-moz-focus-inner { + border: none; } - .command-bar { height: 30px; -} - -html:not([dir="rtl"]) .command-bar { - padding: 8px 5px 10px 1px; -} - -html[dir="rtl"] .command-bar { - padding: 8px 1px 10px 5px; + padding: 8px 5px; + border-bottom: 1px solid var(--theme-splitter-color); } .command-bar > span { @@ -1517,12 +1727,8 @@ html[dir="rtl"] .command-bar { fill: var(--theme-selection-color); } -html:not([dir="rtl"]) .command-bar > span { - margin-right: 0.7em; -} - -html[dir="rtl"] .command-bar > span { - margin-left: 0.7em; +.command-bar > span { + margin-inline-end: 0.7em; } .command-bar > span.disabled { @@ -1530,18 +1736,42 @@ html[dir="rtl"] .command-bar > span { cursor: default; } -html:not([dir="rtl"]) .command-bar .stepOut { - margin-right: 2em; -} - -html[dir="rtl"] .command-bar .stepOut { - margin-left: 2em; +.command-bar .stepOut { + margin-inline-end: 2em; } .command-bar .subSettings { float: right; } +.command-bar .toggleBreakpoints.breakpoints-disabled path { + fill: var(--theme-highlight-blue); +} + +.command-bar span.pause-exceptions.uncaught { + fill: var(--theme-highlight-purple); +} + +.command-bar span.pause-exceptions.all { + fill: var(--theme-highlight-blue); +} +.secondary-panes { + display: flex; + flex-direction: column; + flex: 1; + white-space: nowrap; +} + +.secondary-panes * { + -moz-user-select: none; + user-select: none; +} + +.secondary-panes .accordion { + overflow-y: auto; + overflow-x: hidden; +} + .pane { color: var(--theme-body-color); } @@ -1553,22 +1783,36 @@ html[dir="rtl"] .command-bar .stepOut { -moz-user-select: none; user-select: none; } +.welcomebox { + width: calc(100% - 1px); -.toggleBreakpoints.breakpoints-disabled path { - stroke: var(--theme-highlight-blue); + /* Offsetting it by 30px for the sources-header area */ + height: calc(100% - 30px); + position: absolute; + top: 30px; + left: 0; + padding: 50px 0 0 0; + text-align: center; + font-size: 1.25em; + color: var(--theme-comment-alt); + background-color: var(--theme-tab-toolbar-background); + font-weight: lighter; + z-index: 100; } -span.pause-exceptions.uncaught { - stroke: var(--theme-highlight-purple); -} - -span.pause-exceptions.all { - stroke: var(--theme-highlight-blue); +.welcomebox .toggle-button-end { + bottom: 11px; + position: absolute; + top: auto; } .source-header { border-bottom: 1px solid var(--theme-splitter-color); height: 30px; + display: flex; flex: 1; + flex-flow: row wrap; + -webkit-align-items: stretch; + align-items: stretch; } .source-header * { @@ -1577,63 +1821,59 @@ span.pause-exceptions.all { } .source-tabs { - min-width: 50px; - max-width: calc(100% - 60px); - overflow: hidden; + max-width: calc(100% - 80px); float: left; + margin-inline-start: 21px; } .source-header .new-tab-btn { - width: 16px; + width: 14px; + height: 14px; display: inline-block; position: relative; - top: 4px; + top: 5px; margin: 4px; + margin-inline-start: 8px; line-height: 0; -} - -.source-header .new-tab-btn path { - fill: var(--theme-splitter-color); -} - -.source-header .new-tab-btn:hover path { + cursor: pointer; fill: var(--theme-comment); + transition: 0.1s ease; } .source-tab { - background-color: var(--theme-toolbar-background-alt); color: var(--theme-faded-tab-color); - border: 1px solid var(--theme-splitter-color); + border: 1px solid transparent; border-top-left-radius: 2px; border-top-right-radius: 2px; - height: 23px; + height: 24px; line-height: 20px; display: inline-block; - border-bottom: none; position: relative; transition: all 0.25s ease; min-width: 40px; overflow: hidden; } -html:not([dir="rtl"]) .source-tab { - padding: 2px 20px 2px 12px; - margin: 6px 0 0 8px; -} - -html[dir="rtl"] .source-tab { - padding: 2px 12px 2px 20px; - margin: 6px 8px 0 0; +.source-tab { + padding-top: 2px; + padding-bottom: 2px; + padding-inline-start: 12px; + padding-inline-end: 20px; + margin-top: 6px; + margin-inline-start: 8px; } .source-tab:hover { - background: var(--theme-toolbar-background); + background-color: var(--theme-toolbar-background-alt); + border-color: var(--theme-splitter-color); cursor: pointer; } .source-tab.active { color: var(--theme-body-color); background-color: var(--theme-body-background); + border-color: var(--theme-splitter-color); + border-bottom-color: transparent; } .source-tab path { @@ -1644,6 +1884,22 @@ html[dir="rtl"] .source-tab { fill: var(--theme-body-color); } +.source-tab .prettyPrint { + display: block; + position: absolute; + top: 3px; + left: 6px; +} + +.source-tab .prettyPrint svg { + height: 1em; + width: 1em; +} + +.source-tab .prettyPrint path { + fill: var(--theme-textbox-box-shadow); +} + .source-tab .close-btn { position: absolute; top: 3px; @@ -1654,12 +1910,12 @@ html[dir="rtl"] .source-tab { overflow: hidden; } -html:not([dir="rtl"]) .source-tab .close-btn { - right: 4px; +.source-tab.pretty .filename { + padding-left: 12px; } -html[dir="rtl"] .source-tab .close-btn { - left: 4px; +.source-tab .close-btn { + offset-inline-end: 4px; } .source-tab .close { @@ -1669,6 +1925,40 @@ html[dir="rtl"] .source-tab .close-btn { .source-tab:hover .close { display: block; } + +.toggle-button-start, +.toggle-button-end { + position: absolute; + width: 16px; + height: 16px; + margin: 0 4px; + cursor: pointer; +} + +.toggle-button-start svg, +.toggle-button-end svg { + fill: var(--theme-comment); +} + +.toggle-button-end svg { + transform: rotate(180deg); +} + +.toggle-button-start { + top: 8px; + left: 0; +} + +.toggle-button-end { + top: 8px; + right: 0; +} + +.toggle-button-start.collapsed, +.toggle-button-end.collapsed { + transform: rotate(180deg); + flex: 1; +} .dropdown { background: var(--theme-body-background); border: 1px solid var(--theme-splitter-color); @@ -1683,11 +1973,13 @@ html[dir="rtl"] .source-tab .close-btn { .dropdown-button { position: absolute; - right: 12px; - top: 5px; - font-size: 16px; + right: 18px; + top: 4px; + font-size: 18px; color: var(--theme-body-color); cursor: pointer; + background: none; + border: none; } .dropdown li { @@ -1721,4 +2013,4 @@ html[dir="rtl"] .source-tab .close-btn { top: 0; } -/*# sourceMappingURL=styles.css.map*/ \ No newline at end of file +/*# sourceMappingURL=debugger.css.map*/ \ No newline at end of file diff --git a/devtools/client/debugger/new/debugger.js b/devtools/client/debugger/new/debugger.js index c2553aa4715f..156394ca28db 100644 --- a/devtools/client/debugger/new/debugger.js +++ b/devtools/client/debugger/new/debugger.js @@ -1,5 +1,3 @@ -// Generated from: 8175aacaec380ecf859183ad62bee2a9aef180d2 Disable searching test because it's timing out on try on certain platforms for some reason - var Debugger = /******/ (function(modules) { // webpackBootstrap /******/ // The module cache @@ -7,6 +5,30 @@ var Debugger = /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { +/******/ // SingleModulePlugin +/******/ const smpCache = this.smpCache = this.smpCache || {}; +/******/ const smpMap = this.smpMap = this.smpMap || new Map(); +/******/ function sanitizeString(text) { +/******/ return text.replace(/__webpack_require__\(\d+\)/g,""); +/******/ } +/******/ function getModuleBody(id) { +/******/ if (smpCache.hasOwnProperty(id)) { +/******/ return smpCache[id]; +/******/ } +/******/ +/******/ const body = sanitizeString(String(modules[id])); +/******/ smpCache[id] = body; +/******/ return body; +/******/ } +/******/ if (!installedModules[moduleId]) { +/******/ const body = getModuleBody(moduleId); +/******/ if (smpMap.has(body)) { +/******/ installedModules[moduleId] = installedModules[smpMap.get(body)]; +/******/ } +/******/ else { +/******/ smpMap.set(body, moduleId) +/******/ } +/******/ } /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) @@ -37,7 +59,7 @@ var Debugger = /******/ __webpack_require__.c = installedModules; /******/ /******/ // __webpack_public_path__ -/******/ __webpack_require__.p = "/public/build"; +/******/ __webpack_require__.p = "/assets/build"; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(0); @@ -55,87 +77,98 @@ var Debugger = /***/ function(module, exports, __webpack_require__) { var React = __webpack_require__(2); - - var _require = __webpack_require__(3); - - var bindActionCreators = _require.bindActionCreators; - var combineReducers = _require.combineReducers; - - var ReactDOM = __webpack_require__(16); - - var _require2 = __webpack_require__(18); - - var _require2$client = _require2.client; - var getClient = _require2$client.getClient; - var firefox = _require2$client.firefox; - var renderRoot = _require2.renderRoot; - var bootstrap = _require2.bootstrap; - - var _require3 = __webpack_require__(89); - - var getValue = _require3.getValue; - var isFirefoxPanel = _require3.isFirefoxPanel; - - - var configureStore = __webpack_require__(238); - - var reducers = __webpack_require__(249); - var selectors = __webpack_require__(259); - - var App = __webpack_require__(260); - + + var _require = __webpack_require__(3), + bindActionCreators = _require.bindActionCreators, + combineReducers = _require.combineReducers; + + var ReactDOM = __webpack_require__(22); + + var _require2 = __webpack_require__(23), + getClient = _require2.getClient, + firefox = _require2.firefox; + + var _require3 = __webpack_require__(178), + renderRoot = _require3.renderRoot, + bootstrap = _require3.bootstrap, + L10N = _require3.L10N; + + var _require4 = __webpack_require__(65), + getValue = _require4.getValue, + isFirefoxPanel = _require4.isFirefoxPanel; + + var configureStore = __webpack_require__(227); + + var _require5 = __webpack_require__(237), + onConnect = _require5.onConnect, + onFirefoxConnect = _require5.onFirefoxConnect; + + var reducers = __webpack_require__(238); + var selectors = __webpack_require__(253); + + var App = __webpack_require__(254); + var createStore = configureStore({ log: getValue("logging.actions"), makeThunkArgs: (args, state) => { return Object.assign({}, args, { client: getClient(state) }); } }); - + var store = createStore(combineReducers(reducers)); - var actions = bindActionCreators(__webpack_require__(262), store.dispatch); - + var actions = bindActionCreators(__webpack_require__(255), store.dispatch); + if (!isFirefoxPanel()) { - L10N.setBundle(__webpack_require__(458)); + window.L10N = L10N; + window.L10N.setBundle(__webpack_require__(500)); } - + window.appStore = store; - + // Expose the bound actions so external things can do things like // selecting a source. window.actions = { selectSource: actions.selectSource, selectSourceURL: actions.selectSourceURL }; - + + // Globals needed for mocha integration tests + window.getGlobalsForTesting = () => { + return { + debuggerStore: store, + launchpadStore: window.launchpadStore, + selectors, + actions + }; + }; + function unmountRoot() { - var mount = document.querySelector("#mount"); + var mount = document.querySelector("#mount div"); ReactDOM.unmountComponentAtNode(mount); } - + if (isFirefoxPanel()) { (function () { - var sourceMap = __webpack_require__(264); - var prettyPrint = __webpack_require__(276); - + var sourceMap = __webpack_require__(257); + var prettyPrint = __webpack_require__(268); + module.exports = { bootstrap: (_ref) => { - var threadClient = _ref.threadClient; - var tabTarget = _ref.tabTarget; - var toolbox = _ref.toolbox; - var L10N = _ref.L10N; - - // TODO (jlast) remove when the panel has L10N - if (L10N) { + var threadClient = _ref.threadClient, + tabTarget = _ref.tabTarget, + toolbox = _ref.toolbox; + + // jlast: remove when docker updates + if (!window.L10N) { window.L10N = L10N; - } else { - window.L10N = __webpack_require__(459); - window.L10N.setBundle(__webpack_require__(458)); + window.L10N.setBundle(__webpack_require__(500)); } - + firefox.setThreadClient(threadClient); firefox.setTabTarget(tabTarget); renderRoot(React, ReactDOM, App, store); - return firefox.initPage(actions); + firefox.initPage(actions); + return onFirefoxConnect(actions, firefox); }, destroy: () => { unmountRoot(); @@ -149,7 +182,7 @@ var Debugger = }; })(); } else { - bootstrap(React, ReactDOM, App, actions, store); + bootstrap(React, ReactDOM, App, actions, store).then(conn => onConnect(conn, actions)); } /***/ }, @@ -163,46 +196,46 @@ var Debugger = /***/ function(module, exports, __webpack_require__) { 'use strict'; - + exports.__esModule = true; exports.compose = exports.applyMiddleware = exports.bindActionCreators = exports.combineReducers = exports.createStore = undefined; - + var _createStore = __webpack_require__(4); - + var _createStore2 = _interopRequireDefault(_createStore); - - var _combineReducers = __webpack_require__(11); - + + var _combineReducers = __webpack_require__(17); + var _combineReducers2 = _interopRequireDefault(_combineReducers); - - var _bindActionCreators = __webpack_require__(13); - + + var _bindActionCreators = __webpack_require__(19); + var _bindActionCreators2 = _interopRequireDefault(_bindActionCreators); - - var _applyMiddleware = __webpack_require__(14); - + + var _applyMiddleware = __webpack_require__(20); + var _applyMiddleware2 = _interopRequireDefault(_applyMiddleware); - - var _compose = __webpack_require__(15); - + + var _compose = __webpack_require__(21); + var _compose2 = _interopRequireDefault(_compose); - - var _warning = __webpack_require__(12); - + + var _warning = __webpack_require__(18); + var _warning2 = _interopRequireDefault(_warning); - + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - + /* * This is a dummy function to check if the function name has been altered by minification. * If the function has been minified and NODE_ENV !== 'production', warn the user. */ function isCrushed() {} - + if (false) { (0, _warning2["default"])('You are currently using minified code outside of NODE_ENV === \'production\'. ' + 'This means that you are running a slower development build of Redux. ' + 'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' + 'or DefinePlugin for webpack (http://stackoverflow.com/questions/30030031) ' + 'to ensure you have the correct code for your production build.'); } - + exports.createStore = _createStore2["default"]; exports.combineReducers = _combineReducers2["default"]; exports.bindActionCreators = _bindActionCreators2["default"]; @@ -214,21 +247,21 @@ var Debugger = /***/ function(module, exports, __webpack_require__) { 'use strict'; - + exports.__esModule = true; exports.ActionTypes = undefined; exports["default"] = createStore; - + var _isPlainObject = __webpack_require__(5); - + var _isPlainObject2 = _interopRequireDefault(_isPlainObject); - - var _symbolObservable = __webpack_require__(9); - + + var _symbolObservable = __webpack_require__(15); + var _symbolObservable2 = _interopRequireDefault(_symbolObservable); - + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - + /** * These are private action types reserved by Redux. * For any unknown actions, you must return the current state. @@ -238,7 +271,7 @@ var Debugger = var ActionTypes = exports.ActionTypes = { INIT: '@@redux/INIT' }; - + /** * Creates a Redux store that holds the state tree. * The only way to change the data in the store is to call `dispatch()` on it. @@ -266,36 +299,36 @@ var Debugger = */ function createStore(reducer, initialState, enhancer) { var _ref2; - + if (typeof initialState === 'function' && typeof enhancer === 'undefined') { enhancer = initialState; initialState = undefined; } - + if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.'); } - + return enhancer(createStore)(reducer, initialState); } - + if (typeof reducer !== 'function') { throw new Error('Expected the reducer to be a function.'); } - + var currentReducer = reducer; var currentState = initialState; var currentListeners = []; var nextListeners = currentListeners; var isDispatching = false; - + function ensureCanMutateNextListeners() { if (nextListeners === currentListeners) { nextListeners = currentListeners.slice(); } } - + /** * Reads the state tree managed by the store. * @@ -304,7 +337,7 @@ var Debugger = function getState() { return currentState; } - + /** * Adds a change listener. It will be called any time an action is dispatched, * and some part of the state tree may potentially have changed. You may then @@ -332,25 +365,25 @@ var Debugger = if (typeof listener !== 'function') { throw new Error('Expected listener to be a function.'); } - + var isSubscribed = true; - + ensureCanMutateNextListeners(); nextListeners.push(listener); - + return function unsubscribe() { if (!isSubscribed) { return; } - + isSubscribed = false; - + ensureCanMutateNextListeners(); var index = nextListeners.indexOf(listener); nextListeners.splice(index, 1); }; } - + /** * Dispatches an action. It is the only way to trigger a state change. * @@ -380,30 +413,30 @@ var Debugger = if (!(0, _isPlainObject2["default"])(action)) { throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.'); } - + if (typeof action.type === 'undefined') { throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?'); } - + if (isDispatching) { throw new Error('Reducers may not dispatch actions.'); } - + try { isDispatching = true; currentState = currentReducer(currentState, action); } finally { isDispatching = false; } - + var listeners = currentListeners = nextListeners; for (var i = 0; i < listeners.length; i++) { listeners[i](); } - + return action; } - + /** * Replaces the reducer currently used by the store to calculate the state. * @@ -418,11 +451,11 @@ var Debugger = if (typeof nextReducer !== 'function') { throw new Error('Expected the nextReducer to be a function.'); } - + currentReducer = nextReducer; dispatch({ type: ActionTypes.INIT }); } - + /** * Interoperability point for observable/reactive libraries. * @returns {observable} A minimal observable of state changes. @@ -431,7 +464,7 @@ var Debugger = */ function observable() { var _ref; - + var outerSubscribe = subscribe; return _ref = { /** @@ -442,18 +475,18 @@ var Debugger = * be used to unsubscribe the observable from the store, and prevent further * emission of values from the observable. */ - + subscribe: function subscribe(observer) { if (typeof observer !== 'object') { throw new TypeError('Expected the observer to be an object.'); } - + function observeState() { if (observer.next) { observer.next(getState()); } } - + observeState(); var unsubscribe = outerSubscribe(observeState); return { unsubscribe: unsubscribe }; @@ -462,12 +495,12 @@ var Debugger = return this; }, _ref; } - + // When a store is created, an "INIT" action is dispatched so that every // reducer returns their initial state. This effectively populates // the initial state tree. dispatch({ type: ActionTypes.INIT }); - + return _ref2 = { dispatch: dispatch, subscribe: subscribe, @@ -480,32 +513,26 @@ var Debugger = /* 5 */ /***/ function(module, exports, __webpack_require__) { - var getPrototype = __webpack_require__(6), - isObjectLike = __webpack_require__(8); - + var baseGetTag = __webpack_require__(6), + getPrototype = __webpack_require__(12), + isObjectLike = __webpack_require__(14); + /** `Object#toString` result references. */ var objectTag = '[object Object]'; - + /** Used for built-in method references. */ var funcProto = Function.prototype, objectProto = Object.prototype; - + /** Used to resolve the decompiled source of functions. */ var funcToString = funcProto.toString; - + /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; - + /** Used to infer the `Object` constructor. */ var objectCtorString = funcToString.call(Object); - - /** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ - var objectToString = objectProto.toString; - + /** * Checks if `value` is a plain object, that is, an object created by the * `Object` constructor or one with a `[[Prototype]]` of `null`. @@ -535,7 +562,7 @@ var Debugger = * // => true */ function isPlainObject(value) { - if (!isObjectLike(value) || objectToString.call(value) != objectTag) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { return false; } var proto = getPrototype(value); @@ -543,10 +570,10 @@ var Debugger = return true; } var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; - return (typeof Ctor == 'function' && - Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString); + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; } - + module.exports = isPlainObject; @@ -554,16 +581,168 @@ var Debugger = /* 6 */ /***/ function(module, exports, __webpack_require__) { - var overArg = __webpack_require__(7); - + var Symbol = __webpack_require__(7), + getRawTag = __webpack_require__(10), + objectToString = __webpack_require__(11); + + /** `Object#toString` result references. */ + var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; + /** Built-in value references. */ - var getPrototype = overArg(Object.getPrototypeOf, Object); - - module.exports = getPrototype; + var symToStringTag = Symbol ? Symbol.toStringTag : undefined; + + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); + } + + module.exports = baseGetTag; /***/ }, /* 7 */ +/***/ function(module, exports, __webpack_require__) { + + var root = __webpack_require__(8); + + /** Built-in value references. */ + var Symbol = root.Symbol; + + module.exports = Symbol; + + +/***/ }, +/* 8 */ +/***/ function(module, exports, __webpack_require__) { + + var freeGlobal = __webpack_require__(9); + + /** Detect free variable `self`. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); + + module.exports = root; + + +/***/ }, +/* 9 */ +/***/ function(module, exports) { + + /* WEBPACK VAR INJECTION */(function(global) {/** Detect free variable `global` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + + module.exports = freeGlobal; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }, +/* 10 */ +/***/ function(module, exports, __webpack_require__) { + + var Symbol = __webpack_require__(7); + + /** Used for built-in method references. */ + var objectProto = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto.toString; + + /** Built-in value references. */ + var symToStringTag = Symbol ? Symbol.toStringTag : undefined; + + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; + } + + module.exports = getRawTag; + + +/***/ }, +/* 11 */ +/***/ function(module, exports) { + + /** Used for built-in method references. */ + var objectProto = Object.prototype; + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto.toString; + + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString(value) { + return nativeObjectToString.call(value); + } + + module.exports = objectToString; + + +/***/ }, +/* 12 */ +/***/ function(module, exports, __webpack_require__) { + + var overArg = __webpack_require__(13); + + /** Built-in value references. */ + var getPrototype = overArg(Object.getPrototypeOf, Object); + + module.exports = getPrototype; + + +/***/ }, +/* 13 */ /***/ function(module, exports) { /** @@ -579,12 +758,12 @@ var Debugger = return func(transform(arg)); }; } - + module.exports = overArg; /***/ }, -/* 8 */ +/* 14 */ /***/ function(module, exports) { /** @@ -614,31 +793,31 @@ var Debugger = function isObjectLike(value) { return value != null && typeof value == 'object'; } - + module.exports = isObjectLike; /***/ }, -/* 9 */ +/* 15 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {/* global window */ 'use strict'; - - module.exports = __webpack_require__(10)(global || window || this); - + + module.exports = __webpack_require__(16)(global || window || this); + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, -/* 10 */ +/* 16 */ /***/ function(module, exports) { 'use strict'; - + module.exports = function symbolObservablePonyfill(root) { var result; var Symbol = root.Symbol; - + if (typeof Symbol === 'function') { if (Symbol.observable) { result = Symbol.observable; @@ -649,76 +828,76 @@ var Debugger = } else { result = '@@observable'; } - + return result; }; /***/ }, -/* 11 */ +/* 17 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - + exports.__esModule = true; exports["default"] = combineReducers; - + var _createStore = __webpack_require__(4); - + var _isPlainObject = __webpack_require__(5); - + var _isPlainObject2 = _interopRequireDefault(_isPlainObject); - - var _warning = __webpack_require__(12); - + + var _warning = __webpack_require__(18); + var _warning2 = _interopRequireDefault(_warning); - + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - + function getUndefinedStateErrorMessage(key, action) { var actionType = action && action.type; var actionName = actionType && '"' + actionType.toString() + '"' || 'an action'; - + return 'Given action ' + actionName + ', reducer "' + key + '" returned undefined. ' + 'To ignore an action, you must explicitly return the previous state.'; } - + function getUnexpectedStateShapeWarningMessage(inputState, reducers, action) { var reducerKeys = Object.keys(reducers); var argumentName = action && action.type === _createStore.ActionTypes.INIT ? 'initialState argument passed to createStore' : 'previous state received by the reducer'; - + if (reducerKeys.length === 0) { return 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.'; } - + if (!(0, _isPlainObject2["default"])(inputState)) { return 'The ' + argumentName + ' has unexpected type of "' + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + '". Expected argument to be an object with the following ' + ('keys: "' + reducerKeys.join('", "') + '"'); } - + var unexpectedKeys = Object.keys(inputState).filter(function (key) { return !reducers.hasOwnProperty(key); }); - + if (unexpectedKeys.length > 0) { return 'Unexpected ' + (unexpectedKeys.length > 1 ? 'keys' : 'key') + ' ' + ('"' + unexpectedKeys.join('", "') + '" found in ' + argumentName + '. ') + 'Expected to find one of the known reducer keys instead: ' + ('"' + reducerKeys.join('", "') + '". Unexpected keys will be ignored.'); } } - + function assertReducerSanity(reducers) { Object.keys(reducers).forEach(function (key) { var reducer = reducers[key]; var initialState = reducer(undefined, { type: _createStore.ActionTypes.INIT }); - + if (typeof initialState === 'undefined') { throw new Error('Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined.'); } - + var type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.'); if (typeof reducer(undefined, { type: type }) === 'undefined') { throw new Error('Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + _createStore.ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined.'); } }); } - + /** * Turns an object whose values are different reducer functions, into a single * reducer function. It will call every child reducer, and gather their results @@ -745,29 +924,29 @@ var Debugger = } } var finalReducerKeys = Object.keys(finalReducers); - + var sanityError; try { assertReducerSanity(finalReducers); } catch (e) { sanityError = e; } - + return function combination() { var state = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; var action = arguments[1]; - + if (sanityError) { throw sanityError; } - + if (false) { var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action); if (warningMessage) { (0, _warning2["default"])(warningMessage); } } - + var hasChanged = false; var nextState = {}; for (var i = 0; i < finalReducerKeys.length; i++) { @@ -787,11 +966,11 @@ var Debugger = } /***/ }, -/* 12 */ +/* 18 */ /***/ function(module, exports) { 'use strict'; - + exports.__esModule = true; exports["default"] = warning; /** @@ -817,11 +996,11 @@ var Debugger = } /***/ }, -/* 13 */ +/* 19 */ /***/ function(module, exports) { 'use strict'; - + exports.__esModule = true; exports["default"] = bindActionCreators; function bindActionCreator(actionCreator, dispatch) { @@ -829,7 +1008,7 @@ var Debugger = return dispatch(actionCreator.apply(undefined, arguments)); }; } - + /** * Turns an object whose values are action creators, into an object with the * same keys, but with every function wrapped into a `dispatch` call so they @@ -855,11 +1034,11 @@ var Debugger = if (typeof actionCreators === 'function') { return bindActionCreator(actionCreators, dispatch); } - + if (typeof actionCreators !== 'object' || actionCreators === null) { throw new Error('bindActionCreators expected an object or a function, instead received ' + (actionCreators === null ? 'null' : typeof actionCreators) + '. ' + 'Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?'); } - + var keys = Object.keys(actionCreators); var boundActionCreators = {}; for (var i = 0; i < keys.length; i++) { @@ -873,23 +1052,23 @@ var Debugger = } /***/ }, -/* 14 */ +/* 20 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - + exports.__esModule = true; - + var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - + exports["default"] = applyMiddleware; - - var _compose = __webpack_require__(15); - + + var _compose = __webpack_require__(21); + var _compose2 = _interopRequireDefault(_compose); - + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - + /** * Creates a store enhancer that applies middleware to the dispatch method * of the Redux store. This is handy for a variety of tasks, such as expressing @@ -910,13 +1089,13 @@ var Debugger = for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) { middlewares[_key] = arguments[_key]; } - + return function (createStore) { return function (reducer, initialState, enhancer) { var store = createStore(reducer, initialState, enhancer); var _dispatch = store.dispatch; var chain = []; - + var middlewareAPI = { getState: store.getState, dispatch: function dispatch(action) { @@ -927,7 +1106,7 @@ var Debugger = return middleware(middlewareAPI); }); _dispatch = _compose2["default"].apply(undefined, chain)(store.dispatch); - + return _extends({}, store, { dispatch: _dispatch }); @@ -936,11 +1115,11 @@ var Debugger = } /***/ }, -/* 15 */ +/* 21 */ /***/ function(module, exports) { "use strict"; - + exports.__esModule = true; exports["default"] = compose; /** @@ -953,12 +1132,12 @@ var Debugger = * from right to left. For example, compose(f, g, h) is identical to doing * (...args) => f(g(h(...args))). */ - + function compose() { for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) { funcs[_key] = arguments[_key]; } - + if (funcs.length === 0) { return function (arg) { return arg; @@ -975,907 +1154,326 @@ var Debugger = } }; }(); - + if (typeof _ret === "object") return _ret.v; } } -/***/ }, -/* 16 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - module.exports = __webpack_require__(17); - - -/***/ }, -/* 17 */ -/***/ function(module, exports) { - - module.exports = devtoolsRequire("devtools/client/shared/vendor/react-dom"); - -/***/ }, -/* 18 */ -/***/ function(module, exports, __webpack_require__) { - - /* global window, document, DebuggerConfig */ - - var _require = __webpack_require__(3); - - var bindActionCreators = _require.bindActionCreators; - var combineReducers = _require.combineReducers; - - var _require2 = __webpack_require__(19); - - var Provider = _require2.Provider; - - var _require3 = __webpack_require__(28); - - var DevToolsUtils = _require3.DevToolsUtils; - var AppConstants = _require3.AppConstants; - - var _require4 = __webpack_require__(88); - - var injectGlobals = _require4.injectGlobals; - var debugGlobal = _require4.debugGlobal; - - var _require5 = __webpack_require__(89); - - var setConfig = _require5.setConfig; - var isEnabled = _require5.isEnabled; - var getValue = _require5.getValue; - var isDevelopment = _require5.isDevelopment; - - - setConfig(({"environment":"firefox-panel","baseWorkerURL":"resource://devtools/client/debugger/new/","logging":false,"clientLogging":false,"features":{"tabs":true,"sourceMaps":true,"prettyPrint":true}})); - - // Set various flags before requiring app code. - if (isEnabled("logging.client")) { - DevToolsUtils.dumpn.wantLogging = true; - } - - var client = __webpack_require__(141); - var getClient = client.getClient; - var connectClients = client.connectClients; - var startDebugging = client.startDebugging; - - - var Root = __webpack_require__(210); - - // Using this static variable allows webpack to know at compile-time - // to avoid this require and not include it at all in the output. - if (false) { - var theme = getValue("theme"); - switch (theme) { - case "dark": - require("./lib/themes/dark-theme.css");break; - case "light": - require("./lib/themes/light-theme.css");break; - case "firebug": - require("./lib/themes/firebug-theme.css");break; - } - document.body.parentNode.classList.add(`theme-${ theme }`); - - window.L10N = require("./utils/L10N"); - } - - function initApp() { - var configureStore = __webpack_require__(216); - var reducers = __webpack_require__(226); - var LandingPage = __webpack_require__(231); - - var createStore = configureStore({ - log: getValue("logging.actions"), - makeThunkArgs: (args, state) => { - return Object.assign({}, args, { client: getClient(state) }); - } - }); - - var store = createStore(combineReducers(reducers)); - var actions = bindActionCreators(__webpack_require__(236), store.dispatch); - - if (isDevelopment()) { - AppConstants.DEBUG_JS_MODULES = true; - injectGlobals({ store }); - } - - return { store, actions, LandingPage }; - } - - function renderRoot(_React, _ReactDOM, component, _store) { - var mount = document.querySelector("#mount"); - - // bail in test environments that do not have a mount - if (!mount) { - return; - } - - _ReactDOM.render(_React.createElement(Provider, { store: _store }, Root(component)), mount); - } - - function getTargetFromQuery() { - var href = window.location.href; - var nodeMatch = href.match(/ws=([^&#]*)/); - var firefoxMatch = href.match(/firefox-tab=([^&#]*)/); - var chromeMatch = href.match(/chrome-tab=([^&#]*)/); - - if (nodeMatch) { - return { type: "node", param: nodeMatch[1] }; - } else if (firefoxMatch) { - return { type: "firefox", param: firefoxMatch[1] }; - } else if (chromeMatch) { - return { type: "chrome", param: chromeMatch[1] }; - } - - return null; - } - - function bootstrap(React, ReactDOM, App, appActions, appStore) { - var connTarget = getTargetFromQuery(); - if (connTarget) { - startDebugging(connTarget, appActions).then(tabs => { - renderRoot(React, ReactDOM, App, appStore); - }); - } else { - (function () { - var _initApp = initApp(); - - var store = _initApp.store; - var actions = _initApp.actions; - var LandingPage = _initApp.LandingPage; - - renderRoot(React, ReactDOM, LandingPage, store); - connectClients(tabs => actions.newTabs(tabs)); - })(); - } - } - - module.exports = { - bootstrap, - renderRoot, - debugGlobal, - client - }; - -/***/ }, -/* 19 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - exports.connect = exports.Provider = undefined; - - var _Provider = __webpack_require__(20); - - var _Provider2 = _interopRequireDefault(_Provider); - - var _connect = __webpack_require__(23); - - var _connect2 = _interopRequireDefault(_connect); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - - exports.Provider = _Provider2["default"]; - exports.connect = _connect2["default"]; - -/***/ }, -/* 20 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - exports["default"] = undefined; - - var _react = __webpack_require__(2); - - var _storeShape = __webpack_require__(21); - - var _storeShape2 = _interopRequireDefault(_storeShape); - - var _warning = __webpack_require__(22); - - var _warning2 = _interopRequireDefault(_warning); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - - function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - - var didWarnAboutReceivingStore = false; - function warnAboutReceivingStore() { - if (didWarnAboutReceivingStore) { - return; - } - didWarnAboutReceivingStore = true; - - (0, _warning2["default"])(' does not support changing `store` on the fly. ' + 'It is most likely that you see this error because you updated to ' + 'Redux 2.x and React Redux 2.x which no longer hot reload reducers ' + 'automatically. See https://github.com/reactjs/react-redux/releases/' + 'tag/v2.0.0 for the migration instructions.'); - } - - var Provider = function (_Component) { - _inherits(Provider, _Component); - - Provider.prototype.getChildContext = function getChildContext() { - return { store: this.store }; - }; - - function Provider(props, context) { - _classCallCheck(this, Provider); - - var _this = _possibleConstructorReturn(this, _Component.call(this, props, context)); - - _this.store = props.store; - return _this; - } - - Provider.prototype.render = function render() { - var children = this.props.children; - - return _react.Children.only(children); - }; - - return Provider; - }(_react.Component); - - exports["default"] = Provider; - - if (false) { - Provider.prototype.componentWillReceiveProps = function (nextProps) { - var store = this.store; - var nextStore = nextProps.store; - - if (store !== nextStore) { - warnAboutReceivingStore(); - } - }; - } - - Provider.propTypes = { - store: _storeShape2["default"].isRequired, - children: _react.PropTypes.element.isRequired - }; - Provider.childContextTypes = { - store: _storeShape2["default"].isRequired - }; - -/***/ }, -/* 21 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - - var _react = __webpack_require__(2); - - exports["default"] = _react.PropTypes.shape({ - subscribe: _react.PropTypes.func.isRequired, - dispatch: _react.PropTypes.func.isRequired, - getState: _react.PropTypes.func.isRequired - }); - /***/ }, /* 22 */ -/***/ function(module, exports) { +/***/ function(module, exports, __webpack_require__) { - 'use strict'; - - exports.__esModule = true; - exports["default"] = warning; /** - * Prints a warning in the console if it exists. + * ReactDOM v15.3.1 * - * @param {String} message The warning message. - * @returns {void} - */ - function warning(message) { - /* eslint-disable no-console */ - if (typeof console !== 'undefined' && typeof console.error === 'function') { - console.error(message); - } - /* eslint-enable no-console */ - try { - // This error was thrown as a convenience so that you can use this stack - // to find the callsite that caused this warning to fire. - throw new Error(message); - /* eslint-disable no-empty */ - } catch (e) {} - /* eslint-enable no-empty */ - } - -/***/ }, -/* 23 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - - exports.__esModule = true; - exports["default"] = connect; - - var _react = __webpack_require__(2); - - var _storeShape = __webpack_require__(21); - - var _storeShape2 = _interopRequireDefault(_storeShape); - - var _shallowEqual = __webpack_require__(24); - - var _shallowEqual2 = _interopRequireDefault(_shallowEqual); - - var _wrapActionCreators = __webpack_require__(25); - - var _wrapActionCreators2 = _interopRequireDefault(_wrapActionCreators); - - var _warning = __webpack_require__(22); - - var _warning2 = _interopRequireDefault(_warning); - - var _isPlainObject = __webpack_require__(5); - - var _isPlainObject2 = _interopRequireDefault(_isPlainObject); - - var _hoistNonReactStatics = __webpack_require__(26); - - var _hoistNonReactStatics2 = _interopRequireDefault(_hoistNonReactStatics); - - var _invariant = __webpack_require__(27); - - var _invariant2 = _interopRequireDefault(_invariant); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - - function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - - var defaultMapStateToProps = function defaultMapStateToProps(state) { - return {}; - }; // eslint-disable-line no-unused-vars - var defaultMapDispatchToProps = function defaultMapDispatchToProps(dispatch) { - return { dispatch: dispatch }; - }; - var defaultMergeProps = function defaultMergeProps(stateProps, dispatchProps, parentProps) { - return _extends({}, parentProps, stateProps, dispatchProps); - }; - - function getDisplayName(WrappedComponent) { - return WrappedComponent.displayName || WrappedComponent.name || 'Component'; - } - - var errorObject = { value: null }; - function tryCatch(fn, ctx) { - try { - return fn.apply(ctx); - } catch (e) { - errorObject.value = e; - return errorObject; - } - } - - // Helps track hot reloading. - var nextVersion = 0; - - function connect(mapStateToProps, mapDispatchToProps, mergeProps) { - var options = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3]; - - var shouldSubscribe = Boolean(mapStateToProps); - var mapState = mapStateToProps || defaultMapStateToProps; - - var mapDispatch = undefined; - if (typeof mapDispatchToProps === 'function') { - mapDispatch = mapDispatchToProps; - } else if (!mapDispatchToProps) { - mapDispatch = defaultMapDispatchToProps; - } else { - mapDispatch = (0, _wrapActionCreators2["default"])(mapDispatchToProps); - } - - var finalMergeProps = mergeProps || defaultMergeProps; - var _options$pure = options.pure; - var pure = _options$pure === undefined ? true : _options$pure; - var _options$withRef = options.withRef; - var withRef = _options$withRef === undefined ? false : _options$withRef; - - var checkMergedEquals = pure && finalMergeProps !== defaultMergeProps; - - // Helps track hot reloading. - var version = nextVersion++; - - return function wrapWithConnect(WrappedComponent) { - var connectDisplayName = 'Connect(' + getDisplayName(WrappedComponent) + ')'; - - function checkStateShape(props, methodName) { - if (!(0, _isPlainObject2["default"])(props)) { - (0, _warning2["default"])(methodName + '() in ' + connectDisplayName + ' must return a plain object. ' + ('Instead received ' + props + '.')); - } - } - - function computeMergedProps(stateProps, dispatchProps, parentProps) { - var mergedProps = finalMergeProps(stateProps, dispatchProps, parentProps); - if (false) { - checkStateShape(mergedProps, 'mergeProps'); - } - return mergedProps; - } - - var Connect = function (_Component) { - _inherits(Connect, _Component); - - Connect.prototype.shouldComponentUpdate = function shouldComponentUpdate() { - return !pure || this.haveOwnPropsChanged || this.hasStoreStateChanged; - }; - - function Connect(props, context) { - _classCallCheck(this, Connect); - - var _this = _possibleConstructorReturn(this, _Component.call(this, props, context)); - - _this.version = version; - _this.store = props.store || context.store; - - (0, _invariant2["default"])(_this.store, 'Could not find "store" in either the context or ' + ('props of "' + connectDisplayName + '". ') + 'Either wrap the root component in a , ' + ('or explicitly pass "store" as a prop to "' + connectDisplayName + '".')); - - var storeState = _this.store.getState(); - _this.state = { storeState: storeState }; - _this.clearCache(); - return _this; - } - - Connect.prototype.computeStateProps = function computeStateProps(store, props) { - if (!this.finalMapStateToProps) { - return this.configureFinalMapState(store, props); - } - - var state = store.getState(); - var stateProps = this.doStatePropsDependOnOwnProps ? this.finalMapStateToProps(state, props) : this.finalMapStateToProps(state); - - if (false) { - checkStateShape(stateProps, 'mapStateToProps'); - } - return stateProps; - }; - - Connect.prototype.configureFinalMapState = function configureFinalMapState(store, props) { - var mappedState = mapState(store.getState(), props); - var isFactory = typeof mappedState === 'function'; - - this.finalMapStateToProps = isFactory ? mappedState : mapState; - this.doStatePropsDependOnOwnProps = this.finalMapStateToProps.length !== 1; - - if (isFactory) { - return this.computeStateProps(store, props); - } - - if (false) { - checkStateShape(mappedState, 'mapStateToProps'); - } - return mappedState; - }; - - Connect.prototype.computeDispatchProps = function computeDispatchProps(store, props) { - if (!this.finalMapDispatchToProps) { - return this.configureFinalMapDispatch(store, props); - } - - var dispatch = store.dispatch; - - var dispatchProps = this.doDispatchPropsDependOnOwnProps ? this.finalMapDispatchToProps(dispatch, props) : this.finalMapDispatchToProps(dispatch); - - if (false) { - checkStateShape(dispatchProps, 'mapDispatchToProps'); - } - return dispatchProps; - }; - - Connect.prototype.configureFinalMapDispatch = function configureFinalMapDispatch(store, props) { - var mappedDispatch = mapDispatch(store.dispatch, props); - var isFactory = typeof mappedDispatch === 'function'; - - this.finalMapDispatchToProps = isFactory ? mappedDispatch : mapDispatch; - this.doDispatchPropsDependOnOwnProps = this.finalMapDispatchToProps.length !== 1; - - if (isFactory) { - return this.computeDispatchProps(store, props); - } - - if (false) { - checkStateShape(mappedDispatch, 'mapDispatchToProps'); - } - return mappedDispatch; - }; - - Connect.prototype.updateStatePropsIfNeeded = function updateStatePropsIfNeeded() { - var nextStateProps = this.computeStateProps(this.store, this.props); - if (this.stateProps && (0, _shallowEqual2["default"])(nextStateProps, this.stateProps)) { - return false; - } - - this.stateProps = nextStateProps; - return true; - }; - - Connect.prototype.updateDispatchPropsIfNeeded = function updateDispatchPropsIfNeeded() { - var nextDispatchProps = this.computeDispatchProps(this.store, this.props); - if (this.dispatchProps && (0, _shallowEqual2["default"])(nextDispatchProps, this.dispatchProps)) { - return false; - } - - this.dispatchProps = nextDispatchProps; - return true; - }; - - Connect.prototype.updateMergedPropsIfNeeded = function updateMergedPropsIfNeeded() { - var nextMergedProps = computeMergedProps(this.stateProps, this.dispatchProps, this.props); - if (this.mergedProps && checkMergedEquals && (0, _shallowEqual2["default"])(nextMergedProps, this.mergedProps)) { - return false; - } - - this.mergedProps = nextMergedProps; - return true; - }; - - Connect.prototype.isSubscribed = function isSubscribed() { - return typeof this.unsubscribe === 'function'; - }; - - Connect.prototype.trySubscribe = function trySubscribe() { - if (shouldSubscribe && !this.unsubscribe) { - this.unsubscribe = this.store.subscribe(this.handleChange.bind(this)); - this.handleChange(); - } - }; - - Connect.prototype.tryUnsubscribe = function tryUnsubscribe() { - if (this.unsubscribe) { - this.unsubscribe(); - this.unsubscribe = null; - } - }; - - Connect.prototype.componentDidMount = function componentDidMount() { - this.trySubscribe(); - }; - - Connect.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { - if (!pure || !(0, _shallowEqual2["default"])(nextProps, this.props)) { - this.haveOwnPropsChanged = true; - } - }; - - Connect.prototype.componentWillUnmount = function componentWillUnmount() { - this.tryUnsubscribe(); - this.clearCache(); - }; - - Connect.prototype.clearCache = function clearCache() { - this.dispatchProps = null; - this.stateProps = null; - this.mergedProps = null; - this.haveOwnPropsChanged = true; - this.hasStoreStateChanged = true; - this.haveStatePropsBeenPrecalculated = false; - this.statePropsPrecalculationError = null; - this.renderedElement = null; - this.finalMapDispatchToProps = null; - this.finalMapStateToProps = null; - }; - - Connect.prototype.handleChange = function handleChange() { - if (!this.unsubscribe) { - return; - } - - var storeState = this.store.getState(); - var prevStoreState = this.state.storeState; - if (pure && prevStoreState === storeState) { - return; - } - - if (pure && !this.doStatePropsDependOnOwnProps) { - var haveStatePropsChanged = tryCatch(this.updateStatePropsIfNeeded, this); - if (!haveStatePropsChanged) { - return; - } - if (haveStatePropsChanged === errorObject) { - this.statePropsPrecalculationError = errorObject.value; - } - this.haveStatePropsBeenPrecalculated = true; - } - - this.hasStoreStateChanged = true; - this.setState({ storeState: storeState }); - }; - - Connect.prototype.getWrappedInstance = function getWrappedInstance() { - (0, _invariant2["default"])(withRef, 'To access the wrapped instance, you need to specify ' + '{ withRef: true } as the fourth argument of the connect() call.'); - - return this.refs.wrappedInstance; - }; - - Connect.prototype.render = function render() { - var haveOwnPropsChanged = this.haveOwnPropsChanged; - var hasStoreStateChanged = this.hasStoreStateChanged; - var haveStatePropsBeenPrecalculated = this.haveStatePropsBeenPrecalculated; - var statePropsPrecalculationError = this.statePropsPrecalculationError; - var renderedElement = this.renderedElement; - - this.haveOwnPropsChanged = false; - this.hasStoreStateChanged = false; - this.haveStatePropsBeenPrecalculated = false; - this.statePropsPrecalculationError = null; - - if (statePropsPrecalculationError) { - throw statePropsPrecalculationError; - } - - var shouldUpdateStateProps = true; - var shouldUpdateDispatchProps = true; - if (pure && renderedElement) { - shouldUpdateStateProps = hasStoreStateChanged || haveOwnPropsChanged && this.doStatePropsDependOnOwnProps; - shouldUpdateDispatchProps = haveOwnPropsChanged && this.doDispatchPropsDependOnOwnProps; - } - - var haveStatePropsChanged = false; - var haveDispatchPropsChanged = false; - if (haveStatePropsBeenPrecalculated) { - haveStatePropsChanged = true; - } else if (shouldUpdateStateProps) { - haveStatePropsChanged = this.updateStatePropsIfNeeded(); - } - if (shouldUpdateDispatchProps) { - haveDispatchPropsChanged = this.updateDispatchPropsIfNeeded(); - } - - var haveMergedPropsChanged = true; - if (haveStatePropsChanged || haveDispatchPropsChanged || haveOwnPropsChanged) { - haveMergedPropsChanged = this.updateMergedPropsIfNeeded(); - } else { - haveMergedPropsChanged = false; - } - - if (!haveMergedPropsChanged && renderedElement) { - return renderedElement; - } - - if (withRef) { - this.renderedElement = (0, _react.createElement)(WrappedComponent, _extends({}, this.mergedProps, { - ref: 'wrappedInstance' - })); - } else { - this.renderedElement = (0, _react.createElement)(WrappedComponent, this.mergedProps); - } - - return this.renderedElement; - }; - - return Connect; - }(_react.Component); - - Connect.displayName = connectDisplayName; - Connect.WrappedComponent = WrappedComponent; - Connect.contextTypes = { - store: _storeShape2["default"] - }; - Connect.propTypes = { - store: _storeShape2["default"] - }; - - if (false) { - Connect.prototype.componentWillUpdate = function componentWillUpdate() { - if (this.version === version) { - return; - } - - // We are hot reloading! - this.version = version; - this.trySubscribe(); - this.clearCache(); - }; - } - - return (0, _hoistNonReactStatics2["default"])(Connect, WrappedComponent); - }; - } - -/***/ }, -/* 24 */ -/***/ function(module, exports) { - - "use strict"; - - exports.__esModule = true; - exports["default"] = shallowEqual; - function shallowEqual(objA, objB) { - if (objA === objB) { - return true; - } - - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); - - if (keysA.length !== keysB.length) { - return false; - } - - // Test for A's keys different from B. - var hasOwn = Object.prototype.hasOwnProperty; - for (var i = 0; i < keysA.length; i++) { - if (!hasOwn.call(objB, keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) { - return false; - } - } - - return true; - } - -/***/ }, -/* 25 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - exports["default"] = wrapActionCreators; - - var _redux = __webpack_require__(3); - - function wrapActionCreators(actionCreators) { - return function (dispatch) { - return (0, _redux.bindActionCreators)(actionCreators, dispatch); - }; - } - -/***/ }, -/* 26 */ -/***/ function(module, exports) { - - /** - * Copyright 2015, Yahoo! Inc. - * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. - */ - 'use strict'; - - var REACT_STATICS = { - childContextTypes: true, - contextTypes: true, - defaultProps: true, - displayName: true, - getDefaultProps: true, - mixins: true, - propTypes: true, - type: true - }; - - var KNOWN_STATICS = { - name: true, - length: true, - prototype: true, - caller: true, - arguments: true, - arity: true - }; - - var isGetOwnPropertySymbolsAvailable = typeof Object.getOwnPropertySymbols === 'function'; - - module.exports = function hoistNonReactStatics(targetComponent, sourceComponent, customStatics) { - if (typeof sourceComponent !== 'string') { // don't hoist over string (html) components - var keys = Object.getOwnPropertyNames(sourceComponent); - - /* istanbul ignore else */ - if (isGetOwnPropertySymbolsAvailable) { - keys = keys.concat(Object.getOwnPropertySymbols(sourceComponent)); - } - - for (var i = 0; i < keys.length; ++i) { - if (!REACT_STATICS[keys[i]] && !KNOWN_STATICS[keys[i]] && (!customStatics || !customStatics[keys[i]])) { - try { - targetComponent[keys[i]] = sourceComponent[keys[i]]; - } catch (error) { - - } - } - } - } - - return targetComponent; - }; - - -/***/ }, -/* 27 */ -/***/ function(module, exports, __webpack_require__) { - - /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. - */ - - 'use strict'; - - /** - * Use invariant() to assert state which your program assumes to be true. * - * Provide sprintf-style format (only %s is supported) and arguments - * to provide information about what broke and what you were - * expecting. - * - * The invariant message will be stripped in production, but the invariant - * will remain to ensure logic does not differ in production. */ - - var invariant = function(condition, format, a, b, c, d, e, f) { - if (false) { - if (format === undefined) { - throw new Error('invariant requires an error message argument'); - } - } - - if (!condition) { - var error; - if (format === undefined) { - error = new Error( - 'Minified exception occurred; use the non-minified dev environment ' + - 'for the full error message and additional helpful warnings.' - ); + // Based off https://github.com/ForbesLindesay/umd/blob/master/template.js + ;(function(f) { + // CommonJS + if (true) { + module.exports = f(__webpack_require__(2)); + + // RequireJS + } else if (typeof define === "function" && define.amd) { + define(['react'], f); + + // diff --git a/browser/components/downloads/test/browser/browser_libraryDrop.js b/browser/components/downloads/test/browser/browser_libraryDrop.js index fa7df8a874c2..6f02e1430ea7 100644 --- a/browser/components/downloads/test/browser/browser_libraryDrop.js +++ b/browser/components/downloads/test/browser/browser_libraryDrop.js @@ -17,17 +17,17 @@ add_task(function* test_indicatorDrop() { let EventUtils = {}; scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils); - function task_drop(win, urls) { + async function drop(win, urls) { let dragData = [[{type: "text/plain", data: urls.join("\n")}]]; let listBox = win.document.getElementById("downloadsRichListBox"); ok(listBox, "download list box present"); - let list = yield Downloads.getList(Downloads.ALL); + let list = await Downloads.getList(Downloads.ALL); let added = new Set(); let succeeded = new Set(); - yield new Promise(function(resolve) { + await new Promise(resolve => { let view = { onDownloadAdded: function(download) { added.add(download.source.url); @@ -65,8 +65,8 @@ add_task(function* test_indicatorDrop() { win.close(); }); - yield* task_drop(win, [httpUrl("file1.txt")]); - yield* task_drop(win, [httpUrl("file1.txt"), - httpUrl("file2.txt"), - httpUrl("file3.txt")]); + yield drop(win, [httpUrl("file1.txt")]); + yield drop(win, [httpUrl("file1.txt"), + httpUrl("file2.txt"), + httpUrl("file3.txt")]); }); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js index 54b125a40484..896a2d3efdbb 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js @@ -7,8 +7,7 @@ var gTests; function test() { waitForExplicitFinish(); requestLongerTimeout(2); - gTests = runTest(); - gTests.next(); + runTest().catch(ex => ok(false, ex)); } /* @@ -17,34 +16,22 @@ function test() { * ================ */ -function moveAlong(aResult) { - try { - gTests.send(aResult); - } catch (x if x instanceof StopIteration) { - finish(); - } -} - function createWindow(aOptions) { - whenNewWindowLoaded(aOptions, function(win) { - moveAlong(win); - }); + return new Promise(resolve => whenNewWindowLoaded(aOptions, resolve)); } function getFile(downloadLastDir, aURI) { - downloadLastDir.getFileAsync(aURI, function(result) { - moveAlong(result); - }); + return new Promise(resolve => downloadLastDir.getFileAsync(aURI, resolve)); } function setFile(downloadLastDir, aURI, aValue) { downloadLastDir.setFile(aURI, aValue); - executeSoon(moveAlong); + return new Promise(resolve => executeSoon(resolve)); } function clearHistoryAndWait() { clearHistory(); - executeSoon(() => executeSoon(moveAlong)); + return new Promise(resolve => executeSoon(_ => executeSoon(resolve))); } /* @@ -53,7 +40,7 @@ function clearHistoryAndWait() { * =================== */ -function runTest() { +async function runTest() { let FileUtils = Cu.import("resource://gre/modules/FileUtils.jsm", {}).FileUtils; let DownloadLastDir = @@ -81,12 +68,12 @@ function runTest() { function checkDownloadLastDir(gDownloadLastDir, aLastDir) { is(gDownloadLastDir.file.path, aLastDir.path, "gDownloadLastDir should point to the expected last directory"); - getFile(gDownloadLastDir, uri1); + return getFile(gDownloadLastDir, uri1); } function checkDownloadLastDirNull(gDownloadLastDir) { is(gDownloadLastDir.file, null, "gDownloadLastDir should be null"); - getFile(gDownloadLastDir, uri1); + return getFile(gDownloadLastDir, uri1); } /* @@ -95,8 +82,8 @@ function runTest() { * ================================ */ - let win = yield createWindow({private: false}); - let pbWin = yield createWindow({private: true}); + let win = await createWindow({private: false}); + let pbWin = await createWindow({private: true}); let downloadLastDir = new DownloadLastDir(win); let pbDownloadLastDir = new DownloadLastDir(pbWin); @@ -113,7 +100,7 @@ function runTest() { "LastDir pref should be null to start with"); // set up last dir - yield setFile(downloadLastDir, null, tmpDir); + await setFile(downloadLastDir, null, tmpDir); is(downloadLastDir.file.path, tmpDir.path, "LastDir should point to the tmpDir"); isnot(downloadLastDir.file, tmpDir, @@ -121,111 +108,111 @@ function runTest() { // set uri1 to dir1, all should now return dir1 // also check that a new object is returned - yield setFile(downloadLastDir, uri1, dir1); + await setFile(downloadLastDir, uri1, dir1); is(downloadLastDir.file.path, dir1.path, "downloadLastDir should return dir1"); isnot(downloadLastDir.file, dir1, "downloadLastDir.file should not return dir1"); - is((yield getFile(downloadLastDir, uri1)).path, dir1.path, + is((await getFile(downloadLastDir, uri1)).path, dir1.path, "uri1 should return dir1"); // set in CPS - isnot((yield getFile(downloadLastDir, uri1)), dir1, + isnot((await getFile(downloadLastDir, uri1)), dir1, "getFile on uri1 should not return dir1"); - is((yield getFile(downloadLastDir, uri2)).path, dir1.path, + is((await getFile(downloadLastDir, uri2)).path, dir1.path, "uri2 should return dir1"); // fallback - isnot((yield getFile(downloadLastDir, uri2)), dir1, + isnot((await getFile(downloadLastDir, uri2)), dir1, "getFile on uri2 should not return dir1"); - is((yield getFile(downloadLastDir, uri3)).path, dir1.path, + is((await getFile(downloadLastDir, uri3)).path, dir1.path, "uri3 should return dir1"); // fallback - isnot((yield getFile(downloadLastDir, uri3)), dir1, + isnot((await getFile(downloadLastDir, uri3)), dir1, "getFile on uri3 should not return dir1"); - is((yield getFile(downloadLastDir, uri4)).path, dir1.path, + is((await getFile(downloadLastDir, uri4)).path, dir1.path, "uri4 should return dir1"); // fallback - isnot((yield getFile(downloadLastDir, uri4)), dir1, + isnot((await getFile(downloadLastDir, uri4)), dir1, "getFile on uri4 should not return dir1"); // set uri2 to dir2, all except uri1 should now return dir2 - yield setFile(downloadLastDir, uri2, dir2); + await setFile(downloadLastDir, uri2, dir2); is(downloadLastDir.file.path, dir2.path, "downloadLastDir should point to dir2"); - is((yield getFile(downloadLastDir, uri1)).path, dir1.path, + is((await getFile(downloadLastDir, uri1)).path, dir1.path, "uri1 should return dir1"); // set in CPS - is((yield getFile(downloadLastDir, uri2)).path, dir2.path, + is((await getFile(downloadLastDir, uri2)).path, dir2.path, "uri2 should return dir2"); // set in CPS - is((yield getFile(downloadLastDir, uri3)).path, dir2.path, + is((await getFile(downloadLastDir, uri3)).path, dir2.path, "uri3 should return dir2"); // fallback - is((yield getFile(downloadLastDir, uri4)).path, dir2.path, + is((await getFile(downloadLastDir, uri4)).path, dir2.path, "uri4 should return dir2"); // fallback // set uri3 to dir3, all except uri1 and uri2 should now return dir3 - yield setFile(downloadLastDir, uri3, dir3); + await setFile(downloadLastDir, uri3, dir3); is(downloadLastDir.file.path, dir3.path, "downloadLastDir should point to dir3"); - is((yield getFile(downloadLastDir, uri1)).path, dir1.path, + is((await getFile(downloadLastDir, uri1)).path, dir1.path, "uri1 should return dir1"); // set in CPS - is((yield getFile(downloadLastDir, uri2)).path, dir2.path, + is((await getFile(downloadLastDir, uri2)).path, dir2.path, "uri2 should return dir2"); // set in CPS - is((yield getFile(downloadLastDir, uri3)).path, dir3.path, + is((await getFile(downloadLastDir, uri3)).path, dir3.path, "uri3 should return dir3"); // set in CPS - is((yield getFile(downloadLastDir, uri4)).path, dir3.path, + is((await getFile(downloadLastDir, uri4)).path, dir3.path, "uri4 should return dir4"); // fallback // set uri1 to dir2, all except uri3 should now return dir2 - yield setFile(downloadLastDir, uri1, dir2); + await setFile(downloadLastDir, uri1, dir2); is(downloadLastDir.file.path, dir2.path, "downloadLastDir should point to dir2"); - is((yield getFile(downloadLastDir, uri1)).path, dir2.path, + is((await getFile(downloadLastDir, uri1)).path, dir2.path, "uri1 should return dir2"); // set in CPS - is((yield getFile(downloadLastDir, uri2)).path, dir2.path, + is((await getFile(downloadLastDir, uri2)).path, dir2.path, "uri2 should return dir2"); // set in CPS - is((yield getFile(downloadLastDir, uri3)).path, dir3.path, + is((await getFile(downloadLastDir, uri3)).path, dir3.path, "uri3 should return dir3"); // set in CPS - is((yield getFile(downloadLastDir, uri4)).path, dir2.path, + is((await getFile(downloadLastDir, uri4)).path, dir2.path, "uri4 should return dir2"); // fallback - yield clearHistoryAndWait(); + await clearHistoryAndWait(); // check clearHistory removes all data is(downloadLastDir.file, null, "clearHistory removes all data"); //is(Services.contentPrefs.hasPref(uri1, "browser.download.lastDir", null), // false, "LastDir preference should be absent"); - is((yield getFile(downloadLastDir, uri1)), null, "uri1 should point to null"); - is((yield getFile(downloadLastDir, uri2)), null, "uri2 should point to null"); - is((yield getFile(downloadLastDir, uri3)), null, "uri3 should point to null"); - is((yield getFile(downloadLastDir, uri4)), null, "uri4 should point to null"); + is((await getFile(downloadLastDir, uri1)), null, "uri1 should point to null"); + is((await getFile(downloadLastDir, uri2)), null, "uri2 should point to null"); + is((await getFile(downloadLastDir, uri3)), null, "uri3 should point to null"); + is((await getFile(downloadLastDir, uri4)), null, "uri4 should point to null"); - yield setFile(downloadLastDir, null, tmpDir); + await setFile(downloadLastDir, null, tmpDir); // check data set outside PB mode is remembered - is((yield checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory"); - is((yield checkDownloadLastDir(downloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory"); - yield clearHistoryAndWait(); + is((await checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory"); + is((await checkDownloadLastDir(downloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory"); + await clearHistoryAndWait(); - yield setFile(downloadLastDir, uri1, dir1); + await setFile(downloadLastDir, uri1, dir1); // check data set using CPS outside PB mode is remembered - is((yield checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); - is((yield checkDownloadLastDir(downloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); - yield clearHistoryAndWait(); + is((await checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); + is((await checkDownloadLastDir(downloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); + await clearHistoryAndWait(); // check data set inside PB mode is forgotten - yield setFile(pbDownloadLastDir, null, tmpDir); + await setFile(pbDownloadLastDir, null, tmpDir); - is((yield checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory"); - is((yield checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory"); + is((await checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory"); + is((await checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory"); - yield clearHistoryAndWait(); + await clearHistoryAndWait(); // check data set using CPS inside PB mode is forgotten - yield setFile(pbDownloadLastDir, uri1, dir1); + await setFile(pbDownloadLastDir, uri1, dir1); - is((yield checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); - is((yield checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory"); + is((await checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); + is((await checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory"); // check data set outside PB mode but changed inside is remembered correctly - yield setFile(downloadLastDir, uri1, dir1); - yield setFile(pbDownloadLastDir, uri1, dir2); - is((yield checkDownloadLastDir(pbDownloadLastDir, dir2)).path, dir2.path, "uri1 should return the expected last directory"); - is((yield checkDownloadLastDir(downloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); + await setFile(downloadLastDir, uri1, dir1); + await setFile(pbDownloadLastDir, uri1, dir2); + is((await checkDownloadLastDir(pbDownloadLastDir, dir2)).path, dir2.path, "uri1 should return the expected last directory"); + is((await checkDownloadLastDir(downloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); /* * ==================== @@ -236,47 +223,49 @@ function runTest() { // check that the last dir store got cleared in a new PB window pbWin.close(); // And give it time to close - executeSoon(moveAlong); - yield; - pbWin = yield createWindow({private: true}); + await new Promise(resolve => executeSoon(resolve)); + + pbWin = await createWindow({private: true}); pbDownloadLastDir = new DownloadLastDir(pbWin); - is((yield checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); + is((await checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); - yield clearHistoryAndWait(); + await clearHistoryAndWait(); // check clearHistory inside PB mode clears data outside PB mode - yield setFile(pbDownloadLastDir, uri1, dir2); + await setFile(pbDownloadLastDir, uri1, dir2); - yield clearHistoryAndWait(); + await clearHistoryAndWait(); - is((yield checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory"); - is((yield checkDownloadLastDirNull(pbDownloadLastDir)), null, "uri1 should return the expected last directory"); + is((await checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory"); + is((await checkDownloadLastDirNull(pbDownloadLastDir)), null, "uri1 should return the expected last directory"); // check that disabling CPS works Services.prefs.setBoolPref("browser.download.lastDir.savePerSite", false); - yield setFile(downloadLastDir, uri1, dir1); + await setFile(downloadLastDir, uri1, dir1); is(downloadLastDir.file.path, dir1.path, "LastDir should be set to dir1"); - is((yield getFile(downloadLastDir, uri1)).path, dir1.path, "uri1 should return dir1"); - is((yield getFile(downloadLastDir, uri2)).path, dir1.path, "uri2 should return dir1"); - is((yield getFile(downloadLastDir, uri3)).path, dir1.path, "uri3 should return dir1"); - is((yield getFile(downloadLastDir, uri4)).path, dir1.path, "uri4 should return dir1"); + is((await getFile(downloadLastDir, uri1)).path, dir1.path, "uri1 should return dir1"); + is((await getFile(downloadLastDir, uri2)).path, dir1.path, "uri2 should return dir1"); + is((await getFile(downloadLastDir, uri3)).path, dir1.path, "uri3 should return dir1"); + is((await getFile(downloadLastDir, uri4)).path, dir1.path, "uri4 should return dir1"); downloadLastDir.setFile(uri2, dir2); is(downloadLastDir.file.path, dir2.path, "LastDir should be set to dir2"); - is((yield getFile(downloadLastDir, uri1)).path, dir2.path, "uri1 should return dir2"); - is((yield getFile(downloadLastDir, uri2)).path, dir2.path, "uri2 should return dir2"); - is((yield getFile(downloadLastDir, uri3)).path, dir2.path, "uri3 should return dir2"); - is((yield getFile(downloadLastDir, uri4)).path, dir2.path, "uri4 should return dir2"); + is((await getFile(downloadLastDir, uri1)).path, dir2.path, "uri1 should return dir2"); + is((await getFile(downloadLastDir, uri2)).path, dir2.path, "uri2 should return dir2"); + is((await getFile(downloadLastDir, uri3)).path, dir2.path, "uri3 should return dir2"); + is((await getFile(downloadLastDir, uri4)).path, dir2.path, "uri4 should return dir2"); Services.prefs.clearUserPref("browser.download.lastDir.savePerSite"); // check that passing null to setFile clears the stored value - yield setFile(downloadLastDir, uri3, dir3); - is((yield getFile(downloadLastDir, uri3)).path, dir3.path, "LastDir should be set to dir3"); - yield setFile(downloadLastDir, uri3, null); - is((yield getFile(downloadLastDir, uri3)), null, "uri3 should return null"); + await setFile(downloadLastDir, uri3, dir3); + is((await getFile(downloadLastDir, uri3)).path, dir3.path, "LastDir should be set to dir3"); + await setFile(downloadLastDir, uri3, null); + is((await getFile(downloadLastDir, uri3)), null, "uri3 should return null"); - yield clearHistoryAndWait(); + await clearHistoryAndWait(); + + finish(); } diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent.js index b73bbf2193ab..7c49a25d3f80 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent.js @@ -17,7 +17,7 @@ add_task(function* setup() { }); }); -add_task(function test() { +add_task(function* test() { let prefix = 'http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent_page.html'; function getElts(browser) { diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_crh.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_crh.js index cd316d1fbc02..91b6b3cdb98a 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_crh.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_crh.js @@ -5,7 +5,7 @@ // This test makes sure that the Clear Recent History menu item and command // is disabled inside the private browsing mode. -add_task(function test() { +add_task(function* test() { function checkDisableOption(aPrivateMode, aWindow) { let crhCommand = aWindow.document.getElementById("Tools:Sanitize"); ok(crhCommand, "The clear recent history command should exist"); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js index b192c08f749d..f80771fcd582 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js @@ -75,31 +75,29 @@ add_task(function* test_downloads_last_dir_toggle() { * * @returns Promise */ -function testHelper(options) { - return new Task.spawn(function() { - let win = yield BrowserTestUtils.openNewBrowserWindow(options); - let gDownloadLastDir = new DownloadLastDir(win); +async function testHelper(options) { + let win = await BrowserTestUtils.openNewBrowserWindow(options); + let gDownloadLastDir = new DownloadLastDir(win); - if (options.clearHistory) { - clearHistory(); - } + if (options.clearHistory) { + clearHistory(); + } - if (options.setDir) { - gDownloadLastDir.file = options.setDir; - } + if (options.setDir) { + gDownloadLastDir.file = options.setDir; + } - let expectedDir = options.expectedDir; + let expectedDir = options.expectedDir; - if (expectedDir) { - is(gDownloadLastDir.file.path, expectedDir.path, - "gDownloadLastDir should point to the expected last directory"); - isnot(gDownloadLastDir.file, expectedDir, - "gDownloadLastDir.file should not be pointing to the last directory"); - } else { - is(gDownloadLastDir.file, null, "gDownloadLastDir should be null"); - } + if (expectedDir) { + is(gDownloadLastDir.file.path, expectedDir.path, + "gDownloadLastDir should point to the expected last directory"); + isnot(gDownloadLastDir.file, expectedDir, + "gDownloadLastDir.file should not be pointing to the last directory"); + } else { + is(gDownloadLastDir.file, null, "gDownloadLastDir should be null"); + } - gDownloadLastDir.cleanupPrivateFile(); - yield BrowserTestUtils.closeWindow(win); - }); + gDownloadLastDir.cleanupPrivateFile(); + await BrowserTestUtils.closeWindow(win); } diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js index acccb5e2d41a..c2c4b31570fe 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - add_task(function test() { + add_task(function* test() { requestLongerTimeout(2); const page1 = 'http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/' + 'browser_privatebrowsing_localStorage_page1.html' diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js index 3bcb6e5c9d06..8632cbfefc94 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js @@ -10,7 +10,7 @@ // Step 2: Load the same page in a non-private tab, ensuring that the storage instance reports only one item // existing. -add_task(function test() { +add_task(function* test() { let testURI = "about:blank"; let prefix = 'http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/'; diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js index aca8d0c7b4ce..244117c98a8f 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js @@ -5,7 +5,7 @@ // This test makes sure that the window title changes correctly while switching // from and to private browsing mode. -add_task(function test() { +add_task(function* test() { const testPageURL = "http://mochi.test:8888/browser/" + "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle_page.html"; requestLongerTimeout(2); @@ -37,12 +37,12 @@ add_task(function test() { pb_about_pb_title = "Private Browsing - " + app_name + " (Private Browsing)"; } - function* testTabTitle(aWindow, url, insidePB, expected_title) { - let tab = (yield BrowserTestUtils.openNewForegroundTab(aWindow.gBrowser)); - yield BrowserTestUtils.loadURI(tab.linkedBrowser, url); - yield BrowserTestUtils.browserLoaded(tab.linkedBrowser); + async function testTabTitle(aWindow, url, insidePB, expected_title) { + let tab = (await BrowserTestUtils.openNewForegroundTab(aWindow.gBrowser)); + await BrowserTestUtils.loadURI(tab.linkedBrowser, url); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); - yield BrowserTestUtils.waitForCondition(() => { + await BrowserTestUtils.waitForCondition(() => { return aWindow.document.title === expected_title; }, `Window title should be ${expected_title}, got ${aWindow.document.title}`); @@ -51,9 +51,9 @@ add_task(function test() { " private browsing mode)"); let win = aWindow.gBrowser.replaceTabWithWindow(tab); - yield BrowserTestUtils.waitForEvent(win, "load", false); + await BrowserTestUtils.waitForEvent(win, "load", false); - yield BrowserTestUtils.waitForCondition(() => { + await BrowserTestUtils.waitForCondition(() => { return win.document.title === expected_title; }, `Window title should be ${expected_title}, got ${aWindow.document.title}`); @@ -61,17 +61,17 @@ add_task(function test() { " detached tab is correct (" + (insidePB ? "inside" : "outside") + " private browsing mode)"); - yield Promise.all([ BrowserTestUtils.closeWindow(win), + await Promise.all([ BrowserTestUtils.closeWindow(win), BrowserTestUtils.closeWindow(aWindow) ]); } function openWin(private) { return BrowserTestUtils.openNewBrowserWindow({ private }); } - yield Task.spawn(testTabTitle((yield openWin(false)), "about:blank", false, page_without_title)); - yield Task.spawn(testTabTitle((yield openWin(false)), testPageURL, false, page_with_title)); - yield Task.spawn(testTabTitle((yield openWin(false)), "about:privatebrowsing", false, about_pb_title)); - yield Task.spawn(testTabTitle((yield openWin(true)), "about:blank", true, pb_page_without_title)); - yield Task.spawn(testTabTitle((yield openWin(true)), testPageURL, true, pb_page_with_title)); - yield Task.spawn(testTabTitle((yield openWin(true)), "about:privatebrowsing", true, pb_about_pb_title)); + yield testTabTitle((yield openWin(false)), "about:blank", false, page_without_title); + yield testTabTitle((yield openWin(false)), testPageURL, false, page_with_title); + yield testTabTitle((yield openWin(false)), "about:privatebrowsing", false, about_pb_title); + yield testTabTitle((yield openWin(true)), "about:blank", true, pb_page_without_title); + yield testTabTitle((yield openWin(true)), testPageURL, true, pb_page_with_title); + yield testTabTitle((yield openWin(true)), "about:privatebrowsing", true, pb_about_pb_title); }); diff --git a/browser/components/sessionstore/SessionMigration.jsm b/browser/components/sessionstore/SessionMigration.jsm index ff339eba9ea7..10cbaf949fdf 100644 --- a/browser/components/sessionstore/SessionMigration.jsm +++ b/browser/components/sessionstore/SessionMigration.jsm @@ -66,11 +66,11 @@ var SessionMigrationInternal = { * Asynchronously read session restore state (JSON) from a path */ readState: function(aPath) { - return Task.spawn(function() { + return Task.spawn(function*() { let bytes = yield OS.File.read(aPath); let text = gDecoder.decode(bytes); let state = JSON.parse(text); - throw new Task.Result(state); + return state; }); }, /** @@ -87,7 +87,7 @@ var SessionMigration = { * Migrate a limited set of session data from one path to another. */ migrate: function(aFromPath, aToPath) { - return Task.spawn(function() { + return Task.spawn(function*() { let inState = yield SessionMigrationInternal.readState(aFromPath); let outState = SessionMigrationInternal.convertState(inState); // Unfortunately, we can't use SessionStore's own SessionFile to diff --git a/browser/components/sessionstore/test/browser_393716.js b/browser/components/sessionstore/test/browser_393716.js index c59bdcc8b75a..ef0b2a2fa7eb 100644 --- a/browser/components/sessionstore/test/browser_393716.js +++ b/browser/components/sessionstore/test/browser_393716.js @@ -8,7 +8,7 @@ const URL = "about:config"; /** * Bug 393716 - Basic tests for getTabState(), setTabState(), and duplicateTab(). */ -add_task(function test_set_tabstate() { +add_task(function* test_set_tabstate() { let key = "Unique key: " + Date.now(); let value = "Unique value: " + Math.random(); @@ -35,7 +35,7 @@ add_task(function test_set_tabstate() { gBrowser.removeTab(tab); }); -add_task(function test_set_tabstate_and_duplicate() { +add_task(function* test_set_tabstate_and_duplicate() { let key2 = "key2"; let value2 = "Value " + Math.random(); let value3 = "Another value: " + Date.now(); diff --git a/browser/components/sessionstore/test/browser_456342.js b/browser/components/sessionstore/test/browser_456342.js index d7ed33ee52d8..61f5cc954cc7 100644 --- a/browser/components/sessionstore/test/browser_456342.js +++ b/browser/components/sessionstore/test/browser_456342.js @@ -8,7 +8,7 @@ const URL = ROOT + "browser_456342_sample.xhtml"; /** * Bug 456342 - Restore values from non-standard input field types. */ -add_task(function test_restore_nonstandard_input_values() { +add_task(function* test_restore_nonstandard_input_values() { // Add tab with various non-standard input field types. let tab = gBrowser.addTab(URL); let browser = tab.linkedBrowser; diff --git a/browser/components/sessionstore/test/browser_463205.js b/browser/components/sessionstore/test/browser_463205.js index ad3f227944a1..ddcda287f2d9 100644 --- a/browser/components/sessionstore/test/browser_463205.js +++ b/browser/components/sessionstore/test/browser_463205.js @@ -10,7 +10,7 @@ const URL = ROOT + "browser_463205_sample.html"; * website can't modify frame URLs and make us inject form data into the wrong * web pages. */ -add_task(function test_check_urls_before_restoring() { +add_task(function* test_check_urls_before_restoring() { // Add a blank tab. let tab = gBrowser.addTab("about:blank"); let browser = tab.linkedBrowser; diff --git a/browser/components/sessionstore/test/browser_466937.js b/browser/components/sessionstore/test/browser_466937.js index 0a07caa0cffd..8dd6abfd8b80 100644 --- a/browser/components/sessionstore/test/browser_466937.js +++ b/browser/components/sessionstore/test/browser_466937.js @@ -8,7 +8,7 @@ const URL = ROOT + "browser_466937_sample.html"; /** * Bug 466937 - Prevent file stealing with sessionstore. */ -add_task(function test_prevent_file_stealing() { +add_task(function* test_prevent_file_stealing() { // Add a tab with some file input fields. let tab = gBrowser.addTab(URL); let browser = tab.linkedBrowser; diff --git a/browser/components/sessionstore/test/browser_467409-backslashplosion.js b/browser/components/sessionstore/test/browser_467409-backslashplosion.js index 0e990c6142a7..2279d2a6fb01 100644 --- a/browser/components/sessionstore/test/browser_467409-backslashplosion.js +++ b/browser/components/sessionstore/test/browser_467409-backslashplosion.js @@ -30,7 +30,7 @@ function createEntries(sessionData) { }; } -add_task(function test_nested_about_sessionrestore() { +add_task(function* test_nested_about_sessionrestore() { // Prepare a blank tab. let tab = gBrowser.addTab("about:blank"); let browser = tab.linkedBrowser; diff --git a/browser/components/sessionstore/test/browser_485482.js b/browser/components/sessionstore/test/browser_485482.js index 68ec9941b351..7f1e16d6a5f5 100644 --- a/browser/components/sessionstore/test/browser_485482.js +++ b/browser/components/sessionstore/test/browser_485482.js @@ -9,7 +9,7 @@ const URL = ROOT + "browser_485482_sample.html"; * Bug 485482 - Make sure that we produce valid XPath expressions even for very * weird HTML documents. */ -add_task(function test_xpath_exp_for_strange_documents() { +add_task(function* test_xpath_exp_for_strange_documents() { // Load a page with weird tag names. let tab = gBrowser.addTab(URL); let browser = tab.linkedBrowser; diff --git a/browser/components/sessionstore/test/browser_528776.js b/browser/components/sessionstore/test/browser_528776.js index d799c9740143..7a693445380b 100644 --- a/browser/components/sessionstore/test/browser_528776.js +++ b/browser/components/sessionstore/test/browser_528776.js @@ -11,7 +11,7 @@ function browserWindowsCount(expected) { "number of open browser windows according to getBrowserState"); } -add_task(function() { +add_task(function*() { browserWindowsCount(1); let win = yield BrowserTestUtils.openNewBrowserWindow(); diff --git a/browser/components/sessionstore/test/browser_broadcast.js b/browser/components/sessionstore/test/browser_broadcast.js index 95984d6d0cf1..4824aad5a871 100644 --- a/browser/components/sessionstore/test/browser_broadcast.js +++ b/browser/components/sessionstore/test/browser_broadcast.js @@ -9,7 +9,7 @@ const INITIAL_VALUE = "browser_broadcast.js-initial-value-" + Date.now(); * This test ensures we won't lose tab data queued in the content script when * closing a tab. */ -add_task(function flush_on_tabclose() { +add_task(function* flush_on_tabclose() { let tab = yield createTabWithStorageData(["http://example.com"]); let browser = tab.linkedBrowser; @@ -25,7 +25,7 @@ add_task(function flush_on_tabclose() { * This test ensures we won't lose tab data queued in the content script when * duplicating a tab. */ -add_task(function flush_on_duplicate() { +add_task(function* flush_on_duplicate() { let tab = yield createTabWithStorageData(["http://example.com"]); let browser = tab.linkedBrowser; @@ -45,7 +45,7 @@ add_task(function flush_on_duplicate() { * This test ensures we won't lose tab data queued in the content script when * a window is closed. */ -add_task(function flush_on_windowclose() { +add_task(function* flush_on_windowclose() { let win = yield promiseNewWindow(); let tab = yield createTabWithStorageData(["http://example.com"], win); let browser = tab.linkedBrowser; @@ -62,7 +62,7 @@ add_task(function flush_on_windowclose() { * This test ensures that stale tab data is ignored when reusing a tab * (via e.g. setTabState) and does not overwrite the new data. */ -add_task(function flush_on_settabstate() { +add_task(function* flush_on_settabstate() { let tab = yield createTabWithStorageData(["http://example.com"]); let browser = tab.linkedBrowser; @@ -90,7 +90,7 @@ add_task(function flush_on_settabstate() { * asynchronously just before closing a tab. Flushing must re-send all data * that hasn't been received by chrome, yet. */ -add_task(function flush_on_tabclose_racy() { +add_task(function* flush_on_tabclose_racy() { let tab = yield createTabWithStorageData(["http://example.com"]); let browser = tab.linkedBrowser; @@ -115,17 +115,15 @@ function promiseNewWindow() { return deferred.promise; } -function createTabWithStorageData(urls, win = window) { - return Task.spawn(function task() { - let tab = win.gBrowser.addTab(); - let browser = tab.linkedBrowser; +async function createTabWithStorageData(urls, win = window) { + let tab = win.gBrowser.addTab(); + let browser = tab.linkedBrowser; - for (let url of urls) { - browser.loadURI(url); - yield promiseBrowserLoaded(browser); - yield modifySessionStorage(browser, {test: INITIAL_VALUE}); - } + for (let url of urls) { + browser.loadURI(url); + await promiseBrowserLoaded(browser); + await modifySessionStorage(browser, {test: INITIAL_VALUE}); + } - throw new Task.Result(tab); - }); + return tab; } diff --git a/browser/components/sessionstore/test/browser_capabilities.js b/browser/components/sessionstore/test/browser_capabilities.js index 456e4188295a..e8e187d73071 100644 --- a/browser/components/sessionstore/test/browser_capabilities.js +++ b/browser/components/sessionstore/test/browser_capabilities.js @@ -8,7 +8,7 @@ * properties are (re)stored as disabled. Disallowed features must be * re-enabled when the tab is re-used by another tab restoration. */ -add_task(function docshell_capabilities() { +add_task(function* docshell_capabilities() { let tab = yield createTab(); let browser = tab.linkedBrowser; let docShell = browser.docShell; @@ -69,8 +69,9 @@ add_task(function docshell_capabilities() { gBrowser.removeTab(tab); }); -function createTab() { +async function createTab() { let tab = gBrowser.addTab("about:mozilla"); let browser = tab.linkedBrowser; - return promiseBrowserLoaded(browser).then(() => tab); + await promiseBrowserLoaded(browser); + return tab; } diff --git a/browser/components/sessionstore/test/browser_cookies.js b/browser/components/sessionstore/test/browser_cookies.js index cc5b41e4b426..3299d190c03a 100644 --- a/browser/components/sessionstore/test/browser_cookies.js +++ b/browser/components/sessionstore/test/browser_cookies.js @@ -84,7 +84,7 @@ add_task(function* test_run() { * different cookie domains given in the Set-Cookie header. See above for some * usage examples. */ -var testCookieCollection = Task.async(function (params) { +var testCookieCollection = async function (params) { let tab = gBrowser.addTab("about:blank"); let browser = tab.linkedBrowser; @@ -102,14 +102,14 @@ var testCookieCollection = Task.async(function (params) { // Wait for the browser to load and the cookie to be set. // These two events can probably happen in no particular order, // so let's wait for them in parallel. - yield Promise.all([ + await Promise.all([ waitForNewCookie(), replaceCurrentURI(browser, uri) ]); // Check all URIs for which the cookie should be collected. for (let uri of params.cookieURIs || []) { - yield replaceCurrentURI(browser, uri); + await replaceCurrentURI(browser, uri); // Check the cookie. let cookie = getCookie(); @@ -121,7 +121,7 @@ var testCookieCollection = Task.async(function (params) { // Check all URIs for which the cookie should NOT be collected. for (let uri of params.noCookieURIs || []) { - yield replaceCurrentURI(browser, uri); + await replaceCurrentURI(browser, uri); // Cookie should be ignored. ok(!getCookie(), "no cookie collected"); @@ -130,22 +130,22 @@ var testCookieCollection = Task.async(function (params) { // Clean up. gBrowser.removeTab(tab); Services.cookies.removeAll(); -}); +}; /** * Replace the current URI of the given browser by loading a new URI. The * browser's session history will be completely replaced. This function ensures * that the parent process has the lastest shistory data before resolving. */ -var replaceCurrentURI = Task.async(function* (browser, uri) { +var replaceCurrentURI = async function(browser, uri) { // Replace the tab's current URI with the parent domain. let flags = Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY; browser.loadURIWithFlags(uri, flags); - yield promiseBrowserLoaded(browser); + await promiseBrowserLoaded(browser); // Ensure the tab's session history is up-to-date. - yield TabStateFlusher.flush(browser); -}); + await TabStateFlusher.flush(browser); +}; /** * Waits for a new "*example.com" cookie to be added. diff --git a/browser/components/sessionstore/test/browser_crashedTabs.js b/browser/components/sessionstore/test/browser_crashedTabs.js index 5841d536a6b7..b97bc91e761a 100644 --- a/browser/components/sessionstore/test/browser_crashedTabs.js +++ b/browser/components/sessionstore/test/browser_crashedTabs.js @@ -125,7 +125,7 @@ function promiseTabCrashedReady(browser) { * Checks that if a tab crashes, that information about the tab crashed * page does not get added to the tab history. */ -add_task(function test_crash_page_not_in_history() { +add_task(function* test_crash_page_not_in_history() { let newTab = gBrowser.addTab(); gBrowser.selectedTab = newTab; let browser = newTab.linkedBrowser; @@ -154,7 +154,7 @@ add_task(function test_crash_page_not_in_history() { * to a non-blacklisted site (so the browser becomes remote again), that * we record history for that new visit. */ -add_task(function test_revived_history_from_remote() { +add_task(function* test_revived_history_from_remote() { let newTab = gBrowser.addTab(); gBrowser.selectedTab = newTab; let browser = newTab.linkedBrowser; @@ -193,7 +193,7 @@ add_task(function test_revived_history_from_remote() { * to a blacklisted site (so the browser stays non-remote), that * we record history for that new visit. */ -add_task(function test_revived_history_from_non_remote() { +add_task(function* test_revived_history_from_non_remote() { let newTab = gBrowser.addTab(); gBrowser.selectedTab = newTab; let browser = newTab.linkedBrowser; @@ -231,7 +231,7 @@ add_task(function test_revived_history_from_non_remote() { * Checks that we can revive a crashed tab back to the page that * it was on when it crashed. */ -add_task(function test_revive_tab_from_session_store() { +add_task(function* test_revive_tab_from_session_store() { let newTab = gBrowser.addTab(); gBrowser.selectedTab = newTab; let browser = newTab.linkedBrowser; @@ -284,7 +284,7 @@ add_task(function test_revive_tab_from_session_store() { * Checks that we can revive multiple crashed tabs back to the pages * that they were on when they crashed. */ -add_task(function test_revive_all_tabs_from_session_store() { +add_task(function* test_revive_all_tabs_from_session_store() { let newTab = gBrowser.addTab(); gBrowser.selectedTab = newTab; let browser = newTab.linkedBrowser; @@ -344,7 +344,7 @@ add_task(function test_revive_all_tabs_from_session_store() { /** * Checks that about:tabcrashed can close the current tab */ -add_task(function test_close_tab_after_crash() { +add_task(function* test_close_tab_after_crash() { let newTab = gBrowser.addTab(); gBrowser.selectedTab = newTab; let browser = newTab.linkedBrowser; diff --git a/browser/components/sessionstore/test/browser_dynamic_frames.js b/browser/components/sessionstore/test/browser_dynamic_frames.js index e4355fee3f78..6cd6a927f565 100644 --- a/browser/components/sessionstore/test/browser_dynamic_frames.js +++ b/browser/components/sessionstore/test/browser_dynamic_frames.js @@ -7,7 +7,7 @@ * Ensure that static frames of framesets are serialized but dynamically * inserted iframes are ignored. */ -add_task(function () { +add_task(function*() { // This URL has the following frames: // + data:text/html,A (static) // + data:text/html,B (static) @@ -45,7 +45,7 @@ add_task(function () { * dynamically inserted iframes are ignored. Navigating a subframe should * create a second root entry that doesn't contain any dynamic children either. */ -add_task(function () { +add_task(function*() { // This URL has the following frames: // + data:text/html,A (static) // + data:text/html,C (dynamic iframe) diff --git a/browser/components/sessionstore/test/browser_form_restore_events.js b/browser/components/sessionstore/test/browser_form_restore_events.js index 3fc2e0fd4f0f..280c973a65a9 100644 --- a/browser/components/sessionstore/test/browser_form_restore_events.js +++ b/browser/components/sessionstore/test/browser_form_restore_events.js @@ -9,7 +9,7 @@ const URL = ROOT + "browser_form_restore_events_sample.html"; * Originally a test for Bug 476161, but then expanded to include all input * types in bug 640136. */ -add_task(function () { +add_task(function*() { // Load a page with some form elements. let tab = gBrowser.addTab(URL); let browser = tab.linkedBrowser; diff --git a/browser/components/sessionstore/test/browser_formdata.js b/browser/components/sessionstore/test/browser_formdata.js index ce12728880c8..a19193492932 100644 --- a/browser/components/sessionstore/test/browser_formdata.js +++ b/browser/components/sessionstore/test/browser_formdata.js @@ -9,7 +9,7 @@ requestLongerTimeout(2); * This test ensures that form data collection respects the privacy level as * set by the user. */ -add_task(function test_formdata() { +add_task(function* test_formdata() { const URL = "http://mochi.test:8888/browser/browser/components/" + "sessionstore/test/browser_formdata_sample.html"; @@ -18,23 +18,21 @@ add_task(function test_formdata() { // Creates a tab, loads a page with some form fields, // modifies their values and closes the tab. - function createAndRemoveTab() { - return Task.spawn(function () { - // Create a new tab. - let tab = gBrowser.addTab(URL); - let browser = tab.linkedBrowser; - yield promiseBrowserLoaded(browser); + function* createAndRemoveTab() { + // Create a new tab. + let tab = gBrowser.addTab(URL); + let browser = tab.linkedBrowser; + yield promiseBrowserLoaded(browser); - // Modify form data. - yield setInputValue(browser, {id: "txt", value: OUTER_VALUE}); - yield setInputValue(browser, {id: "txt", value: INNER_VALUE, frame: 0}); + // Modify form data. + yield setInputValue(browser, {id: "txt", value: OUTER_VALUE}); + yield setInputValue(browser, {id: "txt", value: INNER_VALUE, frame: 0}); - // Remove the tab. - yield promiseRemoveTab(tab); - }); + // Remove the tab. + yield promiseRemoveTab(tab); } - yield createAndRemoveTab(); + yield* createAndRemoveTab(); let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); is(formdata.id.txt, OUTER_VALUE, "outer value is correct"); is(formdata.children[0].id.txt, INNER_VALUE, "inner value is correct"); @@ -42,7 +40,7 @@ add_task(function test_formdata() { // Disable saving data for encrypted sites. Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1); - yield createAndRemoveTab(); + yield* createAndRemoveTab(); [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); is(formdata.id.txt, OUTER_VALUE, "outer value is correct"); ok(!formdata.children, "inner value was *not* stored"); @@ -50,7 +48,7 @@ add_task(function test_formdata() { // Disable saving data for any site. Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2); - yield createAndRemoveTab(); + yield* createAndRemoveTab(); [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); ok(!formdata, "form data has *not* been stored"); @@ -63,7 +61,7 @@ add_task(function test_formdata() { * form data into a wrong website and that we always check the stored URL * before doing so. */ -add_task(function test_url_check() { +add_task(function* test_url_check() { const URL = "data:text/html;charset=utf-8,"; const VALUE = "value-" + Math.random(); @@ -98,7 +96,7 @@ add_task(function test_url_check() { * This test ensures that collecting form data works as expected when having * nested frame sets. */ -add_task(function test_nested() { +add_task(function* test_nested() { const URL = "data:text/html;charset=utf-8," + "" + "clickme" + @@ -143,7 +143,7 @@ add_task(function test_subframes() { /** * Ensure that navigating from an about page invalidates shistory. */ -add_task(function test_about_page_navigate() { +add_task(function* test_about_page_navigate() { // Create a new tab. let tab = gBrowser.addTab("about:blank"); let browser = tab.linkedBrowser; @@ -171,7 +171,7 @@ add_task(function test_about_page_navigate() { /** * Ensure that history.pushState and history.replaceState invalidate shistory. */ -add_task(function test_pushstate_replacestate() { +add_task(function* test_pushstate_replacestate() { // Create a new tab. let tab = gBrowser.addTab("http://example.com/1"); let browser = tab.linkedBrowser; @@ -210,7 +210,7 @@ add_task(function test_pushstate_replacestate() { /** * Ensure that slow loading subframes will invalidate shistory. */ -add_task(function test_slow_subframe_load() { +add_task(function* test_slow_subframe_load() { const SLOW_URL = "http://mochi.test:8888/browser/browser/components/" + "sessionstore/test/browser_sessionHistory_slow.sjs"; diff --git a/browser/components/sessionstore/test/browser_sessionStorage.js b/browser/components/sessionstore/test/browser_sessionStorage.js index b580c5cc2e99..4d938963d600 100644 --- a/browser/components/sessionstore/test/browser_sessionStorage.js +++ b/browser/components/sessionstore/test/browser_sessionStorage.js @@ -15,7 +15,7 @@ const INNER_VALUE = "inner-value-" + RAND; * This test ensures that setting, modifying and restoring sessionStorage data * works as expected. */ -add_task(function session_storage() { +add_task(function* session_storage() { let tab = gBrowser.addTab(URL); let browser = tab.linkedBrowser; yield promiseBrowserLoaded(browser); @@ -102,7 +102,7 @@ add_task(function session_storage() { * This test ensures that purging domain data also purges data from the * sessionStorage data collected for tabs. */ -add_task(function purge_domain() { +add_task(function* purge_domain() { let tab = gBrowser.addTab(URL); let browser = tab.linkedBrowser; yield promiseBrowserLoaded(browser); @@ -126,7 +126,7 @@ add_task(function purge_domain() { * This test ensures that collecting sessionStorage data respects the privacy * levels as set by the user. */ -add_task(function respect_privacy_level() { +add_task(function* respect_privacy_level() { let tab = gBrowser.addTab(URL + "&secure"); yield promiseBrowserLoaded(tab.linkedBrowser); yield promiseRemoveTab(tab); From 891c6d266387474c0f63e482a162e0a03f98b8a4 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Sat, 21 Jan 2017 17:40:45 +0100 Subject: [PATCH 56/67] Bug 1326067 part 6 - Fix EmitStubGuardFailure to not clobber registers on ARM/MIPS. r=evilpie --- .../tests/baseline/unboxed-expando-type-update.js | 14 ++++++++++++++ js/src/jit/arm/MacroAssembler-arm.h | 6 ------ js/src/jit/arm/SharedICHelpers-arm.h | 12 +----------- js/src/jit/arm64/SharedICHelpers-arm64.h | 10 +--------- .../jit/mips-shared/SharedICHelpers-mips-shared.h | 10 +--------- js/src/jit/x64/SharedICHelpers-x64.h | 5 ----- js/src/jit/x86/SharedICHelpers-x86.h | 10 ++-------- 7 files changed, 19 insertions(+), 48 deletions(-) create mode 100644 js/src/jit-test/tests/baseline/unboxed-expando-type-update.js diff --git a/js/src/jit-test/tests/baseline/unboxed-expando-type-update.js b/js/src/jit-test/tests/baseline/unboxed-expando-type-update.js new file mode 100644 index 000000000000..35e55d39f793 --- /dev/null +++ b/js/src/jit-test/tests/baseline/unboxed-expando-type-update.js @@ -0,0 +1,14 @@ +function f() { + var a = []; + for (var i=0; i<100; i++) + a.push({x: i}); + + var vals = [1, "", true, null]; + + for (var j=0; j<100; j++) { + var v = vals[j % vals.length]; + a[95].y = v; + assertEq(a[95].y, v); + } +} +f(); diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 8cbf89dec65f..408c13a95e30 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -557,12 +557,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void mov(ImmPtr imm, Register dest) { mov(ImmWord(uintptr_t(imm.value)), dest); } - void mov(Register src, Address dest) { - MOZ_CRASH("NYI-IC"); - } - void mov(Address src, Register dest) { - MOZ_CRASH("NYI-IC"); - } void branch(JitCode* c) { BufferOffset bo = m_buffer.nextOffset(); diff --git a/js/src/jit/arm/SharedICHelpers-arm.h b/js/src/jit/arm/SharedICHelpers-arm.h index 17534adef726..c5464734d823 100644 --- a/js/src/jit/arm/SharedICHelpers-arm.h +++ b/js/src/jit/arm/SharedICHelpers-arm.h @@ -359,22 +359,12 @@ EmitPreBarrier(MacroAssembler& masm, const AddrType& addr, MIRType type) inline void EmitStubGuardFailure(MacroAssembler& masm) { - MOZ_ASSERT(R2 == ValueOperand(r1, r0)); - - // NOTE: This routine assumes that the stub guard code left the stack in the - // same state it was in when it was entered. - - // BaselineStubEntry points to the current stub. - // Load next stub into ICStubReg. masm.loadPtr(Address(ICStubReg, ICStub::offsetOfNext()), ICStubReg); - // Load stubcode pointer from BaselineStubEntry into scratch register. - masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), r0); - // Return address is already loaded, just jump to the next stubcode. MOZ_ASSERT(ICTailCallReg == lr); - masm.branch(r0); + masm.jump(Address(ICStubReg, ICStub::offsetOfStubCode())); } diff --git a/js/src/jit/arm64/SharedICHelpers-arm64.h b/js/src/jit/arm64/SharedICHelpers-arm64.h index b97129e65d5d..30f4a756826c 100644 --- a/js/src/jit/arm64/SharedICHelpers-arm64.h +++ b/js/src/jit/arm64/SharedICHelpers-arm64.h @@ -316,19 +316,11 @@ EmitPreBarrier(MacroAssembler& masm, const AddrType& addr, MIRType type) inline void EmitStubGuardFailure(MacroAssembler& masm) { - // NOTE: This routine assumes that the stub guard code left the stack in the - // same state it was in when it was entered. - - // BaselineStubEntry points to the current stub. - // Load next stub into ICStubReg. masm.loadPtr(Address(ICStubReg, ICStub::offsetOfNext()), ICStubReg); - // Load stubcode pointer from BaselineStubEntry into scratch register. - masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), r0); - // Return address is already loaded, just jump to the next stubcode. - masm.Br(x0); + masm.jump(Address(ICStubReg, ICStub::offsetOfStubCode())); } } // namespace jit diff --git a/js/src/jit/mips-shared/SharedICHelpers-mips-shared.h b/js/src/jit/mips-shared/SharedICHelpers-mips-shared.h index e665c92dd21b..eefd8841e2b4 100644 --- a/js/src/jit/mips-shared/SharedICHelpers-mips-shared.h +++ b/js/src/jit/mips-shared/SharedICHelpers-mips-shared.h @@ -360,20 +360,12 @@ EmitPreBarrier(MacroAssembler& masm, const AddrType& addr, MIRType type) inline void EmitStubGuardFailure(MacroAssembler& masm) { - // NOTE: This routine assumes that the stub guard code left the stack in - // the same state it was in when it was entered. - - // BaselineStubEntry points to the current stub. - // Load next stub into ICStubReg masm.loadPtr(Address(ICStubReg, ICStub::offsetOfNext()), ICStubReg); - // Load stubcode pointer from BaselineStubEntry into scratch register. - masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), R2.scratchReg()); - // Return address is already loaded, just jump to the next stubcode. MOZ_ASSERT(ICTailCallReg == ra); - masm.branch(R2.scratchReg()); + masm.jump(Address(ICStubReg, ICStub::offsetOfStubCode())); } } // namespace jit diff --git a/js/src/jit/x64/SharedICHelpers-x64.h b/js/src/jit/x64/SharedICHelpers-x64.h index b59d05ddc2ae..27d2500f64a1 100644 --- a/js/src/jit/x64/SharedICHelpers-x64.h +++ b/js/src/jit/x64/SharedICHelpers-x64.h @@ -334,11 +334,6 @@ EmitPreBarrier(MacroAssembler& masm, const AddrType& addr, MIRType type) inline void EmitStubGuardFailure(MacroAssembler& masm) { - // NOTE: This routine assumes that the stub guard code left the stack in the - // same state it was in when it was entered. - - // BaselineStubEntry points to the current stub. - // Load next stub into ICStubReg masm.loadPtr(Address(ICStubReg, ICStub::offsetOfNext()), ICStubReg); diff --git a/js/src/jit/x86/SharedICHelpers-x86.h b/js/src/jit/x86/SharedICHelpers-x86.h index e7f75cc95c33..684f9266f48d 100644 --- a/js/src/jit/x86/SharedICHelpers-x86.h +++ b/js/src/jit/x86/SharedICHelpers-x86.h @@ -334,19 +334,13 @@ EmitPreBarrier(MacroAssembler& masm, const AddrType& addr, MIRType type) inline void EmitStubGuardFailure(MacroAssembler& masm) { - // NOTE: This routine assumes that the stub guard code left the stack in the - // same state it was in when it was entered. - - // BaselineStubEntry points to the current stub. - // Load next stub into ICStubReg - masm.loadPtr(Address(ICStubReg, (int32_t) ICStub::offsetOfNext()), ICStubReg); + masm.loadPtr(Address(ICStubReg, ICStub::offsetOfNext()), ICStubReg); // Return address is already loaded, just jump to the next stubcode. - masm.jmp(Operand(ICStubReg, (int32_t) ICStub::offsetOfStubCode())); + masm.jmp(Operand(ICStubReg, ICStub::offsetOfStubCode())); } - } // namespace jit } // namespace js From 8b31ae67495e35157b5db4451efb94d337de598c Mon Sep 17 00:00:00 2001 From: Gabor Krizsanits Date: Sat, 21 Jan 2017 18:24:35 +0100 Subject: [PATCH 57/67] Bug 1303113 - Turn e10s-multi on in Nightly. r=me --- addon-sdk/test/browser.ini | 1 + browser/base/content/test/general/browser.ini | 5 ++++- browser/base/content/test/plugins/browser.ini | 1 + browser/base/content/test/referrer/browser.ini | 2 ++ browser/base/content/test/urlbar/browser.ini | 1 + browser/base/content/test/webrtc/browser.ini | 1 + .../contextualidentity/test/browser/browser.ini | 1 + .../preferences/in-content/tests/browser_security.js | 12 ++++++------ .../privatebrowsing/test/browser/browser.ini | 1 + .../test/browser_service_workers_status.js | 6 ++++-- .../browser_grouped_shistory_dead_navigate.js | 3 ++- dom/base/test/browser.ini | 1 + dom/browser-element/mochitest/mochitest-oop.ini | 1 + dom/cache/test/mochitest/browser.ini | 1 + dom/tests/browser/browser.ini | 4 ++-- modules/libpref/init/all.js | 4 ++++ .../tests/functional/security/manifest.ini | 1 + .../extensions/test/mochitest/mochitest-common.ini | 2 +- .../extensions/test/mochitest/test_ext_cookies.html | 6 ++++-- .../test/browser/browser_ui_requestAutocomplete.js | 6 ++++++ .../components/passwordmgr/test/browser/browser.ini | 1 + .../extensions/test/browser/browser-common.ini | 1 + 22 files changed, 47 insertions(+), 15 deletions(-) diff --git a/addon-sdk/test/browser.ini b/addon-sdk/test/browser.ini index 213698bf83af..e33f658fef1e 100644 --- a/addon-sdk/test/browser.ini +++ b/addon-sdk/test/browser.ini @@ -7,6 +7,7 @@ support-files = invalid.json [browser_sdk_loader_sdk_modules.js] [browser_sdk_loader_sdk_gui_modules.js] +skip-if = e10s # Bug 1315042 [browser_sdk_loader_jsm_modules.js] [browser_sdk_loader_js_modules.js] [browser_sdk_loader_json.js] diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 4d6129ddf09d..6e53cee197f6 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -256,6 +256,7 @@ skip-if = os == "mac" # mac: Intermittent failures, bug 925225 skip-if = os == "mac" # Bug 1102331 - does focus things on the content window which break in e10s mode (still causes orange on Mac 10.10) [browser_bug710878.js] [browser_bug719271.js] +skip-if = e10s # Bug 1315042 [browser_bug724239.js] [browser_bug734076.js] [browser_bug735471.js] @@ -406,6 +407,7 @@ skip-if = os == "linux" # Bug 1329991 - test fails intermittently on Linux build skip-if = os == 'linux' # Bug 1304272 [browser_tab_close_dependent_window.js] [browser_tabDrop.js] +skip-if = e10s # Bug 1315042 [browser_tabReorder.js] [browser_tab_detach_restore.js] [browser_tab_drag_drop_perwindow.js] @@ -416,8 +418,9 @@ skip-if = buildapp == 'mulet' || (e10s && (debug || asan)) # Bug 1312436 skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux # Disabled on OS X because of bug 967917 [browser_tabfocus.js] +skip-if = e10s # Bug 1315042 [browser_tabkeynavigation.js] -skip-if = (os == "mac" && !e10s) # Bug 1237713 - OSX eats keypresses for some reason +skip-if = true || (os == "mac" && !e10s) # Bug 1315042, Bug 1237713 - OSX eats keypresses for some reason [browser_tabopen_reflows.js] [browser_tabs_close_beforeunload.js] support-files = diff --git a/browser/base/content/test/plugins/browser.ini b/browser/base/content/test/plugins/browser.ini index 17954758b4e6..03fe6825e99b 100644 --- a/browser/base/content/test/plugins/browser.ini +++ b/browser/base/content/test/plugins/browser.ini @@ -56,6 +56,7 @@ skip-if = !crashreporter [browser_CTP_iframe.js] [browser_CTP_multi_allow.js] [browser_CTP_nonplugins.js] +skip-if = e10s # Bug 1315042 [browser_CTP_notificationBar.js] [browser_CTP_outsideScrollArea.js] [browser_CTP_remove_navigate.js] diff --git a/browser/base/content/test/referrer/browser.ini b/browser/base/content/test/referrer/browser.ini index 13b712850fcd..ce3d56cc4e36 100644 --- a/browser/base/content/test/referrer/browser.ini +++ b/browser/base/content/test/referrer/browser.ini @@ -6,7 +6,9 @@ support-files = head.js [browser_referrer_middle_click.js] +skip-if = true # Bug 1315042 [browser_referrer_middle_click_in_container.js] +skip-if = true # Bug 1315042 [browser_referrer_open_link_in_private.js] skip-if = os == 'linux' # Bug 1145199 [browser_referrer_open_link_in_tab.js] diff --git a/browser/base/content/test/urlbar/browser.ini b/browser/base/content/test/urlbar/browser.ini index 9d11f931fdce..7e013fdd0044 100644 --- a/browser/base/content/test/urlbar/browser.ini +++ b/browser/base/content/test/urlbar/browser.ini @@ -29,6 +29,7 @@ support-files = [browser_bug556061.js] subsuite = clipboard [browser_bug562649.js] +skip-if = e10s # Bug 1315042 [browser_bug623155.js] support-files = redirect_bug623155.sjs diff --git a/browser/base/content/test/webrtc/browser.ini b/browser/base/content/test/webrtc/browser.ini index 0ea0dcacae63..9e4898e195b2 100644 --- a/browser/base/content/test/webrtc/browser.ini +++ b/browser/base/content/test/webrtc/browser.ini @@ -12,6 +12,7 @@ skip-if = (os == "linux" && debug) # linux: bug 976544 [browser_devices_get_user_media_screen.js] skip-if = (e10s && debug) || (os == "linux" && !debug) # bug 1320754 for e10s debug, and bug 1320994 for linux opt [browser_devices_get_user_media_tear_off_tab.js] +skip-if = e10s # Bug 1315042 [browser_devices_get_user_media_unprompted_access.js] [browser_devices_get_user_media_unprompted_access_in_frame.js] [browser_devices_get_user_media_unprompted_access_tear_off_tab.js] diff --git a/browser/components/contextualidentity/test/browser/browser.ini b/browser/components/contextualidentity/test/browser/browser.ini index af7bd6dbafaf..f13a3fba04ed 100644 --- a/browser/components/contextualidentity/test/browser/browser.ini +++ b/browser/components/contextualidentity/test/browser/browser.ini @@ -13,6 +13,7 @@ support-files = [browser_forgetaboutsite.js] [browser_forgetAPI_cookie_getCookiesWithOriginAttributes.js] [browser_forgetAPI_EME_forgetThisSite.js] +skip-if = e10s # Bug 1315042 [browser_forgetAPI_quota_clearStoragesForPrincipal.js] [browser_newtabButton.js] [browser_usercontext.js] diff --git a/browser/components/preferences/in-content/tests/browser_security.js b/browser/components/preferences/in-content/tests/browser_security.js index e6eb2a91d7a5..cd6b98e8ae31 100644 --- a/browser/components/preferences/in-content/tests/browser_security.js +++ b/browser/components/preferences/in-content/tests/browser_security.js @@ -50,10 +50,10 @@ add_task(function*() { yield BrowserTestUtils.removeTab(gBrowser.selectedTab); } - yield checkPrefSwitch(true, true); - yield checkPrefSwitch(false, true); - yield checkPrefSwitch(true, false); - yield checkPrefSwitch(false, false); + yield* checkPrefSwitch(true, true); + yield* checkPrefSwitch(false, true); + yield* checkPrefSwitch(true, false); + yield* checkPrefSwitch(false, false); }); // test the download protection preference @@ -84,8 +84,8 @@ add_task(function*() { yield BrowserTestUtils.removeTab(gBrowser.selectedTab); } - yield checkPrefSwitch(true); - yield checkPrefSwitch(false); + yield* checkPrefSwitch(true); + yield* checkPrefSwitch(false); }); // test the unwanted/uncommon software warning preference diff --git a/browser/components/privatebrowsing/test/browser/browser.ini b/browser/components/privatebrowsing/test/browser/browser.ini index 5efca4c0ec64..49247119bef3 100644 --- a/browser/components/privatebrowsing/test/browser/browser.ini +++ b/browser/components/privatebrowsing/test/browser/browser.ini @@ -26,6 +26,7 @@ tags = trackingprotection [browser_privatebrowsing_cache.js] [browser_privatebrowsing_certexceptionsui.js] [browser_privatebrowsing_concurrent.js] +skip-if = e10s # Bug 1315042 [browser_privatebrowsing_context_and_chromeFlags.js] [browser_privatebrowsing_crh.js] [browser_privatebrowsing_downloadLastDir.js] diff --git a/devtools/client/aboutdebugging/test/browser_service_workers_status.js b/devtools/client/aboutdebugging/test/browser_service_workers_status.js index 32cae6dc7b96..3cac32f2c639 100644 --- a/devtools/client/aboutdebugging/test/browser_service_workers_status.js +++ b/devtools/client/aboutdebugging/test/browser_service_workers_status.js @@ -42,9 +42,11 @@ add_task(function* () { let targetElement = name.parentNode.parentNode; let status = targetElement.querySelector(".target-status"); - is(status.textContent, "Registering", "Service worker is currently registering"); + // We might miss the registering state in some setup... + if (status.textContent == "Registering") { + yield waitForMutation(serviceWorkersElement, { childList: true, subtree: true }); + } - yield waitForMutation(serviceWorkersElement, { childList: true, subtree: true }); is(status.textContent, "Running", "Service worker is currently running"); yield waitForMutation(serviceWorkersElement, { attributes: true, subtree: true }); diff --git a/docshell/test/browser/browser_grouped_shistory_dead_navigate.js b/docshell/test/browser/browser_grouped_shistory_dead_navigate.js index fd4b7bd83aa0..467f5ba825f6 100644 --- a/docshell/test/browser/browser_grouped_shistory_dead_navigate.js +++ b/docshell/test/browser/browser_grouped_shistory_dead_navigate.js @@ -1,6 +1,7 @@ add_task(function* () { yield SpecialPowers.pushPrefEnv({ - set: [["browser.groupedhistory.enabled", true]] + set: [["browser.groupedhistory.enabled", true], + ["dom.ipc.processCount", 1]] }); // Wait for a process change and then fulfil the promise. diff --git a/dom/base/test/browser.ini b/dom/base/test/browser.ini index 93fe06cd4a9a..3f4d6cf66789 100644 --- a/dom/base/test/browser.ini +++ b/dom/base/test/browser.ini @@ -20,6 +20,7 @@ tags = mcb [browser_bug1011748.js] [browser_bug1058164.js] [browser_messagemanager_loadprocessscript.js] +skip-if = e10s # Bug 1315042 [browser_messagemanager_targetframeloader.js] [browser_messagemanager_unload.js] [browser_pagehide_on_tab_close.js] diff --git a/dom/browser-element/mochitest/mochitest-oop.ini b/dom/browser-element/mochitest/mochitest-oop.ini index 9b42f49d5ddb..e61f37c2f73e 100644 --- a/dom/browser-element/mochitest/mochitest-oop.ini +++ b/dom/browser-element/mochitest/mochitest-oop.ini @@ -71,6 +71,7 @@ disabled = disabled for bug 1266035 (bug 1310706 for re-enabling) [test_browserElement_oop_OpenTab.html] disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling) [test_browserElement_oop_PrivateBrowsing.html] +skip-if = true # Bug 1315042 [test_browserElement_oop_PromptCheck.html] [test_browserElement_oop_PromptConfirm.html] [test_browserElement_oop_PurgeHistory.html] diff --git a/dom/cache/test/mochitest/browser.ini b/dom/cache/test/mochitest/browser.ini index 90a7a53a3a36..3c55c22f52df 100644 --- a/dom/cache/test/mochitest/browser.ini +++ b/dom/cache/test/mochitest/browser.ini @@ -1 +1,2 @@ [browser_cache_pb_window.js] +skip-if = e10s # Bug 1315042 diff --git a/dom/tests/browser/browser.ini b/dom/tests/browser/browser.ini index c7f2114d19f8..f7044ea708b8 100644 --- a/dom/tests/browser/browser.ini +++ b/dom/tests/browser/browser.ini @@ -36,7 +36,7 @@ skip-if = e10s [browser_focus_steal_from_chrome_during_mousedown.js] [browser_frame_elements.js] [browser_largeAllocation.js] -skip-if = !e10s # Large-Allocation requires e10s +skip-if = true || !e10s # Large-Allocation requires e10s, turned off for e10s-multi Bug 1315042 [browser_localStorage_privatestorageevent.js] [browser_test__content.js] [browser_test_new_window_from_content.js] @@ -52,4 +52,4 @@ support-files = support-files = prerender.html prerender_target.html -skip-if = !e10s # Prerendering requires e10s +skip-if = true || !e10s # Prerendering requires e10s, turned off for e10s-multi Bug 1315042 diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 2ca625dd41dc..9ea53d6688e8 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2880,7 +2880,11 @@ pref("dom.ipc.plugins.asyncdrawing.enabled", false); pref("dom.ipc.plugins.asyncdrawing.enabled", true); #endif +#ifdef NIGHTLY_BUILD +pref("dom.ipc.processCount", 2); +#else pref("dom.ipc.processCount", 1); +#endif // Disable support for SVG pref("svg.disabled", false); diff --git a/testing/firefox-ui/tests/functional/security/manifest.ini b/testing/firefox-ui/tests/functional/security/manifest.ini index 6a210cfb7315..a879eae6de38 100644 --- a/testing/firefox-ui/tests/functional/security/manifest.ini +++ b/testing/firefox-ui/tests/functional/security/manifest.ini @@ -11,6 +11,7 @@ tags = local tags = local [test_safe_browsing_initial_download.py] [test_safe_browsing_notification.py] +skip-if = e10s # Bug 1315042 [test_safe_browsing_warning_pages.py] [test_security_notification.py] [test_ssl_disabled_error_page.py] diff --git a/toolkit/components/extensions/test/mochitest/mochitest-common.ini b/toolkit/components/extensions/test/mochitest/mochitest-common.ini index 7188f93e63c3..2474f02acc5e 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest-common.ini @@ -85,7 +85,7 @@ skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975 skip-if = os == 'android' # Android does not currently support tabs. [test_ext_test.html] [test_ext_cookies.html] -skip-if = os == 'android' # Bug 1258975 on android. +os == 'android' # Bug 1258975 on android. [test_ext_background_api_injection.html] [test_ext_background_generated_url.html] [test_ext_background_teardown.html] diff --git a/toolkit/components/extensions/test/mochitest/test_ext_cookies.html b/toolkit/components/extensions/test/mochitest/test_ext_cookies.html index ec5d7ba0f047..825407abc705 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_cookies.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_cookies.html @@ -88,7 +88,8 @@ add_task(function* test_cookies() { browser.test.assertEq(1, stores[0].tabIds.length, "one tabId returned for store"); browser.test.assertEq("number", typeof stores[0].tabIds[0], "tabId is a number"); - { + // This part causes intermittent failures see Bug 1309637. + if (false) { let privateWindow = await browser.windows.create({incognito: true}); let stores = await browser.cookies.getAllCookieStores(); @@ -179,7 +180,8 @@ add_task(function* test_cookies() { browser.test.assertEq("", cookie.value, "default value set"); browser.test.assertEq(true, cookie.session, "no expiry date created session cookie"); - { + // This part causes intermittent failures see Bug 1309637. + if (false) { let privateWindow = await browser.windows.create({incognito: true}); // Hacky work-around for bugzil.la/1309637 diff --git a/toolkit/components/formautofill/test/browser/browser_ui_requestAutocomplete.js b/toolkit/components/formautofill/test/browser/browser_ui_requestAutocomplete.js index 2a7b58f12167..c3257bc46787 100644 --- a/toolkit/components/formautofill/test/browser/browser_ui_requestAutocomplete.js +++ b/toolkit/components/formautofill/test/browser/browser_ui_requestAutocomplete.js @@ -7,6 +7,12 @@ "use strict"; +add_task(function* setup() { + yield SpecialPowers.pushPrefEnv({ + set: [["dom.ipc.processCount", 1]] + }); +}); + /** * Open the requestAutocomplete UI and test that selecting a profile results in * the correct data being sent back to the opener. diff --git a/toolkit/components/passwordmgr/test/browser/browser.ini b/toolkit/components/passwordmgr/test/browser/browser.ini index edabe5aacfdc..a07ec9ed90d6 100644 --- a/toolkit/components/passwordmgr/test/browser/browser.ini +++ b/toolkit/components/passwordmgr/test/browser/browser.ini @@ -45,6 +45,7 @@ support-files = [browser_formless_submit_chrome.js] [browser_hasInsecureLoginForms.js] [browser_hasInsecureLoginForms_streamConverter.js] +skip-if = e10s # Bug 1315042 [browser_http_autofill.js] [browser_insecurePasswordWarning.js] [browser_notifications.js] diff --git a/toolkit/mozapps/extensions/test/browser/browser-common.ini b/toolkit/mozapps/extensions/test/browser/browser-common.ini index eda266e2f30e..dc9e88e5715b 100644 --- a/toolkit/mozapps/extensions/test/browser/browser-common.ini +++ b/toolkit/mozapps/extensions/test/browser/browser-common.ini @@ -65,3 +65,4 @@ skip-if = buildapp == 'mulet' skip-if = buildapp == 'mulet' [browser_webext_options.js] tags = webextensions +skip-if = e10s # Bug 1315042 From c7973f54611fb58ef82d05244248788da69290e7 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Sat, 21 Jan 2017 09:41:03 -0800 Subject: [PATCH 58/67] Backed out 5 changesets (bug 1305162) for permatimeout in e10s browser_action_keyword.js Backed out changeset c633650caea6 (bug 1305162) Backed out changeset 1a23ce5a17c3 (bug 1305162) Backed out changeset d1095e03dfc6 (bug 1305162) Backed out changeset 1202edf6008d (bug 1305162) Backed out changeset de131f7c1fc1 (bug 1305162) --- .../netmonitor/test/browser_net_curl-utils.js | 15 +- .../test/browser_webconsole_netlogging.js | 15 +- ipc/glue/InputStreamParams.ipdlh | 10 +- netwerk/base/nsIMIMEInputStream.idl | 14 -- netwerk/base/nsMIMEInputStream.cpp | 154 +++++++++----- netwerk/protocol/http/HttpBaseChannel.cpp | 197 ++++++++---------- .../browser_nsIFormPOSTActionChannel.js | 30 +-- .../mochitest/test_ext_webrequest_upload.html | 22 +- .../remotebrowserutils/RemoteWebNavigation.js | 19 +- toolkit/content/browser-child.js | 16 +- toolkit/modules/addons/WebRequest.jsm | 12 +- toolkit/modules/addons/WebRequestUpload.jsm | 64 +++--- 12 files changed, 286 insertions(+), 282 deletions(-) diff --git a/devtools/client/netmonitor/test/browser_net_curl-utils.js b/devtools/client/netmonitor/test/browser_net_curl-utils.js index 1fd6c3606394..71389a26eec2 100644 --- a/devtools/client/netmonitor/test/browser_net_curl-utils.js +++ b/devtools/client/netmonitor/test/browser_net_curl-utils.js @@ -41,15 +41,10 @@ add_task(function* () { data = yield createCurlData(requests.multipart, gNetwork); testIsMultipartRequest(data); testGetMultipartBoundary(data); - testMultiPartHeaders(data); testRemoveBinaryDataFromMultipartText(data); data = yield createCurlData(requests.multipartForm, gNetwork); - testMultiPartHeaders(data); - - testGetHeadersFromMultipartText({ - postDataText: "Content-Type: text/plain\r\n\r\n", - }); + testGetHeadersFromMultipartText(data); if (Services.appinfo.OS != "WINNT") { testEscapeStringPosix(); @@ -84,14 +79,6 @@ function testFindHeader(data) { "Should return null when a header is not found."); } -function testMultiPartHeaders(data) { - let headers = data.headers; - let contentType = CurlUtils.findHeader(headers, "Content-Type"); - - ok(contentType.startsWith("multipart/form-data; boundary="), - "Multi-part content type header is present in headers array"); -} - function testWritePostDataTextParams(data) { let params = CurlUtils.writePostDataTextParams(data.postDataText); is(params, "param1=value1¶m2=value2¶m3=value3", diff --git a/devtools/client/webconsole/test/browser_webconsole_netlogging.js b/devtools/client/webconsole/test/browser_webconsole_netlogging.js index f77c88eccb8b..f22ea52003b8 100644 --- a/devtools/client/webconsole/test/browser_webconsole_netlogging.js +++ b/devtools/client/webconsole/test/browser_webconsole_netlogging.js @@ -118,19 +118,14 @@ add_task(function* testFormSubmission() { let client = hud.ui.webConsoleClient; const postData = yield client.getRequestPostData(request.actor); - const requestHeaders = yield client.getRequestHeaders(request.actor); const responseContent = yield client.getResponseContent(request.actor); - let getHeader = name => { - let header = requestHeaders.headers.find(h => h.name == name); - return header && header.value; - }; - is(request.request.method, "POST", "Method is correct"); - is(getHeader("Content-Type"), "application/x-www-form-urlencoded", - "Content-Type is correct"); - is(getHeader("Content-Length"), "20", - "Content-length is correct"); + isnot(postData.postData.text + .indexOf("Content-Type: application/x-www-form-urlencoded"), -1, + "Content-Type is correct"); + isnot(postData.postData.text + .indexOf("Content-Length: 20"), -1, "Content-length is correct"); isnot(postData.postData.text .indexOf("name=foo+bar&age=144"), -1, "Form data is correct"); is(responseContent.content.text.indexOf(""), 0, diff --git a/ipc/glue/InputStreamParams.ipdlh b/ipc/glue/InputStreamParams.ipdlh index f6de7e071461..eb6869c17028 100644 --- a/ipc/glue/InputStreamParams.ipdlh +++ b/ipc/glue/InputStreamParams.ipdlh @@ -11,12 +11,6 @@ using struct mozilla::void_t namespace mozilla { namespace ipc { -struct HeaderEntry -{ - nsCString name; - nsCString value; -}; - struct StringInputStreamParams { nsCString data; @@ -92,8 +86,10 @@ struct BufferedInputStreamParams struct MIMEInputStreamParams { OptionalInputStreamParams optionalStream; - HeaderEntry[] headers; + nsCString headers; + nsCString contentLength; bool startedReading; + bool addContentLength; }; } // namespace ipc diff --git a/netwerk/base/nsIMIMEInputStream.idl b/netwerk/base/nsIMIMEInputStream.idl index 50828ab7afe1..82992d939b2b 100644 --- a/netwerk/base/nsIMIMEInputStream.idl +++ b/netwerk/base/nsIMIMEInputStream.idl @@ -3,7 +3,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsIHttpHeaderVisitor.idl" #include "nsIInputStream.idl" /** @@ -20,10 +19,6 @@ interface nsIMIMEInputStream : nsIInputStream * using the available() method on the data stream. The value is * recalculated every time the stream is rewinded to the start. * Not allowed to be changed once the stream has been started to be read. - * - * @deprecated A Content-Length header is automatically added when - * attaching the stream to a channel, so this setting no longer has any - * effect, and may not be set to false. */ attribute boolean addContentLength; @@ -35,15 +30,6 @@ interface nsIMIMEInputStream : nsIInputStream */ void addHeader(in string name, in string value); - /** - * Visits all headers which have been added via addHeader. Calling - * addHeader while visiting request headers has undefined behavior. - * - * @param aVisitor - * The header visitor instance. - */ - void visitHeaders(in nsIHttpHeaderVisitor visitor); - /** * Sets data-stream. May not be called once the stream has been started * to be read. diff --git a/netwerk/base/nsMIMEInputStream.cpp b/netwerk/base/nsMIMEInputStream.cpp index 02c727b0be68..ce1188ea0817 100644 --- a/netwerk/base/nsMIMEInputStream.cpp +++ b/netwerk/base/nsMIMEInputStream.cpp @@ -12,19 +12,18 @@ #include "nsCOMPtr.h" #include "nsComponentManagerUtils.h" -#include "nsIHttpHeaderVisitor.h" +#include "nsIMultiplexInputStream.h" #include "nsIMIMEInputStream.h" #include "nsISeekableStream.h" +#include "nsIStringStream.h" #include "nsString.h" #include "nsMIMEInputStream.h" #include "nsIClassInfoImpl.h" #include "nsIIPCSerializableInputStream.h" -#include "mozilla/Move.h" #include "mozilla/ipc/InputStreamUtils.h" using namespace mozilla::ipc; using mozilla::Maybe; -using mozilla::Move; class nsMIMEInputStream : public nsIMIMEInputStream, public nsISeekableStream, @@ -41,6 +40,8 @@ public: NS_DECL_NSISEEKABLESTREAM NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM + nsresult Init(); + private: void InitStreams(); @@ -54,9 +55,15 @@ private: const char* aFromRawSegment, uint32_t aToOffset, uint32_t aCount, uint32_t *aWriteCount); - nsTArray mHeaders; - - nsCOMPtr mStream; + nsCString mHeaders; + nsCOMPtr mHeaderStream; + + nsCString mContentLength; + nsCOMPtr mCLStream; + + nsCOMPtr mData; + nsCOMPtr mStream; + bool mAddContentLength; bool mStartedReading; }; @@ -76,7 +83,8 @@ NS_IMPL_CI_INTERFACE_GETTER(nsMIMEInputStream, nsIInputStream, nsISeekableStream) -nsMIMEInputStream::nsMIMEInputStream() : mStartedReading(false) +nsMIMEInputStream::nsMIMEInputStream() : mAddContentLength(false), + mStartedReading(false) { } @@ -84,21 +92,40 @@ nsMIMEInputStream::~nsMIMEInputStream() { } +nsresult nsMIMEInputStream::Init() +{ + nsresult rv = NS_OK; + mStream = do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1", + &rv); + NS_ENSURE_SUCCESS(rv, rv); + + mHeaderStream = do_CreateInstance("@mozilla.org/io/string-input-stream;1", + &rv); + NS_ENSURE_SUCCESS(rv, rv); + mCLStream = do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStream->AppendStream(mHeaderStream); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStream->AppendStream(mCLStream); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + + NS_IMETHODIMP nsMIMEInputStream::GetAddContentLength(bool *aAddContentLength) { - *aAddContentLength = true; + *aAddContentLength = mAddContentLength; return NS_OK; } NS_IMETHODIMP nsMIMEInputStream::SetAddContentLength(bool aAddContentLength) { NS_ENSURE_FALSE(mStartedReading, NS_ERROR_FAILURE); - if (!aAddContentLength) { - // Content-Length is automatically added by the channel when setting the - // upload stream, so setting this to false has no practical effect. - return NS_ERROR_FAILURE; - } + mAddContentLength = aAddContentLength; return NS_OK; } @@ -106,39 +133,30 @@ NS_IMETHODIMP nsMIMEInputStream::AddHeader(const char *aName, const char *aValue) { NS_ENSURE_FALSE(mStartedReading, NS_ERROR_FAILURE); + mHeaders.Append(aName); + mHeaders.AppendLiteral(": "); + mHeaders.Append(aValue); + mHeaders.AppendLiteral("\r\n"); - HeaderEntry* entry = mHeaders.AppendElement(); - entry->name().Append(aName); - entry->value().Append(aValue); + // Just in case someone somehow uses our stream, lets at least + // let the stream have a valid pointer. The stream will be properly + // initialized in nsMIMEInputStream::InitStreams + mHeaderStream->ShareData(mHeaders.get(), 0); return NS_OK; } -NS_IMETHODIMP -nsMIMEInputStream::VisitHeaders(nsIHttpHeaderVisitor *visitor) -{ - nsresult rv; - - for (auto& header : mHeaders) { - rv = visitor->VisitHeader(header.name(), header.value()); - if (NS_FAILED(rv)) { - return rv; - } - } - return NS_OK; -} - NS_IMETHODIMP nsMIMEInputStream::SetData(nsIInputStream *aStream) { NS_ENSURE_FALSE(mStartedReading, NS_ERROR_FAILURE); + // Remove the old stream if there is one + if (mData) + mStream->RemoveStream(2); - nsCOMPtr seekable = do_QueryInterface(aStream); - if (!seekable) { - return NS_ERROR_INVALID_ARG; - } - - mStream = aStream; + mData = aStream; + if (aStream) + mStream->AppendStream(mData); return NS_OK; } @@ -146,7 +164,7 @@ NS_IMETHODIMP nsMIMEInputStream::GetData(nsIInputStream **aStream) { NS_ENSURE_ARG_POINTER(aStream); - *aStream = mStream; + *aStream = mData; NS_IF_ADDREF(*aStream); return NS_OK; } @@ -158,13 +176,28 @@ void nsMIMEInputStream::InitStreams() "Don't call initStreams twice without rewinding"); mStartedReading = true; + + // We'll use the content-length stream to add the final \r\n + if (mAddContentLength) { + uint64_t cl = 0; + if (mData) { + mData->Available(&cl); + } + mContentLength.AssignLiteral("Content-Length: "); + mContentLength.AppendInt(cl); + mContentLength.AppendLiteral("\r\n\r\n"); + } + else { + mContentLength.AssignLiteral("\r\n"); + } + mCLStream->ShareData(mContentLength.get(), -1); + mHeaderStream->ShareData(mHeaders.get(), -1); } #define INITSTREAMS \ if (!mStartedReading) { \ - NS_ENSURE_TRUE(mStream, NS_ERROR_UNEXPECTED); \ InitStreams(); \ } @@ -172,11 +205,8 @@ if (!mStartedReading) { \ NS_IMETHODIMP nsMIMEInputStream::Seek(int32_t whence, int64_t offset) { - NS_ENSURE_TRUE(mStream, NS_ERROR_UNEXPECTED); - nsresult rv; nsCOMPtr stream = do_QueryInterface(mStream); - if (whence == NS_SEEK_SET && offset == 0) { rv = stream->Seek(whence, offset); if (NS_SUCCEEDED(rv)) @@ -254,11 +284,22 @@ nsMIMEInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result) if (outer) return NS_ERROR_NO_AGGREGATION; - RefPtr inst = new nsMIMEInputStream(); + nsMIMEInputStream *inst = new nsMIMEInputStream(); if (!inst) return NS_ERROR_OUT_OF_MEMORY; - return inst->QueryInterface(iid, result); + NS_ADDREF(inst); + + nsresult rv = inst->Init(); + if (NS_FAILED(rv)) { + NS_RELEASE(inst); + return rv; + } + + rv = inst->QueryInterface(iid, result); + NS_RELEASE(inst); + + return rv; } void @@ -267,9 +308,12 @@ nsMIMEInputStream::Serialize(InputStreamParams& aParams, { MIMEInputStreamParams params; - if (mStream) { + if (mData) { + nsCOMPtr stream = do_QueryInterface(mData); + MOZ_ASSERT(stream); + InputStreamParams wrappedParams; - SerializeInputStream(mStream, wrappedParams, aFileDescriptors); + SerializeInputStream(stream, wrappedParams, aFileDescriptors); NS_ASSERTION(wrappedParams.type() != InputStreamParams::T__None, "Wrapped stream failed to serialize!"); @@ -281,7 +325,9 @@ nsMIMEInputStream::Serialize(InputStreamParams& aParams, } params.headers() = mHeaders; + params.contentLength() = mContentLength; params.startedReading() = mStartedReading; + params.addContentLength() = mAddContentLength; aParams = params; } @@ -300,10 +346,17 @@ nsMIMEInputStream::Deserialize(const InputStreamParams& aParams, const OptionalInputStreamParams& wrappedParams = params.optionalStream(); mHeaders = params.headers(); + mContentLength = params.contentLength(); mStartedReading = params.startedReading(); + // nsMIMEInputStream::Init() already appended mHeaderStream & mCLStream + mHeaderStream->ShareData(mHeaders.get(), + mStartedReading ? mHeaders.Length() : 0); + mCLStream->ShareData(mContentLength.get(), + mStartedReading ? mContentLength.Length() : 0); + + nsCOMPtr stream; if (wrappedParams.type() == OptionalInputStreamParams::TInputStreamParams) { - nsCOMPtr stream; stream = DeserializeInputStream(wrappedParams.get_InputStreamParams(), aFileDescriptors); if (!stream) { @@ -311,13 +364,20 @@ nsMIMEInputStream::Deserialize(const InputStreamParams& aParams, return false; } - mStream = stream; + mData = stream; + + if (NS_FAILED(mStream->AppendStream(mData))) { + NS_WARNING("Failed to append stream!"); + return false; + } } else { NS_ASSERTION(wrappedParams.type() == OptionalInputStreamParams::Tvoid_t, "Unknown type for OptionalInputStreamParams!"); } + mAddContentLength = params.addContentLength(); + return true; } diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 5646c41146ea..210a6ab58736 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -52,9 +52,7 @@ #include "nsIURL.h" #include "nsIConsoleService.h" #include "mozilla/BinarySearch.h" -#include "mozilla/DebugOnly.h" #include "nsIHttpHeaderVisitor.h" -#include "nsIMIMEInputStream.h" #include "nsIXULRuntime.h" #include "nsICacheInfoChannel.h" #include "nsIDOMWindowUtils.h" @@ -65,85 +63,6 @@ namespace mozilla { namespace net { -static -bool IsHeaderBlacklistedForRedirectCopy(nsHttpAtom const& aHeader) -{ - // IMPORTANT: keep this list ASCII-code sorted - static nsHttpAtom const* blackList[] = { - &nsHttp::Accept, - &nsHttp::Accept_Encoding, - &nsHttp::Accept_Language, - &nsHttp::Authentication, - &nsHttp::Authorization, - &nsHttp::Connection, - &nsHttp::Content_Length, - &nsHttp::Cookie, - &nsHttp::Host, - &nsHttp::If, - &nsHttp::If_Match, - &nsHttp::If_Modified_Since, - &nsHttp::If_None_Match, - &nsHttp::If_None_Match_Any, - &nsHttp::If_Range, - &nsHttp::If_Unmodified_Since, - &nsHttp::Proxy_Authenticate, - &nsHttp::Proxy_Authorization, - &nsHttp::Range, - &nsHttp::TE, - &nsHttp::Transfer_Encoding, - &nsHttp::Upgrade, - &nsHttp::User_Agent, - &nsHttp::WWW_Authenticate - }; - - class HttpAtomComparator - { - nsHttpAtom const& mTarget; - public: - explicit HttpAtomComparator(nsHttpAtom const& aTarget) - : mTarget(aTarget) {} - int operator()(nsHttpAtom const* aVal) const { - if (mTarget == *aVal) { - return 0; - } - return strcmp(mTarget._val, aVal->_val); - } - }; - - size_t unused; - return BinarySearchIf(blackList, 0, ArrayLength(blackList), - HttpAtomComparator(aHeader), &unused); -} - -class AddHeadersToChannelVisitor final : public nsIHttpHeaderVisitor -{ -public: - NS_DECL_ISUPPORTS - - explicit AddHeadersToChannelVisitor(nsIHttpChannel *aChannel) - : mChannel(aChannel) - { - } - - NS_IMETHOD VisitHeader(const nsACString& aHeader, - const nsACString& aValue) override - { - nsHttpAtom atom = nsHttp::ResolveAtom(aHeader); - if (!IsHeaderBlacklistedForRedirectCopy(atom)) { - mChannel->SetRequestHeader(aHeader, aValue, false); - } - return NS_OK; - } -private: - ~AddHeadersToChannelVisitor() - { - } - - nsCOMPtr mChannel; -}; - -NS_IMPL_ISUPPORTS(AddHeadersToChannelVisitor, nsIHttpHeaderVisitor) - HttpBaseChannel::HttpBaseChannel() : mStartPos(UINT64_MAX) , mStatus(NS_OK) @@ -734,38 +653,22 @@ HttpBaseChannel::SetUploadStream(nsIInputStream *stream, if (stream) { nsAutoCString method; - bool hasHeaders = false; + bool hasHeaders; // This method and ExplicitSetUploadStream mean different things by "empty // content type string". This method means "no header", but // ExplicitSetUploadStream means "header with empty value". So we have to // massage the contentType argument into the form ExplicitSetUploadStream // expects. - nsCOMPtr mimeStream; - nsCString contentType(contentTypeArg); - if (contentType.IsEmpty()) { - contentType.SetIsVoid(true); + nsAutoCString contentType; + if (contentTypeArg.IsEmpty()) { method = NS_LITERAL_CSTRING("POST"); - - // MIME streams are a special case, and include headers which need to be - // copied to the channel. - mimeStream = do_QueryInterface(stream); - if (mimeStream) { - // Copy non-origin related headers to the channel. - nsCOMPtr visitor = - new AddHeadersToChannelVisitor(this); - mimeStream->VisitHeaders(visitor); - - return ExplicitSetUploadStream(stream, contentType, contentLength, - method, hasHeaders); - } - hasHeaders = true; + contentType.SetIsVoid(true); } else { method = NS_LITERAL_CSTRING("PUT"); - - MOZ_ASSERT(NS_FAILED(CallQueryInterface(stream, getter_AddRefs(mimeStream))), - "nsIMIMEInputStream should not be set with an explicit content type"); + hasHeaders = false; + contentType = contentTypeArg; } return ExplicitSetUploadStream(stream, contentType, contentLength, method, hasHeaders); @@ -907,13 +810,6 @@ HttpBaseChannel::ExplicitSetUploadStream(nsIInputStream *aStream, // Ensure stream is set and method is valid NS_ENSURE_TRUE(aStream, NS_ERROR_FAILURE); - { - DebugOnly> mimeStream; - MOZ_ASSERT(!aStreamHasHeaders || - NS_FAILED(CallQueryInterface(aStream, getter_AddRefs(mimeStream.value))), - "nsIMIMEInputStream should not include headers"); - } - if (aContentLength < 0 && !aStreamHasHeaders) { nsresult rv = aStream->Available(reinterpret_cast(&aContentLength)); if (NS_FAILED(rv) || aContentLength < 0) { @@ -2997,6 +2893,85 @@ HttpBaseChannel::ShouldRewriteRedirectToGET(uint32_t httpStatus, return false; } +static +bool IsHeaderBlacklistedForRedirectCopy(nsHttpAtom const& aHeader) +{ + // IMPORTANT: keep this list ASCII-code sorted + static nsHttpAtom const* blackList[] = { + &nsHttp::Accept, + &nsHttp::Accept_Encoding, + &nsHttp::Accept_Language, + &nsHttp::Authentication, + &nsHttp::Authorization, + &nsHttp::Connection, + &nsHttp::Content_Length, + &nsHttp::Cookie, + &nsHttp::Host, + &nsHttp::If, + &nsHttp::If_Match, + &nsHttp::If_Modified_Since, + &nsHttp::If_None_Match, + &nsHttp::If_None_Match_Any, + &nsHttp::If_Range, + &nsHttp::If_Unmodified_Since, + &nsHttp::Proxy_Authenticate, + &nsHttp::Proxy_Authorization, + &nsHttp::Range, + &nsHttp::TE, + &nsHttp::Transfer_Encoding, + &nsHttp::Upgrade, + &nsHttp::User_Agent, + &nsHttp::WWW_Authenticate + }; + + class HttpAtomComparator + { + nsHttpAtom const& mTarget; + public: + explicit HttpAtomComparator(nsHttpAtom const& aTarget) + : mTarget(aTarget) {} + int operator()(nsHttpAtom const* aVal) const { + if (mTarget == *aVal) { + return 0; + } + return strcmp(mTarget._val, aVal->_val); + } + }; + + size_t unused; + return BinarySearchIf(blackList, 0, ArrayLength(blackList), + HttpAtomComparator(aHeader), &unused); +} + +class SetupReplacementChannelHeaderVisitor final : public nsIHttpHeaderVisitor +{ +public: + NS_DECL_ISUPPORTS + + explicit SetupReplacementChannelHeaderVisitor(nsIHttpChannel *aChannel) + : mChannel(aChannel) + { + } + + NS_IMETHOD VisitHeader(const nsACString& aHeader, + const nsACString& aValue) override + { + nsHttpAtom atom = nsHttp::ResolveAtom(aHeader); + if (!IsHeaderBlacklistedForRedirectCopy(atom)) { + mChannel->SetRequestHeader(aHeader, aValue, false); + } + return NS_OK; + } +private: + ~SetupReplacementChannelHeaderVisitor() + { + } + + nsCOMPtr mChannel; +}; + +NS_IMPL_ISUPPORTS(SetupReplacementChannelHeaderVisitor, nsIHttpHeaderVisitor) + nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI, nsIChannel *newChannel, @@ -3292,7 +3267,7 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI, nsIChannelEventSink::REDIRECT_STS_UPGRADE)) { // Copy non-origin related headers to the new channel. nsCOMPtr visitor = - new AddHeadersToChannelVisitor(httpChannel); + new SetupReplacementChannelHeaderVisitor(httpChannel); mRequestHead.VisitHeaders(visitor); } diff --git a/netwerk/test/browser/browser_nsIFormPOSTActionChannel.js b/netwerk/test/browser/browser_nsIFormPOSTActionChannel.js index c8fbb87872b7..150c4feca9b5 100644 --- a/netwerk/test/browser/browser_nsIFormPOSTActionChannel.js +++ b/netwerk/test/browser/browser_nsIFormPOSTActionChannel.js @@ -149,23 +149,15 @@ document.getElementById('form').submit(); `; } else if (this.uri.spec.startsWith(ACTION_BASE)) { var postData = ""; - var headers = {}; if (this._uploadStream) { var bstream = Cc["@mozilla.org/binaryinputstream;1"] .createInstance(Ci.nsIBinaryInputStream); bstream.setInputStream(this._uploadStream); postData = bstream.readBytes(bstream.available()); - - if (this._uploadStream instanceof Ci.nsIMIMEInputStream) { - this._uploadStream.visitHeaders((name, value) => { - headers[name] = value; - }); - } } data += ` - `; } @@ -222,9 +214,8 @@ function frameScript() { if (frame) { var upload_stream = frame.contentDocument.getElementById("upload_stream"); var post_data = frame.contentDocument.getElementById("post_data"); - var headers = frame.contentDocument.getElementById("upload_headers"); - if (upload_stream && post_data && headers) { - sendAsyncMessage("Test:IFrameLoaded", [upload_stream.value, post_data.value, headers.value]); + if (upload_stream && post_data) { + sendAsyncMessage("Test:IFrameLoaded", [upload_stream.value, post_data.value]); return; } } @@ -245,9 +236,9 @@ function loadTestTab(uri) { browser.messageManager.loadFrameScript("data:,(" + frameScript.toString() + ")();", true); return new Promise(resolve => { - function listener({ data: [hasUploadStream, postData, headers] }) { + function listener({ data: [hasUploadStream, postData] }) { manager.removeMessageListener("Test:IFrameLoaded", listener); - resolve([hasUploadStream, atob(postData), JSON.parse(headers)]); + resolve([hasUploadStream, atob(postData)]); } manager.addMessageListener("Test:IFrameLoaded", listener); @@ -281,14 +272,13 @@ add_task(function*() { }); add_task(function*() { - var [hasUploadStream, postData, headers] = yield loadTestTab(POST_FORM_URI); - + var [hasUploadStream, postData] = yield loadTestTab(POST_FORM_URI); is(hasUploadStream, "yes", "post action should have uploadStream"); - is(postData, "foo=bar\r\n", - "POST data is received correctly"); - - is(headers["Content-Type"], "text/plain", "Content-Type header is correct"); - is(headers["Content-Length"], undefined, "Content-Length header is correct"); + is(postData, + "Content-Type: text/plain\r\n" + + "Content-Length: 9\r\n" + + "\r\n" + + "foo=bar\r\n", "POST data is received correctly"); gBrowser.removeCurrentTab(); }); diff --git a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html index 174f40da39ca..998ab9800378 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html @@ -69,13 +69,14 @@ add_task(function* test_setup() { function background() { const FILTERS = {urls: [""]}; + let requestBodySupported = true; + function onUpload(details) { let url = new URL(details.url); let upload = url.searchParams.get("upload"); - if (!upload) { + if (!upload || !requestBodySupported) { return; } - let requestBody = details.requestBody; browser.test.log(`onBeforeRequest upload: ${details.url} ${JSON.stringify(details.requestBody)}`); browser.test.assertTrue(!!requestBody, `Intercepted upload ${details.url} #${details.requestId} ${upload} have a requestBody`); @@ -109,8 +110,21 @@ function background() { onUpload(details); }; - browser.webRequest.onBeforeRequest.addListener( - onBeforeRequest, FILTERS, ["requestBody"]); + try { + browser.webRequest.onBeforeRequest.addListener( + onBeforeRequest, FILTERS, ["requestBody"]); + } catch (e) { + browser.test.assertTrue(/\brequestBody\b/.test(e.message), + "Request body is unsupported"); + + // requestBody is disabled in release builds + if (!/\brequestBody\b/.test(e.message)) { + throw e; + } + + browser.webRequest.onBeforeRequest.addListener( + onBeforeRequest, FILTERS); + } } add_task(function* test_xhr_forms() { diff --git a/toolkit/components/remotebrowserutils/RemoteWebNavigation.js b/toolkit/components/remotebrowserutils/RemoteWebNavigation.js index bd578d26bd70..e6226db0d8d7 100644 --- a/toolkit/components/remotebrowserutils/RemoteWebNavigation.js +++ b/toolkit/components/remotebrowserutils/RemoteWebNavigation.js @@ -18,19 +18,8 @@ function makeURI(url) { return Services.io.newURI(url); } -function serializeInputStream(aStream) { - let data = { - content: NetUtil.readInputStreamToString(aStream, aStream.available()), - }; - - if (aStream instanceof Ci.nsIMIMEInputStream) { - data.headers = new Map(); - aStream.visitHeaders((name, value) => { - data.headers.set(name, value); - }); - } - - return data; +function readInputStreamToString(aStream) { + return NetUtil.readInputStreamToString(aStream, aStream.available()); } function RemoteWebNavigation() { @@ -92,8 +81,8 @@ RemoteWebNavigation.prototype = { flags: aLoadFlags, referrer: aReferrer ? aReferrer.spec : null, referrerPolicy: aReferrerPolicy, - postData: aPostData ? serializeInputStream(aPostData) : null, - headers: aHeaders ? serializeInputStream(aHeaders) : null, + postData: aPostData ? readInputStreamToString(aPostData) : null, + headers: aHeaders ? readInputStreamToString(aHeaders) : null, baseURI: aBaseURI ? aBaseURI.spec : null, triggeringPrincipal: aTriggeringPrincipal ? Utils.serializePrincipal(aTriggeringPrincipal) diff --git a/toolkit/content/browser-child.js b/toolkit/content/browser-child.js index 5f3b71945c38..78d30a21a24b 100644 --- a/toolkit/content/browser-child.js +++ b/toolkit/content/browser-child.js @@ -26,22 +26,10 @@ if (AppConstants.MOZ_CRASHREPORTER) { "nsICrashReporter"); } -function makeInputStream(data) { +function makeInputStream(aString) { let stream = Cc["@mozilla.org/io/string-input-stream;1"]. createInstance(Ci.nsISupportsCString); - stream.data = data.content; - - if (data.headers) { - let mimeStream = Cc["@mozilla.org/network/mime-input-stream;1"] - .createInstance(Ci.nsIMIMEInputStream); - - mimeStream.setData(stream); - for (let [name, value] of data.headers) { - mimeStream.addHeader(name, value); - } - return mimeStream; - } - + stream.data = aString; return stream; // XPConnect will QI this to nsIInputStream for us. } diff --git a/toolkit/modules/addons/WebRequest.jsm b/toolkit/modules/addons/WebRequest.jsm index 6a9c395f1ed2..709d720cd0e8 100644 --- a/toolkit/modules/addons/WebRequest.jsm +++ b/toolkit/modules/addons/WebRequest.jsm @@ -19,6 +19,8 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "AppConstants", + "resource://gre/modules/AppConstants.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ExtensionUtils", @@ -855,8 +857,14 @@ HttpObserverManager = { }; var onBeforeRequest = { - allowedOptions: ["blocking", "requestBody"], - + get allowedOptions() { + delete this.allowedOptions; + this.allowedOptions = ["blocking"]; + if (!AppConstants.RELEASE_OR_BETA) { + this.allowedOptions.push("requestBody"); + } + return this.allowedOptions; + }, addListener(callback, filter = null, opt_extraInfoSpec = null) { let opts = parseExtra(opt_extraInfoSpec, this.allowedOptions); opts.filter = parseFilter(filter); diff --git a/toolkit/modules/addons/WebRequestUpload.jsm b/toolkit/modules/addons/WebRequestUpload.jsm index 280f7868e606..0569221b28ff 100644 --- a/toolkit/modules/addons/WebRequestUpload.jsm +++ b/toolkit/modules/addons/WebRequestUpload.jsm @@ -368,11 +368,31 @@ function parseFormData(stream, channel, lenient = false) { } try { + let headers; if (stream instanceof Ci.nsIMIMEInputStream && stream.data) { + // MIME input streams encode additional headers as a block at the + // beginning of their stream. The actual request data comes from a + // sub-stream, which is accessible via their `data` member. The + // difference in available bytes between the outer stream and the + // inner data stream tells us the size of that header block. + // + // Since we need to know at least the value of the Content-Type + // header to properly parse the request body, we need to read and + // parse the header block in order to extract it. + + headers = readString(createTextStream(stream), + stream.available() - stream.data.available()); + + rewind(stream); stream = stream.data; } - let contentType = channel.getRequestHeader("Content-Type"); + let contentType; + try { + contentType = channel.getRequestHeader("Content-Type"); + } catch (e) { + contentType = new Headers(headers).get("content-type"); + } switch (Headers.getParam(contentType, "")) { case "multipart/form-data": @@ -482,33 +502,29 @@ function* getRawDataChunked(outerStream, maxRead = WebRequestUpload.MAX_RAW_BYTE WebRequestUpload = { createRequestBody(channel) { - if (!(channel instanceof Ci.nsIUploadChannel) || !channel.uploadStream) { - return null; - } + if (channel instanceof Ci.nsIUploadChannel && channel.uploadStream) { + try { + let stream = channel.uploadStream; - if (channel instanceof Ci.nsIUploadChannel2 && channel.uploadStreamHasHeaders) { - return {error: "Upload streams with headers are unsupported"}; - } + let formData = createFormData(stream, channel); + if (formData) { + return {formData}; + } - try { - let stream = channel.uploadStream; - - let formData = createFormData(stream, channel); - if (formData) { - return {formData}; + // If we failed to parse the stream as form data, return it as a + // sequence of raw data chunks, along with a leniently-parsed form + // data object, which ignores encoding errors. + return { + raw: Array.from(getRawDataChunked(stream)), + lenientFormData: createFormData(stream, channel, true), + }; + } catch (e) { + Cu.reportError(e); + return {error: e.message || String(e)}; } - - // If we failed to parse the stream as form data, return it as a - // sequence of raw data chunks, along with a leniently-parsed form - // data object, which ignores encoding errors. - return { - raw: Array.from(getRawDataChunked(stream)), - lenientFormData: createFormData(stream, channel, true), - }; - } catch (e) { - Cu.reportError(e); - return {error: e.message || String(e)}; } + + return null; }, }; From 88345f4996f8ca09440e0df7c5e66fdc674f0f22 Mon Sep 17 00:00:00 2001 From: Bob Clary Date: Sat, 21 Jan 2017 09:49:56 -0800 Subject: [PATCH 59/67] Bug 1328301 - handle push/pull directory semantics changes in adb 1.0.36 for adb.py, r=gbrown. --- testing/mozbase/mozdevice/mozdevice/adb.py | 88 ++++++++++++++++++++-- 1 file changed, 81 insertions(+), 7 deletions(-) diff --git a/testing/mozbase/mozdevice/mozdevice/adb.py b/testing/mozbase/mozdevice/mozdevice/adb.py index 41acdf548d2e..4a2e5d9bb8e6 100644 --- a/testing/mozbase/mozdevice/mozdevice/adb.py +++ b/testing/mozbase/mozdevice/mozdevice/adb.py @@ -5,12 +5,14 @@ import os import posixpath import re +import shutil import subprocess import tempfile import time import traceback from abc import ABCMeta, abstractmethod +from distutils import dir_util class ADBProcess(object): @@ -149,15 +151,19 @@ class ADBCommand(object): self._adb_port = adb_port self._timeout = timeout self._polling_interval = 0.1 + self._adb_version = '' self._logger.debug("%s: %s" % (self.__class__.__name__, self.__dict__)) # catch early a missing or non executable adb command + # and get the adb version while we are at it. try: - subprocess.Popen([adb, 'help'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE).communicate() + output = subprocess.Popen([adb, 'version'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate() + re_version = re.compile(r'Android Debug Bridge version (.*)') + self._adb_version = re_version.match(output[0]).group(1) except Exception as exc: raise ADBError('%s: %s is not executable.' % (exc, adb)) @@ -1718,8 +1724,42 @@ class ADBDevice(ADBCommand): :raises: * ADBTimeoutError * ADBError """ - self.command_output(["push", os.path.realpath(local), remote], - timeout=timeout) + # remove trailing / + local = os.path.normpath(local) + remote = os.path.normpath(remote) + copy_required = False + if self._adb_version >= '1.0.36' and \ + os.path.isdir(local) and self.is_dir(remote): + # See do_sync_push in + # https://android.googlesource.com/platform/system/core/+/master/adb/file_sync_client.cpp + # Work around change in behavior in adb 1.0.36 where if + # the remote destination directory exists, adb push will + # copy the source directory *into* the destination + # directory otherwise it will copy the source directory + # *onto* the destination directory. + # + # If the destination directory does exist, push to its + # parent directory. If the source and destination leaf + # directory names are different, copy the source directory + # to a temporary directory with the same leaf name as the + # destination so that when we push to the parent, the + # source is copied onto the destination directory. + local_name = os.path.basename(local) + remote_name = os.path.basename(remote) + if local_name != remote_name: + copy_required = True + temp_parent = tempfile.mkdtemp() + new_local = os.path.join(temp_parent, remote_name) + dir_util.copy_tree(local, new_local) + local = new_local + remote = '/'.join(remote.rstrip('/').split('/')[:-1]) + try: + self.command_output(["push", local, remote], timeout=timeout) + except: + raise + finally: + if copy_required: + shutil.rmtree(temp_parent) def pull(self, remote, local, timeout=None): """Pulls a file or directory from the device. @@ -1738,8 +1778,42 @@ class ADBDevice(ADBCommand): :raises: * ADBTimeoutError * ADBError """ - self.command_output(["pull", remote, os.path.realpath(local)], - timeout=timeout) + # remove trailing / + local = os.path.normpath(local) + remote = os.path.normpath(remote) + copy_required = False + original_local = local + if self._adb_version >= '1.0.36' and \ + os.path.isdir(local) and self.is_dir(remote): + # See do_sync_pull in + # https://android.googlesource.com/platform/system/core/+/master/adb/file_sync_client.cpp + # Work around change in behavior in adb 1.0.36 where if + # the local destination directory exists, adb pull will + # copy the source directory *into* the destination + # directory otherwise it will copy the source directory + # *onto* the destination directory. + # + # If the destination directory does exist, pull to its + # parent directory. If the source and destination leaf + # directory names are different, pull the source directory + # into a temporary directory and then copy the temporary + # directory onto the destination. + local_name = os.path.basename(local) + remote_name = os.path.basename(remote) + if local_name != remote_name: + copy_required = True + temp_parent = tempfile.mkdtemp() + local = os.path.join(temp_parent, remote_name) + else: + local = '/'.join(local.rstrip('/').split('/')[:-1]) + try: + self.command_output(["pull", remote, local], timeout=timeout) + except: + raise + finally: + if copy_required: + dir_util.copy_tree(local, original_local) + shutil.rmtree(temp_parent) def rm(self, path, recursive=False, force=False, timeout=None, root=False): """Delete files or directories on the device. From 2d71f2717394d9f9fcc549726d65e8ecd30927a8 Mon Sep 17 00:00:00 2001 From: Bob Clary Date: Sat, 21 Jan 2017 09:49:56 -0800 Subject: [PATCH 60/67] Bug 1328301 - handle push/pull directory semantics changes in adb 1.0.36 for devicemanagerADB, r=gbrown --- .../mozdevice/mozdevice/devicemanagerADB.py | 87 ++++++++++++++++--- 1 file changed, 73 insertions(+), 14 deletions(-) diff --git a/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py b/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py index 538c76cefce6..bdd6b2e3c120 100644 --- a/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py +++ b/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py @@ -5,11 +5,12 @@ import logging import re import os -import shutil import tempfile import time import traceback +from distutils import dir_util + from devicemanager import DeviceManager, DMError from mozprocess import ProcessHandler import mozfile @@ -32,6 +33,7 @@ class DeviceManagerADB(DeviceManager): _pollingInterval = 0.01 _packageName = None _tempDir = None + _adb_version = None connected = False def __init__(self, host=None, port=5555, retryLimit=5, packageName='fennec', @@ -271,18 +273,42 @@ class DeviceManagerADB(DeviceManager): self._useZip = False self.pushDir(localDir, remoteDir, retryLimit=retryLimit, timeout=timeout) else: - # If the remote directory exists, newer implementations of - # "adb push" will create a sub-directory, while older versions - # will not! Bug 1285040 - self.mkDirs(remoteDir + "/x") - self.removeDir(remoteDir) - tmpDir = tempfile.mkdtemp() - # copytree's target dir must not already exist, so create a subdir - tmpDirTarget = os.path.join(tmpDir, "tmp") - shutil.copytree(localDir, tmpDirTarget) - self._checkCmd(["push", tmpDirTarget, remoteDir], - retryLimit=retryLimit, timeout=timeout) - mozfile.remove(tmpDir) + localDir = os.path.normpath(localDir) + remoteDir = os.path.normpath(remoteDir) + copyRequired = False + if self._adb_version >= '1.0.36' and \ + os.path.isdir(localDir) and self.dirExists(remoteDir): + # See do_sync_push in + # https://android.googlesource.com/platform/system/core/+/master/adb/file_sync_client.cpp + # Work around change in behavior in adb 1.0.36 where if + # the remote destination directory exists, adb push will + # copy the source directory *into* the destination + # directory otherwise it will copy the source directory + # *onto* the destination directory. + # + # If the destination directory does exist, push to its + # parent directory. If the source and destination leaf + # directory names are different, copy the source directory + # to a temporary directory with the same leaf name as the + # destination so that when we push to the parent, the + # source is copied onto the destination directory. + localName = os.path.basename(localDir) + remoteName = os.path.basename(remoteDir) + if localName != remoteName: + copyRequired = True + tempParent = tempfile.mkdtemp() + newLocal = os.path.join(tempParent, remoteName) + dir_util.copy_tree(localDir, newLocal) + localDir = newLocal + remoteDir = '/'.join(remoteDir.rstrip('/').split('/')[:-1]) + try: + self._checkCmd(["push", localDir, remoteDir], + retryLimit=retryLimit, timeout=timeout) + except: + raise + finally: + if copyRequired: + mozfile.remove(tempParent) def dirExists(self, remotePath): self._detectLsModifier() @@ -464,7 +490,37 @@ class DeviceManagerADB(DeviceManager): self._runPull(remoteFile, localFile) def getDirectory(self, remoteDir, localDir, checkDir=True): + localDir = os.path.normpath(localDir) + remoteDir = os.path.normpath(remoteDir) + copyRequired = False + originalLocal = localDir + if self._adb_version >= '1.0.36' and \ + os.path.isdir(localDir) and self.dirExists(remoteDir): + # See do_sync_pull in + # https://android.googlesource.com/platform/system/core/+/master/adb/file_sync_client.cpp + # Work around change in behavior in adb 1.0.36 where if + # the local destination directory exists, adb pull will + # copy the source directory *into* the destination + # directory otherwise it will copy the source directory + # *onto* the destination directory. + # + # If the destination directory does exist, pull to its + # parent directory. If the source and destination leaf + # directory names are different, pull the source directory + # into a temporary directory and then copy the temporary + # directory onto the destination. + localName = os.path.basename(localDir) + remoteName = os.path.basename(remoteDir) + if localName != remoteName: + copyRequired = True + tempParent = tempfile.mkdtemp() + localDir = os.path.join(tempParent, remoteName) + else: + localDir = '/'.join(localDir.rstrip('/').split('/')[:-1]) self._runCmd(["pull", remoteDir, localDir]).wait() + if copyRequired: + dir_util.copy_tree(localDir, originalLocal) + mozfile.remove(tempParent) def validateFile(self, remoteFile, localFile): md5Remote = self._getRemoteHash(remoteFile) @@ -682,7 +738,10 @@ class DeviceManagerADB(DeviceManager): raise DMError("invalid adb path, or adb not executable: %s" % self._adbPath) try: - self._checkCmd(["version"], timeout=self.short_timeout) + proc = self._runCmd(["version"], timeout=self.short_timeout) + re_version = re.compile(r'Android Debug Bridge version (.*)') + self._adb_version = re_version.match(proc.output[0]).group(1) + self._logger.info("Detected adb %s", self._adb_version) except os.error as err: raise DMError( "unable to execute ADB (%s): ensure Android SDK is installed " From c3744b0594817a132e29309eac65dc368f0586cf Mon Sep 17 00:00:00 2001 From: Sheldon Roddick Date: Sat, 21 Jan 2017 11:25:11 -0700 Subject: [PATCH 61/67] Bug 1332085 - Add Color Name field to Color Widget. r=gl --- .../locales/en-US/colorwidget.properties | 11 ++ devtools/client/shared/test/browser.ini | 1 + .../shared/test/browser_color-widget-01.js | 132 ++++++++++++++++++ devtools/client/shared/widgets/ColorWidget.js | 18 +++ .../server/actors/highlighters/eye-dropper.js | 7 +- devtools/shared/css/color.js | 25 ++-- 6 files changed, 172 insertions(+), 22 deletions(-) create mode 100644 devtools/client/locales/en-US/colorwidget.properties create mode 100644 devtools/client/shared/test/browser_color-widget-01.js diff --git a/devtools/client/locales/en-US/colorwidget.properties b/devtools/client/locales/en-US/colorwidget.properties new file mode 100644 index 000000000000..d4d66fa21867 --- /dev/null +++ b/devtools/client/locales/en-US/colorwidget.properties @@ -0,0 +1,11 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# LOCALIZATION NOTE These strings are used in the CSS Color Editor Widget +# which can be found in a tooltip that appears in the Rules View when clicking +# on a color swatch displayed next to CSS declarations like 'color: #FFF'. + +# LOCALIZATION NOTE (colorNameLabel): The label for the current color +# widget's color name field +colorNameLabel=Color Name: diff --git a/devtools/client/shared/test/browser.ini b/devtools/client/shared/test/browser.ini index ad3f52fbdcb0..19bb55d76eea 100644 --- a/devtools/client/shared/test/browser.ini +++ b/devtools/client/shared/test/browser.ini @@ -25,6 +25,7 @@ support-files = [browser_css_angle.js] [browser_css_color.js] +[browser_color-widget-01.js] [browser_cubic-bezier-01.js] [browser_cubic-bezier-02.js] [browser_cubic-bezier-03.js] diff --git a/devtools/client/shared/test/browser_color-widget-01.js b/devtools/client/shared/test/browser_color-widget-01.js new file mode 100644 index 000000000000..70abab99e54f --- /dev/null +++ b/devtools/client/shared/test/browser_color-widget-01.js @@ -0,0 +1,132 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests that the color widget color picker works correctly. + +const {ColorWidget} = require("devtools/client/shared/widgets/ColorWidget.js"); + +const TEST_URI = `data:text/html, + +
`; + +add_task(function* () { + let [host,, doc] = yield createHost("bottom", TEST_URI); + + let container = doc.getElementById("color-widget-container"); + + yield testCreateAndDestroyShouldAppendAndRemoveElements(container); + yield testPassingAColorAtInitShouldSetThatColor(container); + yield testSettingAndGettingANewColor(container); + yield testChangingColorShouldEmitEvents(container); + yield testSettingColorShoudUpdateTheUI(container); + yield testChangingColorShouldUpdateColorNameDisplay(container); + + host.destroy(); +}); + +function testCreateAndDestroyShouldAppendAndRemoveElements(container) { + ok(container, "We have the root node to append ColorWidget to"); + is(container.childElementCount, 0, "Root node is empty"); + + let s = new ColorWidget(container, [255, 126, 255, 1]); + s.show(); + ok(container.childElementCount > 0, "ColorWidget has appended elements"); + + s.destroy(); + is(container.childElementCount, 0, "Destroying ColorWidget removed all nodes"); +} + +function testPassingAColorAtInitShouldSetThatColor(container) { + let initRgba = [255, 126, 255, 1]; + + let s = new ColorWidget(container, initRgba); + s.show(); + + let setRgba = s.rgb; + + is(initRgba[0], setRgba[0], "ColorWidget initialized with the right color"); + is(initRgba[1], setRgba[1], "ColorWidget initialized with the right color"); + is(initRgba[2], setRgba[2], "ColorWidget initialized with the right color"); + is(initRgba[3], setRgba[3], "ColorWidget initialized with the right color"); + + s.destroy(); +} + +function testSettingAndGettingANewColor(container) { + let s = new ColorWidget(container, [0, 0, 0, 1]); + s.show(); + + let colorToSet = [255, 255, 255, 1]; + s.rgb = colorToSet; + let newColor = s.rgb; + + is(colorToSet[0], newColor[0], "ColorWidget set with the right color"); + is(colorToSet[1], newColor[1], "ColorWidget set with the right color"); + is(colorToSet[2], newColor[2], "ColorWidget set with the right color"); + is(colorToSet[3], newColor[3], "ColorWidget set with the right color"); + + s.destroy(); +} + +function testChangingColorShouldEmitEvents(container) { + return new Promise(resolve => { + let s = new ColorWidget(container, [255, 255, 255, 1]); + s.show(); + + s.once("changed", (event, rgba, color) => { + ok(true, "Changed event was emitted on color change"); + is(rgba[0], 128, "New color is correct"); + is(rgba[1], 64, "New color is correct"); + is(rgba[2], 64, "New color is correct"); + is(rgba[3], 1, "New color is correct"); + is(`rgba(${rgba.join(", ")})`, color, "RGBA and css color correspond"); + + s.destroy(); + resolve(); + }); + + // Simulate a drag move event by calling the handler directly. + s.onDraggerMove(s.dragger.offsetWidth / 2, s.dragger.offsetHeight / 2); + }); +} + +function testSettingColorShoudUpdateTheUI(container) { + let s = new ColorWidget(container, [255, 255, 255, 1]); + s.show(); + let dragHelperOriginalPos = [s.dragHelper.style.top, s.dragHelper.style.left]; + let alphaHelperOriginalPos = s.alphaSliderHelper.style.left; + + s.rgb = [50, 240, 234, .2]; + s.updateUI(); + + ok(s.alphaSliderHelper.style.left != alphaHelperOriginalPos, "Alpha helper has moved"); + ok(s.dragHelper.style.top !== dragHelperOriginalPos[0], "Drag helper has moved"); + ok(s.dragHelper.style.left !== dragHelperOriginalPos[1], "Drag helper has moved"); + + s.rgb = [240, 32, 124, 0]; + s.updateUI(); + is(s.alphaSliderHelper.style.left, -(s.alphaSliderHelper.offsetWidth / 2) + "px", + "Alpha range UI has been updated again"); + + s.destroy(); +} + +function testChangingColorShouldUpdateColorNameDisplay(container) { + let s = new ColorWidget(container, [255, 255, 255, 1]); + s.show(); + s.updateUI(); + is(s.colorName.textContent, "white", "Color Name should be white"); + + s.rgb = [0, 0, 0, 1]; + s.updateUI(); + is(s.colorName.textContent, "black", "Color Name should be black"); + + s.rgb = [0, 0, 1, 1]; + s.updateUI(); + is(s.colorName.textContent, "---", "Color Name should be ---"); + + s.destroy(); +} diff --git a/devtools/client/shared/widgets/ColorWidget.js b/devtools/client/shared/widgets/ColorWidget.js index ba705e6e1680..057a6a8c3433 100644 --- a/devtools/client/shared/widgets/ColorWidget.js +++ b/devtools/client/shared/widgets/ColorWidget.js @@ -10,6 +10,12 @@ "use strict"; const EventEmitter = require("devtools/shared/event-emitter"); +const {rgbToColorName} = require("devtools/shared/css/color").colorUtils; + +const { LocalizationHelper } = require("devtools/shared/l10n"); +const STRINGS_URI = "devtools/client/locales/colorwidget.properties"; +const L10N = new LocalizationHelper(STRINGS_URI); + const XHTML_NS = "http://www.w3.org/1999/xhtml"; /** @@ -38,6 +44,8 @@ const XHTML_NS = "http://www.w3.org/1999/xhtml"; function ColorWidget(parentEl, rgb) { EventEmitter.decorate(this); + let colorNameLabel = L10N.getStr("colorNameLabel"); + this.element = parentEl.ownerDocument.createElementNS(XHTML_NS, "div"); this.parentEl = parentEl; @@ -63,6 +71,10 @@ function ColorWidget(parentEl, rgb) {
+
+ + +
`; this.onElementClick = this.onElementClick.bind(this); @@ -83,6 +95,8 @@ function ColorWidget(parentEl, rgb) { this.alphaSliderHelper = this.element.querySelector(".colorwidget-alpha-handle"); ColorWidget.draggable(this.alphaSliderInner, this.onAlphaSliderMove.bind(this)); + this.colorName = this.element.querySelector(".colorwidget-colorname-value"); + if (rgb) { this.rgb = rgb; this.updateUI(); @@ -325,6 +339,9 @@ ColorWidget.prototype = { let alphaGradient = "linear-gradient(to right, " + rgbAlpha0 + ", " + rgbNoAlpha + ")"; this.alphaSliderInner.style.background = alphaGradient; + + let colorName = rgbToColorName(rgb[0], rgb[1], rgb[2]); + this.colorName.textContent = colorName || "---"; }, destroy: function () { @@ -337,5 +354,6 @@ ColorWidget.prototype = { this.alphaSlider = this.alphaSliderInner = this.alphaSliderHelper = null; this.parentEl = null; this.element = null; + this.colorName = null; } }; diff --git a/devtools/server/actors/highlighters/eye-dropper.js b/devtools/server/actors/highlighters/eye-dropper.js index a90ec22bd0d3..03da1bed2af6 100644 --- a/devtools/server/actors/highlighters/eye-dropper.js +++ b/devtools/server/actors/highlighters/eye-dropper.js @@ -507,12 +507,7 @@ function toColorString(rgb, format) { let [h, s, l] = rgbToHsl(rgb); return "hsl(" + h + ", " + s + "%, " + l + "%)"; case "name": - let str; - try { - str = rgbToColorName(r, g, b); - } catch (e) { - str = hexString(rgb); - } + let str = rgbToColorName(r, g, b) || hexString(rgb); return str; default: return hexString(rgb); diff --git a/devtools/shared/css/color.js b/devtools/shared/css/color.js index 98ddeff1953f..06613ec87d87 100644 --- a/devtools/shared/css/color.js +++ b/devtools/shared/css/color.js @@ -169,17 +169,14 @@ CssColor.prototype = { return invalidOrSpecialValue; } - try { - let tuple = this._getRGBATuple(); + let tuple = this._getRGBATuple(); - if (tuple.a !== 1) { - return this.hex; - } - let {r, g, b} = tuple; - return rgbToColorName(r, g, b); - } catch (e) { + if (tuple.a !== 1) { return this.hex; } + + let {r, g, b} = tuple; + return rgbToColorName(r, g, b) || this.hex; }, get hex() { @@ -537,11 +534,11 @@ function classifyColor(value) { var cssRGBMap; /** - * Given a color, return its name, if it has one. Throws an exception - * if the color does not have a name. + * Given a color, return its name, if it has one. Otherwise + * return an empty string. * * @param {Number} r, g, b The color components. - * @return {String} the name of the color + * @return {String} the name of the color or an empty string */ function rgbToColorName(r, g, b) { if (!cssRGBMap) { @@ -553,11 +550,7 @@ function rgbToColorName(r, g, b) { } } } - let value = cssRGBMap[JSON.stringify([r, g, b, 1])]; - if (!value) { - throw new Error("no such color"); - } - return value; + return cssRGBMap[JSON.stringify([r, g, b, 1])] || ""; } // Translated from nsColor.cpp. From 2dfa56500ae46c8604d533bff62eea7af2dfd7dd Mon Sep 17 00:00:00 2001 From: Gabor Krizsanits Date: Sat, 21 Jan 2017 20:17:59 +0100 Subject: [PATCH 62/67] Bug 1303113 - Followup for a typo in the manigest file. r=me --- .../components/extensions/test/mochitest/mochitest-common.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolkit/components/extensions/test/mochitest/mochitest-common.ini b/toolkit/components/extensions/test/mochitest/mochitest-common.ini index 2474f02acc5e..7188f93e63c3 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest-common.ini @@ -85,7 +85,7 @@ skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975 skip-if = os == 'android' # Android does not currently support tabs. [test_ext_test.html] [test_ext_cookies.html] -os == 'android' # Bug 1258975 on android. +skip-if = os == 'android' # Bug 1258975 on android. [test_ext_background_api_injection.html] [test_ext_background_generated_url.html] [test_ext_background_teardown.html] From 9eb245ebd5eeda558fd4cf8cf859a35d907f5d3c Mon Sep 17 00:00:00 2001 From: Catalin Badea Date: Sat, 21 Jan 2017 21:19:35 +0200 Subject: [PATCH 63/67] Bug 1328293 - Show if a service worker is listening for fetch events in about:debugging. r=jdescottes --- .../aboutdebugging/components/workers/panel.js | 3 +++ .../components/workers/service-worker-target.js | 10 ++++++++++ .../client/locales/en-US/aboutdebugging.properties | 12 ++++++++++++ devtools/server/actors/worker.js | 8 ++++++++ dom/interfaces/base/nsIServiceWorkerManager.idl | 2 ++ dom/workers/ServiceWorkerInfo.cpp | 9 +++++++++ 6 files changed, 44 insertions(+) diff --git a/devtools/client/aboutdebugging/components/workers/panel.js b/devtools/client/aboutdebugging/components/workers/panel.js index b1bab2b99643..dc78535341b4 100644 --- a/devtools/client/aboutdebugging/components/workers/panel.js +++ b/devtools/client/aboutdebugging/components/workers/panel.js @@ -76,6 +76,7 @@ module.exports = createClass({ name: form.url, url: form.url, scope: form.scope, + fetch: form.fetch, registrationActor: form.actor, active: form.active }); @@ -99,6 +100,8 @@ module.exports = createClass({ } registration.workerActor = form.actor; } else { + worker.fetch = form.fetch; + // If a service worker registration could not be found, this means we are in // e10s, and registrations are not forwarded to other processes until they // reach the activated state. Augment the worker as a registration worker to diff --git a/devtools/client/aboutdebugging/components/workers/service-worker-target.js b/devtools/client/aboutdebugging/components/workers/service-worker-target.js index d46f6f20fdc0..6ed8404737e7 100644 --- a/devtools/client/aboutdebugging/components/workers/service-worker-target.js +++ b/devtools/client/aboutdebugging/components/workers/service-worker-target.js @@ -25,6 +25,7 @@ module.exports = createClass({ debugDisabled: PropTypes.bool, target: PropTypes.shape({ active: PropTypes.bool, + fetch: PropTypes.bool.isRequired, icon: PropTypes.string, name: PropTypes.string.isRequired, url: PropTypes.string, @@ -195,6 +196,9 @@ module.exports = createClass({ let { pushSubscription } = this.state; let status = this.getServiceWorkerStatus(); + let fetch = target.fetch ? Strings.GetStringFromName("listeningForFetchEvents") : + Strings.GetStringFromName("notListeningForFetchEvents"); + return dom.div({ className: "target-container" }, dom.img({ className: "target-icon", @@ -215,6 +219,12 @@ module.exports = createClass({ }, pushSubscription.endpoint)) : null ), + dom.li({ className: "target-detail" }, + dom.strong(null, Strings.GetStringFromName("fetch")), + dom.span({ + className: "service-worker-fetch-flag", + title: fetch + }, fetch)), dom.li({ className: "target-detail" }, dom.strong(null, Strings.GetStringFromName("scope")), dom.span({ diff --git a/devtools/client/locales/en-US/aboutdebugging.properties b/devtools/client/locales/en-US/aboutdebugging.properties index eab9ac7f1e15..f9a78c69d0fc 100644 --- a/devtools/client/locales/en-US/aboutdebugging.properties +++ b/devtools/client/locales/en-US/aboutdebugging.properties @@ -21,6 +21,18 @@ unregister = unregister pushService = Push Service +# LOCALIZATION NOTE (fetch): +# Fetch is an event type and should not be translated. +fetch = Fetch + +# LOCALIZATION NOTE (listeningForFetchEvents): +# This is used to display the state of the SW in regard to fetch events. +listeningForFetchEvents = Listening for fetch events. + +# LOCALIZATION NOTE (notListeningForFetchEvents): +# This is used to display the state of the SW in regard to fetch events. +notListeningForFetchEvents = Not listening for fetch events. + # LOCALIZATION NOTE (addons): # This string is displayed as a header of the about:debugging#addons page. addons = Add-ons diff --git a/devtools/server/actors/worker.js b/devtools/server/actors/worker.js index df6ffba148f6..bbfeb43cd83d 100644 --- a/devtools/server/actors/worker.js +++ b/devtools/server/actors/worker.js @@ -53,6 +53,10 @@ let WorkerActor = protocol.ActorClassWithSpec(workerSpec, { if (this._dbg.type === Ci.nsIWorkerDebugger.TYPE_SERVICE) { let registration = this._getServiceWorkerRegistrationInfo(); form.scope = registration.scope; + let newestWorker = (registration.activeWorker || + registration.waitingWorker || + registration.installingWorker); + form.fetch = newestWorker && newestWorker.handlesFetchEvents; } return form; }, @@ -229,6 +233,7 @@ let ServiceWorkerActor = protocol.ActorClassWithSpec(serviceWorkerSpec, { return { url: this._worker.scriptSpec, state: this._worker.state, + fetch: this._worker.handlesFetchEvents }; }, @@ -287,6 +292,8 @@ protocol.ActorClassWithSpec(serviceWorkerRegistrationSpec, { let waitingWorker = this._waitingWorker.form(); let activeWorker = this._activeWorker.form(); + let newestWorker = (activeWorker || waitingWorker || installingWorker); + let isE10s = Services.appinfo.browserTabsRemoteAutostart; return { actor: this.actorID, @@ -295,6 +302,7 @@ protocol.ActorClassWithSpec(serviceWorkerRegistrationSpec, { installingWorker, waitingWorker, activeWorker, + fetch: newestWorker && newestWorker.fetch, // - In e10s: only active registrations are available. // - In non-e10s: registrations always have at least one worker, if the worker is // active, the registration is active. diff --git a/dom/interfaces/base/nsIServiceWorkerManager.idl b/dom/interfaces/base/nsIServiceWorkerManager.idl index eadfc1dc0653..fe1003a08e0d 100644 --- a/dom/interfaces/base/nsIServiceWorkerManager.idl +++ b/dom/interfaces/base/nsIServiceWorkerManager.idl @@ -45,6 +45,8 @@ interface nsIServiceWorkerInfo : nsISupports readonly attribute nsIWorkerDebugger debugger; + readonly attribute bool handlesFetchEvents; + void attachDebugger(); void detachDebugger(); diff --git a/dom/workers/ServiceWorkerInfo.cpp b/dom/workers/ServiceWorkerInfo.cpp index 0901e2eed22d..bdbda8bc3b53 100644 --- a/dom/workers/ServiceWorkerInfo.cpp +++ b/dom/workers/ServiceWorkerInfo.cpp @@ -60,6 +60,15 @@ ServiceWorkerInfo::GetDebugger(nsIWorkerDebugger** aResult) return mServiceWorkerPrivate->GetDebugger(aResult); } +NS_IMETHODIMP +ServiceWorkerInfo::GetHandlesFetchEvents(bool* aValue) +{ + MOZ_ASSERT(aValue); + AssertIsOnMainThread(); + *aValue = HandlesFetch(); + return NS_OK; +} + NS_IMETHODIMP ServiceWorkerInfo::AttachDebugger() { From a9eb0af0c06a84afd9e50a40f3d3df3a94712b5a Mon Sep 17 00:00:00 2001 From: Catalin Badea Date: Sat, 21 Jan 2017 21:19:35 +0200 Subject: [PATCH 64/67] Bug 1328293 - Add test for new entry in about:debugging#workers. r=jdescottes --- .../client/aboutdebugging/test/browser.ini | 3 ++ .../browser_service_workers_fetch_flag.js | 50 +++++++++++++++++++ .../test/service-workers/fetch-sw.html | 22 ++++++++ .../test/service-workers/fetch-sw.js | 4 ++ 4 files changed, 79 insertions(+) create mode 100644 devtools/client/aboutdebugging/test/browser_service_workers_fetch_flag.js create mode 100644 devtools/client/aboutdebugging/test/service-workers/fetch-sw.html create mode 100644 devtools/client/aboutdebugging/test/service-workers/fetch-sw.js diff --git a/devtools/client/aboutdebugging/test/browser.ini b/devtools/client/aboutdebugging/test/browser.ini index 83d4ddff7c96..104686b86f3a 100644 --- a/devtools/client/aboutdebugging/test/browser.ini +++ b/devtools/client/aboutdebugging/test/browser.ini @@ -13,6 +13,8 @@ support-files = service-workers/delay-sw.js service-workers/empty-sw.html service-workers/empty-sw.js + service-workers/fetch-sw.html + service-workers/fetch-sw.js service-workers/push-sw.html service-workers/push-sw.js !/devtools/client/framework/test/shared-head.js @@ -32,6 +34,7 @@ tags = webextensions [browser_addons_toggle_debug.js] [browser_page_not_found.js] [browser_service_workers.js] +[browser_service_workers_fetch_flag.js] [browser_service_workers_not_compatible.js] [browser_service_workers_push.js] [browser_service_workers_push_service.js] diff --git a/devtools/client/aboutdebugging/test/browser_service_workers_fetch_flag.js b/devtools/client/aboutdebugging/test/browser_service_workers_fetch_flag.js new file mode 100644 index 000000000000..68251cb49037 --- /dev/null +++ b/devtools/client/aboutdebugging/test/browser_service_workers_fetch_flag.js @@ -0,0 +1,50 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Service workers can't be loaded from chrome://, +// but http:// is ok with dom.serviceWorkers.testing.enabled turned on. +const EMPTY_SW_TAB_URL = URL_ROOT + "service-workers/empty-sw.html"; +const FETCH_SW_TAB_URL = URL_ROOT + "service-workers/fetch-sw.html"; + +function* testBody(url, expecting) { + yield new Promise(done => { + let options = {"set": [ + ["dom.serviceWorkers.enabled", true], + ["dom.serviceWorkers.testing.enabled", true], + ]}; + SpecialPowers.pushPrefEnv(options, done); + }); + + let { tab, document } = yield openAboutDebugging("workers"); + + let swTab = yield addTab(url); + + let serviceWorkersElement = getServiceWorkerList(document); + yield waitForMutation(serviceWorkersElement, { childList: true }); + + let fetchFlags = [...document.querySelectorAll("#service-workers .service-worker-fetch-flag")]; + fetchFlags = fetchFlags.map(element => element.textContent); + ok(fetchFlags.includes(expecting), "Found correct fetch flag."); + + try { + yield unregisterServiceWorker(swTab, serviceWorkersElement); + ok(true, "Service worker registration unregistered"); + } catch (e) { + ok(false, "SW not unregistered; " + e); + } + + // Check that the service worker disappeared from the UI + let names = [...document.querySelectorAll("#service-workers .target-name")]; + names = names.map(element => element.textContent); + ok(names.length == 0, "All service workers were removed from the list."); + + yield removeTab(swTab); + yield closeAboutDebugging(tab); +} + +add_task(function* () { + yield testBody(FETCH_SW_TAB_URL, "Listening for fetch events."); + yield testBody(EMPTY_SW_TAB_URL, "Not listening for fetch events."); +}); diff --git a/devtools/client/aboutdebugging/test/service-workers/fetch-sw.html b/devtools/client/aboutdebugging/test/service-workers/fetch-sw.html new file mode 100644 index 000000000000..9038d4cbb26d --- /dev/null +++ b/devtools/client/aboutdebugging/test/service-workers/fetch-sw.html @@ -0,0 +1,22 @@ + + + + + Service worker test + + + + + diff --git a/devtools/client/aboutdebugging/test/service-workers/fetch-sw.js b/devtools/client/aboutdebugging/test/service-workers/fetch-sw.js new file mode 100644 index 000000000000..b24ce92439dc --- /dev/null +++ b/devtools/client/aboutdebugging/test/service-workers/fetch-sw.js @@ -0,0 +1,4 @@ +// Bug 1328293 +onfetch = function(event) { + // do nothing. +} From 2b0e87f459027b9880e355518bf7e52211705184 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Sat, 21 Jan 2017 12:19:37 -0800 Subject: [PATCH 65/67] Backed out 2 changesets (bug 1328293) for eslint failures CLOSED TREE Backed out changeset a76a454541fc (bug 1328293) Backed out changeset 42823a93cd16 (bug 1328293) --- .../components/workers/panel.js | 3 -- .../workers/service-worker-target.js | 10 ---- .../client/aboutdebugging/test/browser.ini | 3 -- .../browser_service_workers_fetch_flag.js | 50 ------------------- .../test/service-workers/fetch-sw.html | 22 -------- .../test/service-workers/fetch-sw.js | 4 -- .../locales/en-US/aboutdebugging.properties | 12 ----- devtools/server/actors/worker.js | 8 --- .../base/nsIServiceWorkerManager.idl | 2 - dom/workers/ServiceWorkerInfo.cpp | 9 ---- 10 files changed, 123 deletions(-) delete mode 100644 devtools/client/aboutdebugging/test/browser_service_workers_fetch_flag.js delete mode 100644 devtools/client/aboutdebugging/test/service-workers/fetch-sw.html delete mode 100644 devtools/client/aboutdebugging/test/service-workers/fetch-sw.js diff --git a/devtools/client/aboutdebugging/components/workers/panel.js b/devtools/client/aboutdebugging/components/workers/panel.js index dc78535341b4..b1bab2b99643 100644 --- a/devtools/client/aboutdebugging/components/workers/panel.js +++ b/devtools/client/aboutdebugging/components/workers/panel.js @@ -76,7 +76,6 @@ module.exports = createClass({ name: form.url, url: form.url, scope: form.scope, - fetch: form.fetch, registrationActor: form.actor, active: form.active }); @@ -100,8 +99,6 @@ module.exports = createClass({ } registration.workerActor = form.actor; } else { - worker.fetch = form.fetch; - // If a service worker registration could not be found, this means we are in // e10s, and registrations are not forwarded to other processes until they // reach the activated state. Augment the worker as a registration worker to diff --git a/devtools/client/aboutdebugging/components/workers/service-worker-target.js b/devtools/client/aboutdebugging/components/workers/service-worker-target.js index 6ed8404737e7..d46f6f20fdc0 100644 --- a/devtools/client/aboutdebugging/components/workers/service-worker-target.js +++ b/devtools/client/aboutdebugging/components/workers/service-worker-target.js @@ -25,7 +25,6 @@ module.exports = createClass({ debugDisabled: PropTypes.bool, target: PropTypes.shape({ active: PropTypes.bool, - fetch: PropTypes.bool.isRequired, icon: PropTypes.string, name: PropTypes.string.isRequired, url: PropTypes.string, @@ -196,9 +195,6 @@ module.exports = createClass({ let { pushSubscription } = this.state; let status = this.getServiceWorkerStatus(); - let fetch = target.fetch ? Strings.GetStringFromName("listeningForFetchEvents") : - Strings.GetStringFromName("notListeningForFetchEvents"); - return dom.div({ className: "target-container" }, dom.img({ className: "target-icon", @@ -219,12 +215,6 @@ module.exports = createClass({ }, pushSubscription.endpoint)) : null ), - dom.li({ className: "target-detail" }, - dom.strong(null, Strings.GetStringFromName("fetch")), - dom.span({ - className: "service-worker-fetch-flag", - title: fetch - }, fetch)), dom.li({ className: "target-detail" }, dom.strong(null, Strings.GetStringFromName("scope")), dom.span({ diff --git a/devtools/client/aboutdebugging/test/browser.ini b/devtools/client/aboutdebugging/test/browser.ini index 104686b86f3a..83d4ddff7c96 100644 --- a/devtools/client/aboutdebugging/test/browser.ini +++ b/devtools/client/aboutdebugging/test/browser.ini @@ -13,8 +13,6 @@ support-files = service-workers/delay-sw.js service-workers/empty-sw.html service-workers/empty-sw.js - service-workers/fetch-sw.html - service-workers/fetch-sw.js service-workers/push-sw.html service-workers/push-sw.js !/devtools/client/framework/test/shared-head.js @@ -34,7 +32,6 @@ tags = webextensions [browser_addons_toggle_debug.js] [browser_page_not_found.js] [browser_service_workers.js] -[browser_service_workers_fetch_flag.js] [browser_service_workers_not_compatible.js] [browser_service_workers_push.js] [browser_service_workers_push_service.js] diff --git a/devtools/client/aboutdebugging/test/browser_service_workers_fetch_flag.js b/devtools/client/aboutdebugging/test/browser_service_workers_fetch_flag.js deleted file mode 100644 index 68251cb49037..000000000000 --- a/devtools/client/aboutdebugging/test/browser_service_workers_fetch_flag.js +++ /dev/null @@ -1,50 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -// Service workers can't be loaded from chrome://, -// but http:// is ok with dom.serviceWorkers.testing.enabled turned on. -const EMPTY_SW_TAB_URL = URL_ROOT + "service-workers/empty-sw.html"; -const FETCH_SW_TAB_URL = URL_ROOT + "service-workers/fetch-sw.html"; - -function* testBody(url, expecting) { - yield new Promise(done => { - let options = {"set": [ - ["dom.serviceWorkers.enabled", true], - ["dom.serviceWorkers.testing.enabled", true], - ]}; - SpecialPowers.pushPrefEnv(options, done); - }); - - let { tab, document } = yield openAboutDebugging("workers"); - - let swTab = yield addTab(url); - - let serviceWorkersElement = getServiceWorkerList(document); - yield waitForMutation(serviceWorkersElement, { childList: true }); - - let fetchFlags = [...document.querySelectorAll("#service-workers .service-worker-fetch-flag")]; - fetchFlags = fetchFlags.map(element => element.textContent); - ok(fetchFlags.includes(expecting), "Found correct fetch flag."); - - try { - yield unregisterServiceWorker(swTab, serviceWorkersElement); - ok(true, "Service worker registration unregistered"); - } catch (e) { - ok(false, "SW not unregistered; " + e); - } - - // Check that the service worker disappeared from the UI - let names = [...document.querySelectorAll("#service-workers .target-name")]; - names = names.map(element => element.textContent); - ok(names.length == 0, "All service workers were removed from the list."); - - yield removeTab(swTab); - yield closeAboutDebugging(tab); -} - -add_task(function* () { - yield testBody(FETCH_SW_TAB_URL, "Listening for fetch events."); - yield testBody(EMPTY_SW_TAB_URL, "Not listening for fetch events."); -}); diff --git a/devtools/client/aboutdebugging/test/service-workers/fetch-sw.html b/devtools/client/aboutdebugging/test/service-workers/fetch-sw.html deleted file mode 100644 index 9038d4cbb26d..000000000000 --- a/devtools/client/aboutdebugging/test/service-workers/fetch-sw.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - Service worker test - - - - - diff --git a/devtools/client/aboutdebugging/test/service-workers/fetch-sw.js b/devtools/client/aboutdebugging/test/service-workers/fetch-sw.js deleted file mode 100644 index b24ce92439dc..000000000000 --- a/devtools/client/aboutdebugging/test/service-workers/fetch-sw.js +++ /dev/null @@ -1,4 +0,0 @@ -// Bug 1328293 -onfetch = function(event) { - // do nothing. -} diff --git a/devtools/client/locales/en-US/aboutdebugging.properties b/devtools/client/locales/en-US/aboutdebugging.properties index f9a78c69d0fc..eab9ac7f1e15 100644 --- a/devtools/client/locales/en-US/aboutdebugging.properties +++ b/devtools/client/locales/en-US/aboutdebugging.properties @@ -21,18 +21,6 @@ unregister = unregister pushService = Push Service -# LOCALIZATION NOTE (fetch): -# Fetch is an event type and should not be translated. -fetch = Fetch - -# LOCALIZATION NOTE (listeningForFetchEvents): -# This is used to display the state of the SW in regard to fetch events. -listeningForFetchEvents = Listening for fetch events. - -# LOCALIZATION NOTE (notListeningForFetchEvents): -# This is used to display the state of the SW in regard to fetch events. -notListeningForFetchEvents = Not listening for fetch events. - # LOCALIZATION NOTE (addons): # This string is displayed as a header of the about:debugging#addons page. addons = Add-ons diff --git a/devtools/server/actors/worker.js b/devtools/server/actors/worker.js index bbfeb43cd83d..df6ffba148f6 100644 --- a/devtools/server/actors/worker.js +++ b/devtools/server/actors/worker.js @@ -53,10 +53,6 @@ let WorkerActor = protocol.ActorClassWithSpec(workerSpec, { if (this._dbg.type === Ci.nsIWorkerDebugger.TYPE_SERVICE) { let registration = this._getServiceWorkerRegistrationInfo(); form.scope = registration.scope; - let newestWorker = (registration.activeWorker || - registration.waitingWorker || - registration.installingWorker); - form.fetch = newestWorker && newestWorker.handlesFetchEvents; } return form; }, @@ -233,7 +229,6 @@ let ServiceWorkerActor = protocol.ActorClassWithSpec(serviceWorkerSpec, { return { url: this._worker.scriptSpec, state: this._worker.state, - fetch: this._worker.handlesFetchEvents }; }, @@ -292,8 +287,6 @@ protocol.ActorClassWithSpec(serviceWorkerRegistrationSpec, { let waitingWorker = this._waitingWorker.form(); let activeWorker = this._activeWorker.form(); - let newestWorker = (activeWorker || waitingWorker || installingWorker); - let isE10s = Services.appinfo.browserTabsRemoteAutostart; return { actor: this.actorID, @@ -302,7 +295,6 @@ protocol.ActorClassWithSpec(serviceWorkerRegistrationSpec, { installingWorker, waitingWorker, activeWorker, - fetch: newestWorker && newestWorker.fetch, // - In e10s: only active registrations are available. // - In non-e10s: registrations always have at least one worker, if the worker is // active, the registration is active. diff --git a/dom/interfaces/base/nsIServiceWorkerManager.idl b/dom/interfaces/base/nsIServiceWorkerManager.idl index fe1003a08e0d..eadfc1dc0653 100644 --- a/dom/interfaces/base/nsIServiceWorkerManager.idl +++ b/dom/interfaces/base/nsIServiceWorkerManager.idl @@ -45,8 +45,6 @@ interface nsIServiceWorkerInfo : nsISupports readonly attribute nsIWorkerDebugger debugger; - readonly attribute bool handlesFetchEvents; - void attachDebugger(); void detachDebugger(); diff --git a/dom/workers/ServiceWorkerInfo.cpp b/dom/workers/ServiceWorkerInfo.cpp index bdbda8bc3b53..0901e2eed22d 100644 --- a/dom/workers/ServiceWorkerInfo.cpp +++ b/dom/workers/ServiceWorkerInfo.cpp @@ -60,15 +60,6 @@ ServiceWorkerInfo::GetDebugger(nsIWorkerDebugger** aResult) return mServiceWorkerPrivate->GetDebugger(aResult); } -NS_IMETHODIMP -ServiceWorkerInfo::GetHandlesFetchEvents(bool* aValue) -{ - MOZ_ASSERT(aValue); - AssertIsOnMainThread(); - *aValue = HandlesFetch(); - return NS_OK; -} - NS_IMETHODIMP ServiceWorkerInfo::AttachDebugger() { From 63d58feb4a0bf85b05d48e96851f9d23f12b7b98 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Sat, 21 Jan 2017 12:20:41 -0800 Subject: [PATCH 66/67] Backed out 2 changesets (bug 1303113) for test_ext_cookies.html failures CLOSED TREE Backed out changeset f6c9241b40ec (bug 1303113) Backed out changeset f4b8933f62ea (bug 1303113) --- addon-sdk/test/browser.ini | 1 - browser/base/content/test/general/browser.ini | 5 +---- browser/base/content/test/plugins/browser.ini | 1 - browser/base/content/test/referrer/browser.ini | 2 -- browser/base/content/test/urlbar/browser.ini | 1 - browser/base/content/test/webrtc/browser.ini | 1 - .../contextualidentity/test/browser/browser.ini | 1 - .../preferences/in-content/tests/browser_security.js | 12 ++++++------ .../privatebrowsing/test/browser/browser.ini | 1 - .../test/browser_service_workers_status.js | 6 ++---- .../browser_grouped_shistory_dead_navigate.js | 3 +-- dom/base/test/browser.ini | 1 - dom/browser-element/mochitest/mochitest-oop.ini | 1 - dom/cache/test/mochitest/browser.ini | 1 - dom/tests/browser/browser.ini | 4 ++-- modules/libpref/init/all.js | 4 ---- .../tests/functional/security/manifest.ini | 1 - .../extensions/test/mochitest/test_ext_cookies.html | 6 ++---- .../test/browser/browser_ui_requestAutocomplete.js | 6 ------ .../components/passwordmgr/test/browser/browser.ini | 1 - .../extensions/test/browser/browser-common.ini | 1 - 21 files changed, 14 insertions(+), 46 deletions(-) diff --git a/addon-sdk/test/browser.ini b/addon-sdk/test/browser.ini index e33f658fef1e..213698bf83af 100644 --- a/addon-sdk/test/browser.ini +++ b/addon-sdk/test/browser.ini @@ -7,7 +7,6 @@ support-files = invalid.json [browser_sdk_loader_sdk_modules.js] [browser_sdk_loader_sdk_gui_modules.js] -skip-if = e10s # Bug 1315042 [browser_sdk_loader_jsm_modules.js] [browser_sdk_loader_js_modules.js] [browser_sdk_loader_json.js] diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 6e53cee197f6..4d6129ddf09d 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -256,7 +256,6 @@ skip-if = os == "mac" # mac: Intermittent failures, bug 925225 skip-if = os == "mac" # Bug 1102331 - does focus things on the content window which break in e10s mode (still causes orange on Mac 10.10) [browser_bug710878.js] [browser_bug719271.js] -skip-if = e10s # Bug 1315042 [browser_bug724239.js] [browser_bug734076.js] [browser_bug735471.js] @@ -407,7 +406,6 @@ skip-if = os == "linux" # Bug 1329991 - test fails intermittently on Linux build skip-if = os == 'linux' # Bug 1304272 [browser_tab_close_dependent_window.js] [browser_tabDrop.js] -skip-if = e10s # Bug 1315042 [browser_tabReorder.js] [browser_tab_detach_restore.js] [browser_tab_drag_drop_perwindow.js] @@ -418,9 +416,8 @@ skip-if = buildapp == 'mulet' || (e10s && (debug || asan)) # Bug 1312436 skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux # Disabled on OS X because of bug 967917 [browser_tabfocus.js] -skip-if = e10s # Bug 1315042 [browser_tabkeynavigation.js] -skip-if = true || (os == "mac" && !e10s) # Bug 1315042, Bug 1237713 - OSX eats keypresses for some reason +skip-if = (os == "mac" && !e10s) # Bug 1237713 - OSX eats keypresses for some reason [browser_tabopen_reflows.js] [browser_tabs_close_beforeunload.js] support-files = diff --git a/browser/base/content/test/plugins/browser.ini b/browser/base/content/test/plugins/browser.ini index 03fe6825e99b..17954758b4e6 100644 --- a/browser/base/content/test/plugins/browser.ini +++ b/browser/base/content/test/plugins/browser.ini @@ -56,7 +56,6 @@ skip-if = !crashreporter [browser_CTP_iframe.js] [browser_CTP_multi_allow.js] [browser_CTP_nonplugins.js] -skip-if = e10s # Bug 1315042 [browser_CTP_notificationBar.js] [browser_CTP_outsideScrollArea.js] [browser_CTP_remove_navigate.js] diff --git a/browser/base/content/test/referrer/browser.ini b/browser/base/content/test/referrer/browser.ini index ce3d56cc4e36..13b712850fcd 100644 --- a/browser/base/content/test/referrer/browser.ini +++ b/browser/base/content/test/referrer/browser.ini @@ -6,9 +6,7 @@ support-files = head.js [browser_referrer_middle_click.js] -skip-if = true # Bug 1315042 [browser_referrer_middle_click_in_container.js] -skip-if = true # Bug 1315042 [browser_referrer_open_link_in_private.js] skip-if = os == 'linux' # Bug 1145199 [browser_referrer_open_link_in_tab.js] diff --git a/browser/base/content/test/urlbar/browser.ini b/browser/base/content/test/urlbar/browser.ini index 7e013fdd0044..9d11f931fdce 100644 --- a/browser/base/content/test/urlbar/browser.ini +++ b/browser/base/content/test/urlbar/browser.ini @@ -29,7 +29,6 @@ support-files = [browser_bug556061.js] subsuite = clipboard [browser_bug562649.js] -skip-if = e10s # Bug 1315042 [browser_bug623155.js] support-files = redirect_bug623155.sjs diff --git a/browser/base/content/test/webrtc/browser.ini b/browser/base/content/test/webrtc/browser.ini index 9e4898e195b2..0ea0dcacae63 100644 --- a/browser/base/content/test/webrtc/browser.ini +++ b/browser/base/content/test/webrtc/browser.ini @@ -12,7 +12,6 @@ skip-if = (os == "linux" && debug) # linux: bug 976544 [browser_devices_get_user_media_screen.js] skip-if = (e10s && debug) || (os == "linux" && !debug) # bug 1320754 for e10s debug, and bug 1320994 for linux opt [browser_devices_get_user_media_tear_off_tab.js] -skip-if = e10s # Bug 1315042 [browser_devices_get_user_media_unprompted_access.js] [browser_devices_get_user_media_unprompted_access_in_frame.js] [browser_devices_get_user_media_unprompted_access_tear_off_tab.js] diff --git a/browser/components/contextualidentity/test/browser/browser.ini b/browser/components/contextualidentity/test/browser/browser.ini index f13a3fba04ed..af7bd6dbafaf 100644 --- a/browser/components/contextualidentity/test/browser/browser.ini +++ b/browser/components/contextualidentity/test/browser/browser.ini @@ -13,7 +13,6 @@ support-files = [browser_forgetaboutsite.js] [browser_forgetAPI_cookie_getCookiesWithOriginAttributes.js] [browser_forgetAPI_EME_forgetThisSite.js] -skip-if = e10s # Bug 1315042 [browser_forgetAPI_quota_clearStoragesForPrincipal.js] [browser_newtabButton.js] [browser_usercontext.js] diff --git a/browser/components/preferences/in-content/tests/browser_security.js b/browser/components/preferences/in-content/tests/browser_security.js index cd6b98e8ae31..e6eb2a91d7a5 100644 --- a/browser/components/preferences/in-content/tests/browser_security.js +++ b/browser/components/preferences/in-content/tests/browser_security.js @@ -50,10 +50,10 @@ add_task(function*() { yield BrowserTestUtils.removeTab(gBrowser.selectedTab); } - yield* checkPrefSwitch(true, true); - yield* checkPrefSwitch(false, true); - yield* checkPrefSwitch(true, false); - yield* checkPrefSwitch(false, false); + yield checkPrefSwitch(true, true); + yield checkPrefSwitch(false, true); + yield checkPrefSwitch(true, false); + yield checkPrefSwitch(false, false); }); // test the download protection preference @@ -84,8 +84,8 @@ add_task(function*() { yield BrowserTestUtils.removeTab(gBrowser.selectedTab); } - yield* checkPrefSwitch(true); - yield* checkPrefSwitch(false); + yield checkPrefSwitch(true); + yield checkPrefSwitch(false); }); // test the unwanted/uncommon software warning preference diff --git a/browser/components/privatebrowsing/test/browser/browser.ini b/browser/components/privatebrowsing/test/browser/browser.ini index 49247119bef3..5efca4c0ec64 100644 --- a/browser/components/privatebrowsing/test/browser/browser.ini +++ b/browser/components/privatebrowsing/test/browser/browser.ini @@ -26,7 +26,6 @@ tags = trackingprotection [browser_privatebrowsing_cache.js] [browser_privatebrowsing_certexceptionsui.js] [browser_privatebrowsing_concurrent.js] -skip-if = e10s # Bug 1315042 [browser_privatebrowsing_context_and_chromeFlags.js] [browser_privatebrowsing_crh.js] [browser_privatebrowsing_downloadLastDir.js] diff --git a/devtools/client/aboutdebugging/test/browser_service_workers_status.js b/devtools/client/aboutdebugging/test/browser_service_workers_status.js index 3cac32f2c639..32cae6dc7b96 100644 --- a/devtools/client/aboutdebugging/test/browser_service_workers_status.js +++ b/devtools/client/aboutdebugging/test/browser_service_workers_status.js @@ -42,11 +42,9 @@ add_task(function* () { let targetElement = name.parentNode.parentNode; let status = targetElement.querySelector(".target-status"); - // We might miss the registering state in some setup... - if (status.textContent == "Registering") { - yield waitForMutation(serviceWorkersElement, { childList: true, subtree: true }); - } + is(status.textContent, "Registering", "Service worker is currently registering"); + yield waitForMutation(serviceWorkersElement, { childList: true, subtree: true }); is(status.textContent, "Running", "Service worker is currently running"); yield waitForMutation(serviceWorkersElement, { attributes: true, subtree: true }); diff --git a/docshell/test/browser/browser_grouped_shistory_dead_navigate.js b/docshell/test/browser/browser_grouped_shistory_dead_navigate.js index 467f5ba825f6..fd4b7bd83aa0 100644 --- a/docshell/test/browser/browser_grouped_shistory_dead_navigate.js +++ b/docshell/test/browser/browser_grouped_shistory_dead_navigate.js @@ -1,7 +1,6 @@ add_task(function* () { yield SpecialPowers.pushPrefEnv({ - set: [["browser.groupedhistory.enabled", true], - ["dom.ipc.processCount", 1]] + set: [["browser.groupedhistory.enabled", true]] }); // Wait for a process change and then fulfil the promise. diff --git a/dom/base/test/browser.ini b/dom/base/test/browser.ini index 3f4d6cf66789..93fe06cd4a9a 100644 --- a/dom/base/test/browser.ini +++ b/dom/base/test/browser.ini @@ -20,7 +20,6 @@ tags = mcb [browser_bug1011748.js] [browser_bug1058164.js] [browser_messagemanager_loadprocessscript.js] -skip-if = e10s # Bug 1315042 [browser_messagemanager_targetframeloader.js] [browser_messagemanager_unload.js] [browser_pagehide_on_tab_close.js] diff --git a/dom/browser-element/mochitest/mochitest-oop.ini b/dom/browser-element/mochitest/mochitest-oop.ini index e61f37c2f73e..9b42f49d5ddb 100644 --- a/dom/browser-element/mochitest/mochitest-oop.ini +++ b/dom/browser-element/mochitest/mochitest-oop.ini @@ -71,7 +71,6 @@ disabled = disabled for bug 1266035 (bug 1310706 for re-enabling) [test_browserElement_oop_OpenTab.html] disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling) [test_browserElement_oop_PrivateBrowsing.html] -skip-if = true # Bug 1315042 [test_browserElement_oop_PromptCheck.html] [test_browserElement_oop_PromptConfirm.html] [test_browserElement_oop_PurgeHistory.html] diff --git a/dom/cache/test/mochitest/browser.ini b/dom/cache/test/mochitest/browser.ini index 3c55c22f52df..90a7a53a3a36 100644 --- a/dom/cache/test/mochitest/browser.ini +++ b/dom/cache/test/mochitest/browser.ini @@ -1,2 +1 @@ [browser_cache_pb_window.js] -skip-if = e10s # Bug 1315042 diff --git a/dom/tests/browser/browser.ini b/dom/tests/browser/browser.ini index f7044ea708b8..c7f2114d19f8 100644 --- a/dom/tests/browser/browser.ini +++ b/dom/tests/browser/browser.ini @@ -36,7 +36,7 @@ skip-if = e10s [browser_focus_steal_from_chrome_during_mousedown.js] [browser_frame_elements.js] [browser_largeAllocation.js] -skip-if = true || !e10s # Large-Allocation requires e10s, turned off for e10s-multi Bug 1315042 +skip-if = !e10s # Large-Allocation requires e10s [browser_localStorage_privatestorageevent.js] [browser_test__content.js] [browser_test_new_window_from_content.js] @@ -52,4 +52,4 @@ support-files = support-files = prerender.html prerender_target.html -skip-if = true || !e10s # Prerendering requires e10s, turned off for e10s-multi Bug 1315042 +skip-if = !e10s # Prerendering requires e10s diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 9ea53d6688e8..2ca625dd41dc 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2880,11 +2880,7 @@ pref("dom.ipc.plugins.asyncdrawing.enabled", false); pref("dom.ipc.plugins.asyncdrawing.enabled", true); #endif -#ifdef NIGHTLY_BUILD -pref("dom.ipc.processCount", 2); -#else pref("dom.ipc.processCount", 1); -#endif // Disable support for SVG pref("svg.disabled", false); diff --git a/testing/firefox-ui/tests/functional/security/manifest.ini b/testing/firefox-ui/tests/functional/security/manifest.ini index a879eae6de38..6a210cfb7315 100644 --- a/testing/firefox-ui/tests/functional/security/manifest.ini +++ b/testing/firefox-ui/tests/functional/security/manifest.ini @@ -11,7 +11,6 @@ tags = local tags = local [test_safe_browsing_initial_download.py] [test_safe_browsing_notification.py] -skip-if = e10s # Bug 1315042 [test_safe_browsing_warning_pages.py] [test_security_notification.py] [test_ssl_disabled_error_page.py] diff --git a/toolkit/components/extensions/test/mochitest/test_ext_cookies.html b/toolkit/components/extensions/test/mochitest/test_ext_cookies.html index 825407abc705..ec5d7ba0f047 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_cookies.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_cookies.html @@ -88,8 +88,7 @@ add_task(function* test_cookies() { browser.test.assertEq(1, stores[0].tabIds.length, "one tabId returned for store"); browser.test.assertEq("number", typeof stores[0].tabIds[0], "tabId is a number"); - // This part causes intermittent failures see Bug 1309637. - if (false) { + { let privateWindow = await browser.windows.create({incognito: true}); let stores = await browser.cookies.getAllCookieStores(); @@ -180,8 +179,7 @@ add_task(function* test_cookies() { browser.test.assertEq("", cookie.value, "default value set"); browser.test.assertEq(true, cookie.session, "no expiry date created session cookie"); - // This part causes intermittent failures see Bug 1309637. - if (false) { + { let privateWindow = await browser.windows.create({incognito: true}); // Hacky work-around for bugzil.la/1309637 diff --git a/toolkit/components/formautofill/test/browser/browser_ui_requestAutocomplete.js b/toolkit/components/formautofill/test/browser/browser_ui_requestAutocomplete.js index c3257bc46787..2a7b58f12167 100644 --- a/toolkit/components/formautofill/test/browser/browser_ui_requestAutocomplete.js +++ b/toolkit/components/formautofill/test/browser/browser_ui_requestAutocomplete.js @@ -7,12 +7,6 @@ "use strict"; -add_task(function* setup() { - yield SpecialPowers.pushPrefEnv({ - set: [["dom.ipc.processCount", 1]] - }); -}); - /** * Open the requestAutocomplete UI and test that selecting a profile results in * the correct data being sent back to the opener. diff --git a/toolkit/components/passwordmgr/test/browser/browser.ini b/toolkit/components/passwordmgr/test/browser/browser.ini index a07ec9ed90d6..edabe5aacfdc 100644 --- a/toolkit/components/passwordmgr/test/browser/browser.ini +++ b/toolkit/components/passwordmgr/test/browser/browser.ini @@ -45,7 +45,6 @@ support-files = [browser_formless_submit_chrome.js] [browser_hasInsecureLoginForms.js] [browser_hasInsecureLoginForms_streamConverter.js] -skip-if = e10s # Bug 1315042 [browser_http_autofill.js] [browser_insecurePasswordWarning.js] [browser_notifications.js] diff --git a/toolkit/mozapps/extensions/test/browser/browser-common.ini b/toolkit/mozapps/extensions/test/browser/browser-common.ini index dc9e88e5715b..eda266e2f30e 100644 --- a/toolkit/mozapps/extensions/test/browser/browser-common.ini +++ b/toolkit/mozapps/extensions/test/browser/browser-common.ini @@ -65,4 +65,3 @@ skip-if = buildapp == 'mulet' skip-if = buildapp == 'mulet' [browser_webext_options.js] tags = webextensions -skip-if = e10s # Bug 1315042 From 4dec450e6f99069a7f80d9b760880ee0ba31655c Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Sat, 21 Jan 2017 12:22:06 -0800 Subject: [PATCH 67/67] Backed out changeset e329450e4d25 (bug 1332085) for browser_color-widget-01.js failures CLOSED TREE --- .../locales/en-US/colorwidget.properties | 11 -- devtools/client/shared/test/browser.ini | 1 - .../shared/test/browser_color-widget-01.js | 132 ------------------ devtools/client/shared/widgets/ColorWidget.js | 18 --- .../server/actors/highlighters/eye-dropper.js | 7 +- devtools/shared/css/color.js | 25 ++-- 6 files changed, 22 insertions(+), 172 deletions(-) delete mode 100644 devtools/client/locales/en-US/colorwidget.properties delete mode 100644 devtools/client/shared/test/browser_color-widget-01.js diff --git a/devtools/client/locales/en-US/colorwidget.properties b/devtools/client/locales/en-US/colorwidget.properties deleted file mode 100644 index d4d66fa21867..000000000000 --- a/devtools/client/locales/en-US/colorwidget.properties +++ /dev/null @@ -1,11 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# LOCALIZATION NOTE These strings are used in the CSS Color Editor Widget -# which can be found in a tooltip that appears in the Rules View when clicking -# on a color swatch displayed next to CSS declarations like 'color: #FFF'. - -# LOCALIZATION NOTE (colorNameLabel): The label for the current color -# widget's color name field -colorNameLabel=Color Name: diff --git a/devtools/client/shared/test/browser.ini b/devtools/client/shared/test/browser.ini index 19bb55d76eea..ad3f52fbdcb0 100644 --- a/devtools/client/shared/test/browser.ini +++ b/devtools/client/shared/test/browser.ini @@ -25,7 +25,6 @@ support-files = [browser_css_angle.js] [browser_css_color.js] -[browser_color-widget-01.js] [browser_cubic-bezier-01.js] [browser_cubic-bezier-02.js] [browser_cubic-bezier-03.js] diff --git a/devtools/client/shared/test/browser_color-widget-01.js b/devtools/client/shared/test/browser_color-widget-01.js deleted file mode 100644 index 70abab99e54f..000000000000 --- a/devtools/client/shared/test/browser_color-widget-01.js +++ /dev/null @@ -1,132 +0,0 @@ -/* vim: set ts=2 et sw=2 tw=80: */ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -// Tests that the color widget color picker works correctly. - -const {ColorWidget} = require("devtools/client/shared/widgets/ColorWidget.js"); - -const TEST_URI = `data:text/html, - -
`; - -add_task(function* () { - let [host,, doc] = yield createHost("bottom", TEST_URI); - - let container = doc.getElementById("color-widget-container"); - - yield testCreateAndDestroyShouldAppendAndRemoveElements(container); - yield testPassingAColorAtInitShouldSetThatColor(container); - yield testSettingAndGettingANewColor(container); - yield testChangingColorShouldEmitEvents(container); - yield testSettingColorShoudUpdateTheUI(container); - yield testChangingColorShouldUpdateColorNameDisplay(container); - - host.destroy(); -}); - -function testCreateAndDestroyShouldAppendAndRemoveElements(container) { - ok(container, "We have the root node to append ColorWidget to"); - is(container.childElementCount, 0, "Root node is empty"); - - let s = new ColorWidget(container, [255, 126, 255, 1]); - s.show(); - ok(container.childElementCount > 0, "ColorWidget has appended elements"); - - s.destroy(); - is(container.childElementCount, 0, "Destroying ColorWidget removed all nodes"); -} - -function testPassingAColorAtInitShouldSetThatColor(container) { - let initRgba = [255, 126, 255, 1]; - - let s = new ColorWidget(container, initRgba); - s.show(); - - let setRgba = s.rgb; - - is(initRgba[0], setRgba[0], "ColorWidget initialized with the right color"); - is(initRgba[1], setRgba[1], "ColorWidget initialized with the right color"); - is(initRgba[2], setRgba[2], "ColorWidget initialized with the right color"); - is(initRgba[3], setRgba[3], "ColorWidget initialized with the right color"); - - s.destroy(); -} - -function testSettingAndGettingANewColor(container) { - let s = new ColorWidget(container, [0, 0, 0, 1]); - s.show(); - - let colorToSet = [255, 255, 255, 1]; - s.rgb = colorToSet; - let newColor = s.rgb; - - is(colorToSet[0], newColor[0], "ColorWidget set with the right color"); - is(colorToSet[1], newColor[1], "ColorWidget set with the right color"); - is(colorToSet[2], newColor[2], "ColorWidget set with the right color"); - is(colorToSet[3], newColor[3], "ColorWidget set with the right color"); - - s.destroy(); -} - -function testChangingColorShouldEmitEvents(container) { - return new Promise(resolve => { - let s = new ColorWidget(container, [255, 255, 255, 1]); - s.show(); - - s.once("changed", (event, rgba, color) => { - ok(true, "Changed event was emitted on color change"); - is(rgba[0], 128, "New color is correct"); - is(rgba[1], 64, "New color is correct"); - is(rgba[2], 64, "New color is correct"); - is(rgba[3], 1, "New color is correct"); - is(`rgba(${rgba.join(", ")})`, color, "RGBA and css color correspond"); - - s.destroy(); - resolve(); - }); - - // Simulate a drag move event by calling the handler directly. - s.onDraggerMove(s.dragger.offsetWidth / 2, s.dragger.offsetHeight / 2); - }); -} - -function testSettingColorShoudUpdateTheUI(container) { - let s = new ColorWidget(container, [255, 255, 255, 1]); - s.show(); - let dragHelperOriginalPos = [s.dragHelper.style.top, s.dragHelper.style.left]; - let alphaHelperOriginalPos = s.alphaSliderHelper.style.left; - - s.rgb = [50, 240, 234, .2]; - s.updateUI(); - - ok(s.alphaSliderHelper.style.left != alphaHelperOriginalPos, "Alpha helper has moved"); - ok(s.dragHelper.style.top !== dragHelperOriginalPos[0], "Drag helper has moved"); - ok(s.dragHelper.style.left !== dragHelperOriginalPos[1], "Drag helper has moved"); - - s.rgb = [240, 32, 124, 0]; - s.updateUI(); - is(s.alphaSliderHelper.style.left, -(s.alphaSliderHelper.offsetWidth / 2) + "px", - "Alpha range UI has been updated again"); - - s.destroy(); -} - -function testChangingColorShouldUpdateColorNameDisplay(container) { - let s = new ColorWidget(container, [255, 255, 255, 1]); - s.show(); - s.updateUI(); - is(s.colorName.textContent, "white", "Color Name should be white"); - - s.rgb = [0, 0, 0, 1]; - s.updateUI(); - is(s.colorName.textContent, "black", "Color Name should be black"); - - s.rgb = [0, 0, 1, 1]; - s.updateUI(); - is(s.colorName.textContent, "---", "Color Name should be ---"); - - s.destroy(); -} diff --git a/devtools/client/shared/widgets/ColorWidget.js b/devtools/client/shared/widgets/ColorWidget.js index 057a6a8c3433..ba705e6e1680 100644 --- a/devtools/client/shared/widgets/ColorWidget.js +++ b/devtools/client/shared/widgets/ColorWidget.js @@ -10,12 +10,6 @@ "use strict"; const EventEmitter = require("devtools/shared/event-emitter"); -const {rgbToColorName} = require("devtools/shared/css/color").colorUtils; - -const { LocalizationHelper } = require("devtools/shared/l10n"); -const STRINGS_URI = "devtools/client/locales/colorwidget.properties"; -const L10N = new LocalizationHelper(STRINGS_URI); - const XHTML_NS = "http://www.w3.org/1999/xhtml"; /** @@ -44,8 +38,6 @@ const XHTML_NS = "http://www.w3.org/1999/xhtml"; function ColorWidget(parentEl, rgb) { EventEmitter.decorate(this); - let colorNameLabel = L10N.getStr("colorNameLabel"); - this.element = parentEl.ownerDocument.createElementNS(XHTML_NS, "div"); this.parentEl = parentEl; @@ -71,10 +63,6 @@ function ColorWidget(parentEl, rgb) {
-
- - -
`; this.onElementClick = this.onElementClick.bind(this); @@ -95,8 +83,6 @@ function ColorWidget(parentEl, rgb) { this.alphaSliderHelper = this.element.querySelector(".colorwidget-alpha-handle"); ColorWidget.draggable(this.alphaSliderInner, this.onAlphaSliderMove.bind(this)); - this.colorName = this.element.querySelector(".colorwidget-colorname-value"); - if (rgb) { this.rgb = rgb; this.updateUI(); @@ -339,9 +325,6 @@ ColorWidget.prototype = { let alphaGradient = "linear-gradient(to right, " + rgbAlpha0 + ", " + rgbNoAlpha + ")"; this.alphaSliderInner.style.background = alphaGradient; - - let colorName = rgbToColorName(rgb[0], rgb[1], rgb[2]); - this.colorName.textContent = colorName || "---"; }, destroy: function () { @@ -354,6 +337,5 @@ ColorWidget.prototype = { this.alphaSlider = this.alphaSliderInner = this.alphaSliderHelper = null; this.parentEl = null; this.element = null; - this.colorName = null; } }; diff --git a/devtools/server/actors/highlighters/eye-dropper.js b/devtools/server/actors/highlighters/eye-dropper.js index 03da1bed2af6..a90ec22bd0d3 100644 --- a/devtools/server/actors/highlighters/eye-dropper.js +++ b/devtools/server/actors/highlighters/eye-dropper.js @@ -507,7 +507,12 @@ function toColorString(rgb, format) { let [h, s, l] = rgbToHsl(rgb); return "hsl(" + h + ", " + s + "%, " + l + "%)"; case "name": - let str = rgbToColorName(r, g, b) || hexString(rgb); + let str; + try { + str = rgbToColorName(r, g, b); + } catch (e) { + str = hexString(rgb); + } return str; default: return hexString(rgb); diff --git a/devtools/shared/css/color.js b/devtools/shared/css/color.js index 06613ec87d87..98ddeff1953f 100644 --- a/devtools/shared/css/color.js +++ b/devtools/shared/css/color.js @@ -169,14 +169,17 @@ CssColor.prototype = { return invalidOrSpecialValue; } - let tuple = this._getRGBATuple(); + try { + let tuple = this._getRGBATuple(); - if (tuple.a !== 1) { + if (tuple.a !== 1) { + return this.hex; + } + let {r, g, b} = tuple; + return rgbToColorName(r, g, b); + } catch (e) { return this.hex; } - - let {r, g, b} = tuple; - return rgbToColorName(r, g, b) || this.hex; }, get hex() { @@ -534,11 +537,11 @@ function classifyColor(value) { var cssRGBMap; /** - * Given a color, return its name, if it has one. Otherwise - * return an empty string. + * Given a color, return its name, if it has one. Throws an exception + * if the color does not have a name. * * @param {Number} r, g, b The color components. - * @return {String} the name of the color or an empty string + * @return {String} the name of the color */ function rgbToColorName(r, g, b) { if (!cssRGBMap) { @@ -550,7 +553,11 @@ function rgbToColorName(r, g, b) { } } } - return cssRGBMap[JSON.stringify([r, g, b, 1])] || ""; + let value = cssRGBMap[JSON.stringify([r, g, b, 1])]; + if (!value) { + throw new Error("no such color"); + } + return value; } // Translated from nsColor.cpp.