From 5ef6b7bea8f3b662b5c2435ac5337130dce8718f Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Fri, 19 Jun 2015 14:26:44 -0700 Subject: [PATCH 001/111] Bug 1176085 - Fix second/nanosecond confusion in Linux sandbox start error case. r=kang --- security/sandbox/linux/Sandbox.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/sandbox/linux/Sandbox.cpp b/security/sandbox/linux/Sandbox.cpp index 1520dd9a4c0..2f851e25d9f 100644 --- a/security/sandbox/linux/Sandbox.cpp +++ b/security/sandbox/linux/Sandbox.cpp @@ -394,8 +394,8 @@ BroadcastSetThreadSandbox(UniquePtr aProgram, size_t aProgLen) } struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - if (now.tv_sec > timeLimit.tv_nsec || - (now.tv_sec == timeLimit.tv_nsec && + if (now.tv_sec > timeLimit.tv_sec || + (now.tv_sec == timeLimit.tv_sec && now.tv_nsec > timeLimit.tv_nsec)) { SANDBOX_LOG_ERROR("Thread %d unresponsive for %d seconds." " Killing process.", From 919541984930d4f7b259e660ebd4aec13e049a4c Mon Sep 17 00:00:00 2001 From: Michael Layzell Date: Fri, 19 Jun 2015 14:27:37 -0700 Subject: [PATCH 002/111] Bug 1173503 - Make do_check_true output include the passed message in xpcshell unit tests r=ted --- testing/xpcshell/head.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/xpcshell/head.js b/testing/xpcshell/head.js index b80bae4ca44..83c2fc689b6 100644 --- a/testing/xpcshell/head.js +++ b/testing/xpcshell/head.js @@ -855,7 +855,7 @@ function todo_check_eq(left, right, stack) { } function do_check_true(condition, stack) { - Assert.ok(condition); + Assert.ok(condition, stack); } function todo_check_true(condition, stack) { From 28fe48ffe9b1cbda55b686d109856ccbcb8c420f Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Fri, 19 Jun 2015 14:36:23 -0400 Subject: [PATCH 003/111] Bug 1150232 - Stop gap solution until we can integrate the graphics docs. r=mstange --- gfx/docs/index.rst | 9 +++++++++ gfx/moz.build | 1 + 2 files changed, 10 insertions(+) create mode 100644 gfx/docs/index.rst diff --git a/gfx/docs/index.rst b/gfx/docs/index.rst new file mode 100644 index 00000000000..c6621c81ab2 --- /dev/null +++ b/gfx/docs/index.rst @@ -0,0 +1,9 @@ +======== +Graphics +======== + +The graphics team's documentation is currently using doxygen. We're tracking the work to integrate it better at https://bugzilla.mozilla.org/show_bug.cgi?id=1150232. + +For now you can read the graphics source code documentation here: + +http://people.mozilla.org/~bgirard/doxygen/gfx/ diff --git a/gfx/moz.build b/gfx/moz.build index 7b2cba5b95c..d5e33270335 100644 --- a/gfx/moz.build +++ b/gfx/moz.build @@ -34,3 +34,4 @@ if CONFIG['ENABLE_TESTS']: TEST_DIRS += ['tests'] +SPHINX_TREES['gfx'] = 'docs' From 8c71cdf13dbebb1f8fe870350c232ec61bbec91e Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Fri, 19 Jun 2015 21:04:51 +0300 Subject: [PATCH 004/111] Bug 654579 - Set the network.manage-offline-status to true for desktop. r=bagder CLOSED TREE --- browser/app/profile/firefox.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 9d37961378b..2363b998c59 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -628,7 +628,7 @@ pref("browser.xul.error_pages.enabled", true); pref("browser.xul.error_pages.expert_bad_cert", false); // If true, network link events will change the value of navigator.onLine -pref("network.manage-offline-status", false); +pref("network.manage-offline-status", true); // We want to make sure mail URLs are handled externally... pref("network.protocol-handler.external.mailto", true); // for mail From e4f98fdfd06d6da80edeb7600d1bda187038a58e Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Fri, 19 Jun 2015 15:55:12 -0700 Subject: [PATCH 005/111] Bug 1174923 - Stop delaying the document load event until images are decoded. r=tn a=kwierso --- dom/base/nsImageLoadingContent.cpp | 33 ++-------------- dom/base/nsImageLoadingContent.h | 1 - image/Decoder.cpp | 7 ++-- image/RasterImage.cpp | 8 ++-- image/test/browser/browser_bug666317.js | 38 +++++++++++++----- image/test/mochitest/mochitest.ini | 1 - image/test/mochitest/test_bug512435.html | 49 ------------------------ layout/reftests/css-break/reftest.list | 2 +- 8 files changed, 39 insertions(+), 100 deletions(-) delete mode 100644 image/test/mochitest/test_bug512435.html diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index 9008d4fbbc4..18205ab5d31 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -87,7 +87,6 @@ nsImageLoadingContent::nsImageLoadingContent() mBroken(true), mUserDisabled(false), mSuppressed(false), - mFireEventsOnDecode(false), mNewRequestsWillNeedAnimationReset(false), mStateChangerDepth(0), mCurrentRequestRegistered(false), @@ -186,18 +185,6 @@ nsImageLoadingContent::Notify(imgIRequest* aRequest, } if (aType == imgINotificationObserver::DECODE_COMPLETE) { - if (mFireEventsOnDecode) { - mFireEventsOnDecode = false; - - uint32_t reqStatus; - aRequest->GetImageStatus(&reqStatus); - if (reqStatus & imgIRequest::STATUS_ERROR) { - FireEvent(NS_LITERAL_STRING("error")); - } else { - FireEvent(NS_LITERAL_STRING("load")); - } - } - UpdateImageState(true); } @@ -277,23 +264,11 @@ nsImageLoadingContent::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus) } } - // We want to give the decoder a chance to find errors. If we haven't found - // an error yet and we've started decoding, either from the above - // StartDecoding or from some other place, we must only fire these events - // after we finish decoding. - uint32_t reqStatus; - aRequest->GetImageStatus(&reqStatus); - if (NS_SUCCEEDED(aStatus) && !(reqStatus & imgIRequest::STATUS_ERROR) && - (reqStatus & imgIRequest::STATUS_DECODE_STARTED) && - !(reqStatus & imgIRequest::STATUS_DECODE_COMPLETE)) { - mFireEventsOnDecode = true; + // Fire the appropriate DOM event. + if (NS_SUCCEEDED(aStatus)) { + FireEvent(NS_LITERAL_STRING("load")); } else { - // Fire the appropriate DOM event. - if (NS_SUCCEEDED(aStatus)) { - FireEvent(NS_LITERAL_STRING("load")); - } else { - FireEvent(NS_LITERAL_STRING("error")); - } + FireEvent(NS_LITERAL_STRING("error")); } nsCOMPtr thisNode = do_QueryInterface(static_cast(this)); diff --git a/dom/base/nsImageLoadingContent.h b/dom/base/nsImageLoadingContent.h index 36b130dbc0e..8d23d379557 100644 --- a/dom/base/nsImageLoadingContent.h +++ b/dom/base/nsImageLoadingContent.h @@ -410,7 +410,6 @@ private: bool mBroken : 1; bool mUserDisabled : 1; bool mSuppressed : 1; - bool mFireEventsOnDecode : 1; protected: /** diff --git a/image/Decoder.cpp b/image/Decoder.cpp index 8ce895f052a..9de720488b4 100644 --- a/image/Decoder.cpp +++ b/image/Decoder.cpp @@ -83,9 +83,8 @@ Decoder::Init() // No re-initializing MOZ_ASSERT(!mInitialized, "Can't re-initialize a decoder!"); - // Fire OnStartDecode at init time to support bug 512435. if (!IsSizeDecode()) { - mProgress |= FLAG_DECODE_STARTED | FLAG_ONLOAD_BLOCKED; + mProgress |= FLAG_DECODE_STARTED; } // Implementation-specific initialization @@ -273,7 +272,7 @@ Decoder::CompleteDecode() } else { // We're not usable. Record some final progress indicating the error. if (!IsSizeDecode()) { - mProgress |= FLAG_DECODE_COMPLETE | FLAG_ONLOAD_UNBLOCKED; + mProgress |= FLAG_DECODE_COMPLETE; } mProgress |= FLAG_HAS_ERROR; } @@ -624,7 +623,7 @@ Decoder::PostFrameStop(Opacity aFrameOpacity /* = Opacity::TRANSPARENT */, mCurrentFrame->Finish(aFrameOpacity, aDisposalMethod, aTimeout, aBlendMethod); - mProgress |= FLAG_FRAME_COMPLETE | FLAG_ONLOAD_UNBLOCKED; + mProgress |= FLAG_FRAME_COMPLETE; // If we're not sending partial invalidations, then we send an invalidation // here when the first frame is complete. diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index e986ada7258..440297d3bf5 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -1211,11 +1211,9 @@ RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult aStatus, // to draw. (We may have already sent some of these notifications from // NotifyForDecodeOnlyOnDraw(), but ProgressTracker will ensure no duplicate // notifications get sent.) - loadProgress |= FLAG_ONLOAD_BLOCKED | - FLAG_DECODE_STARTED | + loadProgress |= FLAG_DECODE_STARTED | FLAG_FRAME_COMPLETE | - FLAG_DECODE_COMPLETE | - FLAG_ONLOAD_UNBLOCKED; + FLAG_DECODE_COMPLETE; } // Notify our listeners, which will fire this image's load event. @@ -1234,7 +1232,7 @@ RasterImage::NotifyForDecodeOnlyOnDraw() return; } - NotifyProgress(FLAG_DECODE_STARTED | FLAG_ONLOAD_BLOCKED); + NotifyProgress(FLAG_DECODE_STARTED); } nsresult diff --git a/image/test/browser/browser_bug666317.js b/image/test/browser/browser_bug666317.js index ed7024db399..dfc6b91862d 100644 --- a/image/test/browser/browser_bug666317.js +++ b/image/test/browser/browser_bug666317.js @@ -41,6 +41,23 @@ function forceDecodeImg() { ctx.drawImage(img, 0, 0); } +function runAfterAsyncEvents(aCallback) { + function handlePostMessage(aEvent) { + if (aEvent.data == 'next') { + window.removeEventListener('message', handlePostMessage, false); + aCallback(); + } + } + + window.addEventListener('message', handlePostMessage, false); + + // We'll receive the 'message' event after everything else that's currently in + // the event queue (which is a stronger guarantee than setTimeout, because + // setTimeout events may be coalesced). This lets us ensure that we run + // aCallback *after* any asynchronous events are delivered. + window.postMessage('next', '*'); +} + function test() { // Enable the discarding pref. oldDiscardingPref = prefBranch.getBoolPref('discardable'); @@ -72,6 +89,13 @@ function step2() { // Check that the image is decoded. forceDecodeImg(); + + // The FRAME_COMPLETE notification is delivered asynchronously, so continue + // after we're sure it has been delivered. + runAfterAsyncEvents(() => step3(result, scriptedObserver, clonedRequest)); +} + +function step3(result, scriptedObserver, clonedRequest) { ok(isImgDecoded(), 'Image should initially be decoded.'); // Focus the old tab, then fire a memory-pressure notification. This should @@ -81,18 +105,12 @@ function step2() { .getService(Ci.nsIObserverService); os.notifyObservers(null, 'memory-pressure', 'heap-minimize'); - // The discard notification is delivered asynchronously, so pump the event - // loop before checking. - window.addEventListener('message', function (event) { - if (event.data == 'step3') { - step3(result, scriptedObserver, clonedRequest); - } - }, false); - - window.postMessage('step3', '*'); + // The DISCARD notification is delivered asynchronously, so continue after + // we're sure it has been delivered. + runAfterAsyncEvents(() => step4(result, scriptedObserver, clonedRequest)); } -function step3(result, scriptedObserver, clonedRequest) { +function step4(result, scriptedObserver, clonedRequest) { ok(result.wasDiscarded, 'Image should be discarded.'); // And we're done. diff --git a/image/test/mochitest/mochitest.ini b/image/test/mochitest/mochitest.ini index 0ea4e292211..611d543637a 100644 --- a/image/test/mochitest/mochitest.ini +++ b/image/test/mochitest/mochitest.ini @@ -70,7 +70,6 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only [test_bug496292.html] [test_bug497665.html] skip-if = (toolkit == 'android' && processor == 'x86') #x86 only -[test_bug512435.html] [test_bug552605-1.html] [test_bug552605-2.html] [test_bug553982.html] diff --git a/image/test/mochitest/test_bug512435.html b/image/test/mochitest/test_bug512435.html deleted file mode 100644 index 1bffca1647e..00000000000 --- a/image/test/mochitest/test_bug512435.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - Test for Bug 512435 - - - - - - -Mozilla Bug 512435 - - - -
-
-
- - diff --git a/layout/reftests/css-break/reftest.list b/layout/reftests/css-break/reftest.list index ae58ccdfb69..eccad5dc895 100644 --- a/layout/reftests/css-break/reftest.list +++ b/layout/reftests/css-break/reftest.list @@ -6,4 +6,4 @@ fuzzy(16,460) fuzzy-if(Android,10,3667) == box-decoration-break-with-outset-box- random-if(!gtkWidget) HTTP(..) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html == box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html -fuzzy-if(Android,8,6627) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html +fuzzy-if(!Android,1,5) fuzzy-if(Android,8,6627) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html From d3a685e1c32c5ed918d54757f8ef2f42ea9f1caf Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Fri, 19 Jun 2015 15:56:12 -0700 Subject: [PATCH 006/111] Bug 1176270: Handle self-assignment in StyleAnimationValue::operator=. r=dbaron a=KWierso to land while checkins are metered --- layout/style/StyleAnimationValue.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/layout/style/StyleAnimationValue.cpp b/layout/style/StyleAnimationValue.cpp index 1a2ac0676b7..e435fa0dd97 100644 --- a/layout/style/StyleAnimationValue.cpp +++ b/layout/style/StyleAnimationValue.cpp @@ -3564,6 +3564,10 @@ StyleAnimationValue::StyleAnimationValue(nscolor aColor, ColorConstructorType) StyleAnimationValue& StyleAnimationValue::operator=(const StyleAnimationValue& aOther) { + if (this == &aOther) { + return *this; + } + FreeValue(); mUnit = aOther.mUnit; From cf4e8799c5f4d2eeafdba4e83a153f5c2afd8d0e Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 19 Jun 2015 16:22:19 -0700 Subject: [PATCH 007/111] Bug 1176411 - Stop parenthesizing array/object pattern destructuring assignment targets in addon SDK code. r=jsantell, a=KWierso --- addon-sdk/source/lib/sdk/io/buffer.js | 4 ++-- addon-sdk/source/lib/sdk/panel/utils.js | 4 ++-- addon-sdk/source/lib/sdk/util/sequence.js | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/addon-sdk/source/lib/sdk/io/buffer.js b/addon-sdk/source/lib/sdk/io/buffer.js index 77a480597a9..bb4d5c34536 100644 --- a/addon-sdk/source/lib/sdk/io/buffer.js +++ b/addon-sdk/source/lib/sdk/io/buffer.js @@ -247,11 +247,11 @@ Object.defineProperties(Buffer.prototype, { value: function(string, offset, length, encoding = 'utf8') { // write(string, encoding); if (typeof(offset) === 'string' && Number.isNaN(parseInt(offset))) { - ([offset, length, encoding]) = [0, null, offset]; + [offset, length, encoding] = [0, null, offset]; } // write(string, offset, encoding); else if (typeof(length) === 'string') - ([length, encoding]) = [null, length]; + [length, encoding] = [null, length]; if (offset < 0 || offset > this.length) throw new RangeError('offset is outside of valid range'); diff --git a/addon-sdk/source/lib/sdk/panel/utils.js b/addon-sdk/source/lib/sdk/panel/utils.js index 577ed1e6c52..c9a39e97bef 100644 --- a/addon-sdk/source/lib/sdk/panel/utils.js +++ b/addon-sdk/source/lib/sdk/panel/utils.js @@ -129,7 +129,7 @@ function display(panel, options, anchor) { let viewportRect = document.defaultView.gBrowser.getBoundingClientRect(); - ({x, y, width, height}) = calculateRegion(options, viewportRect); + ({x, y, width, height} = calculateRegion(options, viewportRect)); } else { // The XUL Panel has an arrow, so the margin needs to be reset @@ -145,7 +145,7 @@ function display(panel, options, anchor) { // chrome browser window, and therefore there is no need for this check. if (CustomizableUI) { let node = anchor; - ({anchor}) = CustomizableUI.getWidget(anchor.id).forWindow(window); + ({anchor} = CustomizableUI.getWidget(anchor.id).forWindow(window)); // if `node` is not the `anchor` itself, it means the widget is // positioned in a panel, therefore we have to hide it before show diff --git a/addon-sdk/source/lib/sdk/util/sequence.js b/addon-sdk/source/lib/sdk/util/sequence.js index e10563a9a36..28e3de25588 100644 --- a/addon-sdk/source/lib/sdk/util/sequence.js +++ b/addon-sdk/source/lib/sdk/util/sequence.js @@ -245,7 +245,7 @@ const map = (f, ...sequences) => seq(function* () { let index = 0; let value = void(0); while (index < count && !done) { - ({ done, value }) = inputs[index].next(); + ({ done, value } = inputs[index].next()); // If input is not exhausted yet store value in args. if (!done) { @@ -273,10 +273,10 @@ const reductions = (...params) => { let hasInitial = false; let f, initial, source; if (count === 2) { - ([f, source]) = params; + [f, source] = params; } else if (count === 3) { - ([f, initial, source]) = params; + [f, initial, source] = params; hasInitial = true; } else { From d6cc8a3b563e4b0f727c55830a76b0937c3e84f6 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 16 Jun 2015 23:53:04 -0700 Subject: [PATCH 008/111] Bug 1146136 - Parenthesized "destructuring patterns" shouldn't actually be destructuring patterns. r=efaust, a=KWierso --- js/src/frontend/FoldConstants.cpp | 1 + js/src/frontend/FullParseHandler.h | 37 ++- js/src/frontend/Parser.cpp | 267 +++++++++++------- js/src/frontend/Parser.h | 25 +- js/src/frontend/SyntaxParseHandler.h | 135 +++++++-- .../tests/basic/destructuring-rest.js | 11 +- .../tests/basic/spread-call-setcall.js | 6 +- js/src/js.msg | 1 + .../destructuring-pattern-parenthesized.js | 105 +++++++ js/src/vm/Xdr.h | 4 +- 10 files changed, 432 insertions(+), 160 deletions(-) create mode 100644 js/src/tests/ecma_6/Expressions/destructuring-pattern-parenthesized.js diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 5b35f86a825..bee049ff2c4 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -1087,6 +1087,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, ParseNode* expr = handler.newPropertyAccess(pn->pn_left, name, pn->pn_pos.end); if (!expr) return false; + expr->setInParens(pn->isInParens()); ReplaceNode(pnp, expr); // Supposing we're replacing |obj["prop"]| with |obj.prop|, we now diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index d548efb192c..c44562539b2 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -83,8 +83,21 @@ class FullParseHandler return node->isKind(PNK_CALL); } - bool isDestructuringTarget(ParseNode* node) { - return node->isKind(PNK_OBJECT) || node->isKind(PNK_ARRAY); + static bool isUnparenthesizedDestructuringPattern(ParseNode* node) { + return !node->isInParens() && (node->isKind(PNK_OBJECT) || node->isKind(PNK_ARRAY)); + } + + static bool isParenthesizedDestructuringPattern(ParseNode* node) { + // Technically this isn't a destructuring pattern at all -- the grammar + // doesn't treat it as such. But we need to know when this happens to + // consider it a SyntaxError rather than an invalid-left-hand-side + // ReferenceError. + return node->isInParens() && (node->isKind(PNK_OBJECT) || node->isKind(PNK_ARRAY)); + } + + static bool isDestructuringPatternAnyParentheses(ParseNode* node) { + return isUnparenthesizedDestructuringPattern(node) || + isParenthesizedDestructuringPattern(node); } FullParseHandler(ExclusiveContext* cx, LifoAlloc& alloc, @@ -780,9 +793,25 @@ class FullParseHandler bool isConstant(ParseNode* pn) { return pn->isConstant(); } - PropertyName* maybeName(ParseNode* pn) { - return pn->isKind(PNK_NAME) ? pn->pn_atom->asPropertyName() : nullptr; + + PropertyName* maybeUnparenthesizedName(ParseNode* pn) { + if (!pn->isInParens() && pn->isKind(PNK_NAME)) + return pn->pn_atom->asPropertyName(); + return nullptr; } + + PropertyName* maybeParenthesizedName(ParseNode* pn) { + if (pn->isInParens() && pn->isKind(PNK_NAME)) + return pn->pn_atom->asPropertyName(); + return nullptr; + } + + PropertyName* maybeNameAnyParentheses(ParseNode* node) { + if (PropertyName* name = maybeUnparenthesizedName(node)) + return name; + return maybeParenthesizedName(node); + } + bool isCall(ParseNode* pn) { return pn->isKind(PNK_CALL); } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c5cf09a3108..b88019787a5 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1155,7 +1155,7 @@ Parser::makeDefIntoUse(Definition* dn, ParseNode* pn, JSAtom* * helper function signature in order to share code among destructuring and * simple variable declaration parsers. In the destructuring case, the binder * function is called indirectly from the variable declaration parser by way - * of checkDestructuring and its friends. + * of checkDestructuringPattern and its friends. */ template @@ -3383,7 +3383,65 @@ Parser::bindInitialized(BindData* data, Pars template <> bool -Parser::checkDestructuring(BindData* data, ParseNode* left); +Parser::checkDestructuringName(BindData* data, ParseNode* expr) +{ + MOZ_ASSERT(!handler.isUnparenthesizedDestructuringPattern(expr)); + + // Parentheses are forbidden around destructuring *patterns* (but allowed + // around names). Use our nicer error message for parenthesized, nested + // patterns. + if (handler.isParenthesizedDestructuringPattern(expr)) { + report(ParseError, false, expr, JSMSG_BAD_DESTRUCT_PARENS); + return false; + } + + // This expression might be in a variable-binding pattern where only plain, + // unparenthesized names are permitted. + if (data) { + // Destructuring patterns in declarations must only contain + // unparenthesized names. + if (!handler.maybeUnparenthesizedName(expr)) { + report(ParseError, false, expr, JSMSG_NO_VARIABLE_NAME); + return false; + } + + return bindInitialized(data, expr); + } + + // Otherwise this is an expression in destructuring outside a declaration. + if (!reportIfNotValidSimpleAssignmentTarget(expr, KeyedDestructuringAssignment)) + return false; + + MOZ_ASSERT(!handler.isFunctionCall(expr), + "function calls shouldn't be considered valid targets in " + "destructuring patterns"); + + if (handler.maybeNameAnyParentheses(expr)) { + // The arguments/eval identifiers are simple in non-strict mode code. + // Warn to discourage their use nonetheless. + if (!reportIfArgumentsEvalTarget(expr)) + return false; + + // We may be called on a name node that has already been + // specialized, in the very weird "for (var [x] = i in o) ..." + // case. See bug 558633. + // + // XXX Is this necessary with the changes in bug 1164741? This is + // likely removable now. + handler.maybeDespecializeSet(expr); + + handler.markAsAssigned(expr); + return true; + } + + // Nothing further to do for property accesses. + MOZ_ASSERT(handler.isPropertyAccess(expr)); + return true; +} + +template <> +bool +Parser::checkDestructuringPattern(BindData* data, ParseNode* pattern); template <> bool @@ -3393,30 +3451,28 @@ Parser::checkDestructuringObject(BindData* d MOZ_ASSERT(objectPattern->isKind(PNK_OBJECT)); for (ParseNode* member = objectPattern->pn_head; member; member = member->pn_next) { - ParseNode* expr; + ParseNode* target; if (member->isKind(PNK_MUTATEPROTO)) { - expr = member->pn_kid; + target = member->pn_kid; } else { MOZ_ASSERT(member->isKind(PNK_COLON) || member->isKind(PNK_SHORTHAND)); - expr = member->pn_right; - } - if (expr->isKind(PNK_ASSIGN)) - expr = expr->pn_left; + MOZ_ASSERT_IF(member->isKind(PNK_SHORTHAND), + member->pn_left->isKind(PNK_OBJECT_PROPERTY_NAME) && + member->pn_right->isKind(PNK_NAME) && + member->pn_left->pn_atom == member->pn_right->pn_atom); - bool ok; - if (expr->isKind(PNK_ARRAY) || expr->isKind(PNK_OBJECT)) { - ok = checkDestructuring(data, expr); - } else if (data) { - if (!expr->isKind(PNK_NAME)) { - report(ParseError, false, expr, JSMSG_NO_VARIABLE_NAME); - return false; - } - ok = bindInitialized(data, expr); - } else { - ok = checkAndMarkAsAssignmentLhs(expr, KeyedDestructuringAssignment); + target = member->pn_right; + } + if (target->isKind(PNK_ASSIGN)) + target = target->pn_left; + + if (handler.isUnparenthesizedDestructuringPattern(target)) { + if (!checkDestructuringPattern(data, target)) + return false; + } else { + if (!checkDestructuringName(data, target)) + return false; } - if (!ok) - return false; } return true; @@ -3433,39 +3489,31 @@ Parser::checkDestructuringArray(BindData* da if (element->isKind(PNK_ELISION)) continue; - ParseNode* target = element; - if (target->isKind(PNK_SPREAD)) { - if (target->pn_next) { - report(ParseError, false, target->pn_next, JSMSG_PARAMETER_AFTER_REST); + ParseNode* target; + if (element->isKind(PNK_SPREAD)) { + if (element->pn_next) { + report(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST); return false; } - target = target->pn_kid; + target = element->pn_kid; - // The RestElement should not support nested patterns. - if (target->isKind(PNK_ARRAY) || target->isKind(PNK_OBJECT)) { + if (handler.isUnparenthesizedDestructuringPattern(target)) { report(ParseError, false, target, JSMSG_BAD_DESTRUCT_TARGET); return false; } - } else if (target->isKind(PNK_ASSIGN)) { - target = target->pn_left; + } else if (element->isKind(PNK_ASSIGN)) { + target = element->pn_left; + } else { + target = element; } - bool ok; - if (target->isKind(PNK_ARRAY) || target->isKind(PNK_OBJECT)) { - ok = checkDestructuring(data, target); + if (handler.isUnparenthesizedDestructuringPattern(target)) { + if (!checkDestructuringPattern(data, target)) + return false; } else { - if (data) { - if (!target->isKind(PNK_NAME)) { - report(ParseError, false, target, JSMSG_NO_VARIABLE_NAME); - return false; - } - ok = bindInitialized(data, target); - } else { - ok = checkAndMarkAsAssignmentLhs(target, KeyedDestructuringAssignment); - } + if (!checkDestructuringName(data, target)) + return false; } - if (!ok) - return false; } return true; @@ -3485,16 +3533,16 @@ Parser::checkDestructuringArray(BindData* da * simple names; the destructuring defines them as new variables. * * In both cases, other code parses the pattern as an arbitrary - * primaryExpr, and then, here in checkDestructuring, verify that the - * tree is a valid AssignmentPattern or BindingPattern. + * primaryExpr, and then, here in checkDestructuringPattern, verify + * that the tree is a valid AssignmentPattern or BindingPattern. * * In assignment-like contexts, we parse the pattern with * pc->inDeclDestructuring clear, so the lvalue expressions in the * pattern are parsed normally. primaryExpr links variable references * into the appropriate use chains; creates placeholder definitions; - * and so on. checkDestructuring is called with |data| nullptr (since - * we won't be binding any new names), and we specialize lvalues as - * appropriate. + * and so on. checkDestructuringPattern is called with |data| nullptr + * (since we won't be binding any new names), and we specialize lvalues + * as appropriate. * * In declaration-like contexts, the normal variable reference * processing would just be an obstruction, because we're going to @@ -3502,28 +3550,28 @@ Parser::checkDestructuringArray(BindData* da * variables anyway. In this case, we parse the pattern with * pc->inDeclDestructuring set, which directs primaryExpr to leave * whatever name nodes it creates unconnected. Then, here in - * checkDestructuring, we require the pattern's property value + * checkDestructuringPattern, we require the pattern's property value * positions to be simple names, and define them as appropriate to the * context. For these calls, |data| points to the right sort of * BindData. */ template <> bool -Parser::checkDestructuring(BindData* data, ParseNode* left) +Parser::checkDestructuringPattern(BindData* data, ParseNode* pattern) { - if (left->isKind(PNK_ARRAYCOMP)) { - report(ParseError, false, left, JSMSG_ARRAY_COMP_LEFTSIDE); + if (pattern->isKind(PNK_ARRAYCOMP)) { + report(ParseError, false, pattern, JSMSG_ARRAY_COMP_LEFTSIDE); return false; } - if (left->isKind(PNK_ARRAY)) - return checkDestructuringArray(data, left); - return checkDestructuringObject(data, left); + if (pattern->isKind(PNK_ARRAY)) + return checkDestructuringArray(data, pattern); + return checkDestructuringObject(data, pattern); } template <> bool -Parser::checkDestructuring(BindData* data, Node left) +Parser::checkDestructuringPattern(BindData* data, Node pattern) { return abortIfSyntaxParser(); } @@ -3540,7 +3588,7 @@ Parser::destructuringExpr(YieldHandling yieldHandling, BindDatainDeclDestructuring = false; if (!pn) return null(); - if (!checkDestructuring(data, pn)) + if (!checkDestructuringPattern(data, pn)) return null(); return pn; } @@ -3829,7 +3877,7 @@ Parser::variables(YieldHandling yieldHandling, // handles the non-destructuring case. bool bindBeforeInitializer = (kind != PNK_LET && kind != PNK_CONST) || parsingForInOrOfInit; - if (bindBeforeInitializer && !checkDestructuring(&data, pn2)) + if (bindBeforeInitializer && !checkDestructuringPattern(&data, pn2)) return null(); if (parsingForInOrOfInit) { @@ -3858,7 +3906,7 @@ Parser::variables(YieldHandling yieldHandling, } } - if (!bindBeforeInitializer && !checkDestructuring(&data, pn2)) + if (!bindBeforeInitializer && !checkDestructuringPattern(&data, pn2)) return null(); pn2 = handler.newBinary(PNK_ASSIGN, pn2, init); @@ -5131,7 +5179,7 @@ Parser::forStatement(YieldHandling yieldHandling) /* Check that the left side of the 'in' or 'of' is valid. */ if (!isForDecl && - !handler.maybeName(lhsNode) && + !handler.maybeNameAnyParentheses(lhsNode) && !handler.isPropertyAccess(lhsNode)) { JS_ALWAYS_FALSE(abortIfSyntaxParser()); @@ -6422,14 +6470,17 @@ template bool Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor flavor) { - // Handle destructuring object/array patterns specially. - if (handler.isDestructuringTarget(target)) { + MOZ_ASSERT(flavor != KeyedDestructuringAssignment, + "destructuring must use special checking/marking code, not " + "this method"); + + if (handler.isUnparenthesizedDestructuringPattern(target)) { if (flavor == CompoundAssignment) { report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_ASS); return false; } - return checkDestructuring(nullptr, target); + return checkDestructuringPattern(nullptr, target); } // All other permitted targets are simple. @@ -6439,34 +6490,18 @@ Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor if (handler.isPropertyAccess(target)) return true; - if (handler.maybeName(target)) { + if (handler.maybeNameAnyParentheses(target)) { // The arguments/eval identifiers are simple in non-strict mode code, // but warn to discourage use nonetheless. if (!reportIfArgumentsEvalTarget(target)) return false; - if (flavor == KeyedDestructuringAssignment) { - // We may be called on a name node that has already been - // specialized, in the very weird "for (var [x] = i in o) ..." - // case. See bug 558633. - // - // XXX Is this necessary with the changes in bug 1164741? This is - // likely removable now. - handler.maybeDespecializeSet(target); - } else { - handler.adjustGetToSet(target); - } + handler.adjustGetToSet(target); handler.markAsAssigned(target); return true; } MOZ_ASSERT(handler.isFunctionCall(target)); - - if (flavor == KeyedDestructuringAssignment) { - report(ParseError, false, target, JSMSG_BAD_DESTRUCT_TARGET); - return false; - } - return makeSetCall(target, JSMSG_BAD_LEFTSIDE_OF_ASS); } @@ -6593,11 +6628,14 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl template bool -Parser::isValidSimpleAssignmentTarget(Node node) +Parser::isValidSimpleAssignmentTarget(Node node, + FunctionCallBehavior behavior /* = ForbidAssignmentToFunctionCalls */) { - if (PropertyName* name = handler.maybeName(node)) { - // Note that we implement *exactly* the ES6 semantics here. Warning - // for arguments/eval when extraWarnings is set isn't handled here. + // Note that this method implements *only* a boolean test. Reporting an + // error for the various syntaxes that fail this, and warning for the + // various syntaxes that "pass" this but should not, occurs elsewhere. + + if (PropertyName* name = handler.maybeNameAnyParentheses(node)) { if (!pc->sc->strict()) return true; @@ -6606,16 +6644,21 @@ Parser::isValidSimpleAssignmentTarget(Node node) if (handler.isPropertyAccess(node)) return true; - return handler.isFunctionCall(node); + + if (behavior == PermitAssignmentToFunctionCalls) { + if (handler.isFunctionCall(node)) + return true; + } + + return false; } template bool -Parser::reportIfArgumentsEvalTarget(Node target) +Parser::reportIfArgumentsEvalTarget(Node nameNode) { - PropertyName* name = handler.maybeName(target); - if (!name) - return true; + PropertyName* name = handler.maybeNameAnyParentheses(nameNode); + MOZ_ASSERT(name, "must only call this function on known names"); const char* chars = (name == context->names().arguments) ? js_arguments_str @@ -6625,7 +6668,7 @@ Parser::reportIfArgumentsEvalTarget(Node target) if (!chars) return true; - if (!report(ParseStrictError, pc->sc->strict(), target, JSMSG_BAD_STRICT_ASSIGN, chars)) + if (!report(ParseStrictError, pc->sc->strict(), nameNode, JSMSG_BAD_STRICT_ASSIGN, chars)) return false; MOZ_ASSERT(!pc->sc->strict(), "in strict mode an error should have been reported"); @@ -6634,15 +6677,21 @@ Parser::reportIfArgumentsEvalTarget(Node target) template bool -Parser::reportIfNotValidSimpleAssignmentTarget(Node target, - AssignmentFlavor flavor) +Parser::reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor) { - if (isValidSimpleAssignmentTarget(target)) + FunctionCallBehavior behavior = flavor == KeyedDestructuringAssignment + ? ForbidAssignmentToFunctionCalls + : PermitAssignmentToFunctionCalls; + if (isValidSimpleAssignmentTarget(target, behavior)) return true; - // Use a special error if the target is arguments/eval, as a nicety. - if (!reportIfArgumentsEvalTarget(target)) - return false; + if (handler.maybeNameAnyParentheses(target)) { + // Use a special error if the target is arguments/eval. This ensures + // targeting these names is consistently a SyntaxError (which error numbers + // below don't guarantee) while giving us a nicer error message. + if (!reportIfArgumentsEvalTarget(target)) + return false; + } unsigned errnum; const char* extra = nullptr; @@ -6676,17 +6725,19 @@ template bool Parser::checkAndMarkAsIncOperand(Node target, AssignmentFlavor flavor) { + MOZ_ASSERT(flavor == IncrementAssignment || flavor == DecrementAssignment); + // Check. if (!reportIfNotValidSimpleAssignmentTarget(target, flavor)) return false; - // Assignment to arguments/eval is allowed outside strict mode code, - // but it's dodgy. Report a strict warning (error, if werror was set). - if (!reportIfArgumentsEvalTarget(target)) - return false; - // Mark. - if (handler.maybeName(target)) { + if (handler.maybeNameAnyParentheses(target)) { + // Assignment to arguments/eval is allowed outside strict mode code, + // but it's dodgy. Report a strict warning (error, if werror was set). + if (!reportIfArgumentsEvalTarget(target)) + return false; + handler.markAsAssigned(target); } else if (handler.isFunctionCall(target)) { if (!makeSetCall(target, JSMSG_BAD_INCOP_OPERAND)) @@ -6772,7 +6823,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, InvokedPrediction i // Per spec, deleting any unary expression is valid -- it simply // returns true -- except for one case that is illegal in strict mode. - if (handler.maybeName(expr)) { + if (handler.maybeNameAnyParentheses(expr)) { if (!report(ParseStrictError, pc->sc->strict(), expr, JSMSG_DEPRECATED_DELETE_OPERAND)) return null(); pc->sc->setBindingsAccessedDynamically(); @@ -7257,7 +7308,7 @@ Parser::legacyComprehensionTail(ParseNode* bodyExpr, unsigned switch (tt) { case TOK_LB: case TOK_LC: - if (!checkDestructuring(&data, pn3)) + if (!checkDestructuringPattern(&data, pn3)) return null(); break; @@ -8013,7 +8064,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool return null(); JSOp op = JSOP_CALL; - if (PropertyName* name = handler.maybeName(lhs)) { + if (PropertyName* name = handler.maybeNameAnyParentheses(lhs)) { if (tt == TOK_LP && name == context->names().eval) { /* Select JSOP_EVAL and flag pc as heavyweight. */ op = pc->sc->strict() ? JSOP_STRICTEVAL : JSOP_EVAL; @@ -8318,7 +8369,7 @@ Parser::computedPropertyName(YieldHandling yieldHandling, Node lit // Turn off the inDeclDestructuring flag when parsing computed property // names. In short, when parsing 'let {[x + y]: z} = obj;', noteNameUse() // should be called on x and y, but not on z. See the comment on - // Parser<>::checkDestructuring() for details. + // Parser<>::checkDestructuringPattern() for details. bool saved = pc->inDeclDestructuring; pc->inDeclDestructuring = false; Node assignNode = assignExpr(InAllowed, yieldHandling); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index dd3ed238e97..12236772bb4 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -683,11 +683,15 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter ParseNodeKind headKind); bool checkForHeadConstInitializers(Node pn1); - bool isValidSimpleAssignmentTarget(Node node); + enum FunctionCallBehavior { + PermitAssignmentToFunctionCalls, + ForbidAssignmentToFunctionCalls + }; - // Invalid assignment targets are handled differently in different places. - // Select the desired semantics using |flavor|. - bool reportIfArgumentsEvalTarget(Node target); + bool isValidSimpleAssignmentTarget(Node node, + FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls); + + bool reportIfArgumentsEvalTarget(Node nameNode); bool reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor); bool checkAndMarkAsIncOperand(Node kid, AssignmentFlavor flavor); @@ -712,9 +716,18 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter Node makeInitializedLexicalBinding(HandlePropertyName name, bool isConst, const TokenPos& pos); Node newBindingNode(PropertyName* name, bool functionScope, VarContext varContext = HoistVars); - bool checkDestructuring(BindData* data, Node left); - bool checkDestructuringObject(BindData* data, Node objectPattern); + + // Top-level entrypoint into destructuring pattern checking/name-analyzing. + bool checkDestructuringPattern(BindData* data, Node pattern); + + // Recursive methods for checking/name-analyzing subcomponents of a + // destructuring pattern. The array/object methods *must* be passed arrays + // or objects. The name method may be passed anything but will report an + // error if not passed a name. bool checkDestructuringArray(BindData* data, Node arrayPattern); + bool checkDestructuringObject(BindData* data, Node objectPattern); + bool checkDestructuringName(BindData* data, Node expr); + bool bindInitialized(BindData* data, Node pn); bool makeSetCall(Node node, unsigned errnum); Node cloneDestructuringDefault(Node opn); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 2c8fdbcd3e6..2ce8876668f 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -46,6 +46,9 @@ class SyntaxParseHandler NodeBreak, NodeThrow, + NodeSuperProperty, + NodeSuperElement, + // This is needed for proper assignment-target handling. ES6 formally // requires function calls *not* pass IsValidSimpleAssignmentTarget, // but at last check there were still sites with |f() = 5| and similar @@ -53,25 +56,48 @@ class SyntaxParseHandler // noticed). NodeFunctionCall, - // Nodes representing names. These *must* be sequential per |isName|. - NodeArgumentsName, - NodeEvalName, - NodeName, + // Nodes representing *parenthesized* IsValidSimpleAssignmentTarget + // nodes. We can't simply treat all such parenthesized nodes + // identically, because in assignment and increment/decrement contexts + // ES6 says that parentheses constitute a syntax error. + // + // var obj = {}; + // var val; + // (val) = 3; (obj.prop) = 4; // okay per ES5's little mind + // [(a)] = [3]; [(obj.prop)] = [4]; // invalid ES6 syntax + // // ...and so on for the other IsValidSimpleAssignmentTarget nodes + // + // We don't know in advance in the current parser when we're parsing + // in a place where name parenthesization changes meaning, so we must + // have multiple node values for these cases. + NodeParenthesizedArgumentsName, + NodeParenthesizedEvalName, + NodeParenthesizedName, NodeDottedProperty, NodeElement, - NodeSuperProperty, - NodeSuperElement, - // Valuable for recognizing potential destructuring patterns. - NodeArray, - NodeObject, + // Destructuring target patterns can't be parenthesized: |([a]) = [3];| + // must be a syntax error. (We can't use NodeGeneric instead of these + // because that would trigger invalid-left-hand-side ReferenceError + // semantics when SyntaxError semantics are desired.) + NodeParenthesizedArray, + NodeParenthesizedObject, // In rare cases a parenthesized |node| doesn't have the same semantics // as |node|. Each such node has a special Node value, and we use a // different Node value to represent the parenthesized form. See also - // isUnparenthesized*(Node), newExprStatement(Node, uint32_t), - // parenthesize(Node), and meaningMightChangeIfParenthesized(Node). + // is{Unp,P}arenthesized*(Node), parenthesize(Node), and the various + // functions that deal in NodeUnparenthesized* below. + + // Nodes representing unparenthesized names. + NodeUnparenthesizedArgumentsName, + NodeUnparenthesizedEvalName, + NodeUnparenthesizedName, + + // Valuable for recognizing potential destructuring patterns. + NodeUnparenthesizedArray, + NodeUnparenthesizedObject, // The directive prologue at the start of a FunctionBody or ScriptBody // is the longest sequence (possibly empty) of string literal @@ -119,18 +145,22 @@ class SyntaxParseHandler return node == NodeFunctionCall; } - bool isDestructuringTarget(Node node) { - return node == NodeArray || node == NodeObject; + static bool isUnparenthesizedDestructuringPattern(Node node) { + return node == NodeUnparenthesizedArray || node == NodeUnparenthesizedObject; } - private: - static bool meaningMightChangeIfParenthesized(Node node) { - return node == NodeUnparenthesizedString || - node == NodeUnparenthesizedCommaExpr || - node == NodeUnparenthesizedYieldExpr || - node == NodeUnparenthesizedAssignment; + static bool isParenthesizedDestructuringPattern(Node node) { + // Technically this isn't a destructuring target at all -- the grammar + // doesn't treat it as such. But we need to know when this happens to + // consider it a SyntaxError rather than an invalid-left-hand-side + // ReferenceError. + return node == NodeParenthesizedArray || node == NodeParenthesizedObject; } + static bool isDestructuringPatternAnyParentheses(Node node) { + return isUnparenthesizedDestructuringPattern(node) || + isParenthesizedDestructuringPattern(node); + } public: SyntaxParseHandler(ExclusiveContext* cx, LifoAlloc& alloc, @@ -147,14 +177,14 @@ class SyntaxParseHandler Node newName(PropertyName* name, uint32_t blockid, const TokenPos& pos, ExclusiveContext* cx) { lastAtom = name; if (name == cx->names().arguments) - return NodeArgumentsName; + return NodeUnparenthesizedArgumentsName; if (name == cx->names().eval) - return NodeEvalName; - return NodeName; + return NodeUnparenthesizedEvalName; + return NodeUnparenthesizedName; } Node newComputedName(Node expr, uint32_t start, uint32_t end) { - return NodeName; + return NodeGeneric; } DefinitionNode newPlaceholder(JSAtom* atom, uint32_t blockid, const TokenPos& pos) { @@ -162,7 +192,7 @@ class SyntaxParseHandler } Node newObjectLiteralPropertyName(JSAtom* atom, const TokenPos& pos) { - return NodeName; + return NodeUnparenthesizedName; } Node newNumber(double value, DecimalPoint decimalPoint, const TokenPos& pos) { return NodeGeneric; } @@ -231,7 +261,7 @@ class SyntaxParseHandler Node newArrayComprehension(Node body, unsigned blockid, const TokenPos& pos) { return NodeGeneric; } - Node newArrayLiteral(uint32_t begin, unsigned blockid) { return NodeArray; } + Node newArrayLiteral(uint32_t begin, unsigned blockid) { return NodeUnparenthesizedArray; } bool addElision(Node literal, const TokenPos& pos) { return true; } bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; } void addArrayElement(Node literal, Node element) { } @@ -239,7 +269,7 @@ class SyntaxParseHandler Node newCall() { return NodeFunctionCall; } Node newTaggedTemplate() { return NodeGeneric; } - Node newObjectLiteral(uint32_t begin) { return NodeObject; } + Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; } Node newClassMethodList(uint32_t begin) { return NodeGeneric; } Node newSuperProperty(PropertyName* prop, const TokenPos& pos) { @@ -368,8 +398,8 @@ class SyntaxParseHandler void addList(Node list, Node kid) { MOZ_ASSERT(list == NodeGeneric || - list == NodeArray || - list == NodeObject || + list == NodeUnparenthesizedArray || + list == NodeUnparenthesizedObject || list == NodeUnparenthesizedCommaExpr || list == NodeHoistableDeclaration || list == NodeFunctionCall); @@ -408,8 +438,30 @@ class SyntaxParseHandler void setFlag(Node pn, unsigned flag) {} void setListFlag(Node pn, unsigned flag) {} MOZ_WARN_UNUSED_RESULT Node parenthesize(Node node) { - if (meaningMightChangeIfParenthesized(node)) + // A number of nodes have different behavior upon parenthesization, but + // only in some circumstances. Convert these nodes to special + // parenthesized forms. + if (node == NodeUnparenthesizedArgumentsName) + return NodeParenthesizedArgumentsName; + if (node == NodeUnparenthesizedEvalName) + return NodeParenthesizedEvalName; + if (node == NodeUnparenthesizedName) + return NodeParenthesizedName; + + if (node == NodeUnparenthesizedArray) + return NodeParenthesizedArray; + if (node == NodeUnparenthesizedObject) + return NodeParenthesizedObject; + + // Other nodes need not be recognizable after parenthesization; convert + // them to a generic node. + if (node == NodeUnparenthesizedString || + node == NodeUnparenthesizedCommaExpr || + node == NodeUnparenthesizedYieldExpr || + node == NodeUnparenthesizedAssignment) + { return NodeGeneric; + } // In all other cases, the parenthesized form of |node| is equivalent // to the unparenthesized form: return |node| unchanged. @@ -421,12 +473,33 @@ class SyntaxParseHandler void setPrologue(Node pn) {} bool isConstant(Node pn) { return false; } - PropertyName* maybeName(Node pn) { - if (pn == NodeName || pn == NodeArgumentsName || pn == NodeEvalName) + + PropertyName* maybeUnparenthesizedName(Node node) { + if (node == NodeUnparenthesizedName || + node == NodeUnparenthesizedArgumentsName || + node == NodeUnparenthesizedEvalName) + { return lastAtom->asPropertyName(); + } return nullptr; } + PropertyName* maybeParenthesizedName(Node node) { + if (node == NodeParenthesizedName || + node == NodeParenthesizedArgumentsName || + node == NodeParenthesizedEvalName) + { + return lastAtom->asPropertyName(); + } + return nullptr; + } + + PropertyName* maybeNameAnyParentheses(Node node) { + if (PropertyName* name = maybeUnparenthesizedName(node)) + return name; + return maybeParenthesizedName(node); + } + PropertyName* maybeDottedProperty(Node node) { // Note: |super.apply(...)| is a special form that calls an "apply" // method retrieved from one value, but using a *different* value as diff --git a/js/src/jit-test/tests/basic/destructuring-rest.js b/js/src/jit-test/tests/basic/destructuring-rest.js index 82a22ffff22..6c08161299f 100644 --- a/js/src/jit-test/tests/basic/destructuring-rest.js +++ b/js/src/jit-test/tests/basic/destructuring-rest.js @@ -13,16 +13,15 @@ assertThrowsInstanceOf(() => new Function('[...a++] = []'), SyntaxError, 'postfi assertThrowsInstanceOf(() => new Function('[...!a] = []'), SyntaxError, 'unary expression'); assertThrowsInstanceOf(() => new Function('[...a+b] = []'), SyntaxError, 'binary expression'); assertThrowsInstanceOf(() => new Function('var [...a.x] = []'), SyntaxError, 'lvalue expression in declaration'); +assertThrowsInstanceOf(() => new Function('var [...(b)] = []'), SyntaxError); -// XXX: The way the current parser works, certain things, like a trailing comma -// and parenthesis, are lost before we check for destructuring. -// See bug 1041341. Once fixed, please update these assertions +// XXX: The way the current parser works, a trailing comma is lost before we +// check for destructuring. See bug 1041341. Once fixed, please update +// this assertion. assertThrowsInstanceOf(() => assertThrowsInstanceOf(() => new Function('[...b,] = []'), SyntaxError) , Error); -assertThrowsInstanceOf(() => - assertThrowsInstanceOf(() => new Function('var [...(b)] = []'), SyntaxError) - , Error); + var inputArray = [1, 2, 3]; var inputDeep = [1, inputArray]; diff --git a/js/src/jit-test/tests/basic/spread-call-setcall.js b/js/src/jit-test/tests/basic/spread-call-setcall.js index 8afb686c74e..5a1100b8e94 100644 --- a/js/src/jit-test/tests/basic/spread-call-setcall.js +++ b/js/src/jit-test/tests/basic/spread-call-setcall.js @@ -24,6 +24,6 @@ check("eval(...['1']) ++"); checkDestructuring("[g(...[])] = []"); checkDestructuring("[a.g(...[])] = []"); checkDestructuring("[eval(...['1'])] = []"); -checkDestructuring("({y: g(...[])}) = 1"); -checkDestructuring("({y: a.g(...[])}) = 1"); -checkDestructuring("({y: eval(...['1'])}) = 1"); +checkDestructuring("({y: g(...[])} = 1)"); +checkDestructuring("({y: a.g(...[])} = 1)"); +checkDestructuring("({y: eval(...['1'])} = 1)"); diff --git a/js/src/js.msg b/js/src/js.msg index f2a4ec51a06..669562e230f 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -194,6 +194,7 @@ MSG_DEF(JSMSG_BAD_CONST_ASSIGN, 1, JSEXN_SYNTAXERR, "invalid assignment t MSG_DEF(JSMSG_BAD_CONTINUE, 0, JSEXN_SYNTAXERR, "continue must be inside loop") MSG_DEF(JSMSG_BAD_DESTRUCT_ASS, 0, JSEXN_REFERENCEERR, "invalid destructuring assignment operator") MSG_DEF(JSMSG_BAD_DESTRUCT_TARGET, 0, JSEXN_SYNTAXERR, "invalid destructuring target") +MSG_DEF(JSMSG_BAD_DESTRUCT_PARENS, 0, JSEXN_SYNTAXERR, "destructuring patterns in assignments can't be parenthesized") MSG_DEF(JSMSG_BAD_DESTRUCT_DECL, 0, JSEXN_SYNTAXERR, "missing = in destructuring declaration") MSG_DEF(JSMSG_BAD_DUP_ARGS, 0, JSEXN_SYNTAXERR, "duplicate argument names not allowed in this context") MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loop") diff --git a/js/src/tests/ecma_6/Expressions/destructuring-pattern-parenthesized.js b/js/src/tests/ecma_6/Expressions/destructuring-pattern-parenthesized.js new file mode 100644 index 00000000000..4543fde27d1 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/destructuring-pattern-parenthesized.js @@ -0,0 +1,105 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1146136; +var summary = + 'Parenthesized "destructuring patterns" are not usable as destructuring ' + + 'patterns'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +// Don't pollute the top-level script with eval references. +var savedEval = this[String.fromCharCode(101, 118, 97, 108)]; + +function checkError(code, nonstrictErr, strictErr) +{ + function helper(exec, prefix, err) + { + var fullCode = prefix + code; + try + { + var f = exec(fullCode); + + var error = + "no early error, parsed code <" + fullCode + "> using " + exec.name; + if (typeof f === "function") + { + try + { + f(); + error += ", and the function can be called without error"; + } + catch (e) + { + error +=", and calling the function throws " + e; + } + } + + throw new Error(error); + } + catch (e) + { + assertEq(e instanceof err, true, + "expected " + err.name + ", got " + e + " " + + "for code <" + fullCode + "> when parsed using " + exec.name); + } + } + + helper(Function, "", nonstrictErr); + helper(Function, "'use strict'; ", strictErr); + helper(savedEval, "", nonstrictErr); + helper(savedEval, "'use strict'; ", strictErr); +} + +// Parenthesized destructuring patterns don't trigger grammar refinement, so we +// get the currently-usual ReferenceError for an invalid assignment target, per +// 12.14.1 second bullet. +checkError("var a, b; ([a, b]) = [1, 2];", ReferenceError, ReferenceError); +checkError("var a, b; ({a, b}) = { a: 1, b: 2 };", ReferenceError, ReferenceError); + +// *Nested* parenthesized destructuring patterns, on the other hand, do trigger +// grammar refinement. But subtargets in a destructuring pattern must be +// either object/array literals that match the destructuring pattern refinement +// *or* valid simple assignment targets. Parenthesized object/array patterns +// are neither. And so 12.14.5.1 third bullet requires an early SyntaxError. +checkError("var a, b; ({ a: ({ b: b }) } = { a: { b: 42 } });", SyntaxError, SyntaxError); +checkError("var a, b; ({ a: ([b]) } = { a: [42] });", SyntaxError, SyntaxError); + +Function("var a, b; [(a), b] = [1, 2];")(); +Function("var a, b; [(a) = 5, b] = [1, 2];")(); +Function("var a, b; [(arguments), b] = [1, 2];")(); +Function("var a, b; [(arguments) = 5, b] = [1, 2];")(); +Function("var a, b; [(eval), b] = [1, 2];")(); +Function("var a, b; [(eval) = 5, b] = [1, 2];")(); + +var repair = {}, demolition = {}; + +Function("var a, b; [(repair.man), b] = [1, 2];")(); +Function("var a, b; [(demolition['man']) = 'motel', b] = [1, 2];")(); +Function("var a, b; [(demolition['man' + {}]) = 'motel', b] = [1, 2];")(); // evade constant-folding +Function("var a, b; var obj = { x() { [(super.man), b] = [1, 2]; } };")(); +Function("var a, b; var obj = { x() { [(super[8]) = 'motel', b] = [1, 2]; } };")(); +Function("var a, b; var obj = { x() { [(super[8 + {}]) = 'motel', b] = [1, 2]; } };")(); // evade constant-folding + +// In strict mode, assignment to funcall *immediately* triggers ReferenceError +// before we can recognize this doesn't even match the destructuring grammar to +// begin with. Bleh. :-( Probably they should all be made SyntaxError in the +// specs; see . +checkError("var a, b; [f() = 'ohai', b] = [1, 2];", SyntaxError, ReferenceError); +checkError("var a, b; [(f()) = 'kthxbai', b] = [1, 2];", SyntaxError, ReferenceError); + +Function("var a, b; ({ a: (a), b} = { a: 1, b: 2 });")(); +Function("var a, b; ({ a: (a) = 5, b} = { a: 1, b: 2 });")(); + + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 0028d42d082..61317de7168 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -29,11 +29,11 @@ namespace js { * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 294; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 295; static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND); -static_assert(JSErr_Limit == 403, +static_assert(JSErr_Limit == 404, "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or " "removed MSG_DEFs from js.msg, you should increment " "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's " From 36b20fdd64bbd66c4e20eef7518828cf069b43a2 Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Wed, 17 Jun 2015 19:11:25 -0400 Subject: [PATCH 009/111] Bug 1175585 - Generalize scrollWheelOver() so it's usable by other APZ tests. r=kats --- .../apz/test/apz_test_native_event_utils.js | 20 ++++++++++++++ gfx/layers/apz/test/test_layerization.html | 26 +++++-------------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/gfx/layers/apz/test/apz_test_native_event_utils.js b/gfx/layers/apz/test/apz_test_native_event_utils.js index 531c258baba..5b0ca7135a7 100644 --- a/gfx/layers/apz/test/apz_test_native_event_utils.js +++ b/gfx/layers/apz/test/apz_test_native_event_utils.js @@ -124,3 +124,23 @@ function synthesizeNativeMouseMoveAndWaitForMoveEvent(aElement, aX, aY, aCallbac }); return synthesizeNativeMouseMove(aElement, aX, aY); } + +// Scroll the mouse wheel (in the vertical direction) by |aWheelDelta| over |aElement|, +// calling |aCallback| when the first resulting scroll event is received. +function scrollWheelOver(aElement, aWheelDelta, aCallback) { + var scale = window.devicePixelRatio; + var rect = aElement.getBoundingClientRect(); + var x = (rect.left + 10) * scale; + var y = (rect.top + 10) * scale; + // Move the mouse to the desired wheel location. + // Not doing so can result in the wheel events from two consecutive + // scrollWheelOver() calls on different elements being incorrectly considered + // as part of the same wheel transaction. + // We also wait for the mouse move event to be processed before sending the + // wheel event, otherwise there is a chance they might get reordered, and + // we have the transaction problem again. + synthesizeNativeMouseMoveAndWaitForMoveEvent(aElement, x, y, function() { + synthesizeNativeWheelAndWaitForScrollEvent(aElement, x, y, 0, aWheelDelta, aCallback); + }); +} + diff --git a/gfx/layers/apz/test/test_layerization.html b/gfx/layers/apz/test/test_layerization.html index 63d455d0e2c..3750cadd296 100644 --- a/gfx/layers/apz/test/test_layerization.html +++ b/gfx/layers/apz/test/test_layerization.html @@ -50,22 +50,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1173580
 
+  
+  
+  
+  
+
+
+APZ wheel transactions test
+

+
+
+
+
+
+
+
+
+ + + From d606390997ecf38393c67857194d4759ba1e93ba Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Thu, 18 Jun 2015 13:10:46 -0700 Subject: [PATCH 011/111] Bug 1175975 - Null crash fix in ProcessHangMonitor (r=jimm) --- dom/ipc/ProcessHangMonitor.cpp | 28 +++++++++++++++++++++----- dom/plugins/ipc/PluginHangUIParent.cpp | 3 +-- dom/plugins/ipc/PluginModuleParent.cpp | 14 ++++++------- dom/plugins/ipc/PluginModuleParent.h | 2 +- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/dom/ipc/ProcessHangMonitor.cpp b/dom/ipc/ProcessHangMonitor.cpp index be90848b17b..74c2e450e8d 100644 --- a/dom/ipc/ProcessHangMonitor.cpp +++ b/dom/ipc/ProcessHangMonitor.cpp @@ -156,7 +156,7 @@ public: NS_IMETHOD IsReportForBrowser(nsIFrameLoader* aFrameLoader, bool* aResult) override; - // Called on xpcom shutdown + // Called when a content process shuts down. void Clear() { mContentParent = nullptr; mActor = nullptr; @@ -456,11 +456,25 @@ HangMonitorParent::HangMonitorParent(ProcessHangMonitor* aMonitor) mReportHangs = mozilla::Preferences::GetBool("dom.ipc.reportProcessHangs", false); } +static PLDHashOperator +DeleteMinidump(const uint32_t& aPluginId, nsString aCrashId, void* aUserData) +{ +#ifdef MOZ_CRASHREPORTER + if (!aCrashId.IsEmpty()) { + CrashReporter::DeleteMinidumpFilesForID(aCrashId); + } +#endif + return PL_DHASH_NEXT; +} + HangMonitorParent::~HangMonitorParent() { // For some reason IPDL doesn't autmatically delete the channel for a // bridged protocol (bug 1090570). So we have to do it ourselves. XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask(GetTransport())); + + MutexAutoLock lock(mBrowserCrashDumpHashLock); + mBrowserCrashDumpIds.EnumerateRead(DeleteMinidump, nullptr); } void @@ -805,7 +819,9 @@ HangMonitoredProcess::TerminatePlugin() uint32_t id = mHangData.get_PluginHangData().pluginId(); plugins::TerminatePlugin(id, mBrowserDumpId); - mActor->CleanupPluginHang(id, false); + if (mActor) { + mActor->CleanupPluginHang(id, false); + } return NS_OK; } @@ -818,7 +834,7 @@ HangMonitoredProcess::TerminateProcess() return NS_ERROR_UNEXPECTED; } - if (mHangData.type() == HangData::TPluginHangData) { + if (mActor && mHangData.type() == HangData::TPluginHangData) { uint32_t id = mHangData.get_PluginHangData().pluginId(); mActor->CleanupPluginHang(id, true); } @@ -855,8 +871,10 @@ HangMonitoredProcess::UserCanceled() return NS_OK; } - uint32_t id = mHangData.get_PluginHangData().pluginId(); - mActor->CleanupPluginHang(id, true); + if (mActor) { + uint32_t id = mHangData.get_PluginHangData().pluginId(); + mActor->CleanupPluginHang(id, true); + } return NS_OK; } diff --git a/dom/plugins/ipc/PluginHangUIParent.cpp b/dom/plugins/ipc/PluginHangUIParent.cpp index ae922d05484..e2e0eb2f16b 100644 --- a/dom/plugins/ipc/PluginHangUIParent.cpp +++ b/dom/plugins/ipc/PluginHangUIParent.cpp @@ -353,8 +353,7 @@ PluginHangUIParent::RecvUserResponse(const unsigned int& aResponse) int responseCode; if (aResponse & HANGUI_USER_RESPONSE_STOP) { // User clicked Stop - nsString dummy; - mModule->TerminateChildProcess(mMainThreadMessageLoop, &dummy); + mModule->TerminateChildProcess(mMainThreadMessageLoop, EmptyString()); responseCode = 1; } else if(aResponse & HANGUI_USER_RESPONSE_CONTINUE) { mModule->OnHangUIContinue(); diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 0c1547e0e74..9dc6f29d731 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -359,10 +359,9 @@ mozilla::plugins::TerminatePlugin(uint32_t aPluginId, const nsString& aBrowserDu if (!pluginTag || !pluginTag->mPlugin) { return; } - nsAutoString dumpId(aBrowserDumpId); nsRefPtr plugin = pluginTag->mPlugin; PluginModuleChromeParent* chromeParent = static_cast(plugin->GetLibrary()); - chromeParent->TerminateChildProcess(MessageLoop::current(), &dumpId); + chromeParent->TerminateChildProcess(MessageLoop::current(), aBrowserDumpId); } /* static */ PluginLibrary* @@ -1154,8 +1153,7 @@ PluginModuleChromeParent::ShouldContinueFromReplyTimeout() // original plugin hang behaviour and kill the plugin container. FinishHangUI(); #endif // XP_WIN - nsString dummy; - TerminateChildProcess(MessageLoop::current(), &dummy); + TerminateChildProcess(MessageLoop::current(), EmptyString()); GetIPCChannel()->CloseWithTimeout(); return false; } @@ -1179,7 +1177,7 @@ PluginModuleContentParent::OnExitedSyncSend() void PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop, - nsAString* aBrowserDumpId) + const nsAString& aBrowserDumpId) { #ifdef MOZ_CRASHREPORTER #ifdef XP_WIN @@ -1215,8 +1213,8 @@ PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop, // since the posted message will trash our browser stack state. bool exists; nsCOMPtr browserDumpFile; - if (aBrowserDumpId && !aBrowserDumpId->IsEmpty() && - CrashReporter::GetMinidumpForID(*aBrowserDumpId, getter_AddRefs(browserDumpFile)) && + if (!aBrowserDumpId.IsEmpty() && + CrashReporter::GetMinidumpForID(aBrowserDumpId, getter_AddRefs(browserDumpFile)) && browserDumpFile && NS_SUCCEEDED(browserDumpFile->Exists(&exists)) && exists) { @@ -1226,7 +1224,7 @@ PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop, NS_LITERAL_CSTRING("browser")); if (!reportsReady) { browserDumpFile = nullptr; - CrashReporter::DeleteMinidumpFilesForID(*aBrowserDumpId); + CrashReporter::DeleteMinidumpFilesForID(aBrowserDumpId); } } diff --git a/dom/plugins/ipc/PluginModuleParent.h b/dom/plugins/ipc/PluginModuleParent.h index 32ea0b64781..1ea44032641 100644 --- a/dom/plugins/ipc/PluginModuleParent.h +++ b/dom/plugins/ipc/PluginModuleParent.h @@ -387,7 +387,7 @@ class PluginModuleChromeParent * generating a multi-process crash report. If not provided a browser * dump will be taken at the time of this call. */ - void TerminateChildProcess(MessageLoop* aMsgLoop, nsAString* aBrowserDumpId); + void TerminateChildProcess(MessageLoop* aMsgLoop, const nsAString& aBrowserDumpId); #ifdef XP_WIN /** From 11b5bafe6f70584bdd94acb01ed66393fc373cb9 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 17 Jun 2015 15:08:12 -0700 Subject: [PATCH 012/111] Bug 1164543 - Add HasLocalInstance support (r=jimm) --- dom/plugins/base/PluginPRLibrary.h | 1 + dom/plugins/base/nsPluginHost.cpp | 2 ++ dom/plugins/base/nsPluginTags.cpp | 1 + dom/plugins/base/nsPluginTags.h | 4 ++++ dom/plugins/ipc/PluginLibrary.h | 1 + dom/plugins/ipc/PluginModuleParent.cpp | 1 + dom/plugins/ipc/PluginModuleParent.h | 4 ++++ 7 files changed, 14 insertions(+) diff --git a/dom/plugins/base/PluginPRLibrary.h b/dom/plugins/base/PluginPRLibrary.h index d824ece0ab7..c92ef831062 100644 --- a/dom/plugins/base/PluginPRLibrary.h +++ b/dom/plugins/base/PluginPRLibrary.h @@ -123,6 +123,7 @@ public: gfxContext* aCtx, const nsIntRect&) override; virtual void GetLibraryPath(nsACString& aPath) { aPath.Assign(mFilePath); } virtual nsresult GetRunID(uint32_t* aRunID) override { return NS_ERROR_NOT_IMPLEMENTED; } + virtual void SetHasLocalInstance() override { } private: NP_InitializeFunc mNP_Initialize; diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 92f024779f0..f08eaee8542 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -955,6 +955,8 @@ nsPluginHost::TrySetUpPluginInstance(const nsACString &aMimeType, NS_ASSERTION(pluginTag, "Must have plugin tag here!"); + plugin->GetLibrary()->SetHasLocalInstance(); + #if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_CRASHREPORTER) if (pluginTag->mIsFlashPlugin) { CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FlashVersion"), pluginTag->mVersion); diff --git a/dom/plugins/base/nsPluginTags.cpp b/dom/plugins/base/nsPluginTags.cpp index c161579d9b7..11c42c40201 100644 --- a/dom/plugins/base/nsPluginTags.cpp +++ b/dom/plugins/base/nsPluginTags.cpp @@ -148,6 +148,7 @@ nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo, bool fromExtension) : mId(sNextId++), mContentProcessRunningCount(0), + mHadLocalInstance(false), mName(aPluginInfo->fName), mDescription(aPluginInfo->fDescription), mLibrary(nullptr), diff --git a/dom/plugins/base/nsPluginTags.h b/dom/plugins/base/nsPluginTags.h index 86015c7e37b..35e8bc7ae98 100644 --- a/dom/plugins/base/nsPluginTags.h +++ b/dom/plugins/base/nsPluginTags.h @@ -90,6 +90,10 @@ public: // Number of PluginModuleParents living in all content processes. size_t mContentProcessRunningCount; + + // True if we've ever created an instance of this plugin in the current process. + bool mHadLocalInstance; + nsCString mName; // UTF-8 nsCString mDescription; // UTF-8 nsTArray mMimeTypes; // UTF-8 diff --git a/dom/plugins/ipc/PluginLibrary.h b/dom/plugins/ipc/PluginLibrary.h index efec7ce84ca..8422edccb70 100644 --- a/dom/plugins/ipc/PluginLibrary.h +++ b/dom/plugins/ipc/PluginLibrary.h @@ -85,6 +85,7 @@ public: virtual nsresult EndUpdateBackground(NPP instance, gfxContext*, const nsIntRect&) = 0; virtual nsresult GetRunID(uint32_t* aRunID) = 0; + virtual void SetHasLocalInstance() = 0; }; diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 9dc6f29d731..637c60b600c 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -621,6 +621,7 @@ PluginModuleChromeParent::WaitForIPCConnection() PluginModuleParent::PluginModuleParent(bool aIsChrome) : mIsChrome(aIsChrome) , mShutdown(false) + , mHadLocalInstance(false) , mClearSiteDataSupported(false) , mGetSitesWithDataSupported(false) , mNPNIface(nullptr) diff --git a/dom/plugins/ipc/PluginModuleParent.h b/dom/plugins/ipc/PluginModuleParent.h index 1ea44032641..a21fad2e65b 100644 --- a/dom/plugins/ipc/PluginModuleParent.h +++ b/dom/plugins/ipc/PluginModuleParent.h @@ -133,6 +133,9 @@ public: } virtual nsresult GetRunID(uint32_t* aRunID) override; + virtual void SetHasLocalInstance() override { + mHadLocalInstance = true; + } protected: virtual mozilla::ipc::RacyInterruptPolicy @@ -284,6 +287,7 @@ protected: bool mIsChrome; bool mShutdown; + bool mHadLocalInstance; bool mClearSiteDataSupported; bool mGetSitesWithDataSupported; NPNetscapeFuncs* mNPNIface; From a73d9c1d4257a93cdb477ac9578f32e001c086be Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 17 Jun 2015 15:28:39 -0700 Subject: [PATCH 013/111] Bug 1164543 - Remove gAllInstances from PluginModuleChild (r=jimm) --- dom/plugins/ipc/PluginModuleChild.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index b90600e0d04..4e737b3fb15 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -67,7 +67,6 @@ const wchar_t * kMozillaWindowClass = L"MozillaWindowClass"; namespace { // see PluginModuleChild::GetChrome() PluginModuleChild* gChromeInstance = nullptr; -nsTArray* gAllInstances; } #ifdef MOZ_WIDGET_QT @@ -142,11 +141,6 @@ PluginModuleChild::PluginModuleChild(bool aIsChrome) , mGlobalCallWndProcHook(nullptr) #endif { - if (!gAllInstances) { - gAllInstances = new nsTArray(1); - } - gAllInstances->AppendElement(this); - memset(&mFunctions, 0, sizeof(mFunctions)); if (mIsChrome) { MOZ_ASSERT(!gChromeInstance); @@ -170,13 +164,6 @@ PluginModuleChild::~PluginModuleChild() XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask(mTransport)); } - gAllInstances->RemoveElement(this); - MOZ_ASSERT_IF(mIsChrome, gAllInstances->Length() == 0); - if (gAllInstances->IsEmpty()) { - delete gAllInstances; - gAllInstances = nullptr; - } - if (mIsChrome) { MOZ_ASSERT(gChromeInstance == this); From cb25927dae5111a79218b4d4359753c1ab17c2de Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 17 Jun 2015 15:38:07 -0700 Subject: [PATCH 014/111] Bug 1164543 - Make plugin shutdown async in e10s (r=jimm) --- dom/plugins/ipc/PluginModuleChild.cpp | 25 ++++++++++++++++++++++--- dom/plugins/ipc/PluginModuleChild.h | 3 +++ dom/plugins/ipc/PluginModuleParent.cpp | 7 ++++++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index 4e737b3fb15..5375544d008 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -126,6 +126,7 @@ PluginModuleChild::PluginModuleChild(bool aIsChrome) , mPluginFilename("") , mQuirks(QUIRKS_NOT_INITIALIZED) , mIsChrome(aIsChrome) + , mHasShutdown(false) , mTransport(nullptr) , mShutdownFunc(0) , mInitializeFunc(0) @@ -681,12 +682,16 @@ PluginModuleChild::DeinitGraphics() #endif } -bool -PluginModuleChild::AnswerNP_Shutdown(NPError *rv) +NPError +PluginModuleChild::NP_Shutdown() { AssertPluginThread(); MOZ_ASSERT(mIsChrome); + if (mHasShutdown) { + return NPERR_NO_ERROR; + } + #if defined XP_WIN mozilla::widget::StopAudioSession(); #endif @@ -694,7 +699,7 @@ PluginModuleChild::AnswerNP_Shutdown(NPError *rv) // the PluginModuleParent shuts down this process after this interrupt // call pops off its stack - *rv = mShutdownFunc ? mShutdownFunc() : NPERR_NO_ERROR; + NPError rv = mShutdownFunc ? mShutdownFunc() : NPERR_NO_ERROR; // weakly guard against re-entry after NP_Shutdown memset(&mFunctions, 0, sizeof(mFunctions)); @@ -705,6 +710,15 @@ PluginModuleChild::AnswerNP_Shutdown(NPError *rv) GetIPCChannel()->SetAbortOnError(false); + mHasShutdown = true; + + return rv; +} + +bool +PluginModuleChild::AnswerNP_Shutdown(NPError *rv) +{ + *rv = NP_Shutdown(); return true; } @@ -826,6 +840,11 @@ PluginModuleChild::ActorDestroy(ActorDestroyReason why) QuickExit(); } + if (!mHasShutdown) { + MOZ_ASSERT(gChromeInstance == this); + NP_Shutdown(); + } + // doesn't matter why we're being destroyed; it's up to us to // initiate (clean) shutdown XRE_ShutdownChildProcess(); diff --git a/dom/plugins/ipc/PluginModuleChild.h b/dom/plugins/ipc/PluginModuleChild.h index 50dd8347f12..265fcde4bd0 100644 --- a/dom/plugins/ipc/PluginModuleChild.h +++ b/dom/plugins/ipc/PluginModuleChild.h @@ -177,6 +177,8 @@ public: void CleanUp(); + NPError NP_Shutdown(); + const char* GetUserAgent(); static const NPNetscapeFuncs sBrowserFuncs; @@ -327,6 +329,7 @@ private: int mQuirks; bool mIsChrome; + bool mHasShutdown; // true if NP_Shutdown has run Transport* mTransport; // we get this from the plugin diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 637c60b600c..207898b7bd1 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -2386,7 +2386,12 @@ bool PluginModuleParent::DoShutdown(NPError* error) { bool ok = true; - if (IsChrome()) { + if (IsChrome() && mHadLocalInstance) { + // We synchronously call NP_Shutdown if the chrome process was using + // plugins itself. That way we can service any requests the plugin + // makes. If we're in e10s, though, the content processes will have + // already shut down and there's no one to talk to. So we shut down + // asynchronously in PluginModuleChild::ActorDestroy. ok = CallNP_Shutdown(error); } From 0db020fa01f2b3f5111593cc4a3f3362f1167c80 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 3 Jun 2015 12:43:44 -0700 Subject: [PATCH 015/111] Bug 1171248 - Add MatchPattern support to WebRequest module (r=Mossop) --- toolkit/modules/addons/MatchPattern.jsm | 120 ++++++++++++++++++ toolkit/modules/addons/WebRequest.jsm | 3 + toolkit/modules/addons/WebRequestCommon.jsm | 11 +- toolkit/modules/addons/WebRequestContent.js | 5 + toolkit/modules/moz.build | 1 + .../browser/browser_WebRequest_filtering.js | 3 +- .../tests/xpcshell/test_MatchPattern.js | 92 ++++++++++++++ toolkit/modules/tests/xpcshell/xpcshell.ini | 1 + 8 files changed, 227 insertions(+), 9 deletions(-) create mode 100644 toolkit/modules/addons/MatchPattern.jsm create mode 100644 toolkit/modules/tests/xpcshell/test_MatchPattern.js diff --git a/toolkit/modules/addons/MatchPattern.jsm b/toolkit/modules/addons/MatchPattern.jsm new file mode 100644 index 00000000000..91d4bf6b30c --- /dev/null +++ b/toolkit/modules/addons/MatchPattern.jsm @@ -0,0 +1,120 @@ +/* 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/. */ + +"use strict"; + +const Cu = Components.utils; + +const EXPORTED_SYMBOLS = ["MatchPattern"]; + +const PERMITTED_SCHEMES = ["http", "https", "file", "ftp"]; + +// This function converts a glob pattern (containing * and possibly ? +// as wildcards) to a regular expression. +function globToRegexp(pat, allowQuestion) +{ + // Escape everything except ? and *. + pat = pat.replace(/[.+^${}()|[\]\\]/g, "\\$&"); + + if (allowQuestion) { + pat = pat.replace(/\?/g, "."); + } else { + pat = pat.replace(/\?/g, "\\?"); + } + pat = pat.replace(/\*/g, ".*"); + return new RegExp("^" + pat + "$"); +} + +// These patterns follow the syntax in +// https://developer.chrome.com/extensions/match_patterns +function SingleMatchPattern(pat) +{ + if (pat == "") { + this.scheme = PERMITTED_SCHEMES; + this.host = "*"; + this.path = new RegExp('.*'); + } else if (!pat) { + this.scheme = []; + } else { + let re = new RegExp("^(http|https|file|ftp|\\*)://(\\*|\\*\\.[^*/]+|[^*/]+|)(/.*)$"); + let match = re.exec(pat); + if (!match) { + Cu.reportError(`Invalid match pattern: '${pat}'`); + this.scheme = []; + return; + } + + if (match[1] == '*') { + this.scheme = ["http", "https"]; + } else { + this.scheme = [match[1]]; + } + this.host = match[2]; + this.path = globToRegexp(match[3], false); + + // We allow the host to be empty for file URLs. + if (this.host == "" && this.scheme[0] != "file") { + Cu.reportError(`Invalid match pattern: '${pat}'`); + this.scheme = []; + return; + } + } +} + +SingleMatchPattern.prototype = { + matches(uri) { + if (this.scheme.indexOf(uri.scheme) == -1) { + return false; + } + + // This code ignores the port, as Chrome does. + if (this.host == '*') { + // Don't check anything. + } else if (this.host[0] == '*') { + // It must be *.foo. We also need to allow foo by itself. + let suffix = this.host.substr(2); + if (uri.host != suffix && !uri.host.endsWith("." + suffix)) { + return false; + } + } else { + if (this.host != uri.host) { + return false; + } + } + + if (!this.path.test(uri.path)) { + return false; + } + + return true; + } +}; + +function MatchPattern(pat) +{ + this.pat = pat; + if (!pat) { + this.matchers = []; + } else if (pat instanceof String || typeof(pat) == "string") { + this.matchers = [new SingleMatchPattern(pat)]; + } else { + this.matchers = [for (p of pat) new SingleMatchPattern(p)]; + } +} + +MatchPattern.prototype = { + // |uri| should be an nsIURI. + matches(uri) { + for (let matcher of this.matchers) { + if (matcher.matches(uri)) { + return true; + } + } + return false; + }, + + serialize() { + return this.pat; + }, +}; diff --git a/toolkit/modules/addons/WebRequest.jsm b/toolkit/modules/addons/WebRequest.jsm index b7f9d1ccc81..13230a2b956 100644 --- a/toolkit/modules/addons/WebRequest.jsm +++ b/toolkit/modules/addons/WebRequest.jsm @@ -100,6 +100,9 @@ let ContentPolicyManager = { addListener(callback, opts) { let id = this.nextId++; opts.id = id; + if (opts.filter.urls) { + opts.filter.urls = opts.filter.urls.serialize(); + } Services.ppmm.broadcastAsyncMessage("WebRequest:AddContentPolicy", opts); this.policyData.set(id, opts); diff --git a/toolkit/modules/addons/WebRequestCommon.jsm b/toolkit/modules/addons/WebRequestCommon.jsm index 34b75fdcd0b..a7dd9c68209 100644 --- a/toolkit/modules/addons/WebRequestCommon.jsm +++ b/toolkit/modules/addons/WebRequestCommon.jsm @@ -32,16 +32,11 @@ let WebRequestCommon = { return filterTypes.indexOf(this.typeForPolicyType(policyType)) != -1; }, - urlMatches(uri, urlFilters) { - if (urlFilters === null) { + urlMatches(uri, urlFilter) { + if (urlFilter === null) { return true; } - for (let urlRegexp of urlFilters) { - if (urlRegexp.test(uri.spec)) { - return true; - } - } - return false; + return urlFilter.matches(uri); } }; diff --git a/toolkit/modules/addons/WebRequestContent.js b/toolkit/modules/addons/WebRequestContent.js index 8d0eda48739..2cd019a3bdf 100644 --- a/toolkit/modules/addons/WebRequestContent.js +++ b/toolkit/modules/addons/WebRequestContent.js @@ -12,6 +12,8 @@ const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "MatchPattern", + "resource://gre/modules/MatchPattern.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "WebRequestCommon", "resource://gre/modules/WebRequestCommon.jsm"); @@ -43,6 +45,9 @@ let ContentPolicy = { if (this.contentPolicies.size == 0) { this.register(); } + if (filter.urls) { + filter.urls = new MatchPattern(filter.urls); + } this.contentPolicies.set(id, {blocking, filter}); }, diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index 517fe668f45..92a7a4d0c2e 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -12,6 +12,7 @@ MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini'] SPHINX_TREES['toolkit_modules'] = 'docs' EXTRA_JS_MODULES += [ + 'addons/MatchPattern.jsm', 'addons/WebRequest.jsm', 'addons/WebRequestCommon.jsm', 'addons/WebRequestContent.js', diff --git a/toolkit/modules/tests/browser/browser_WebRequest_filtering.js b/toolkit/modules/tests/browser/browser_WebRequest_filtering.js index 56a8f17fffd..14d8ea73241 100644 --- a/toolkit/modules/tests/browser/browser_WebRequest_filtering.js +++ b/toolkit/modules/tests/browser/browser_WebRequest_filtering.js @@ -3,6 +3,7 @@ const { interfaces: Ci, classes: Cc, utils: Cu, results: Cr } = Components; let {WebRequest} = Cu.import("resource://gre/modules/WebRequest.jsm", {}); +let {MatchPattern} = Cu.import("resource://gre/modules/MatchPattern.jsm", {}); const BASE = "http://example.com/browser/toolkit/modules/tests/browser"; const URL = BASE + "/file_WebRequest_page2.html"; @@ -64,7 +65,7 @@ function compareLists(list1, list2, kind) } add_task(function* filter_urls() { - let filter = {urls: [/.*_style_.*/]}; + let filter = {urls: new MatchPattern("*://*/*_style_*")}; WebRequest.onBeforeRequest.addListener(onBeforeRequest, filter, ["blocking"]); WebRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, filter, ["blocking"]); diff --git a/toolkit/modules/tests/xpcshell/test_MatchPattern.js b/toolkit/modules/tests/xpcshell/test_MatchPattern.js new file mode 100644 index 00000000000..6e713d7b388 --- /dev/null +++ b/toolkit/modules/tests/xpcshell/test_MatchPattern.js @@ -0,0 +1,92 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +Components.utils.import("resource://gre/modules/MatchPattern.jsm"); +Components.utils.import("resource://gre/modules/Services.jsm"); + +function test(url, pattern) +{ + let uri = Services.io.newURI(url, null, null); + let m = new MatchPattern(pattern); + return m.matches(uri); +} + +function pass({url, pattern}) +{ + do_check_true(test(url, pattern), `Expected match: ${JSON.stringify(pattern)}, ${url}`); +} + +function fail({url, pattern}) +{ + do_check_false(test(url, pattern), `Expected no match: ${JSON.stringify(pattern)}, ${url}`); +} + +function run_test() +{ + // Invalid pattern. + fail({url:"http://mozilla.org", pattern:""}); + + // Pattern must include trailing slash. + fail({url:"http://mozilla.org", pattern:"http://mozilla.org"}); + + // Protocol not allowed. + fail({url:"http://mozilla.org", pattern:"gopher://wuarchive.wustl.edu/"}); + + pass({url:"http://mozilla.org", pattern:"http://mozilla.org/"}); + pass({url:"http://mozilla.org/", pattern:"http://mozilla.org/"}); + + pass({url:"http://mozilla.org/", pattern:"*://mozilla.org/"}); + pass({url:"https://mozilla.org/", pattern:"*://mozilla.org/"}); + fail({url:"file://mozilla.org/", pattern:"*://mozilla.org/"}); + fail({url:"ftp://mozilla.org/", pattern:"*://mozilla.org/"}); + + fail({url:"http://mozilla.com", pattern:"http://*mozilla.com*/"}); + fail({url:"http://mozilla.com", pattern:"http://mozilla.*/"}); + fail({url:"http://mozilla.com", pattern:"http:/mozilla.com/"}); + + pass({url:"http://google.com", pattern:"http://*.google.com/"}); + pass({url:"http://docs.google.com", pattern:"http://*.google.com/"}); + + pass({url:"http://mozilla.org:8080", pattern:"http://mozilla.org/"}); + pass({url:"http://mozilla.org:8080", pattern:"*://mozilla.org/"}); + fail({url:"http://mozilla.org:8080", pattern:"http://mozilla.org:8080/"}); + + // Now try with * in the path. + pass({url:"http://mozilla.org", pattern:"http://mozilla.org/*"}); + pass({url:"http://mozilla.org/", pattern:"http://mozilla.org/*"}); + + pass({url:"http://mozilla.org/", pattern:"*://mozilla.org/*"}); + pass({url:"https://mozilla.org/", pattern:"*://mozilla.org/*"}); + fail({url:"file://mozilla.org/", pattern:"*://mozilla.org/*"}); + fail({url:"http://mozilla.com", pattern:"http://mozilla.*/*"}); + + pass({url:"http://google.com", pattern:"http://*.google.com/*"}); + pass({url:"http://docs.google.com", pattern:"http://*.google.com/*"}); + + // Check path stuff. + fail({url:"http://mozilla.com/abc/def", pattern:"http://mozilla.com/"}); + pass({url:"http://mozilla.com/abc/def", pattern:"http://mozilla.com/*"}); + pass({url:"http://mozilla.com/abc/def", pattern:"http://mozilla.com/a*f"}); + pass({url:"http://mozilla.com/abc/def", pattern:"http://mozilla.com/a*"}); + pass({url:"http://mozilla.com/abc/def", pattern:"http://mozilla.com/*f"}); + fail({url:"http://mozilla.com/abc/def", pattern:"http://mozilla.com/*e"}); + fail({url:"http://mozilla.com/abc/def", pattern:"http://mozilla.com/*c"}); + + fail({url:"http:///a.html", pattern:"http:///a.html"}); + pass({url:"file:///foo", pattern:"file:///foo*"}); + pass({url:"file:///foo/bar.html", pattern:"file:///foo*"}); + + pass({url:"http://mozilla.org/a", pattern:""}); + pass({url:"https://mozilla.org/a", pattern:""}); + pass({url:"ftp://mozilla.org/a", pattern:""}); + pass({url:"file:///a", pattern:""}); + fail({url:"gopher://wuarchive.wustl.edu/a", pattern:""}); + + // Multiple patterns. + pass({url:"http://mozilla.org", pattern:["http://mozilla.org/"]}); + pass({url:"http://mozilla.org", pattern:["http://mozilla.org/", "http://mozilla.com/"]}); + pass({url:"http://mozilla.com", pattern:["http://mozilla.org/", "http://mozilla.com/"]}); + fail({url:"http://mozilla.biz", pattern:["http://mozilla.org/", "http://mozilla.com/"]}); +} diff --git a/toolkit/modules/tests/xpcshell/xpcshell.ini b/toolkit/modules/tests/xpcshell/xpcshell.ini index 9725d5ad6b0..48a8b78ffcf 100644 --- a/toolkit/modules/tests/xpcshell/xpcshell.ini +++ b/toolkit/modules/tests/xpcshell/xpcshell.ini @@ -15,6 +15,7 @@ support-files = [test_GMPInstallManager.js] [test_Http.js] [test_Log.js] +[test_MatchPattern.js] [test_NewTabUtils.js] [test_ObjectUtils.js] [test_ObjectUtils_strict.js] From 4c97d96b0a52d46614eaeab2b620b183fc1e8bec Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 3 Jun 2015 14:53:12 -0700 Subject: [PATCH 016/111] Bug 1171256 - Add an API similar to Chrome's webNavigation (r=Mossop) --- toolkit/modules/addons/WebNavigation.jsm | 157 ++++++++++++++++++ .../modules/addons/WebNavigationContent.js | 105 ++++++++++++ toolkit/modules/moz.build | 2 + toolkit/modules/tests/browser/browser.ini | 4 + .../tests/browser/browser_WebNavigation.js | 140 ++++++++++++++++ .../browser/file_WebNavigation_page1.html | 9 + .../browser/file_WebNavigation_page2.html | 7 + .../browser/file_WebNavigation_page3.html | 9 + 8 files changed, 433 insertions(+) create mode 100644 toolkit/modules/addons/WebNavigation.jsm create mode 100644 toolkit/modules/addons/WebNavigationContent.js create mode 100644 toolkit/modules/tests/browser/browser_WebNavigation.js create mode 100644 toolkit/modules/tests/browser/file_WebNavigation_page1.html create mode 100644 toolkit/modules/tests/browser/file_WebNavigation_page2.html create mode 100644 toolkit/modules/tests/browser/file_WebNavigation_page3.html diff --git a/toolkit/modules/addons/WebNavigation.jsm b/toolkit/modules/addons/WebNavigation.jsm new file mode 100644 index 00000000000..3e6c3bbef31 --- /dev/null +++ b/toolkit/modules/addons/WebNavigation.jsm @@ -0,0 +1,157 @@ +/* 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/. */ + +"use strict"; + +const EXPORTED_SYMBOLS = ["WebNavigation"]; + +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +// TODO: +// Transition types and qualifiers +// onReferenceFragmentUpdated also triggers for pushState +// getFrames, getAllFrames +// onCreatedNavigationTarget, onHistoryStateUpdated + +let Manager = { + listeners: new Map(), + + init() { + Services.mm.addMessageListener("Extension:DOMContentLoaded", this); + Services.mm.addMessageListener("Extension:StateChange", this); + Services.mm.addMessageListener("Extension:LocationChange", this); + Services.mm.loadFrameScript("resource://gre/modules/WebNavigationContent.js", true); + }, + + uninit() { + Services.mm.removeMessageListener("Extension:StateChange", this); + Services.mm.removeMessageListener("Extension:LocationChange", this); + Services.mm.removeMessageListener("Extension:DOMContentLoaded", this); + Services.mm.removeDelayedFrameScript("resource://gre/modules/WebNavigationContent.js"); + Services.mm.broadcastAsyncMessage("Extension:DisableWebNavigation"); + }, + + addListener(type, listener) { + if (this.listeners.size == 0) { + this.init(); + } + + if (!this.listeners.has(type)) { + this.listeners.set(type, new Set()); + } + let listeners = this.listeners.get(type); + listeners.add(listener); + }, + + removeListener(type, listener) { + let listeners = this.listeners.get(type); + if (!listeners) { + return; + } + listeners.delete(listener); + if (listeners.size == 0) { + this.listeners.delete(type); + } + + if (this.listeners.size == 0) { + this.uninit(); + } + }, + + receiveMessage({name, data, target}) { + switch (name) { + case "Extension:StateChange": + this.onStateChange(target, data); + break; + + case "Extension:LocationChange": + this.onLocationChange(target, data); + break; + + case "Extension:DOMContentLoaded": + this.onLoad(target, data); + break; + } + }, + + onStateChange(browser, data) { + let stateFlags = data.stateFlags; + if (stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) { + let url = data.requestURL; + if (stateFlags & Ci.nsIWebProgressListener.STATE_START) { + this.fire("onBeforeNavigate", browser, data, {url}); + } else if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) { + if (Components.isSuccessCode(data.status)) { + this.fire("onCompleted", browser, data, {url}); + } else { + let error = `Error code ${data.status}`; + this.fire("onErrorOccurred", browser, data, {error, url}); + } + } + } + }, + + onLocationChange(browser, data) { + let url = data.location; + if (data.flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) { + this.fire("onReferenceFragmentUpdated", browser, data, {url}); + } else { + this.fire("onCommitted", browser, data, {url}); + } + }, + + onLoad(browser, data) { + this.fire("onDOMContentLoaded", browser, data, {url: data.url}); + }, + + fire(type, browser, data, extra) { + let listeners = this.listeners.get(type); + if (!listeners) { + return; + } + + let details = { + browser, + windowId: data.windowId, + }; + + if (data.parentWindowId) { + details.parentWindowId = data.parentWindowId; + } + + for (let prop in extra) { + details[prop] = extra[prop]; + } + + for (let listener of listeners) { + listener(details); + } + }, +}; + +const EVENTS = [ + "onBeforeNavigate", + "onCommitted", + "onDOMContentLoaded", + "onCompleted", + "onErrorOccurred", + "onReferenceFragmentUpdated", + + //"onCreatedNavigationTarget", + //"onHistoryStateUpdated", +]; + +let WebNavigation = {}; + +for (let event of EVENTS) { + WebNavigation[event] = { + addListener: Manager.addListener.bind(Manager, event), + removeListener: Manager.removeListener.bind(Manager, event), + } +} diff --git a/toolkit/modules/addons/WebNavigationContent.js b/toolkit/modules/addons/WebNavigationContent.js new file mode 100644 index 00000000000..f5df9a980a0 --- /dev/null +++ b/toolkit/modules/addons/WebNavigationContent.js @@ -0,0 +1,105 @@ +const Ci = Components.interfaces; + +function getWindowId(window) +{ + return window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils) + .outerWindowID; +} + +function getParentWindowId(window) +{ + return getWindowId(window.parent); +} + +function loadListener(event) +{ + let document = event.target; + let window = document.defaultView; + let url = document.documentURI; + let windowId = getWindowId(window); + let parentWindowId = getParentWindowId(window); + sendAsyncMessage("Extension:DOMContentLoaded", {windowId, parentWindowId, url}); +} + +addEventListener("DOMContentLoaded", loadListener); +addMessageListener("Extension:DisableWebNavigation", () => { + removeEventListener("DOMContentLoaded", loadListener); +}); + +let WebProgressListener = { + init: function() { + let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebProgress); + webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_WINDOW | + Ci.nsIWebProgress.NOTIFY_LOCATION); + }, + + uninit() { + if (!docShell) { + return; + } + let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebProgress); + webProgress.removeProgressListener(this); + }, + + onStateChange: function onStateChange(webProgress, request, stateFlags, status) { + let data = { + requestURL: request.QueryInterface(Ci.nsIChannel).URI.spec, + windowId: webProgress.DOMWindowID, + parentWindowId: getParentWindowId(webProgress.DOMWindow), + status, + stateFlags, + }; + sendAsyncMessage("Extension:StateChange", data); + + if (webProgress.DOMWindow.top != webProgress.DOMWindow) { + let webNav = webProgress.QueryInterface(Ci.nsIWebNavigation); + if (!webNav.canGoBack) { + // For some reason we don't fire onLocationChange for the + // initial navigation of a sub-frame. So we need to simulate + // it here. + let data = { + location: request.QueryInterface(Ci.nsIChannel).URI.spec, + windowId: webProgress.DOMWindowID, + parentWindowId: getParentWindowId(webProgress.DOMWindow), + flags: 0, + }; + sendAsyncMessage("Extension:LocationChange", data); + } + } + }, + + onLocationChange: function onLocationChange(webProgress, request, locationURI, flags) { + let data = { + location: locationURI ? locationURI.spec : "", + windowId: webProgress.DOMWindowID, + parentWindowId: getParentWindowId(webProgress.DOMWindow), + flags, + }; + sendAsyncMessage("Extension:LocationChange", data); + }, + + QueryInterface: function QueryInterface(aIID) { + if (aIID.equals(Ci.nsIWebProgressListener) || + aIID.equals(Ci.nsISupportsWeakReference) || + aIID.equals(Ci.nsISupports)) { + return this; + } + + throw Components.results.NS_ERROR_NO_INTERFACE; + } +}; + +let disabled = false; +WebProgressListener.init(); +addEventListener("unload", () => { + if (!disabled) { + WebProgressListener.uninit(); + } +}); +addMessageListener("Extension:DisableWebNavigation", () => { + disabled = true; + WebProgressListener.uninit(); +}); diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index 92a7a4d0c2e..52fafba412a 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -13,6 +13,8 @@ SPHINX_TREES['toolkit_modules'] = 'docs' EXTRA_JS_MODULES += [ 'addons/MatchPattern.jsm', + 'addons/WebNavigation.jsm', + 'addons/WebNavigationContent.js', 'addons/WebRequest.jsm', 'addons/WebRequestCommon.jsm', 'addons/WebRequestContent.js', diff --git a/toolkit/modules/tests/browser/browser.ini b/toolkit/modules/tests/browser/browser.ini index 4d651bd93e0..2937d30041e 100644 --- a/toolkit/modules/tests/browser/browser.ini +++ b/toolkit/modules/tests/browser/browser.ini @@ -3,6 +3,9 @@ support-files = dummy_page.html metadata_*.html testremotepagemanager.html + file_WebNavigation_page1.html + file_WebNavigation_page2.html + file_WebNavigation_page3.html file_WebRequest_page1.html file_WebRequest_page2.html file_image_good.png @@ -23,6 +26,7 @@ support-files = skip-if = e10s # Bug ?????? - test already uses content scripts, but still fails only under e10s. [browser_Geometry.js] [browser_InlineSpellChecker.js] +[browser_WebNavigation.js] [browser_WebRequest.js] [browser_WebRequest_cookies.js] [browser_WebRequest_filtering.js] diff --git a/toolkit/modules/tests/browser/browser_WebNavigation.js b/toolkit/modules/tests/browser/browser_WebNavigation.js new file mode 100644 index 00000000000..d06e9bd1294 --- /dev/null +++ b/toolkit/modules/tests/browser/browser_WebNavigation.js @@ -0,0 +1,140 @@ +"use strict"; + +const { interfaces: Ci, classes: Cc, utils: Cu, results: Cr } = Components; + +let {WebNavigation} = Cu.import("resource://gre/modules/WebNavigation.jsm", {}); + +const BASE = "http://example.com/browser/toolkit/modules/tests/browser"; +const URL = BASE + "/file_WebNavigation_page1.html"; +const FRAME = BASE + "/file_WebNavigation_page2.html"; +const FRAME2 = BASE + "/file_WebNavigation_page3.html"; + +const EVENTS = [ + "onBeforeNavigate", + "onCommitted", + "onDOMContentLoaded", + "onCompleted", + "onErrorOccurred", + "onReferenceFragmentUpdated", +]; + +const REQUIRED = [ + "onBeforeNavigate", + "onCommitted", + "onDOMContentLoaded", + "onCompleted", +]; + +let expectedBrowser; +let received = []; +let completedResolve; +let waitingURL, waitingEvent; +let rootWindowID; + +function gotEvent(event, details) +{ + if (!details.url.startsWith(BASE)) { + return; + } + info(`Got ${event} ${details.url} ${details.windowId} ${details.parentWindowId}`); + + is(details.browser, expectedBrowser, "correct element"); + + received.push({url: details.url, event}); + + if (typeof(rootWindowID) == "undefined") { + rootWindowID = details.windowId; + } + + if (details.url == URL) { + is(details.windowId, rootWindowID, "root window ID correct"); + } else { + is(details.parentWindowId, rootWindowID, "parent window ID correct"); + isnot(details.windowId, rootWindowID, "window ID probably okay"); + } + + isnot(details.windowId, undefined); + isnot(details.parentWindowId, undefined); + + if (details.url == waitingURL && event == waitingEvent) { + completedResolve(); + } +} + +function loadViaFrameScript(url, event, script) +{ + // Loading via a frame script ensures that the chrome process never + // "gets ahead" of frame scripts in non-e10s mode. + received = []; + waitingURL = url; + waitingEvent = event; + expectedBrowser.messageManager.loadFrameScript("data:," + script, false); + return new Promise(resolve => { completedResolve = resolve; }); +} + +add_task(function* webnav_ordering() { + let listeners = {}; + for (let event of EVENTS) { + listeners[event] = gotEvent.bind(null, event); + WebNavigation[event].addListener(listeners[event]); + } + + gBrowser.selectedTab = gBrowser.addTab(); + let browser = gBrowser.selectedBrowser; + expectedBrowser = browser; + + yield BrowserTestUtils.browserLoaded(browser); + + yield loadViaFrameScript(URL, "onCompleted", `content.location = "${URL}";`); + + function checkRequired(url) { + for (let event of REQUIRED) { + let found = false; + for (let r of received) { + if (r.url == url && r.event == event) { + found = true; + } + } + ok(found, `Received event ${event} from ${url}`); + } + } + + checkRequired(URL); + checkRequired(FRAME); + + function checkBefore(action1, action2) { + function find(action) { + for (let i = 0; i < received.length; i++) { + if (received[i].url == action.url && received[i].event == action.event) { + return i; + } + } + return -1; + } + + let index1 = find(action1); + let index2 = find(action2); + ok(index1 != -1, `Action ${JSON.stringify(action1)} happened`); + ok(index2 != -1, `Action ${JSON.stringify(action2)} happened`); + ok(index1 < index2, `Action ${JSON.stringify(action1)} happened before ${JSON.stringify(action2)}`); + } + + checkBefore({url: URL, event: "onCommitted"}, {url: FRAME, event: "onBeforeNavigate"}); + checkBefore({url: FRAME, event: "onCompleted"}, {url: URL, event: "onCompleted"}); + + yield loadViaFrameScript(FRAME2, "onCompleted", `content.frames[0].location = "${FRAME2}";`); + + checkRequired(FRAME2); + + yield loadViaFrameScript(FRAME2 + "#ref", "onReferenceFragmentUpdated", + "content.frames[0].document.getElementById('elt').click();"); + + info("Received onReferenceFragmentUpdated from FRAME2"); + + gBrowser.removeCurrentTab(); + + for (let event of EVENTS) { + WebNavigation[event].removeListener(listeners[event]); + } +}); + diff --git a/toolkit/modules/tests/browser/file_WebNavigation_page1.html b/toolkit/modules/tests/browser/file_WebNavigation_page1.html new file mode 100644 index 00000000000..1b68697562a --- /dev/null +++ b/toolkit/modules/tests/browser/file_WebNavigation_page1.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/toolkit/modules/tests/browser/file_WebNavigation_page2.html b/toolkit/modules/tests/browser/file_WebNavigation_page2.html new file mode 100644 index 00000000000..cc1acc83d63 --- /dev/null +++ b/toolkit/modules/tests/browser/file_WebNavigation_page2.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/toolkit/modules/tests/browser/file_WebNavigation_page3.html b/toolkit/modules/tests/browser/file_WebNavigation_page3.html new file mode 100644 index 00000000000..a0a26a2e9d5 --- /dev/null +++ b/toolkit/modules/tests/browser/file_WebNavigation_page3.html @@ -0,0 +1,9 @@ + + + + + +click me + + + From 9de6fdd63f51ef7114b3258b58f7c919355ad0e4 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Tue, 16 Jun 2015 11:58:04 -0700 Subject: [PATCH 017/111] Bug 1143006 - Show warning for http-on-* in child process (r=mrbkap) --- js/xpconnect/idl/nsIScriptError.idl | 4 ++++ xpcom/ds/nsObserverService.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/js/xpconnect/idl/nsIScriptError.idl b/js/xpconnect/idl/nsIScriptError.idl index 35c8ef77243..83b0fd6329c 100644 --- a/js/xpconnect/idl/nsIScriptError.idl +++ b/js/xpconnect/idl/nsIScriptError.idl @@ -11,6 +11,10 @@ #include "nsISupports.idl" #include "nsIConsoleMessage.idl" +%{C++ +#include "nsString.h" // for nsDependentCString +%} + [scriptable, uuid(248b2c94-2736-4d29-bfdf-bc64a2e60d35)] interface nsIScriptError : nsIConsoleMessage { diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index f36a8baab74..7a25b035ba5 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -6,10 +6,13 @@ #include "mozilla/Logging.h" #include "nsAutoPtr.h" +#include "nsIConsoleService.h" #include "nsIObserverService.h" #include "nsIObserver.h" +#include "nsIScriptError.h" #include "nsObserverService.h" #include "nsObserverList.h" +#include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" #include "nsEnumeratorUtils.h" #include "xpcpublic.h" @@ -264,6 +267,13 @@ nsObserverService::AddObserver(nsIObserver* aObserver, const char* aTopic, } if (mozilla::net::IsNeckoChild() && !strncmp(aTopic, "http-on-", 8)) { + nsCOMPtr console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); + nsCOMPtr error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); + error->Init(NS_LITERAL_STRING("http-on-* observers only work in the parent process"), + EmptyString(), EmptyString(), 0, 0, + nsIScriptError::warningFlag, "chrome javascript"); + console->LogMessage(error); + return NS_ERROR_NOT_IMPLEMENTED; } From cb82c001ba5e53de452b437a10fd72b3a892e0c2 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Fri, 22 May 2015 15:54:06 -0700 Subject: [PATCH 018/111] Bug 1167794 - Allow dumping shim debugging to stdout (r=gabor,a=KWierso) --- toolkit/components/addoncompat/CompatWarning.jsm | 9 +++++++++ .../components/addoncompat/RemoteAddonsParent.jsm | 12 ++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/toolkit/components/addoncompat/CompatWarning.jsm b/toolkit/components/addoncompat/CompatWarning.jsm index c281d190c75..d5de342372b 100644 --- a/toolkit/components/addoncompat/CompatWarning.jsm +++ b/toolkit/components/addoncompat/CompatWarning.jsm @@ -74,6 +74,15 @@ let CompatWarning = { /*flags*/ Ci.nsIScriptError.warningFlag, /*category*/ "chrome javascript"); Services.console.logMessage(error); + + if (Preferences.get("dom.ipc.shims.dumpWarnings", false)) { + dump(message + "\n"); + while (stack) { + dump(stack + "\n"); + stack = stack.caller; + } + dump("\n"); + } }; }, diff --git a/toolkit/components/addoncompat/RemoteAddonsParent.jsm b/toolkit/components/addoncompat/RemoteAddonsParent.jsm index 5572fe7f49a..5d9e2d0187a 100644 --- a/toolkit/components/addoncompat/RemoteAddonsParent.jsm +++ b/toolkit/components/addoncompat/RemoteAddonsParent.jsm @@ -616,7 +616,7 @@ let EventTargetInterposition = new Interposition("EventTargetInterposition"); EventTargetInterposition.methods.addEventListener = function(addon, target, type, listener, useCapture, wantsUntrusted) { let delayed = CompatWarning.delayedWarning( - "Registering an event listener on content DOM nodes" + + `Registering a ${type} event listener on content DOM nodes` + " needs to happen in the content process.", addon, CompatWarning.warnings.DOM_events); @@ -819,7 +819,7 @@ function makeDummyContentWindow(browser) { } RemoteBrowserElementInterposition.getters.contentWindow = function(addon, target) { - CompatWarning.warn("Direct access to content objects will no longer work in the chrome process.", + CompatWarning.warn("Direct access to browser.contentWindow will no longer work in the chrome process.", addon, CompatWarning.warnings.content); // If we don't have a CPOW yet, just return something we can use for @@ -847,7 +847,7 @@ function getContentDocument(addon, browser) } RemoteBrowserElementInterposition.getters.contentDocument = function(addon, target) { - CompatWarning.warn("Direct access to content objects will no longer work in the chrome process.", + CompatWarning.warn("Direct access to browser.contentDocument will no longer work in the chrome process.", addon, CompatWarning.warnings.content); return getContentDocument(addon, target); @@ -857,7 +857,7 @@ let TabBrowserElementInterposition = new Interposition("TabBrowserElementInterpo EventTargetInterposition); TabBrowserElementInterposition.getters.contentWindow = function(addon, target) { - CompatWarning.warn("Direct access to content objects will no longer work in the chrome process.", + CompatWarning.warn("Direct access to gBrowser.contentWindow will no longer work in the chrome process.", addon, CompatWarning.warnings.content); if (!target.selectedBrowser.contentWindowAsCPOW) { @@ -867,7 +867,7 @@ TabBrowserElementInterposition.getters.contentWindow = function(addon, target) { }; TabBrowserElementInterposition.getters.contentDocument = function(addon, target) { - CompatWarning.warn("Direct access to content objects will no longer work in the chrome process.", + CompatWarning.warn("Direct access to gBrowser.contentDocument will no longer work in the chrome process.", addon, CompatWarning.warnings.content); let browser = target.selectedBrowser; @@ -945,7 +945,7 @@ let ChromeWindowInterposition = new Interposition("ChromeWindowInterposition", // that should be using content instead. ChromeWindowInterposition.getters.content = ChromeWindowInterposition.getters._content = function(addon, target) { - CompatWarning.warn("Direct access to content objects will no longer work in the chrome process.", + CompatWarning.warn("Direct access to chromeWindow.content will no longer work in the chrome process.", addon, CompatWarning.warnings.content); let browser = target.gBrowser.selectedBrowser; From 68dc1bfbf25e7c152e1f2287829845a81e0c5cc3 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 19 Jun 2015 18:00:02 -0700 Subject: [PATCH 019/111] Bug 1146136 - Fix another test that parenthesizes destructuring pattern assignment targets, that snuck in in the last week, as ES6 forbids such parenthesization. r=bustage, a=bustage --- .../extensions/test/browser/browser_list.js | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/toolkit/mozapps/extensions/test/browser/browser_list.js b/toolkit/mozapps/extensions/test/browser/browser_list.js index b99bbd57a61..6c16e7ae28d 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_list.js +++ b/toolkit/mozapps/extensions/test/browser/browser_list.js @@ -180,7 +180,7 @@ add_task(function*() { info("Addon 2"); addon = items["Test add-on 2"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 2", "Name should be correct"); is(name, "Test add-on 2", "Tooltip name should be correct"); is(version, "2.0", "Tooltip version should be correct"); @@ -217,7 +217,7 @@ add_task(function*() { info("Addon 3"); addon = items["Test add-on 3"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 3", "Name should be correct"); is(name, "Test add-on 3", "Tooltip name should be correct"); is(version, undefined, "Tooltip version should be hidden"); @@ -237,7 +237,7 @@ add_task(function*() { info("Addon 4"); addon = items["Test add-on 4"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 4", "Name should be correct"); is(name, "Test add-on 4", "Tooltip name should be correct"); @@ -272,7 +272,7 @@ add_task(function*() { info("Addon 5"); addon = items["Test add-on 5"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 5", "Name should be correct"); is(name, "Test add-on 5", "Tooltip name should be correct"); @@ -293,7 +293,7 @@ add_task(function*() { info("Addon 6"); addon = items["Test add-on 6"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 6", "Name should be correct"); is(name, "Test add-on 6", "Tooltip name should be correct"); is_element_hidden(get_class_node(addon, "disabled-postfix"), "Disabled postfix should be hidden"); @@ -327,7 +327,7 @@ add_task(function*() { info("Addon 7"); addon = items["Test add-on 7"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 7", "Name should be correct"); is(name, "Test add-on 7", "Tooltip name should be correct"); @@ -362,7 +362,7 @@ add_task(function*() { info("Addon 8"); addon = items["Test add-on 8"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 8", "Name should be correct"); is(name, "Test add-on 8", "Tooltip name should be correct"); @@ -383,7 +383,7 @@ add_task(function*() { info("Addon 9"); addon = items["Test add-on 9"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 9", "Name should be correct"); is(name, "Test add-on 9", "Tooltip name should be correct"); @@ -404,7 +404,7 @@ add_task(function*() { info("Addon 10"); addon = items["Test add-on 10"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 10", "Name should be correct"); is(name, "Test add-on 10", "Tooltip name should be correct"); @@ -425,7 +425,7 @@ add_task(function*() { info("Addon 11"); addon = items["Test add-on 11"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 11", "Name should be correct"); is(name, "Test add-on 11", "Tooltip name should be correct"); @@ -536,7 +536,7 @@ add_task(function*() { info("Addon 2"); addon = items["Test add-on 2"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 2", "Name should be correct"); is(name, "Test add-on 2", "Tooltip name should be correct"); is(version, "2.0", "Tooltip version should be correct"); @@ -573,7 +573,7 @@ add_task(function*() { info("Addon 4"); addon = items["Test add-on 4"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 4", "Name should be correct"); is(name, "Test add-on 4", "Tooltip name should be correct"); @@ -608,7 +608,7 @@ add_task(function*() { info("Addon 6"); addon = items["Test add-on 6"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 6", "Name should be correct"); is(name, "Test add-on 6", "Tooltip name should be correct"); is_element_visible(get_class_node(addon, "disabled-postfix"), "Disabled postfix should be visible"); @@ -642,7 +642,7 @@ add_task(function*() { info("Addon 7"); addon = items["Test add-on 7"]; addon.parentNode.ensureElementIsVisible(addon); - ({ name, version }) = yield get_tooltip_info(addon); + ({ name, version } = yield get_tooltip_info(addon)); is(get_node(addon, "name").value, "Test add-on 7", "Name should be correct"); is(name, "Test add-on 7", "Tooltip name should be correct"); From f466a03d88921d36243e0be044abd43178e44126 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 19 Jun 2015 18:03:05 -0700 Subject: [PATCH 020/111] Backed out 2 changesets (bug 1175585) for test_wheel_transactions.html failures CLOSED TREE Backed out changeset 5b56c3d0e379 (bug 1175585) Backed out changeset 89b4c0b06ff3 (bug 1175585) --- .../apz/test/apz_test_native_event_utils.js | 20 --- gfx/layers/apz/test/mochitest.ini | 2 - gfx/layers/apz/test/test_layerization.html | 26 +++- .../apz/test/test_wheel_transactions.html | 131 ------------------ 4 files changed, 20 insertions(+), 159 deletions(-) delete mode 100644 gfx/layers/apz/test/test_wheel_transactions.html diff --git a/gfx/layers/apz/test/apz_test_native_event_utils.js b/gfx/layers/apz/test/apz_test_native_event_utils.js index 5b0ca7135a7..531c258baba 100644 --- a/gfx/layers/apz/test/apz_test_native_event_utils.js +++ b/gfx/layers/apz/test/apz_test_native_event_utils.js @@ -124,23 +124,3 @@ function synthesizeNativeMouseMoveAndWaitForMoveEvent(aElement, aX, aY, aCallbac }); return synthesizeNativeMouseMove(aElement, aX, aY); } - -// Scroll the mouse wheel (in the vertical direction) by |aWheelDelta| over |aElement|, -// calling |aCallback| when the first resulting scroll event is received. -function scrollWheelOver(aElement, aWheelDelta, aCallback) { - var scale = window.devicePixelRatio; - var rect = aElement.getBoundingClientRect(); - var x = (rect.left + 10) * scale; - var y = (rect.top + 10) * scale; - // Move the mouse to the desired wheel location. - // Not doing so can result in the wheel events from two consecutive - // scrollWheelOver() calls on different elements being incorrectly considered - // as part of the same wheel transaction. - // We also wait for the mouse move event to be processed before sending the - // wheel event, otherwise there is a chance they might get reordered, and - // we have the transaction problem again. - synthesizeNativeMouseMoveAndWaitForMoveEvent(aElement, x, y, function() { - synthesizeNativeWheelAndWaitForScrollEvent(aElement, x, y, 0, aWheelDelta, aCallback); - }); -} - diff --git a/gfx/layers/apz/test/mochitest.ini b/gfx/layers/apz/test/mochitest.ini index ba1fd6db177..bdf949c999a 100644 --- a/gfx/layers/apz/test/mochitest.ini +++ b/gfx/layers/apz/test/mochitest.ini @@ -14,8 +14,6 @@ skip-if = toolkit != 'gonk' # bug 991198 skip-if = toolkit != 'gonk' # bug 991198 [test_wheel_scroll.html] skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet -[test_wheel_transactions.html] -skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet [test_bug1151667.html] skip-if = (os == 'android') || (os == 'b2g') # wheel events not supported on mobile [test_layerization.html] diff --git a/gfx/layers/apz/test/test_layerization.html b/gfx/layers/apz/test/test_layerization.html index 3750cadd296..63d455d0e2c 100644 --- a/gfx/layers/apz/test/test_layerization.html +++ b/gfx/layers/apz/test/test_layerization.html @@ -50,8 +50,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1173580
 
-  
-  
-  
-  
-
-
-APZ wheel transactions test
-

-
-
-
-
-
-
-
-
- - - From f4df2d2e077be6aaac4d6c784ec810301eae74fd Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 19 Jun 2015 18:30:44 -0700 Subject: [PATCH 021/111] Bug 1146136 - Fix another test that parenthesizes destructuring pattern assignment targets, that snuck in in the last week, as ES6 forbids such parenthesization. r=bustage, a=bustage --- toolkit/mozapps/extensions/test/browser/browser_experiments.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolkit/mozapps/extensions/test/browser/browser_experiments.js b/toolkit/mozapps/extensions/test/browser/browser_experiments.js index a21b40f446f..3da5fd423fe 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_experiments.js +++ b/toolkit/mozapps/extensions/test/browser/browser_experiments.js @@ -459,7 +459,7 @@ add_task(function testActivateRealExperiments() { is_element_hidden(el, "warning-container should be hidden."); el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "pending-container"); is_element_hidden(el, "pending-container should be hidden."); - ({ version }) = yield get_tooltip_info(item); + ({ version } = yield get_tooltip_info(item)); Assert.equal(version, undefined, "version should be hidden."); el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix"); is_element_hidden(el, "disabled-postfix should be hidden."); From 0e89355f254434bdcafcbf794945061f35296d91 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 19 Jun 2015 22:51:35 -0400 Subject: [PATCH 022/111] Bug 1139155 - Add a mechanism to know when the APZ is done processing. r=botond --- dom/ipc/TabChild.cpp | 7 +++++++ gfx/layers/apz/src/AsyncPanZoomController.cpp | 1 + 2 files changed, 8 insertions(+) diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index c50f9e5e527..6105b2cec42 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -2146,6 +2146,13 @@ TabChild::RecvNotifyAPZStateChange(const ViewID& aViewId, const int& aArg) { mAPZEventState->ProcessAPZStateChange(GetDocument(), aViewId, aChange, aArg); + if (aChange == APZStateChange::TransformEnd) { + // This is used by tests to determine when the APZ is done doing whatever + // it's doing. XXX generify this as needed when writing additional tests. + DispatchMessageManagerMessage( + NS_LITERAL_STRING("APZ:TransformEnd"), + NS_LITERAL_STRING("{}")); + } return true; } diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 7bec3cc2154..68198770ccb 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -3123,6 +3123,7 @@ void AsyncPanZoomController::SetState(PanZoomState aNewState) // Intentional scoping for mutex { ReentrantMonitorAutoEnter lock(mMonitor); + APZC_LOG("%p changing from state %d to %d\n", this, mState, aNewState); oldState = mState; mState = aNewState; } From a054adb558e59fc4db140c19987d91eeb24e34d2 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 19 Jun 2015 22:52:07 -0400 Subject: [PATCH 023/111] Bug 1139155 - Add a basic sanity test to exercise touch-based scrolling on B2G. r=botond --- .../apz/test/apz_test_native_event_utils.js | 27 +++++++++ gfx/layers/apz/test/apz_test_utils.js | 17 ++++++ gfx/layers/apz/test/helper_basic_pan.html | 38 +++++++++++++ gfx/layers/apz/test/helper_div_pan.html | 44 ++++++++++++++ gfx/layers/apz/test/helper_iframe_pan.html | 41 +++++++++++++ gfx/layers/apz/test/mochitest.ini | 5 ++ gfx/layers/apz/test/test_basic_pan.html | 57 +++++++++++++++++++ 7 files changed, 229 insertions(+) create mode 100644 gfx/layers/apz/test/helper_basic_pan.html create mode 100644 gfx/layers/apz/test/helper_div_pan.html create mode 100644 gfx/layers/apz/test/helper_iframe_pan.html create mode 100644 gfx/layers/apz/test/test_basic_pan.html diff --git a/gfx/layers/apz/test/apz_test_native_event_utils.js b/gfx/layers/apz/test/apz_test_native_event_utils.js index 531c258baba..efe887b53cf 100644 --- a/gfx/layers/apz/test/apz_test_native_event_utils.js +++ b/gfx/layers/apz/test/apz_test_native_event_utils.js @@ -124,3 +124,30 @@ function synthesizeNativeMouseMoveAndWaitForMoveEvent(aElement, aX, aY, aCallbac }); return synthesizeNativeMouseMove(aElement, aX, aY); } + +// Synthesizes a native touch event and dispatches it. aX and aY in CSS pixels +// relative to the top-left of |aElement|'s bounding rect. +function synthesizeNativeTouch(aElement, aX, aY, aType, aObserver = null, aTouchId = 0) { + var targetWindow = aElement.ownerDocument.defaultView; + + var scale = targetWindow.devicePixelRatio; + var rect = aElement.getBoundingClientRect(); + var x = targetWindow.mozInnerScreenX + ((rect.left + aX) * scale); + var y = targetWindow.mozInnerScreenY + ((rect.top + aY) * scale); + + var utils = SpecialPowers.getDOMWindowUtils(targetWindow); + utils.sendNativeTouchPoint(aTouchId, aType, x, y, 1, 90, aObserver); + return true; +} + +function synthesizeNativeDrag(aElement, aX, aY, aDeltaX, aDeltaY, aObserver = null, aTouchId = 0) { + synthesizeNativeTouch(aElement, aX, aY, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, null, aTouchId); + var steps = Math.max(Math.abs(aDeltaX), Math.abs(aDeltaY)); + for (var i = 1; i < steps; i++) { + var dx = i * (aDeltaX / steps); + var dy = i * (aDeltaY / steps); + synthesizeNativeTouch(aElement, aX + dx, aY + dy, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, null, aTouchId); + } + synthesizeNativeTouch(aElement, aX + aDeltaX, aY + aDeltaY, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, null, aTouchId); + return synthesizeNativeTouch(aElement, aX + aDeltaX, aY + aDeltaY, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, aObserver, aTouchId); +} diff --git a/gfx/layers/apz/test/apz_test_utils.js b/gfx/layers/apz/test/apz_test_utils.js index 834afd8970e..a4da4fa4dd8 100644 --- a/gfx/layers/apz/test/apz_test_utils.js +++ b/gfx/layers/apz/test/apz_test_utils.js @@ -99,3 +99,20 @@ function buildApzcTree(paint) { } return root; } + +function flushApzRepaints(aCallback, aWindow = window) { + if (!aCallback) { + throw "A callback must be provided!"; + } + var repaintDone = function() { + SpecialPowers.Services.obs.removeObserver(repaintDone, "apz-repaints-flushed", false); + setTimeout(aCallback, 0); + }; + SpecialPowers.Services.obs.addObserver(repaintDone, "apz-repaints-flushed", false); + if (SpecialPowers.getDOMWindowUtils(aWindow).flushApzRepaints()) { + dump("Flushed APZ repaints, waiting for callback...\n"); + } else { + dump("Flushing APZ repaints was a no-op, triggering callback directly...\n"); + repaintDone(); + } +} diff --git a/gfx/layers/apz/test/helper_basic_pan.html b/gfx/layers/apz/test/helper_basic_pan.html new file mode 100644 index 00000000000..88765216837 --- /dev/null +++ b/gfx/layers/apz/test/helper_basic_pan.html @@ -0,0 +1,38 @@ + + + + + + Sanity panning test + + + + + +
+ This div makes the page scrollable. +
+ + diff --git a/gfx/layers/apz/test/helper_div_pan.html b/gfx/layers/apz/test/helper_div_pan.html new file mode 100644 index 00000000000..8807611f668 --- /dev/null +++ b/gfx/layers/apz/test/helper_div_pan.html @@ -0,0 +1,44 @@ + + + + + + Sanity panning test for scrollable div + + + + + +
+
+ This div makes the |outer| div scrollable. +
+
+
+ This div makes the top-level page scrollable. +
+ + diff --git a/gfx/layers/apz/test/helper_iframe_pan.html b/gfx/layers/apz/test/helper_iframe_pan.html new file mode 100644 index 00000000000..e74be49ca0a --- /dev/null +++ b/gfx/layers/apz/test/helper_iframe_pan.html @@ -0,0 +1,41 @@ + + + + + + Sanity panning test for scrollable div + + + + + + +
+ This div makes the top-level page scrollable. +
+ + diff --git a/gfx/layers/apz/test/mochitest.ini b/gfx/layers/apz/test/mochitest.ini index bdf949c999a..7f203f0aa66 100644 --- a/gfx/layers/apz/test/mochitest.ini +++ b/gfx/layers/apz/test/mochitest.ini @@ -7,6 +7,9 @@ support-files = helper_iframe1.html helper_iframe2.html helper_subframe_style.css + helper_basic_pan.html + helper_div_pan.html + helper_iframe_pan.html tags = apz [test_bug982141.html] skip-if = toolkit != 'gonk' # bug 991198 @@ -18,3 +21,5 @@ skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel ev skip-if = (os == 'android') || (os == 'b2g') # wheel events not supported on mobile [test_layerization.html] skip-if = (os == 'android') || (os == 'b2g') # uses wheel events which are not supported on mobile +[test_basic_pan.html] +skip-if = toolkit != 'gonk' diff --git a/gfx/layers/apz/test/test_basic_pan.html b/gfx/layers/apz/test/test_basic_pan.html new file mode 100644 index 00000000000..4c21b22ab92 --- /dev/null +++ b/gfx/layers/apz/test/test_basic_pan.html @@ -0,0 +1,57 @@ + + + + + Sanity panning test + + + + + + + From 7f0178f0d881f1c73fc7a1060fea5d5823413ffa Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 19 Jun 2015 22:57:37 -0400 Subject: [PATCH 024/111] Bug 1153841 - Remove the 'it must be 2D' restriction for transforms on fixed-pos layers. r=BenWa,mattwoodrow --- .../composite/AsyncCompositionManager.cpp | 80 +++++++------------ 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 76df089fbc2..84602b1541b 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -141,12 +141,14 @@ AsyncCompositionManager::ComputeRotation() } } -static bool -GetBaseTransform2D(Layer* aLayer, Matrix* aTransform) +static void +GetBaseTransform(Layer* aLayer, Matrix4x4* aTransform) { // Start with the animated transform if there is one - return (aLayer->AsLayerComposite()->GetShadowTransformSetByAnimation() ? - aLayer->GetLocalTransform() : aLayer->GetTransform()).Is2D(aTransform); + *aTransform = + (aLayer->AsLayerComposite()->GetShadowTransformSetByAnimation() + ? aLayer->GetLocalTransform() + : aLayer->GetTransform()); } static void @@ -183,9 +185,9 @@ SetShadowTransform(Layer* aLayer, Matrix4x4 aTransform) } static void -TranslateShadowLayer2D(Layer* aLayer, - const gfxPoint& aTranslation, - bool aAdjustClipRect) +TranslateShadowLayer(Layer* aLayer, + const gfxPoint& aTranslation, + bool aAdjustClipRect) { // This layer might also be a scrollable layer and have an async transform. // To make sure we don't clobber that, we start with the shadow transform. @@ -193,16 +195,12 @@ TranslateShadowLayer2D(Layer* aLayer, // Note that the shadow transform is reset on every frame of composition so // we don't have to worry about the adjustments compounding over successive // frames. - Matrix layerTransform; - if (!aLayer->GetLocalTransform().Is2D(&layerTransform)) { - return; - } + Matrix4x4 layerTransform = aLayer->GetLocalTransform(); - // Apply the 2D translation to the layer transform. - layerTransform._31 += aTranslation.x; - layerTransform._32 += aTranslation.y; + // Apply the translation to the layer transform. + layerTransform.PostTranslate(aTranslation.x, aTranslation.y, 0); - SetShadowTransform(aLayer, Matrix4x4::From2D(layerTransform)); + SetShadowTransform(aLayer, layerTransform); aLayer->AsLayerComposite()->SetShadowTransformSetByAnimation(false); if (aAdjustClipRect) { @@ -212,25 +210,21 @@ TranslateShadowLayer2D(Layer* aLayer, // If a fixed- or sticky-position layer has a mask layer, that mask should // move along with the layer, so apply the translation to the mask layer too. if (Layer* maskLayer = aLayer->GetMaskLayer()) { - TranslateShadowLayer2D(maskLayer, aTranslation, false); + TranslateShadowLayer(maskLayer, aTranslation, false); } } -static bool -AccumulateLayerTransforms2D(Layer* aLayer, - Layer* aAncestor, - Matrix& aMatrix) +static void +AccumulateLayerTransforms(Layer* aLayer, + Layer* aAncestor, + Matrix4x4& aMatrix) { // Accumulate the transforms between this layer and the subtree root layer. for (Layer* l = aLayer; l && l != aAncestor; l = l->GetParent()) { - Matrix l2D; - if (!GetBaseTransform2D(l, &l2D)) { - return false; - } - aMatrix *= l2D; + Matrix4x4 transform; + GetBaseTransform(l, &transform); + aMatrix *= transform; } - - return true; } static LayerPoint @@ -312,37 +306,25 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer, // Insert a translation so that the position of the anchor point is the same // before and after the change to the transform of aTransformedSubtreeRoot. - // This currently only works for fixed layers with 2D transforms. // Accumulate the transforms between this layer and the subtree root layer. - Matrix ancestorTransform; - if (!AccumulateLayerTransforms2D(aLayer->GetParent(), aTransformedSubtreeRoot, - ancestorTransform)) { - return; - } - - Matrix oldRootTransform; - Matrix newRootTransform; - if (!aPreviousTransformForRoot.Is2D(&oldRootTransform) || - !aCurrentTransformForRoot.Is2D(&newRootTransform)) { - return; - } + Matrix4x4 ancestorTransform; + AccumulateLayerTransforms(aLayer->GetParent(), aTransformedSubtreeRoot, + ancestorTransform); // Calculate the cumulative transforms between the subtree root with the // old transform and the current transform. - Matrix oldCumulativeTransform = ancestorTransform * oldRootTransform; - Matrix newCumulativeTransform = ancestorTransform * newRootTransform; + Matrix4x4 oldCumulativeTransform = ancestorTransform * aPreviousTransformForRoot; + Matrix4x4 newCumulativeTransform = ancestorTransform * aCurrentTransformForRoot; if (newCumulativeTransform.IsSingular()) { return; } - Matrix newCumulativeTransformInverse = newCumulativeTransform.Inverse(); + Matrix4x4 newCumulativeTransformInverse = newCumulativeTransform.Inverse(); // Now work out the translation necessary to make sure the layer doesn't // move given the new sub-tree root transform. - Matrix layerTransform; - if (!GetBaseTransform2D(aLayer, &layerTransform)) { - return; - } + Matrix4x4 layerTransform; + GetBaseTransform(aLayer, &layerTransform); // Calculate any offset necessary, in previous transform sub-tree root // space. This is used to make sure fixed position content respects @@ -387,7 +369,7 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer, IntervalOverlap(translation.x, stickyInner.x, stickyInner.XMost()); } - // Finally, apply the 2D translation to the layer transform. Note that in + // Finally, apply the translation to the layer transform. Note that in // general we need to apply the same translation to the layer's clip rect, so // that the effective transform on the clip rect takes it back to where it was // originally, had there been no async scroll. In the case where the @@ -395,7 +377,7 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer, // rect is not affected by the scroll-induced async scroll transform anyway // (since the clip is applied post-transform) so we don't need to make the // adjustment. - TranslateShadowLayer2D(aLayer, ThebesPoint(translation), aLayer != aTransformedSubtreeRoot); + TranslateShadowLayer(aLayer, ThebesPoint(translation), aLayer != aTransformedSubtreeRoot); } static void From 1dbc3646362e21adf0225a60f4124742e238ecea Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Fri, 19 Jun 2015 21:49:50 -0700 Subject: [PATCH 025/111] Bug 1150534 - Synchronously decode favicons before calling GetFrame. r=tn --- widget/windows/WinUtils.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/widget/windows/WinUtils.cpp b/widget/windows/WinUtils.cpp index 4bd2ecfe432..bda029aeea2 100644 --- a/widget/windows/WinUtils.cpp +++ b/widget/windows/WinUtils.cpp @@ -1156,7 +1156,9 @@ AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI, NS_ENSURE_SUCCESS(rv, rv); RefPtr surface = - container->GetFrame(imgIContainer::FRAME_FIRST, 0); + container->GetFrame(imgIContainer::FRAME_FIRST, + imgIContainer::FLAG_SYNC_DECODE | + imgIContainer::FLAG_ASYNC_NOTIFY); NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE); RefPtr dataSurface; From 295faeeca9d8e8782563aecaa14730177f716237 Mon Sep 17 00:00:00 2001 From: Nikhil Marathe Date: Fri, 12 Jun 2015 16:28:13 -0700 Subject: [PATCH 026/111] Bug 1173389 - Disable ServiceWorker network interception by default. r=ehsan --- browser/app/profile/firefox.js | 1 + docshell/base/nsDocShell.cpp | 12 ++- docshell/base/nsDocShell.h | 3 + dom/webidl/ServiceWorkerGlobalScope.webidl | 2 + dom/workers/RuntimeService.cpp | 13 +++ dom/workers/WorkerPrivate.h | 7 ++ dom/workers/WorkerScope.cpp | 10 ++ dom/workers/WorkerScope.h | 3 + dom/workers/Workers.h | 1 + .../interception_featuredetect.js | 4 + dom/workers/test/serviceworkers/mochitest.ini | 2 + .../serviceworkers/periodic_update_test.js | 1 + .../serviceworkers/test_app_protocol.html | 1 + .../test/serviceworkers/test_bug1151916.html | 1 + .../test/serviceworkers/test_claim.html | 1 + .../test/serviceworkers/test_claim_fetch.html | 1 + .../serviceworkers/test_claim_oninstall.html | 1 + .../serviceworkers/test_client_focus.html | 1 + .../test/serviceworkers/test_close.html | 1 + .../test/serviceworkers/test_controller.html | 1 + .../test_cross_origin_url_after_redirect.html | 1 + .../test_empty_serviceworker.html | 1 + .../test/serviceworkers/test_fetch_event.html | 1 + .../serviceworkers/test_force_refresh.html | 1 + .../test/serviceworkers/test_https_fetch.html | 1 + .../test_https_fetch_cloned_response.html | 1 + ...test_https_synth_fetch_from_cached_sw.html | 1 + .../serviceworkers/test_importscript.html | 1 + .../serviceworkers/test_install_event.html | 1 + .../test_installation_simple.html | 1 + .../test_interception_featuredetect.html | 96 +++++++++++++++++++ .../test/serviceworkers/test_match_all.html | 1 + .../test_match_all_advanced.html | 1 + .../test_match_all_client_id.html | 1 + .../test_match_all_client_properties.html | 1 + .../test/serviceworkers/test_navigator.html | 1 + .../serviceworkers/test_post_message.html | 1 + .../test_post_message_advanced.html | 1 + .../test_post_message_source.html | 1 + .../serviceworkers/test_request_context.html | 1 + .../test_sandbox_intercept.html | 1 + .../test/serviceworkers/test_sanitize.html | 1 + .../serviceworkers/test_sanitize_domain.html | 1 + .../test/serviceworkers/test_scopes.html | 1 + .../test_service_worker_allowed.html | 1 + .../test_serviceworker_interfaces.html | 1 + .../test_serviceworker_not_sharedworker.html | 1 + .../serviceworkers/test_skip_waiting.html | 1 + .../test_strict_mode_error.html | 1 + .../test/serviceworkers/test_unregister.html | 1 + .../serviceworkers/test_workerUnregister.html | 1 + .../serviceworkers/test_workerUpdate.html | 1 + .../test_workerupdatefoundevent.html | 1 + mobile/android/app/mobile.js | 1 + .../serviceworker/cache-add.https.html.ini | 2 +- .../serviceworker/cache-delete.https.html.ini | 2 +- .../serviceworker/cache-match.https.html.ini | 2 +- .../serviceworker/cache-put.https.html.ini | 2 +- .../cache-storage-keys.https.html.ini | 2 +- .../cache-storage-match.https.html.ini | 2 +- .../cache-storage.https.html.ini | 2 +- 61 files changed, 202 insertions(+), 8 deletions(-) create mode 100644 dom/workers/test/serviceworkers/interception_featuredetect.js create mode 100644 dom/workers/test/serviceworkers/test_interception_featuredetect.html diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 2363b998c59..8d690942907 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1951,4 +1951,5 @@ pref("view_source.tab", true); // Enable Service Workers for desktop on non-release builds #ifndef RELEASE_BUILD pref("dom.serviceWorkers.enabled", true); +pref("dom.serviceWorkers.interception.enabled", true); #endif diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 1fc4a85afa6..d42b9a6b331 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -224,10 +224,12 @@ using namespace mozilla; using namespace mozilla::dom; using mozilla::dom::workers::ServiceWorkerManager; -// True means sUseErrorPages has been added to preferences var cache. +// True means sUseErrorPages and sInterceptionEnabled has been added to +// preferences var cache. static bool gAddedPreferencesVarCache = false; bool nsDocShell::sUseErrorPages = false; +bool nsDocShell::sInterceptionEnabled = false; // Number of documents currently loading static int32_t gNumberOfDocumentsLoading = 0; @@ -5741,6 +5743,9 @@ nsDocShell::Create() Preferences::AddBoolVarCache(&sUseErrorPages, "browser.xul.error_pages.enabled", mUseErrorPages); + Preferences::AddBoolVarCache(&sInterceptionEnabled, + "dom.serviceWorkers.interception.enabled", + false); gAddedPreferencesVarCache = true; } @@ -14047,6 +14052,11 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNavigate, bool* aShouldIntercept) { *aShouldIntercept = false; + // Preffed off. + if (!sInterceptionEnabled) { + return NS_OK; + } + if (mSandboxFlags) { // If we're sandboxed, don't intercept. return NS_OK; diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 3f376c39905..e3809ff5557 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -903,6 +903,9 @@ protected: // Cached value of the "browser.xul.error_pages.enabled" preference. static bool sUseErrorPages; + // Cached value of the "dom.serviceWorkers.interception.enabled" preference. + static bool sInterceptionEnabled; + bool mCreated; bool mAllowSubframes; bool mAllowPlugins; diff --git a/dom/webidl/ServiceWorkerGlobalScope.webidl b/dom/webidl/ServiceWorkerGlobalScope.webidl index 1068c703d91..1f350551875 100644 --- a/dom/webidl/ServiceWorkerGlobalScope.webidl +++ b/dom/webidl/ServiceWorkerGlobalScope.webidl @@ -21,6 +21,8 @@ interface ServiceWorkerGlobalScope : WorkerGlobalScope { attribute EventHandler oninstall; attribute EventHandler onactivate; + + [Func="mozilla::dom::workers::ServiceWorkerGlobalScope::InterceptionEnabled"] attribute EventHandler onfetch; attribute EventHandler onbeforeevicted; attribute EventHandler onevicted; diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 010536c552b..f0d55d67307 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -161,6 +161,7 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 1, #define PREF_WORKERS_LATEST_JS_VERSION "dom.workers.latestJSVersion" #define PREF_INTL_ACCEPT_LANGUAGES "intl.accept_languages" #define PREF_SERVICEWORKERS_ENABLED "dom.serviceWorkers.enabled" +#define PREF_INTERCEPTION_ENABLED "dom.serviceWorkers.interception.enabled" namespace { @@ -1905,6 +1906,10 @@ RuntimeService::Init() WorkerPrefChanged, PREF_SERVICEWORKERS_ENABLED, reinterpret_cast(WORKERPREF_SERVICEWORKERS))) || + NS_FAILED(Preferences::RegisterCallbackAndCall( + WorkerPrefChanged, + PREF_INTERCEPTION_ENABLED, + reinterpret_cast(WORKERPREF_INTERCEPTION_ENABLED))) || NS_FAILED(Preferences::RegisterCallback(LoadRuntimeOptions, PREF_JS_OPTIONS_PREFIX, nullptr)) || @@ -2100,6 +2105,10 @@ RuntimeService::Cleanup() NS_FAILED(Preferences::UnregisterCallback(LoadRuntimeOptions, PREF_WORKERS_OPTIONS_PREFIX, nullptr)) || + NS_FAILED(Preferences::UnregisterCallback( + WorkerPrefChanged, + PREF_INTERCEPTION_ENABLED, + reinterpret_cast(WORKERPREF_INTERCEPTION_ENABLED))) || NS_FAILED(Preferences::UnregisterCallback( WorkerPrefChanged, PREF_SERVICEWORKERS_ENABLED, @@ -2656,6 +2665,10 @@ RuntimeService::WorkerPrefChanged(const char* aPrefName, void* aClosure) key = WORKERPREF_SERVICEWORKERS; sDefaultPreferences[WORKERPREF_SERVICEWORKERS] = Preferences::GetBool(PREF_SERVICEWORKERS_ENABLED, false); + } else if (key == WORKERPREF_INTERCEPTION_ENABLED) { + key = WORKERPREF_INTERCEPTION_ENABLED; + sDefaultPreferences[key] = + Preferences::GetBool(PREF_INTERCEPTION_ENABLED, false); } // This function should never be registered as a callback for a preference it // does not handle. diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 976c0581391..d644df811d9 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -1239,6 +1239,13 @@ public: return mPreferences[WORKERPREF_SERVICEWORKERS]; } + bool + InterceptionEnabled() const + { + AssertIsOnWorkerThread(); + return mPreferences[WORKERPREF_INTERCEPTION_ENABLED]; + } + bool OnLine() const { diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index f5c8f772c6b..98dde6b188f 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -621,6 +621,16 @@ ServiceWorkerGlobalScope::SkipWaiting(ErrorResult& aRv) return promise.forget(); } +// static +bool +ServiceWorkerGlobalScope::InterceptionEnabled(JSContext* aCx, JSObject* aObj) +{ + WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(worker); + worker->AssertIsOnWorkerThread(); + return worker->InterceptionEnabled(); +} + WorkerDebuggerGlobalScope::WorkerDebuggerGlobalScope( WorkerPrivate* aWorkerPrivate) : mWorkerPrivate(aWorkerPrivate) diff --git a/dom/workers/WorkerScope.h b/dom/workers/WorkerScope.h index 8e1a1e42227..f75e1c79302 100644 --- a/dom/workers/WorkerScope.h +++ b/dom/workers/WorkerScope.h @@ -215,6 +215,9 @@ public: WrapGlobalObject(JSContext* aCx, JS::MutableHandle aReflector) override; + static bool + InterceptionEnabled(JSContext* aCx, JSObject* aObj); + void GetScope(nsString& aScope) const { diff --git a/dom/workers/Workers.h b/dom/workers/Workers.h index c25c11f45af..60fa2a1996a 100644 --- a/dom/workers/Workers.h +++ b/dom/workers/Workers.h @@ -198,6 +198,7 @@ enum WorkerPreference WORKERPREF_DUMP = 0, // browser.dom.window.dump.enabled WORKERPREF_DOM_CACHES, // dom.caches.enabled WORKERPREF_SERVICEWORKERS, // dom.serviceWorkers.enabled + WORKERPREF_INTERCEPTION_ENABLED, // dom.serviceWorkers.interception.enabled WORKERPREF_COUNT }; diff --git a/dom/workers/test/serviceworkers/interception_featuredetect.js b/dom/workers/test/serviceworkers/interception_featuredetect.js new file mode 100644 index 00000000000..d720144894f --- /dev/null +++ b/dom/workers/test/serviceworkers/interception_featuredetect.js @@ -0,0 +1,4 @@ +// Only succeeds if onfetch is available. +if (!("onfetch" in self)) { + throw new Error("Not capable of interception"); +} diff --git a/dom/workers/test/serviceworkers/mochitest.ini b/dom/workers/test/serviceworkers/mochitest.ini index 94b300a90b3..a34bd0e664a 100644 --- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -129,6 +129,7 @@ support-files = strict_mode_error.js skip_waiting_installed_worker.js skip_waiting_scope/index.html + interception_featuredetect.js thirdparty/iframe1.html thirdparty/iframe2.html thirdparty/register.html @@ -183,6 +184,7 @@ support-files = [test_skip_waiting.html] [test_strict_mode_error.html] [test_cross_origin_url_after_redirect.html] +[test_interception_featuredetect.html] [test_origin_after_redirect.html] [test_origin_after_redirect_cached.html] [test_origin_after_redirect_to_https.html] diff --git a/dom/workers/test/serviceworkers/periodic_update_test.js b/dom/workers/test/serviceworkers/periodic_update_test.js index 2b0c2e0fa3c..23abaabb3ca 100644 --- a/dom/workers/test/serviceworkers/periodic_update_test.js +++ b/dom/workers/test/serviceworkers/periodic_update_test.js @@ -65,6 +65,7 @@ function runTheTest() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]}, function() { diff --git a/dom/workers/test/serviceworkers/test_app_protocol.html b/dom/workers/test/serviceworkers/test_app_protocol.html index 4a50a4cb7ca..b5b72ff7e03 100644 --- a/dom/workers/test/serviceworkers/test_app_protocol.html +++ b/dom/workers/test/serviceworkers/test_app_protocol.html @@ -27,6 +27,7 @@ function setup() { SpecialPowers.pushPrefEnv({'set': [ ['dom.mozBrowserFramesEnabled', true], ['dom.serviceWorkers.exemptFromPerDomainMax', true], + ["dom.serviceWorkers.interception.enabled", true], ['dom.serviceWorkers.enabled', true], ['dom.serviceWorkers.testing.enabled', true], ['dom.caches.enabled', true], diff --git a/dom/workers/test/serviceworkers/test_bug1151916.html b/dom/workers/test/serviceworkers/test_bug1151916.html index 67cada3e69a..abd3d4da2f9 100644 --- a/dom/workers/test/serviceworkers/test_bug1151916.html +++ b/dom/workers/test/serviceworkers/test_bug1151916.html @@ -94,6 +94,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["dom.caches.enabled", true], diff --git a/dom/workers/test/serviceworkers/test_claim.html b/dom/workers/test/serviceworkers/test_claim.html index d7015850fc1..1c0aa97c7c8 100644 --- a/dom/workers/test/serviceworkers/test_claim.html +++ b/dom/workers/test/serviceworkers/test_claim.html @@ -162,6 +162,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_claim_fetch.html b/dom/workers/test/serviceworkers/test_claim_fetch.html index 8db6d304e47..9c7d925d002 100644 --- a/dom/workers/test/serviceworkers/test_claim_fetch.html +++ b/dom/workers/test/serviceworkers/test_claim_fetch.html @@ -88,6 +88,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_claim_oninstall.html b/dom/workers/test/serviceworkers/test_claim_oninstall.html index 584461424f1..a2bd4f21578 100644 --- a/dom/workers/test/serviceworkers/test_claim_oninstall.html +++ b/dom/workers/test/serviceworkers/test_claim_oninstall.html @@ -63,6 +63,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_client_focus.html b/dom/workers/test/serviceworkers/test_client_focus.html index e1b08c7ca38..be0f18f69d7 100644 --- a/dom/workers/test/serviceworkers/test_client_focus.html +++ b/dom/workers/test/serviceworkers/test_client_focus.html @@ -86,6 +86,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_close.html b/dom/workers/test/serviceworkers/test_close.html index d2f72b9ef93..1ea6efde0c3 100644 --- a/dom/workers/test/serviceworkers/test_close.html +++ b/dom/workers/test/serviceworkers/test_close.html @@ -54,6 +54,7 @@ onload = function() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_controller.html b/dom/workers/test/serviceworkers/test_controller.html index 789d7746dae..1840bbd1bf9 100644 --- a/dom/workers/test/serviceworkers/test_controller.html +++ b/dom/workers/test/serviceworkers/test_controller.html @@ -74,6 +74,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_cross_origin_url_after_redirect.html b/dom/workers/test/serviceworkers/test_cross_origin_url_after_redirect.html index e56bb84ca05..bf9c21d058f 100644 --- a/dom/workers/test/serviceworkers/test_cross_origin_url_after_redirect.html +++ b/dom/workers/test/serviceworkers/test_cross_origin_url_after_redirect.html @@ -40,6 +40,7 @@ onload = function() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_empty_serviceworker.html b/dom/workers/test/serviceworkers/test_empty_serviceworker.html index e4295189618..a06ee4f1323 100644 --- a/dom/workers/test/serviceworkers/test_empty_serviceworker.html +++ b/dom/workers/test/serviceworkers/test_empty_serviceworker.html @@ -36,6 +36,7 @@ onload = function() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_fetch_event.html b/dom/workers/test/serviceworkers/test_fetch_event.html index 764be87b131..169cb455796 100644 --- a/dom/workers/test/serviceworkers/test_fetch_event.html +++ b/dom/workers/test/serviceworkers/test_fetch_event.html @@ -73,6 +73,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_force_refresh.html b/dom/workers/test/serviceworkers/test_force_refresh.html index 05caf0e6ac4..e39330e5a34 100644 --- a/dom/workers/test/serviceworkers/test_force_refresh.html +++ b/dom/workers/test/serviceworkers/test_force_refresh.html @@ -74,6 +74,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["dom.caches.enabled", true], diff --git a/dom/workers/test/serviceworkers/test_https_fetch.html b/dom/workers/test/serviceworkers/test_https_fetch.html index c5de59e49c8..5b0dc31b1b4 100644 --- a/dom/workers/test/serviceworkers/test_https_fetch.html +++ b/dom/workers/test/serviceworkers/test_https_fetch.html @@ -47,6 +47,7 @@ onload = function() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["dom.caches.enabled", true] diff --git a/dom/workers/test/serviceworkers/test_https_fetch_cloned_response.html b/dom/workers/test/serviceworkers/test_https_fetch_cloned_response.html index 1cf1dbef139..410db7a2769 100644 --- a/dom/workers/test/serviceworkers/test_https_fetch_cloned_response.html +++ b/dom/workers/test/serviceworkers/test_https_fetch_cloned_response.html @@ -45,6 +45,7 @@ onload = function() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["dom.caches.enabled", true] diff --git a/dom/workers/test/serviceworkers/test_https_synth_fetch_from_cached_sw.html b/dom/workers/test/serviceworkers/test_https_synth_fetch_from_cached_sw.html index a968ac1a8ee..100ec57fea9 100644 --- a/dom/workers/test/serviceworkers/test_https_synth_fetch_from_cached_sw.html +++ b/dom/workers/test/serviceworkers/test_https_synth_fetch_from_cached_sw.html @@ -58,6 +58,7 @@ onload = function() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["dom.caches.enabled", true] diff --git a/dom/workers/test/serviceworkers/test_importscript.html b/dom/workers/test/serviceworkers/test_importscript.html index 5d2d5b3522c..7a363eed2a6 100644 --- a/dom/workers/test/serviceworkers/test_importscript.html +++ b/dom/workers/test/serviceworkers/test_importscript.html @@ -63,6 +63,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_install_event.html b/dom/workers/test/serviceworkers/test_install_event.html index 86532002d69..67e41e21ef7 100644 --- a/dom/workers/test/serviceworkers/test_install_event.html +++ b/dom/workers/test/serviceworkers/test_install_event.html @@ -103,6 +103,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_installation_simple.html b/dom/workers/test/serviceworkers/test_installation_simple.html index f5dee7e5267..c4d89bf9137 100644 --- a/dom/workers/test/serviceworkers/test_installation_simple.html +++ b/dom/workers/test/serviceworkers/test_installation_simple.html @@ -201,6 +201,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.messageChannel.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] diff --git a/dom/workers/test/serviceworkers/test_interception_featuredetect.html b/dom/workers/test/serviceworkers/test_interception_featuredetect.html new file mode 100644 index 00000000000..61dd04366b6 --- /dev/null +++ b/dom/workers/test/serviceworkers/test_interception_featuredetect.html @@ -0,0 +1,96 @@ + + + + + + Bug 1173389 - Test fetch interception feature detection. + + + + +

+ +

+
+
+ + + diff --git a/dom/workers/test/serviceworkers/test_match_all.html b/dom/workers/test/serviceworkers/test_match_all.html index f4e65a730e9..47c195cfb35 100644 --- a/dom/workers/test/serviceworkers/test_match_all.html +++ b/dom/workers/test/serviceworkers/test_match_all.html @@ -70,6 +70,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_match_all_advanced.html b/dom/workers/test/serviceworkers/test_match_all_advanced.html index a458ed70ba4..c68e691e3c2 100644 --- a/dom/workers/test/serviceworkers/test_match_all_advanced.html +++ b/dom/workers/test/serviceworkers/test_match_all_advanced.html @@ -90,6 +90,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_match_all_client_id.html b/dom/workers/test/serviceworkers/test_match_all_client_id.html index c3cc5756a23..9807820c66a 100644 --- a/dom/workers/test/serviceworkers/test_match_all_client_id.html +++ b/dom/workers/test/serviceworkers/test_match_all_client_id.html @@ -81,6 +81,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_match_all_client_properties.html b/dom/workers/test/serviceworkers/test_match_all_client_properties.html index 14e3445a4b7..51f4e3fc5d9 100644 --- a/dom/workers/test/serviceworkers/test_match_all_client_properties.html +++ b/dom/workers/test/serviceworkers/test_match_all_client_properties.html @@ -88,6 +88,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_navigator.html b/dom/workers/test/serviceworkers/test_navigator.html index 164f41bcd2c..2b286bd9363 100644 --- a/dom/workers/test/serviceworkers/test_navigator.html +++ b/dom/workers/test/serviceworkers/test_navigator.html @@ -28,6 +28,7 @@ SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true] ]}, function() { checkEnabled(); diff --git a/dom/workers/test/serviceworkers/test_post_message.html b/dom/workers/test/serviceworkers/test_post_message.html index 7df4bef1fcc..1e2fc3c6903 100644 --- a/dom/workers/test/serviceworkers/test_post_message.html +++ b/dom/workers/test/serviceworkers/test_post_message.html @@ -69,6 +69,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_post_message_advanced.html b/dom/workers/test/serviceworkers/test_post_message_advanced.html index ca769586159..2f63dc5c57d 100644 --- a/dom/workers/test/serviceworkers/test_post_message_advanced.html +++ b/dom/workers/test/serviceworkers/test_post_message_advanced.html @@ -98,6 +98,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_post_message_source.html b/dom/workers/test/serviceworkers/test_post_message_source.html index 4353e59b498..aec3820e9e1 100644 --- a/dom/workers/test/serviceworkers/test_post_message_source.html +++ b/dom/workers/test/serviceworkers/test_post_message_source.html @@ -57,6 +57,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_request_context.html b/dom/workers/test/serviceworkers/test_request_context.html index 904859b7f24..6f3dc785ca2 100644 --- a/dom/workers/test/serviceworkers/test_request_context.html +++ b/dom/workers/test/serviceworkers/test_request_context.html @@ -88,6 +88,7 @@ ["dom.image.picture.enabled", true], ["dom.image.srcset.enabled", true], ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_sandbox_intercept.html b/dom/workers/test/serviceworkers/test_sandbox_intercept.html index 273df53ff51..73c581c92e5 100644 --- a/dom/workers/test/serviceworkers/test_sandbox_intercept.html +++ b/dom/workers/test/serviceworkers/test_sandbox_intercept.html @@ -40,6 +40,7 @@ onload = function() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_sanitize.html b/dom/workers/test/serviceworkers/test_sanitize.html index 732785faa78..8168e497cea 100644 --- a/dom/workers/test/serviceworkers/test_sanitize.html +++ b/dom/workers/test/serviceworkers/test_sanitize.html @@ -75,6 +75,7 @@ SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]}, function() { diff --git a/dom/workers/test/serviceworkers/test_sanitize_domain.html b/dom/workers/test/serviceworkers/test_sanitize_domain.html index 70e108b717d..d55873203a8 100644 --- a/dom/workers/test/serviceworkers/test_sanitize_domain.html +++ b/dom/workers/test/serviceworkers/test_sanitize_domain.html @@ -78,6 +78,7 @@ SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]}, function() { diff --git a/dom/workers/test/serviceworkers/test_scopes.html b/dom/workers/test/serviceworkers/test_scopes.html index 2d8116f8373..7bd389390dd 100644 --- a/dom/workers/test/serviceworkers/test_scopes.html +++ b/dom/workers/test/serviceworkers/test_scopes.html @@ -111,6 +111,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_service_worker_allowed.html b/dom/workers/test/serviceworkers/test_service_worker_allowed.html index eca94ebb436..98a850d7a34 100644 --- a/dom/workers/test/serviceworkers/test_service_worker_allowed.html +++ b/dom/workers/test/serviceworkers/test_service_worker_allowed.html @@ -67,6 +67,7 @@ ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ]}, runTest);
diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.html b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.html index 60a5dfd1f22..f998d8f6636 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.html +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.html @@ -104,6 +104,7 @@ // force creation of our own Navigator object before our prefs are set. var prefs = [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]; diff --git a/dom/workers/test/serviceworkers/test_serviceworker_not_sharedworker.html b/dom/workers/test/serviceworkers/test_serviceworker_not_sharedworker.html index 96dd9f15992..da8c3d0af1b 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_not_sharedworker.html +++ b/dom/workers/test/serviceworkers/test_serviceworker_not_sharedworker.html @@ -56,6 +56,7 @@ onload = function() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_skip_waiting.html b/dom/workers/test/serviceworkers/test_skip_waiting.html index 7707d603505..f4081ee26fe 100644 --- a/dom/workers/test/serviceworkers/test_skip_waiting.html +++ b/dom/workers/test/serviceworkers/test_skip_waiting.html @@ -86,6 +86,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_strict_mode_error.html b/dom/workers/test/serviceworkers/test_strict_mode_error.html index 77bf8ab07bb..68cb4bea3e5 100644 --- a/dom/workers/test/serviceworkers/test_strict_mode_error.html +++ b/dom/workers/test/serviceworkers/test_strict_mode_error.html @@ -29,6 +29,7 @@ onload = function() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_unregister.html b/dom/workers/test/serviceworkers/test_unregister.html index 8366f50c1ce..b6263d4752e 100644 --- a/dom/workers/test/serviceworkers/test_unregister.html +++ b/dom/workers/test/serviceworkers/test_unregister.html @@ -128,6 +128,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_workerUnregister.html b/dom/workers/test/serviceworkers/test_workerUnregister.html index 947861c176b..631d961a677 100644 --- a/dom/workers/test/serviceworkers/test_workerUnregister.html +++ b/dom/workers/test/serviceworkers/test_workerUnregister.html @@ -72,6 +72,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_workerUpdate.html b/dom/workers/test/serviceworkers/test_workerUpdate.html index 16aae86fee7..eeccbc5d56a 100644 --- a/dom/workers/test/serviceworkers/test_workerUpdate.html +++ b/dom/workers/test/serviceworkers/test_workerUpdate.html @@ -45,6 +45,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true] ]}, runTest); diff --git a/dom/workers/test/serviceworkers/test_workerupdatefoundevent.html b/dom/workers/test/serviceworkers/test_workerupdatefoundevent.html index 3361eba08a3..0134a726490 100644 --- a/dom/workers/test/serviceworkers/test_workerupdatefoundevent.html +++ b/dom/workers/test/serviceworkers/test_workerupdatefoundevent.html @@ -75,6 +75,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ]}, runTest); diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index 8dd65c22ba6..9138869f586 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -918,4 +918,5 @@ pref("consoleservice.logcat", true); // Enable Service Workers for Android on non-release builds #ifndef RELEASE_BUILD pref("dom.serviceWorkers.enabled", true); +pref("dom.serviceWorkers.interception.enabled", true); #endif diff --git a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-add.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-add.https.html.ini index e0a2f554998..2dc41a01c86 100644 --- a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-add.https.html.ini +++ b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-add.https.html.ini @@ -1,3 +1,3 @@ [cache-add.https.html] type: testharness - prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] + prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.interception.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] diff --git a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-delete.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-delete.https.html.ini index 01a553609de..4deb7c86674 100644 --- a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-delete.https.html.ini +++ b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-delete.https.html.ini @@ -1,3 +1,3 @@ [cache-delete.https.html] type: testharness - prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] + prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.interception.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] diff --git a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-match.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-match.https.html.ini index 6dac66d34a5..52b6da31c22 100644 --- a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-match.https.html.ini +++ b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-match.https.html.ini @@ -1,3 +1,3 @@ [cache-match.https.html] type: testharness - prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] + prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.interception.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] diff --git a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-put.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-put.https.html.ini index c5ec54eac63..4414167e39b 100644 --- a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-put.https.html.ini +++ b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-put.https.html.ini @@ -1,3 +1,3 @@ [cache-put.https.html] type: testharness - prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] + prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.interception.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] diff --git a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-keys.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-keys.https.html.ini index 09a9000d4e0..bfd50d10e30 100644 --- a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-keys.https.html.ini +++ b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-keys.https.html.ini @@ -1,3 +1,3 @@ [cache-storage-keys.https.html] type: testharness - prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] + prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.interception.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] diff --git a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-match.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-match.https.html.ini index 7c23b404d32..435b29a8cfb 100644 --- a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-match.https.html.ini +++ b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-match.https.html.ini @@ -1,3 +1,3 @@ [cache-storage-match.https.html] type: testharness - prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] + prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.interception.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] diff --git a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage.https.html.ini b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage.https.html.ini index d6c3ee54cf1..f651f5610ba 100644 --- a/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage.https.html.ini +++ b/testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage.https.html.ini @@ -1,3 +1,3 @@ [cache-storage.https.html] type: testharness - prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] + prefs: [dom.serviceWorkers.enabled: true, dom.serviceWorkers.interception.enabled: true, dom.serviceWorkers.exemptFromPerDomainMax:true, dom.caches.enabled:true] From 1ee1eb6edbf4141b2e0bd6f27c6ada2ee5916a8b Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Sat, 20 Jun 2015 09:16:50 +0200 Subject: [PATCH 027/111] Bug 1174093 - Don't recurse into caps/tests/mochitest during the build; r=mshal --- caps/moz.build | 4 ++-- caps/tests/mochitest/moz.build | 9 --------- 2 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 caps/tests/mochitest/moz.build diff --git a/caps/moz.build b/caps/moz.build index c50409655d5..b8005c506ae 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -4,8 +4,8 @@ # 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/. -TEST_DIRS += ['tests/mochitest'] - +MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini'] +MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini'] XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] XPIDL_SOURCES += [ diff --git a/caps/tests/mochitest/moz.build b/caps/tests/mochitest/moz.build deleted file mode 100644 index 76deffb6d1f..00000000000 --- a/caps/tests/mochitest/moz.build +++ /dev/null @@ -1,9 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -MOCHITEST_MANIFESTS += ['mochitest.ini'] -MOCHITEST_CHROME_MANIFESTS += ['chrome.ini'] - From f676f86358bd337a6effc16b59d4f9c261b09622 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Sat, 20 Jun 2015 09:16:50 +0200 Subject: [PATCH 028/111] Bug 1173363 - Don't go through nsIDOMDocument in nsContentUtils::FlushLayoutForTree; r=khuey --- dom/base/nsContentUtils.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index eb598dce06c..c7991278c59 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -6313,10 +6313,7 @@ nsContentUtils::FlushLayoutForTree(nsIDOMWindow* aWindow) // is O(N^2) in docshell tree depth. However, the docshell tree is // usually pretty shallow. - nsCOMPtr domDoc; - aWindow->GetDocument(getter_AddRefs(domDoc)); - nsCOMPtr doc = do_QueryInterface(domDoc); - if (doc) { + if (nsCOMPtr doc = piWin->GetDoc()) { doc->FlushPendingNotifications(Flush_Layout); } From 53af35efa2dad4eb1f734381a424e188d93647f4 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Sat, 20 Jun 2015 09:16:50 +0200 Subject: [PATCH 029/111] Bug 1173344 - Remove an intermediary root from nsXBLProtoImplField's FieldGetterImpl; r=jandem --- dom/xbl/nsXBLProtoImplField.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/dom/xbl/nsXBLProtoImplField.cpp b/dom/xbl/nsXBLProtoImplField.cpp index 5b57118f8d8..ed79c8db100 100644 --- a/dom/xbl/nsXBLProtoImplField.cpp +++ b/dom/xbl/nsXBLProtoImplField.cpp @@ -245,12 +245,7 @@ FieldGetterImpl(JSContext *cx, JS::CallArgs args) return true; } - JS::Rooted v(cx); - if (!JS_GetPropertyById(cx, thisObj, id, &v)) { - return false; - } - args.rval().set(v); - return true; + return JS_GetPropertyById(cx, thisObj, id, args.rval()); } static bool From 909e2c851ded11512b45589356e3c052f2db80db Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Sat, 20 Jun 2015 09:16:51 +0200 Subject: [PATCH 030/111] Bug 1172536 - Stop using for each loops in layout; r=roc These are SpiderMonkey-proprietary legacy feature which has been deprecated and is expected to be removed in due course. This commit also fixes a number of bugs in test_bug708874.xul. In particular, because of the semicolon after the for head, the (alleged) loop body was only executed for the final element of the array ({}), and because each of the functions under test threw an exception, only the first call was executed. I do not know of a way to test the changes in frame-verify.js, so I can't guarantee they actually work. --- .../chrome_content_integration_window.xul | 2 +- .../chrome/chrome_over_plugin_window.xul | 2 +- .../chrome/default_background_window.xul | 2 +- .../tests/chrome/no_clip_iframe_window.xul | 2 +- layout/generic/frame-verify.js | 8 ++++---- .../inspector/tests/chrome/test_bug708874.xul | 19 +++++++++---------- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/layout/base/tests/chrome/chrome_content_integration_window.xul b/layout/base/tests/chrome/chrome_content_integration_window.xul index d53efac084f..23cd21e6e6c 100644 --- a/layout/base/tests/chrome/chrome_content_integration_window.xul +++ b/layout/base/tests/chrome/chrome_content_integration_window.xul @@ -21,7 +21,7 @@