From 1f74203658f3e1ca9715446f03b3a6180baffb21 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Tue, 30 Sep 2014 10:28:51 -0700 Subject: [PATCH 01/58] Bug 1073991 - Don't change types in JIT caches when the type's newScript has been cleared, r=jandem. --- js/src/jit/BaselineIC.cpp | 15 ++++++++++++++- js/src/jit/IonCaches.cpp | 18 +++++++++++++++++- js/src/jsinfer.h | 4 ++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 2bc96fe1231e..d998628f7c64 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -7911,13 +7911,26 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm) masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); masm.storePtr(scratch, shapeAddr); - // Change the object's type if required. + // Try to change the object's type. Label noTypeChange; + + // Check if the cache has a new type to change to. masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch); masm.branchTestPtr(Assembler::Zero, scratch, scratch, &noTypeChange); + + // Check if the old type still has a newScript. + Register scratch2 = protoReg; + masm.loadPtr(Address(objReg, JSObject::offsetOfType()), scratch2); + masm.branchPtr(Assembler::Equal, + Address(scratch2, types::TypeObject::offsetOfNewScript()), + ImmWord(0), + &noTypeChange); + + // Change the object's type. Address typeAddr(objReg, JSObject::offsetOfType()); EmitPreBarrier(masm, typeAddr, MIRType_TypeObject); masm.storePtr(scratch, typeAddr); + masm.bind(&noTypeChange); Register holderReg; diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 2c0a5f914baa..cf3657f68dbd 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -2583,11 +2583,27 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att if (oldType != obj->type()) { // Changing object's type from a partially to fully initialized type, - // per the acquired properties analysis. + // per the acquired properties analysis. Only change the type if the + // old type still has a newScript. + Label noTypeChange, skipPop; + + masm.push(object); + masm.loadPtr(Address(object, JSObject::offsetOfType()), object); + masm.branchPtr(Assembler::Equal, + Address(object, types::TypeObject::offsetOfNewScript()), + ImmWord(0), + &noTypeChange); + masm.pop(object); + Address typeAddr(object, JSObject::offsetOfType()); if (cx->zone()->needsIncrementalBarrier()) masm.callPreBarrier(typeAddr, MIRType_TypeObject); masm.storePtr(ImmGCPtr(obj->type()), typeAddr); + + masm.jump(&skipPop); + masm.bind(&noTypeChange); + masm.pop(object); + masm.bind(&skipPop); } // Set the value on the object. Since this is an add, obj->lastProperty() diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index a2575e037eea..92fbfc970fd8 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -1236,6 +1236,10 @@ struct TypeObject : public gc::TenuredCell return offsetof(TypeObject, proto_); } + static inline uint32_t offsetOfNewScript() { + return offsetof(TypeObject, newScript_); + } + private: inline uint32_t basePropertyCount() const; inline void setBasePropertyCount(uint32_t count); From 3a8f6e7a5f468b59c0fba16475ca9c1a8f34e08d Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 30 Sep 2014 18:35:32 +0100 Subject: [PATCH 02/58] Bug 1073615 - One MediaStreamGraph singleton per audioChannel, r=roc --- content/media/MediaStreamGraph.cpp | 49 ++++++++++++++----- content/media/MediaStreamGraphImpl.h | 5 ++ content/media/webaudio/AudioContext.cpp | 6 --- content/media/webaudio/AudioContext.h | 1 - .../webaudio/test/test_mozaudiochannel.html | 18 +++---- dom/webidl/AudioContext.webidl | 4 +- 6 files changed, 50 insertions(+), 33 deletions(-) diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index fc7f1e6577bb..f033ce576f5e 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -63,7 +63,7 @@ PRLogModuleInfo* gMediaStreamGraphLog; /** * The singleton graph instance. */ -static MediaStreamGraphImpl* gGraph; +static nsDataHashtable gGraphs; MediaStreamGraphImpl::~MediaStreamGraphImpl() { @@ -1633,9 +1633,10 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG) NS_DispatchToMainThread(event); LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this); - if (this == gGraph) { + MediaStreamGraphImpl* graph; + if (gGraphs.Get(mAudioChannel, &graph) && graph == this) { // null out gGraph if that's the graph being shut down - gGraph = nullptr; + gGraphs.Remove(mAudioChannel); } } } else { @@ -1786,9 +1787,12 @@ MediaStreamGraphImpl::AppendMessage(ControlMessage* aMessage) delete aMessage; if (IsEmpty() && mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) { - if (gGraph == this) { - gGraph = nullptr; + + MediaStreamGraphImpl* graph; + if (gGraphs.Get(mAudioChannel, &graph) && graph == this) { + gGraphs.Remove(mAudioChannel); } + Destroy(); } return; @@ -2736,6 +2740,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime, #ifdef DEBUG , mCanRunMessagesSynchronously(false) #endif + , mAudioChannel(static_cast(aChannel)) { #ifdef PR_LOGGING if (!gMediaStreamGraphLog) { @@ -2774,15 +2779,26 @@ NS_IMPL_ISUPPORTS(MediaStreamGraphShutdownObserver, nsIObserver) static bool gShutdownObserverRegistered = false; +namespace { + +PLDHashOperator +ForceShutdownEnumerator(const uint32_t& /* aAudioChannel */, + MediaStreamGraphImpl* aGraph, + void* /* aUnused */) +{ + aGraph->ForceShutDown(); + return PL_DHASH_NEXT; +} + +} // anonymous namespace + NS_IMETHODIMP MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) { if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { - if (gGraph) { - gGraph->ForceShutDown(); - } + gGraphs.EnumerateRead(ForceShutdownEnumerator, nullptr); nsContentUtils::UnregisterShutdownObserver(this); gShutdownObserverRegistered = false; } @@ -2794,7 +2810,10 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh { NS_ASSERTION(NS_IsMainThread(), "Main thread only"); - if (!gGraph) { + uint32_t channel = static_cast(aChannel); + MediaStreamGraphImpl* graph = nullptr; + + if (!gGraphs.Get(channel, &graph)) { if (!gShutdownObserverRegistered) { gShutdownObserverRegistered = true; nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver()); @@ -2802,12 +2821,13 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh CubebUtils::InitPreferredSampleRate(); - gGraph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel); + graph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel); + gGraphs.Put(channel, graph); - STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph)); + STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", graph)); } - return gGraph; + return graph; } MediaStreamGraph* @@ -2978,7 +2998,10 @@ MediaStreamGraph::CreateAudioNodeStream(AudioNodeEngine* aEngine, bool MediaStreamGraph::IsNonRealtime() const { - return this != gGraph; + const MediaStreamGraphImpl* impl = static_cast(this); + MediaStreamGraphImpl* graph; + + return !gGraphs.Get(impl->AudioChannel(), &graph) || graph != impl; } void diff --git a/content/media/MediaStreamGraphImpl.h b/content/media/MediaStreamGraphImpl.h index 690dc6ff8bfd..e8193ce64f7b 100644 --- a/content/media/MediaStreamGraphImpl.h +++ b/content/media/MediaStreamGraphImpl.h @@ -654,6 +654,8 @@ public: nsRefPtr mFarendObserverRef; #endif + uint32_t AudioChannel() const { return mAudioChannel; } + private: virtual ~MediaStreamGraphImpl(); @@ -687,6 +689,9 @@ private: bool mCanRunMessagesSynchronously; #endif + // We use uint32_t instead AudioChannel because this is just used as key for + // the hashtable gGraphs. + uint32_t mAudioChannel; }; } diff --git a/content/media/webaudio/AudioContext.cpp b/content/media/webaudio/AudioContext.cpp index fe249abe72b4..929cbbda687e 100644 --- a/content/media/webaudio/AudioContext.cpp +++ b/content/media/webaudio/AudioContext.cpp @@ -648,12 +648,6 @@ AudioContext::MozAudioChannelType() const return mDestination->MozAudioChannelType(); } -void -AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv) -{ - mDestination->SetMozAudioChannelType(aValue, aRv); -} - AudioChannel AudioContext::TestAudioChannelInAudioNodeStream() { diff --git a/content/media/webaudio/AudioContext.h b/content/media/webaudio/AudioContext.h index 857f66e790c9..d266c6f38480 100644 --- a/content/media/webaudio/AudioContext.h +++ b/content/media/webaudio/AudioContext.h @@ -222,7 +222,6 @@ public: JSObject* GetGlobalJSObject() const; AudioChannel MozAudioChannelType() const; - void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv); AudioChannel TestAudioChannelInAudioNodeStream(); diff --git a/content/media/webaudio/test/test_mozaudiochannel.html b/content/media/webaudio/test/test_mozaudiochannel.html index bfe19b33bb34..be6794432bea 100644 --- a/content/media/webaudio/test/test_mozaudiochannel.html +++ b/content/media/webaudio/test/test_mozaudiochannel.html @@ -18,27 +18,23 @@ function test_basic() { // Default is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - // random wrong channel - ac.mozAudioChannelType = "foo"; - is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - // Unpermitted channels - ac.mozAudioChannelType = "content"; + ac = new AudioContext("content"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - ac.mozAudioChannelType = "notification"; + ac = new AudioContext("notification"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - ac.mozAudioChannelType = "alarm"; + ac = new AudioContext("alarm"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - ac.mozAudioChannelType = "telephony"; + ac = new AudioContext("telephony"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - ac.mozAudioChannelType = "ringer"; + ac = new AudioContext("ringer"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); - ac.mozAudioChannelType = "publicnotification"; + ac = new AudioContext("publicnotification"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); runTest(); @@ -56,7 +52,7 @@ function test_permission(aChannel) { SpecialPowers.pushPermissions( [{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }], function() { - ac.mozAudioChannelType = aChannel; + var ac = new AudioContext(aChannel); is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'"); var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream(); diff --git a/dom/webidl/AudioContext.webidl b/dom/webidl/AudioContext.webidl index bf51646abfee..6ad60b850a8b 100644 --- a/dom/webidl/AudioContext.webidl +++ b/dom/webidl/AudioContext.webidl @@ -78,8 +78,8 @@ interface AudioContext : EventTarget { // Mozilla extensions partial interface AudioContext { // Read AudioChannel.webidl for more information about this attribute. - [Pref="media.useAudioChannelService", SetterThrows] - attribute AudioChannel mozAudioChannelType; + [Pref="media.useAudioChannelService"] + readonly attribute AudioChannel mozAudioChannelType; // These 2 events are dispatched when the AudioContext object is muted by // the AudioChannelService. It's call 'interrupt' because when this event is From ed6740b1ea89572348d563542b72d894fc6c5c62 Mon Sep 17 00:00:00 2001 From: Simon Montagu Date: Tue, 30 Sep 2014 10:59:12 -0700 Subject: [PATCH 03/58] Tests for bug 1069941, one by jfkthame, r=smontagu; the other by smontagu, r=jfkthame --- .../1069941-inline-bidi-border-1-ref.html | 15 ++++++++++++++ .../bidi/1069941-inline-bidi-border-1.html | 15 ++++++++++++++ .../1069941-inline-bidi-margin-1-ref.html | 20 +++++++++++++++++++ .../bidi/1069941-inline-bidi-margin-1.html | 20 +++++++++++++++++++ layout/reftests/bidi/reftest.list | 3 +++ 5 files changed, 73 insertions(+) create mode 100644 layout/reftests/bidi/1069941-inline-bidi-border-1-ref.html create mode 100644 layout/reftests/bidi/1069941-inline-bidi-border-1.html create mode 100644 layout/reftests/bidi/1069941-inline-bidi-margin-1-ref.html create mode 100644 layout/reftests/bidi/1069941-inline-bidi-margin-1.html diff --git a/layout/reftests/bidi/1069941-inline-bidi-border-1-ref.html b/layout/reftests/bidi/1069941-inline-bidi-border-1-ref.html new file mode 100644 index 000000000000..eeca3ef8cbe5 --- /dev/null +++ b/layout/reftests/bidi/1069941-inline-bidi-border-1-ref.html @@ -0,0 +1,15 @@ + + + + +Test for bug 1069941 -- borders + + +
+ +
+
+ +
+ + diff --git a/layout/reftests/bidi/1069941-inline-bidi-border-1.html b/layout/reftests/bidi/1069941-inline-bidi-border-1.html new file mode 100644 index 000000000000..79b41aaf1ba5 --- /dev/null +++ b/layout/reftests/bidi/1069941-inline-bidi-border-1.html @@ -0,0 +1,15 @@ + + + + +Test for bug 1069941 -- borders + + +
+ +
+
+ +
+ + diff --git a/layout/reftests/bidi/1069941-inline-bidi-margin-1-ref.html b/layout/reftests/bidi/1069941-inline-bidi-margin-1-ref.html new file mode 100644 index 000000000000..c981cd73c913 --- /dev/null +++ b/layout/reftests/bidi/1069941-inline-bidi-margin-1-ref.html @@ -0,0 +1,20 @@ + + + +Test for bug 1069941 -- margins + + + +(12] + + diff --git a/layout/reftests/bidi/1069941-inline-bidi-margin-1.html b/layout/reftests/bidi/1069941-inline-bidi-margin-1.html new file mode 100644 index 000000000000..02d0d325cba8 --- /dev/null +++ b/layout/reftests/bidi/1069941-inline-bidi-margin-1.html @@ -0,0 +1,20 @@ + + + +Test for bug 1069941 -- margins + + + +[12) + + diff --git a/layout/reftests/bidi/reftest.list b/layout/reftests/bidi/reftest.list index a8c314a1fade..740fe4d74bf9 100644 --- a/layout/reftests/bidi/reftest.list +++ b/layout/reftests/bidi/reftest.list @@ -142,3 +142,6 @@ skip-if(B2G) == 726420-1.html 726420-1-ref.html skip-if(B2G&&browserIsRemote) == 869833-1.xul 869833-1-ref.xul == 922530-1.html 922530-1-ref.html == 922550-1.html 922550-1-ref.html +== 1069941-inline-bidi-border-1.html 1069941-inline-bidi-border-1-ref.html +== 1069941-inline-bidi-margin-1.html 1069941-inline-bidi-margin-1-ref.html + From 859e13d16de8bbfba3809a83b461cba6ae05e123 Mon Sep 17 00:00:00 2001 From: Simon Montagu Date: Tue, 30 Sep 2014 10:59:13 -0700 Subject: [PATCH 04/58] Bug 1069941 patch 1: be more accurate when identifying the first and last frames on the line and applying margin/border/padding, r=jfkthame --- layout/base/nsBidiPresUtils.cpp | 64 ++++++++++++++++++++++----------- layout/base/nsBidiPresUtils.h | 32 +++++++++++------ 2 files changed, 65 insertions(+), 31 deletions(-) diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index a7a8a7f36692..9f4cbc6a7701 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -1279,6 +1279,7 @@ nsBidiPresUtils::GetFrameBaseLevel(nsIFrame* aFrame) void nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame, nsContinuationStates* aContinuationStates, + bool aSpanDirMatchesLineDir, bool& aIsFirst /* out */, bool& aIsLast /* out */) { @@ -1293,6 +1294,7 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame, * chain on this line. */ + bool firstInLineOrder, lastInLineOrder; nsFrameContinuationState* frameState = aContinuationStates->GetEntry(aFrame); nsFrameContinuationState* firstFrameState; @@ -1327,16 +1329,30 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame, } frameState->mHasContOnNextLines = (frame != nullptr); - aIsFirst = !frameState->mHasContOnPrevLines; + firstInLineOrder = true; firstFrameState = frameState; } else { // aFrame is not the first visual frame of its continuation chain - aIsFirst = false; + firstInLineOrder = false; firstFrameState = aContinuationStates->GetEntry(frameState->mFirstVisualFrame); } - aIsLast = (firstFrameState->mFrameCount == 1 && - !firstFrameState->mHasContOnNextLines); + lastInLineOrder = (firstFrameState->mFrameCount == 1); + + if (aSpanDirMatchesLineDir) { + aIsFirst = firstInLineOrder; + aIsLast = lastInLineOrder; + } else { + aIsFirst = lastInLineOrder; + aIsLast = firstInLineOrder; + } + + if (frameState->mHasContOnPrevLines) { + aIsFirst = false; + } + if (firstFrameState->mHasContOnNextLines) { + aIsLast = false; + } if ((aIsFirst || aIsLast) && (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) { @@ -1370,12 +1386,13 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame, return; bool isFirst, isLast; + WritingMode frameWM = aFrame->GetWritingMode(); IsFirstOrLast(aFrame, aContinuationStates, + aLineWM.IsBidiLTR() == frameWM.IsBidiLTR(), isFirst /* out */, isLast /* out */); - WritingMode frameWM = aFrame->GetWritingMode(); nsInlineFrame* testFrame = do_QueryFrame(aFrame); if (testFrame) { @@ -1393,24 +1410,36 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame, aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST); } } + + // We only need the margin if the frame is first or last in its own + // writing mode, but we're traversing the frames in the order of the + // container's writing mode. To get the right values, we set start and + // end margins on a logical margin in the frame's writing mode, and + // then convert the margin to the container's writing mode to set the + // coordinates. + // This method is called from nsBlockFrame::PlaceLine via the call to // bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines // have been reflowed, which is required for GetUsedMargin/Border/Padding - LogicalMargin margin(aLineWM, aFrame->GetUsedMargin()); - if (isFirst) { - aStart += margin.IStart(aLineWM); + LogicalMargin frameMargin = aFrame->GetLogicalUsedMargin(frameWM); + LogicalMargin borderPadding = aFrame->GetLogicalUsedBorderAndPadding(frameWM); + if (!isFirst) { + frameMargin.IStart(frameWM) = 0; + borderPadding.IStart(frameWM) = 0; } + if (!isLast) { + frameMargin.IEnd(frameWM) = 0; + borderPadding.IEnd(frameWM) = 0; + } + LogicalMargin margin = frameMargin.ConvertTo(aLineWM, frameWM); + aStart += margin.IStart(aLineWM); nscoord start = aStart; nscoord frameISize = aFrame->ISize(aLineWM); if (!IsBidiLeaf(aFrame)) { - nscoord iCoord = 0; - LogicalMargin borderPadding(frameWM, aFrame->GetUsedBorderAndPadding()); - if (isFirst) { - iCoord += borderPadding.IStart(frameWM); - } + nscoord iCoord = borderPadding.IStart(frameWM); // If the resolved direction of the container is different from the // direction of the frame, we need to traverse the child list in reverse @@ -1443,10 +1472,7 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame, frame->GetNextSibling(); } - if (isLast) { - iCoord += borderPadding.IEnd(frameWM); - } - aStart += iCoord; + aStart += iCoord + borderPadding.IEnd(frameWM); } else { aStart += frameISize; } @@ -1456,9 +1482,7 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame, logicalRect.ISize(aLineWM) = aStart - start; aFrame->SetRect(aLineWM, logicalRect, aLineWidth); - if (isLast) { - aStart += margin.IEnd(aLineWM); - } + aStart += margin.IEnd(aLineWM); } void diff --git a/layout/base/nsBidiPresUtils.h b/layout/base/nsBidiPresUtils.h index a9b9657aaa91..7c7c03ba683b 100644 --- a/layout/base/nsBidiPresUtils.h +++ b/layout/base/nsBidiPresUtils.h @@ -412,22 +412,32 @@ private: nsContinuationStates* aContinuationStates); /* - * Determine if aFrame is leftmost or rightmost, and set aIsLeftMost and - * aIsRightMost values. Also set continuation states of aContinuationStates. + * Determine if aFrame is first or last, and set aIsFirst and + * aIsLast values. Also set continuation states of + * aContinuationStates. * - * A frame is leftmost if it's the first appearance of its continuation chain - * on the line and the chain is on its first line if it's LTR or the chain is - * on its last line if it's RTL. - * A frame is rightmost if it's the last appearance of its continuation chain - * on the line and the chain is on its first line if it's RTL or the chain is - * on its last line if it's LTR. + * A frame is first if it's the first appearance of its continuation + * chain on the line and the chain is on its first line. + * A frame is last if it's the last appearance of its continuation + * chain on the line and the chain is on its last line. * - * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState - * @param[out] aIsLeftMost TRUE means aFrame is leftmost frame or continuation - * @param[out] aIsRightMost TRUE means aFrame is rightmost frame or continuation + * N.B: "First appearance" and "Last appearance" in the previous + * paragraph refer to the frame's inline direction, not necessarily + * the line's. + * + * @param aContinuationStates A map from nsIFrame* to + * nsFrameContinuationState + * @param[in] aSpanDirMatchesLineDir TRUE means that the inline + * direction of aFrame is the same + * as its container + * @param[out] aIsFirst TRUE means aFrame is first frame + * or continuation + * @param[out] aIsLast TRUE means aFrame is last frame + * or continuation */ static void IsFirstOrLast(nsIFrame* aFrame, nsContinuationStates* aContinuationStates, + bool aSpanInLineOrder /* in */, bool& aIsFirst /* out */, bool& aIsLast /* out */); From 72a6973797ff819ce2bab9476b398cc4f96bdf2f Mon Sep 17 00:00:00 2001 From: Simon Montagu Date: Tue, 30 Sep 2014 10:59:13 -0700 Subject: [PATCH 05/58] Bug 1069941 patch 2: reset the start coordinate of the inline frames before ReorderFrames so that the margin doesn't get added twice, r=jfkthame --- layout/base/nsBidiPresUtils.cpp | 21 ++++++--------------- layout/base/nsBidiPresUtils.h | 6 ++++-- layout/generic/nsLineLayout.cpp | 18 ++++++++++-------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index 9f4cbc6a7701..a28755cff684 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -1224,7 +1224,8 @@ void nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine, int32_t aNumFramesOnLine, WritingMode aLineWM, - nscoord& aLineWidth) + nscoord& aLineWidth, + nscoord aStart) { // If this line consists of a line frame, reorder the line frame's children. if (aFirstFrameOnLine->GetType() == nsGkAtoms::lineFrame) { @@ -1237,7 +1238,7 @@ nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine, } BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine); - RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth); + RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth, aStart); } nsIFrame* @@ -1509,20 +1510,10 @@ void nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld, nsIFrame* aFirstChild, WritingMode aLineWM, - nscoord& aLineWidth) + nscoord& aLineWidth, + nscoord& aStart) { - nscoord startSpace = 0; - - // This method is called from nsBlockFrame::PlaceLine via the call to - // bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines - // have been reflowed, which is required for GetUsedMargin/Border/Padding - LogicalMargin margin(aLineWM, aFirstChild->GetUsedMargin()); - if (!aFirstChild->GetPrevContinuation() && - !aFirstChild->FrameIsNonFirstInIBSplit()) - startSpace = margin.IStart(aLineWM); - - nscoord start = LogicalRect(aLineWM, aFirstChild->GetRect(), - aLineWidth).IStart(aLineWM) - startSpace; + nscoord start = aStart; nsIFrame* frame; int32_t count = aBld->mVisualFrames.Length(); int32_t index; diff --git a/layout/base/nsBidiPresUtils.h b/layout/base/nsBidiPresUtils.h index 7c7c03ba683b..56d6b826ddf1 100644 --- a/layout/base/nsBidiPresUtils.h +++ b/layout/base/nsBidiPresUtils.h @@ -160,7 +160,8 @@ public: static void ReorderFrames(nsIFrame* aFirstFrameOnLine, int32_t aNumFramesOnLine, mozilla::WritingMode aLineWM, - nscoord& aLineWidth); + nscoord& aLineWidth, + nscoord aStart); /** * Format Unicode text, taking into account bidi capabilities @@ -451,7 +452,8 @@ private: static void RepositionInlineFrames(BidiLineData* aBld, nsIFrame* aFirstChild, mozilla::WritingMode aLineWM, - nscoord& aLineWidth); + nscoord& aLineWidth, + nscoord& aStart); /** * Helper method for Resolve() diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index 5313aae2ea97..99a1a1528dcc 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -2598,20 +2598,22 @@ nsLineLayout::TextAlignLine(nsLineBox* aLine, } } - if (dx) { + if (mPresContext->BidiEnabled() && + (!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) { + nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame, + aLine->GetChildCount(), + lineWM, mContainerWidth, + psd->mIStart + mTextIndent + dx); + if (dx) { + aLine->IndentBy(dx, mContainerWidth); + } + } else if (dx) { for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) { pfd->mBounds.IStart(lineWM) += dx; pfd->mFrame->SetRect(lineWM, pfd->mBounds, mContainerWidth); } aLine->IndentBy(dx, mContainerWidth); } - - if (mPresContext->BidiEnabled() && - (!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) { - nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame, - aLine->GetChildCount(), - lineWM, mContainerWidth); - } } void From 5240838225b527af5697015a2055c9f0875943f8 Mon Sep 17 00:00:00 2001 From: Simon Montagu Date: Tue, 30 Sep 2014 10:59:14 -0700 Subject: [PATCH 06/58] Bug 1069941 patch 3: Pass the frame physical width, not inline size, to the inner loop of RepositionFrame, plus cosmetic fixes, r=jfkthame --- layout/base/nsBidiPresUtils.cpp | 69 ++++++++++++++++----------------- layout/base/nsBidiPresUtils.h | 4 +- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index a28755cff684..1a3dc7042dce 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -1373,6 +1373,24 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame, // Reduce number of remaining frames of the continuation chain on the line. firstFrameState->mFrameCount--; + + nsInlineFrame* testFrame = do_QueryFrame(aFrame); + + if (testFrame) { + aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET); + + if (aIsFirst) { + aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST); + } else { + aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST); + } + + if (aIsLast) { + aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST); + } else { + aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST); + } + } } void @@ -1380,8 +1398,8 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame, bool aIsEvenLevel, nscoord& aStart, nsContinuationStates* aContinuationStates, - WritingMode aLineWM, - nscoord& aLineWidth) + WritingMode aContainerWM, + nscoord& aContainerWidth) { if (!aFrame) return; @@ -1390,28 +1408,10 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame, WritingMode frameWM = aFrame->GetWritingMode(); IsFirstOrLast(aFrame, aContinuationStates, - aLineWM.IsBidiLTR() == frameWM.IsBidiLTR(), + aContainerWM.IsBidiLTR() == frameWM.IsBidiLTR(), isFirst /* out */, isLast /* out */); - nsInlineFrame* testFrame = do_QueryFrame(aFrame); - - if (testFrame) { - aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET); - - if (isFirst) { - aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST); - } else { - aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST); - } - - if (isLast) { - aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST); - } else { - aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST); - } - } - // We only need the margin if the frame is first or last in its own // writing mode, but we're traversing the frames in the order of the // container's writing mode. To get the right values, we set start and @@ -1432,16 +1432,12 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame, frameMargin.IEnd(frameWM) = 0; borderPadding.IEnd(frameWM) = 0; } - LogicalMargin margin = frameMargin.ConvertTo(aLineWM, frameWM); - aStart += margin.IStart(aLineWM); + LogicalMargin margin = frameMargin.ConvertTo(aContainerWM, frameWM); + aStart += margin.IStart(aContainerWM); nscoord start = aStart; - nscoord frameISize = aFrame->ISize(aLineWM); - - if (!IsBidiLeaf(aFrame)) - { - nscoord iCoord = borderPadding.IStart(frameWM); + if (!IsBidiLeaf(aFrame)) { // If the resolved direction of the container is different from the // direction of the frame, we need to traverse the child list in reverse // order, to make it O(n) we store the list locally and iterate the list @@ -1460,13 +1456,15 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame, // Reposition the child frames int32_t index = 0; + nscoord iCoord = borderPadding.IStart(frameWM); + while (frame) { RepositionFrame(frame, aIsEvenLevel, iCoord, aContinuationStates, frameWM, - frameISize); + aFrame->GetLogicalSize(aContainerWM).Width(aContainerWM)); index++; frame = reverseOrder ? childList[childList.Length() - index - 1] : @@ -1475,15 +1473,16 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame, aStart += iCoord + borderPadding.IEnd(frameWM); } else { - aStart += frameISize; + aStart += aFrame->ISize(aContainerWM); } - LogicalRect logicalRect(aLineWM, aFrame->GetRect(), aLineWidth); - logicalRect.IStart(aLineWM) = start; - logicalRect.ISize(aLineWM) = aStart - start; - aFrame->SetRect(aLineWM, logicalRect, aLineWidth); + LogicalRect logicalRect = aFrame->GetLogicalRect(aContainerWM, + aContainerWidth); + logicalRect.IStart(aContainerWM) = start; + logicalRect.ISize(aContainerWM) = aStart - start; + aFrame->SetRect(aContainerWM, logicalRect, aContainerWidth); - aStart += margin.IEnd(aLineWM); + aStart += margin.IEnd(aContainerWM); } void diff --git a/layout/base/nsBidiPresUtils.h b/layout/base/nsBidiPresUtils.h index 56d6b826ddf1..3377ab6de57a 100644 --- a/layout/base/nsBidiPresUtils.h +++ b/layout/base/nsBidiPresUtils.h @@ -398,8 +398,8 @@ private: bool aIsEvenLevel, nscoord& aStart, nsContinuationStates* aContinuationStates, - mozilla::WritingMode aLineWM, - nscoord& aLineWidth); + mozilla::WritingMode aContainerWM, + nscoord& aContainerWidth); /* * Initialize the continuation state(nsFrameContinuationState) to From 08cf036ad457351564236cf11380cf11e056d323 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 30 Sep 2014 14:13:54 -0400 Subject: [PATCH 07/58] Backed out changeset af3a0d277ad2 (bug 1073991) for mass bustage. CLOSED TREE --- js/src/jit/BaselineIC.cpp | 15 +-------------- js/src/jit/IonCaches.cpp | 18 +----------------- js/src/jsinfer.h | 4 ---- 3 files changed, 2 insertions(+), 35 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index d998628f7c64..2bc96fe1231e 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -7911,26 +7911,13 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm) masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); masm.storePtr(scratch, shapeAddr); - // Try to change the object's type. + // Change the object's type if required. Label noTypeChange; - - // Check if the cache has a new type to change to. masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch); masm.branchTestPtr(Assembler::Zero, scratch, scratch, &noTypeChange); - - // Check if the old type still has a newScript. - Register scratch2 = protoReg; - masm.loadPtr(Address(objReg, JSObject::offsetOfType()), scratch2); - masm.branchPtr(Assembler::Equal, - Address(scratch2, types::TypeObject::offsetOfNewScript()), - ImmWord(0), - &noTypeChange); - - // Change the object's type. Address typeAddr(objReg, JSObject::offsetOfType()); EmitPreBarrier(masm, typeAddr, MIRType_TypeObject); masm.storePtr(scratch, typeAddr); - masm.bind(&noTypeChange); Register holderReg; diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index cf3657f68dbd..2c0a5f914baa 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -2583,27 +2583,11 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att if (oldType != obj->type()) { // Changing object's type from a partially to fully initialized type, - // per the acquired properties analysis. Only change the type if the - // old type still has a newScript. - Label noTypeChange, skipPop; - - masm.push(object); - masm.loadPtr(Address(object, JSObject::offsetOfType()), object); - masm.branchPtr(Assembler::Equal, - Address(object, types::TypeObject::offsetOfNewScript()), - ImmWord(0), - &noTypeChange); - masm.pop(object); - + // per the acquired properties analysis. Address typeAddr(object, JSObject::offsetOfType()); if (cx->zone()->needsIncrementalBarrier()) masm.callPreBarrier(typeAddr, MIRType_TypeObject); masm.storePtr(ImmGCPtr(obj->type()), typeAddr); - - masm.jump(&skipPop); - masm.bind(&noTypeChange); - masm.pop(object); - masm.bind(&skipPop); } // Set the value on the object. Since this is an add, obj->lastProperty() diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index 92fbfc970fd8..a2575e037eea 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -1236,10 +1236,6 @@ struct TypeObject : public gc::TenuredCell return offsetof(TypeObject, proto_); } - static inline uint32_t offsetOfNewScript() { - return offsetof(TypeObject, newScript_); - } - private: inline uint32_t basePropertyCount() const; inline void setBasePropertyCount(uint32_t count); From 48cdd5bef610d87bd3a4adccba845f8a8be84962 Mon Sep 17 00:00:00 2001 From: "Byron Campen [:bwc]" Date: Mon, 29 Sep 2014 10:17:07 -0700 Subject: [PATCH 08/58] Bug 1071207: Remove trickle ICE pref. r=mt --- dom/media/PeerConnection.js | 5 +---- modules/libpref/init/all.js | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index 0660570268bf..caf1bde15162 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -301,7 +301,6 @@ function RTCPeerConnection() { this._localType = null; this._remoteType = null; - this._trickleIce = false; this._peerIdentity = null; /** @@ -326,7 +325,6 @@ RTCPeerConnection.prototype = { init: function(win) { this._win = win; }, __init: function(rtcConfig) { - this._trickleIce = Services.prefs.getBoolPref("media.peerconnection.trickle_ice"); if (!rtcConfig.iceServers || !Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) { rtcConfig.iceServers = @@ -365,8 +363,7 @@ RTCPeerConnection.prototype = { this._queueOrRun({ func: this._initialize, args: [rtcConfig], - // If not trickling, suppress start. - wait: !this._trickleIce + wait: false }); }, diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index bb1470872e97..077f4078dc9c 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -341,7 +341,6 @@ pref("media.peerconnection.video.max_bitrate", 2000); #endif pref("media.navigator.permission.disabled", false); pref("media.peerconnection.default_iceservers", "[{\"url\": \"stun:stun.services.mozilla.com\"}]"); -pref("media.peerconnection.trickle_ice", true); pref("media.peerconnection.use_document_iceservers", true); // Do not enable identity before ensuring that the UX cannot be spoofed // see Bug 884573 for details From 962dcb158022a51ed35f4d4a67edc648f40c934a Mon Sep 17 00:00:00 2001 From: "Byron Campen [:bwc]" Date: Fri, 26 Sep 2014 15:54:36 -0700 Subject: [PATCH 09/58] Bug 1073710: Fix typos in vcmCheckAttribs that caused the max-dpb and max-fr to be set equal to the max-cpb. r=jesup --- media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp index 84547fc9e62f..af942cb66474 100644 --- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp +++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp @@ -2549,12 +2549,12 @@ cc_boolean vcmCheckAttribs(cc_uint32_t media_type, void *sdp_p, int level, rcap->max_cpb = t_uint; } - if ( ccsdpAttrGetFmtpMaxCpb(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS ) + if ( ccsdpAttrGetFmtpMaxDpb(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS ) { rcap->max_dpb = t_uint; } - if ( ccsdpAttrGetFmtpMaxCpb(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS ) + if ( ccsdpAttrGetFmtpMaxBr(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS ) { rcap->max_br = t_uint; } From 02bb2d0f9aea7d4583dd67a108f4fda7c1595d9d Mon Sep 17 00:00:00 2001 From: "Byron Campen [:bwc]" Date: Fri, 26 Sep 2014 16:02:46 -0700 Subject: [PATCH 10/58] Bug 1073226: Check whether PC is closed before delivering events. r=mt --- dom/media/PeerConnection.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index caf1bde15162..a30d7da003b9 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -497,7 +497,11 @@ RTCPeerConnection.prototype = { }, dispatchEvent: function(event) { - this.__DOM_IMPL__.dispatchEvent(event); + // PC can close while events are firing if there is an async dispatch + // in c++ land + if (!this._closed) { + this.__DOM_IMPL__.dispatchEvent(event); + } }, // Log error message to web console and window.onerror, if present. From b7f16a90532db58fa8ed5c2da6dfb7f7fd38c1fb Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Tue, 30 Sep 2014 16:11:16 -0400 Subject: [PATCH 11/58] Bug 1074548: lazy-allocate webrtc trace buffers in RELEASE_BUILDs r=ted --- build/gyp.mozbuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gyp.mozbuild b/build/gyp.mozbuild index c3c1cc9eaeb8..950804ae4549 100644 --- a/build/gyp.mozbuild +++ b/build/gyp.mozbuild @@ -31,7 +31,7 @@ gyp_vars = { 'use_openssl': 0, # saves 4MB when webrtc_trace is off - 'enable_lazy_trace_alloc': 0, + 'enable_lazy_trace_alloc': 1 if CONFIG['RELEASE_BUILD'] else 0, 'use_x11': 1 if CONFIG['MOZ_X11'] else 0, 'use_glib': 1 if CONFIG['GLIB_LIBS'] else 0, From ef58f4304f221b61cf34f837799b1dadd4ccc1f4 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 30 Sep 2014 16:20:48 -0400 Subject: [PATCH 12/58] Bug 1066664. Fix screenshot rotation. r=mwoodrow This moves the screenshot (now-nonexistent) unrotation code from the opengl compositor into ClientLayerManager.cpp --- gfx/layers/client/ClientLayerManager.cpp | 17 ++++++++ widget/WidgetUtils.h | 7 ++++ widget/xpwidgets/WidgetUtils.cpp | 52 ++++++++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index ffb298ab2b42..9c7354892827 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -443,7 +443,17 @@ ClientLayerManager::MakeSnapshotIfRequired() } if (mWidget) { if (CompositorChild* remoteRenderer = GetRemoteRenderer()) { + // The compositor doesn't draw to a different sized surface + // when there's a rotation. Instead we rotate the result + // when drawing into dt + nsIntRect outerBounds; + mWidget->GetBounds(outerBounds); + nsIntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents()); + if (mTargetRotation) { + bounds = RotateRect(bounds, outerBounds, mTargetRotation); + } + SurfaceDescriptor inSnapshot; if (!bounds.IsEmpty() && mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(), @@ -452,11 +462,18 @@ ClientLayerManager::MakeSnapshotIfRequired() remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) { RefPtr surf = GetSurfaceForDescriptor(inSnapshot); DrawTarget* dt = mShadowTarget->GetDrawTarget(); + Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height); Rect srcRect(0, 0, bounds.width, bounds.height); + + gfx::Matrix rotate = ComputeTransformForUnRotation(outerBounds, mTargetRotation); + + gfx::Matrix oldMatrix = dt->GetTransform(); + dt->SetTransform(oldMatrix * rotate); dt->DrawSurface(surf, dstRect, srcRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_OVER)); + dt->SetTransform(oldMatrix); } mForwarder->DestroySharedSurface(&inSnapshot); } diff --git a/widget/WidgetUtils.h b/widget/WidgetUtils.h index 9d740eccb53c..9511b298898e 100644 --- a/widget/WidgetUtils.h +++ b/widget/WidgetUtils.h @@ -26,6 +26,13 @@ enum ScreenRotation { gfx::Matrix ComputeTransformForRotation(const nsIntRect& aBounds, ScreenRotation aRotation); +gfx::Matrix ComputeTransformForUnRotation(const nsIntRect& aBounds, + ScreenRotation aRotation); + +nsIntRect RotateRect(nsIntRect aRect, + const nsIntRect& aBounds, + ScreenRotation aRotation); + } // namespace mozilla #endif // mozilla_WidgetUtils_h diff --git a/widget/xpwidgets/WidgetUtils.cpp b/widget/xpwidgets/WidgetUtils.cpp index 7db4c70096e1..6d6d05fbc328 100644 --- a/widget/xpwidgets/WidgetUtils.cpp +++ b/widget/xpwidgets/WidgetUtils.cpp @@ -37,4 +37,56 @@ ComputeTransformForRotation(const nsIntRect& aBounds, return transform; } +gfx::Matrix +ComputeTransformForUnRotation(const nsIntRect& aBounds, + ScreenRotation aRotation) +{ + gfx::Matrix transform; + static const gfx::Float floatPi = static_cast(M_PI); + + switch (aRotation) { + case ROTATION_0: + break; + case ROTATION_90: + transform.PreTranslate(0, aBounds.height); + transform.PreRotate(floatPi * 3 / 2); + break; + case ROTATION_180: + transform.PreTranslate(aBounds.width, aBounds.height); + transform.PreRotate(floatPi); + break; + case ROTATION_270: + transform.PreTranslate(aBounds.width, 0); + transform.PreRotate(floatPi / 2); + break; + default: + MOZ_CRASH("Unknown rotation"); + } + return transform; +} + +nsIntRect RotateRect(nsIntRect aRect, + const nsIntRect& aBounds, + ScreenRotation aRotation) +{ + switch (aRotation) { + case ROTATION_0: + return aRect; + case ROTATION_90: + return nsIntRect(aRect.y, + aBounds.width - aRect.x - aRect.width, + aRect.height, aRect.width); + case ROTATION_180: + return nsIntRect(aBounds.width - aRect.x - aRect.width, + aBounds.height - aRect.y - aRect.height, + aRect.width, aRect.height); + case ROTATION_270: + return nsIntRect(aBounds.height - aRect.y - aRect.height, + aRect.x, + aRect.height, aRect.width); + default: + MOZ_CRASH("Unknown rotation"); + return aRect; + } +} } // namespace mozilla From dafe148290445f478e4df91da16ae8caa7103b1c Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Tue, 30 Sep 2014 13:35:08 -0700 Subject: [PATCH 13/58] Bug 1074561 - Allow media plugins to run on Linuxes without sandboxing support. r=jesup --HG-- extra : amend_source : dcbbf2bcbb8481e60504c1483a61627bde4850a2 --- content/media/gmp/GMPChild.cpp | 8 ++++++-- content/media/gmp/GMPService.cpp | 8 -------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/content/media/gmp/GMPChild.cpp b/content/media/gmp/GMPChild.cpp index 7293a1013c67..bc6db6b9e403 100644 --- a/content/media/gmp/GMPChild.cpp +++ b/content/media/gmp/GMPChild.cpp @@ -263,8 +263,12 @@ GMPChild::LoadPluginLibrary(const std::string& aPluginPath) // Enable sandboxing here -- we know the plugin file's path, but // this process's execution hasn't been affected by its content yet. - MOZ_ASSERT(mozilla::CanSandboxMediaPlugin()); - mozilla::SetMediaPluginSandbox(nativePath.get()); + if (mozilla::CanSandboxMediaPlugin()) { + mozilla::SetMediaPluginSandbox(nativePath.get()); + } else { + printf_stderr("GMPChild::LoadPluginLibrary: Loading media plugin %s unsandboxed.\n", + nativePath.get()); + } #endif // XP_LINUX && MOZ_GMP_SANDBOX libFile->Load(&mLib); diff --git a/content/media/gmp/GMPService.cpp b/content/media/gmp/GMPService.cpp index 4a9285573241..c54eca156f19 100644 --- a/content/media/gmp/GMPService.cpp +++ b/content/media/gmp/GMPService.cpp @@ -22,9 +22,6 @@ #include "nsComponentManagerUtils.h" #include "mozilla/Preferences.h" #include "runnable_utils.h" -#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX) -#include "mozilla/Sandbox.h" -#endif namespace mozilla { @@ -625,11 +622,6 @@ NS_IMETHODIMP GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory) { MOZ_ASSERT(NS_IsMainThread()); -#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX) - if (!mozilla::CanSandboxMediaPlugin()) { - return NS_ERROR_NOT_AVAILABLE; - } -#endif nsCOMPtr thread; nsresult rv = GetThread(getter_AddRefs(thread)); if (NS_FAILED(rv)) { From 23fbe5d28f81a1b5ae61bd1b1ff6539c83df1567 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Tue, 30 Sep 2014 13:35:21 -0700 Subject: [PATCH 14/58] Bug 1074561 - Disable EME plugins on Linux if sandboxing is unavailable. r=jesup --HG-- extra : amend_source : 5e2192974cce18fd94abff72c9def32cfbaf675d --- content/media/gmp/GMPParent.cpp | 14 ++++++++++++++ content/media/gmp/GMPService.cpp | 11 +++++++++++ 2 files changed, 25 insertions(+) diff --git a/content/media/gmp/GMPParent.cpp b/content/media/gmp/GMPParent.cpp index 90878ca14f55..aed2d4e7a176 100644 --- a/content/media/gmp/GMPParent.cpp +++ b/content/media/gmp/GMPParent.cpp @@ -18,6 +18,9 @@ #include "nsIObserverService.h" #include "GMPTimerParent.h" #include "runnable_utils.h" +#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX) +#include "mozilla/Sandbox.h" +#endif #include "mozilla/dom/CrashReporterParent.h" using mozilla::dom::CrashReporterParent; @@ -852,6 +855,17 @@ GMPParent::ReadGMPMetaData() } } +#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX) + if (cap->mAPIName.EqualsLiteral("eme-decrypt") && + !mozilla::CanSandboxMediaPlugin()) { + printf_stderr("GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM" + " but this system can't sandbox it; not loading.\n", + mDisplayName.get()); + delete cap; + return NS_ERROR_FAILURE; + } +#endif + mCapabilities.AppendElement(cap); } diff --git a/content/media/gmp/GMPService.cpp b/content/media/gmp/GMPService.cpp index c54eca156f19..09817605d4bf 100644 --- a/content/media/gmp/GMPService.cpp +++ b/content/media/gmp/GMPService.cpp @@ -22,6 +22,9 @@ #include "nsComponentManagerUtils.h" #include "mozilla/Preferences.h" #include "runnable_utils.h" +#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX) +#include "mozilla/Sandbox.h" +#endif namespace mozilla { @@ -432,6 +435,14 @@ GeckoMediaPluginService::GetGMPDecryptor(nsTArray* aTags, const nsAString& aOrigin, GMPDecryptorProxy** aDecryptor) { +#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX) + if (!mozilla::CanSandboxMediaPlugin()) { + NS_WARNING("GeckoMediaPluginService::GetGMPDecryptor: " + "EME decryption not available without sandboxing support."); + return NS_ERROR_NOT_AVAILABLE; + } +#endif + MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); NS_ENSURE_ARG(aTags && aTags->Length() > 0); NS_ENSURE_ARG(aDecryptor); From 0d587be0934f65f09ec0df6f9a4f3ef80dc906f0 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Tue, 30 Sep 2014 13:53:09 -0700 Subject: [PATCH 15/58] Bug 1073826 - Fix isBrowserPrivate on Android (r=margaret) --- toolkit/modules/PrivateBrowsingUtils.jsm | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/toolkit/modules/PrivateBrowsingUtils.jsm b/toolkit/modules/PrivateBrowsingUtils.jsm index faa7b992c3cd..f322347fa380 100644 --- a/toolkit/modules/PrivateBrowsingUtils.jsm +++ b/toolkit/modules/PrivateBrowsingUtils.jsm @@ -34,7 +34,15 @@ this.PrivateBrowsingUtils = { }, isBrowserPrivate: function(aBrowser) { - return this.isWindowPrivate(aBrowser.ownerDocument.defaultView); + let chromeWin = aBrowser.ownerDocument.defaultView; + if (chromeWin.gMultiProcessBrowser) { + // In e10s we have to look at the chrome window's private + // browsing status since the only alternative is to check the + // content window, which is in another process. + return this.isWindowPrivate(chromeWin); + } else { + return this.privacyContextFromWindow(aBrowser.contentWindow).usePrivateBrowsing; + } }, privacyContextFromWindow: function pbu_privacyContextFromWindow(aWindow) { From e38122656e66d9a8c1803b28cd780fe297ed86ba Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Tue, 30 Sep 2014 13:53:59 -0700 Subject: [PATCH 16/58] Bug 1074410 - Remove a use of isWindowPrivate (r=margaret) --- mobile/android/chrome/content/aboutPrivateBrowsing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/android/chrome/content/aboutPrivateBrowsing.js b/mobile/android/chrome/content/aboutPrivateBrowsing.js index 9b04825309cd..0c8fce873b95 100644 --- a/mobile/android/chrome/content/aboutPrivateBrowsing.js +++ b/mobile/android/chrome/content/aboutPrivateBrowsing.js @@ -9,7 +9,7 @@ const Cu = Components.utils; Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); -if (!PrivateBrowsingUtils.isWindowPrivate(window)) { +if (!PrivateBrowsingUtils.isContentWindowPrivate(window)) { document.addEventListener("DOMContentLoaded", function () { document.body.setAttribute("class", "normal"); }, false); From b71a75b37a665d6c9543d6b017ff8b67dbab72f0 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 30 Sep 2014 14:17:27 -0700 Subject: [PATCH 17/58] Bug 1068276, part 1 - Allow configuring which type of processes we complain about when there's no leak log. r=jmaher Then don't warn for missing logs from tab and geckomediaplugin processes, or default processes on B2G. --- build/automationutils.py | 12 +++++++++--- layout/tools/reftest/remotereftest.py | 1 + layout/tools/reftest/runreftest.py | 4 +++- testing/mochitest/mochitest_options.py | 10 ++++++++++ testing/mochitest/runtests.py | 2 +- testing/mochitest/runtestsb2g.py | 2 +- 6 files changed, 25 insertions(+), 6 deletions(-) diff --git a/build/automationutils.py b/build/automationutils.py index dd9027ce5493..459a2dd77d7c 100644 --- a/build/automationutils.py +++ b/build/automationutils.py @@ -196,7 +196,7 @@ def dumpLeakLog(leakLogFile, filter = False): # Simply copy the log. log.info(leakReport.rstrip("\n")) -def processSingleLeakFile(leakLogFileName, processType, leakThreshold): +def processSingleLeakFile(leakLogFileName, processType, leakThreshold, ignoreMissingLeaks): """Process a single leak log. """ @@ -273,11 +273,16 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold): if crashedOnPurpose: log.info("TEST-INFO | leakcheck | %s deliberate crash and thus no leak log" % processString) + elif ignoreMissingLeaks: + log.info("TEST-INFO | leakcheck | %s ignoring missing output line for total leaks" + % processString) else: # TODO: This should be a TEST-UNEXPECTED-FAIL, but was changed to a warning # due to too many intermittent failures (see bug 831223). log.info("WARNING | leakcheck | %s missing output line for total leaks!" % processString) + log.info("TEST-INFO | leakcheck | missing output line from log file %s" + % leakLogFileName) return if totalBytesLeaked == 0: @@ -306,7 +311,7 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold): log.info("%s | leakcheck | %s %d bytes leaked (%s)" % (prefix, processString, totalBytesLeaked, leakedObjectSummary)) -def processLeakLog(leakLogFile, leakThresholds): +def processLeakLog(leakLogFile, leakThresholds, ignoreMissingLeaks): """Process the leak log, including separate leak logs created by child processes. @@ -363,7 +368,8 @@ def processLeakLog(leakLogFile, leakThresholds): log.info("TEST-UNEXPECTED-FAIL | leakcheck | Leak log with unknown process type %s" % processType) leakThreshold = leakThresholds.get(processType, 0) - processSingleLeakFile(thisFile, processType, leakThreshold) + processSingleLeakFile(thisFile, processType, leakThreshold, + processType in ignoreMissingLeaks) def replaceBackSlashes(input): return input.replace('\\', '/') diff --git a/layout/tools/reftest/remotereftest.py b/layout/tools/reftest/remotereftest.py index 8327ef064999..b105fc9500fe 100644 --- a/layout/tools/reftest/remotereftest.py +++ b/layout/tools/reftest/remotereftest.py @@ -164,6 +164,7 @@ class RemoteOptions(ReftestOptions): # Android does not run leak tests, but set some reasonable defaults to avoid errors. options.leakThresholds = {} + options.ignoreMissingLeaks = [] # TODO: Copied from main, but I think these are no longer used in a post xulrunner world #options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner' diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index c36b218d5c84..a9f22ffda411 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -344,7 +344,7 @@ class RefTest(object): # give the JS harness 30 seconds to deal # with its own timeouts timeout=options.timeout + 30.0) - processLeakLog(self.leakLogFile, options.leakThresholds) + processLeakLog(self.leakLogFile, options.leakThresholds, options.ignoreMissingLeaks) self.automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.") finally: self.cleanup(profileDir) @@ -513,6 +513,8 @@ class ReftestOptions(OptionParser): options.leakThresholds = {"default": options.defaultLeakThreshold} + options.ignoreMissingLeaks = [] + return options def main(): diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py index 4b259c442bee..f3e9773de517 100644 --- a/testing/mochitest/mochitest_options.py +++ b/testing/mochitest/mochitest_options.py @@ -615,6 +615,10 @@ class MochitestOptions(optparse.OptionParser): "tab": 10000, # See dependencies of bug 1051230. } + # Bug 1051230 - Leak logging does not yet work for tab processes on desktop. + # Bug 1065098 - The geckomediaplugin process fails to produce a leak log for some reason. + options.ignoreMissingLeaks = ["tab", "geckomediaplugin"] + return options @@ -819,6 +823,12 @@ class B2GOptions(MochitestOptions): options.sslPort = tempSSL options.httpPort = tempPort + # Bug 1071866 - B2G Mochitests do not always produce a leak log. + options.ignoreMissingLeaks.append("default") + + # Bug 1070068 - Leak logging does not work for tab processes on B2G. + assert "tab" in options.ignoreMissingLeaks, "Ignore failures for tab processes on B2G" + return options def elf_arm(self, filename): diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index c85ad35d0a16..52904ae741ef 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -1842,7 +1842,7 @@ class Mochitest(MochitestUtilsMixin): self.stopVMwareRecording(); self.stopServers() - processLeakLog(self.leak_report_file, options.leakThresholds) + processLeakLog(self.leak_report_file, options.leakThresholds, options.ignoreMissingLeaks) if self.nsprLogs: with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip: diff --git a/testing/mochitest/runtestsb2g.py b/testing/mochitest/runtestsb2g.py index 5d32e09d7b66..ed0a2d99cb47 100644 --- a/testing/mochitest/runtestsb2g.py +++ b/testing/mochitest/runtestsb2g.py @@ -202,7 +202,7 @@ class B2GMochitest(MochitestUtilsMixin): self.app_ctx.dm.getFile(self.leak_report_file, local_leak_file.name) self.app_ctx.dm.removeFile(self.leak_report_file) - processLeakLog(local_leak_file.name, options.leakThresholds) + processLeakLog(local_leak_file.name, options.leakThresholds, options.ignoreMissingLeaks) except KeyboardInterrupt: self.log.info("runtests.py | Received keyboard interrupt.\n"); status = -1 From 79f57cdabf7652c15907c44042e5b9e051a3ba13 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 30 Sep 2014 14:17:27 -0700 Subject: [PATCH 18/58] Bug 1068276, part 2 - Make unexpected failure to produce a leak log an error. r=jmaher --- build/automationutils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build/automationutils.py b/build/automationutils.py index 459a2dd77d7c..80cf66e7b430 100644 --- a/build/automationutils.py +++ b/build/automationutils.py @@ -277,9 +277,7 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold, ignoreMis log.info("TEST-INFO | leakcheck | %s ignoring missing output line for total leaks" % processString) else: - # TODO: This should be a TEST-UNEXPECTED-FAIL, but was changed to a warning - # due to too many intermittent failures (see bug 831223). - log.info("WARNING | leakcheck | %s missing output line for total leaks!" + log.info("TEST-UNEXPECTED-FAIL | leakcheck | %s missing output line for total leaks!" % processString) log.info("TEST-INFO | leakcheck | missing output line from log file %s" % leakLogFileName) From a2967c7d5e105d4d12e6797b8f6142039852d489 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Tue, 30 Sep 2014 11:11:50 -0700 Subject: [PATCH 19/58] Bug 1075053 - Use the GC's low-memory profile on mobile; r=sfink --HG-- extra : rebase_source : 664b0f188d2126cb4d549531479815ae3b00599a --- mobile/android/confvars.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mobile/android/confvars.sh b/mobile/android/confvars.sh index 120f36569b60..feb9662597f8 100644 --- a/mobile/android/confvars.sh +++ b/mobile/android/confvars.sh @@ -98,6 +98,8 @@ if test ! "$RELEASE_BUILD"; then MOZ_ANDROID_DOWNLOADS_INTEGRATION=1 fi - # Enable generational GC on mobile. JSGC_GENERATIONAL=1 + +# Use the low-memory GC tuning. +JS_GC_SMALL_CHUNK_SIZE=1 From 1aebc796884b824ca54005db41918a9473f66e14 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Tue, 30 Sep 2014 17:43:49 -0400 Subject: [PATCH 20/58] Bug 1064320 - NSC_Encrypt returns uninitialised garbage which is handed onwards to realloc --- dom/crypto/WebCryptoTask.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp index 90bf6c6002f4..384ef6f9c8e9 100644 --- a/dom/crypto/WebCryptoTask.cpp +++ b/dom/crypto/WebCryptoTask.cpp @@ -824,7 +824,7 @@ private: param.data = (unsigned char*) &oaepParams; param.len = sizeof(oaepParams); - uint32_t outLen; + uint32_t outLen = 0; if (mEncrypt) { // PK11_PubEncrypt() checks the plaintext's length and fails if it is too // long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k' @@ -841,9 +841,9 @@ private: mResult.Elements(), &outLen, mResult.Length(), mData.Elements(), mData.Length())); } - mResult.SetLength(outLen); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); + + mResult.SetLength(outLen); return NS_OK; } }; From fd4944d360f88e137d07c16447af5b81736ddb59 Mon Sep 17 00:00:00 2001 From: Eric Rahm Date: Tue, 30 Sep 2014 15:11:22 -0700 Subject: [PATCH 21/58] Bug 1075093 - Build error in txStylesheet.cpp when enabling PR_LOGGING in non-debug builds. r=froydnj --- dom/xslt/xslt/txStylesheet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/xslt/xslt/txStylesheet.cpp b/dom/xslt/xslt/txStylesheet.cpp index a9ee817923b1..9df69b8e76f2 100644 --- a/dom/xslt/xslt/txStylesheet.cpp +++ b/dom/xslt/xslt/txStylesheet.cpp @@ -128,7 +128,7 @@ txStylesheet::findTemplate(const txXPathNode& aNode, endFrame = aImportedBy->mFirstNotImported; } -#ifdef PR_LOGGING +#if defined(PR_LOGGING) && defined(TX_TO_STRING) txPattern* match = 0; #endif @@ -149,7 +149,7 @@ txStylesheet::findTemplate(const txXPathNode& aNode, if (templ.mMatch->matches(aNode, aContext)) { matchTemplate = templ.mFirstInstruction; *aImportFrame = frame; -#ifdef PR_LOGGING +#if defined(PR_LOGGING) && defined(TX_TO_STRING) match = templ.mMatch; #endif } From 2a400ac8f1027a78f91166e55292028cdf4b15a4 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 30 Sep 2014 15:18:29 -0700 Subject: [PATCH 22/58] Bug 1070465 - Give JS_UNINITIALIZED_LEXICAL constants unknown type sets in Ion. (r=jandem) --- js/src/jit-test/tests/ion/bug1070465.js | 5 +++++ js/src/jit/MIR.cpp | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 js/src/jit-test/tests/ion/bug1070465.js diff --git a/js/src/jit-test/tests/ion/bug1070465.js b/js/src/jit-test/tests/ion/bug1070465.js new file mode 100644 index 000000000000..68946a338373 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1070465.js @@ -0,0 +1,5 @@ +// |jit-test| error: ReferenceError +{ + while (x && 0) {} + let x +} diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 6c6ef3e03d2b..440503843284 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -573,6 +573,13 @@ jit::MakeSingletonTypeSet(types::CompilerConstraintList *constraints, JSObject * return alloc->new_(alloc, types::Type::ObjectType(obj)); } +static types::TemporaryTypeSet * +MakeUnknownTypeSet() +{ + LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc(); + return alloc->new_(alloc, types::Type::UnknownType()); +} + MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constraints) : value_(vp) { @@ -582,6 +589,16 @@ MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constra // other types as the result type encodes all needed information. setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject())); } + if (vp.isMagic() && vp.whyMagic() == JS_UNINITIALIZED_LEXICAL) { + // JS_UNINITIALIZED_LEXICAL does not escape to script and is not + // observed in type sets. However, it may flow around freely during + // Ion compilation. Give it an unknown typeset to poison any type sets + // it merges with. + // + // TODO We could track uninitialized lexicals more precisely by tracking + // them in type sets. + setResultTypeSet(MakeUnknownTypeSet()); + } setMovable(); } From 5dbc8ef624c4b215aaa35397e96a5b6c41bce229 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 30 Sep 2014 15:18:30 -0700 Subject: [PATCH 23/58] Bug 1073702 - Check for uninitialized lexical bindings in FetchName and friends. (r=jandem) --- js/src/jit-test/tests/ion/bug1073702.js | 10 ++++++++++ js/src/vm/Interpreter-inl.h | 7 +++++-- js/src/vm/Interpreter.cpp | 14 +++----------- 3 files changed, 18 insertions(+), 13 deletions(-) create mode 100644 js/src/jit-test/tests/ion/bug1073702.js diff --git a/js/src/jit-test/tests/ion/bug1073702.js b/js/src/jit-test/tests/ion/bug1073702.js new file mode 100644 index 000000000000..bd7d6df8a89a --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1073702.js @@ -0,0 +1,10 @@ +try { + let x = ((function f(y) { + if (y > 0) { + f(-1) + } + x + })(1)) +} catch (e) { + assertEq(e instanceof ReferenceError, true); +} diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 90937805e101..a4823501aad9 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -254,7 +254,10 @@ FetchName(JSContext *cx, HandleObject obj, HandleObject obj2, HandlePropertyName return false; } } - return true; + + // NAME operations are the slow paths already, so unconditionally check + // for uninitialized lets. + return CheckUninitializedLexical(cx, name, vp); } inline bool @@ -264,7 +267,7 @@ FetchNameNoGC(JSObject *pobj, Shape *shape, MutableHandleValue vp) return false; vp.set(pobj->nativeGetSlot(shape->slot())); - return true; + return !IsUninitializedLexical(vp); } inline bool diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 04deb6752390..f96635178dcf 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -298,17 +298,9 @@ NameOperation(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc, MutableHandle /* Kludge to allow (typeof foo == "undefined") tests. */ JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]); - if (op2 == JSOP_TYPEOF) { - if (!FetchName(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp)) - return false; - } else { - if (!FetchName(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp)) - return false; - } - - // NAME operations are the slow paths already, so unconditionally check - // for uninitialized lets. - return CheckUninitializedLexical(cx, nameRoot, vp); + if (op2 == JSOP_TYPEOF) + return FetchName(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp); + return FetchName(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp); } static inline bool From f7f8c6ce8cdfbf56252d1c8d6ba10ac95f95ac5d Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 30 Sep 2014 15:18:30 -0700 Subject: [PATCH 24/58] Bug 1074504 - Consider TDZ uses effectful in the frontend. (r=Waldo) --- js/src/frontend/BytecodeEmitter.cpp | 6 +++++ .../jit-test/tests/basic/letTDZEffectful.js | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 js/src/jit-test/tests/basic/letTDZEffectful.js diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 5c6e97300f8a..7c571324d128 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -2016,6 +2016,12 @@ CheckSideEffects(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool *answer = true; } } + + if (pn->isHoistedLetUse()) { + // Hoisted uses of lexical bindings throw on access. + *answer = true; + } + if (pn->isKind(PNK_DOT)) { /* Dotted property references in general can call getters. */ *answer = true; diff --git a/js/src/jit-test/tests/basic/letTDZEffectful.js b/js/src/jit-test/tests/basic/letTDZEffectful.js new file mode 100644 index 000000000000..e2f859bf1e43 --- /dev/null +++ b/js/src/jit-test/tests/basic/letTDZEffectful.js @@ -0,0 +1,24 @@ +function assertThrowsReferenceError(f) { + var e = null; + try { + f(); + } catch (ex) { + e = ex; + } + assertEq(e instanceof ReferenceError, true); +} + +// TDZ is effectful, don't optimize out x. +assertThrowsReferenceError(function () { x; let x; }); + +// FIXME do this unconditionally once bug 611388 lands. +function constIsLexical() { + try { + (function () { z++; const z; })(); + return false; + } catch (e) { + return true; + } +} +if (constIsLexical()) + assertThrowsReferenceError(function () { x; const x; }); From 1303551d3c9a4b429256029885a829e7c1d2df8e Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 30 Sep 2014 15:18:30 -0700 Subject: [PATCH 25/58] Bug 1074571 - Make the delete operator trigger TDZ. (r=Waldo) --- js/src/jit-test/tests/basic/letTDZDelete.js | 23 +++++++++++++++++++++ js/src/vm/Interpreter.cpp | 11 ++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 js/src/jit-test/tests/basic/letTDZDelete.js diff --git a/js/src/jit-test/tests/basic/letTDZDelete.js b/js/src/jit-test/tests/basic/letTDZDelete.js new file mode 100644 index 000000000000..6fb1048f0cbe --- /dev/null +++ b/js/src/jit-test/tests/basic/letTDZDelete.js @@ -0,0 +1,23 @@ +function assertThrowsReferenceError(f) { + var e = null; + try { + f(); + } catch (ex) { + e = ex; + } + assertEq(e instanceof ReferenceError, true); +} + +assertThrowsReferenceError(function () { delete x; let x; }); + +// FIXME do this unconditionally once bug 611388 lands. +function constIsLexical() { + try { + (function () { z++; const z; })(); + return false; + } catch (e) { + return true; + } +} +if (constIsLexical()) + assertThrowsReferenceError(function () { delete x; const x; }); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index f96635178dcf..924eb390bbc9 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -3556,7 +3556,7 @@ js::GetScopeName(JSContext *cx, HandleObject scopeChain, HandlePropertyName name if (!JSObject::getProperty(cx, obj, obj, name, vp)) return false; - // See note in NameOperation. + // See note in FetchName. return CheckUninitializedLexical(cx, name, vp); } @@ -3581,7 +3581,7 @@ js::GetScopeNameForTypeOf(JSContext *cx, HandleObject scopeChain, HandleProperty if (!JSObject::getProperty(cx, obj, obj, name, vp)) return false; - // See note in NameOperation. + // See note in FetchName. return CheckUninitializedLexical(cx, name, vp); } @@ -3866,6 +3866,13 @@ js::DeleteNameOperation(JSContext *cx, HandlePropertyName name, HandleObject sco return true; } + // NAME operations are the slow paths already, so unconditionally check + // for uninitialized lets. + if (pobj == scope && IsUninitializedLexicalSlot(scope, shape)) { + ReportUninitializedLexical(cx, name); + return false; + } + bool succeeded; RootedId id(cx, NameToId(name)); if (!JSObject::deleteGeneric(cx, scope, id, &succeeded)) From 12d7d71d8f5b8951536eac66a436926f8e970598 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 30 Sep 2014 18:19:25 -0400 Subject: [PATCH 26/58] Bug 1062377 - Try loading profile.ini in background; r=mfinkle r=rnewman We can move our profile accessing code to later in the startup process. The benefit of that is in early startup, we can prefetch the profile.ini file in the background and not block the UI thread --- mobile/android/base/GeckoApp.java | 12 ++++++++++-- mobile/android/base/db/SuggestedSites.java | 18 +++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index c7222399a03d..2234097499fa 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -1163,7 +1163,13 @@ public abstract class GeckoApp } } - BrowserDB.initialize(getProfile().getName()); + // Speculatively pre-fetch the profile in the background. + ThreadUtils.postToBackgroundThread(new Runnable() { + @Override + public void run() { + getProfile(); + } + }); // Workaround for . try { @@ -1425,6 +1431,8 @@ public abstract class GeckoApp initializeChrome(); + BrowserDB.initialize(getProfile().getName()); + // If we are doing a restore, read the session data and send it to Gecko if (!mIsRestoringActivity) { String restoreMessage = null; @@ -1647,7 +1655,7 @@ public abstract class GeckoApp } } - public GeckoProfile getProfile() { + public synchronized GeckoProfile getProfile() { // fall back to default profile if we didn't load a specific one if (mProfile == null) { mProfile = GeckoProfile.get(this); diff --git a/mobile/android/base/db/SuggestedSites.java b/mobile/android/base/db/SuggestedSites.java index d6cf7b630e10..2a1b88f730dc 100644 --- a/mobile/android/base/db/SuggestedSites.java +++ b/mobile/android/base/db/SuggestedSites.java @@ -157,7 +157,7 @@ public class SuggestedSites { final Context context; final Distribution distribution; - final File file; + private File cachedFile; private Map cachedSites; private Set cachedBlacklist; @@ -166,14 +166,20 @@ public class SuggestedSites { } public SuggestedSites(Context appContext, Distribution distribution) { - this(appContext, distribution, - GeckoProfile.get(appContext).getFile(FILENAME)); + this(appContext, distribution, null); } public SuggestedSites(Context appContext, Distribution distribution, File file) { this.context = appContext; this.distribution = distribution; - this.file = file; + this.cachedFile = file; + } + + synchronized File getFile() { + if (cachedFile == null) { + cachedFile = GeckoProfile.get(context).getFile(FILENAME); + } + return cachedFile; } private static boolean isNewLocale(Context context, Locale requestedLocale) { @@ -306,6 +312,7 @@ public class SuggestedSites { setCachedSites(sites); // Save the result to disk. + final File file = getFile(); synchronized (file) { saveSites(file, sites); } @@ -349,6 +356,7 @@ public class SuggestedSites { private Map loadFromProfile() { try { + final File file = getFile(); synchronized (file) { return loadSites(file); } @@ -462,7 +470,7 @@ public class SuggestedSites { // Force the suggested sites file in profile dir to be re-generated // if the locale has changed. if (isNewLocale) { - file.delete(); + getFile().delete(); } if (cachedSites == null || isNewLocale) { From 18d2c2ded222a63d16e152de618ea5cd3ba34238 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 30 Sep 2014 18:19:25 -0400 Subject: [PATCH 27/58] Bug 1062377 - Rewrite GeckoBackgroundThread to not wait for thread start if possible; r=rnewman When GeckoBackgroundThread is first used, it starts a new thread and waits for a Handler. This can delay startup. Instead, we can just save the Runnable and run it when the thread is starting. --- .../base/util/GeckoBackgroundThread.java | 69 ++++++++++++------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/mobile/android/base/util/GeckoBackgroundThread.java b/mobile/android/base/util/GeckoBackgroundThread.java index bdd64d096d23..442f782e2f52 100644 --- a/mobile/android/base/util/GeckoBackgroundThread.java +++ b/mobile/android/base/util/GeckoBackgroundThread.java @@ -12,44 +12,65 @@ import java.util.concurrent.SynchronousQueue; final class GeckoBackgroundThread extends Thread { private static final String LOOPER_NAME = "GeckoBackgroundThread"; - // Guarded by 'this'. - private static Handler sHandler; - private SynchronousQueue mHandlerQueue = new SynchronousQueue(); + // Guarded by 'GeckoBackgroundThread.class'. + private static Handler handler; + private static Thread thread; + + // The initial Runnable to run on the new thread. Its purpose + // is to avoid us having to wait for the new thread to start. + private Runnable initialRunnable; // Singleton, so private constructor. - private GeckoBackgroundThread() { - super(); + private GeckoBackgroundThread(final Runnable initialRunnable) { + this.initialRunnable = initialRunnable; } @Override public void run() { setName(LOOPER_NAME); Looper.prepare(); - try { - mHandlerQueue.put(new Handler()); - } catch (InterruptedException ie) {} + + synchronized (GeckoBackgroundThread.class) { + handler = new Handler(); + GeckoBackgroundThread.class.notify(); + } + + if (initialRunnable != null) { + initialRunnable.run(); + initialRunnable = null; + } Looper.loop(); } - // Get a Handler for a looper thread, or create one if it doesn't yet exist. - /*package*/ static synchronized Handler getHandler() { - if (sHandler == null) { - GeckoBackgroundThread lt = new GeckoBackgroundThread(); - ThreadUtils.setBackgroundThread(lt); - lt.start(); - try { - sHandler = lt.mHandlerQueue.take(); - } catch (InterruptedException ie) {} - } - return sHandler; + private static void startThread(final Runnable initialRunnable) { + thread = new GeckoBackgroundThread(initialRunnable); + ThreadUtils.setBackgroundThread(thread); + + thread.setDaemon(true); + thread.start(); } - /*package*/ static void post(Runnable runnable) { - Handler handler = getHandler(); - if (handler == null) { - throw new IllegalStateException("No handler! Must have been interrupted. Not posting."); + // Get a Handler for a looper thread, or create one if it doesn't yet exist. + /*package*/ static synchronized Handler getHandler() { + if (thread == null) { + startThread(null); } - handler.post(runnable); + + while (handler == null) { + try { + GeckoBackgroundThread.class.wait(); + } catch (final InterruptedException e) { + } + } + return handler; + } + + /*package*/ static synchronized void post(final Runnable runnable) { + if (thread == null) { + startThread(runnable); + return; + } + getHandler().post(runnable); } } From 331fc995557542a012ba57eccb9a3d160be94fc2 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 30 Sep 2014 18:19:26 -0400 Subject: [PATCH 28/58] Bug 1062377 - Add JUnit test for new GeckoBackgroundThread; r=rnewman --- mobile/android/base/util/ThreadUtils.java | 2 + mobile/android/tests/browser/junit3/moz.build | 3 + .../junit3/src/TestGeckoBackgroundThread.java | 55 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 mobile/android/tests/browser/junit3/src/TestGeckoBackgroundThread.java diff --git a/mobile/android/base/util/ThreadUtils.java b/mobile/android/base/util/ThreadUtils.java index 967fa2b49dc6..90043b589ee7 100644 --- a/mobile/android/base/util/ThreadUtils.java +++ b/mobile/android/base/util/ThreadUtils.java @@ -189,6 +189,7 @@ public final class ThreadUtils { return isOnThread(getUiThread()); } + @RobocopTarget public static boolean isOnBackgroundThread() { if (sBackgroundThread == null) { return false; @@ -197,6 +198,7 @@ public final class ThreadUtils { return isOnThread(sBackgroundThread); } + @RobocopTarget public static boolean isOnThread(Thread thread) { return (Thread.currentThread().getId() == thread.getId()); } diff --git a/mobile/android/tests/browser/junit3/moz.build b/mobile/android/tests/browser/junit3/moz.build index e5cdd8da2d18..9f8474bbd686 100644 --- a/mobile/android/tests/browser/junit3/moz.build +++ b/mobile/android/tests/browser/junit3/moz.build @@ -12,6 +12,9 @@ jar.sources += [ 'src/harness/BrowserInstrumentationTestRunner.java', 'src/harness/BrowserTestListener.java', 'src/TestDistribution.java', + 'src/TestGeckoBackgroundThread.java', + 'src/TestGeckoMenu.java', + 'src/TestGeckoProfilesProvider.java', 'src/TestGeckoSharedPrefs.java', 'src/TestImageDownloader.java', 'src/TestJarReader.java', diff --git a/mobile/android/tests/browser/junit3/src/TestGeckoBackgroundThread.java b/mobile/android/tests/browser/junit3/src/TestGeckoBackgroundThread.java new file mode 100644 index 000000000000..a2bec3d6122b --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/TestGeckoBackgroundThread.java @@ -0,0 +1,55 @@ +/* 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/. */ + +package org.mozilla.gecko; + +import org.mozilla.gecko.util.ThreadUtils; + +public class TestGeckoBackgroundThread extends BrowserTestCase { + + private boolean finishedTest; + private boolean ranFirstRunnable; + + public void testGeckoBackgroundThread() throws InterruptedException { + + final Thread testThread = Thread.currentThread(); + + ThreadUtils.postToBackgroundThread(new Runnable() { + @Override + public void run() { + // Must *not* be on thread that posted the Runnable. + assertFalse(ThreadUtils.isOnThread(testThread)); + + // Must be on background thread. + assertTrue(ThreadUtils.isOnBackgroundThread()); + + ranFirstRunnable = true; + } + }); + + // Post a second Runnable to make sure it still runs on the background thread, + // and it only runs after the first Runnable has run. + ThreadUtils.postToBackgroundThread(new Runnable() { + @Override + public void run() { + // Must still be on background thread. + assertTrue(ThreadUtils.isOnBackgroundThread()); + + // This Runnable must be run after the first Runnable had finished. + assertTrue(ranFirstRunnable); + + synchronized (TestGeckoBackgroundThread.this) { + finishedTest = true; + TestGeckoBackgroundThread.this.notify(); + } + } + }); + + synchronized (this) { + while (!finishedTest) { + wait(); + } + } + } +} From 32dd31158fd0813093b49cb84e8050c91002a5e6 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 30 Sep 2014 18:19:26 -0400 Subject: [PATCH 29/58] Bug 1062377 - Lock profile and use separate LocalBrowserDB instance for initializing new profile; r=rnewman --- mobile/android/base/GeckoProfile.java | 33 ++++++++++++++++--------- mobile/android/base/tests/BaseTest.java | 2 +- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/mobile/android/base/GeckoProfile.java b/mobile/android/base/GeckoProfile.java index 040fed2eb88d..cec58c13f476 100644 --- a/mobile/android/base/GeckoProfile.java +++ b/mobile/android/base/GeckoProfile.java @@ -17,7 +17,7 @@ import java.util.Hashtable; import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException; import org.mozilla.gecko.GeckoProfileDirectories.NoSuchProfileException; -import org.mozilla.gecko.db.BrowserDB; +import org.mozilla.gecko.db.LocalBrowserDB; import org.mozilla.gecko.distribution.Distribution; import org.mozilla.gecko.mozglue.RobocopTarget; import org.mozilla.gecko.util.INIParser; @@ -209,7 +209,7 @@ public final class GeckoProfile { * Now do the things that createProfileDirectory normally does -- * right now that's kicking off DB init. */ - profile.enqueueInitialization(); + profile.enqueueInitialization(profile.getDir()); return profile; } catch (Exception ex) { @@ -650,7 +650,7 @@ public final class GeckoProfile { // Trigger init for non-webapp profiles. if (!mIsWebAppProfile) { - enqueueInitialization(); + enqueueInitialization(profileDir); } // Write out profile creation time, mirroring the logic in nsToolkitProfileService. @@ -684,7 +684,7 @@ public final class GeckoProfile { * This is public for use *from tests only*! */ @RobocopTarget - public void enqueueInitialization() { + public void enqueueInitialization(final File profileDir) { Log.i(LOGTAG, "Enqueuing profile init."); final Context context = mApplicationContext; @@ -697,13 +697,24 @@ public final class GeckoProfile { final ContentResolver cr = context.getContentResolver(); - // We pass the number of added bookmarks to ensure that the - // indices of the distribution and default bookmarks are - // contiguous. Because there are always at least as many - // bookmarks as there are favicons, we can also guarantee that - // the favicon IDs won't overlap. - final int offset = BrowserDB.addDistributionBookmarks(cr, distribution, 0); - BrowserDB.addDefaultBookmarks(context, cr, offset); + // Because we are running in the background, we want to synchronize on the + // GeckoProfile instance so that we don't race with main thread operations + // such as locking/unlocking/removing the profile. + synchronized (GeckoProfile.this) { + // Skip initialization if the profile directory has been removed. + if (!profileDir.exists()) { + return; + } + + // We pass the number of added bookmarks to ensure that the + // indices of the distribution and default bookmarks are + // contiguous. Because there are always at least as many + // bookmarks as there are favicons, we can also guarantee that + // the favicon IDs won't overlap. + final LocalBrowserDB db = new LocalBrowserDB(getName()); + final int offset = db.addDistributionBookmarks(cr, distribution, 0); + db.addDefaultBookmarks(context, cr, offset); + } } }); } diff --git a/mobile/android/base/tests/BaseTest.java b/mobile/android/base/tests/BaseTest.java index b49ea390d086..a2efec9bf103 100644 --- a/mobile/android/base/tests/BaseTest.java +++ b/mobile/android/base/tests/BaseTest.java @@ -133,7 +133,7 @@ abstract class BaseTest extends BaseRobocopTest { // In Robocop tests, we typically don't get initialized correctly, because // GeckoProfile doesn't create the profile directory. - profile.enqueueInitialization(); + profile.enqueueInitialization(profile.getDir()); } @Override From fb28ffc3735ad77234cfbfb7b4dd90b35b035bab Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 30 Sep 2014 18:20:58 -0400 Subject: [PATCH 30/58] Bug 888482 - Make new event to set layer client in Gecko; r=snorp --- mobile/android/base/GeckoEvent.java | 12 ++++++++++++ widget/android/AndroidJavaWrappers.cpp | 9 +++++++++ widget/android/AndroidJavaWrappers.h | 10 ++++++++++ widget/android/nsAppShell.cpp | 14 ++++++++++++++ 4 files changed, 45 insertions(+) diff --git a/mobile/android/base/GeckoEvent.java b/mobile/android/base/GeckoEvent.java index 6a55fbca0512..4239b6a4ad18 100644 --- a/mobile/android/base/GeckoEvent.java +++ b/mobile/android/base/GeckoEvent.java @@ -76,6 +76,7 @@ public class GeckoEvent { KEY_EVENT(1), MOTION_EVENT(2), SENSOR_EVENT(3), + PROCESS_OBJECT(4), LOCATION_EVENT(5), IME_EVENT(6), SIZE_CHANGED(8), @@ -183,6 +184,8 @@ public class GeckoEvent { public static final int ACTION_GAMEPAD_BUTTON = 1; public static final int ACTION_GAMEPAD_AXES = 2; + public static final int ACTION_OBJECT_LAYER_CLIENT = 1; + private final int mType; private int mAction; private boolean mAckNeeded; @@ -245,6 +248,8 @@ public class GeckoEvent { private String[] mPrefNames; + private Object mObject; + private GeckoEvent(NativeGeckoEvent event) { mType = event.value; } @@ -597,6 +602,13 @@ public class GeckoEvent { return event; } + public static GeckoEvent createObjectEvent(final int action, final Object object) { + GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.PROCESS_OBJECT); + event.mAction = action; + event.mObject = object; + return event; + } + public static GeckoEvent createLocationEvent(Location l) { GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOCATION_EVENT); event.mLocation = l; diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index bdb76a948ff4..bf300ed66376 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -71,6 +71,7 @@ jfieldID AndroidGeckoEvent::jGamepadButtonPressedField = 0; jfieldID AndroidGeckoEvent::jGamepadButtonValueField = 0; jfieldID AndroidGeckoEvent::jGamepadValuesField = 0; jfieldID AndroidGeckoEvent::jPrefNamesField = 0; +jfieldID AndroidGeckoEvent::jObjectField = 0; jclass AndroidGeckoEvent::jDomKeyLocationClass = 0; jfieldID AndroidGeckoEvent::jDomKeyLocationValueField = 0; @@ -183,6 +184,7 @@ AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv) jGamepadButtonValueField = getField("mGamepadButtonValue", "F"); jGamepadValuesField = getField("mGamepadValues", "[F"); jPrefNamesField = getField("mPrefNames", "[Ljava/lang/String;"); + jObjectField = getField("mObject", "Ljava/lang/Object;"); // Init GeckoEvent.DomKeyLocation enum jDomKeyLocationClass = getClassGlobalRef("org/mozilla/gecko/GeckoEvent$DomKeyLocation"); @@ -503,6 +505,13 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj) mMetaState = jenv->GetIntField(jobj, jMetaStateField); break; + case PROCESS_OBJECT: { + const jobject obj = jenv->GetObjectField(jobj, jObjectField); + mObject.Init(obj, jenv); + jenv->DeleteLocalRef(obj); + break; + } + case LOCATION_EVENT: { jobject location = jenv->GetObjectField(jobj, jLocationField); mGeoPosition = AndroidLocation::CreateGeoPosition(jenv, location); diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h index e4cbf4c078c6..e2e7dc6e4aea 100644 --- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -552,6 +552,7 @@ public: float GamepadButtonValue() { return mGamepadButtonValue; } const nsTArray& GamepadValues() { return mGamepadValues; } int RequestId() { return mCount; } // for convenience + const AutoGlobalWrappedJavaObject& Object() { return mObject; } bool CanCoalesceWith(AndroidGeckoEvent* ae); WidgetTouchEvent MakeTouchEvent(nsIWidget* widget); MultiTouchInput MakeMultiTouchInput(nsIWidget* widget); @@ -601,6 +602,7 @@ protected: nsTArray mPrefNames; MultiTouchInput mApzInput; mozilla::layers::ScrollableLayerGuid mApzGuid; + AutoGlobalWrappedJavaObject mObject; void ReadIntArray(nsTArray &aVals, JNIEnv *jenv, @@ -685,6 +687,8 @@ protected: static jfieldID jGamepadButtonValueField; static jfieldID jGamepadValuesField; + static jfieldID jObjectField; + static jclass jDomKeyLocationClass; static jfieldID jDomKeyLocationValueField; @@ -694,6 +698,7 @@ public: KEY_EVENT = 1, MOTION_EVENT = 2, SENSOR_EVENT = 3, + PROCESS_OBJECT = 4, LOCATION_EVENT = 5, IME_EVENT = 6, SIZE_CHANGED = 8, @@ -766,6 +771,11 @@ public: ACTION_GAMEPAD_BUTTON = 1, ACTION_GAMEPAD_AXES = 2 }; + + enum { + ACTION_OBJECT_LAYER_CLIENT = 1, + dummy_object_enum_list_end + }; }; class nsJNIString : public nsString diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp index 222bf3ff0a2b..8108035f7ad0 100644 --- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -312,6 +312,20 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) } break; + case AndroidGeckoEvent::PROCESS_OBJECT: { + JNIEnv* const env = AndroidBridge::Bridge()->GetJNIEnv(); + AutoLocalJNIFrame frame(env, 1); + + switch (curEvent->Action()) { + case AndroidGeckoEvent::ACTION_OBJECT_LAYER_CLIENT: + // SetLayerClient expects a local reference + const jobject obj = env->NewLocalRef(curEvent->Object().wrappedObject()); + AndroidBridge::Bridge()->SetLayerClient(env, obj); + break; + } + break; + } + case AndroidGeckoEvent::LOCATION_EVENT: { if (!gLocationCallback) break; From f6e00ce7f5321ed9c7570363a993763f7be05768 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 30 Sep 2014 18:20:58 -0400 Subject: [PATCH 31/58] Bug 888482 - Send event to set layer client; r=snorp --- mobile/android/base/GeckoApp.java | 4 +++- mobile/android/base/GeckoAppShell.java | 5 ----- mobile/android/base/GeckoView.java | 3 ++- mozglue/android/jni-stubs.inc | 19 ------------------- widget/android/AndroidJNI.cpp | 6 ------ 5 files changed, 5 insertions(+), 32 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 2234097499fa..a9f37298e497 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -1374,6 +1374,9 @@ public abstract class GeckoApp layerView.initializeView(EventDispatcher.getInstance()); mLayerView = layerView; GeckoAppShell.setLayerView(layerView); + GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent( + GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, layerView.getLayerClientObject())); + // bind the GeckoEditable instance to the new LayerView GeckoAppShell.notifyIMEContext(GeckoEditableListener.IME_STATE_DISABLED, "", "", ""); } @@ -1588,7 +1591,6 @@ public abstract class GeckoApp if (selectedTab != null) Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED); geckoConnected(); - GeckoAppShell.setLayerClient(mLayerView.getLayerClientObject()); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null)); } diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 5724fe0ac4cc..438282cafe42 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -198,8 +198,6 @@ public class GeckoAppShell public static native void nativeInit(); // helper methods - // public static native void setSurfaceView(GeckoSurfaceView sv); - public static native void setLayerClient(Object client); public static native void onResume(); public static void callObserver(String observerKey, String topic, String data) { sendEventToGecko(GeckoEvent.createCallObserverEvent(observerKey, topic, data)); @@ -335,9 +333,6 @@ public class GeckoAppShell // run gecko -- it will spawn its own thread GeckoAppShell.nativeInit(); - if (sLayerView != null) - GeckoAppShell.setLayerClient(sLayerView.getLayerClientObject()); - // First argument is the .apk path String combinedArgs = apkPath + " -greomni " + apkPath; if (args != null) diff --git a/mobile/android/base/GeckoView.java b/mobile/android/base/GeckoView.java index be3936194fcb..8309a5d187f1 100644 --- a/mobile/android/base/GeckoView.java +++ b/mobile/android/base/GeckoView.java @@ -174,6 +174,8 @@ public class GeckoView extends LayerView BrowserDB.initialize(profile.getName()); GeckoAppShell.setLayerView(this); + GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent( + GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, getLayerClientObject())); GeckoThread.createAndStart(); } else if(GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) { // If Gecko is already running, that means the Activity was @@ -247,7 +249,6 @@ public class GeckoView extends LayerView if (selectedTab != null) Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED); geckoConnected(); - GeckoAppShell.setLayerClient(getLayerClientObject()); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null)); } diff --git a/mozglue/android/jni-stubs.inc b/mozglue/android/jni-stubs.inc index 5833e72a9caf..babd19bde979 100644 --- a/mozglue/android/jni-stubs.inc +++ b/mozglue/android/jni-stubs.inc @@ -96,25 +96,6 @@ Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv * arg0, jclass arg1) { #ifdef JNI_STUBS -typedef void (*Java_org_mozilla_gecko_GeckoAppShell_setLayerClient_t)(JNIEnv *, jclass, jobject); -static Java_org_mozilla_gecko_GeckoAppShell_setLayerClient_t f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient; -extern "C" NS_EXPORT void JNICALL -Java_org_mozilla_gecko_GeckoAppShell_setLayerClient(JNIEnv * arg0, jclass arg1, jobject arg2) { - if (!f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient) { - arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), - "JNI Function called before it was loaded"); - return ; - } - f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient(arg0, arg1, arg2); -} -#endif - -#ifdef JNI_BINDINGS - xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_setLayerClient", &f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient); -#endif - -#ifdef JNI_STUBS - typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onResume_t)(JNIEnv *, jclass); static Java_org_mozilla_gecko_GeckoAppShell_onResume_t f_Java_org_mozilla_gecko_GeckoAppShell_onResume; extern "C" NS_EXPORT void JNICALL diff --git a/widget/android/AndroidJNI.cpp b/widget/android/AndroidJNI.cpp index 3a2b8396d9bf..58702163f806 100644 --- a/widget/android/AndroidJNI.cpp +++ b/widget/android/AndroidJNI.cpp @@ -119,12 +119,6 @@ Java_org_mozilla_gecko_GeckoAppShell_runUiThreadCallback(JNIEnv* env, jclass) return AndroidBridge::Bridge()->RunDelayedUiThreadTasks(); } -NS_EXPORT void JNICALL -Java_org_mozilla_gecko_GeckoAppShell_setLayerClient(JNIEnv *jenv, jclass, jobject obj) -{ - AndroidBridge::Bridge()->SetLayerClient(jenv, obj); -} - NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *jenv, jclass jc) { From 713dfafceb15c876033feac43b3d7c5bcf98c40d Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 30 Sep 2014 18:20:59 -0400 Subject: [PATCH 32/58] Bug 888482 - Start Gecko early; r=snorp --- mobile/android/base/GeckoApp.java | 44 ++++++++++++++++++------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index a9f37298e497..165ec68a57d5 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -1124,6 +1124,7 @@ public abstract class GeckoApp mGeckoReadyStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY"); final Intent intent = getIntent(); + final String action = intent.getAction(); final String args = intent.getStringExtra("args"); earlyStartJavaSampler(intent); @@ -1211,6 +1212,30 @@ public abstract class GeckoApp // without killing the entire application (see Bug 769269). mIsRestoringActivity = true; Telemetry.HistogramAdd("FENNEC_RESTORING_ACTIVITY", 1); + + } else { + final String uri = getURIFromIntent(intent); + + GeckoThread.setArgs(args); + GeckoThread.setAction(action); + GeckoThread.setUri(TextUtils.isEmpty(uri) ? null : uri); + } + + if (!ACTION_DEBUG.equals(action) && + GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, + GeckoThread.LaunchState.Launched)) { + GeckoThread.createAndStart(); + + } else if (ACTION_DEBUG.equals(action) && + GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, + GeckoThread.LaunchState.WaitForDebugger)) { + ThreadUtils.getUiHandler().postDelayed(new Runnable() { + @Override + public void run() { + GeckoThread.setLaunchState(GeckoThread.LaunchState.Launched); + GeckoThread.createAndStart(); + } + }, 1000 * 5 /* 5 seconds */); } Bundle stateBundle = getIntent().getBundleExtra(EXTRA_STATE_BUNDLE); @@ -1478,25 +1503,6 @@ public abstract class GeckoApp Telemetry.HistogramAdd("FENNEC_STARTUP_GECKOAPP_ACTION", startupAction.ordinal()); - if (!mIsRestoringActivity) { - GeckoThread.setArgs(intent.getStringExtra("args")); - GeckoThread.setAction(intent.getAction()); - GeckoThread.setUri(passedUri); - } - if (!ACTION_DEBUG.equals(action) && - GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) { - GeckoThread.createAndStart(); - } else if (ACTION_DEBUG.equals(action) && - GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.WaitForDebugger)) { - ThreadUtils.getUiHandler().postDelayed(new Runnable() { - @Override - public void run() { - GeckoThread.setLaunchState(GeckoThread.LaunchState.Launching); - GeckoThread.createAndStart(); - } - }, 1000 * 5 /* 5 seconds */); - } - // Check if launched from data reporting notification. if (ACTION_LAUNCH_SETTINGS.equals(action)) { Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class); From df48524a262f9efa5c78eb7f27e63ddf4040609d Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 30 Sep 2014 18:20:59 -0400 Subject: [PATCH 33/58] Bug 888482 - Make sure default profile exists when starting Gecko; r=snorp --- mobile/android/base/GeckoThread.java | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/mobile/android/base/GeckoThread.java b/mobile/android/base/GeckoThread.java index 8de0341ecba9..0b424f4cecb1 100644 --- a/mobile/android/base/GeckoThread.java +++ b/mobile/android/base/GeckoThread.java @@ -136,25 +136,29 @@ public class GeckoThread extends Thread implements GeckoEventListener { } private String addCustomProfileArg(String args) { - String profile = ""; - String guest = ""; + String profileArg = ""; + String guestArg = ""; if (GeckoAppShell.getGeckoInterface() != null) { - if (GeckoAppShell.getGeckoInterface().getProfile().inGuestMode()) { + final GeckoProfile profile = GeckoAppShell.getGeckoInterface().getProfile(); + + if (profile.inGuestMode()) { try { - profile = " -profile " + GeckoAppShell.getGeckoInterface().getProfile().getDir().getCanonicalPath(); - } catch (IOException ioe) { Log.e(LOGTAG, "error getting guest profile path", ioe); } + profileArg = " -profile " + profile.getDir().getCanonicalPath(); + } catch (final IOException ioe) { + Log.e(LOGTAG, "error getting guest profile path", ioe); + } if (args == null || !args.contains(BrowserApp.GUEST_BROWSING_ARG)) { - guest = " " + BrowserApp.GUEST_BROWSING_ARG; + guestArg = " " + BrowserApp.GUEST_BROWSING_ARG; } } else if (!GeckoProfile.sIsUsingCustomProfile) { - // If nothing was passed in in the intent, force Gecko to use the default profile for - // for this activity - profile = " -P " + GeckoAppShell.getGeckoInterface().getProfile().getName(); + // If nothing was passed in the intent, make sure the default profile exists and + // force Gecko to use the default profile for this activity + profileArg = " -P " + profile.forceCreate().getName(); } } - return (args != null ? args : "") + profile + guest; + return (args != null ? args : "") + profileArg + guestArg; } @Override From c3dee3558d789369e0871da58c69d18e1e5057c0 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Wed, 1 Oct 2014 09:13:57 +1000 Subject: [PATCH 34/58] Bug 1072724 - Support showing more information about style structs in restyle logs. r=dbaron The MOZ_DEBUG_RESTYLE_STRUCTS environment variable can be set to a comma- separated list of style struct names. When restyle logging is enabled, this will cause the style context tree -- showing cached style struct pointers for those structs specified -- to be logged before each individual restyle is processed. It will also show the struct pointer values involved when swapping structs between style contexts. For example, set MOZ_DEBUG_RESTYLE_STRUCTS=Font,UserInterface to show the cached nsStyleFont and nsStyleUserInterface pointers on the style contexts involved in the restyle process. --- layout/base/RestyleManager.cpp | 43 +++++++++++++ layout/base/RestyleManager.h | 7 +++ layout/base/RestyleTracker.cpp | 10 +++ layout/style/nsStyleContext.cpp | 108 ++++++++++++++++++++++++++++++++ layout/style/nsStyleContext.h | 17 +++++ 5 files changed, 185 insertions(+) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index ffd2f3dfcdc7..74b53b25281d 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -3069,6 +3069,16 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, oldContext.get(), newContext.get()); oldContext->SwapStyleData(newContext, equalStructs); *aSwappedStructs |= equalStructs; +#ifdef RESTYLE_LOGGING + uint32_t structs = RestyleManager::StructsToLog() & equalStructs; + if (structs) { + LOG_RESTYLE_INDENT(); + LOG_RESTYLE("old style context now has: %s", + oldContext->GetCachedStyleDataAsString(structs).get()); + LOG_RESTYLE("new style context now has: %s", + newContext->GetCachedStyleDataAsString(structs).get()); + } +#endif } LOG_RESTYLE("setting new style context"); aSelf->SetStyleContext(newContext); @@ -3636,6 +3646,39 @@ RestyleManager::ComputeStyleChangeFor(nsIFrame* aFrame, } } +#ifdef RESTYLE_LOGGING +uint32_t +RestyleManager::StructsToLog() +{ + static bool initialized = false; + static uint32_t structs; + if (!initialized) { + structs = 0; + const char* value = getenv("MOZ_DEBUG_RESTYLE_STRUCTS"); + if (value) { + nsCString s(value); + while (!s.IsEmpty()) { + int32_t index = s.FindChar(','); + nsStyleStructID sid; + bool found; + if (index == -1) { + found = nsStyleContext::LookupStruct(s, sid); + s.Truncate(); + } else { + found = nsStyleContext::LookupStruct(Substring(s, 0, index), sid); + s = Substring(s, index + 1); + } + if (found) { + structs |= nsCachedStyleData::GetBitForSID(sid); + } + } + } + initialized = true; + } + return structs; +} +#endif + #ifdef DEBUG /* static */ nsCString RestyleManager::RestyleHintToString(nsRestyleHint aHint) diff --git a/layout/base/RestyleManager.h b/layout/base/RestyleManager.h index 66b3bad69d79..9ea35f0bffc4 100644 --- a/layout/base/RestyleManager.h +++ b/layout/base/RestyleManager.h @@ -386,6 +386,13 @@ public: return animations; } + // Set MOZ_DEBUG_RESTYLE_STRUCTS to a comma-separated string of + // style struct names -- such as "Font,SVGReset" -- to log the style context + // tree and those cached struct pointers before each restyle. This + // function returns a bitfield of the structs named in the + // environment variable. + static uint32_t StructsToLog(); + static nsCString StructNamesToString(uint32_t aSIDs); int32_t& LoggingDepth() { return mLoggingDepth; } #endif diff --git a/layout/base/RestyleTracker.cpp b/layout/base/RestyleTracker.cpp index b516c7670db5..4dd86967c03c 100644 --- a/layout/base/RestyleTracker.cpp +++ b/layout/base/RestyleTracker.cpp @@ -162,7 +162,17 @@ RestyleTracker::ProcessOneRestyle(Element* aElement, RestyleManager::ChangeHintToString(aChangeHint).get()); nsIFrame* primaryFrame = aElement->GetPrimaryFrame(); + if (aRestyleHint & ~eRestyle_LaterSiblings) { +#ifdef RESTYLE_LOGGING + if (ShouldLogRestyle() && primaryFrame && + RestyleManager::StructsToLog() != 0) { + LOG_RESTYLE("style context tree before restyle:"); + LOG_RESTYLE_INDENT(); + primaryFrame->StyleContext()->LogStyleContextTree( + LoggingDepth(), RestyleManager::StructsToLog()); + } +#endif mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint, *this, aRestyleHint); } else if (aChangeHint && diff --git a/layout/style/nsStyleContext.cpp b/layout/style/nsStyleContext.cpp index 6af26d43f844..8ea22e8216a1 100644 --- a/layout/style/nsStyleContext.cpp +++ b/layout/style/nsStyleContext.cpp @@ -1048,6 +1048,21 @@ nsStyleContext::StructName(nsStyleStructID aSID) return "Unknown"; } } + +/* static */ bool +nsStyleContext::LookupStruct(const nsACString& aName, nsStyleStructID& aResult) +{ + if (false) + ; +#define STYLE_STRUCT(name_, checkdata_cb_) \ + else if (aName.EqualsLiteral(#name_)) \ + aResult = eStyleStruct_##name_; +#include "nsStyleStructList.h" +#undef STYLE_STRUCT + else + return false; + return true; +} #endif bool @@ -1162,3 +1177,96 @@ nsStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs) ClearCachedInheritedStyleDataOnDescendants(aStructs); } + +#ifdef RESTYLE_LOGGING +nsCString +nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs) +{ + nsCString structs; + for (nsStyleStructID i = nsStyleStructID(0); + i < nsStyleStructID_Length; + i = nsStyleStructID(i + 1)) { + if (aStructs & nsCachedStyleData::GetBitForSID(i)) { + const void* data = GetCachedStyleData(i); + if (!structs.IsEmpty()) { + structs.Append(' '); + } + structs.AppendPrintf("%s=%p", StructName(i), data); + if (HasCachedInheritedStyleData(i)) { + structs.AppendLiteral("(dependent)"); + } else { + structs.AppendLiteral("(owned)"); + } + } + } + return structs; +} + +int32_t& +nsStyleContext::LoggingDepth() +{ + static int32_t depth = 0; + return depth; +} + +void +nsStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs) +{ + LoggingDepth() = aLoggingDepth; + LogStyleContextTree(true, aStructs); +} + +void +nsStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs) +{ + nsCString structs = GetCachedStyleDataAsString(aStructs); + if (!structs.IsEmpty()) { + structs.Append(' '); + } + + nsCString pseudo; + if (mPseudoTag) { + nsAutoString pseudoTag; + mPseudoTag->ToString(pseudoTag); + AppendUTF16toUTF8(pseudoTag, pseudo); + pseudo.Append(' '); + } + + nsCString flags; + if (IsStyleIfVisited()) { + flags.AppendLiteral("IS_STYLE_IF_VISITED "); + } + if (UsesGrandancestorStyle()) { + flags.AppendLiteral("USES_GRANDANCESTOR_STYLE "); + } + if (IsShared()) { + flags.AppendLiteral("IS_SHARED "); + } + + nsCString parent; + if (aFirst) { + parent.AppendPrintf("parent=%p ", mParent); + } + + LOG_RESTYLE("%p(%d) %s%s%s%s", + this, mRefCnt, + structs.get(), pseudo.get(), flags.get(), parent.get()); + + LOG_RESTYLE_INDENT(); + + if (nullptr != mChild) { + nsStyleContext* child = mChild; + do { + child->LogStyleContextTree(false, aStructs); + child = child->mNextSibling; + } while (mChild != child); + } + if (nullptr != mEmptyChild) { + nsStyleContext* child = mEmptyChild; + do { + child->LogStyleContextTree(false, aStructs); + child = child->mNextSibling; + } while (mEmptyChild != child); + } +} +#endif diff --git a/layout/style/nsStyleContext.h b/layout/style/nsStyleContext.h index 18116b6789db..7bf0551985b5 100644 --- a/layout/style/nsStyleContext.h +++ b/layout/style/nsStyleContext.h @@ -8,6 +8,7 @@ #ifndef _nsStyleContext_h_ #define _nsStyleContext_h_ +#include "mozilla/RestyleLogging.h" #include "nsRuleNode.h" #include "nsCSSPseudoElements.h" @@ -397,6 +398,13 @@ public: void List(FILE* out, int32_t aIndent); static void AssertStyleStructMaxDifferenceValid(); static const char* StructName(nsStyleStructID aSID); + static bool LookupStruct(const nsACString& aName, nsStyleStructID& aResult); +#endif + +#ifdef RESTYLE_LOGGING + nsCString GetCachedStyleDataAsString(uint32_t aStructs); + void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs); + int32_t& LoggingDepth(); #endif private: @@ -450,6 +458,15 @@ private: int32_t aLevels) const; #endif +#ifdef RESTYLE_LOGGING + void LogStyleContextTree(bool aFirst, uint32_t aStructs); + + // This only gets called under call trees where we've already checked + // that PresContext()->RestyleManager()->ShouldLogRestyle() returned true. + // It exists here just to satisfy LOG_RESTYLE's expectations. + bool ShouldLogRestyle() { return true; } +#endif + nsStyleContext* mParent; // STRONG // Children are kept in two circularly-linked lists. The list anchor From 65bc1e2db27813f9f63e407dd0ab2df609152b71 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 23 Sep 2014 15:47:30 +1200 Subject: [PATCH 35/58] b=1069671 don't dispatch "update" after "abort" r=kinetik --HG-- extra : rebase_source : 20f644edb8eb99791b29303adce90d3659582821 --- content/media/mediasource/SourceBuffer.cpp | 10 +++++++++- .../media-source/SourceBuffer-abort-updating.html.ini | 4 ---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/content/media/mediasource/SourceBuffer.cpp b/content/media/mediasource/SourceBuffer.cpp index e6570b772a0d..57fe1f586470 100644 --- a/content/media/mediasource/SourceBuffer.cpp +++ b/content/media/mediasource/SourceBuffer.cpp @@ -289,7 +289,15 @@ void SourceBuffer::StopUpdating() { MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mUpdating); + if (!mUpdating) { + // The buffer append algorithm has been interrupted by abort(). + // + // If the sequence appendBuffer(), abort(), appendBuffer() occurs before + // the first StopUpdating() runnable runs, then a second StopUpdating() + // runnable will be scheduled, but still only one (the first) will queue + // events. + return; + } mUpdating = false; QueueAsyncSimpleEvent("update"); QueueAsyncSimpleEvent("updateend"); diff --git a/testing/web-platform/meta/media-source/SourceBuffer-abort-updating.html.ini b/testing/web-platform/meta/media-source/SourceBuffer-abort-updating.html.ini index be478219659e..84262857e64d 100644 --- a/testing/web-platform/meta/media-source/SourceBuffer-abort-updating.html.ini +++ b/testing/web-platform/meta/media-source/SourceBuffer-abort-updating.html.ini @@ -1,9 +1,5 @@ [SourceBuffer-abort-updating.html] type: testharness - expected: ERROR - [SourceBuffer#abort() (video/webm; codecs="vorbis,vp8") : Check the algorithm when the updating attribute is true.] - expected: FAIL - [SourceBuffer#abort() (video/mp4) : Check the algorithm when the updating attribute is true.] expected: FAIL From 1b5fee3ae217f509d0e47bb49bd30c79a8fac6b0 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Wed, 1 Oct 2014 11:25:24 +1300 Subject: [PATCH 36/58] b=1074765 test PeriodicWave output --HG-- extra : rebase_source : ccf075b9d52dc4da22e9d7f3f3bb73eceefdf1cd --- .../webaudio/test/test_periodicWave.html | 68 +++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/content/media/webaudio/test/test_periodicWave.html b/content/media/webaudio/test/test_periodicWave.html index 71490aa39f5d..6ea5f06dec11 100644 --- a/content/media/webaudio/test/test_periodicWave.html +++ b/content/media/webaudio/test/test_periodicWave.html @@ -11,11 +11,26 @@ From ad0b48363f396b52fe20ccef8d8e16417e316052 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 30 Sep 2014 17:13:27 +1300 Subject: [PATCH 37/58] b=1074765 move const periodicWaveSize multiplier out of loop r=rillian --HG-- extra : rebase_source : f09104d4df99cf36dd03c883eec2980d503b0c06 --- content/media/webaudio/OscillatorNode.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/content/media/webaudio/OscillatorNode.cpp b/content/media/webaudio/OscillatorNode.cpp index adf3292c8b1b..9444c66b9426 100644 --- a/content/media/webaudio/OscillatorNode.cpp +++ b/content/media/webaudio/OscillatorNode.cpp @@ -376,16 +376,18 @@ public: float* higherWaveData = nullptr; float* lowerWaveData = nullptr; float tableInterpolationFactor; - float rate = 1.0 / mSource->SampleRate(); - + // Phase increment at frequency of 1 Hz. + // mPhase runs [0,periodicWaveSize) here instead of [0,2*M_PI). + float basePhaseIncrement = + static_cast(periodicWaveSize) / mSource->SampleRate(); + for (uint32_t i = aStart; i < aEnd; ++i) { UpdateParametersIfNeeded(ticks, i); mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency, lowerWaveData, higherWaveData, tableInterpolationFactor); - // mPhase runs 0..periodicWaveSize here instead of 0..2*M_PI. - mPhase += periodicWaveSize * mFinalFrequency * rate; + mPhase += basePhaseIncrement * mFinalFrequency; mPhase = fmod(mPhase, periodicWaveSize); // Bilinear interpolation between adjacent samples in each table. uint32_t j1 = floor(mPhase); From 534ee9bcad721aa635e0bf66ce7ac5f798ccbfd4 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 30 Sep 2014 17:26:26 +1300 Subject: [PATCH 38/58] b=1074765 increment phase after sampling to begin PeriodicWave at phase = 0 r=rillian This makes phase consistent with the sine OscillatorType and with Blink's custom OscillatorType. --HG-- extra : rebase_source : bd046ec14d18115af18f929126aae287c258adf2 --- content/media/webaudio/OscillatorNode.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/media/webaudio/OscillatorNode.cpp b/content/media/webaudio/OscillatorNode.cpp index 9444c66b9426..90f234c78308 100644 --- a/content/media/webaudio/OscillatorNode.cpp +++ b/content/media/webaudio/OscillatorNode.cpp @@ -387,7 +387,6 @@ public: lowerWaveData, higherWaveData, tableInterpolationFactor); - mPhase += basePhaseIncrement * mFinalFrequency; mPhase = fmod(mPhase, periodicWaveSize); // Bilinear interpolation between adjacent samples in each table. uint32_t j1 = floor(mPhase); @@ -402,6 +401,8 @@ public: (1 - sampleInterpolationFactor) * higherWaveData[j2]; aOutput[i] = tableInterpolationFactor * lower + (1 - tableInterpolationFactor) * higher; + + mPhase += basePhaseIncrement * mFinalFrequency; } } From b7f87dd74c711ce3d3e5789a6022acef59ada6e2 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 30 Sep 2014 17:30:30 +1300 Subject: [PATCH 39/58] b=1074765 use greater weight for nearer sample in PeriodicWave interpolation r=rillian --HG-- extra : rebase_source : 0c6ac8b0a870caa4bf5e770fe431aebe25b5af26 --- content/media/webaudio/OscillatorNode.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/content/media/webaudio/OscillatorNode.cpp b/content/media/webaudio/OscillatorNode.cpp index 90f234c78308..14d3dfe06cf6 100644 --- a/content/media/webaudio/OscillatorNode.cpp +++ b/content/media/webaudio/OscillatorNode.cpp @@ -395,12 +395,12 @@ public: j2 -= periodicWaveSize; } float sampleInterpolationFactor = mPhase - j1; - float lower = sampleInterpolationFactor * lowerWaveData[j1] + - (1 - sampleInterpolationFactor) * lowerWaveData[j2]; - float higher = sampleInterpolationFactor * higherWaveData[j1] + - (1 - sampleInterpolationFactor) * higherWaveData[j2]; - aOutput[i] = tableInterpolationFactor * lower + - (1 - tableInterpolationFactor) * higher; + float lower = (1.0f - sampleInterpolationFactor) * lowerWaveData[j1] + + sampleInterpolationFactor * lowerWaveData[j2]; + float higher = (1.0f - sampleInterpolationFactor) * higherWaveData[j1] + + sampleInterpolationFactor * higherWaveData[j2]; + aOutput[i] = (1.0f - tableInterpolationFactor) * lower + + tableInterpolationFactor * higher; mPhase += basePhaseIncrement * mFinalFrequency; } From 209307a0375703e9b157c26061119db7653d4866 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 30 Sep 2014 21:26:26 -0400 Subject: [PATCH 40/58] Bug 1072991. Make sure to set the right base URI on the document clones we create for printing. r=smaug --- content/base/src/nsDocument.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 8436d32137b2..8c0444e3f20d 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -9178,14 +9178,6 @@ nsDocument::CloneDocHelper(nsDocument* clone) const nsresult rv = clone->Init(); NS_ENSURE_SUCCESS(rv, rv); - // Set URI/principal - clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI()); - clone->SetChromeXHRDocURI(mChromeXHRDocURI); - // Must set the principal first, since SetBaseURI checks it. - clone->SetPrincipal(NodePrincipal()); - clone->mDocumentBaseURI = mDocumentBaseURI; - clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI); - if (mCreatingStaticClone) { nsCOMPtr loadGroup; @@ -9210,6 +9202,18 @@ nsDocument::CloneDocHelper(nsDocument* clone) const clone->SetContainer(mDocumentContainer); } + // Now ensure that our clone has the same URI, base URI, and principal as us. + // We do this after the mCreatingStaticClone block above, because that block + // can set the base URI to an incorrect value in cases when base URI + // information came from the channel. So we override explicitly, and do it + // for all these properties, in case ResetToURI messes with any of the rest of + // them. + clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI()); + clone->SetChromeXHRDocURI(mChromeXHRDocURI); + clone->SetPrincipal(NodePrincipal()); + clone->mDocumentBaseURI = mDocumentBaseURI; + clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI); + // Set scripting object bool hasHadScriptObject = true; nsIScriptGlobalObject* scriptObject = From 9804f7130647ee9d4c3adff61136689b3777f91d Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 30 Sep 2014 21:26:28 -0400 Subject: [PATCH 41/58] Bug 1066432. Update ForOfIterator to the changes in Web IDL's handling of sequences as iterables. We now commit to an iterable if we get a non-undefined value for the Symbol.iterator property, not just if we get a callable value. r=jorendorff --- dom/bindings/test/TestInterfaceJS.js | 3 ++ dom/bindings/test/mochitest.ini | 2 + .../test/test_sequence_detection.html | 54 +++++++++++++++++++ dom/webidl/TestInterfaceJS.webidl | 6 +++ js/src/jsapi-tests/README | 10 ++-- js/src/jsapi-tests/moz.build | 1 + js/src/jsapi-tests/testForOfIterator.cpp | 53 ++++++++++++++++++ js/src/jsapi.h | 8 +-- js/src/jsiter.cpp | 10 ++-- 9 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 dom/bindings/test/test_sequence_detection.html create mode 100644 js/src/jsapi-tests/testForOfIterator.cpp diff --git a/dom/bindings/test/TestInterfaceJS.js b/dom/bindings/test/TestInterfaceJS.js index 7bbd3d8d8d91..102e3cbcfa71 100644 --- a/dom/bindings/test/TestInterfaceJS.js +++ b/dom/bindings/test/TestInterfaceJS.js @@ -56,6 +56,9 @@ TestInterfaceJS.prototype = { get cachedAttr() { return this._cachedAttr; }, setCachedAttr: function(n) { this._cachedAttr = n; }, clearCachedAttrCache: function () { this.__DOM_IMPL__._clearCachedCachedAttrValue(); }, + + testSequenceOverload: function(arg) {}, + testSequenceUnion: function(arg) {}, }; this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS]) diff --git a/dom/bindings/test/mochitest.ini b/dom/bindings/test/mochitest.ini index fa1b792a2b31..3df211461e02 100644 --- a/dom/bindings/test/mochitest.ini +++ b/dom/bindings/test/mochitest.ini @@ -50,3 +50,5 @@ skip-if = debug == false [test_throwing_method_noDCE.html] [test_treat_non_object_as_null.html] [test_traceProtos.html] +[test_sequence_detection.html] +skip-if = debug == false diff --git a/dom/bindings/test/test_sequence_detection.html b/dom/bindings/test/test_sequence_detection.html new file mode 100644 index 000000000000..6dd6d7c64077 --- /dev/null +++ b/dom/bindings/test/test_sequence_detection.html @@ -0,0 +1,54 @@ + + + + + + Test for Bug 1066432 + + + + + +Mozilla Bug 1066432 +

+ +
+
+ + diff --git a/dom/webidl/TestInterfaceJS.webidl b/dom/webidl/TestInterfaceJS.webidl index 825296364036..1b49f480779f 100644 --- a/dom/webidl/TestInterfaceJS.webidl +++ b/dom/webidl/TestInterfaceJS.webidl @@ -42,4 +42,10 @@ interface TestInterfaceJS { readonly attribute short cachedAttr; void setCachedAttr(short n); void clearCachedAttrCache(); + + // Test for sequence overloading and union behavior + void testSequenceOverload(sequence arg); + void testSequenceOverload(DOMString arg); + + void testSequenceUnion((sequence or DOMString) arg); }; diff --git a/js/src/jsapi-tests/README b/js/src/jsapi-tests/README index 4caf1ec04a57..05575dba0804 100644 --- a/js/src/jsapi-tests/README +++ b/js/src/jsapi-tests/README @@ -7,17 +7,19 @@ The tests in this directory exercise the JSAPI. If you built JS, you already built the tests. -If you did `make check` in your JS objdir, you already ran them. - The tests are built by default when you build JS. All the tests are compiled into a single binary named jsapi-tests. They all run in a single process. +To run the tests: + + cd $OBJDIR/dist/bin + ./jsapi-tests + To run the tests in a debugger: - cd $OBJDIR/jsapi-tests + cd $OBJDIR/dist/bin gdb ./jsapi-tests - --- Creating new tests 1. You can either add to an existing test*.cpp file or make a new one. diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index 97ce03d107e2..e72d2baadb83 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -29,6 +29,7 @@ UNIFIED_SOURCES += [ 'testException.cpp', 'testExternalStrings.cpp', 'testFindSCCs.cpp', + 'testForOfIterator.cpp', 'testFreshGlobalEvalRedefinition.cpp', 'testFuncCallback.cpp', 'testFunctionProperties.cpp', diff --git a/js/src/jsapi-tests/testForOfIterator.cpp b/js/src/jsapi-tests/testForOfIterator.cpp new file mode 100644 index 000000000000..6b4d9f986afb --- /dev/null +++ b/js/src/jsapi-tests/testForOfIterator.cpp @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jsapi-tests/tests.h" + +BEGIN_TEST(testForOfIterator_basicNonIterable) +{ + JS::RootedValue v(cx); + // Hack to make it simple to produce an object that has a property + // named Symbol.iterator. + EVAL("var obj = { '@@iterator': 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; obj;", &v); + JS::ForOfIterator iter(cx); + bool ok = iter.init(v); + CHECK(!ok); + JS_ClearPendingException(cx); + return true; +} +END_TEST(testForOfIterator_basicNonIterable) + +BEGIN_TEST(testForOfIterator_bug515273_part1) +{ + JS::RootedValue v(cx); + + // Hack to make it simple to produce an object that has a property + // named Symbol.iterator. + EVAL("var obj = { '@@iterator': 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; obj;", &v); + + JS::ForOfIterator iter(cx); + bool ok = iter.init(v, JS::ForOfIterator::AllowNonIterable); + CHECK(!ok); + JS_ClearPendingException(cx); + return true; +} +END_TEST(testForOfIterator_bug515273_part1) + +BEGIN_TEST(testForOfIterator_bug515273_part2) +{ + JS::RootedObject obj(cx, + JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); + CHECK(obj); + JS::RootedValue v(cx, JS::ObjectValue(*obj)); + + JS::ForOfIterator iter(cx); + bool ok = iter.init(v, JS::ForOfIterator::AllowNonIterable); + CHECK(ok); + CHECK(!iter.valueIsIterable()); + return true; +} +END_TEST(testForOfIterator_bug515273_part2) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 6b226a46c261..defabeddce12 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -5191,10 +5191,10 @@ class MOZ_STACK_CLASS JS_PUBLIC_API(ForOfIterator) { }; /* - * Initialize the iterator. If AllowNonIterable is passed then if iterable - * does not have a callable @@iterator init() will just return true instead - * of throwing. Callers should then check valueIsIterable() before - * continuing with the iteration. + * Initialize the iterator. If AllowNonIterable is passed then if getting + * the @@iterator property from iterable returns undefined init() will just + * return true instead of throwing. Callers must then check + * valueIsIterable() before continuing with the iteration. */ bool init(JS::HandleValue iterable, NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable); diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 7789b638733e..c0886a61f851 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -1366,13 +1366,17 @@ ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavio if (!JSObject::getProperty(cx, iterableObj, iterableObj, cx->names().std_iterator, &callee)) return false; - // Throw if obj[@@iterator] isn't callable if we were asked to do so. + // If obj[@@iterator] is undefined and we were asked to allow non-iterables, + // bail out now without setting iterator. This will make valueIsIterable(), + // which our caller should check, return false. + if (nonIterableBehavior == AllowNonIterable && callee.isUndefined()) + return true; + + // Throw if obj[@@iterator] isn't callable. // js::Invoke is about to check for this kind of error anyway, but it would // throw an inscrutable error message about |method| rather than this nice // one about |obj|. if (!callee.isObject() || !callee.toObject().isCallable()) { - if (nonIterableBehavior == AllowNonIterable) - return true; char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, NullPtr()); if (!bytes) return false; From 5d0ad9dd5f3533922c8e11cfd48d3a1cc550a6fc Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Tue, 30 Sep 2014 15:30:58 +1300 Subject: [PATCH 42/58] Bug 1064634 - Use the same media thread stack size on all platforms where we specify a size. Also document the rationale behind the MOZ_ASAN exception. r=cpearce --- content/media/VideoUtils.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/content/media/VideoUtils.h b/content/media/VideoUtils.h index e4217330e622..56f8e7d80352 100644 --- a/content/media/VideoUtils.h +++ b/content/media/VideoUtils.h @@ -168,9 +168,11 @@ static const int32_t MAX_VIDEO_HEIGHT = 3000; void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio); // The amount of virtual memory reserved for thread stacks. -#if (defined(XP_WIN) || defined(LINUX)) && !defined(MOZ_ASAN) -#define MEDIA_THREAD_STACK_SIZE (128 * 1024) -#elif defined(XP_MACOSX) && !defined(MOZ_ASAN) +#if defined(MOZ_ASAN) +// Use the system default in ASAN builds, because the default is assumed to be +// larger than the size we want to use and is hopefully sufficient for ASAN. +#define MEDIA_THREAD_STACK_SIZE nsIThreadManager::DEFAULT_STACK_SIZE +#elif defined(XP_WIN) || defined(XP_MACOSX) || defined(LINUX) #define MEDIA_THREAD_STACK_SIZE (256 * 1024) #else // All other platforms use their system defaults. From 2396718a16c905ea0be88be0c01ef0c3c78485a0 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 30 Sep 2014 22:14:27 -0400 Subject: [PATCH 43/58] Bug 1066432 followup. Remove bogus alerts from the test. --- dom/bindings/test/test_sequence_detection.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/dom/bindings/test/test_sequence_detection.html b/dom/bindings/test/test_sequence_detection.html index 6dd6d7c64077..f861abd02a04 100644 --- a/dom/bindings/test/test_sequence_detection.html +++ b/dom/bindings/test/test_sequence_detection.html @@ -21,7 +21,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1066432 ok(false, "Should have thrown in the overload case"); } catch (e) { ise(e.name, "TypeError", "Should get a TypeError for the overload case"); - alert(e.message); ok(e.message.contains("not iterable"), "Should have a message about being non-iterable in the overload case"); } @@ -32,7 +31,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1066432 ok(false, "Should have thrown in the union case"); } catch (e) { ise(e.name, "TypeError", "Should get a TypeError for the union case"); - alert(e.message); ok(e.message.contains("not iterable"), "Should have a message about being non-iterable in the union case"); } From a29fc8e4ef8d1e403fa4902c755d974c69f7e428 Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Fri, 19 Sep 2014 02:28:43 +0300 Subject: [PATCH 44/58] Bug 1002855 - Turn on Resource Timing r=bz --- 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 077f4078dc9c..bbc3779094e6 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -135,7 +135,7 @@ pref("dom.serviceWorkers.enabled", false); pref("dom.enable_performance", true); // Whether resource timing will be gathered and returned by performance.GetEntries* -pref("dom.enable_resource_timing", false); +pref("dom.enable_resource_timing", true); // Whether the Gamepad API is enabled pref("dom.gamepad.enabled", true); From 2576f16ba05ce192759219107567e4a98a805ad2 Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Tue, 30 Sep 2014 17:56:25 +0300 Subject: [PATCH 45/58] Bug 1002855 - Fix web-platform-tests for resource-timing and remove expect FAIL. r=bz --- .../performance-timeline/idlharness.html.ini | 26 ------------------- .../test_resource_timing.html.ini | 9 +------ .../resource-timing/test_resource_timing.html | 3 ++- 3 files changed, 3 insertions(+), 35 deletions(-) delete mode 100644 testing/web-platform/meta/performance-timeline/idlharness.html.ini diff --git a/testing/web-platform/meta/performance-timeline/idlharness.html.ini b/testing/web-platform/meta/performance-timeline/idlharness.html.ini deleted file mode 100644 index 74372195a6d1..000000000000 --- a/testing/web-platform/meta/performance-timeline/idlharness.html.ini +++ /dev/null @@ -1,26 +0,0 @@ -[idlharness.html] - type: testharness - [Performance interface: operation getEntries()] - expected: FAIL - - [Performance interface: operation getEntriesByType(DOMString)] - expected: FAIL - - [Performance interface: operation getEntriesByName(DOMString,DOMString)] - expected: FAIL - - [Performance interface: window.performance must inherit property "getEntries" with the proper type (0)] - expected: FAIL - - [Performance interface: window.performance must inherit property "getEntriesByType" with the proper type (1)] - expected: FAIL - - [Performance interface: calling getEntriesByType(DOMString) on window.performance with too few arguments must throw TypeError] - expected: FAIL - - [Performance interface: window.performance must inherit property "getEntriesByName" with the proper type (2)] - expected: FAIL - - [Performance interface: calling getEntriesByName(DOMString,DOMString) on window.performance with too few arguments must throw TypeError] - expected: FAIL - diff --git a/testing/web-platform/meta/resource-timing/test_resource_timing.html.ini b/testing/web-platform/meta/resource-timing/test_resource_timing.html.ini index 2bb2563119bd..d6d5159bb074 100644 --- a/testing/web-platform/meta/resource-timing/test_resource_timing.html.ini +++ b/testing/web-platform/meta/resource-timing/test_resource_timing.html.ini @@ -1,11 +1,4 @@ [test_resource_timing.html] type: testharness - [window.performance.getEntriesByName() is defined] + [window.performance.getEntriesByName("http://.../resource_timing_test0.xml") returns a PerformanceEntry object] expected: FAIL - - [window.performance.getEntriesByType() is defined] - expected: FAIL - - [window.performance.getEntries() is defined] - expected: FAIL - diff --git a/testing/web-platform/tests/resource-timing/test_resource_timing.html b/testing/web-platform/tests/resource-timing/test_resource_timing.html index ca683e495d94..6846c7a4ba60 100644 --- a/testing/web-platform/tests/resource-timing/test_resource_timing.html +++ b/testing/web-platform/tests/resource-timing/test_resource_timing.html @@ -286,7 +286,8 @@ pass = (actualEntry.redirectStart == 0) && (actualEntry.redirectEnd == 0) && - (actualEntry.secureConnectionStart == undefined) && + (actualEntry.secureConnectionStart == undefined || + actualEntry.secureConnectionStart == 0) && validate_timeline(actualEntry); (pass) ? test_true(true, From 6c48290b50bca172dbf0a2609064e1d69c1079e2 Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Mon, 29 Sep 2014 13:13:10 +1300 Subject: [PATCH 46/58] Bug 1074004 - Update nestegg from upstream. r=giles --HG-- rename : media/libnestegg/README => media/libnestegg/README.md --- media/libnestegg/{README => README.md} | 2 + media/libnestegg/README_MOZILLA | 2 +- media/libnestegg/include/nestegg.h | 5 +- media/libnestegg/src/halloc.c | 23 ++- media/libnestegg/src/nestegg.c | 241 +++++++++++++++++-------- media/libnestegg/update.sh | 2 +- 6 files changed, 187 insertions(+), 88 deletions(-) rename media/libnestegg/{README => README.md} (63%) diff --git a/media/libnestegg/README b/media/libnestegg/README.md similarity index 63% rename from media/libnestegg/README rename to media/libnestegg/README.md index 47c8237d2f1a..aba7dc2727f6 100644 --- a/media/libnestegg/README +++ b/media/libnestegg/README.md @@ -1,3 +1,5 @@ +[![Build Status](https://travis-ci.org/kinetiknz/nestegg.svg?branch=master)](https://travis-ci.org/kinetiknz/nestegg) + See INSTALL for build instructions. Licensed under an ISC-style license. See LICENSE for details. diff --git a/media/libnestegg/README_MOZILLA b/media/libnestegg/README_MOZILLA index c7857bbdbe88..d6de9ed3b469 100644 --- a/media/libnestegg/README_MOZILLA +++ b/media/libnestegg/README_MOZILLA @@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system. The nestegg git repository is: git://github.com/kinetiknz/nestegg.git -The git commit ID used was 46ab96bcc8b099704cc8a15993f80fe0269a5284. +The git commit ID used was 59220ae3e801cbad0f8160129c4df315469af671. diff --git a/media/libnestegg/include/nestegg.h b/media/libnestegg/include/nestegg.h index 06f9c83b8772..04fc3e9c0555 100644 --- a/media/libnestegg/include/nestegg.h +++ b/media/libnestegg/include/nestegg.h @@ -381,8 +381,11 @@ int nestegg_sniff(unsigned char const * buffer, size_t length); * Set the underlying allocation function for library allocations. * * @param realloc_func The desired function. + * @retval 0 realloc_func(p, 0) does not act as free() + * @retval 1 realloc_func(p, 0) acts as free() + * @retval -1 malloc failed during realloc_func test */ -void nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t)); +int nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t)); #if defined(__cplusplus) } diff --git a/media/libnestegg/src/halloc.c b/media/libnestegg/src/halloc.c index 5758fc07b9e7..3187b3c609a2 100644 --- a/media/libnestegg/src/halloc.c +++ b/media/libnestegg/src/halloc.c @@ -46,7 +46,7 @@ realloc_t halloc_allocator = NULL; /* * static methods */ -static void _set_allocator(void); +int halloc_set_allocator(realloc_t realloc_func); static void * _realloc(void * ptr, size_t n); static int _relate(hblock_t * b, hblock_t * p); @@ -62,7 +62,10 @@ void * halloc(void * ptr, size_t len) /* set up default allocator */ if (! allocator) { - _set_allocator(); + if (halloc_set_allocator(realloc) == 0) + { + halloc_set_allocator(_realloc); + } assert(allocator); } @@ -172,7 +175,7 @@ char * h_strdup(const char * str) /* * static stuff */ -static void _set_allocator(void) +int halloc_set_allocator(realloc_t realloc_func) { void * p; assert(! allocator); @@ -187,17 +190,17 @@ static void _set_allocator(void) * * Thanks to Stan Tobias for pointing this tricky part out. */ - allocator = realloc; - if (! (p = malloc(1))) + if (! (p = realloc_func(NULL, 1))) /* hmm */ - return; + return -1; - if ((p = realloc(p, 0))) + if ((p = realloc_func(p, 0))) { - /* realloc cannot be used as free() */ - allocator = _realloc; - free(p); + /* realloc_func cannot be used as free() */ + return 0; } + allocator = realloc_func; + return 1; } static void * _realloc(void * ptr, size_t n) diff --git a/media/libnestegg/src/nestegg.c b/media/libnestegg/src/nestegg.c index f74ba04bc870..2f52888db39b 100644 --- a/media/libnestegg/src/nestegg.c +++ b/media/libnestegg/src/nestegg.c @@ -321,9 +321,18 @@ struct block_additional { struct block_additional * next; }; +#define NE_IO_BUFSZ 16384 + +struct nestegg_io_buf { + nestegg_io io; + unsigned char buffer[NE_IO_BUFSZ]; + size_t bufsz; + int offset; +}; + /* Public (opaque) Structures */ struct nestegg { - nestegg_io * io; + struct nestegg_io_buf * io; nestegg_log log; struct pool_ctx * alloc_pool; uint64_t last_id; @@ -546,19 +555,99 @@ ne_alloc(size_t size) } static int -ne_io_read(nestegg_io * io, void * buffer, size_t length) +ne_io_read(struct nestegg_io_buf * io, void * buffer, size_t length) { - return io->read(buffer, length, io->userdata); + int64_t off; + int r; + size_t avail; + + assert(io->offset == -1 || (io->offset >= 0 && (unsigned int) io->offset < io->bufsz)); + + /* Too big to buffer, invalidate buffer and read through */ + if (length > io->bufsz) { + if (io->offset != -1) { + r = io->io.seek(-(io->bufsz - io->offset), NESTEGG_SEEK_CUR, io->io.userdata); + if (r != 0) { + return -1; + } + } + io->offset = -1; + return io->io.read(buffer, length, io->io.userdata); + } + + /* Buffer invalid */ + if (io->offset == -1) { + off = io->io.tell(io->io.userdata); + if (off == -1) { + return -1; + } + /* Refill buffer */ + r = io->io.read(io->buffer, io->bufsz, io->io.userdata); + if (r != 1) { + /* Read truncated due to being within io->bufsz of EOS, reset read + position and switch to read through mode */ + io->offset = -1; + io->bufsz = 0; + if (r == 0) { + r = io->io.seek(off, NESTEGG_SEEK_SET, io->io.userdata); + } + if (r == 0) { + return io->io.read(buffer, length, io->io.userdata); + } + return -1; + } + if (r == 1) { + io->offset = 0; + } + } + + /* Service request with what we have */ + avail = length; + if (io->bufsz - io->offset < length) { + avail = io->bufsz - io->offset; + } + memcpy(buffer, io->buffer + io->offset, avail); + io->offset += avail; + + if ((unsigned int) io->offset == io->bufsz) { + io->offset = -1; + } + + /* Still more to read, invalidate buffer and read more */ + if (length - avail > 0) { + return ne_io_read(io, (char *) buffer + avail, length - avail); + } + + return 1; } static int -ne_io_seek(nestegg_io * io, int64_t offset, int whence) +ne_io_seek(struct nestegg_io_buf * io, int64_t offset, int whence) { - return io->seek(offset, whence, io->userdata); + /* Invalidate buffer */ + io->offset = -1; + + return io->io.seek(offset, whence, io->io.userdata); +} + +static int64_t +ne_io_tell(struct nestegg_io_buf * io) +{ + int64_t off; + + off = io->io.tell(io->io.userdata); + if (off == -1) { + return -1; + } + if (io->offset == -1) { + return off; + } + assert(off >= (int64_t) io->bufsz - io->offset); + return off - io->bufsz + (unsigned int) io->offset; } static int -ne_io_read_skip(nestegg_io * io, size_t length) +ne_io_read_skip(struct nestegg_io_buf * io, size_t length) { size_t get; unsigned char buf[8192]; @@ -575,14 +664,8 @@ ne_io_read_skip(nestegg_io * io, size_t length) return r; } -static int64_t -ne_io_tell(nestegg_io * io) -{ - return io->tell(io->userdata); -} - static int -ne_bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vint_mask maskflag) +ne_bare_read_vint(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length, enum vint_mask maskflag) { int r; unsigned char b; @@ -619,19 +702,19 @@ ne_bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vin } static int -ne_read_id(nestegg_io * io, uint64_t * value, uint64_t * length) +ne_read_id(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length) { return ne_bare_read_vint(io, value, length, MASK_NONE); } static int -ne_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length) +ne_read_vint(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length) { return ne_bare_read_vint(io, value, length, MASK_FIRST_BIT); } static int -ne_read_svint(nestegg_io * io, int64_t * value, uint64_t * length) +ne_read_svint(struct nestegg_io_buf * io, int64_t * value, uint64_t * length) { int r; uint64_t uvalue; @@ -653,7 +736,7 @@ ne_read_svint(nestegg_io * io, int64_t * value, uint64_t * length) } static int -ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length) +ne_read_uint(struct nestegg_io_buf * io, uint64_t * val, uint64_t length) { unsigned char b; int r; @@ -675,7 +758,7 @@ ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length) } static int -ne_read_int(nestegg_io * io, int64_t * val, uint64_t length) +ne_read_int(struct nestegg_io_buf * io, int64_t * val, uint64_t length) { int r; uint64_t uval, base; @@ -688,8 +771,8 @@ ne_read_int(nestegg_io * io, int64_t * val, uint64_t length) base = 1; base <<= length * 8 - 1; if (uval >= base) { - base = 1; - base <<= length * 8; + base = 1; + base <<= length * 8; } else { base = 0; } @@ -702,7 +785,7 @@ ne_read_int(nestegg_io * io, int64_t * val, uint64_t length) } static int -ne_read_float(nestegg_io * io, double * val, uint64_t length) +ne_read_float(struct nestegg_io_buf * io, double * val, uint64_t length) { union { uint64_t u; @@ -736,9 +819,9 @@ ne_read_string(nestegg * ctx, char ** val, uint64_t length) if (!str) return -1; if (length) { - r = ne_io_read(ctx->io, (unsigned char *) str, length); - if (r != 1) - return r; + r = ne_io_read(ctx->io, (unsigned char *) str, length); + if (r != 1) + return r; } str[length] = '\0'; *val = str; @@ -1018,8 +1101,9 @@ ne_read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length) break; case TYPE_MASTER: case TYPE_UNKNOWN: - assert(0); + default: r = 0; + assert(0); break; } @@ -1136,7 +1220,7 @@ ne_xiph_lace_value(unsigned char ** np) } static int -ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed) +ne_read_xiph_lace_value(struct nestegg_io_buf * io, uint64_t * value, size_t * consumed) { int r; uint64_t lace; @@ -1159,7 +1243,7 @@ ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed) } static int -ne_read_xiph_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) +ne_read_xiph_lacing(struct nestegg_io_buf * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) { int r; size_t i = 0; @@ -1182,7 +1266,7 @@ ne_read_xiph_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, ui } static int -ne_read_ebml_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) +ne_read_ebml_lacing(struct nestegg_io_buf * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) { int r; uint64_t lace, sum, length; @@ -1792,9 +1876,9 @@ struct sniff_buffer { }; static int -ne_buffer_read(void * buffer, size_t length, void * user_data) +ne_buffer_read(void * buffer, size_t length, void * userdata) { - struct sniff_buffer * sb = user_data; + struct sniff_buffer * sb = userdata; int rv = 1; size_t available = sb->length - sb->offset; @@ -1809,21 +1893,21 @@ ne_buffer_read(void * buffer, size_t length, void * user_data) } static int -ne_buffer_seek(int64_t offset, int whence, void * user_data) +ne_buffer_seek(int64_t offset, int whence, void * userdata) { - struct sniff_buffer * sb = user_data; + struct sniff_buffer * sb = userdata; int64_t o = sb->offset; switch(whence) { - case NESTEGG_SEEK_SET: - o = offset; - break; - case NESTEGG_SEEK_CUR: - o += offset; - break; - case NESTEGG_SEEK_END: - o = sb->length + offset; - break; + case NESTEGG_SEEK_SET: + o = offset; + break; + case NESTEGG_SEEK_CUR: + o += offset; + break; + case NESTEGG_SEEK_END: + o = sb->length + offset; + break; } if (o < 0 || o > (int64_t) sb->length) @@ -1834,9 +1918,9 @@ ne_buffer_seek(int64_t offset, int whence, void * user_data) } static int64_t -ne_buffer_tell(void * user_data) +ne_buffer_tell(void * userdata) { - struct sniff_buffer * sb = user_data; + struct sniff_buffer * sb = userdata; return sb->offset; } @@ -1860,7 +1944,9 @@ ne_match_webm(nestegg_io io, int64_t max_offset) nestegg_destroy(ctx); return -1; } - *ctx->io = io; + ctx->io->io = io; + ctx->io->bufsz = NE_IO_BUFSZ; + ctx->io->offset = -1; ctx->alloc_pool = ne_pool_init(); if (!ctx->alloc_pool) { nestegg_destroy(ctx); @@ -1918,7 +2004,9 @@ nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback, int64_t ma nestegg_destroy(ctx); return -1; } - *ctx->io = io; + ctx->io->io = io; + ctx->io->bufsz = NE_IO_BUFSZ; + ctx->io->offset = -1; ctx->log = callback; ctx->alloc_pool = ne_pool_init(); if (!ctx->alloc_pool) { @@ -2264,35 +2352,35 @@ nestegg_track_codec_data(nestegg * ctx, unsigned int track, unsigned int item, return -1; if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS - && nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS) + && nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS) return -1; if (ne_get_binary(entry->codec_private, &codec_private) != 0) return -1; if (nestegg_track_codec_id(ctx, track) == NESTEGG_CODEC_VORBIS) { - p = codec_private.data; - count = *p++ + 1; + p = codec_private.data; + count = *p++ + 1; - if (count > 3) + if (count > 3) + return -1; + + i = 0; + total = 0; + while (--count) { + sizes[i] = ne_xiph_lace_value(&p); + total += sizes[i]; + i += 1; + } + sizes[i] = codec_private.length - total - (p - codec_private.data); + + for (i = 0; i < item; ++i) { + if (sizes[i] > LIMIT_FRAME) return -1; - - i = 0; - total = 0; - while (--count) { - sizes[i] = ne_xiph_lace_value(&p); - total += sizes[i]; - i += 1; - } - sizes[i] = codec_private.length - total - (p - codec_private.data); - - for (i = 0; i < item; ++i) { - if (sizes[i] > LIMIT_FRAME) - return -1; - p += sizes[i]; - } - *data = p; - *length = sizes[item]; + p += sizes[i]; + } + *data = p; + *length = sizes[item]; } else { *data = codec_private.data; *length = codec_private.length; @@ -2494,7 +2582,7 @@ nestegg_free_packet(nestegg_packet * pkt) free(block_additional); } - free(pkt); + free(pkt); } int @@ -2588,28 +2676,31 @@ int nestegg_has_cues(nestegg * ctx) { return ctx->segment.cues.cue_point.head || - ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES); + ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES); } int nestegg_sniff(unsigned char const * buffer, size_t length) { nestegg_io io; - struct sniff_buffer user_data; + struct sniff_buffer userdata; - user_data.buffer = buffer; - user_data.length = length; - user_data.offset = 0; + userdata.buffer = buffer; + userdata.length = length; + userdata.offset = 0; io.read = ne_buffer_read; io.seek = ne_buffer_seek; io.tell = ne_buffer_tell; - io.userdata = &user_data; + io.userdata = &userdata; return ne_match_webm(io, length); } -void +/* From halloc.c */ +int halloc_set_allocator(realloc_t realloc_func); + +int nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t)) { - halloc_allocator = realloc_func; + return halloc_set_allocator(realloc_func); } diff --git a/media/libnestegg/update.sh b/media/libnestegg/update.sh index 27d4ec58b4a6..2d97f3eaec48 100755 --- a/media/libnestegg/update.sh +++ b/media/libnestegg/update.sh @@ -7,7 +7,7 @@ cp $1/halloc/src/halloc.c src cp $1/halloc/src/hlist.h src cp $1/halloc/src/macros.h src cp $1/LICENSE . -cp $1/README . +cp $1/README.md . cp $1/AUTHORS . if [ -d $1/.git ]; then rev=$(cd $1 && git rev-parse --verify HEAD) From a7457c180c07878b88e4abfe657ccb5de0fe0c69 Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Mon, 29 Sep 2014 13:13:21 +1300 Subject: [PATCH 47/58] Bug 1074004 - Fix WebMioData implementation in TestWebMWriter. r=giles --- content/media/gtest/TestWebMWriter.cpp | 5 ++--- media/libcubeb/update.sh | 0 2 files changed, 2 insertions(+), 3 deletions(-) mode change 100644 => 100755 media/libcubeb/update.sh diff --git a/content/media/gtest/TestWebMWriter.cpp b/content/media/gtest/TestWebMWriter.cpp index 99339c0f4536..fd58ed071fa8 100644 --- a/content/media/gtest/TestWebMWriter.cpp +++ b/content/media/gtest/TestWebMWriter.cpp @@ -240,8 +240,7 @@ static int webm_read(void* aBuffer, size_t aLength, void* aUserData) // Check the read length. if (aLength > ioData->data.Length()) { - NS_ERROR("Invalid read length"); - return -1; + return 0; } // Check eos. @@ -292,7 +291,7 @@ static int webm_seek(int64_t aOffset, int aWhence, void* aUserData) return -1; } - return 1; + return 0; } static int64_t webm_tell(void* aUserData) diff --git a/media/libcubeb/update.sh b/media/libcubeb/update.sh old mode 100644 new mode 100755 From fc6ee6630d1765d3ee2c162dd5f44eddb76289eb Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Tue, 30 Sep 2014 20:35:37 -0700 Subject: [PATCH 48/58] Bug 1073991 - Don't change types in JIT caches when the type's newScript has been cleared, r=jandem. --- js/src/jit/BaselineIC.cpp | 17 ++++++++++++++++- js/src/jit/IonCaches.cpp | 18 +++++++++++++++++- js/src/jsinfer.h | 4 ++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 2bc96fe1231e..b362cb23eb24 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -7911,13 +7911,28 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm) masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); masm.storePtr(scratch, shapeAddr); - // Change the object's type if required. + // Try to change the object's type. Label noTypeChange; + + // Check if the cache has a new type to change to. masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch); masm.branchTestPtr(Assembler::Zero, scratch, scratch, &noTypeChange); + + // Check if the old type still has a newScript. + masm.loadPtr(Address(objReg, JSObject::offsetOfType()), scratch); + masm.branchPtr(Assembler::Equal, + Address(scratch, types::TypeObject::offsetOfNewScript()), + ImmWord(0), + &noTypeChange); + + // Reload the new type from the cache. + masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch); + + // Change the object's type. Address typeAddr(objReg, JSObject::offsetOfType()); EmitPreBarrier(masm, typeAddr, MIRType_TypeObject); masm.storePtr(scratch, typeAddr); + masm.bind(&noTypeChange); Register holderReg; diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 2c0a5f914baa..cf3657f68dbd 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -2583,11 +2583,27 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att if (oldType != obj->type()) { // Changing object's type from a partially to fully initialized type, - // per the acquired properties analysis. + // per the acquired properties analysis. Only change the type if the + // old type still has a newScript. + Label noTypeChange, skipPop; + + masm.push(object); + masm.loadPtr(Address(object, JSObject::offsetOfType()), object); + masm.branchPtr(Assembler::Equal, + Address(object, types::TypeObject::offsetOfNewScript()), + ImmWord(0), + &noTypeChange); + masm.pop(object); + Address typeAddr(object, JSObject::offsetOfType()); if (cx->zone()->needsIncrementalBarrier()) masm.callPreBarrier(typeAddr, MIRType_TypeObject); masm.storePtr(ImmGCPtr(obj->type()), typeAddr); + + masm.jump(&skipPop); + masm.bind(&noTypeChange); + masm.pop(object); + masm.bind(&skipPop); } // Set the value on the object. Since this is an add, obj->lastProperty() diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index a2575e037eea..92fbfc970fd8 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -1236,6 +1236,10 @@ struct TypeObject : public gc::TenuredCell return offsetof(TypeObject, proto_); } + static inline uint32_t offsetOfNewScript() { + return offsetof(TypeObject, newScript_); + } + private: inline uint32_t basePropertyCount() const; inline void setBasePropertyCount(uint32_t count); From a6fea7c09c0596525dc66ab6cdfc613805b51f69 Mon Sep 17 00:00:00 2001 From: "Patrick Wang (Chih-Kai Wang)" Date: Tue, 30 Sep 2014 22:12:11 +0800 Subject: [PATCH 49/58] Bug 1032125: Part 1: Prevent from sending message to Nuwa after Nuwa frozen. r=khuey --- dom/ipc/ContentParent.cpp | 3 +++ dom/ipc/ContentParent.h | 5 +++++ ipc/glue/MessageLink.cpp | 28 ++++++++++++++++++++++++++++ ipc/glue/MessageLink.h | 3 +++ 4 files changed, 39 insertions(+) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 4b38a0ba065e..60b6ae3efb21 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -344,6 +344,7 @@ namespace mozilla { namespace dom { #ifdef MOZ_NUWA_PROCESS +int32_t ContentParent::sNuwaPid = 0; bool ContentParent::sNuwaReady = false; #endif @@ -589,6 +590,7 @@ ContentParent::RunNuwaProcess() /* aIsNuwaProcess = */ true); nuwaProcess->Init(); #ifdef MOZ_NUWA_PROCESS + sNuwaPid = nuwaProcess->Pid(); sNuwaReady = false; #endif return nuwaProcess.forget(); @@ -1992,6 +1994,7 @@ ContentParent::~ContentParent() #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { sNuwaReady = false; + sNuwaPid = 0; } #endif } diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index e59035b41a3f..1ab6467cd976 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -79,6 +79,10 @@ class ContentParent MOZ_FINAL : public PContentParent public: #ifdef MOZ_NUWA_PROCESS + static int32_t NuwaPid() { + return sNuwaPid; + } + static bool IsNuwaReady() { return sNuwaReady; } @@ -730,6 +734,7 @@ private: #endif #ifdef MOZ_NUWA_PROCESS + static int32_t sNuwaPid; static bool sNuwaReady; #endif }; diff --git a/ipc/glue/MessageLink.cpp b/ipc/glue/MessageLink.cpp index 1c5ddeef6727..83cebe301dbd 100644 --- a/ipc/glue/MessageLink.cpp +++ b/ipc/glue/MessageLink.cpp @@ -13,6 +13,7 @@ #ifdef MOZ_NUWA_PROCESS #include "ipc/Nuwa.h" #include "mozilla/Preferences.h" +#include "mozilla/dom/ContentParent.h" #endif #include "mozilla/Assertions.h" @@ -70,6 +71,9 @@ ProcessLink::ProcessLink(MessageChannel *aChan) , mTransport(nullptr) , mIOLoop(nullptr) , mExistingListener(nullptr) +#ifdef MOZ_NUWA_PROCESS + , mIsToNuwaProcess(false) +#endif { } @@ -168,6 +172,26 @@ ProcessLink::SendMessage(Message *msg) mChan->AssertWorkerThread(); mChan->mMonitor->AssertCurrentThreadOwns(); +#ifdef MOZ_NUWA_PROCESS + if (mIsToNuwaProcess && mozilla::dom::ContentParent::IsNuwaReady()) { + switch (msg->type()) { + case mozilla::dom::PContent::Msg_NuwaFork__ID: + case mozilla::dom::PContent::Reply_AddNewProcess__ID: + case mozilla::dom::PContent::Msg_NotifyPhoneStateChange__ID: + case GOODBYE_MESSAGE_TYPE: + break; + default: +#ifdef DEBUG + MOZ_CRASH(); +#else + // In optimized build, message will be dropped. + printf_stderr("Sending message to frozen Nuwa"); + return; +#endif + } + } +#endif + mIOLoop->PostTask( FROM_HERE, NewRunnableMethod(mTransport, &Transport::Send, msg)); @@ -360,6 +384,10 @@ ProcessLink::OnChannelConnected(int32_t peer_pid) if (mExistingListener) mExistingListener->OnChannelConnected(peer_pid); +#ifdef MOZ_NUWA_PROCESS + mIsToNuwaProcess = (peer_pid == mozilla::dom::ContentParent::NuwaPid()); +#endif + if (notifyChannel) { mChan->OnChannelConnected(peer_pid); } diff --git a/ipc/glue/MessageLink.h b/ipc/glue/MessageLink.h index c069112f6c11..42535c02c73b 100644 --- a/ipc/glue/MessageLink.h +++ b/ipc/glue/MessageLink.h @@ -170,6 +170,9 @@ class ProcessLink Transport* mTransport; MessageLoop* mIOLoop; // thread where IO happens Transport::Listener* mExistingListener; // channel's previous listener +#ifdef MOZ_NUWA_PROCESS + bool mIsToNuwaProcess; +#endif }; class ThreadLink : public MessageLink From 6f5608b972870b03c37d120f48fe8a4aca87a80f Mon Sep 17 00:00:00 2001 From: "Patrick Wang (Chih-Kai Wang)" Date: Tue, 30 Sep 2014 22:13:25 +0800 Subject: [PATCH 50/58] Bug 1032125: Part 2: Prevent DOM Storage from sending IPC after Nuwa ready. r=khuey --- dom/storage/DOMStorageIPC.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dom/storage/DOMStorageIPC.cpp b/dom/storage/DOMStorageIPC.cpp index 26dc2d540790..eb8726705eb5 100644 --- a/dom/storage/DOMStorageIPC.cpp +++ b/dom/storage/DOMStorageIPC.cpp @@ -589,8 +589,15 @@ DOMStorageDBParent::Observe(const char* aTopic, const nsACString& aScopePrefix) { if (mIPCOpen) { - mozilla::unused << SendObserve(nsDependentCString(aTopic), - nsCString(aScopePrefix)); +#ifdef MOZ_NUWA_PROCESS + if (!(static_cast(Manager())->IsNuwaProcess() && + ContentParent::IsNuwaReady())) { +#endif + mozilla::unused << SendObserve(nsDependentCString(aTopic), + nsCString(aScopePrefix)); +#ifdef MOZ_NUWA_PROCESS + } +#endif } return NS_OK; From dbc6cda1a68a85560227d4ba4e4d35f0e4342670 Mon Sep 17 00:00:00 2001 From: "Patrick Wang (Chih-Kai Wang)" Date: Tue, 30 Sep 2014 22:13:52 +0800 Subject: [PATCH 51/58] Bug 1032125: Part 3: Don't send frame messages to Nuwa process after Nuwa has frozen. r=khuey --- dom/ipc/ContentParent.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 60b6ae3efb21..6bb6c7d80707 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -3732,6 +3732,12 @@ ContentParent::DoSendAsyncMessage(JSContext* aCx, if (aCpows && !GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { return false; } +#ifdef MOZ_NUWA_PROCESS + if (IsNuwaProcess() && IsNuwaReady()) { + // Nuwa won't receive frame messages after it is frozen. + return true; + } +#endif return SendAsyncMessage(nsString(aMessage), data, cpows, Principal(aPrincipal)); } From a6e2d3180f854ff399d31052e17117d6b5e5d97b Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Wed, 1 Oct 2014 01:25:25 -0400 Subject: [PATCH 52/58] Bug 1074615. Remove DRAW_SNAPPED. r=mwoodrow This doesn't seem to be necessary and doesn't really make sense to me. This will help us moving region clipping into Moz2D --HG-- extra : rebase_source : 4a5987ce2a95eaba44a69233d1b7f461f5ec16ea --- gfx/layers/LayersTypes.h | 3 +-- gfx/layers/RotatedBuffer.cpp | 2 +- gfx/layers/RotatedBuffer.h | 2 +- gfx/layers/basic/BasicPaintedLayer.cpp | 2 +- gfx/layers/client/TiledContentClient.cpp | 4 ++-- gfx/layers/d3d9/PaintedLayerD3D9.cpp | 2 +- layout/base/FrameLayerBuilder.cpp | 12 ++++-------- 7 files changed, 11 insertions(+), 16 deletions(-) diff --git a/gfx/layers/LayersTypes.h b/gfx/layers/LayersTypes.h index c88a0dd3695f..09d922379c5c 100644 --- a/gfx/layers/LayersTypes.h +++ b/gfx/layers/LayersTypes.h @@ -64,8 +64,7 @@ MOZ_END_ENUM_CLASS(BufferMode) MOZ_BEGIN_ENUM_CLASS(DrawRegionClip, int8_t) DRAW, - DRAW_SNAPPED, - CLIP_NONE + NONE MOZ_END_ENUM_CLASS(DrawRegionClip) MOZ_BEGIN_ENUM_CLASS(SurfaceMode, int8_t) diff --git a/gfx/layers/RotatedBuffer.cpp b/gfx/layers/RotatedBuffer.cpp index abe5c267b951..4d00ac6ce7a0 100644 --- a/gfx/layers/RotatedBuffer.cpp +++ b/gfx/layers/RotatedBuffer.cpp @@ -695,7 +695,7 @@ RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer, nsIntRegion invalidate; invalidate.Sub(aLayer->GetValidRegion(), destBufferRect); result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate); - result.mClip = DrawRegionClip::DRAW_SNAPPED; + result.mClip = DrawRegionClip::DRAW; result.mMode = mode; return result; diff --git a/gfx/layers/RotatedBuffer.h b/gfx/layers/RotatedBuffer.h index 51c70f918af3..c71225d7c7d7 100644 --- a/gfx/layers/RotatedBuffer.h +++ b/gfx/layers/RotatedBuffer.h @@ -229,7 +229,7 @@ public: : mRegionToDraw() , mRegionToInvalidate() , mMode(SurfaceMode::SURFACE_NONE) - , mClip(DrawRegionClip::CLIP_NONE) + , mClip(DrawRegionClip::NONE) , mContentType(gfxContentType::SENTINEL) , mDidSelfCopy(false) {} diff --git a/gfx/layers/basic/BasicPaintedLayer.cpp b/gfx/layers/basic/BasicPaintedLayer.cpp index 1180f45a3126..ab7fa7e1b95a 100644 --- a/gfx/layers/basic/BasicPaintedLayer.cpp +++ b/gfx/layers/basic/BasicPaintedLayer.cpp @@ -91,7 +91,7 @@ BasicPaintedLayer::PaintThebes(gfxContext* aContext, groupContext = aContext; } SetAntialiasingFlags(this, groupContext->GetDrawTarget()); - aCallback(this, groupContext, toDraw, DrawRegionClip::CLIP_NONE, nsIntRegion(), aCallbackData); + aCallback(this, groupContext, toDraw, DrawRegionClip::NONE, nsIntRegion(), aCallbackData); if (needsGroup) { aContext->PopGroupToSource(); if (needsClipToVisibleRegion) { diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 90f6884c3d14..f622ca8d9d4f 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -934,7 +934,7 @@ ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw", js::ProfileEntry::Category::GRAPHICS); - mCallback(mPaintedLayer, ctxt, aPaintRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), mCallbackData); + mCallback(mPaintedLayer, ctxt, aPaintRegion, DrawRegionClip::NONE, nsIntRegion(), mCallbackData); } #ifdef GFX_TILEDLAYER_PREF_WARNINGS @@ -1304,7 +1304,7 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile, Scale(mResolution, mResolution)); mCallback(mPaintedLayer, ctxt, tileRegion.GetBounds(), - DrawRegionClip::CLIP_NONE, + DrawRegionClip::NONE, nsIntRegion(), mCallbackData); } diff --git a/gfx/layers/d3d9/PaintedLayerD3D9.cpp b/gfx/layers/d3d9/PaintedLayerD3D9.cpp index c484b7c96362..b49a59a9c0b1 100644 --- a/gfx/layers/d3d9/PaintedLayerD3D9.cpp +++ b/gfx/layers/d3d9/PaintedLayerD3D9.cpp @@ -537,7 +537,7 @@ PaintedLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode, context->SetMatrix(context->CurrentMatrix().Translate(-bounds.x, -bounds.y)); LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); - cbInfo.Callback(this, context, aRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), cbInfo.CallbackData); + cbInfo.Callback(this, context, aRegion, DrawRegionClip::NONE, nsIntRegion(), cbInfo.CallbackData); for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) { NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE, diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index f67bb9d0ca2e..b03cc274041a 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -4371,7 +4371,7 @@ FrameLayerBuilder::PaintItems(nsTArray& aItems, static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip) { if (!gfxPrefs::LayoutPaintRectsSeparately() || - aClip == DrawRegionClip::CLIP_NONE) { + aClip == DrawRegionClip::NONE) { return false; } @@ -4453,9 +4453,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer, bool shouldDrawRectsSeparately = ShouldDrawRectsSeparately(aContext, aClip); if (!shouldDrawRectsSeparately) { - if (aClip == DrawRegionClip::DRAW_SNAPPED) { - gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw); - } else if (aClip == DrawRegionClip::DRAW) { + if (aClip == DrawRegionClip::DRAW) { gfxUtils::ClipToRegion(aContext, aRegionToDraw); } @@ -4486,7 +4484,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer, while (const nsIntRect* iterRect = it.Next()) { gfxContextAutoSaveRestore save(aContext); aContext->NewPath(); - aContext->Rectangle(*iterRect, aClip == DrawRegionClip::DRAW_SNAPPED); + aContext->Rectangle(*iterRect); aContext->Clip(); DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor); @@ -4522,9 +4520,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer, if (presContext->GetPaintFlashing() && isActiveLayerManager) { gfxContextAutoSaveRestore save(aContext); if (shouldDrawRectsSeparately) { - if (aClip == DrawRegionClip::DRAW_SNAPPED) { - gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw); - } else if (aClip == DrawRegionClip::DRAW) { + if (aClip == DrawRegionClip::DRAW) { gfxUtils::ClipToRegion(aContext, aRegionToDraw); } } From 2a587168679c22fe8997a8c3da48f50caaa3be8d Mon Sep 17 00:00:00 2001 From: Gian-Carlo Pascutto Date: Wed, 1 Oct 2014 09:24:14 +0200 Subject: [PATCH 53/58] Bug 1074196 - Correctly initialize PrefixSets with no deltas. r=mmc --- .../nsUrlClassifierPrefixSet.cpp | 11 ++--- .../tests/unit/head_urlclassifier.js | 2 + .../tests/unit/test_prefixset.js | 45 +++++++++++++++++-- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp index f3bf3316a312..fd94760da42b 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp @@ -311,11 +311,11 @@ nsUrlClassifierPrefixSet::LoadFromFd(AutoFDClose& fileFd) if (indexSize != 0 && indexStarts[0] != 0) { return NS_ERROR_FILE_CORRUPTED; } - if (deltaSize > 0) { - for (uint32_t i = 0; i < indexSize; i++) { - mIndexDeltas.AppendElement(); - uint32_t numInDelta = i == indexSize - 1 ? deltaSize - indexStarts[i] - : indexStarts[i + 1] - indexStarts[i]; + for (uint32_t i = 0; i < indexSize; i++) { + mIndexDeltas.AppendElement(); + uint32_t numInDelta = i == indexSize - 1 ? deltaSize - indexStarts[i] + : indexStarts[i + 1] - indexStarts[i]; + if (numInDelta > 0) { mIndexDeltas[i].SetLength(numInDelta); mTotalPrefixes += numInDelta; toRead = numInDelta * sizeof(uint16_t); @@ -330,6 +330,7 @@ nsUrlClassifierPrefixSet::LoadFromFd(AutoFDClose& fileFd) return NS_ERROR_FILE_CORRUPTED; } + MOZ_ASSERT(mIndexPrefixes.Length() == mIndexDeltas.Length()); LOG(("Loading PrefixSet successful")); return NS_OK; diff --git a/toolkit/components/url-classifier/tests/unit/head_urlclassifier.js b/toolkit/components/url-classifier/tests/unit/head_urlclassifier.js index f28fddd3f858..69c249640bec 100644 --- a/toolkit/components/url-classifier/tests/unit/head_urlclassifier.js +++ b/toolkit/components/url-classifier/tests/unit/head_urlclassifier.js @@ -57,6 +57,8 @@ function cleanUp() { delFile("safebrowsing/test-malware-simple.cache"); delFile("safebrowsing/test-phish-simple.pset"); delFile("safebrowsing/test-malware-simple.pset"); + delFile("testLarge.pset"); + delFile("testNoDelta.pset"); } var allTables = "test-phish-simple,test-malware-simple"; diff --git a/toolkit/components/url-classifier/tests/unit/test_prefixset.js b/toolkit/components/url-classifier/tests/unit/test_prefixset.js index f79a3cc2a782..ca2c8a5058c6 100644 --- a/toolkit/components/url-classifier/tests/unit/test_prefixset.js +++ b/toolkit/components/url-classifier/tests/unit/test_prefixset.js @@ -140,7 +140,7 @@ function testReSetPrefixes() { checkContents(pset, secondPrefixes); } -function testLargeSet() { +function testLoadSaveLargeSet() { let N = 1000; let arr = []; @@ -158,6 +158,20 @@ function testLargeSet() { doRandomLookups(pset, arr, 1000); checkContents(pset, arr); + + // Now try to save, restore, and redo the lookups + var file = dirSvc.get('ProfLD', Ci.nsIFile); + file.append("testLarge.pset"); + + pset.storeToFile(file); + + let psetLoaded = newPset(); + psetLoaded.loadFromFile(file); + + doExpectedLookups(psetLoaded, arr, 1); + doRandomLookups(psetLoaded, arr, 1000); + + checkContents(psetLoaded, arr); } function testTinySet() { @@ -176,12 +190,37 @@ function testTinySet() { checkContents(pset, prefixes); } +function testLoadSaveNoDelta() { + let N = 100; + let arr = []; + + for (let i = 0; i < N; i++) { + // construct a tree without deltas by making the distance + // between entries larger than 16 bits + arr.push(((1 << 16) + 1) * i); + } + + let pset = newPset(); + pset.setPrefixes(arr, arr.length); + + doExpectedLookups(pset, arr, 1); + + var file = dirSvc.get('ProfLD', Ci.nsIFile); + file.append("testNoDelta.pset"); + + pset.storeToFile(file); + pset.loadFromFile(file); + + doExpectedLookups(pset, arr, 1); +} + let tests = [testBasicPset, testSimplePset, testReSetPrefixes, - testLargeSet, + testLoadSaveLargeSet, testDuplicates, - testTinySet]; + testTinySet, + testLoadSaveNoDelta]; function run_test() { // None of the tests use |executeSoon| or any sort of callbacks, so we can From 75000a49cd500dbb042921c2af6847d0bbb526dd Mon Sep 17 00:00:00 2001 From: Nikhil Marathe Date: Sat, 23 Aug 2014 20:25:08 -0700 Subject: [PATCH 54/58] Bug 1049599 - ServiceWorkers should also be canceled when a window goes away. r=bent --- dom/workers/RuntimeService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 1526b1f8dc46..0981cf84c3cf 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -2205,7 +2205,7 @@ RuntimeService::CancelWorkersForWindow(nsPIDOMWindow* aWindow) for (uint32_t index = 0; index < workers.Length(); index++) { WorkerPrivate*& worker = workers[index]; - if (worker->IsSharedWorker()) { + if (worker->IsSharedWorker() || worker->IsServiceWorker()) { worker->CloseSharedWorkersForWindow(aWindow); } else if (!worker->Cancel(cx)) { JS_ReportPendingException(cx); From 98029cd38583898ee7c9a5d0dbc5dd26a9467336 Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Mon, 22 Sep 2014 20:03:17 +0200 Subject: [PATCH 55/58] =?UTF-8?q?Bug=201071133=20=E2=80=94=20Make=20sure?= =?UTF-8?q?=20mercurial-setup=20knows=20how=20to=20handle=20unicode=20char?= =?UTF-8?q?acters.=20r=3Dgps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/mercurial/hgsetup/config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/mercurial/hgsetup/config.py b/tools/mercurial/hgsetup/config.py index a89299d0746a..9123c1d9d853 100644 --- a/tools/mercurial/hgsetup/config.py +++ b/tools/mercurial/hgsetup/config.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals from configobj import ConfigObj +import codecs import re import os @@ -43,7 +44,7 @@ class MercurialConfig(object): # other files, this is not supported by ConfigObj, so throw a useful # error saying this. if os.path.exists(infile): - with open(infile, 'r') as f: + with codecs.open(infile, 'r', encoding='utf-8') as f: for line in f: if line.startswith('%include'): raise HgIncludeException( From ca8e97b1fd50603a47dd6d7d60279229c6b15cc9 Mon Sep 17 00:00:00 2001 From: "Nils Ohlmeier [:drno]" Date: Fri, 26 Sep 2014 14:34:00 +0200 Subject: [PATCH 56/58] Bug 1072945 - stop trickle ICE if PeerConnections are closed. r=bwc --- dom/media/tests/mochitest/pc.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/dom/media/tests/mochitest/pc.js b/dom/media/tests/mochitest/pc.js index 1e4e4a6b8920..0b1d3bc86723 100644 --- a/dom/media/tests/mochitest/pc.js +++ b/dom/media/tests/mochitest/pc.js @@ -1937,6 +1937,10 @@ PeerConnectionWrapper.prototype = { var self = this; self._remote_ice_candidates.push(candidate); + if (self.signalingstate === 'closed') { + info("Received ICE candidate for closed PeerConnection - discarding"); + return; + } if (self.remoteDescriptionSet) { self.addIceCandidate(candidate); } else { @@ -2566,15 +2570,9 @@ PeerConnectionWrapper.prototype = { * Closes the connection */ close : function PCW_close() { - // It might be that a test has already closed the pc. In those cases - // we should not fail. - try { - this._pc.close(); - info(this + ": Closed connection."); - } - catch (e) { - info(this + ": Failure in closing connection - " + e.message); - } + this._ice_candidates_to_add = []; + this._pc.close(); + info(this + ": Closed connection."); }, /** From 388ecb11aed28ddbd70956a8ea2305aa9b39997c Mon Sep 17 00:00:00 2001 From: xKhorasan Date: Sun, 28 Sep 2014 08:51:23 +0900 Subject: [PATCH 57/58] Bug 1073882 - XMLHttpRequest.prototype.responseURL should not have fragment per latest spec. r=smaug --- content/base/src/nsXMLHttpRequest.cpp | 2 +- content/base/test/file_XHRResponseURL.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 49a9cc4b10ac..80d053254314 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -1090,7 +1090,7 @@ nsXMLHttpRequest::GetResponseURL(nsAString& aUrl) } nsAutoCString temp; - responseUrl->GetSpec(temp); + responseUrl->GetSpecIgnoringRef(temp); CopyUTF8toUTF16(temp, aUrl); } diff --git a/content/base/test/file_XHRResponseURL.js b/content/base/test/file_XHRResponseURL.js index 0481afc759f9..ab4326ba8353 100644 --- a/content/base/test/file_XHRResponseURL.js +++ b/content/base/test/file_XHRResponseURL.js @@ -189,6 +189,11 @@ function testSuccessResponse() { skip: isInWorker(), reason: "cross-origin redirect request not works on Workers, see bug 882458" }, + { + message: "request URL has fragment", + requestURL: "http://mochi.test:8888/tests/content/base/test/file_XHRResponseURL.text#fragment", + responseURL: "http://mochi.test:8888/tests/content/base/test/file_XHRResponseURL.text" + }, // tests for non-http(s) URL { From 784c2ac8ee3461000333097130d16437c45a683e Mon Sep 17 00:00:00 2001 From: Dave Hunt Date: Tue, 30 Sep 2014 02:10:00 +0200 Subject: [PATCH 58/58] Bug 1073441 - [mozversion] Include base image version for Flame-KK device. r=wlachance --- testing/mozbase/mozversion/mozversion/mozversion.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/testing/mozbase/mozversion/mozversion/mozversion.py b/testing/mozbase/mozversion/mozversion/mozversion.py index d24fa9c1c091..ca5d76bf884c 100644 --- a/testing/mozbase/mozversion/mozversion/mozversion.py +++ b/testing/mozbase/mozversion/mozversion/mozversion.py @@ -231,8 +231,11 @@ class RemoteB2GVersion(B2GVersion): self._info[desired_props[key]] = value if self._info.get('device_id', '').lower() == 'flame': - self._info['device_firmware_version_base'] = dm._runCmd( - ['shell', 'getprop', 't2m.sw.version']).output[0] + for prop in ['ro.boot.bootloader', 't2m.sw.version']: + value = dm.shellCheckOutput(['getprop', prop]) + if value: + self._info['device_firmware_version_base'] = value + break def get_version(binary=None, sources=None, dm_type=None, host=None,