| author | Ryan VanderMeulen <ryanvm@gmail.com> |
| Wed, 31 Aug 2016 22:33:17 -0400 | |
| changeset 312143 | b7f7ae14590aced450bb0b0469dfb38edd2c0ace |
| parent 312071 | 9e00b305da24074ae5aba1227beb5e096b026100 (current diff) |
| parent 312142 | cbe18f18111247e3b541cf0e5d3c97b0c1478e46 (diff) |
| child 312144 | 561fa3ce8c0906c35af942bb44e84254afc25541 |
| child 312153 | a7ef41c19c53686fade038ef68ffc91a36e3fcab |
| child 312185 | 9f33ab9fd502d2a4c38aef7744ab68c0aaa78234 |
| child 312223 | 981dabd02177ddd384d4709bfb827a11ef6f417a |
| push id | 30632 |
| push user | ryanvm@gmail.com |
| push date | Thu, 01 Sep 2016 02:33:28 +0000 |
| treeherder | mozilla-central@b7f7ae14590a [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| reviewers | merge |
| milestone | 51.0a1 |
| first release with | nightly linux32
b7f7ae14590a
/
51.0a1
/
20160901030202
/
files
nightly linux64
b7f7ae14590a
/
51.0a1
/
20160901030202
/
files
nightly mac
b7f7ae14590a
/
51.0a1
/
20160901030202
/
files
nightly win32
b7f7ae14590a
/
51.0a1
/
20160901030202
/
files
nightly win64
b7f7ae14590a
/
51.0a1
/
20160901030202
/
files
|
| last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| releases | nightly linux32
51.0a1
/
20160901030202
/
pushlog to previous
nightly linux64
51.0a1
/
20160901030202
/
pushlog to previous
nightly mac
51.0a1
/
20160901030202
/
pushlog to previous
nightly win32
51.0a1
/
20160901030202
/
pushlog to previous
nightly win64
51.0a1
/
20160901030202
/
pushlog to previous
|
| browser/base/content/test/newtab/head.js | file | annotate | diff | comparison | revisions | |
| dom/base/test/test_getFeature_with_perm.html | file | annotate | diff | comparison | revisions | |
| dom/base/test/test_hasFeature.html | file | annotate | diff | comparison | revisions | |
| dom/html/HTMLMediaElement.cpp | file | annotate | diff | comparison | revisions | |
| js/src/jit-test/tests/jaeger/bug601400.js | file | annotate | diff | comparison | revisions | |
| layout/svg/SVGTextFrame.cpp | file | annotate | diff | comparison | revisions | |
| mobile/android/chrome/content/browser.js | file | annotate | diff | comparison | revisions | |
| testing/marionette/listener.js | file | annotate | diff | comparison | revisions | |
| testing/web-platform/meta/html/semantics/selectors/pseudo-classes/indeterminate.html.ini | file | annotate | diff | comparison | revisions |
--- a/addon-sdk/source/lib/sdk/content/l10n-html.js +++ b/addon-sdk/source/lib/sdk/content/l10n-html.js @@ -2,21 +2,25 @@ * 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"; module.metadata = { "stability": "unstable" }; -const { Ci } = require("chrome"); +const { Ci, Cc, Cu } = require("chrome"); const core = require("../l10n/core"); const { loadSheet, removeSheet } = require("../stylesheet/utils"); const { process, frames } = require("../remote/child"); -const { Services } = require("resource://gre/modules/Services.jsm"); +var observerService = Cc["@mozilla.org/observer-service;1"] + .getService(Ci.nsIObserverService); +const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm"); +const addObserver = ShimWaiver.getProperty(observerService, "addObserver"); +const removeObserver = ShimWaiver.getProperty(observerService, "removeObserver"); const assetsURI = require('../self').data.url(); const hideSheetUri = "data:text/css,:root {visibility: hidden !important;}"; function translateElementAttributes(element) { // Translateable attributes const attrList = ['title', 'accesskey', 'alt', 'label', 'placeholder']; @@ -110,20 +114,20 @@ function onContentWindow(document) { // Listen to creation of content documents in order to translate them as soon // as possible in their loading process const ON_CONTENT = "document-element-inserted"; let enabled = false; function enable() { if (enabled) return; - Services.obs.addObserver(onContentWindow, ON_CONTENT, false); + addObserver(onContentWindow, ON_CONTENT, false); enabled = true; } process.port.on("sdk/l10n/html/enable", enable); function disable() { if (!enabled) return; - Services.obs.removeObserver(onContentWindow, ON_CONTENT); + removeObserver(onContentWindow, ON_CONTENT); enabled = false; } process.port.on("sdk/l10n/html/disable", disable);
--- a/addon-sdk/source/lib/sdk/deprecated/window-utils.js +++ b/addon-sdk/source/lib/sdk/deprecated/window-utils.js @@ -57,17 +57,16 @@ function browserWindowIterator() { exports.browserWindowIterator = browserWindowIterator; function WindowTracker(delegate) { if (!(this instanceof WindowTracker)) { return new WindowTracker(delegate); } this._delegate = delegate; - this._loadingWindows = []; for (let window of getWindows()) this._regWindow(window); windowWatcher.registerNotification(this); this._onToplevelWindowReady = this._onToplevelWindowReady.bind(this); events.on('toplevel-window-ready', this._onToplevelWindowReady); require('../system/unload').ensure(this); @@ -76,27 +75,22 @@ function WindowTracker(delegate) { }; WindowTracker.prototype = { _regLoadingWindow: function _regLoadingWindow(window) { // Bug 834961: ignore private windows when they are not supported if (ignoreWindow(window)) return; - this._loadingWindows.push(window); window.addEventListener('load', this, true); }, _unregLoadingWindow: function _unregLoadingWindow(window) { - var index = this._loadingWindows.indexOf(window); - - if (index != -1) { - this._loadingWindows.splice(index, 1); - window.removeEventListener('load', this, true); - } + // This may have no effect if we ignored the window in _regLoadingWindow(). + window.removeEventListener('load', this, true); }, _regWindow: function _regWindow(window) { // Bug 834961: ignore private windows when they are not supported if (ignoreWindow(window)) return; if (window.document.readyState == 'complete') {
--- a/browser/base/content/newtab/dropTargetShim.js +++ b/browser/base/content/newtab/dropTargetShim.js @@ -216,17 +216,17 @@ var gDropTargetShim = { /** * Dispatches a custom DragEvent on the given target node. * @param aEvent The source event. * @param aType The event type. * @param aTarget The target node that receives the event. */ _dispatchEvent: function (aEvent, aType, aTarget) { let node = aTarget.node; - let event = document.createEvent("DragEvents"); + let event = document.createEvent("DragEvent"); // The event should not bubble to prevent recursion. event.initDragEvent(aType, false, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, node, aEvent.dataTransfer); node.dispatchEvent(event); } };
--- a/browser/base/content/test/newtab/browser_newtab_bug723121.js +++ b/browser/base/content/test/newtab/browser_newtab_bug723121.js @@ -14,17 +14,17 @@ add_task(function* () { let link = site.querySelector(".newtab-link"); function checkGridLocked(aLocked, aMessage) { Assert.equal(grid.node.hasAttribute("locked"), aLocked, aMessage); } function sendDragEvent(aEventType, aTarget) { let dataTransfer = new content.DataTransfer(aEventType, false); - let event = content.document.createEvent("DragEvents"); + let event = content.document.createEvent("DragEvent"); event.initDragEvent(aEventType, true, true, content, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); aTarget.dispatchEvent(event); } checkGridLocked(false, "grid is unlocked"); sendDragEvent("dragstart", link);
--- a/browser/base/content/test/newtab/browser_newtab_bug725996.js +++ b/browser/base/content/test/newtab/browser_newtab_bug725996.js @@ -7,17 +7,17 @@ add_task(function* () { yield* addNewTabPageTab(); yield* checkGrid("0,1,2,3,4,5,6,7,8"); function doDrop(data) { return ContentTask.spawn(gBrowser.selectedBrowser, { data: data }, function*(args) { let dataTransfer = new content.DataTransfer("dragstart", false); dataTransfer.mozSetDataAt("text/x-moz-url", args.data, 0); - let event = content.document.createEvent("DragEvents"); + let event = content.document.createEvent("DragEvent"); event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); let target = content.gGrid.cells[0].node; target.dispatchEvent(event); }); }
--- a/browser/base/content/test/newtab/browser_newtab_bug765628.js +++ b/browser/base/content/test/newtab/browser_newtab_bug765628.js @@ -10,17 +10,17 @@ add_task(function* () { yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() { const BAD_DRAG_DATA = "javascript:alert('h4ck0rz');\nbad stuff"; const GOOD_DRAG_DATA = "http://example99.com/\nsite 99"; function sendDropEvent(aCellIndex, aDragData) { let dataTransfer = new content.DataTransfer("dragstart", false); dataTransfer.mozSetDataAt("text/x-moz-url", aDragData, 0); - let event = content.document.createEvent("DragEvents"); + let event = content.document.createEvent("DragEvent"); event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); let target = content.gGrid.cells[aCellIndex].node; target.dispatchEvent(event); } sendDropEvent(0, BAD_DRAG_DATA);
--- a/browser/base/content/test/newtab/browser_newtab_drag_drop.js +++ b/browser/base/content/test/newtab/browser_newtab_drag_drop.js @@ -73,23 +73,23 @@ add_task(function* () { yield doDragEvent(0, 4); yield* checkGrid("3,1p,2p,4,0p,5p,6,7,8"); }); function doDragEvent(sourceIndex, dropIndex) { return ContentTask.spawn(gBrowser.selectedBrowser, { sourceIndex: sourceIndex, dropIndex: dropIndex }, function*(args) { let dataTransfer = new content.DataTransfer("dragstart", false); - let event = content.document.createEvent("DragEvents"); + let event = content.document.createEvent("DragEvent"); event.initDragEvent("dragstart", true, true, content, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); let target = content.gGrid.cells[args.sourceIndex].site.node; target.dispatchEvent(event); - event = content.document.createEvent("DragEvents"); + event = content.document.createEvent("DragEvent"); event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); target = content.gGrid.cells[args.dropIndex].node; target.dispatchEvent(event); }); }
--- a/browser/base/content/test/newtab/head.js +++ b/browser/base/content/test/newtab/head.js @@ -414,17 +414,17 @@ function* simulateExternalDrop(aDestInde let iframe = doc.createElement("iframe"); function iframeLoaded() { let link = iframe.contentDocument.getElementById("link"); let dataTransfer = new iframe.contentWindow.DataTransfer("dragstart", false); dataTransfer.mozSetDataAt("text/x-moz-url", "http://example99.com/", 0); - let event = content.document.createEvent("DragEvents"); + let event = content.document.createEvent("DragEvent"); event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); let target = content.gGrid.cells[dropIndex].node; target.dispatchEvent(event); iframe.remove();
--- a/browser/components/extensions/schemas/tabs.json +++ b/browser/components/extensions/schemas/tabs.json @@ -829,17 +829,17 @@ "name": "callback", "optional": true, "description": "Called after all the JavaScript has been executed.", "parameters": [ { "name": "result", "optional": true, "type": "array", - "items": {"type": "any", "minimum": 0}, + "items": {"type": "any"}, "description": "The result of the script in every injected frame." } ] } ] }, { "name": "insertCSS",
--- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -2609,16 +2609,55 @@ ContentPermissionPrompt.prototype = { } secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST); this._showPrompt(aRequest, message, "geo", actions, "geolocation", "geo-notification-icon", options); }, + _promptFlyWebPublishServer : function(aRequest) { + var message = "Would you like to let this site start a server accessible to nearby devices and people?"; + var actions = [ + { + stringId: "flyWebPublishServer.allowPublishServer", + action: Ci.nsIPermissionManager.ALLOW_ACTION, + expireType: Ci.nsIPermissionManager.EXPIRE_SESSION + }, + { + stringId: "flyWebPublishServer.denyPublishServer", + action: Ci.nsIPermissionManager.DENY_ACTION, + expireType: Ci.nsIPermissionManager.EXPIRE_SESSION + } + ]; + + let options = { + learnMoreURL: "https://flyweb.github.io", + popupIconURL: "chrome://flyweb/skin/icon-64.png" + }; + + let browser = this._getBrowserForRequest(aRequest); + let chromeDoc = browser.ownerDocument; + let iconElem = chromeDoc.getElementById("flyweb-publish-server-notification-icon"); + if (!iconElem) { + let notificationPopupBox = chromeDoc.getElementById("notification-popup-box"); + let notificationIcon = chromeDoc.createElement("image"); + notificationIcon.setAttribute("id", "flyweb-publish-server-notification-icon"); + notificationIcon.setAttribute("src", "chrome://flyweb/skin/icon-64.png"); + notificationIcon.setAttribute("class", "notification-anchor-icon flyweb-publish-server-icon"); + notificationIcon.setAttribute("style", "filter: url(chrome://browser/skin/filters.svg#fill); fill: currentColor; opacity: .4;"); + notificationIcon.setAttribute("role", "button"); + notificationIcon.setAttribute("aria-label", "View the publish-server request"); + notificationPopupBox.appendChild(notificationIcon); + } + + this._showPrompt(aRequest, message, "flyweb-publish-server", actions, "flyweb-publish-server", + "flyweb-publish-server-notification-icon", options); + }, + _promptWebNotifications : function(aRequest) { var message = gBrowserBundle.GetStringFromName("webNotifications.receiveFromSite"); var actions; var browser = this._getBrowserForRequest(aRequest); // Only show "allow for session" in PB mode, we don't // support "allow for session" in non-PB mode. @@ -2673,17 +2712,18 @@ ContentPermissionPrompt.prototype = { let types = request.types.QueryInterface(Ci.nsIArray); if (types.length != 1) { request.cancel(); return; } let perm = types.queryElementAt(0, Ci.nsIContentPermissionType); const kFeatureKeys = { "geolocation" : "geo", - "desktop-notification" : "desktop-notification" + "desktop-notification" : "desktop-notification", + "flyweb-publish-server": "flyweb-publish-server" }; // Make sure that we support the request. if (!(perm.type in kFeatureKeys)) { return; } var requestingPrincipal = request.principal; @@ -2716,16 +2756,21 @@ ContentPermissionPrompt.prototype = { // Show the prompt. switch (perm.type) { case "geolocation": this._promptGeo(request); break; case "desktop-notification": this._promptWebNotifications(request); break; + case "flyweb-publish-server": + if (AppConstants.NIGHTLY_BUILD) { + this._promptFlyWebPublishServer(request); + } + break; } }, }; var DefaultBrowserCheck = { get OPTIONPOPUP() { return "defaultBrowserNotificationPopup" }, _setAsDefaultTimer: null,
--- a/browser/extensions/e10srollout/bootstrap.js +++ b/browser/extensions/e10srollout/bootstrap.js @@ -8,16 +8,17 @@ const {classes: Cc, interfaces: Ci, util Cu.import("resource://gre/modules/Preferences.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/UpdateUtils.jsm"); // The amount of people to be part of e10s const TEST_THRESHOLD = { "beta" : 0.5, // 50% + "release" : 1.0, // 100% }; const ADDON_ROLLOUT_POLICY = { "beta" : "2a", // Set 2 + any WebExtension }; const PREF_COHORT_SAMPLE = "e10s.rollout.cohortSample"; const PREF_COHORT_NAME = "e10s.rollout.cohort";
--- a/browser/extensions/e10srollout/install.rdf.in +++ b/browser/extensions/e10srollout/install.rdf.in @@ -5,17 +5,17 @@ #filter substitution <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> <Description about="urn:mozilla:install-manifest"> <em:id>e10srollout@mozilla.org</em:id> - <em:version>1.0</em:version> + <em:version>1.2</em:version> <em:type>2</em:type> <em:bootstrap>true</em:bootstrap> <em:multiprocessCompatible>true</em:multiprocessCompatible> <!-- Target Application this theme can install into, with minimum and maximum supported versions. --> <em:targetApplication> <Description>
--- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -373,16 +373,26 @@ geolocation.shareLocation=Share Location geolocation.shareLocation.accesskey=a geolocation.alwaysShareLocation=Always Share Location geolocation.alwaysShareLocation.accesskey=A geolocation.neverShareLocation=Never Share Location geolocation.neverShareLocation.accesskey=N geolocation.shareWithSite2=Would you like to share your location with this site? geolocation.shareWithFile2=Would you like to share your location with this file? +# FlyWeb UI +# LOCALIZATION NOTE (flyWebPublishServer.allowPublishServer): This is an experimental feature only shipping in Nightly, and doesn't need translation. +flyWebPublishServer.allowPublishServer=Allow Server +# LOCALIZATION NOTE (flyWebPublishServer.allowPublishServer.accessKey): This is an experimental feature only shipping in Nightly, and doesn't need translation. +flyWebPublishServer.allowPublishServer.accesskey=A +# LOCALIZATION NOTE (flyWebPublishServer.denyPublishServer): This is an experimental feature only shipping in Nightly, and doesn't need translation. +flyWebPublishServer.denyPublishServer=Block Server +# LOCALIZATION NOTE (flyWebPublishServer.denyPublishServer.accessKey): This is an experimental feature only shipping in Nightly, and doesn't need translation. +flyWebPublishServer.denyPublishServer.accesskey=B + webNotifications.receiveForSession=Receive for this session webNotifications.receiveForSession.accesskey=s webNotifications.alwaysReceive=Always Receive Notifications webNotifications.alwaysReceive.accesskey=A webNotifications.neverShow=Always Block Notifications webNotifications.neverShow.accesskey=N webNotifications.receiveFromSite=Would you like to receive notifications from this site? # LOCALIZATION NOTE (webNotifications.upgradeTitle): When using native notifications on OS X, the title may be truncated around 32 characters.
--- a/browser/themes/shared/devedition.inc.css +++ b/browser/themes/shared/devedition.inc.css @@ -53,20 +53,16 @@ --urlbar-dropmarker-hover-region: rect(0, 22px, 14px, 11px); --urlbar-dropmarker-active-region: rect(0px, 33px, 14px, 22px); --urlbar-dropmarker-2x-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg"); --urlbar-dropmarker-2x-region: rect(0px, 11px, 14px, 0px); --urlbar-dropmarker-hover-2x-region: rect(0, 22px, 14px, 11px); --urlbar-dropmarker-active-2x-region: rect(0px, 33px, 14px, 22px); } -:root[devtoolstheme="dark"] #identity-box { - --identity-box-chrome-color: #46afe3; -} - :root[devtoolstheme="light"] { --url-and-searchbar-background-color: #fff; --chrome-background-color: #E3E4E6; --chrome-color: #18191a; --chrome-secondary-background-color: #f5f6f7; --chrome-navigator-toolbox-separator-color: #cccccc; --chrome-nav-bar-separator-color: #B6B6B8;
--- a/browser/themes/shared/identity-block/identity-block.inc.css +++ b/browser/themes/shared/identity-block/identity-block.inc.css @@ -1,42 +1,33 @@ %if 0 /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ %endif #identity-box { - --identity-box-verified-color: hsl(92,100%,30%); -%ifdef MOZ_OFFICIAL_BRANDING - --identity-box-chrome-color: rgb(229,115,0); -%else -%if MOZ_UPDATE_CHANNEL == aurora - --identity-box-chrome-color: rgb(51,30,84); -%else - --identity-box-chrome-color: rgb(0,33,71); -%endif -%endif - font-size: .9em; padding: 3px 5px; overflow: hidden; /* The padding-left and padding-right transitions handle the delayed hiding of the forward button when hovered. */ transition: padding-left, padding-right; } -#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #connection-icon, #urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #identity-icon-labels { - color: var(--identity-box-verified-color); + color: hsl(92,100%,30%); } -#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #connection-icon, #urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon-labels { - color: var(--identity-box-chrome-color); +%ifdef MOZ_OFFICIAL_BRANDING + color: rgb(229,115,0); +%else + color: inherit; +%endif } #identity-icon-labels:-moz-locale-dir(ltr) { padding-left: 2px; } #identity-icon-labels:-moz-locale-dir(rtl) { padding-right: 2px;
--- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -1,12 +1,15 @@ /* 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/. */ +/* This file respects the LLVM coding standard described at + * http://llvm.org/docs/CodingStandards.html */ + #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/Version.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendPluginRegistry.h" @@ -37,47 +40,47 @@ typedef ASTConsumer *ASTConsumerPtr; #define cxxMethodDecl methodDecl #define cxxNewExpr newExpr #define cxxRecordDecl recordDecl #endif // Check if the given expression contains an assignment expression. // This can either take the form of a Binary Operator or a // Overloaded Operator Call. -bool HasSideEffectAssignment(const Expr *expr) { - if (auto opCallExpr = dyn_cast_or_null<CXXOperatorCallExpr>(expr)) { - auto binOp = opCallExpr->getOperator(); - if (binOp == OO_Equal || (binOp >= OO_PlusEqual && binOp <= OO_PipeEqual)) { +bool hasSideEffectAssignment(const Expr *Expression) { + if (auto OpCallExpr = dyn_cast_or_null<CXXOperatorCallExpr>(Expression)) { + auto BinOp = OpCallExpr->getOperator(); + if (BinOp == OO_Equal || (BinOp >= OO_PlusEqual && BinOp <= OO_PipeEqual)) { return true; } - } else if (auto binOpExpr = dyn_cast_or_null<BinaryOperator>(expr)) { - if (binOpExpr->isAssignmentOp()) { + } else if (auto BinOpExpr = dyn_cast_or_null<BinaryOperator>(Expression)) { + if (BinOpExpr->isAssignmentOp()) { return true; } } // Recurse to children. - for (const Stmt *SubStmt : expr->children()) { - auto childExpr = dyn_cast_or_null<Expr>(SubStmt); - if (childExpr && HasSideEffectAssignment(childExpr)) { + for (const Stmt *SubStmt : Expression->children()) { + auto ChildExpr = dyn_cast_or_null<Expr>(SubStmt); + if (ChildExpr && hasSideEffectAssignment(ChildExpr)) { return true; } } return false; } namespace { using namespace clang::ast_matchers; class DiagnosticsMatcher { public: DiagnosticsMatcher(); - ASTConsumerPtr makeASTConsumer() { return astMatcher.newASTConsumer(); } + ASTConsumerPtr makeASTConsumer() { return AstMatcher.newASTConsumer(); } private: class ScopeChecker : public MatchFinder::MatchCallback { public: virtual void run(const MatchFinder::MatchResult &Result); }; class ArithmeticArgChecker : public MatchFinder::MatchCallback { @@ -150,134 +153,134 @@ private: virtual void run(const MatchFinder::MatchResult &Result); }; class AssertAssignmentChecker : public MatchFinder::MatchCallback { public: virtual void run(const MatchFinder::MatchResult &Result); }; - ScopeChecker scopeChecker; - ArithmeticArgChecker arithmeticArgChecker; - TrivialCtorDtorChecker trivialCtorDtorChecker; - NaNExprChecker nanExprChecker; - NoAddRefReleaseOnReturnChecker noAddRefReleaseOnReturnChecker; - RefCountedInsideLambdaChecker refCountedInsideLambdaChecker; - ExplicitOperatorBoolChecker explicitOperatorBoolChecker; - NoDuplicateRefCntMemberChecker noDuplicateRefCntMemberChecker; - NeedsNoVTableTypeChecker needsNoVTableTypeChecker; - NonMemMovableTemplateArgChecker nonMemMovableTemplateArgChecker; - NonMemMovableMemberChecker nonMemMovableMemberChecker; - ExplicitImplicitChecker explicitImplicitChecker; - NoAutoTypeChecker noAutoTypeChecker; - NoExplicitMoveConstructorChecker noExplicitMoveConstructorChecker; - RefCountedCopyConstructorChecker refCountedCopyConstructorChecker; - AssertAssignmentChecker assertAttributionChecker; - MatchFinder astMatcher; + ScopeChecker Scope; + ArithmeticArgChecker ArithmeticArg; + TrivialCtorDtorChecker TrivialCtorDtor; + NaNExprChecker NaNExpr; + NoAddRefReleaseOnReturnChecker NoAddRefReleaseOnReturn; + RefCountedInsideLambdaChecker RefCountedInsideLambda; + ExplicitOperatorBoolChecker ExplicitOperatorBool; + NoDuplicateRefCntMemberChecker NoDuplicateRefCntMember; + NeedsNoVTableTypeChecker NeedsNoVTableType; + NonMemMovableTemplateArgChecker NonMemMovableTemplateArg; + NonMemMovableMemberChecker NonMemMovableMember; + ExplicitImplicitChecker ExplicitImplicit; + NoAutoTypeChecker NoAutoType; + NoExplicitMoveConstructorChecker NoExplicitMoveConstructor; + RefCountedCopyConstructorChecker RefCountedCopyConstructor; + AssertAssignmentChecker AssertAttribution; + MatchFinder AstMatcher; }; namespace { -std::string getDeclarationNamespace(const Decl *decl) { +std::string getDeclarationNamespace(const Decl *Declaration) { const DeclContext *DC = - decl->getDeclContext()->getEnclosingNamespaceContext(); + Declaration->getDeclContext()->getEnclosingNamespaceContext(); const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC); if (!ND) { return ""; } while (const DeclContext *ParentDC = ND->getParent()) { if (!isa<NamespaceDecl>(ParentDC)) { break; } ND = cast<NamespaceDecl>(ParentDC); } - const auto &name = ND->getName(); - return name; + const auto &Name = ND->getName(); + return Name; } -bool isInIgnoredNamespaceForImplicitCtor(const Decl *decl) { - std::string name = getDeclarationNamespace(decl); - if (name == "") { +bool isInIgnoredNamespaceForImplicitCtor(const Decl *Declaration) { + std::string Name = getDeclarationNamespace(Declaration); + if (Name == "") { return false; } - return name == "std" || // standard C++ lib - name == "__gnu_cxx" || // gnu C++ lib - name == "boost" || // boost - name == "webrtc" || // upstream webrtc - name == "rtc" || // upstream webrtc 'base' package - name.substr(0, 4) == "icu_" || // icu - name == "google" || // protobuf - name == "google_breakpad" || // breakpad - name == "soundtouch" || // libsoundtouch - name == "stagefright" || // libstagefright - name == "MacFileUtilities" || // MacFileUtilities - name == "dwarf2reader" || // dwarf2reader - name == "arm_ex_to_module" || // arm_ex_to_module - name == "testing"; // gtest + return Name == "std" || // standard C++ lib + Name == "__gnu_cxx" || // gnu C++ lib + Name == "boost" || // boost + Name == "webrtc" || // upstream webrtc + Name == "rtc" || // upstream webrtc 'base' package + Name.substr(0, 4) == "icu_" || // icu + Name == "google" || // protobuf + Name == "google_breakpad" || // breakpad + Name == "soundtouch" || // libsoundtouch + Name == "stagefright" || // libstagefright + Name == "MacFileUtilities" || // MacFileUtilities + Name == "dwarf2reader" || // dwarf2reader + Name == "arm_ex_to_module" || // arm_ex_to_module + Name == "testing"; // gtest } -bool isInIgnoredNamespaceForImplicitConversion(const Decl *decl) { - std::string name = getDeclarationNamespace(decl); - if (name == "") { +bool isInIgnoredNamespaceForImplicitConversion(const Decl *Declaration) { + std::string Name = getDeclarationNamespace(Declaration); + if (Name == "") { return false; } - return name == "std" || // standard C++ lib - name == "__gnu_cxx" || // gnu C++ lib - name == "google_breakpad" || // breakpad - name == "testing"; // gtest + return Name == "std" || // standard C++ lib + Name == "__gnu_cxx" || // gnu C++ lib + Name == "google_breakpad" || // breakpad + Name == "testing"; // gtest } -bool isIgnoredPathForImplicitCtor(const Decl *decl) { - SourceLocation Loc = decl->getLocation(); - const SourceManager &SM = decl->getASTContext().getSourceManager(); +bool isIgnoredPathForImplicitCtor(const Decl *Declaration) { + SourceLocation Loc = Declaration->getLocation(); + const SourceManager &SM = Declaration->getASTContext().getSourceManager(); SmallString<1024> FileName = SM.getFilename(Loc); llvm::sys::fs::make_absolute(FileName); - llvm::sys::path::reverse_iterator begin = llvm::sys::path::rbegin(FileName), - end = llvm::sys::path::rend(FileName); - for (; begin != end; ++begin) { - if (begin->compare_lower(StringRef("skia")) == 0 || - begin->compare_lower(StringRef("angle")) == 0 || - begin->compare_lower(StringRef("harfbuzz")) == 0 || - begin->compare_lower(StringRef("hunspell")) == 0 || - begin->compare_lower(StringRef("scoped_ptr.h")) == 0 || - begin->compare_lower(StringRef("graphite2")) == 0) { + llvm::sys::path::reverse_iterator Begin = llvm::sys::path::rbegin(FileName), + End = llvm::sys::path::rend(FileName); + for (; Begin != End; ++Begin) { + if (Begin->compare_lower(StringRef("skia")) == 0 || + Begin->compare_lower(StringRef("angle")) == 0 || + Begin->compare_lower(StringRef("harfbuzz")) == 0 || + Begin->compare_lower(StringRef("hunspell")) == 0 || + Begin->compare_lower(StringRef("scoped_ptr.h")) == 0 || + Begin->compare_lower(StringRef("graphite2")) == 0) { return true; } - if (begin->compare_lower(StringRef("chromium")) == 0) { + if (Begin->compare_lower(StringRef("chromium")) == 0) { // Ignore security/sandbox/chromium but not ipc/chromium. - ++begin; - return begin != end && begin->compare_lower(StringRef("sandbox")) == 0; + ++Begin; + return Begin != End && Begin->compare_lower(StringRef("sandbox")) == 0; } } return false; } -bool isIgnoredPathForImplicitConversion(const Decl *decl) { - decl = decl->getCanonicalDecl(); - SourceLocation Loc = decl->getLocation(); - const SourceManager &SM = decl->getASTContext().getSourceManager(); +bool isIgnoredPathForImplicitConversion(const Decl *Declaration) { + Declaration = Declaration->getCanonicalDecl(); + SourceLocation Loc = Declaration->getLocation(); + const SourceManager &SM = Declaration->getASTContext().getSourceManager(); SmallString<1024> FileName = SM.getFilename(Loc); llvm::sys::fs::make_absolute(FileName); - llvm::sys::path::reverse_iterator begin = llvm::sys::path::rbegin(FileName), - end = llvm::sys::path::rend(FileName); - for (; begin != end; ++begin) { - if (begin->compare_lower(StringRef("graphite2")) == 0) { + llvm::sys::path::reverse_iterator Begin = llvm::sys::path::rbegin(FileName), + End = llvm::sys::path::rend(FileName); + for (; Begin != End; ++Begin) { + if (Begin->compare_lower(StringRef("graphite2")) == 0) { return true; } } return false; } -bool isInterestingDeclForImplicitConversion(const Decl *decl) { - return !isInIgnoredNamespaceForImplicitConversion(decl) && - !isIgnoredPathForImplicitConversion(decl); +bool isInterestingDeclForImplicitConversion(const Decl *Declaration) { + return !isInIgnoredNamespaceForImplicitConversion(Declaration) && + !isIgnoredPathForImplicitConversion(Declaration); } bool isIgnoredExprForMustUse(const Expr *E) { if (const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(E)) { switch (OpCall->getOperator()) { case OO_Equal: case OO_PlusEqual: case OO_MinusEqual: @@ -400,257 +403,257 @@ protected: } }; static MemMoveAnnotation NonMemMovable = MemMoveAnnotation(); class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> { DiagnosticsEngine &Diag; const CompilerInstance &CI; - DiagnosticsMatcher matcher; + DiagnosticsMatcher Matcher; public: MozChecker(const CompilerInstance &CI) : Diag(CI.getDiagnostics()), CI(CI) {} - ASTConsumerPtr getOtherConsumer() { return matcher.makeASTConsumer(); } + ASTConsumerPtr getOtherConsumer() { return Matcher.makeASTConsumer(); } - virtual void HandleTranslationUnit(ASTContext &ctx) { - TraverseDecl(ctx.getTranslationUnitDecl()); + virtual void HandleTranslationUnit(ASTContext &Ctx) override { + TraverseDecl(Ctx.getTranslationUnitDecl()); } static bool hasCustomAnnotation(const Decl *D, const char *Spelling) { iterator_range<specific_attr_iterator<AnnotateAttr>> Attrs = D->specific_attrs<AnnotateAttr>(); for (AnnotateAttr *Attr : Attrs) { if (Attr->getAnnotation() == Spelling) { return true; } } return false; } - void HandleUnusedExprResult(const Stmt *stmt) { - const Expr *E = dyn_cast_or_null<Expr>(stmt); + void handleUnusedExprResult(const Stmt *Statement) { + const Expr *E = dyn_cast_or_null<Expr>(Statement); if (E) { E = E->IgnoreImplicit(); // Ignore ExprWithCleanup etc. implicit wrappers QualType T = E->getType(); if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) { - unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "Unused value of must-use type %0"); - Diag.Report(E->getLocStart(), errorID) << T; + Diag.Report(E->getLocStart(), ErrorID) << T; MustUse.dumpAnnotationReason(Diag, T, E->getLocStart()); } } } - bool VisitCXXRecordDecl(CXXRecordDecl *d) { + bool VisitCXXRecordDecl(CXXRecordDecl *D) { // We need definitions, not declarations - if (!d->isThisDeclarationADefinition()) + if (!D->isThisDeclarationADefinition()) return true; // Look through all of our immediate bases to find methods that need to be // overridden typedef std::vector<CXXMethodDecl *> OverridesVector; - OverridesVector must_overrides; - for (CXXRecordDecl::base_class_iterator base = d->bases_begin(), - e = d->bases_end(); - base != e; ++base) { + OverridesVector MustOverrides; + for (CXXRecordDecl::base_class_iterator Base = D->bases_begin(), + E = D->bases_end(); + Base != E; ++Base) { // The base is either a class (CXXRecordDecl) or it's a templated class... - CXXRecordDecl *parent = base->getType() - .getDesugaredType(d->getASTContext()) + CXXRecordDecl *Parent = Base->getType() + .getDesugaredType(D->getASTContext()) ->getAsCXXRecordDecl(); // The parent might not be resolved to a type yet. In this case, we can't // do any checking here. For complete correctness, we should visit // template instantiations, but this case is likely to be rare, so we will // ignore it until it becomes important. - if (!parent) { + if (!Parent) { continue; } - parent = parent->getDefinition(); - for (CXXRecordDecl::method_iterator M = parent->method_begin(); - M != parent->method_end(); ++M) { + Parent = Parent->getDefinition(); + for (CXXRecordDecl::method_iterator M = Parent->method_begin(); + M != Parent->method_end(); ++M) { if (hasCustomAnnotation(*M, "moz_must_override")) - must_overrides.push_back(*M); + MustOverrides.push_back(*M); } } - for (OverridesVector::iterator it = must_overrides.begin(); - it != must_overrides.end(); ++it) { - bool overridden = false; - for (CXXRecordDecl::method_iterator M = d->method_begin(); - !overridden && M != d->method_end(); ++M) { + for (OverridesVector::iterator It = MustOverrides.begin(); + It != MustOverrides.end(); ++It) { + bool Overridden = false; + for (CXXRecordDecl::method_iterator M = D->method_begin(); + !Overridden && M != D->method_end(); ++M) { // The way that Clang checks if a method M overrides its parent method // is if the method has the same name but would not overload. - if (getNameChecked(M) == getNameChecked(*it) && - !CI.getSema().IsOverload(*M, (*it), false)) { - overridden = true; + if (getNameChecked(M) == getNameChecked(*It) && + !CI.getSema().IsOverload(*M, (*It), false)) { + Overridden = true; break; } } - if (!overridden) { - unsigned overrideID = Diag.getDiagnosticIDs()->getCustomDiagID( + if (!Overridden) { + unsigned OverrideID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "%0 must override %1"); - unsigned overrideNote = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned OverrideNote = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Note, "function to override is here"); - Diag.Report(d->getLocation(), overrideID) << d->getDeclName() - << (*it)->getDeclName(); - Diag.Report((*it)->getLocation(), overrideNote); + Diag.Report(D->getLocation(), OverrideID) << D->getDeclName() + << (*It)->getDeclName(); + Diag.Report((*It)->getLocation(), OverrideNote); } } return true; } - bool VisitSwitchCase(SwitchCase *stmt) { - HandleUnusedExprResult(stmt->getSubStmt()); + bool VisitSwitchCase(SwitchCase *Statement) { + handleUnusedExprResult(Statement->getSubStmt()); return true; } - bool VisitCompoundStmt(CompoundStmt *stmt) { - for (CompoundStmt::body_iterator it = stmt->body_begin(), - e = stmt->body_end(); - it != e; ++it) { - HandleUnusedExprResult(*it); + bool VisitCompoundStmt(CompoundStmt *Statement) { + for (CompoundStmt::body_iterator It = Statement->body_begin(), + E = Statement->body_end(); + It != E; ++It) { + handleUnusedExprResult(*It); } return true; } - bool VisitIfStmt(IfStmt *Stmt) { - HandleUnusedExprResult(Stmt->getThen()); - HandleUnusedExprResult(Stmt->getElse()); + bool VisitIfStmt(IfStmt *Statement) { + handleUnusedExprResult(Statement->getThen()); + handleUnusedExprResult(Statement->getElse()); return true; } - bool VisitWhileStmt(WhileStmt *Stmt) { - HandleUnusedExprResult(Stmt->getBody()); + bool VisitWhileStmt(WhileStmt *Statement) { + handleUnusedExprResult(Statement->getBody()); return true; } - bool VisitDoStmt(DoStmt *Stmt) { - HandleUnusedExprResult(Stmt->getBody()); + bool VisitDoStmt(DoStmt *Statement) { + handleUnusedExprResult(Statement->getBody()); return true; } - bool VisitForStmt(ForStmt *Stmt) { - HandleUnusedExprResult(Stmt->getBody()); - HandleUnusedExprResult(Stmt->getInit()); - HandleUnusedExprResult(Stmt->getInc()); + bool VisitForStmt(ForStmt *Statement) { + handleUnusedExprResult(Statement->getBody()); + handleUnusedExprResult(Statement->getInit()); + handleUnusedExprResult(Statement->getInc()); return true; } bool VisitBinComma(BinaryOperator *Op) { - HandleUnusedExprResult(Op->getLHS()); + handleUnusedExprResult(Op->getLHS()); return true; } }; /// A cached data of whether classes are refcounted or not. typedef DenseMap<const CXXRecordDecl *, std::pair<const Decl *, bool>> RefCountedMap; -RefCountedMap refCountedClasses; +RefCountedMap RefCountedClasses; bool classHasAddRefRelease(const CXXRecordDecl *D) { - const RefCountedMap::iterator &it = refCountedClasses.find(D); - if (it != refCountedClasses.end()) { - return it->second.second; + const RefCountedMap::iterator &It = RefCountedClasses.find(D); + if (It != RefCountedClasses.end()) { + return It->second.second; } - bool seenAddRef = false; - bool seenRelease = false; - for (CXXRecordDecl::method_iterator method = D->method_begin(); - method != D->method_end(); ++method) { - const auto &name = getNameChecked(method); - if (name == "AddRef") { - seenAddRef = true; - } else if (name == "Release") { - seenRelease = true; + bool SeenAddRef = false; + bool SeenRelease = false; + for (CXXRecordDecl::method_iterator Method = D->method_begin(); + Method != D->method_end(); ++Method) { + const auto &Name = getNameChecked(Method); + if (Name == "AddRef") { + SeenAddRef = true; + } else if (Name == "Release") { + SeenRelease = true; } } - refCountedClasses[D] = std::make_pair(D, seenAddRef && seenRelease); - return seenAddRef && seenRelease; + RefCountedClasses[D] = std::make_pair(D, SeenAddRef && SeenRelease); + return SeenAddRef && SeenRelease; } bool isClassRefCounted(QualType T); bool isClassRefCounted(const CXXRecordDecl *D) { // Normalize so that D points to the definition if it exists. if (!D->hasDefinition()) return false; D = D->getDefinition(); // Base class: anyone with AddRef/Release is obviously a refcounted class. if (classHasAddRefRelease(D)) return true; // Look through all base cases to figure out if the parent is a refcounted // class. - for (CXXRecordDecl::base_class_const_iterator base = D->bases_begin(); - base != D->bases_end(); ++base) { - bool super = isClassRefCounted(base->getType()); - if (super) { + for (CXXRecordDecl::base_class_const_iterator Base = D->bases_begin(); + Base != D->bases_end(); ++Base) { + bool Super = isClassRefCounted(Base->getType()); + if (Super) { return true; } } return false; } bool isClassRefCounted(QualType T) { - while (const clang::ArrayType *arrTy = T->getAsArrayTypeUnsafe()) - T = arrTy->getElementType(); - CXXRecordDecl *clazz = T->getAsCXXRecordDecl(); - return clazz ? isClassRefCounted(clazz) : false; + while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe()) + T = ArrTy->getElementType(); + CXXRecordDecl *Clazz = T->getAsCXXRecordDecl(); + return Clazz ? isClassRefCounted(Clazz) : false; } -template <class T> bool IsInSystemHeader(const ASTContext &AC, const T &D) { +template <class T> bool ASTIsInSystemHeader(const ASTContext &AC, const T &D) { auto &SourceManager = AC.getSourceManager(); auto ExpansionLoc = SourceManager.getExpansionLoc(D.getLocStart()); if (ExpansionLoc.isInvalid()) { return false; } return SourceManager.isInSystemHeader(ExpansionLoc); } const FieldDecl *getClassRefCntMember(const CXXRecordDecl *D) { - for (RecordDecl::field_iterator field = D->field_begin(), e = D->field_end(); - field != e; ++field) { - if (getNameChecked(field) == "mRefCnt") { - return *field; + for (RecordDecl::field_iterator Field = D->field_begin(), E = D->field_end(); + Field != E; ++Field) { + if (getNameChecked(Field) == "mRefCnt") { + return *Field; } } return 0; } const FieldDecl *getBaseRefCntMember(QualType T); const FieldDecl *getBaseRefCntMember(const CXXRecordDecl *D) { - const FieldDecl *refCntMember = getClassRefCntMember(D); - if (refCntMember && isClassRefCounted(D)) { - return refCntMember; + const FieldDecl *RefCntMember = getClassRefCntMember(D); + if (RefCntMember && isClassRefCounted(D)) { + return RefCntMember; } - for (CXXRecordDecl::base_class_const_iterator base = D->bases_begin(), - e = D->bases_end(); - base != e; ++base) { - refCntMember = getBaseRefCntMember(base->getType()); - if (refCntMember) { - return refCntMember; + for (CXXRecordDecl::base_class_const_iterator Base = D->bases_begin(), + E = D->bases_end(); + Base != E; ++Base) { + RefCntMember = getBaseRefCntMember(Base->getType()); + if (RefCntMember) { + return RefCntMember; } } return 0; } const FieldDecl *getBaseRefCntMember(QualType T) { - while (const clang::ArrayType *arrTy = T->getAsArrayTypeUnsafe()) - T = arrTy->getElementType(); - CXXRecordDecl *clazz = T->getAsCXXRecordDecl(); - return clazz ? getBaseRefCntMember(clazz) : 0; + while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe()) + T = ArrTy->getElementType(); + CXXRecordDecl *Clazz = T->getAsCXXRecordDecl(); + return Clazz ? getBaseRefCntMember(Clazz) : 0; } bool typeHasVTable(QualType T) { - while (const clang::ArrayType *arrTy = T->getAsArrayTypeUnsafe()) - T = arrTy->getElementType(); - CXXRecordDecl *offender = T->getAsCXXRecordDecl(); - return offender && offender->hasDefinition() && offender->isDynamicClass(); + while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe()) + T = ArrTy->getElementType(); + CXXRecordDecl *Offender = T->getAsCXXRecordDecl(); + return Offender && Offender->hasDefinition() && Offender->isDynamicClass(); } } namespace clang { namespace ast_matchers { /// This matcher will match any function declaration that is declared as a heap /// allocator. @@ -674,49 +677,49 @@ AST_MATCHER(CXXRecordDecl, hasTrivialCto /// calling AddRef or Release on its return value. AST_MATCHER(FunctionDecl, hasNoAddRefReleaseOnReturnAttr) { return MozChecker::hasCustomAnnotation(&Node, "moz_no_addref_release_on_return"); } /// This matcher will match all arithmetic binary operators. AST_MATCHER(BinaryOperator, binaryArithmeticOperator) { - BinaryOperatorKind opcode = Node.getOpcode(); - return opcode == BO_Mul || opcode == BO_Div || opcode == BO_Rem || - opcode == BO_Add || opcode == BO_Sub || opcode == BO_Shl || - opcode == BO_Shr || opcode == BO_And || opcode == BO_Xor || - opcode == BO_Or || opcode == BO_MulAssign || opcode == BO_DivAssign || - opcode == BO_RemAssign || opcode == BO_AddAssign || - opcode == BO_SubAssign || opcode == BO_ShlAssign || - opcode == BO_ShrAssign || opcode == BO_AndAssign || - opcode == BO_XorAssign || opcode == BO_OrAssign; + BinaryOperatorKind OpCode = Node.getOpcode(); + return OpCode == BO_Mul || OpCode == BO_Div || OpCode == BO_Rem || + OpCode == BO_Add || OpCode == BO_Sub || OpCode == BO_Shl || + OpCode == BO_Shr || OpCode == BO_And || OpCode == BO_Xor || + OpCode == BO_Or || OpCode == BO_MulAssign || OpCode == BO_DivAssign || + OpCode == BO_RemAssign || OpCode == BO_AddAssign || + OpCode == BO_SubAssign || OpCode == BO_ShlAssign || + OpCode == BO_ShrAssign || OpCode == BO_AndAssign || + OpCode == BO_XorAssign || OpCode == BO_OrAssign; } /// This matcher will match all arithmetic unary operators. AST_MATCHER(UnaryOperator, unaryArithmeticOperator) { - UnaryOperatorKind opcode = Node.getOpcode(); - return opcode == UO_PostInc || opcode == UO_PostDec || opcode == UO_PreInc || - opcode == UO_PreDec || opcode == UO_Plus || opcode == UO_Minus || - opcode == UO_Not; + UnaryOperatorKind OpCode = Node.getOpcode(); + return OpCode == UO_PostInc || OpCode == UO_PostDec || OpCode == UO_PreInc || + OpCode == UO_PreDec || OpCode == UO_Plus || OpCode == UO_Minus || + OpCode == UO_Not; } /// This matcher will match == and != binary operators. AST_MATCHER(BinaryOperator, binaryEqualityOperator) { - BinaryOperatorKind opcode = Node.getOpcode(); - return opcode == BO_EQ || opcode == BO_NE; + BinaryOperatorKind OpCode = Node.getOpcode(); + return OpCode == BO_EQ || OpCode == BO_NE; } /// This matcher will match floating point types. AST_MATCHER(QualType, isFloat) { return Node->isRealFloatingType(); } /// This matcher will match locations in system headers. This is adopted from /// isExpansionInSystemHeader in newer clangs, but modified in order to work /// with old clangs that we use on infra. AST_MATCHER(BinaryOperator, isInSystemHeader) { - return IsInSystemHeader(Finder->getASTContext(), Node); + return ASTIsInSystemHeader(Finder->getASTContext(), Node); } /// This matcher will match locations in SkScalar.h. This header contains a /// known NaN-testing expression which we would like to whitelist. AST_MATCHER(BinaryOperator, isInSkScalarDotH) { SourceLocation Loc = Node.getOperatorLoc(); auto &SourceManager = Finder->getASTContext().getSourceManager(); SmallString<1024> FileName = SourceManager.getFilename(Loc); @@ -756,28 +759,28 @@ AST_MATCHER(CXXRecordDecl, needsMemMovab } /// This matcher will select classes which require all members to be memmovable AST_MATCHER(CXXRecordDecl, needsMemMovableMembers) { return MozChecker::hasCustomAnnotation(&Node, "moz_needs_memmovable_members"); } AST_MATCHER(CXXConstructorDecl, isInterestingImplicitCtor) { - const CXXConstructorDecl *decl = Node.getCanonicalDecl(); + const CXXConstructorDecl *Declaration = Node.getCanonicalDecl(); return // Skip ignored namespaces and paths - !isInIgnoredNamespaceForImplicitCtor(decl) && - !isIgnoredPathForImplicitCtor(decl) && + !isInIgnoredNamespaceForImplicitCtor(Declaration) && + !isIgnoredPathForImplicitCtor(Declaration) && // We only want Converting constructors - decl->isConvertingConstructor(false) && + Declaration->isConvertingConstructor(false) && // We don't want copy of move constructors, as those are allowed to be // implicit - !decl->isCopyOrMoveConstructor() && + !Declaration->isCopyOrMoveConstructor() && // We don't want deleted constructors. - !decl->isDeleted(); + !Declaration->isDeleted(); } // We can't call this "isImplicit" since it clashes with an existing matcher in // clang. AST_MATCHER(CXXConstructorDecl, isMarkedImplicit) { return MozChecker::hasCustomAnnotation(&Node, "moz_implicit"); } @@ -796,22 +799,22 @@ AST_MATCHER(CXXConstructorDecl, isExplic return Node.isExplicit() && Node.isMoveConstructor(); } AST_MATCHER(CXXConstructorDecl, isCompilerProvidedCopyConstructor) { return !Node.isUserProvided() && Node.isCopyConstructor(); } AST_MATCHER(CallExpr, isAssertAssignmentTestFunc) { - static const std::string assertName = "MOZ_AssertAssignmentTest"; - const FunctionDecl *method = Node.getDirectCallee(); + static const std::string AssertName = "MOZ_AssertAssignmentTest"; + const FunctionDecl *Method = Node.getDirectCallee(); - return method - && method->getDeclName().isIdentifier() - && method->getName() == assertName; + return Method + && Method->getDeclName().isIdentifier() + && Method->getName() == AssertName; } AST_MATCHER(CXXRecordDecl, isLambdaDecl) { return Node.isLambda(); } } } @@ -835,32 +838,33 @@ void CustomTypeAnnotation::dumpAnnotatio AnnotationReason Reason = directAnnotationReason(T); for (;;) { switch (Reason.Kind) { case RK_ArrayElement: Diag.Report(Loc, ArrayID) << Pretty << T << Reason.Type; break; case RK_BaseClass: { - const CXXRecordDecl *Decl = T->getAsCXXRecordDecl(); - assert(Decl && "This type should be a C++ class"); + const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl(); + assert(Declaration && "This type should be a C++ class"); - Diag.Report(Decl->getLocation(), InheritsID) << Pretty << T + Diag.Report(Declaration->getLocation(), InheritsID) << Pretty << T << Reason.Type; break; } case RK_Field: Diag.Report(Reason.Field->getLocation(), MemberID) << Pretty << T << Reason.Field << Reason.Type; break; case RK_TemplateInherited: { - const CXXRecordDecl *Decl = T->getAsCXXRecordDecl(); - assert(Decl && "This type should be a C++ class"); + const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl(); + assert(Declaration && "This type should be a C++ class"); - Diag.Report(Decl->getLocation(), TemplID) << Pretty << T << Reason.Type; + Diag.Report(Declaration->getLocation(), TemplID) << Pretty << T + << Reason.Type; break; } default: // FIXME (bug 1203263): note the original annotation. return; } T = Reason.Type; @@ -898,44 +902,44 @@ CustomTypeAnnotation::directAnnotationRe if (hasEffectiveAnnotation(Array->getElementType())) { AnnotationReason Reason = {Array->getElementType(), RK_ArrayElement, nullptr}; Cache[Key] = Reason; return Reason; } } - // Recurse into base classes - if (const CXXRecordDecl *Decl = T->getAsCXXRecordDecl()) { - if (Decl->hasDefinition()) { - Decl = Decl->getDefinition(); + // Recurse into Base classes + if (const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl()) { + if (Declaration->hasDefinition()) { + Declaration = Declaration->getDefinition(); - for (const CXXBaseSpecifier &Base : Decl->bases()) { + for (const CXXBaseSpecifier &Base : Declaration->bases()) { if (hasEffectiveAnnotation(Base.getType())) { AnnotationReason Reason = {Base.getType(), RK_BaseClass, nullptr}; Cache[Key] = Reason; return Reason; } } // Recurse into members - for (const FieldDecl *Field : Decl->fields()) { + for (const FieldDecl *Field : Declaration->fields()) { if (hasEffectiveAnnotation(Field->getType())) { AnnotationReason Reason = {Field->getType(), RK_Field, Field}; Cache[Key] = Reason; return Reason; } } // Recurse into template arguments if the annotation // MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS is present if (MozChecker::hasCustomAnnotation( - Decl, "moz_inherit_type_annotations_from_template_args")) { + Declaration, "moz_inherit_type_annotations_from_template_args")) { const ClassTemplateSpecializationDecl *Spec = - dyn_cast<ClassTemplateSpecializationDecl>(Decl); + dyn_cast<ClassTemplateSpecializationDecl>(Declaration); if (Spec) { const TemplateArgumentList &Args = Spec->getTemplateArgs(); AnnotationReason Reason = tmplArgAnnotationReason(Args.asArray()); if (Reason.Kind != RK_None) { Cache[Key] = Reason; return Reason; } @@ -965,55 +969,56 @@ CustomTypeAnnotation::tmplArgAnnotationR } } } AnnotationReason Reason = {QualType(), RK_None, nullptr}; return Reason; } -bool isPlacementNew(const CXXNewExpr *Expr) { +bool isPlacementNew(const CXXNewExpr *Expression) { // Regular new expressions aren't placement new - if (Expr->getNumPlacementArgs() == 0) + if (Expression->getNumPlacementArgs() == 0) return false; - const FunctionDecl *Decl = Expr->getOperatorNew(); - if (Decl && MozChecker::hasCustomAnnotation(Decl, "moz_heap_allocator")) { + const FunctionDecl *Declaration = Expression->getOperatorNew(); + if (Declaration && MozChecker::hasCustomAnnotation(Declaration, + "moz_heap_allocator")) { return false; } return true; } DiagnosticsMatcher::DiagnosticsMatcher() { - astMatcher.addMatcher(varDecl().bind("node"), &scopeChecker); - astMatcher.addMatcher(cxxNewExpr().bind("node"), &scopeChecker); - astMatcher.addMatcher(materializeTemporaryExpr().bind("node"), &scopeChecker); - astMatcher.addMatcher( + AstMatcher.addMatcher(varDecl().bind("node"), &Scope); + AstMatcher.addMatcher(cxxNewExpr().bind("node"), &Scope); + AstMatcher.addMatcher(materializeTemporaryExpr().bind("node"), &Scope); + AstMatcher.addMatcher( callExpr(callee(functionDecl(heapAllocator()))).bind("node"), - &scopeChecker); - astMatcher.addMatcher(parmVarDecl().bind("parm_vardecl"), &scopeChecker); + &Scope); + AstMatcher.addMatcher(parmVarDecl().bind("parm_vardecl"), &Scope); - astMatcher.addMatcher( + AstMatcher.addMatcher( callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()), anyOf(hasDescendant( binaryOperator( allOf(binaryArithmeticOperator(), hasLHS(hasDescendant(declRefExpr())), hasRHS(hasDescendant(declRefExpr())))) .bind("node")), hasDescendant( unaryOperator( allOf(unaryArithmeticOperator(), hasUnaryOperand(allOf( hasType(builtinType()), anyOf(hasDescendant(declRefExpr()), declRefExpr()))))) .bind("node"))))) .bind("call"), - &arithmeticArgChecker); - astMatcher.addMatcher( + &ArithmeticArg); + AstMatcher.addMatcher( cxxConstructExpr( allOf(hasDeclaration(noArithmeticExprInArgs()), anyOf(hasDescendant( binaryOperator( allOf(binaryArithmeticOperator(), hasLHS(hasDescendant(declRefExpr())), hasRHS(hasDescendant(declRefExpr())))) .bind("node")), @@ -1021,122 +1026,125 @@ DiagnosticsMatcher::DiagnosticsMatcher() unaryOperator( allOf(unaryArithmeticOperator(), hasUnaryOperand(allOf( hasType(builtinType()), anyOf(hasDescendant(declRefExpr()), declRefExpr()))))) .bind("node"))))) .bind("call"), - &arithmeticArgChecker); + &ArithmeticArg); - astMatcher.addMatcher(cxxRecordDecl(hasTrivialCtorDtor()).bind("node"), - &trivialCtorDtorChecker); + AstMatcher.addMatcher(cxxRecordDecl(hasTrivialCtorDtor()).bind("node"), + &TrivialCtorDtor); - astMatcher.addMatcher( + AstMatcher.addMatcher( binaryOperator( allOf(binaryEqualityOperator(), hasLHS(has( declRefExpr(hasType(qualType((isFloat())))).bind("lhs"))), hasRHS(has( declRefExpr(hasType(qualType((isFloat())))).bind("rhs"))), unless(anyOf(isInSystemHeader(), isInSkScalarDotH())))) .bind("node"), - &nanExprChecker); + &NaNExpr); // First, look for direct parents of the MemberExpr. - astMatcher.addMatcher( + AstMatcher.addMatcher( callExpr( callee(functionDecl(hasNoAddRefReleaseOnReturnAttr()).bind("func")), hasParent(memberExpr(isAddRefOrRelease(), hasParent(callExpr())) .bind("member"))) .bind("node"), - &noAddRefReleaseOnReturnChecker); + &NoAddRefReleaseOnReturn); // Then, look for MemberExpr that need to be casted to the right type using // an intermediary CastExpr before we get to the CallExpr. - astMatcher.addMatcher( + AstMatcher.addMatcher( callExpr( callee(functionDecl(hasNoAddRefReleaseOnReturnAttr()).bind("func")), hasParent(castExpr( hasParent(memberExpr(isAddRefOrRelease(), hasParent(callExpr())) .bind("member"))))) .bind("node"), - &noAddRefReleaseOnReturnChecker); + &NoAddRefReleaseOnReturn); // We want to reject any code which captures a pointer to an object of a // refcounted type, and then lets that value escape. As a primitive analysis, // we reject any occurances of the lambda as a template parameter to a class // (which could allow it to escape), as well as any presence of such a lambda // in a return value (either from lambdas, or in c++14, auto functions). // // We check these lambdas' capture lists for raw pointers to refcounted types. - astMatcher.addMatcher( - functionDecl(returns(recordType(hasDeclaration(cxxRecordDecl(isLambdaDecl()).bind("decl"))))), - &refCountedInsideLambdaChecker); - astMatcher.addMatcher(lambdaExpr().bind("lambdaExpr"), &refCountedInsideLambdaChecker); - astMatcher.addMatcher( + AstMatcher.addMatcher( + functionDecl(returns(recordType(hasDeclaration(cxxRecordDecl( + isLambdaDecl()).bind("decl"))))), + &RefCountedInsideLambda); + AstMatcher.addMatcher(lambdaExpr().bind("lambdaExpr"), + &RefCountedInsideLambda); + AstMatcher.addMatcher( classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType( - recordType(hasDeclaration(cxxRecordDecl(isLambdaDecl()).bind("decl")))))), - &refCountedInsideLambdaChecker); + recordType(hasDeclaration(cxxRecordDecl( + isLambdaDecl()).bind("decl")))))), + &RefCountedInsideLambda); // Older clang versions such as the ones used on the infra recognize these // conversions as 'operator _Bool', but newer clang versions recognize these // as 'operator bool'. - astMatcher.addMatcher( + AstMatcher.addMatcher( cxxMethodDecl(anyOf(hasName("operator bool"), hasName("operator _Bool"))) .bind("node"), - &explicitOperatorBoolChecker); + &ExplicitOperatorBool); - astMatcher.addMatcher(cxxRecordDecl().bind("decl"), &noDuplicateRefCntMemberChecker); + AstMatcher.addMatcher(cxxRecordDecl().bind("decl"), &NoDuplicateRefCntMember); - astMatcher.addMatcher( + AstMatcher.addMatcher( classTemplateSpecializationDecl( allOf(hasAnyTemplateArgument(refersToType(hasVTable())), hasNeedsNoVTableTypeAttr())) .bind("node"), - &needsNoVTableTypeChecker); + &NeedsNoVTableType); // Handle non-mem-movable template specializations - astMatcher.addMatcher( + AstMatcher.addMatcher( classTemplateSpecializationDecl( allOf(needsMemMovableTemplateArg(), hasAnyTemplateArgument(refersToType(isNonMemMovable())))) .bind("specialization"), - &nonMemMovableTemplateArgChecker); + &NonMemMovableTemplateArg); // Handle non-mem-movable members - astMatcher.addMatcher( + AstMatcher.addMatcher( cxxRecordDecl(needsMemMovableMembers()) .bind("decl"), - &nonMemMovableMemberChecker); + &NonMemMovableMember); - astMatcher.addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(), + AstMatcher.addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(), ofClass(allOf(isConcreteClass(), decl().bind("class"))), unless(isMarkedImplicit())) .bind("ctor"), - &explicitImplicitChecker); + &ExplicitImplicit); - astMatcher.addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"), - &noAutoTypeChecker); + AstMatcher.addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"), + &NoAutoType); - astMatcher.addMatcher( + AstMatcher.addMatcher( cxxConstructorDecl(isExplicitMoveConstructor()).bind("node"), - &noExplicitMoveConstructorChecker); + &NoExplicitMoveConstructor); - astMatcher.addMatcher( + AstMatcher.addMatcher( cxxConstructExpr( hasDeclaration(cxxConstructorDecl(isCompilerProvidedCopyConstructor(), ofClass(hasRefCntMember())))) .bind("node"), - &refCountedCopyConstructorChecker); + &RefCountedCopyConstructor); - astMatcher.addMatcher( + AstMatcher.addMatcher( callExpr(isAssertAssignmentTestFunc()).bind("funcCall"), - &assertAttributionChecker); + &AssertAttribution); } // These enum variants determine whether an allocation has occured in the code. enum AllocationVariety { AV_None, AV_Global, AV_Automatic, AV_Temporary, @@ -1290,111 +1298,115 @@ void DiagnosticsMatcher::ScopeChecker::r NonHeapClass.reportErrorIfPresent(Diag, T, Loc, NonHeapID, HeapNoteID); break; } } void DiagnosticsMatcher::ArithmeticArgChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "cannot pass an arithmetic expression of built-in types to %0"); - const Expr *expr = Result.Nodes.getNodeAs<Expr>("node"); - if (const CallExpr *call = Result.Nodes.getNodeAs<CallExpr>("call")) { - Diag.Report(expr->getLocStart(), errorID) << call->getDirectCallee(); - } else if (const CXXConstructExpr *ctr = + const Expr *Expression = Result.Nodes.getNodeAs<Expr>("node"); + if (const CallExpr *Call = Result.Nodes.getNodeAs<CallExpr>("call")) { + Diag.Report(Expression->getLocStart(), ErrorID) << Call->getDirectCallee(); + } else if (const CXXConstructExpr *Ctr = Result.Nodes.getNodeAs<CXXConstructExpr>("call")) { - Diag.Report(expr->getLocStart(), errorID) << ctr->getConstructor(); + Diag.Report(Expression->getLocStart(), ErrorID) << Ctr->getConstructor(); } } void DiagnosticsMatcher::TrivialCtorDtorChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "class %0 must have trivial constructors and destructors"); - const CXXRecordDecl *node = Result.Nodes.getNodeAs<CXXRecordDecl>("node"); + const CXXRecordDecl *Node = Result.Nodes.getNodeAs<CXXRecordDecl>("node"); // We need to accept non-constexpr trivial constructors as well. This occurs // when a struct contains pod members, which will not be initialized. As // constexpr values are initialized, the constructor is non-constexpr. - bool badCtor = !(node->hasConstexprDefaultConstructor() || - node->hasTrivialDefaultConstructor()); - bool badDtor = !node->hasTrivialDestructor(); - if (badCtor || badDtor) - Diag.Report(node->getLocStart(), errorID) << node; + bool BadCtor = !(Node->hasConstexprDefaultConstructor() || + Node->hasTrivialDefaultConstructor()); + bool BadDtor = !Node->hasTrivialDestructor(); + if (BadCtor || BadDtor) + Diag.Report(Node->getLocStart(), ErrorID) << Node; } void DiagnosticsMatcher::NaNExprChecker::run( const MatchFinder::MatchResult &Result) { if (!Result.Context->getLangOpts().CPlusPlus) { // mozilla::IsNaN is not usable in C, so there is no point in issuing these // warnings. return; } DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "comparing a floating point value to itself for " "NaN checking can lead to incorrect results"); - unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Note, "consider using mozilla::IsNaN instead"); - const BinaryOperator *expr = Result.Nodes.getNodeAs<BinaryOperator>("node"); - const DeclRefExpr *lhs = Result.Nodes.getNodeAs<DeclRefExpr>("lhs"); - const DeclRefExpr *rhs = Result.Nodes.getNodeAs<DeclRefExpr>("rhs"); - const ImplicitCastExpr *lhsExpr = dyn_cast<ImplicitCastExpr>(expr->getLHS()); - const ImplicitCastExpr *rhsExpr = dyn_cast<ImplicitCastExpr>(expr->getRHS()); + const BinaryOperator *Expression = Result.Nodes.getNodeAs<BinaryOperator>( + "node"); + const DeclRefExpr *LHS = Result.Nodes.getNodeAs<DeclRefExpr>("lhs"); + const DeclRefExpr *RHS = Result.Nodes.getNodeAs<DeclRefExpr>("rhs"); + const ImplicitCastExpr *LHSExpr = dyn_cast<ImplicitCastExpr>( + Expression->getLHS()); + const ImplicitCastExpr *RHSExpr = dyn_cast<ImplicitCastExpr>( + Expression->getRHS()); // The AST subtree that we are looking for will look like this: // -BinaryOperator ==/!= // |-ImplicitCastExpr LValueToRValue // | |-DeclRefExpr // |-ImplicitCastExpr LValueToRValue // |-DeclRefExpr // The check below ensures that we are dealing with the correct AST subtree // shape, and // also that both of the found DeclRefExpr's point to the same declaration. - if (lhs->getFoundDecl() == rhs->getFoundDecl() && lhsExpr && rhsExpr && - std::distance(lhsExpr->child_begin(), lhsExpr->child_end()) == 1 && - std::distance(rhsExpr->child_begin(), rhsExpr->child_end()) == 1 && - *lhsExpr->child_begin() == lhs && *rhsExpr->child_begin() == rhs) { - Diag.Report(expr->getLocStart(), errorID); - Diag.Report(expr->getLocStart(), noteID); + if (LHS->getFoundDecl() == RHS->getFoundDecl() && LHSExpr && RHSExpr && + std::distance(LHSExpr->child_begin(), LHSExpr->child_end()) == 1 && + std::distance(RHSExpr->child_begin(), RHSExpr->child_end()) == 1 && + *LHSExpr->child_begin() == LHS && *RHSExpr->child_begin() == RHS) { + Diag.Report(Expression->getLocStart(), ErrorID); + Diag.Report(Expression->getLocStart(), NoteID); } } void DiagnosticsMatcher::NoAddRefReleaseOnReturnChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "%1 cannot be called on the return value of %0"); - const Stmt *node = Result.Nodes.getNodeAs<Stmt>("node"); - const FunctionDecl *func = Result.Nodes.getNodeAs<FunctionDecl>("func"); - const MemberExpr *member = Result.Nodes.getNodeAs<MemberExpr>("member"); - const CXXMethodDecl *method = - dyn_cast<CXXMethodDecl>(member->getMemberDecl()); + const Stmt *Node = Result.Nodes.getNodeAs<Stmt>("node"); + const FunctionDecl *Func = Result.Nodes.getNodeAs<FunctionDecl>("func"); + const MemberExpr *Member = Result.Nodes.getNodeAs<MemberExpr>("member"); + const CXXMethodDecl *Method = + dyn_cast<CXXMethodDecl>(Member->getMemberDecl()); - Diag.Report(node->getLocStart(), errorID) << func << method; + Diag.Report(Node->getLocStart(), ErrorID) << Func << Method; } void DiagnosticsMatcher::RefCountedInsideLambdaChecker::run( const MatchFinder::MatchResult &Result) { static DenseSet<const CXXRecordDecl*> CheckedDecls; DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "Refcounted variable %0 of type %1 cannot be captured by a lambda"); - unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Note, "Please consider using a smart pointer"); const CXXRecordDecl *Lambda = Result.Nodes.getNodeAs<CXXRecordDecl>("decl"); - if (const LambdaExpr *OuterLambda = Result.Nodes.getNodeAs<LambdaExpr>("lambdaExpr")) { + if (const LambdaExpr *OuterLambda = + Result.Nodes.getNodeAs<LambdaExpr>("lambdaExpr")) { const CXXMethodDecl *OpCall = OuterLambda->getCallOperator(); QualType ReturnTy = OpCall->getReturnType(); if (const CXXRecordDecl *Record = ReturnTy->getAsCXXRecordDecl()) { Lambda = Record; } } if (!Lambda || !Lambda->isLambda()) { @@ -1407,193 +1419,193 @@ void DiagnosticsMatcher::RefCountedInsid } CheckedDecls.insert(Lambda); for (const LambdaCapture Capture : Lambda->captures()) { if (Capture.capturesVariable() && Capture.getCaptureKind() != LCK_ByRef) { QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType(); if (!Pointee.isNull() && isClassRefCounted(Pointee)) { - Diag.Report(Capture.getLocation(), errorID) << Capture.getCapturedVar() + Diag.Report(Capture.getLocation(), ErrorID) << Capture.getCapturedVar() << Pointee; - Diag.Report(Capture.getLocation(), noteID); + Diag.Report(Capture.getLocation(), NoteID); return; } } } } void DiagnosticsMatcher::ExplicitOperatorBoolChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "bad implicit conversion operator for %0"); - unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Note, "consider adding the explicit keyword to %0"); - const CXXConversionDecl *method = + const CXXConversionDecl *Method = Result.Nodes.getNodeAs<CXXConversionDecl>("node"); - const CXXRecordDecl *clazz = method->getParent(); + const CXXRecordDecl *Clazz = Method->getParent(); - if (!method->isExplicitSpecified() && - !MozChecker::hasCustomAnnotation(method, "moz_implicit") && - !IsInSystemHeader(method->getASTContext(), *method) && - isInterestingDeclForImplicitConversion(method)) { - Diag.Report(method->getLocStart(), errorID) << clazz; - Diag.Report(method->getLocStart(), noteID) << "'operator bool'"; + if (!Method->isExplicitSpecified() && + !MozChecker::hasCustomAnnotation(Method, "moz_implicit") && + !ASTIsInSystemHeader(Method->getASTContext(), *Method) && + isInterestingDeclForImplicitConversion(Method)) { + Diag.Report(Method->getLocStart(), ErrorID) << Clazz; + Diag.Report(Method->getLocStart(), NoteID) << "'operator bool'"; } } void DiagnosticsMatcher::NoDuplicateRefCntMemberChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); const CXXRecordDecl *D = Result.Nodes.getNodeAs<CXXRecordDecl>("decl"); - const FieldDecl *refCntMember = getClassRefCntMember(D); - const FieldDecl *foundRefCntBase = nullptr; + const FieldDecl *RefCntMember = getClassRefCntMember(D); + const FieldDecl *FoundRefCntBase = nullptr; if (!D->hasDefinition()) return; D = D->getDefinition(); // If we don't have an mRefCnt member, and we have less than 2 superclasses, // we don't have to run this loop, as neither case will ever apply. - if (!refCntMember && D->getNumBases() < 2) { + if (!RefCntMember && D->getNumBases() < 2) { return; } // Check every superclass for whether it has a base with a refcnt member, and // warn for those which do - for (auto &base : D->bases()) { + for (auto &Base : D->bases()) { // Determine if this base class has an mRefCnt member - const FieldDecl *baseRefCntMember = getBaseRefCntMember(base.getType()); + const FieldDecl *BaseRefCntMember = getBaseRefCntMember(Base.getType()); - if (baseRefCntMember) { - if (refCntMember) { + if (BaseRefCntMember) { + if (RefCntMember) { // We have an mRefCnt, and superclass has an mRefCnt - unsigned error = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned Error = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "Refcounted record %0 has multiple mRefCnt members"); - unsigned note1 = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned Note1 = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Note, "Superclass %0 also has an mRefCnt member"); - unsigned note2 = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned Note2 = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Note, "Consider using the _INHERITED macros for AddRef and Release here"); - Diag.Report(D->getLocStart(), error) << D; - Diag.Report(baseRefCntMember->getLocStart(), note1) - << baseRefCntMember->getParent(); - Diag.Report(refCntMember->getLocStart(), note2); + Diag.Report(D->getLocStart(), Error) << D; + Diag.Report(BaseRefCntMember->getLocStart(), Note1) + << BaseRefCntMember->getParent(); + Diag.Report(RefCntMember->getLocStart(), Note2); } - if (foundRefCntBase) { - unsigned error = Diag.getDiagnosticIDs()->getCustomDiagID( + if (FoundRefCntBase) { + unsigned Error = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "Refcounted record %0 has multiple superclasses with mRefCnt members"); - unsigned note = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned Note = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Note, "Superclass %0 has an mRefCnt member"); // superclass has mRefCnt, and another superclass also has an mRefCnt - Diag.Report(D->getLocStart(), error) << D; - Diag.Report(baseRefCntMember->getLocStart(), note) - << baseRefCntMember->getParent(); - Diag.Report(foundRefCntBase->getLocStart(), note) - << foundRefCntBase->getParent(); + Diag.Report(D->getLocStart(), Error) << D; + Diag.Report(BaseRefCntMember->getLocStart(), Note) + << BaseRefCntMember->getParent(); + Diag.Report(FoundRefCntBase->getLocStart(), Note) + << FoundRefCntBase->getParent(); } // Record that we've found a base with a mRefCnt member - foundRefCntBase = baseRefCntMember; + FoundRefCntBase = BaseRefCntMember; } } } void DiagnosticsMatcher::NeedsNoVTableTypeChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "%0 cannot be instantiated because %1 has a VTable"); - unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Note, "bad instantiation of %0 requested here"); - const ClassTemplateSpecializationDecl *specialization = + const ClassTemplateSpecializationDecl *Specialization = Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("node"); // Get the offending template argument - QualType offender; - const TemplateArgumentList &args = - specialization->getTemplateInstantiationArgs(); - for (unsigned i = 0; i < args.size(); ++i) { - offender = args[i].getAsType(); - if (typeHasVTable(offender)) { + QualType Offender; + const TemplateArgumentList &Args = + Specialization->getTemplateInstantiationArgs(); + for (unsigned i = 0; i < Args.size(); ++i) { + Offender = Args[i].getAsType(); + if (typeHasVTable(Offender)) { break; } } - Diag.Report(specialization->getLocStart(), errorID) << specialization - << offender; - Diag.Report(specialization->getPointOfInstantiation(), noteID) - << specialization; + Diag.Report(Specialization->getLocStart(), ErrorID) << Specialization + << Offender; + Diag.Report(Specialization->getPointOfInstantiation(), NoteID) + << Specialization; } void DiagnosticsMatcher::NonMemMovableTemplateArgChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "Cannot instantiate %0 with non-memmovable template argument %1"); - unsigned note1ID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned Note1ID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Note, "instantiation of %0 requested here"); // Get the specialization - const ClassTemplateSpecializationDecl *specialization = + const ClassTemplateSpecializationDecl *Specialization = Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization"); - SourceLocation requestLoc = specialization->getPointOfInstantiation(); + SourceLocation RequestLoc = Specialization->getPointOfInstantiation(); // Report an error for every template argument which is non-memmovable - const TemplateArgumentList &args = - specialization->getTemplateInstantiationArgs(); - for (unsigned i = 0; i < args.size(); ++i) { - QualType argType = args[i].getAsType(); - if (NonMemMovable.hasEffectiveAnnotation(argType)) { - Diag.Report(specialization->getLocation(), errorID) << specialization - << argType; + const TemplateArgumentList &Args = + Specialization->getTemplateInstantiationArgs(); + for (unsigned i = 0; i < Args.size(); ++i) { + QualType ArgType = Args[i].getAsType(); + if (NonMemMovable.hasEffectiveAnnotation(ArgType)) { + Diag.Report(Specialization->getLocation(), ErrorID) << Specialization + << ArgType; // XXX It would be really nice if we could get the instantiation stack // information // from Sema such that we could print a full template instantiation stack, // however, // it seems as though that information is thrown out by the time we get // here so we // can only report one level of template specialization (which in many // cases won't // be useful) - Diag.Report(requestLoc, note1ID) << specialization; - NonMemMovable.dumpAnnotationReason(Diag, argType, requestLoc); + Diag.Report(RequestLoc, Note1ID) << Specialization; + NonMemMovable.dumpAnnotationReason(Diag, ArgType, RequestLoc); } } } void DiagnosticsMatcher::NonMemMovableMemberChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "class %0 cannot have non-memmovable member %1 of type %2"); // Get the specialization - const CXXRecordDecl* Decl = + const CXXRecordDecl* Declaration = Result.Nodes.getNodeAs<CXXRecordDecl>("decl"); // Report an error for every member which is non-memmovable - for (const FieldDecl *Field : Decl->fields()) { + for (const FieldDecl *Field : Declaration->fields()) { QualType Type = Field->getType(); if (NonMemMovable.hasEffectiveAnnotation(Type)) { - Diag.Report(Field->getLocation(), errorID) << Decl + Diag.Report(Field->getLocation(), ErrorID) << Declaration << Field << Type; - NonMemMovable.dumpAnnotationReason(Diag, Type, Decl->getLocation()); + NonMemMovable.dumpAnnotationReason(Diag, Type, Declaration->getLocation()); } } } void DiagnosticsMatcher::ExplicitImplicitChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( @@ -1602,19 +1614,20 @@ void DiagnosticsMatcher::ExplicitImplici DiagnosticIDs::Note, "consider adding the explicit keyword to the constructor"); // We've already checked everything in the matcher, so we just have to report // the error. const CXXConstructorDecl *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor"); - const CXXRecordDecl *Decl = Result.Nodes.getNodeAs<CXXRecordDecl>("class"); + const CXXRecordDecl *Declaration = + Result.Nodes.getNodeAs<CXXRecordDecl>("class"); - Diag.Report(Ctor->getLocation(), ErrorID) << Decl->getDeclName(); + Diag.Report(Ctor->getLocation(), ErrorID) << Declaration->getDeclName(); Diag.Report(Ctor->getLocation(), NoteID); } void DiagnosticsMatcher::NoAutoTypeChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "Cannot use auto to declare a variable of type %0"); @@ -1661,47 +1674,47 @@ void DiagnosticsMatcher::RefCountedCopyC Diag.Report(E->getLocation(), ErrorID); Diag.Report(E->getLocation(), NoteID); } void DiagnosticsMatcher::AssertAssignmentChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned assignInsteadOfComp = Diag.getDiagnosticIDs()->getCustomDiagID( + unsigned AssignInsteadOfComp = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "Forbidden assignment in assert expression"); - const CallExpr *funcCall = Result.Nodes.getNodeAs<CallExpr>("funcCall"); + const CallExpr *FuncCall = Result.Nodes.getNodeAs<CallExpr>("funcCall"); - if (funcCall && HasSideEffectAssignment(funcCall)) { - Diag.Report(funcCall->getLocStart(), assignInsteadOfComp); + if (FuncCall && hasSideEffectAssignment(FuncCall)) { + Diag.Report(FuncCall->getLocStart(), AssignInsteadOfComp); } } class MozCheckAction : public PluginASTAction { public: ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, - StringRef fileName) override { + StringRef FileName) override { #if CLANG_VERSION_FULL >= 306 - std::unique_ptr<MozChecker> checker(llvm::make_unique<MozChecker>(CI)); - ASTConsumerPtr other(checker->getOtherConsumer()); + std::unique_ptr<MozChecker> Checker(llvm::make_unique<MozChecker>(CI)); + ASTConsumerPtr Other(Checker->getOtherConsumer()); - std::vector<ASTConsumerPtr> consumers; - consumers.push_back(std::move(checker)); - consumers.push_back(std::move(other)); - return llvm::make_unique<MultiplexConsumer>(std::move(consumers)); + std::vector<ASTConsumerPtr> Consumers; + Consumers.push_back(std::move(Checker)); + Consumers.push_back(std::move(Other)); + return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); #else - MozChecker *checker = new MozChecker(CI); + MozChecker *Checker = new MozChecker(CI); - ASTConsumer *consumers[] = {checker, checker->getOtherConsumer()}; - return new MultiplexConsumer(consumers); + ASTConsumer *Consumers[] = {Checker, Checker->getOtherConsumer()}; + return new MultiplexConsumer(Consumers); #endif } bool ParseArgs(const CompilerInstance &CI, - const std::vector<std::string> &args) override { + const std::vector<std::string> &Args) override { return true; } }; } static FrontendPluginRegistry::Add<MozCheckAction> X("moz-check", "check moz action"); // Export the registry on Windows.
--- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -115,20 +115,16 @@ #endif #include "mozilla/dom/ContentChild.h" #ifdef MOZ_EME #include "mozilla/EMEUtils.h" #include "mozilla/DetailedPromise.h" #endif -#ifdef MOZ_WIDGET_GONK -#include <cutils/properties.h> -#endif - namespace mozilla { namespace dom { static bool sVibratorEnabled = false; static uint32_t sMaxVibrateMS = 0; static uint32_t sMaxVibrateListLen = 0; static const char* kVibrationPermissionType = "vibration"; @@ -1634,167 +1630,16 @@ Navigator::PublishServer(const nsAString }, [domPromise] (nsresult aStatus) { domPromise->MaybeReject(aStatus); }); return domPromise.forget(); } -already_AddRefed<Promise> -Navigator::GetFeature(const nsAString& aName, ErrorResult& aRv) -{ - nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow); - RefPtr<Promise> p = Promise::Create(go, aRv); - if (aRv.Failed()) { - return nullptr; - } - -#if defined(XP_LINUX) - if (aName.EqualsLiteral("hardware.memory")) { - // with seccomp enabled, fopen() should be in a non-sandboxed process - if (XRE_IsParentProcess()) { - uint32_t memLevel = mozilla::hal::GetTotalSystemMemoryLevel(); - if (memLevel == 0) { - p->MaybeReject(NS_ERROR_NOT_AVAILABLE); - return p.forget(); - } - p->MaybeResolve((int)memLevel); - } else { - mozilla::dom::ContentChild* cc = - mozilla::dom::ContentChild::GetSingleton(); - RefPtr<Promise> ipcRef(p); - cc->SendGetSystemMemory(reinterpret_cast<uint64_t>(ipcRef.forget().take())); - } - return p.forget(); - } // hardware.memory -#endif - -#ifdef MOZ_WIDGET_GONK - if (StringBeginsWith(aName, NS_LITERAL_STRING("acl.")) && - (aName.EqualsLiteral("acl.version") || CheckPermission("external-app"))) { - char value[PROPERTY_VALUE_MAX]; - nsCString propertyKey("persist."); - propertyKey.Append(NS_ConvertUTF16toUTF8(aName)); - uint32_t len = property_get(propertyKey.get(), value, nullptr); - if (len > 0) { - p->MaybeResolve(NS_ConvertUTF8toUTF16(value)); - return p.forget(); - } - } -#endif - - // Mirror the dom.apps.developer_mode pref to let apps get it read-only. - if (aName.EqualsLiteral("dom.apps.developer_mode")) { - p->MaybeResolve(Preferences::GetBool("dom.apps.developer_mode", false)); - return p.forget(); - } - - p->MaybeResolveWithUndefined(); - return p.forget(); -} - -already_AddRefed<Promise> -Navigator::HasFeature(const nsAString& aName, ErrorResult& aRv) -{ - nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow); - RefPtr<Promise> p = Promise::Create(go, aRv); - if (aRv.Failed()) { - return nullptr; - } - - // Hardcoded extensions features which are b2g specific. -#ifdef MOZ_B2G - if (aName.EqualsLiteral("web-extensions") || - aName.EqualsLiteral("late-customization")) { - p->MaybeResolve(true); - return p.forget(); - } -#endif - - // Hardcoded manifest features. Some are still b2g specific. - const char manifestFeatures[][64] = { - "manifest.origin" - , "manifest.redirects" -#ifdef MOZ_B2G - , "manifest.chrome.navigation" - , "manifest.precompile" - , "manifest.role.homescreen" -#endif - }; - - nsAutoCString feature = NS_ConvertUTF16toUTF8(aName); - for (uint32_t i = 0; i < MOZ_ARRAY_LENGTH(manifestFeatures); i++) { - if (feature.Equals(manifestFeatures[i])) { - p->MaybeResolve(true); - return p.forget(); - } - } - - NS_NAMED_LITERAL_STRING(apiWindowPrefix, "api.window."); - if (StringBeginsWith(aName, apiWindowPrefix)) { - const nsAString& featureName = Substring(aName, apiWindowPrefix.Length()); - - // Temporary hardcoded entry points due to technical constraints - if (featureName.EqualsLiteral("Navigator.mozTCPSocket")) { - p->MaybeResolve(Preferences::GetBool("dom.mozTCPSocket.enabled")); - return p.forget(); - } - - if (featureName.EqualsLiteral("Navigator.mozMobileConnections") || - featureName.EqualsLiteral("MozMobileNetworkInfo")) { - p->MaybeResolve(Preferences::GetBool("dom.mobileconnection.enabled")); - return p.forget(); - } - - if (featureName.EqualsLiteral("Navigator.mozInputMethod")) { - p->MaybeResolve(Preferences::GetBool("dom.mozInputMethod.enabled")); - return p.forget(); - } - - if (featureName.EqualsLiteral("Navigator.getDeviceStorage")) { - p->MaybeResolve(Preferences::GetBool("device.storage.enabled")); - return p.forget(); - } - - if (featureName.EqualsLiteral("Navigator.mozNetworkStats")) { - p->MaybeResolve(Preferences::GetBool("dom.mozNetworkStats.enabled")); - return p.forget(); - } - - if (featureName.EqualsLiteral("Navigator.push")) { - p->MaybeResolve(Preferences::GetBool("services.push.enabled")); - return p.forget(); - } - - if (featureName.EqualsLiteral("Navigator.mozAlarms")) { - p->MaybeResolve(Preferences::GetBool("dom.mozAlarms.enabled")); - return p.forget(); - } - - if (featureName.EqualsLiteral("Navigator.mozCameras")) { - p->MaybeResolve(true); - return p.forget(); - } - - if (featureName.EqualsLiteral("XMLHttpRequest.mozSystem")) { - p->MaybeResolve(true); - return p.forget(); - } - - p->MaybeResolveWithUndefined(); - return p.forget(); - } - - // resolve with <undefined> because the feature name is not supported - p->MaybeResolveWithUndefined(); - - return p.forget(); -} - PowerManager* Navigator::GetMozPower(ErrorResult& aRv) { if (!mPowerManager) { if (!mWindow) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; }
--- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -180,23 +180,16 @@ public: nsIURI* aURI, bool aIsCallerChrome, nsAString& aUserAgent); // Clears the user agent cache by calling: // NavigatorBinding::ClearCachedUserAgentValue(this); void ClearUserAgentCache(); - // Feature Detection API - already_AddRefed<Promise> GetFeature(const nsAString& aName, - ErrorResult& aRv); - - already_AddRefed<Promise> HasFeature(const nsAString &aName, - ErrorResult& aRv); - bool Vibrate(uint32_t aDuration); bool Vibrate(const nsTArray<uint32_t>& aDuration); void SetVibrationPermission(bool aPermitted, bool aPersistent); uint32_t MaxTouchPoints(); void GetAppCodeName(nsString& aAppCodeName, ErrorResult& aRv) { aRv = GetAppCodeName(aAppCodeName); }
--- a/dom/base/test/chrome.ini +++ b/dom/base/test/chrome.ini @@ -21,11 +21,9 @@ support-files = file_navigator_resolve_i subsuite = clipboard [test_messagemanager_principal.html] [test_messagemanager_send_principal.html] skip-if = buildapp == 'mulet' [test_bug945152.html] [test_bug1008126.html] [test_sandboxed_blob_uri.html] [test_websocket_frame.html] -[test_getFeature_with_perm.html] -[test_hasFeature.html] [test_mozbrowser_apis_allowed.html]
deleted file mode 100644 --- a/dom/base/test/test_getFeature_with_perm.html +++ /dev/null @@ -1,135 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=979109 ---> -<head> - <meta charset="utf-8"> - <title>Test for Bug 979109</title> - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=983502">Mozilla Bug 983502</a> -<script type="application/javascript"> - -function testSupported() { - var mem; - navigator.getFeature("hardware.memory").then(function(mem) { - - var isLinux = (navigator.platform.indexOf('Linux') != -1); - var isAndroid = !!navigator.userAgent.includes("Android"); - var isB2G = !isAndroid && /Mobile|Tablet/.test(navigator.userAgent); - - if (isLinux) { - info("It is Linux version:"); - } - if (isAndroid) { - info("It is Android version"); - } - if (isB2G) { - info("It is B2G version"); - } - - if (isLinux || isAndroid || isB2G) { - ok(typeof mem === 'number' && (mem) % 1 === 0, "We should receive an integer on this platform"); - ok(mem > 0, "hardware.memory is supported on this platform. mem=" + mem + "MiB"); - } else { - ok(typeof mem === 'undefined', "hardware.memory is not support on this platform"); - } - - runNextTest(); - - },function(mem) { - ok(false, "The Promise should not be rejected"); - }); -} - -function testNotSupported() { - var tv; - navigator.getFeature("hardware.tv").then(function(tv) { - ok(typeof tv === 'undefined', "Resolve the Promise with undefined value (hardware.tv)"); - runNextTest(); - },function(tv) { - ok(false, "The Promise should not be rejected"); - }); -} - -function testNotSupportedManifest() { - navigator.getFeature("manifest.origin").then(function(feature) { - ok(typeof feature == 'undefined', "manifest.* resolves with undefined on getFeature"); - runNextTest(); - }, function() { - ok(false, "The Promise should not be rejected"); - }); -} - -function createManifestTest(aFeature) { - return function() { - var res; - navigator.hasFeature(aFeature).then(function(res) { - ok(res === true, "Resolve the Promise with 'true' for " + aFeature); - runNextTest(); - }, function(tv) { - ok(false, "The Promise should not be rejected"); - }); - } -} - -function testDevMode(aExpected) { - return function() { - navigator.getFeature("dom.apps.developer_mode").then(res => { - is(res, aExpected, "dom.apps.developer_mode is " + aExpected); - runNextTest(); - }, function() { - ok(false, "The Promise should not be rejected"); - }); - } -} - -function enableDevMode() { - SpecialPowers.pushPrefEnv({"set": [["dom.apps.developer_mode", true]]}, runNextTest); -} - -var currentTest = -1; -var tests = [ - testNotSupported, - testNotSupportedManifest, - testSupported, - createManifestTest("manifest.origin"), - createManifestTest("manifest.redirects"), - testDevMode(false), - enableDevMode, - testDevMode(true) -]; - -function runNextTest() { - currentTest++; - if (currentTest < tests.length) { - tests[currentTest](); - } else { - SimpleTest.finish(); - } -} - -info("About to run " + tests.length + " tests"); - -ok('getFeature' in navigator, "navigator.getFeature should exist"); -ok('hasFeature' in navigator, "navigator.hasFeature should exist"); -// B2G specific manifest features. -// Touching navigator before pushPermissions makes it fail. -if (!navigator.userAgent.includes("Android") && - /Mobile|Tablet/.test(navigator.userAgent)) { - info("Adding B2G specific tests"); - tests.push(createManifestTest("manifest.chrome.navigation")); - tests.push(createManifestTest("manifest.precompile")); - tests.push(createManifestTest("manifest.role.homescreen")); -} -runNextTest(); -ok(true, "Test DONE"); - -SimpleTest.waitForExplicitFinish(); - -</script> -</body> -</html>
deleted file mode 100644 --- a/dom/base/test/test_hasFeature.html +++ /dev/null @@ -1,101 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=1009645 ---> -<head> - <meta charset="utf-8"> - <title>Test for Bug 1009645</title> - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1009645">Mozilla Bug 1009645</a> -<script type="application/javascript"> - -var b2gOnly; - -function pref(name) { - try { - return SpecialPowers.getBoolPref(name); - } catch (e) { - return false; - } -} - -function testAPIs() { - var APIEndPoints = [ - { name: "MozMobileNetworkInfo", enabled: pref("dom.mobileconnection.enabled") }, - // { name: "Navigator.mozBluetooth", enabled: b2gOnly }, // conditional on MOZ_B2G_BT, tricky to test - // Bug 1266035 { name: "Navigator.mozContacts", enabled: pref("dom.mozContacts.enabled") }, - { name: "Navigator.getDeviceStorage", enabled: pref("device.storage.enabled") }, - // Bug 1266035 { name: "Navigator.addIdleObserver", enabled: true }, - { name: "Navigator.mozNetworkStats", enabled: pref("dom.mozNetworkStats.enabled") }, - { name: "Navigator.push", enabled: pref("services.push.enabled") }, - // { name: "Navigator.mozTime", enabled: b2gOnly }, // conditional on MOZ_TIME_MANAGER, tricky to test - // { name: "Navigator.mozFMRadio", enabled: b2gOnly }, // conditional on MOZ_B2G_FM, tricky to test - { name: "Navigator.mozCameras", enabled: true }, - { name: "Navigator.mozAlarms", enabled: pref("dom.mozAlarms.enabled") }, - { name: "Navigator.mozTCPSocket", enabled: pref("dom.mozTCPSocket.enabled") }, - { name: "Navigator.mozInputMethod", enabled: pref("dom.mozInputMethod.enabled") }, - { name: "Navigator.mozMobileConnections", enabled: pref("dom.mobileconnection.enabled") }, - { name: "XMLHttpRequest.mozSystem", enabled: true } - ]; - - var promises = []; - APIEndPoints.forEach(function(v) { - promises.push(navigator.hasFeature("api.window." + v.name)); - }); - - return Promise.all(promises).then(function(values) { - for (var i = 0; i < values.length; ++i) { - is(values[i], APIEndPoints[i].enabled, - "Endpoint " + APIEndPoints[i].name + " resolved with the correct value. " + - "If this is failing because you're changing how an API is exposed, you " + - "must contact the Marketplace team to let them know about the change."); - } - }, function() { - ok(false, "The Promise should not be rejected"); - }); -} - -function testExtensions() { - if (!b2gOnly) { - return Promise.resolve(); - } - - var builtInFeatures = [ - {feature: "web-extensions", value: true}, - {feature: "late-customization", value: true} - ]; - - builtInFeatures.forEach(function(x) { - navigator.hasFeature(x.feature).then(function(value) { - is(value, x.value, "Resolve the Promise with " + value + " for feature: " + x.feature); - }).catch(function(ex) { - ok(false, "The Promise should not be rejected"); - }); - }); - return Promise.resolve(); -} - -SpecialPowers.pushPermissions([ - {type: "feature-detection", allow: true, context: document} -], function() { - b2gOnly = (function() { - var isAndroid = !!navigator.userAgent.includes("Android"); - var isMulet = pref("b2g.is_mulet"); - var isB2g = isMulet || (!isAndroid && /Mobile|Tablet/.test(navigator.userAgent)); - return isB2g ? true : undefined; - })(); - - ok('hasFeature' in navigator, "navigator.hasFeature should exist"); - testAPIs().then(testExtensions).catch(function(e) { - ok(false, "The Promise should not be rejected: " + e); - }).then(SimpleTest.finish); -}); - -SimpleTest.waitForExplicitFinish(); -</script> -</body> -</html>
--- a/dom/browser-element/BrowserElementParent.js +++ b/dom/browser-element/BrowserElementParent.js @@ -784,49 +784,35 @@ BrowserElementParent.prototype = { "modifiers": modifiers }); }), sendTouchEvent: defineNoReturnMethod(function(type, identifiers, touchesX, touchesY, radiisX, radiisY, rotationAngles, forces, count, modifiers) { - let tabParent = this._frameLoader.tabParent; - if (tabParent && tabParent.useAsyncPanZoom) { - tabParent.injectTouchEvent(type, - identifiers, - touchesX, - touchesY, - radiisX, - radiisY, - rotationAngles, - forces, - count, - modifiers); - } else { - let offset = this.getChildProcessOffset(); - for (var i = 0; i < touchesX.length; i++) { - touchesX[i] += offset.x; - } - for (var i = 0; i < touchesY.length; i++) { - touchesY[i] += offset.y; - } - this._sendAsyncMsg("send-touch-event", { - "type": type, - "identifiers": identifiers, - "touchesX": touchesX, - "touchesY": touchesY, - "radiisX": radiisX, - "radiisY": radiisY, - "rotationAngles": rotationAngles, - "forces": forces, - "count": count, - "modifiers": modifiers - }); + let offset = this.getChildProcessOffset(); + for (var i = 0; i < touchesX.length; i++) { + touchesX[i] += offset.x; + } + for (var i = 0; i < touchesY.length; i++) { + touchesY[i] += offset.y; } + this._sendAsyncMsg("send-touch-event", { + "type": type, + "identifiers": identifiers, + "touchesX": touchesX, + "touchesY": touchesY, + "radiisX": radiisX, + "radiisY": radiisY, + "rotationAngles": rotationAngles, + "forces": forces, + "count": count, + "modifiers": modifiers + }); }), getCanGoBack: defineDOMRequestMethod('get-can-go-back'), getCanGoForward: defineDOMRequestMethod('get-can-go-forward'), getContentDimensions: defineDOMRequestMethod('get-contentdimensions'), findAll: defineNoReturnMethod(function(searchString, caseSensitivity) { return this._sendAsyncMsg('find-all', {
--- a/dom/canvas/test/webgl-conf/checkout/conformance2/glsl3/array-complex-indexing.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/glsl3/array-complex-indexing.html @@ -72,27 +72,16 @@ void main() { precision mediump float; out vec4 color; void main() { float a = (float[3](2.0, 1.0, 0.0))[0]; color = (a == 2.0) ? vec4(0, 1.0, 0, 1.0) : vec4(1.0, 0, 0, 1.0); } </script> -<script id="fshader-sequence-operator" type="x-shader/x-fragment">#version 300 es -precision mediump float; -out vec4 color; - -void main() { - float a[2] = float[2](1.0, 0.0); - float b[2] = float[2](2.0, 3.0); - float c = (a, b)[0]; - color = (c == 2.0) ? vec4(0, 1.0, 0, 1.0) : vec4(1.0, 0, 0, 1.0); -} -</script> <script type="application/javascript"> "use strict"; description("Indexing complex array expressions"); debug(""); GLSLConformanceTester.runRenderTests([ { fShaderId: 'fshader-assignment', @@ -107,19 +96,13 @@ GLSLConformanceTester.runRenderTests([ passMsg: 'Test indexing a function return with a side-effect: (functionReturnArray())[0]' }, { fShaderId: 'fshader-array-initialization', fShaderSuccess: true, linkSuccess: true, passMsg: 'Test indexing an array initialization: (float[3](2.0, 1.0, 0.0))[0]' }, -{ - fShaderId: 'fshader-sequence-operator', - fShaderSuccess: true, - linkSuccess: true, - passMsg: 'Test indexing a sequence operator: (a, b)[0]' -}, ], 2); </script> </body> </html>
--- a/dom/events/test/test_bug456273.html +++ b/dom/events/test/test_bug456273.html @@ -18,17 +18,17 @@ https://bugzilla.mozilla.org/show_bug.cg <div id="edit456273" contenteditable="true">text</div> <pre id="test"> <script type="application/javascript"> /** Test for Bug 456273 **/ function doTest() { - var ev = document.createEvent('KeyEvents'); + var ev = document.createEvent('KeyboardEvent'); ev.initKeyEvent("keypress", true, true, null, true, false, false, false, 0, "z".charCodeAt(0)); SpecialPowers.dispatchEvent(window, document.getElementById('edit456273'), ev); ok(true, "PASS"); SimpleTest.finish(); }
--- a/dom/events/test/test_bug508479.html +++ b/dom/events/test/test_bug508479.html @@ -34,25 +34,25 @@ function fireDrop(element, shouldAllowDr synthesizeMouse(element, 2, 2, { type: "mousedown" }); synthesizeMouse(element, 11, 11, { type: "mousemove" }); synthesizeMouse(element, 20, 20, { type: "mousemove" }); window.removeEventListener("dragstart", trapDrag, true); synthesizeMouse(element, 20, 20, { type: "mouseup" }); ds.startDragSession(); - var event = document.createEvent("DragEvents"); + var event = document.createEvent("DragEvent"); event.initDragEvent("dragover", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); fireEvent(element, event); is(ds.getCurrentSession().canDrop, shouldAllowDrop, "Unexpected .canDrop"); is(ds.getCurrentSession().onlyChromeDrop, shouldAllowOnlyChromeDrop, "Unexpected .onlyChromeDrop"); - event = document.createEvent("DragEvents"); + event = document.createEvent("DragEvent"); event.initDragEvent("drop", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); fireEvent(element, event); ds.endDragSession(false); ok(!ds.getCurrentSession(), "There shouldn't be a drag session anymore!"); } var chromeGotEvent = false;
--- a/dom/events/test/test_bug591249.xul +++ b/dom/events/test/test_bug591249.xul @@ -55,17 +55,17 @@ function RunTest() { // need to use real mouse action to get the dataTransfer window.addEventListener("dragstart", trapDrag, true); synthesizeMouse(image, 2, 2, { type: "mousedown" }); synthesizeMouse(image, 11, 11, { type: "mousemove" }); synthesizeMouse(image, 20, 20, { type: "mousemove" }); window.removeEventListener("dragstart", trapDrag, true); synthesizeMouse(image, 20, 20, { type: "mouseup" }); - var event = document.createEvent("DragEvents"); + var event = document.createEvent("DragEvent"); event.initDragEvent("dragover", true, true, iBox.ownerDocument.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, iBox, dataTransfer); fireEvent(iBox, event); synthesizeMouse(image, 3, 3, { type: "mousedown" }); synthesizeMouse(image, 23, 23, { type: "mousemove" }); synthesizeMouse(iBox, insideBoxX, insideBoxY, { type: "mousemove" }); ok(window.getComputedStyle(iBox).backgroundColor == "rgb(255, 255, 0)", "The -moz-drag-over style should be applied."); synthesizeMouse(iBox, insideBoxX, insideBoxY, { type: "mouseup" }); window.setTimeout(function () { completeTest(iBox); }, 40);
--- a/dom/events/test/test_dom_keyboard_event.html +++ b/dom/events/test/test_dom_keyboard_event.html @@ -37,32 +37,32 @@ function testInitializingUntrustedEvent( ctrlKey: false, altKey: true, shiftKey: false, metaKey: false, keyCode: 0x11, charCode: 0x30 }, { createEventArg: "keyboardEvent", type: "boo", bubbles: false, cancelable: false, view: window, ctrlKey: false, altKey: false, shiftKey: true, metaKey: false, keyCode: 0x30, charCode: 0x40 }, - { createEventArg: "KeyEvents", + { createEventArg: "KeyBoardEvent", type: "foo", bubbles: true, cancelable: true, view: null, ctrlKey: false, altKey: false, shiftKey: false, metaKey: true, keyCode: 0x00, charCode: 0x50 }, - { createEventArg: "keyevents", + { createEventArg: "keyboardevEnt", type: "bar", bubbles: false, cancelable: true, view: window, ctrlKey: true, altKey: true, shiftKey: false, metaKey: false, keyCode: 0x00, charCode: 0x60 }, - { createEventArg: "Keyevents", + { createEventArg: "KeyboaRdevent", type: "keydown", bubbles: true, cancelable: false, view: null, ctrlKey: false, altKey: true, shiftKey: false, metaKey: true, keyCode: 0x30, charCode: 0x00 }, - { createEventArg: "keyEvents", + { createEventArg: "KEYBOARDEVENT", type: "keyup", bubbles: false, cancelable: false, view: window, ctrlKey: true, altKey: false, shiftKey: true, metaKey: false, keyCode: 0x10, charCode: 0x80 }, { createEventArg: "KeyboardEvent", type: "keypress", bubbles: false, cancelable: false, view: window, ctrlKey: true, altKey: false, shiftKey: true, metaKey: true, keyCode: 0x10, charCode: 0x80 },
--- a/dom/events/test/test_dragstart.html +++ b/dom/events/test/test_dragstart.html @@ -52,18 +52,18 @@ function afterDragTests() var evt = document.createEvent("dragevent"); ok(evt instanceof DragEvent, "synthetic dragevent class") ok(evt instanceof MouseEvent, "synthetic event inherits from MouseEvent") evt.initDragEvent("dragstart", true, true, window, 1, 40, 35, 20, 15, false, true, false, false, 0, null, null); $("synthetic").dispatchEvent(evt); - var evt = document.createEvent("dragevents"); - ok(evt instanceof DragEvent, "synthetic dragevents class") + var evt = document.createEvent("dragevent"); + ok(evt instanceof DragEvent, "synthetic dragevent class") evt.initDragEvent("dragover", true, true, window, 0, 40, 35, 20, 15, true, false, true, true, 2, document.documentElement, null); $("synthetic2").dispatchEvent(evt); // next, dragging links and images sendMouseEventsForDrag("link"); sendMouseEventsForDrag("image");
--- a/dom/flyweb/FlyWebPublishedServer.cpp +++ b/dom/flyweb/FlyWebPublishedServer.cpp @@ -166,16 +166,26 @@ NS_IMPL_ISUPPORTS_INHERITED0(FlyWebPubli FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(nsPIDOMWindowInner* aOwner, const nsAString& aName, const FlyWebPublishOptions& aOptions) : FlyWebPublishedServer(aOwner, aName, aOptions) , mHttpServer(new HttpServer()) { LOG_I("FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(%p)", this); +} + +void +FlyWebPublishedServerImpl::PermissionGranted(bool aGranted) +{ + LOG_I("FlyWebPublishedServerImpl::PermissionGranted(%b)", aGranted); + if (!aGranted) { + PublishedServerStarted(NS_ERROR_FAILURE); + return; + } mHttpServer->Init(-1, Preferences::GetBool("flyweb.use-tls", false), this); } void FlyWebPublishedServerImpl::Close() { FlyWebPublishedServer::Close(); @@ -247,72 +257,84 @@ FlyWebPublishedServerImpl::OnWebSocketAc } /******** FlyWebPublishedServerChild ********/ FlyWebPublishedServerChild::FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwner, const nsAString& aName, const FlyWebPublishOptions& aOptions) : FlyWebPublishedServer(aOwner, aName, aOptions) - , mActorDestroyed(false) + , mActorExists(false) { LOG_I("FlyWebPublishedServerChild::FlyWebPublishedServerChild(%p)", this); - ContentChild::GetSingleton()-> - SendPFlyWebPublishedServerConstructor(this, - PromiseFlatString(aName), - aOptions); - // The matching release happens when the actor is destroyed, in // ContentChild::DeallocPFlyWebPublishedServerChild NS_ADDREF_THIS(); } +void +FlyWebPublishedServerChild::PermissionGranted(bool aGranted) +{ + if (!aGranted) { + PublishedServerStarted(NS_ERROR_FAILURE); + return; + } + + mActorExists = true; + FlyWebPublishOptions options; + options.mUiUrl = mUiUrl; + + // Proceed with initialization. + ContentChild::GetSingleton()-> + SendPFlyWebPublishedServerConstructor(this, mName, options); +} + bool FlyWebPublishedServerChild::RecvServerReady(const nsresult& aStatus) { LOG_I("FlyWebPublishedServerChild::RecvServerReady(%p)", this); - MOZ_ASSERT(!mActorDestroyed); + MOZ_ASSERT(mActorExists); PublishedServerStarted(aStatus); return true; } bool FlyWebPublishedServerChild::RecvServerClose() { LOG_I("FlyWebPublishedServerChild::RecvServerClose(%p)", this); - MOZ_ASSERT(!mActorDestroyed); + MOZ_ASSERT(mActorExists); Close(); return true; } bool FlyWebPublishedServerChild::RecvFetchRequest(const IPCInternalRequest& aRequest, const uint64_t& aRequestId) { LOG_I("FlyWebPublishedServerChild::RecvFetchRequest(%p)", this); - MOZ_ASSERT(!mActorDestroyed); + MOZ_ASSERT(mActorExists); RefPtr<InternalRequest> request = new InternalRequest(aRequest); mPendingRequests.Put(request, aRequestId); FireFetchEvent(request); return true; } bool FlyWebPublishedServerChild::RecvWebSocketRequest(const IPCInternalRequest& aRequest, const uint64_t& aRequestId, PTransportProviderChild* aProvider) { LOG_I("FlyWebPublishedServerChild::RecvWebSocketRequest(%p)", this); - MOZ_ASSERT(!mActorDestroyed); + MOZ_ASSERT(mActorExists); RefPtr<InternalRequest> request = new InternalRequest(aRequest); mPendingRequests.Put(request, aRequestId); // Not addreffing here. The addref was already done when the // PTransportProvider child constructor original ran. mPendingTransportProviders.Put(aRequestId, dont_AddRef(static_cast<TransportProviderChild*>(aProvider))); @@ -322,26 +344,26 @@ FlyWebPublishedServerChild::RecvWebSocke return true; } void FlyWebPublishedServerChild::ActorDestroy(ActorDestroyReason aWhy) { LOG_I("FlyWebPublishedServerChild::ActorDestroy(%p)", this); - mActorDestroyed = true; + mActorExists = false; } void FlyWebPublishedServerChild::OnFetchResponse(InternalRequest* aRequest, InternalResponse* aResponse) { LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this); - if (mActorDestroyed) { + if (!mActorExists) { LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this); return; } uint64_t id = mPendingRequests.Get(aRequest); MOZ_ASSERT(id); mPendingRequests.Remove(aRequest); @@ -356,17 +378,17 @@ FlyWebPublishedServerChild::OnFetchRespo already_AddRefed<nsITransportProvider> FlyWebPublishedServerChild::OnWebSocketAcceptInternal(InternalRequest* aRequest, const Optional<nsAString>& aProtocol, ErrorResult& aRv) { LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p)", this); - if (mActorDestroyed) { + if (!mActorExists) { LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p) - No actor!", this); return nullptr; } uint64_t id = mPendingRequests.Get(aRequest); MOZ_ASSERT(id); mPendingRequests.Remove(aRequest); @@ -395,17 +417,17 @@ FlyWebPublishedServerChild::OnWebSocketA } void FlyWebPublishedServerChild::OnWebSocketResponse(InternalRequest* aRequest, InternalResponse* aResponse) { LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this); - if (mActorDestroyed) { + if (!mActorExists) { LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this); return; } uint64_t id = mPendingRequests.Get(aRequest); MOZ_ASSERT(id); mPendingRequests.Remove(aRequest); @@ -423,17 +445,17 @@ FlyWebPublishedServerChild::OnWebSocketR void FlyWebPublishedServerChild::Close() { LOG_I("FlyWebPublishedServerChild::Close(%p)", this); FlyWebPublishedServer::Close(); - if (!mActorDestroyed) { + if (mActorExists) { LOG_I("FlyWebPublishedServerChild::Close - sending __delete__ (%p)", this); Send__delete__(this); } } /******** FlyWebPublishedServerParent ********/
--- a/dom/flyweb/FlyWebPublishedServer.h +++ b/dom/flyweb/FlyWebPublishedServer.h @@ -52,16 +52,18 @@ public: return mName; } void GetUiUrl(nsAString& aUiUrl) { aUiUrl = mUiUrl; } + virtual void PermissionGranted(bool aGranted) = 0; + virtual void OnFetchResponse(InternalRequest* aRequest, InternalResponse* aResponse) = 0; already_AddRefed<WebSocket> OnWebSocketAccept(InternalRequest* aConnectRequest, const Optional<nsAString>& aProtocol, ErrorResult& aRv); virtual void OnWebSocketResponse(InternalRequest* aConnectRequest, InternalResponse* aResponse) = 0;
--- a/dom/flyweb/FlyWebPublishedServerIPC.h +++ b/dom/flyweb/FlyWebPublishedServerIPC.h @@ -45,16 +45,17 @@ public: void GetCertKey(nsACString& aKey) { if (mHttpServer) { mHttpServer->GetCertKey(aKey); } else { aKey.Truncate(); } } + virtual void PermissionGranted(bool aGranted) override; virtual void OnFetchResponse(InternalRequest* aRequest, InternalResponse* aResponse) override; virtual void OnWebSocketResponse(InternalRequest* aConnectRequest, InternalResponse* aResponse) override; virtual already_AddRefed<nsITransportProvider> OnWebSocketAcceptInternal(InternalRequest* aConnectRequest, const Optional<nsAString>& aProtocol, ErrorResult& aRv) override; @@ -93,16 +94,17 @@ private: class FlyWebPublishedServerChild final : public FlyWebPublishedServer , public PFlyWebPublishedServerChild { public: FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwner, const nsAString& aName, const FlyWebPublishOptions& aOptions); + virtual void PermissionGranted(bool aGranted) override; virtual bool RecvServerReady(const nsresult& aStatus) override; virtual bool RecvServerClose() override; virtual bool RecvFetchRequest(const IPCInternalRequest& aRequest, const uint64_t& aRequestId) override; virtual bool RecvWebSocketRequest(const IPCInternalRequest& aRequest, const uint64_t& aRequestId, PTransportProviderChild* aProvider) override; @@ -120,17 +122,17 @@ public: virtual void ActorDestroy(ActorDestroyReason aWhy) override; private: ~FlyWebPublishedServerChild() {} nsDataHashtable<nsRefPtrHashKey<InternalRequest>, uint64_t> mPendingRequests; nsRefPtrHashtable<nsUint64HashKey, TransportProviderChild> mPendingTransportProviders; - bool mActorDestroyed; + bool mActorExists; }; class FlyWebPublishedServerParent final : public PFlyWebPublishedServerParent , public nsIDOMEventListener { public: FlyWebPublishedServerParent(const nsAString& aName, const FlyWebPublishOptions& aOptions);
--- a/dom/flyweb/FlyWebService.cpp +++ b/dom/flyweb/FlyWebService.cpp @@ -4,46 +4,160 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/FlyWebService.h" #include "mozilla/StaticPtr.h" #include "mozilla/ScopeExit.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/FlyWebPublishedServerIPC.h" +#include "mozilla/AddonPathService.h" #include "nsISocketTransportService.h" #include "mdns/libmdns/nsDNSServiceInfo.h" #include "nsIUUIDGenerator.h" #include "nsStandardURL.h" #include "mozilla/Services.h" #include "nsISupportsPrimitives.h" #include "mozilla/dom/FlyWebDiscoveryManagerBinding.h" #include "prnetdb.h" #include "DNS.h" +#include "nsContentPermissionHelper.h" #include "nsSocketTransportService2.h" #include "nsSocketTransport2.h" #include "nsHashPropertyBag.h" #include "nsNetUtil.h" #include "nsISimpleEnumerator.h" #include "nsIProperty.h" #include "nsICertOverrideService.h" namespace mozilla { namespace dom { struct FlyWebPublishOptions; static LazyLogModule gFlyWebServiceLog("FlyWebService"); #undef LOG_I #define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) + #undef LOG_E #define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Error, (__VA_ARGS__)) + #undef LOG_TEST_I #define LOG_TEST_I(...) MOZ_LOG_TEST(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug) +class FlyWebPublishServerPermissionCheck final + : public nsIContentPermissionRequest + , public nsIRunnable +{ +public: + NS_DECL_ISUPPORTS + + FlyWebPublishServerPermissionCheck(const nsCString& aServiceName, uint64_t aWindowID, + FlyWebPublishedServer* aServer) + : mServiceName(aServiceName) + , mWindowID(aWindowID) + , mServer(aServer) + {} + + uint64_t WindowID() const + { + return mWindowID; + } + + NS_IMETHOD Run() override + { + MOZ_ASSERT(NS_IsMainThread()); + + nsGlobalWindow* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID); + if (!globalWindow) { + return Cancel(); + } + mWindow = globalWindow->AsInner(); + if (NS_WARN_IF(!mWindow)) { + return Cancel(); + } + + nsCOMPtr<nsIDocument> doc = mWindow->GetDoc(); + if (NS_WARN_IF(!doc)) { + return Cancel(); + } + + mPrincipal = doc->NodePrincipal(); + MOZ_ASSERT(mPrincipal); + + mRequester = new nsContentPermissionRequester(mWindow); + return nsContentPermissionUtils::AskPermission(this, mWindow); + } + + NS_IMETHOD Cancel() override + { + Resolve(false); + return NS_OK; + } + + NS_IMETHOD Allow(JS::HandleValue aChoices) override + { + MOZ_ASSERT(aChoices.isUndefined()); + Resolve(true); + return NS_OK; + } + + NS_IMETHOD GetTypes(nsIArray** aTypes) override + { + nsTArray<nsString> emptyOptions; + return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("flyweb-publish-server"), + NS_LITERAL_CSTRING("unused"), emptyOptions, aTypes); + } + + NS_IMETHOD GetRequester(nsIContentPermissionRequester** aRequester) override + { + NS_ENSURE_ARG_POINTER(aRequester); + nsCOMPtr<nsIContentPermissionRequester> requester = mRequester; + requester.forget(aRequester); + return NS_OK; + } + + NS_IMETHOD GetPrincipal(nsIPrincipal** aRequestingPrincipal) override + { + NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal); + return NS_OK; + } + + NS_IMETHOD GetWindow(mozIDOMWindow** aRequestingWindow) override + { + NS_IF_ADDREF(*aRequestingWindow = mWindow); + return NS_OK; + } + + NS_IMETHOD GetElement(nsIDOMElement** aRequestingElement) override + { + *aRequestingElement = nullptr; + return NS_OK; + } + +private: + void Resolve(bool aResolve) + { + mServer->PermissionGranted(aResolve); + } + + virtual ~FlyWebPublishServerPermissionCheck() = default; + + nsCString mServiceName; + uint64_t mWindowID; + RefPtr<FlyWebPublishedServer> mServer; + nsCOMPtr<nsPIDOMWindowInner> mWindow; + nsCOMPtr<nsIPrincipal> mPrincipal; + nsCOMPtr<nsIContentPermissionRequester> mRequester; +}; + +NS_IMPL_ISUPPORTS(FlyWebPublishServerPermissionCheck, + nsIContentPermissionRequest, + nsIRunnable) + class FlyWebMDNSService final : public nsIDNSServiceDiscoveryListener , public nsIDNSServiceResolveListener , public nsIDNSRegistrationListener , public nsITimerCallback { friend class FlyWebService; @@ -836,39 +950,88 @@ FlyWebService::Init() mMDNSFlywebService = nullptr; rv.SuppressException(); } } return ErrorResult(NS_OK); } +static already_AddRefed<FlyWebPublishPromise> +MakeRejectionPromise(const char* name) +{ + MozPromiseHolder<FlyWebPublishPromise> holder; + RefPtr<FlyWebPublishPromise> promise = holder.Ensure(name); + holder.Reject(NS_ERROR_FAILURE, name); + return promise.forget(); +} + already_AddRefed<FlyWebPublishPromise> FlyWebService::PublishServer(const nsAString& aName, const FlyWebPublishOptions& aOptions, nsPIDOMWindowInner* aWindow) { // Scan uiUrl for illegal characters RefPtr<FlyWebPublishedServer> existingServer = FlyWebService::GetOrCreate()->FindPublishedServerByName(aName); if (existingServer) { LOG_I("PublishServer: Trying to publish server with already-existing name %s.", NS_ConvertUTF16toUTF8(aName).get()); - MozPromiseHolder<FlyWebPublishPromise> holder; - RefPtr<FlyWebPublishPromise> promise = holder.Ensure(__func__); - holder.Reject(NS_ERROR_FAILURE, __func__); - return promise.forget(); + return MakeRejectionPromise(__func__); } RefPtr<FlyWebPublishedServer> server; if (XRE_GetProcessType() == GeckoProcessType_Content) { server = new FlyWebPublishedServerChild(aWindow, aName, aOptions); } else { server = new FlyWebPublishedServerImpl(aWindow, aName, aOptions); + + // Before proceeding, ensure that the FlyWeb system addon exists. + nsresult rv; + nsCOMPtr<nsIURI> uri; + rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("chrome://flyweb/skin/icon-64.png")); + if (NS_FAILED(rv)) { + return MakeRejectionPromise(__func__); + } + + JSAddonId *addonId = MapURIToAddonID(uri); + if (!addonId) { + LOG_E("PublishServer: Failed to find FlyWeb system addon."); + return MakeRejectionPromise(__func__); + } + + JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId)); + nsAutoString addonIdString; + AssignJSFlatString(addonIdString, flat); + if (!addonIdString.EqualsLiteral("flyweb@mozilla.org")) { + nsCString addonIdCString = NS_ConvertUTF16toUTF8(addonIdString); + LOG_E("PublishServer: FlyWeb resource found on wrong system addon: %s.", addonIdCString.get()); + return MakeRejectionPromise(__func__); + } + } + + if (aWindow) { + nsresult rv; + + MOZ_ASSERT(NS_IsMainThread()); + rv = NS_DispatchToCurrentThread( + MakeAndAddRef<FlyWebPublishServerPermissionCheck>( + NS_ConvertUTF16toUTF8(aName), aWindow->WindowID(), server)); + if (NS_WARN_IF(NS_FAILED(rv))) { + LOG_E("PublishServer: Failed to dispatch permission check runnable for %s", + NS_ConvertUTF16toUTF8(aName).get()); + return MakeRejectionPromise(__func__); + } + } else { + // If aWindow is null, we're definitely in the e10s parent process. + // In this case, we know that permission has already been granted + // by the user because of content-process prompt. + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + server->PermissionGranted(true); } mServers.AppendElement(server); return server->GetPublishPromise(); } already_AddRefed<FlyWebPublishedServer>
--- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -1532,17 +1532,17 @@ HTMLFormElement::NamedGetter(const nsASt aFound = false; return nullptr; } void HTMLFormElement::GetSupportedNames(nsTArray<nsString >& aRetval) { - // TODO https://www.w3.org/Bugs/Public/show_bug.cgi?id=22320 + // TODO https://github.com/whatwg/html/issues/1731 } already_AddRefed<nsISupports> HTMLFormElement::FindNamedItem(const nsAString& aName, nsWrapperCache** aCache) { // FIXME Get the wrapper cache from DoResolveName.
--- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -3284,17 +3284,17 @@ HTMLInputElement::GetRadioGroupContainer return mForm; } //XXXsmaug It isn't clear how this should work in Shadow DOM. return static_cast<nsDocument*>(GetUncomposedDoc()); } already_AddRefed<nsIDOMHTMLInputElement> -HTMLInputElement::GetSelectedRadioButton() +HTMLInputElement::GetSelectedRadioButton() const { nsIRadioGroupContainer* container = GetRadioGroupContainer(); if (!container) { return nullptr; } nsAutoString name; GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); @@ -3355,16 +3355,23 @@ HTMLInputElement::SetCheckedInternal(boo } } UpdateAllValidityStates(aNotify); // Notify the document that the CSS :checked pseudoclass for this element // has changed state. UpdateState(aNotify); + + // Notify all radios in the group that value has changed, this is to let + // radios to have the chance to update its states, e.g., :indeterminate. + if (mType == NS_FORM_INPUT_RADIO) { + nsCOMPtr<nsIRadioVisitor> visitor = new nsRadioUpdateStateVisitor(this); + VisitGroup(visitor, aNotify); + } } void HTMLInputElement::Blur(ErrorResult& aError) { if (mType == NS_FORM_INPUT_NUMBER) { // Blur our anonymous text control, if we have one. (DOM 'change' event // firing and other things depend on this.) @@ -6415,16 +6422,25 @@ HTMLInputElement::IntrinsicState() const state |= NS_EVENT_STATE_CHECKED; } // Check current indeterminate state (:indeterminate) if (mType == NS_FORM_INPUT_CHECKBOX && mIndeterminate) { state |= NS_EVENT_STATE_INDETERMINATE; } + if (mType == NS_FORM_INPUT_RADIO) { + nsCOMPtr<nsIDOMHTMLInputElement> selected = GetSelectedRadioButton(); + bool indeterminate = !selected && !mChecked; + + if (indeterminate) { + state |= NS_EVENT_STATE_INDETERMINATE; + } + } + // Check whether we are the default checked element (:default) if (DefaultChecked()) { state |= NS_EVENT_STATE_DEFAULT; } } else if (mType == NS_FORM_INPUT_IMAGE) { state |= nsImageLoadingContent::ImageState(); } @@ -6638,16 +6654,19 @@ HTMLInputElement::WillRemoveFromRadioGro nsAutoString name; GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); // If this button was checked, we need to notify the group that there is no // longer a selected radio button if (mChecked) { container->SetCurrentRadioButton(name, nullptr); + + nsCOMPtr<nsIRadioVisitor> visitor = new nsRadioUpdateStateVisitor(this); + VisitGroup(visitor, true); } // Remove this radio from its group in the container. // We need to call UpdateValueMissingValidityStateForRadio before to make sure // the group validity is updated (with this element being ignored). UpdateValueMissingValidityStateForRadio(true); container->RemoveFromRadioGroup(name, static_cast<nsIFormControl*>(this)); }
--- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -259,17 +259,17 @@ public: /** * Helper function returning the currently selected button in the radio group. * Returning null if the element is not a button or if there is no selectied * button in the group. * * @return the selected button (or null). */ - already_AddRefed<nsIDOMHTMLInputElement> GetSelectedRadioButton(); + already_AddRefed<nsIDOMHTMLInputElement> GetSelectedRadioButton() const; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override; NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLInputElement, nsGenericHTMLFormElementWithState) static UploadLastDir* gUploadLastDir; // create and destroy the static UploadLastDir object for remembering
--- a/dom/html/nsRadioVisitor.cpp +++ b/dom/html/nsRadioVisitor.cpp @@ -50,8 +50,20 @@ nsRadioSetValueMissingState::Visit(nsIFo input->SetValidityState(nsIConstraintValidation::VALIDITY_STATE_VALUE_MISSING, mValidity); input->UpdateState(true); return true; } +bool +nsRadioUpdateStateVisitor::Visit(nsIFormControl* aRadio) +{ + if (aRadio == mExcludeElement) { + return true; + } + + HTMLInputElement* input = static_cast<HTMLInputElement*>(aRadio); + input->UpdateState(true); + + return true; +} \ No newline at end of file
--- a/dom/html/nsRadioVisitor.h +++ b/dom/html/nsRadioVisitor.h @@ -89,10 +89,23 @@ public: virtual bool Visit(nsIFormControl* aRadio) override; protected: nsIFormControl* mExcludeElement; bool mValidity; bool mNotify; }; +class nsRadioUpdateStateVisitor : public nsRadioVisitor +{ +public: + explicit nsRadioUpdateStateVisitor(nsIFormControl* aExcludeElement) + : mExcludeElement(aExcludeElement) + { } + + virtual bool Visit(nsIFormControl* aRadio) override; + +protected: + nsIFormControl* mExcludeElement; +}; + #endif // _nsRadioVisitor_h__
--- a/dom/html/reftests/autofocus/reftest.list +++ b/dom/html/reftests/autofocus/reftest.list @@ -1,13 +1,13 @@ default-preferences pref(dom.forms.number,true) skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == input-load.html input-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == input-create.html input-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == input-number.html input-number-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == button-load.html button-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == button-create.html button-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == textarea-load.html textarea-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == textarea-create.html textarea-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,4) needs-focus == select-load.html select-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) fuzzy-if(skiaContent,9,6) needs-focus == select-load.html select-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,4) needs-focus == select-create.html select-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop needs-focus == autofocus-after-load.html autofocus-after-load-ref.html fails-if(B2G||Mulet) fuzzy-if(skiaContent,2,5) needs-focus == autofocus-leaves-iframe.html autofocus-leaves-iframe-ref.html # B2G focus difference between test and reference # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,5) needs-focus == autofocus-after-body-focus.html autofocus-after-body-focus-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
--- a/dom/html/test/file_fullscreen-api-keys.html +++ b/dom/html/test/file_fullscreen-api-keys.html @@ -4,29 +4,29 @@ <meta charset="UTF-8"> </head> <body> <script> window.addEventListener("Test:DispatchKeyEvents", aEvent => { var keyCode = KeyEvent["DOM_" + aEvent.detail.code]; document.body.focus(); - var evt = document.createEvent("KeyEvents"); + var evt = document.createEvent("KeyboardEvent"); evt.initKeyEvent("keydown", true, true, window, false, false, false, false, keyCode, 0); document.body.dispatchEvent(evt); - evt = document.createEvent("KeyEvents"); + evt = document.createEvent("KeyboardEvent"); evt.initKeyEvent("keypress", true, true, window, false, false, false, false, keyCode, 0); document.body.dispatchEvent(evt); - evt = document.createEvent("KeyEvents"); + evt = document.createEvent("KeyboardEvent"); evt.initKeyEvent("keyup", true, true, window, false, false, false, false, keyCode, 0); document.body.dispatchEvent(evt); }); </script> </body> </html>
--- a/dom/html/test/forms/mochitest.ini +++ b/dom/html/test/forms/mochitest.ini @@ -4,16 +4,17 @@ support-files = test_input_number_data.js !/dom/html/test/reflect.js [test_bug1039548.html] [test_bug1283915.html] [test_bug1286509.html] skip-if = os == "android" || appname == "b2g" # up/down arrow keys not supported on android/b2g [test_button_attributes_reflection.html] +[test_input_radio_indeterminate.html] [test_input_radio_radiogroup.html] [test_input_radio_required.html] [test_change_event.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage [test_datalist_element.html] [test_form_attribute-1.html] [test_form_attribute-2.html] [test_form_attribute-3.html]
new file mode 100644 --- /dev/null +++ b/dom/html/test/forms/test_input_radio_indeterminate.html @@ -0,0 +1,109 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=885359 +--> +<head> + <title>Test for Bug 885359</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=885359">Mozilla Bug 343444</a> +<p id="display"></p> +<form> + <input type="radio" id='radio1'/><br/> + + <input type="radio" id="g1radio1" name="group1"/> + <input type="radio" id="g1radio2" name="group1"/></br> + <input type="radio" id="g1radio3" name="group1"/></br> + + <input type="radio" id="g2radio1" name="group2"/> + <input type="radio" id="g2radio2" name="group2" checked/></br> +</form> +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); + +var radio1 = document.getElementById("radio1"); +var g1radio1 = document.getElementById("g1radio1"); +var g1radio2 = document.getElementById("g1radio2"); +var g1radio3 = document.getElementById("g1radio3"); +var g2radio1 = document.getElementById("g2radio1"); +var g2radio2 = document.getElementById("g2radio2"); + +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +function verifyIndeterminateState(aElement, aIsIndeterminate, aMessage) { + is(aElement.mozMatchesSelector(':indeterminate'), aIsIndeterminate, aMessage); +} + +function test() { + // Initial State. + verifyIndeterminateState(radio1, true, + "Unchecked radio in its own group (no name attribute)"); + verifyIndeterminateState(g1radio1, true, "No selected radio in its group"); + verifyIndeterminateState(g1radio2, true, "No selected radio in its group"); + verifyIndeterminateState(g1radio3, true, "No selected radio in its group"); + verifyIndeterminateState(g2radio1, false, "Selected radio in its group"); + verifyIndeterminateState(g2radio2, false, "Selected radio in its group"); + + // Selecting radio buttion. + g1radio1.checked = true; + verifyIndeterminateState(g1radio1, false, + "Selecting a radio should affect all radios in the group"); + verifyIndeterminateState(g1radio2, false, + "Selecting a radio should affect all radios in the group"); + verifyIndeterminateState(g1radio3, false, + "Selecting a radio should affect all radios in the group"); + + // Changing the selected radio button. + g1radio3.checked = true; + verifyIndeterminateState(g1radio1, false, + "Selecting a radio should affect all radios in the group"); + verifyIndeterminateState(g1radio2, false, + "Selecting a radio should affect all radios in the group"); + verifyIndeterminateState(g1radio3, false, + "Selecting a radio should affect all radios in the group"); + + // Deselecting radio button. + g2radio2.checked = false; + verifyIndeterminateState(g2radio1, true, + "Deselecting a radio should affect all radios in the group"); + verifyIndeterminateState(g2radio2, true, + "Deselecting a radio should affect all radios in the group"); + + // Move a selected radio button to another group. + g1radio3.name = "group2"; + + // The radios' state in the original group becomes indeterminated. + verifyIndeterminateState(g1radio1, true, + "Removing a radio from a group should affect all radios in the group"); + verifyIndeterminateState(g1radio2, true, + "Removing a radio from a group should affect all radios in the group"); + + // The radios' state in the new group becomes determinated. + verifyIndeterminateState(g1radio3, false, + "Adding a radio from a group should affect all radios in the group"); + verifyIndeterminateState(g2radio1, false, + "Adding a radio from a group should affect all radios in the group"); + verifyIndeterminateState(g2radio2, false, + "Adding a radio from a group should affect all radios in the group"); + + // Change input type to 'text'. + g1radio3.type = "text"; + verifyIndeterminateState(g1radio3, false, + "Input type text does not have an indeterminate state"); + verifyIndeterminateState(g2radio1, true, + "Changing input type should affect all radios in the group"); + verifyIndeterminateState(g2radio2, true, + "Changing input type should affect all radios in the group"); +} +</script> +</pre> +</body> +</html> +
--- a/dom/interfaces/base/nsITabParent.idl +++ b/dom/interfaces/base/nsITabParent.idl @@ -3,27 +3,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "domstubs.idl" [builtinclass, scriptable, uuid(8e49f7b0-1f98-4939-bf91-e9c39cd56434)] interface nsITabParent : nsISupports { - void injectTouchEvent(in AString aType, - [array, size_is(count)] in uint32_t aIdentifiers, - [array, size_is(count)] in int32_t aXs, - [array, size_is(count)] in int32_t aYs, - [array, size_is(count)] in uint32_t aRxs, - [array, size_is(count)] in uint32_t aRys, - [array, size_is(count)] in float aRotationAngles, - [array, size_is(count)] in float aForces, - in uint32_t count, - in long aModifiers); - void getChildProcessOffset(out int32_t aCssX, out int32_t aCssY); readonly attribute boolean useAsyncPanZoom; /** * Manages the docshell active state of the remote browser. */ attribute boolean docShellIsActive;
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -27,17 +27,16 @@ #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/DataTransfer.h" #include "mozilla/dom/DOMStorageIPC.h" #include "mozilla/dom/ExternalHelperAppChild.h" #include "mozilla/dom/FlyWebPublishedServerIPC.h" #include "mozilla/dom/GetFilesHelper.h" #include "mozilla/dom/PCrashReporterChild.h" #include "mozilla/dom/ProcessGlobal.h" -#include "mozilla/dom/Promise.h" #include "mozilla/dom/workers/ServiceWorkerManager.h" #include "mozilla/dom/nsIContentChild.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/psm/PSMContentListener.h" #include "mozilla/hal_sandbox/PHalChild.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/FileDescriptorSetChild.h" #include "mozilla/ipc/FileDescriptorUtils.h" @@ -2258,32 +2257,16 @@ nsresult ContentChild::AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver) { NS_ASSERTION(aObserver, "Adding a null observer?"); mAlertObservers.AppendElement(new AlertObserver(aObserver, aData)); return NS_OK; } - -bool -ContentChild::RecvSystemMemoryAvailable(const uint64_t& aGetterId, - const uint32_t& aMemoryAvailable) -{ - RefPtr<Promise> p = dont_AddRef(reinterpret_cast<Promise*>(aGetterId)); - - if (!aMemoryAvailable) { - p->MaybeReject(NS_ERROR_NOT_AVAILABLE); - return true; - } - - p->MaybeResolve((int)aMemoryAvailable); - return true; -} - bool ContentChild::RecvPreferenceUpdate(const PrefSetting& aPref) { Preferences::SetPreference(aPref); return true; } bool
--- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -399,19 +399,16 @@ public: virtual bool RecvBidiKeyboardNotify(const bool& isLangRTL, const bool& haveBidiKeyboards) override; virtual bool RecvNotifyVisited(const URIParams& aURI) override; // auto remove when alertfinished is received. nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver); - virtual bool RecvSystemMemoryAvailable(const uint64_t& aGetterId, - const uint32_t& aMemoryAvailable) override; - virtual bool RecvPreferenceUpdate(const PrefSetting& aPref) override; virtual bool RecvVarUpdate(const GfxVarUpdate& pref) override; virtual bool RecvDataStoragePut(const nsString& aFilename, const DataStorageItem& aItem) override; virtual bool RecvDataStorageRemove(const nsString& aFilename, const nsCString& aKey,
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -3905,30 +3905,16 @@ ContentParent::RecvNSSU2FTokenSign(nsTAr MOZ_ASSERT(buffer); aSignature->ReplaceElementsAt(0, aSignature->Length(), buffer, bufferlen); free(buffer); return NS_SUCCEEDED(rv); } bool -ContentParent::RecvGetSystemMemory(const uint64_t& aGetterId) -{ - uint32_t memoryTotal = 0; - -#if defined(XP_LINUX) - memoryTotal = mozilla::hal::GetTotalSystemMemoryLevel(); -#endif - - Unused << SendSystemMemoryAvailable(aGetterId, memoryTotal); - - return true; -} - -bool ContentParent::RecvGetLookAndFeelCache(nsTArray<LookAndFeelInt>* aLookAndFeelIntCache) { *aLookAndFeelIntCache = LookAndFeel::GetIntCache(); return true; } bool ContentParent::RecvIsSecureURI(const uint32_t& type,
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -1008,18 +1008,16 @@ private: virtual bool RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel, const bool& aHidden) override; virtual bool RecvAudioChannelServiceStatus(const bool& aTelephonyChannel, const bool& aContentOrNormalChannel, const bool& aAnyChannel) override; - virtual bool RecvGetSystemMemory(const uint64_t& getterId) override; - virtual bool RecvGetLookAndFeelCache(nsTArray<LookAndFeelInt>* aLookAndFeelIntCache) override; virtual bool RecvSpeakerManagerGetSpeakerStatus(bool* aValue) override; virtual bool RecvSpeakerManagerForceSpeaker(const bool& aEnable) override; virtual bool RecvCreateFakeVolume(const nsString& aFsName, const nsString& aMountPoint) override;
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -513,18 +513,16 @@ child: async ClearImageCache(bool privateLoader, bool chrome); async SetOffline(bool offline); async SetConnectivity(bool connectivity); async NotifyVisited(URIParams uri); - async SystemMemoryAvailable(uint64_t getterId, uint32_t memoryAvailable); - async PreferenceUpdate(PrefSetting pref); async VarUpdate(GfxVarUpdate var); async DataStoragePut(nsString aFilename, DataStorageItem aItem); async DataStorageRemove(nsString aFilename, nsCString aKey, DataStorageType aType); async DataStorageClear(nsString aFilename); async NotifyAlertsObserver(nsCString topic, nsString data); @@ -824,18 +822,16 @@ parent: * |challenge| The Challenge to satisfy in the response. * |keyHandle| The Key Handle opaque object to use. * |signature| The resulting signature. */ sync NSSU2FTokenSign(uint8_t[] application, uint8_t[] challenge, uint8_t[] keyHandle) returns (uint8_t[] signature); - async GetSystemMemory(uint64_t getterId); - sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags) returns (bool isSecureURI); async AccumulateMixedContentHSTS(URIParams uri, bool active); sync GetLookAndFeelCache() returns (LookAndFeelInt[] lookAndFeelIntCache);
--- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2805,81 +2805,16 @@ TabParent::GetLoadContext() mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW, OriginAttributesRef()); mLoadContext = loadContext; } return loadContext.forget(); } NS_IMETHODIMP -TabParent::InjectTouchEvent(const nsAString& aType, - uint32_t* aIdentifiers, - int32_t* aXs, - int32_t* aYs, - uint32_t* aRxs, - uint32_t* aRys, - float* aRotationAngles, - float* aForces, - uint32_t aCount, - int32_t aModifiers) -{ - EventMessage msg; - nsContentUtils::GetEventMessageAndAtom(aType, eTouchEventClass, &msg); - if (msg != eTouchStart && msg != eTouchMove && - msg != eTouchEnd && msg != eTouchCancel) { - return NS_ERROR_FAILURE; - } - - nsCOMPtr<nsIWidget> widget = GetWidget(); - if (!widget) { - return NS_ERROR_FAILURE; - } - - WidgetTouchEvent event(true, msg, widget); - event.mModifiers = aModifiers; - event.mTime = PR_IntervalNow(); - - nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement); - if (!content || !content->OwnerDoc()) { - return NS_ERROR_FAILURE; - } - - nsIDocument* doc = content->OwnerDoc(); - if (!doc || !doc->GetShell()) { - return NS_ERROR_FAILURE; - } - nsPresContext* presContext = doc->GetShell()->GetPresContext(); - - event.mTouches.SetCapacity(aCount); - for (uint32_t i = 0; i < aCount; ++i) { - LayoutDeviceIntPoint pt = - LayoutDeviceIntPoint::FromAppUnitsRounded( - CSSPoint::ToAppUnits(CSSPoint(aXs[i], aYs[i])), - presContext->AppUnitsPerDevPixel()); - - LayoutDeviceIntPoint radius = - LayoutDeviceIntPoint::FromAppUnitsRounded( - CSSPoint::ToAppUnits(CSSPoint(aRxs[i], aRys[i])), - presContext->AppUnitsPerDevPixel()); - - RefPtr<Touch> t = - new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i], aForces[i]); - - // Consider all injected touch events as changedTouches. For more details - // about the meaning of changedTouches for each event, see - // https://developer.mozilla.org/docs/Web/API/TouchEvent.changedTouches - t->mChanged = true; - event.mTouches.AppendElement(t); - } - - SendRealTouchEvent(event); - return NS_OK; -} - -NS_IMETHODIMP TabParent::GetUseAsyncPanZoom(bool* useAsyncPanZoom) { *useAsyncPanZoom = AsyncPanZoomEnabled(); return NS_OK; } // defined in nsITabParent NS_IMETHODIMP
--- a/dom/plugins/test/reftest/reftest.list +++ b/dom/plugins/test/reftest/reftest.list @@ -1,26 +1,26 @@ # basic sanity checking random-if(!haveTestPlugin) != plugin-sanity.html about:blank fails-if(!haveTestPlugin) == plugin-sanity.html div-sanity.html -fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-alpha-zindex.html div-alpha-zindex.html -fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,164000) == plugin-alpha-opacity.html div-alpha-opacity.html +fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-alpha-zindex.html div-alpha-zindex.html +fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,164000) == plugin-alpha-opacity.html div-alpha-opacity.html random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == windowless-clipping-1.html windowless-clipping-1-ref.html # bug 631832 # fuzzy because of anti-aliasing in dashed border fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-1.html border-padding-1-ref.html # bug 629430 fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-2.html border-padding-2-ref.html # bug 629430 fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) skip-if(!haveTestPlugin) skip-if(Android||B2G) == border-padding-3.html border-padding-3-ref.html # bug 629430 # bug 773482 # The following two "pluginproblemui-direction" tests are unreliable on all platforms. They should be re-written or replaced. #random-if(cocoaWidget||d2d||/^Windows\x20NT\x205\.1/.test(http.oscpu)) fails-if(!haveTestPlugin&&!Android) == pluginproblemui-direction-1.html pluginproblemui-direction-1-ref.html # bug 567367 #random-if(cocoaWidget) fails-if(!haveTestPlugin&&!Android) == pluginproblemui-direction-2.html pluginproblemui-direction-2-ref.html -fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-canvas-alpha-zindex.html div-alpha-zindex.html -fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-transform-alpha-zindex.html div-alpha-zindex.html -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-busy-alpha-zindex.html div-alpha-zindex.html -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background.html plugin-background-ref.html -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-1-step.html plugin-background-ref.html -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-2-step.html plugin-background-ref.html -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-5-step.html plugin-background-ref.html -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-10-step.html plugin-background-ref.html +fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-canvas-alpha-zindex.html div-alpha-zindex.html +fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-transform-alpha-zindex.html div-alpha-zindex.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-busy-alpha-zindex.html div-alpha-zindex.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background.html plugin-background-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-1-step.html plugin-background-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-2-step.html plugin-background-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-5-step.html plugin-background-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-10-step.html plugin-background-ref.html random-if(!haveTestPlugin) == plugin-transform-1.html plugin-transform-1-ref.html fails-if(!haveTestPlugin) == plugin-transform-2.html plugin-transform-2-ref.html skip-if(!haveTestPlugin) == shrink-1.html shrink-1-ref.html skip-if(!haveTestPlugin) == update-1.html update-1-ref.html skip-if(!haveTestPlugin) == windowless-layers.html windowless-layers-ref.html
--- a/dom/tests/mochitest/ajax/prototype/test/lib/unittest.js +++ b/dom/tests/mochitest/ajax/prototype/test/lib/unittest.js @@ -58,17 +58,17 @@ Event.simulateKey = function(element, ev ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, keyCode: 0, charCode: 0 }, arguments[2] || {}); - var oEvent = document.createEvent("KeyEvents"); + var oEvent = document.createEvent("KeyboardEvent"); oEvent.initKeyEvent(eventName, true, true, window, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.keyCode, options.charCode ); $(element).dispatchEvent(oEvent); }; Event.simulateKeys = function(element, command) { for (var i=0; i<command.length; i++) {
--- a/dom/tests/mochitest/ajax/scriptaculous/src/unittest.js +++ b/dom/tests/mochitest/ajax/scriptaculous/src/unittest.js @@ -49,17 +49,17 @@ Event.simulateKey = function(element, ev ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, keyCode: 0, charCode: 0 }, arguments[2] || {}); - var oEvent = document.createEvent("KeyEvents"); + var oEvent = document.createEvent("KeyboardEvent"); oEvent.initKeyEvent(eventName, true, true, window, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.keyCode, options.charCode ); $(element).dispatchEvent(oEvent); }; Event.simulateKeys = function(element, command) { for(var i=0; i<command.length; i++) {
--- a/dom/tests/mochitest/whatwg/test_bug477323.html +++ b/dom/tests/mochitest/whatwg/test_bug477323.html @@ -25,17 +25,17 @@ function start() element.ondragenter = function(event) {gotdragenter = true;} element.ondragover = function(event) {gotdragover = true;} element.ondragleave = function(event) {gotdragleave = true;} element.ondrop = function(event) {gotdrop = true;} element.ondragend = function(event) {gotdragend = true;} function dispatch(eventName) { - var event = document.createEvent("DragEvents"); + var event = document.createEvent("DragEvent"); event.initDragEvent(eventName, true, true, window, 0, 5, 5, 5, 5, false, false, false, false, 0, null, null); element.dispatchEvent(event); } dispatch("dragstart"); dispatch("drag"); dispatch("dragenter");
--- a/dom/webidl/HTMLFormElement.webidl +++ b/dom/webidl/HTMLFormElement.webidl @@ -6,19 +6,17 @@ * The origin of this IDL file is * http://www.whatwg.org/specs/web-apps/current-work/#htmlformelement * * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and * Opera Software ASA. You are granted a license to use, reproduce * and create derivative works of this document. */ -// Should be LegacyUnenumerableNamedProperties. See -// https://bugzilla.mozilla.org/show_bug.cgi?id=1270369 -[OverrideBuiltins] +[OverrideBuiltins, LegacyUnenumerableNamedProperties] interface HTMLFormElement : HTMLElement { [Pure, SetterThrows] attribute DOMString acceptCharset; [Pure, SetterThrows] attribute DOMString action; [Pure, SetterThrows] attribute DOMString autocomplete; [Pure, SetterThrows]
--- a/dom/webidl/MimeTypeArray.webidl +++ b/dom/webidl/MimeTypeArray.webidl @@ -1,15 +1,13 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ -// [LegacyUnenumerableNamedProperties] -// Named properties enumerable for now; see -// https://bugzilla.mozilla.org/show_bug.cgi?id=1270364 +[LegacyUnenumerableNamedProperties] interface MimeTypeArray { readonly attribute unsigned long length; getter MimeType? item(unsigned long index); getter MimeType? namedItem(DOMString name); };
--- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -24,17 +24,16 @@ interface Navigator { // objects implementing this interface also implement the interfaces given below }; Navigator implements NavigatorID; Navigator implements NavigatorLanguage; Navigator implements NavigatorOnLine; Navigator implements NavigatorContentUtils; Navigator implements NavigatorStorageUtils; -Navigator implements NavigatorFeatures; Navigator implements NavigatorConcurrentHardware; [NoInterfaceObject, Exposed=(Window,Worker)] interface NavigatorID { // WebKit/Blink/Trident/Presto support this (hardcoded "Mozilla"). [Constant, Cached] readonly attribute DOMString appCodeName; // constant "Mozilla" [Constant, Cached] @@ -87,25 +86,16 @@ interface NavigatorContentUtils { }; [NoInterfaceObject] interface NavigatorStorageUtils { // NOT IMPLEMENTED //void yieldForStorageUpdates(); }; -[NoInterfaceObject] -interface NavigatorFeatures { - [ChromeOnly, Throws] - Promise<any> getFeature(DOMString name); - - [ChromeOnly, Throws] - Promise<any> hasFeature(DOMString name); -}; - partial interface Navigator { [Throws] readonly attribute Permissions permissions; }; // Things that definitely need to be in the spec and and are not for some // reason. See https://www.w3.org/Bugs/Public/show_bug.cgi?id=22406 partial interface Navigator {
--- a/dom/webidl/Plugin.webidl +++ b/dom/webidl/Plugin.webidl @@ -1,17 +1,15 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ -// [LegacyUnenumerableNamedProperties] -// Named properties enumerable for now; see -// https://bugzilla.mozilla.org/show_bug.cgi?id=1270366 +[LegacyUnenumerableNamedProperties] interface Plugin { readonly attribute DOMString description; readonly attribute DOMString filename; readonly attribute DOMString version; readonly attribute DOMString name; readonly attribute unsigned long length; getter MimeType? item(unsigned long index);
--- a/dom/webidl/PluginArray.webidl +++ b/dom/webidl/PluginArray.webidl @@ -1,17 +1,15 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ -// [LegacyUnenumerableNamedProperties] -// Named properties enumerable for now; see -// https://bugzilla.mozilla.org/show_bug.cgi?id=1270366 +[LegacyUnenumerableNamedProperties] interface PluginArray { readonly attribute unsigned long length; getter Plugin? item(unsigned long index); getter Plugin? namedItem(DOMString name); void refresh(optional boolean reloadDocuments = false); };
--- a/editor/libeditor/tests/test_contenteditable_text_input_handling.html +++ b/editor/libeditor/tests/test_contenteditable_text_input_handling.html @@ -160,17 +160,17 @@ function runTests() } // When key events are fired on unfocused editor. function testDispatchedKeyEvent(aTarget) { var targetDescription = " (dispatched to " + aTarget._description + ")"; function dispatchKeyEvent(aKeyCode, aChar, aTarget) { - var keyEvent = document.createEvent("KeyEvents"); + var keyEvent = document.createEvent("KeyboardEvent"); keyEvent.initKeyEvent("keypress", true, true, null, false, false, false, false, aKeyCode, aChar ? aChar.charCodeAt(0) : 0); aTarget.dispatchEvent(keyEvent); } function checkValueForDispatchedKeyEvent(aElement, aInsertedText) {
--- a/gfx/layers/apz/util/APZEventState.cpp +++ b/gfx/layers/apz/util/APZEventState.cpp @@ -285,25 +285,21 @@ APZEventState::ProcessTouchEvent(const W bool sentContentResponse = false; APZES_LOG("Handling event type %d\n", aEvent.mMessage); switch (aEvent.mMessage) { case eTouchStart: { mTouchEndCancelled = false; sentContentResponse = SendPendingTouchPreventedResponse(false); // sentContentResponse can be true here if we get two TOUCH_STARTs in a row // and just responded to the first one. - if (!aEvent.mFlags.mHandledByAPZ) { - // This condition being true means this touchstart is synthetic and is - // coming from TabParent.injectTouchEvent. - // Since APZ doesn't know about it we don't want to send a response for - // this block; we want to just skip over it from the point of view of - // prevent-default notifications. - APZES_LOG("Got a synthetic touch-start!\n"); - break; - } + + // We're about to send a response back to APZ, but we should only do it + // for events that went through APZ (which should be all of them). + MOZ_ASSERT(aEvent.mFlags.mHandledByAPZ); + if (isTouchPrevented) { mContentReceivedInputBlockCallback(aGuid, aInputBlockId, isTouchPrevented); sentContentResponse = true; } else { APZES_LOG("Event not prevented; pending response for %" PRIu64 " %s\n", aInputBlockId, Stringify(aGuid).c_str()); mPendingTouchPreventedResponse = true; mPendingTouchPreventedGuid = aGuid;
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -1066,16 +1066,17 @@ CompositorBridgeParent::ResumeCompositio __android_log_print(ANDROID_LOG_INFO, "CompositorBridgeParent", "Unable to renew compositor surface; remaining in paused state"); #endif lock.NotifyAll(); return; } mPaused = false; + Invalidate(); mCompositorScheduler->ResumeComposition(); // if anyone's waiting to make sure that composition really got resumed, tell them lock.NotifyAll(); } void CompositorBridgeParent::ForceComposition()
--- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -494,20 +494,21 @@ gfxPlatform::gfxPlatform() mWordCacheMaxEntries = UNINITIALIZED_VALUE; mGraphiteShapingEnabled = UNINITIALIZED_VALUE; mOpenTypeSVGEnabled = UNINITIALIZED_VALUE; mBidiNumeralOption = UNINITIALIZED_VALUE; mSkiaGlue = nullptr; uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO); + uint32_t contentMask = BackendTypeBit(BackendType::CAIRO); #ifdef USE_SKIA canvasMask |= BackendTypeBit(BackendType::SKIA); + contentMask |= BackendTypeBit(BackendType::SKIA); #endif - uint32_t contentMask = BackendTypeBit(BackendType::CAIRO); InitBackendPrefs(canvasMask, BackendType::CAIRO, contentMask, BackendType::CAIRO); mTotalSystemMemory = mozilla::hal::GetTotalSystemMemory(); VRManager::ManagerInit(); } gfxPlatform*
--- a/hal/Hal.cpp +++ b/hal/Hal.cpp @@ -1207,22 +1207,16 @@ StopDiskSpaceWatcher() } uint32_t GetTotalSystemMemory() { return hal_impl::GetTotalSystemMemory(); } -uint32_t -GetTotalSystemMemoryLevel() -{ - return hal_impl::GetTotalSystemMemoryLevel(); -} - bool IsHeadphoneEventFromInputDev() { AssertMainThread(); RETURN_PROXY_IF_SANDBOXED(IsHeadphoneEventFromInputDev(), false); } nsresult StartSystemService(const char* aSvcName, const char* aArgs) {
--- a/hal/Hal.h +++ b/hal/Hal.h @@ -623,24 +623,16 @@ void StopDiskSpaceWatcher(); /** * Get total system memory of device being run on in bytes. * * Returns 0 if we are unable to determine this information from /proc/meminfo. */ uint32_t GetTotalSystemMemory(); /** - * Get the level of total system memory on device in MiB. - * (round the value up to the next power of two) - * - * Returns 0 if we are unable to determine this information from /proc/meminfo. - */ -uint32_t GetTotalSystemMemoryLevel(); - -/** * Determine whether the headphone switch event is from input device */ bool IsHeadphoneEventFromInputDev(); /** * Start the system service with the specified name and arguments. */ nsresult StartSystemService(const char* aSvcName, const char* aArgs);
--- a/hal/fallback/FallbackMemory.cpp +++ b/hal/fallback/FallbackMemory.cpp @@ -11,16 +11,10 @@ namespace mozilla { namespace hal_impl { uint32_t GetTotalSystemMemory() { return 0; } -uint32_t -GetTotalSystemMemoryLevel() -{ - return 0; -} - } // namespace hal_impl } // namespace mozilla
--- a/hal/linux/LinuxMemory.cpp +++ b/hal/linux/LinuxMemory.cpp @@ -30,42 +30,10 @@ GetTotalSystemMemory() if (fclose(fd) || rv != 1) { return 0; } } return sTotalMemory * 1024; } -uint32_t -GetTotalSystemMemoryLevel() -{ - static uint32_t sTotalMemoryLevel = 1; - uint32_t sTotalMemory; - static bool sTotalMemoryObtained = false; - - if (!sTotalMemoryObtained) { - sTotalMemoryObtained = true; - - FILE* fd = fopen("/proc/meminfo", "r"); - if (!fd) { - return 0; - } - - int rv = fscanf(fd, "MemTotal: %i kB", &sTotalMemory); - - if (fclose(fd) || rv != 1) { - return 0; - } - - // From KB to MiB - sTotalMemory /= 1024; - - while (sTotalMemoryLevel <= sTotalMemory) { - sTotalMemoryLevel *= 2; - } - } - - return sTotalMemoryLevel; -} - } // namespace hal_impl } // namespace mozilla
--- a/image/test/reftest/downscaling/reftest.list +++ b/image/test/reftest/downscaling/reftest.list @@ -82,17 +82,17 @@ fuzzy(20,999) != downscale-2d.html?203,5 fuzzy(20,999) != downscale-2e.html?203,52,bottom about:blank fuzzy(20,999) != downscale-2a.html?205,53,bottom about:blank fuzzy(20,999) != downscale-2b.html?205,53,bottom about:blank fuzzy(20,999) != downscale-2c.html?205,53,bottom about:blank fuzzy(20,999) != downscale-2d.html?205,53,bottom about:blank fuzzy(20,999) fails-if(OSX>=1008&&!skiaContent) != downscale-2e.html?205,53,bottom about:blank -fuzzy(63,3386) == downscale-moz-icon-1.html downscale-moz-icon-1-ref.html +fuzzy(63,3391) == downscale-moz-icon-1.html downscale-moz-icon-1-ref.html == downscale-png.html?16,16,interlaced downscale-png.html?16,16,normal == downscale-png.html?24,24,interlaced downscale-png.html?24,24,normal # Non-transparent and transparent ICO images == downscale-16px.html?ff-0RGB.ico downscale-16px.html?ff-0RGB.png fuzzy(1,1) == downscale-16px.html?ff-ARGB.ico downscale-16px.html?ff-ARGB.png
--- a/js/public/Class.h +++ b/js/public/Class.h @@ -782,17 +782,17 @@ struct JSClass { // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was // previously allowed, but is now an ES5 violation and thus unsupported. // // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at // the beginning of every global object's slots for use by the // application. #define JSCLASS_GLOBAL_APPLICATION_SLOTS 5 #define JSCLASS_GLOBAL_SLOT_COUNT \ - (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 37) + (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 37) #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) #define JSCLASS_GLOBAL_FLAGS \ JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0) #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \ (((clasp)->flags & JSCLASS_IS_GLOBAL) \ && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
--- a/js/public/GCPolicyAPI.h +++ b/js/public/GCPolicyAPI.h @@ -139,18 +139,21 @@ struct GCPolicy<JS::Heap<T>> }; // GCPolicy<UniquePtr<T>> forwards the contained pointer to GCPolicy<T>. template <typename T, typename D> struct GCPolicy<mozilla::UniquePtr<T, D>> { static mozilla::UniquePtr<T,D> initial() { return mozilla::UniquePtr<T,D>(); } static void trace(JSTracer* trc, mozilla::UniquePtr<T,D>* tp, const char* name) { - GCPolicy<T>::trace(trc, tp->get(), name); + if (tp->get()) + GCPolicy<T>::trace(trc, tp->get(), name); } static bool needsSweep(mozilla::UniquePtr<T,D>* tp) { - return GCPolicy<T>::needsSweep(tp->get()); + if (tp->get()) + return GCPolicy<T>::needsSweep(tp->get()); + return false; } }; } // namespace JS #endif // GCPolicyAPI_h
--- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -296,16 +296,17 @@ class TryFinallyControl : public Bytecod return emittingSubroutine_; } }; static bool ScopeKindIsInBody(ScopeKind kind) { return kind == ScopeKind::Lexical || + kind == ScopeKind::SimpleCatch || kind == ScopeKind::Catch || kind == ScopeKind::With || kind == ScopeKind::FunctionBodyVar || kind == ScopeKind::ParameterExpressionVar; } static inline void MarkAllBindingsClosedOver(LexicalScope::Data& data) @@ -676,16 +677,17 @@ BytecodeEmitter::EmitterScope::searchInE } break; case ScopeKind::FunctionBodyVar: case ScopeKind::ParameterExpressionVar: case ScopeKind::Lexical: case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: + case ScopeKind::SimpleCatch: case ScopeKind::Catch: if (hasEnv) { for (BindingIter bi(si.scope()); bi; bi++) { if (bi.name() != name) continue; // The name must already have been marked as closed // over. If this assertion is hit, there is a bug in the @@ -1407,16 +1409,17 @@ BytecodeEmitter::EmitterScope::leave(Byt { // If we aren't leaving the scope due to a non-local jump (e.g., break), // we must be the innermost scope. MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScope); ScopeKind kind = scope(bce)->kind(); switch (kind) { case ScopeKind::Lexical: + case ScopeKind::SimpleCatch: case ScopeKind::Catch: if (!bce->emit1(hasEnvironment() ? JSOP_POPLEXICALENV : JSOP_DEBUGLEAVELEXICALENV)) return false; break; case ScopeKind::With: if (!bce->emit1(JSOP_LEAVEWITH)) return false; @@ -5659,32 +5662,37 @@ BytecodeEmitter::emitLexicalScope(ParseN // Update line number notes before emitting TDZ poison in // EmitterScope::enterLexical to avoid spurious pausing on seemingly // non-effectful lines in Debugger. // // For example, consider the following code. // // L1: { - // L2: let x = 42; + // L2: let x = 42; // L3: } // // If line number notes were not updated before the TDZ poison, the TDZ // poison bytecode sequence of 'uninitialized; initlexical' will have line // number L1, and the Debugger will pause there. if (!ParseNodeRequiresSpecialLineNumberNotes(body)) { ParseNode* pnForPos = body; if (body->isKind(PNK_STATEMENTLIST) && body->pn_head) pnForPos = body->pn_head; if (!updateLineNumberNotes(pnForPos->pn_pos.begin)) return false; } EmitterScope emitterScope(this); - ScopeKind kind = body->isKind(PNK_CATCH) ? ScopeKind::Catch : ScopeKind::Lexical; + ScopeKind kind; + if (body->isKind(PNK_CATCH)) + kind = body->pn_kid1->isKind(PNK_NAME) ? ScopeKind::SimpleCatch : ScopeKind::Catch; + else + kind = ScopeKind::Lexical; + if (!emitterScope.enterLexical(this, kind, pn->scopeBindings())) return false; if (body->isKind(PNK_FOR)) { // for loops need to emit {FRESHEN,RECREATE}LEXICALENV if there are // lexical declarations in the head. Signal this by passing a // non-nullptr lexical scope. if (!emitFor(body, &emitterScope))
--- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -165,25 +165,57 @@ ParseContext::Scope::removeVarForAnnexBL } } // Annex B semantics no longer applies to any functions with this name, as // an early error would have occurred. pc->removeInnerFunctionBoxesForAnnexB(name); } +static bool +DeclarationKindIsCatchParameter(DeclarationKind kind) +{ + return kind == DeclarationKind::SimpleCatchParameter || + kind == DeclarationKind::CatchParameter; +} + +bool +ParseContext::Scope::addCatchParameters(ParseContext* pc, Scope& catchParamScope) +{ + if (pc->useAsmOrInsideUseAsm()) + return true; + + for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty(); r.popFront()) { + DeclarationKind kind = r.front().value()->kind(); + MOZ_ASSERT(DeclarationKindIsCatchParameter(kind)); + JSAtom* name = r.front().key(); + AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name); + MOZ_ASSERT(!p); + if (!addDeclaredName(pc, p, name, kind)) + return false; + } + + return true; +} + void -ParseContext::Scope::removeSimpleCatchParameter(ParseContext* pc, JSAtom* name) +ParseContext::Scope::removeCatchParameters(ParseContext* pc, Scope& catchParamScope) { if (pc->useAsmOrInsideUseAsm()) return; - DeclaredNamePtr p = declared_->lookup(name); - MOZ_ASSERT(p && p->value()->kind() == DeclarationKind::SimpleCatchParameter); - declared_->remove(p); + for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty(); r.popFront()) { + DeclaredNamePtr p = declared_->lookup(r.front().key()); + MOZ_ASSERT(p); + + // This check is needed because the catch body could have declared + // vars, which would have been added to catchParamScope. + if (DeclarationKindIsCatchParameter(r.front().value()->kind())) + declared_->remove(p); + } } void SharedContext::computeAllowSyntax(Scope* scope) { for (ScopeIter si(scope); si; si++) { if (si.kind() == ScopeKind::Function) { JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction(); @@ -916,16 +948,70 @@ static bool DeclarationKindIsVar(DeclarationKind kind) { return kind == DeclarationKind::Var || kind == DeclarationKind::BodyLevelFunction || kind == DeclarationKind::VarForAnnexBLexicalFunction || kind == DeclarationKind::ForOfVar; } +template <typename ParseHandler> +Maybe<DeclarationKind> +Parser<ParseHandler>::isVarRedeclaredInEval(HandlePropertyName name, DeclarationKind kind) +{ + MOZ_ASSERT(DeclarationKindIsVar(kind)); + MOZ_ASSERT(pc->sc()->isEvalContext()); + + // In the case of eval, we also need to check enclosing VM scopes to see + // if the var declaration is allowed in the context. + // + // This check is necessary in addition to + // js::CheckEvalDeclarationConflicts because we only know during parsing + // if a var is bound by for-of. + Scope* enclosingScope = pc->sc()->compilationEnclosingScope(); + Scope* varScope = EvalScope::nearestVarScopeForDirectEval(enclosingScope); + MOZ_ASSERT(varScope); + for (ScopeIter si(enclosingScope); si; si++) { + for (js::BindingIter bi(si.scope()); bi; bi++) { + if (bi.name() != name) + continue; + + switch (bi.kind()) { + case BindingKind::Let: { + // Annex B.3.5 allows redeclaring simple (non-destructured) + // catch parameters with var declarations, except when it + // appears in a for-of. + bool annexB35Allowance = si.kind() == ScopeKind::SimpleCatch && + kind != DeclarationKind::ForOfVar; + if (!annexB35Allowance) { + return Some(ScopeKindIsCatch(si.kind()) + ? DeclarationKind::CatchParameter + : DeclarationKind::Let); + } + break; + } + + case BindingKind::Const: + return Some(DeclarationKind::Const); + + case BindingKind::Import: + case BindingKind::FormalParameter: + case BindingKind::Var: + case BindingKind::NamedLambdaCallee: + break; + } + } + + if (si.scope() == varScope) + break; + } + + return Nothing(); +} + static bool DeclarationKindIsParameter(DeclarationKind kind) { return kind == DeclarationKind::PositionalFormalParameter || kind == DeclarationKind::FormalParameter; } template <typename ParseHandler> @@ -971,68 +1057,31 @@ Parser<ParseHandler>::tryDeclareVar(Hand } } } else { if (!scope->addDeclaredName(pc, p, name, kind)) return false; } } + if (!pc->sc()->strict() && pc->sc()->isEvalContext()) + *redeclaredKind = isVarRedeclaredInEval(name, kind); + return true; } template <typename ParseHandler> bool Parser<ParseHandler>::tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name, bool* tryAnnexB) { Maybe<DeclarationKind> redeclaredKind; if (!tryDeclareVar(name, DeclarationKind::VarForAnnexBLexicalFunction, &redeclaredKind)) return false; - // In the case of eval, we also need to check enclosing VM scopes to see - // if an Annex B var should be synthesized. - if (!redeclaredKind && pc->sc()->isEvalContext()) { - Scope* enclosingScope = pc->sc()->compilationEnclosingScope(); - Scope* varScope = EvalScope::nearestVarScopeForDirectEval(enclosingScope); - MOZ_ASSERT(varScope); - for (ScopeIter si(enclosingScope); si; si++) { - for (js::BindingIter bi(si.scope()); bi; bi++) { - if (bi.name() != name) - continue; - - switch (bi.kind()) { - case BindingKind::Let: { - // Annex B.3.5 allows redeclaring simple (non-destructured) - // catch parameters with var declarations, except when it - // appears in a for-of, which a function declaration is - // definitely not. - bool annexB35Allowance = si.kind() == ScopeKind::Catch; - if (!annexB35Allowance) - redeclaredKind = Some(DeclarationKind::Let); - break; - } - - case BindingKind::Const: - redeclaredKind = Some(DeclarationKind::Const); - break; - - case BindingKind::Import: - case BindingKind::FormalParameter: - case BindingKind::Var: - case BindingKind::NamedLambdaCallee: - break; - } - } - - if (si.scope() == varScope) - break; - } - } - if (redeclaredKind) { // If an early error would have occurred, undo all the // VarForAnnexBLexicalFunction declarations. *tryAnnexB = false; ParseContext::Scope::removeVarForAnnexBLexicalFunction(pc, name); } else { *tryAnnexB = true; } @@ -2699,17 +2748,17 @@ Parser<ParseHandler>::functionArguments( } return true; } template <typename ParseHandler> bool Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, - bool *tryAnnexB) + GeneratorKind generatorKind, bool* tryAnnexB) { if (kind == Statement) { TokenPos pos = handler.getPosition(pn); RootedPropertyName funName(context, funAtom->asPropertyName()); // In sloppy mode, Annex B.3.2 allows labelled function // declarations. Otherwise it is a parse error. ParseContext::Statement* declaredInStmt = pc->innermostStatement(); @@ -2728,17 +2777,17 @@ Parser<ParseHandler>::checkFunctionDefin return false; } } if (declaredInStmt) { MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); - if (!pc->sc()->strict()) { + if (!pc->sc()->strict() && generatorKind == NotGenerator) { // Under sloppy mode, try Annex B.3.3 semantics. If making an // additional 'var' binding of the same name does not throw an // early error, do so. This 'var' binding would be assigned // the function object when its declaration is reached, not at // the start of the block. if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB)) return false; @@ -2888,17 +2937,17 @@ Parser<ParseHandler>::functionDefinition if (!pn) return null(); if (invoked) pn = handler.setLikelyIIFE(pn); // Note the declared name and check for early errors. bool tryAnnexB = false; - if (!checkFunctionDefinition(funName, pn, kind, &tryAnnexB)) + if (!checkFunctionDefinition(funName, pn, kind, generatorKind, &tryAnnexB)) return null(); // When fully parsing a LazyScript, we do not fully reparse its inner // functions, which are also lazy. Instead, their free variables and // source extents are recorded and may be skipped. if (handler.canSkipLazyInnerFunctions()) { if (!skipLazyInnerFunction(pn, tryAnnexB)) return null(); @@ -5969,18 +6018,16 @@ Parser<ParseHandler>::tryStatement(Yield * Legal catch forms are: * catch (lhs) * catch (lhs if <boolean_expression>) * where lhs is a name or a destructuring left-hand side. * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD) */ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH); - RootedPropertyName simpleCatchParam(context); - if (!tokenStream.getToken(&tt)) return null(); Node catchName; switch (tt) { case TOK_LB: case TOK_LC: catchName = destructuringDeclaration(DeclarationKind::CatchParameter, yieldHandling, tt); @@ -5993,27 +6040,25 @@ Parser<ParseHandler>::tryStatement(Yield return null(); } // Even if yield is *not* necessarily a keyword, we still must // check its validity for legacy generators. if (!checkYieldNameValidity()) return null(); MOZ_FALLTHROUGH; - case TOK_NAME: - simpleCatchParam = tokenStream.currentName(); - catchName = newName(simpleCatchParam); + case TOK_NAME: { + RootedPropertyName param(context, tokenStream.currentName()); + catchName = newName(param); if (!catchName) return null(); - if (!noteDeclaredName(simpleCatchParam, DeclarationKind::SimpleCatchParameter, - pos())) - { + if (!noteDeclaredName(param, DeclarationKind::SimpleCatchParameter, pos())) return null(); - } break; + } default: report(ParseError, false, null(), JSMSG_CATCH_IDENTIFIER); return null(); } Node catchGuard = null(); #if JS_HAS_CATCH_GUARD @@ -6030,17 +6075,17 @@ Parser<ParseHandler>::tryStatement(Yield if (!catchGuard) return null(); } #endif MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH); MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH); - Node catchBody = catchBlockStatement(yieldHandling, simpleCatchParam); + Node catchBody = catchBlockStatement(yieldHandling, scope); if (!catchBody) return null(); if (!catchGuard) hasUnconditionalCatch = true; pnblock = finishLexicalScope(scope, catchBody); if (!pnblock) @@ -6084,53 +6129,43 @@ Parser<ParseHandler>::tryStatement(Yield } return handler.newTryStatement(begin, innerBlock, catchList, finallyBlock); } template <typename ParseHandler> typename ParseHandler::Node Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling, - HandlePropertyName simpleCatchParam) + ParseContext::Scope& catchParamScope) { ParseContext::Statement stmt(pc, StatementKind::Block); - // Annex B.3.5 requires that vars be allowed to redeclare a simple - // (non-destructured) catch parameter (including via a direct eval), so - // the catch parameter needs to live in its own scope. So if we have a - // simple catch parameter, make a new scope. - Node body; - if (simpleCatchParam) { - ParseContext::Scope scope(this); - if (!scope.init(pc)) - return null(); - - // The catch parameter name cannot be redeclared inside the catch - // block, so declare the name in the inner scope. - if (!noteDeclaredName(simpleCatchParam, DeclarationKind::SimpleCatchParameter, pos())) - return null(); - - Node list = statementList(yieldHandling); - if (!list) - return null(); - - // The catch parameter name is not bound in this scope, so remove it - // before generating bindings. - scope.removeSimpleCatchParameter(pc, simpleCatchParam); - - body = finishLexicalScope(scope, list); - } else { - body = statementList(yieldHandling); - } - if (!body) + // ES 13.15.7 CatchClauseEvaluation + // + // Step 8 means that the body of a catch block always has an additional + // lexical scope. + ParseContext::Scope scope(this); + if (!scope.init(pc)) + return null(); + + // The catch parameter names cannot be redeclared inside the catch + // block, so declare the name in the inner scope. + if (!scope.addCatchParameters(pc, catchParamScope)) + return null(); + + Node list = statementList(yieldHandling); + if (!list) return null(); MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_CATCH); - return body; + // The catch parameter names are not bound in the body scope, so remove + // them before generating bindings. + scope.removeCatchParameters(pc, catchParamScope); + return finishLexicalScope(scope, list); } template <typename ParseHandler> typename ParseHandler::Node Parser<ParseHandler>::debuggerStatement() { TokenPos p; p.begin = pos().begin;
--- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -149,19 +149,20 @@ class ParseContext : public Nestable<Par { return maybeReportOOM(pc, declared_->add(p, name, DeclaredNameInfo(kind))); } // Remove all VarForAnnexBLexicalFunction declarations of a certain // name from all scopes in pc's scope stack. static void removeVarForAnnexBLexicalFunction(ParseContext* pc, JSAtom* name); - // Remove a simple catch parameter name. Used to implement the odd - // semantics of Annex B.3.5. - void removeSimpleCatchParameter(ParseContext* pc, JSAtom* name); + // Add and remove catch parameter names. Used to implement the odd + // semantics of catch bodies. + bool addCatchParameters(ParseContext* pc, Scope& catchParamScope); + void removeCatchParameters(ParseContext* pc, Scope& catchParamScope); void useAsVarScope(ParseContext* pc) { MOZ_ASSERT(!pc->varScope_); pc->varScope_ = this; } // An iterator for the set of names a scope binds: the set of all // declared names for 'var' scopes, and the set of lexically declared @@ -1037,17 +1038,17 @@ class Parser final : private JS::AutoGCR Node switchStatement(YieldHandling yieldHandling); Node continueStatement(YieldHandling yieldHandling); Node breakStatement(YieldHandling yieldHandling); Node returnStatement(YieldHandling yieldHandling); Node withStatement(YieldHandling yieldHandling); Node throwStatement(YieldHandling yieldHandling); Node tryStatement(YieldHandling yieldHandling); - Node catchBlockStatement(YieldHandling yieldHandling, HandlePropertyName simpleCatchParam); + Node catchBlockStatement(YieldHandling yieldHandling, ParseContext::Scope& catchParamScope); Node debuggerStatement(); Node variableStatement(YieldHandling yieldHandling); Node labeledStatement(YieldHandling yieldHandling); Node labeledItem(YieldHandling yieldHandling); Node ifStatement(YieldHandling yieldHandling); @@ -1234,17 +1235,17 @@ class Parser final : private JS::AutoGCR bool declareFunctionArgumentsObject(); bool declareFunctionThis(); Node newInternalDotName(HandlePropertyName name); Node newThisName(); Node newDotGeneratorName(); bool declareDotGeneratorName(); bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, - bool *tryAnnexB); + GeneratorKind generatorKind, bool* tryAnnexB); bool skipLazyInnerFunction(Node pn, bool tryAnnexB); bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, InHandling inHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, InHandling inHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, bool tryAnnexB, Directives inheritedDirectives, @@ -1270,16 +1271,18 @@ class Parser final : private JS::AutoGCR bool checkStrictAssignment(Node lhs); bool checkStrictBinding(PropertyName* name, TokenPos pos); void reportRedeclaration(HandlePropertyName name, DeclarationKind kind, TokenPos pos); bool notePositionalFormalParameter(Node fn, HandlePropertyName name, bool disallowDuplicateParams = false, bool* duplicatedParam = nullptr); bool noteDestructuredPositionalFormalParameter(Node fn, Node destruct); + mozilla::Maybe<DeclarationKind> isVarRedeclaredInEval(HandlePropertyName name, + DeclarationKind kind); bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind, mozilla::Maybe<DeclarationKind>* redeclaredKind); bool tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name, bool* tryAnnexB); bool checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt, DeclarationKind kind, TokenPos pos); bool noteDeclaredName(HandlePropertyName name, DeclarationKind kind, TokenPos pos); bool noteUsedName(HandlePropertyName name); bool hasUsedName(HandlePropertyName name);
--- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1272,16 +1272,17 @@ Scope::traceChildren(JSTracer* trc) case ScopeKind::Function: reinterpret_cast<FunctionScope::Data*>(data_)->trace(trc); break; case ScopeKind::FunctionBodyVar: case ScopeKind::ParameterExpressionVar: reinterpret_cast<VarScope::Data*>(data_)->trace(trc); break; case ScopeKind::Lexical: + case ScopeKind::SimpleCatch: case ScopeKind::Catch: case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: reinterpret_cast<LexicalScope::Data*>(data_)->trace(trc); break; case ScopeKind::Global: case ScopeKind::NonSyntactic: reinterpret_cast<GlobalScope::Data*>(data_)->trace(trc); @@ -1319,16 +1320,17 @@ js::GCMarker::eagerlyMarkChildren(Scope* case ScopeKind::ParameterExpressionVar: { VarScope::Data* data = reinterpret_cast<VarScope::Data*>(scope->data_); names = data->names; length = data->length; break; } case ScopeKind::Lexical: + case ScopeKind::SimpleCatch: case ScopeKind::Catch: case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: { LexicalScope::Data* data = reinterpret_cast<LexicalScope::Data*>(scope->data_); names = data->names; length = data->length; break; }
deleted file mode 100644 --- a/js/src/jit-test/tests/jaeger/bug601400.js +++ /dev/null @@ -1,8 +0,0 @@ -// |jit-test| error: TypeError - -eval("\ - function NaN() {}\ - for(w in s) {}\ -") - -// Don't assert.
--- a/js/src/jit/JitFrameIterator.h +++ b/js/src/jit/JitFrameIterator.h @@ -647,17 +647,17 @@ class InlineFrameIterator struct Nop { void operator()(const Value& v) { } }; private: void findNextFrame(); JSObject* computeEnvironmentChain(Value envChainValue, MaybeReadFallback& fallback, - bool* hasCallObj = nullptr) const; + bool* hasInitialEnv = nullptr) const; public: InlineFrameIterator(JSContext* cx, const JitFrameIterator* iter); InlineFrameIterator(JSRuntime* rt, const JitFrameIterator* iter); InlineFrameIterator(JSContext* cx, const InlineFrameIterator* iter); bool more() const { return frame_ && framesRead_ < frameCount_; @@ -689,27 +689,27 @@ class InlineFrameIterator if (more()) return numActualArgs_; return frame_->numActualArgs(); } template <class ArgOp, class LocalOp> void readFrameArgsAndLocals(JSContext* cx, ArgOp& argOp, LocalOp& localOp, - JSObject** envChain, bool* hasCallObj, + JSObject** envChain, bool* hasInitialEnv, Value* rval, ArgumentsObject** argsObj, Value* thisv, ReadFrameArgsBehavior behavior, MaybeReadFallback& fallback) const { SnapshotIterator s(si_); // Read the env chain. if (envChain) { Value envChainValue = s.maybeRead(fallback); - *envChain = computeEnvironmentChain(envChainValue, fallback, hasCallObj); + *envChain = computeEnvironmentChain(envChainValue, fallback, hasInitialEnv); } else { s.skip(); } // Read return value. if (rval) *rval = s.maybeRead(fallback); else
--- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -2392,27 +2392,29 @@ InlineFrameIterator::callee(MaybeReadFal SnapshotIterator s(si_); // :TODO: Handle allocation failures from recover instruction. Value funval = s.maybeRead(calleeRVA_, fallback); return &funval.toObject().as<JSFunction>(); } JSObject* InlineFrameIterator::computeEnvironmentChain(Value envChainValue, MaybeReadFallback& fallback, - bool* hasCallObj) const + bool* hasInitialEnv) const { if (envChainValue.isObject()) { - if (hasCallObj) { + if (hasInitialEnv) { if (fallback.canRecoverResults()) { RootedObject obj(fallback.maybeCx, &envChainValue.toObject()); - *hasCallObj = isFunctionFrame() && callee(fallback)->needsCallObject(); + *hasInitialEnv = isFunctionFrame() && + callee(fallback)->needsFunctionEnvironmentObjects(); return obj; } else { JS::AutoSuppressGCAnalysis nogc; // If we cannot recover then we cannot GC. - *hasCallObj = isFunctionFrame() && callee(fallback)->needsCallObject(); + *hasInitialEnv = isFunctionFrame() && + callee(fallback)->needsFunctionEnvironmentObjects(); } } return &envChainValue.toObject(); } // Note we can hit this case even for functions with a CallObject, in case // we are walking the frame during the function prologue, before the env
--- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1664,37 +1664,16 @@ JSObject::swap(JSContext* cx, HandleObje return true; } static bool DefineStandardSlot(JSContext* cx, HandleObject obj, JSProtoKey key, JSAtom* atom, HandleValue v, uint32_t attrs, bool& named) { RootedId id(cx, AtomToId(atom)); - - if (key != JSProto_Null) { - /* - * Initializing an actual standard class on a global object. If the - * property is not yet present, force it into a new one bound to a - * reserved slot. Otherwise, go through the normal property path. - */ - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); - - if (!global->lookup(cx, id)) { - global->setConstructorPropertySlot(key, v); - - uint32_t slot = GlobalObject::constructorPropertySlot(key); - if (!NativeObject::addProperty(cx, global, id, nullptr, nullptr, slot, attrs, 0)) - return false; - - named = true; - return true; - } - } - named = DefineProperty(cx, obj, id, v, nullptr, nullptr, attrs); return named; } static void SetClassObject(JSObject* obj, JSProtoKey key, JSObject* cobj, JSObject* proto) { if (!obj->is<GlobalObject>())
--- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -706,16 +706,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl return false; break; case ScopeKind::FunctionBodyVar: case ScopeKind::ParameterExpressionVar: if (!VarScope::XDR(xdr, scopeKind, enclosing, &scope)) return false; break; case ScopeKind::Lexical: + case ScopeKind::SimpleCatch: case ScopeKind::Catch: case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: if (!LexicalScope::XDR(xdr, scopeKind, enclosing, &scope)) return false; break; case ScopeKind::With: if (mode == XDR_DECODE) {
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-generators.js @@ -0,0 +1,26 @@ +// Tests by André Bargull <andrebargull@googlemail.com> + +// Annex B.3.3.1 +function f1() { + { function* g() {} } + assertEq(typeof g, "undefined"); +} +f1(); + +// Annex B.3.3.2 +{ function* g() {} } +assertEq(typeof g, "undefined"); + +// Annex B.3.3.3 +function f2() { + eval("{ function* g() {} }"); + assertEq(typeof g, "undefined"); +} +f2(); + +// Annex B.3.3.3 +eval("{ function* g() {} }"); +assertEq(typeof g, "undefined"); + +if (typeof reportCompare === "function") + reportCompare(true, true);
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/LexicalEnvironment/catch-body.js @@ -0,0 +1,19 @@ +function f() { + var probeParam, probeBlock; + let x = 'outside'; + + try { + throw []; + } catch ([_ = probeParam = function() { return x; }]) { + probeBlock = function() { return x; }; + let x = 'inside'; + } + + assertEq(probeBlock(), 'inside'); + assertEq(probeParam(), 'outside'); +} + +f(); + +if (typeof reportCompare === 'function') + reportCompare(true, true);
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/LexicalEnvironment/var-in-catch-body-annex-b-eval-destructuring.js @@ -0,0 +1,10 @@ +// |reftest| skip-if(!xulRuntime.shell) + +assertThrowsInstanceOf(() => evaluate(`try { throw {} } catch ({e}) { var e; }`), SyntaxError); +assertThrowsInstanceOf(() => evaluate(`try { throw {} } catch ({e}) { eval('var e'); }`), SyntaxError); + +assertThrowsInstanceOf(() => new Function(`try { throw {} } catch ({e}) { var e; }`), SyntaxError); +assertThrowsInstanceOf(new Function(`try { throw {} } catch ({e}) { eval('var e'); }`), SyntaxError); + +if (typeof reportCompare === "function") + reportCompare(true, true);
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/LexicalEnvironment/var-in-catch-body-annex-b-eval-for-of.js @@ -0,0 +1,12 @@ +// |reftest| skip-if(!xulRuntime.shell) + +assertThrowsInstanceOf(() => evaluate(` + try { throw null; } catch (e) { eval("for (var e of []) {}") } +`), SyntaxError); + +assertThrowsInstanceOf(new Function(` + try { throw null; } catch (e) { eval("for (var e of []) {}") } +`), SyntaxError); + +if (typeof reportCompare === "function") + reportCompare(true, true);
--- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -546,24 +546,24 @@ class js::WasmArrayRawBuffer MOZ_RELEASE_ASSERT(newMax.isValid()); MOZ_RELEASE_ASSERT(newMax.value() % wasm::PageSize == 0); size_t newMapped = wasm::LegalizeMapLength(newMax.value()); # ifdef XP_WIN if (!VirtualAlloc(dataPointer(), newMapped, MEM_RESERVE, PAGE_NOACCESS)) return; -# elif defined(XP_DARWIN) +# elif defined(XP_LINUX) + // Note this will not move memory (no MREMAP_MAYMOVE specified) + if (MAP_FAILED == mremap(dataPointer(), mappedSize_, newMapped, 0)) + return; +# else // No mechanism for remapping on MaxOS. Luckily shouldn't need it here // as most MacOS configs are 64 bit return; -#else // Unix - // Note this will not move memory (no MREMAP_MAYMOVE specified) - if (MAP_FAILED == mremap(dataPointer(), mappedSize_, newMapped, 0)) - return; # endif // !XP_WIN mappedSize_ = newMapped; maxSize_ = Some(newMax.value()); return; } };
--- a/js/src/vm/Debugger-inl.h +++ b/js/src/vm/Debugger-inl.h @@ -96,9 +96,23 @@ js::DebuggerFrame::owner() const inline js::Debugger* js::DebuggerObject::owner() const { JSObject* dbgobj = &getReservedSlot(OWNER_SLOT).toObject(); return Debugger::fromJSObject(dbgobj); } +inline js::PromiseObject* +js::DebuggerObject::promise() const +{ + MOZ_ASSERT(isPromise()); + + JSObject* referent = this->referent(); + if (IsCrossCompartmentWrapper(referent)) { + referent = CheckedUnwrap(referent); + MOZ_ASSERT(referent); + } + + return &referent->as<PromiseObject>(); +} + #endif /* vm_Debugger_inl_h */
--- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -15,17 +15,16 @@ #include "jsfriendapi.h" #include "jshashutil.h" #include "jsnum.h" #include "jsobj.h" #include "jsprf.h" #include "jswrapper.h" #include "asmjs/WasmInstance.h" -#include "builtin/Promise.h" #include "frontend/BytecodeCompiler.h" #include "frontend/Parser.h" #include "gc/Marking.h" #include "gc/Policy.h" #include "jit/BaselineDebugModeOSR.h" #include "jit/BaselineJIT.h" #include "js/Date.h" #include "js/GCAPI.h" @@ -745,17 +744,17 @@ Debugger::getScriptFrameWithIter(JSConte FrameMap::AddPtr p = frames.lookupForAdd(referent); if (!p) { /* Create and populate the Debugger.Frame object. */ RootedObject proto(cx, &object->getReservedSlot(JSSLOT_DEBUG_FRAME_PROTO).toObject()); RootedNativeObject debugger(cx, object); RootedDebuggerFrame frame(cx, DebuggerFrame::create(cx, proto, referent, maybeIter, - debugger)); + debugger)); if (!frame) return false; if (!ensureExecutionObservabilityOfFrame(cx, referent)) return false; if (!frames.add(p, referent, frame)) { ReportOutOfMemory(cx); @@ -6184,56 +6183,84 @@ Debugger::observesScript(JSScript* scrip } /* static */ bool Debugger::replaceFrameGuts(JSContext* cx, AbstractFramePtr from, AbstractFramePtr to, ScriptFrameIter& iter) { auto removeFromDebuggerFramesOnExit = MakeScopeExit([&] { // Remove any remaining old entries on exit, as the 'from' frame will - // be gone. On success, the range will be empty. - Debugger::forEachDebuggerFrame(from, [&](NativeObject* frameobj) { - frameobj->setPrivate(nullptr); - Debugger::fromChildJSObject(frameobj)->frames.remove(from); - }); + // be gone. This is only done in the failure case. On failure, the + // removeToDebuggerFramesOnExit lambda below will rollback any frames + // that were replaced, resulting in !frameMaps(to). On success, the + // range will be empty, as all from Frame.Debugger instances will have + // been removed. + MOZ_ASSERT_IF(inFrameMaps(to), !inFrameMaps(from)); + removeFromFrameMapsAndClearBreakpointsIn(cx, from); // Rekey missingScopes to maintain Debugger.Environment identity and // forward liveScopes to point to the new frame. DebugEnvironments::forwardLiveFrame(cx, from, to); }); // Forward live Debugger.Frame objects. Rooted<DebuggerFrameVector> frames(cx, DebuggerFrameVector(cx)); - if (!getDebuggerFrames(from, &frames)) - return false; + if (!getDebuggerFrames(from, &frames)) { + // An OOM here means that all Debuggers' frame maps still contain + // entries for 'from' and no entries for 'to'. Since the 'from' frame + // will be gone, they are removed by removeFromDebuggerFramesOnExit + // above. + return false; + } // If during the loop below we hit an OOM, we must also rollback any of // the frames that were successfully replaced. For OSR frames, OOM here // means those frames will pop from the OSR trampoline, which does not // call Debugger::onLeaveFrame. auto removeToDebuggerFramesOnExit = MakeScopeExit([&] { removeFromFrameMapsAndClearBreakpointsIn(cx, to); }); for (size_t i = 0; i < frames.length(); i++) { HandleDebuggerFrame frameobj = frames[i]; Debugger* dbg = Debugger::fromChildJSObject(frameobj); // Update frame object's ScriptFrameIter::data pointer. DebuggerFrame_freeScriptFrameIterData(cx->runtime()->defaultFreeOp(), frameobj); ScriptFrameIter::Data* data = iter.copyData(); - if (!data) - return false; + if (!data) { + // An OOM here means that some Debuggers' frame maps may still + // contain entries for 'from' and some Debuggers' frame maps may + // also contain entries for 'to'. Thus both + // removeFromDebuggerFramesOnExit and + // removeToDebuggerFramesOnExit must both run. + // + // The current frameobj in question is still in its Debugger's + // frame map keyed by 'from', so it will be covered by + // removeFromDebuggerFramesOnExit. + return false; + } frameobj->setPrivate(data); // Remove old frame. dbg->frames.remove(from); // Add the frame object with |to| as key. if (!dbg->frames.putNew(to, frameobj)) { + // This OOM is subtle. At this point, both + // removeFromDebuggerFramesOnExit and removeToDebuggerFramesOnExit + // must both run for the same reason given above. + // + // The difference is that the current frameobj is no longer in its + // Debugger's frame map, so it will not be cleaned up by neither + // lambda. Manually clean it up here. + FreeOp* fop = cx->runtime()->defaultFreeOp(); + DebuggerFrame_freeScriptFrameIterData(fop, frameobj); + DebuggerFrame_maybeDecrementFrameScriptStepModeCount(fop, to, frameobj); + ReportOutOfMemory(cx); return false; } } // All frames successfuly replaced, cancel the rollback. removeToDebuggerFramesOnExit.release(); @@ -8597,31 +8624,30 @@ DebuggerObject::proxyHandlerGetter(JSCon } #ifdef SPIDERMONKEY_PROMISE /* static */ bool DebuggerObject::isPromiseGetter(JSContext* cx, unsigned argc, Value* vp) { THIS_DEBUGOBJECT(cx, argc, vp, "get isPromise", args, object) - bool result; - if (!DebuggerObject::getIsPromise(cx, object, result)) - return false; - - args.rval().setBoolean(result); + args.rval().setBoolean(object->isPromise()); return true; } /* static */ bool DebuggerObject::promiseStateGetter(JSContext* cx, unsigned argc, Value* vp) { - THIS_DEBUGOBJECT_PROMISE(cx, argc, vp, "get promiseState", args, refobj); + THIS_DEBUGOBJECT(cx, argc, vp, "get promiseState", args, object); + + if (!DebuggerObject::requirePromise(cx, object)) + return false; RootedValue result(cx); - switch (promise->state()) { + switch (object->promiseState()) { case JS::PromiseState::Pending: result.setString(cx->names().pending); break; case JS::PromiseState::Fulfilled: result.setString(cx->names().fulfilled); break; case JS::PromiseState::Rejected: result.setString(cx->names().rejected); @@ -8630,47 +8656,43 @@ DebuggerObject::promiseStateGetter(JSCon args.rval().set(result); return true; } /* static */ bool DebuggerObject::promiseValueGetter(JSContext* cx, unsigned argc, Value* vp) { - THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, "get promiseValue", args, dbg, refobj); - - if (promise->state() != JS::PromiseState::Fulfilled) { + THIS_DEBUGOBJECT(cx, argc, vp, "get promiseValue", args, object); + + if (!DebuggerObject::requirePromise(cx, object)) + return false; + + if (object->promiseState() != JS::PromiseState::Fulfilled) { args.rval().setUndefined(); return true; } - RootedValue result(cx, promise->value()); - if (!dbg->wrapDebuggeeValue(cx, &result)) - return false; - - args.rval().set(result); - return true; + return DebuggerObject::getPromiseValue(cx, object, args.rval());; } /* static */ bool DebuggerObject::promiseReasonGetter(JSContext* cx, unsigned argc, Value* vp) { - THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, "get promiseReason", args, dbg, refobj); - - if (promise->state() != JS::PromiseState::Rejected) { + THIS_DEBUGOBJECT(cx, argc, vp, "get promiseReason", args, object); + + if (!DebuggerObject::requirePromise(cx, object)) + return false; + + if (object->promiseState() != JS::PromiseState::Rejected) { args.rval().setUndefined(); return true; } - RootedValue result(cx, promise->reason()); - if (!dbg->wrapDebuggeeValue(cx, &result)) - return false; - - args.rval().set(result); - return true; + return DebuggerObject::getPromiseReason(cx, object, args.rval());; } /* static */ bool DebuggerObject::promiseLifetimeGetter(JSContext* cx, unsigned argc, Value* vp) { THIS_DEBUGOBJECT_PROMISE(cx, argc, vp, "get promiseLifetime", args, refobj); args.rval().setNumber(promise->lifetime()); @@ -9320,32 +9342,28 @@ DebuggerObject::isGlobal() const bool DebuggerObject::isScriptedProxy() const { return js::IsScriptedProxy(referent()); } #ifdef SPIDERMONKEY_PROMISE -/* static */ bool -DebuggerObject::getIsPromise(JSContext* cx, HandleDebuggerObject object, - bool& result) -{ - JSObject* referent = object->referent(); +bool +DebuggerObject::isPromise() const +{ + JSObject* referent = this->referent(); + if (IsCrossCompartmentWrapper(referent)) { referent = CheckedUnwrap(referent); - - if (!referent) { - JS_ReportError(cx, "Permission denied to access object"); - return false; - } - } - - result = referent->is<PromiseObject>(); - return true; + if (!referent) + return false; + } + + return referent->is<PromiseObject>(); } #endif // SPIDERMONKEY_PROMISE /* static */ bool DebuggerObject::getClassName(JSContext* cx, HandleDebuggerObject object, MutableHandleString result) { RootedObject referent(cx, object->referent()); @@ -9386,16 +9404,22 @@ DebuggerObject::name() const JSAtom* DebuggerObject::displayName() const { MOZ_ASSERT(isFunction()); return referent()->as<JSFunction>().displayAtom(); } +JS::PromiseState +DebuggerObject::promiseState() const +{ + return promise()->state(); +} + /* static */ bool DebuggerObject::getParameterNames(JSContext* cx, HandleDebuggerObject object, MutableHandle<StringVector> result) { MOZ_ASSERT(object->isDebuggeeFunction()); RootedFunction referent(cx, &object->referent()->as<JSFunction>()); @@ -9525,16 +9549,38 @@ DebuggerObject::getErrorMessageName(JSCo } } } result.set(nullptr); return true; } +#ifdef SPIDERMONKEY_PROMISE +/* static */ bool +DebuggerObject::getPromiseValue(JSContext* cx, HandleDebuggerObject object, + MutableHandleValue result) +{ + MOZ_ASSERT(object->promiseState() == JS::PromiseState::Fulfilled); + + result.set(object->promise()->value()); + return object->owner()->wrapDebuggeeValue(cx, result); +} + +/* static */ bool +DebuggerObject::getPromiseReason(JSContext* cx, HandleDebuggerObject object, + MutableHandleValue result) +{ + MOZ_ASSERT(object->promiseState() == JS::PromiseState::Rejected); + + result.set(object->promise()->reason()); + return object->owner()->wrapDebuggeeValue(cx, result); +} +#endif // SPIDERMONKEY_PROMISE + /* static */ bool DebuggerObject::isExtensible(JSContext* cx, HandleDebuggerObject object, bool& result) { RootedObject referent(cx, object->referent()); Maybe<AutoCompartment> ac; ac.emplace(cx, referent); ErrorCopier ec(ac); @@ -9994,16 +10040,40 @@ DebuggerObject::requireGlobal(JSContext* "a global object", nullptr); } return false; } return true; } +#ifdef SPIDERMONKEY_PROMISE +/* static */ bool +DebuggerObject::requirePromise(JSContext* cx, HandleDebuggerObject object) +{ + RootedObject referent(cx, object->referent()); + + if (IsCrossCompartmentWrapper(referent)) { + referent = CheckedUnwrap(referent); + if (!referent) { + JS_ReportError(cx, "Permission denied to access object"); + return false; + } + } + + if (!referent->is<PromiseObject>()) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE, + "Debugger", "Promise", object->getClass()->name); + return false; + } + + return true; +} +#endif // SPIDERMONKEY_PROMISE + /* static */ bool DebuggerObject::getScriptedProxyTarget(JSContext* cx, HandleDebuggerObject object, MutableHandleDebuggerObject result) { MOZ_ASSERT(object->isScriptedProxy()); RootedObject referent(cx, object->referent()); Debugger* dbg = object->owner(); RootedObject unwrapped(cx, js::GetProxyTargetObject(referent));
--- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -14,16 +14,17 @@ #include "jsclist.h" #include "jscntxt.h" #include "jscompartment.h" #include "jsweakmap.h" #include "jswrapper.h" #include "asmjs/WasmJS.h" +#include "builtin/Promise.h" #include "ds/TraceableFifo.h" #include "gc/Barrier.h" #include "js/Debug.h" #include "js/GCVariant.h" #include "js/HashTable.h" #include "vm/GlobalObject.h" #include "vm/SavedStacks.h" @@ -1252,18 +1253,20 @@ class DebuggerObject : public NativeObje MutableHandleObject result); static MOZ_MUST_USE bool getErrorMessageName(JSContext* cx, HandleDebuggerObject object, MutableHandleString result); static MOZ_MUST_USE bool getScriptedProxyTarget(JSContext* cx, HandleDebuggerObject object, MutableHandleDebuggerObject result); static MOZ_MUST_USE bool getScriptedProxyHandler(JSContext* cx, HandleDebuggerObject object, MutableHandleDebuggerObject result); #ifdef SPIDERMONKEY_PROMISE - static MOZ_MUST_USE bool getIsPromise(JSContext* cx, HandleDebuggerObject object, - bool& result); + static MOZ_MUST_USE bool getPromiseValue(JSContext* cx, HandleDebuggerObject object, + MutableHandleValue result); + static MOZ_MUST_USE bool getPromiseReason(JSContext* cx, HandleDebuggerObject object, + MutableHandleValue result); #endif // SPIDERMONKEY_PROMISE // Methods static MOZ_MUST_USE bool isExtensible(JSContext* cx, HandleDebuggerObject object, bool& result); static MOZ_MUST_USE bool isSealed(JSContext* cx, HandleDebuggerObject object, bool& result); static MOZ_MUST_USE bool isFrozen(JSContext* cx, HandleDebuggerObject object, bool& result); static MOZ_MUST_USE bool getPrototypeOf(JSContext* cx, HandleDebuggerObject object, @@ -1304,18 +1307,24 @@ class DebuggerObject : public NativeObje // Infallible properties bool isCallable() const; bool isFunction() const; bool isDebuggeeFunction() const; bool isBoundFunction() const; bool isArrowFunction() const; bool isGlobal() const; bool isScriptedProxy() const; +#ifdef SPIDERMONKEY_PROMISE + bool isPromise() const; +#endif // SPIDERMONKEY_PROMISE JSAtom* name() const; JSAtom* displayName() const; +#ifdef SPIDERMONKEY_PROMISE + JS::PromiseState promiseState() const; +#endif // SPIDERMONKEY_PROMISE private: enum { OWNER_SLOT }; static const unsigned RESERVED_SLOTS = 1; @@ -1330,18 +1339,25 @@ class DebuggerObject : public NativeObje JSObject* referent() const { JSObject* obj = (JSObject*) getPrivate(); MOZ_ASSERT(obj); return obj; } Debugger* owner() const; +#ifdef SPIDERMONKEY_PROMISE + PromiseObject* promise() const; +#endif // SPIDERMONKEY_PROMISE + static DebuggerObject* checkThis(JSContext* cx, const CallArgs& args, const char* fnname); static MOZ_MUST_USE bool requireGlobal(JSContext* cx, HandleDebuggerObject object); +#ifdef SPIDERMONKEY_PROMISE + static MOZ_MUST_USE bool requirePromise(JSContext* cx, HandleDebuggerObject object); +#endif // SPIDERMONKEY_PROMISE static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp); // JSNative properties static MOZ_MUST_USE bool callableGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool isBoundFunctionGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool isArrowFunctionGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool protoGetter(JSContext* cx, unsigned argc, Value* vp);
--- a/js/src/vm/EnvironmentObject.cpp +++ b/js/src/vm/EnvironmentObject.cpp @@ -3224,19 +3224,21 @@ CheckVarNameConflictsInEnv(JSContext* cx obj->as<DebugEnvironmentProxy>().environment().is<LexicalEnvironmentObject>()) { env = &obj->as<DebugEnvironmentProxy>().environment().as<LexicalEnvironmentObject>(); } else { // Environment cannot contain lexical bindings. return true; } - if (env->isSyntactic() && !env->isGlobal() && env->scope().kind() == ScopeKind::Catch) { - // Annex B.3.5 says 'var' declarations with the same name as catch - // parameters are allowed. + if (env->isSyntactic() && !env->isGlobal() && env->scope().kind() == ScopeKind::SimpleCatch) { + // Annex B.3.5 allows redeclaring simple (non-destructured) catch + // parameters with var declarations, except when it appears in a + // for-of. The for-of allowance is computed in + // Parser::isVarRedeclaredInEval. return true; } RootedPropertyName name(cx); for (BindingIter bi(script); bi; bi++) { name = bi.name()->asPropertyName(); if (!CheckVarNameConflict(cx, env, name)) return false; @@ -3244,18 +3246,16 @@ CheckVarNameConflictsInEnv(JSContext* cx return true; } bool js::CheckEvalDeclarationConflicts(JSContext* cx, HandleScript script, HandleObject scopeChain, HandleObject varObj) { - // We don't need to check body-level lexical bindings for conflict. Eval - // scripts always execute under their own lexical scope. if (!script->bodyScope()->as<EvalScope>().hasBindings()) return true; RootedObject obj(cx, scopeChain); // ES6 18.2.1.2 step d // // Check that a direct eval will not hoist 'var' bindings over lexical
--- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -215,22 +215,22 @@ GlobalObject::resolveConstructor(JSConte // Create the constructor. RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, key)); if (!ctor) return false; RootedId id(cx, NameToId(ClassName(key, cx))); if (isObjectOrFunction) { if (clasp->specShouldDefineConstructor()) { - if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0)) + RootedValue ctorValue(cx, ObjectValue(*ctor)); + if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING)) return false; } global->setConstructor(key, ObjectValue(*ctor)); - global->setConstructorPropertySlot(key, ObjectValue(*ctor)); } // Define any specified functions and properties, unless we're a dependent // standard class (in which case they live on the prototype), or we're // operating on the self-hosting global, in which case we don't want any // functions and properties on the builtins and their prototypes. if (!StandardClassIsDependent(key) && !cx->runtime()->isSelfHostingGlobal(global)) { if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) { @@ -262,56 +262,48 @@ GlobalObject::resolveConstructor(JSConte } if (!isObjectOrFunction) { // Any operations that modifies the global object should be placed // after any other fallible operations. // Fallible operation that modifies the global object. if (clasp->specShouldDefineConstructor()) { - if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0)) + RootedValue ctorValue(cx, ObjectValue(*ctor)); + if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING)) return false; } // Infallible operations that modify the global object. global->setConstructor(key, ObjectValue(*ctor)); - global->setConstructorPropertySlot(key, ObjectValue(*ctor)); if (proto) global->setPrototype(key, ObjectValue(*proto)); } - if (clasp->specShouldDefineConstructor()) { - // Stash type information, so that what we do here is equivalent to - // initBuiltinConstructor. - AddTypePropertyId(cx, global, id, ObjectValue(*ctor)); - } - return true; } /* static */ bool GlobalObject::initBuiltinConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key, HandleObject ctor, HandleObject proto) { MOZ_ASSERT(!global->empty()); // reserved slots already allocated MOZ_ASSERT(key != JSProto_Null); MOZ_ASSERT(ctor); MOZ_ASSERT(proto); RootedId id(cx, NameToId(ClassName(key, cx))); MOZ_ASSERT(!global->lookup(cx, id)); - if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0)) + RootedValue ctorValue(cx, ObjectValue(*ctor)); + if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING)) return false; global->setConstructor(key, ObjectValue(*ctor)); global->setPrototype(key, ObjectValue(*proto)); - global->setConstructorPropertySlot(key, ObjectValue(*ctor)); - - AddTypePropertyId(cx, global, id, ObjectValue(*ctor)); return true; } GlobalObject* GlobalObject::createInternal(JSContext* cx, const Class* clasp) { MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL); MOZ_ASSERT(clasp->isTrace(JS_GlobalObjectTraceHook));
--- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -41,43 +41,39 @@ enum class SimdType; * are traced for GC purposes. Apart from that the engine never touches * these slots, so the embedding can do whatever it wants with them. * [APPLICATION_SLOTS, APPLICATION_SLOTS + JSProto_LIMIT) * Stores the original value of the constructor for the corresponding * JSProtoKey. * [APPLICATION_SLOTS + JSProto_LIMIT, APPLICATION_SLOTS + 2 * JSProto_LIMIT) * Stores the prototype, if any, for the constructor for the corresponding * JSProtoKey offset from JSProto_LIMIT. - * [APPLICATION_SLOTS + 2 * JSProto_LIMIT, APPLICATION_SLOTS + 3 * JSProto_LIMIT) - * Stores the current value of the global property named for the JSProtoKey - * for the corresponding JSProtoKey offset from 2 * JSProto_LIMIT. - * [APPLICATION_SLOTS + 3 * JSProto_LIMIT, RESERVED_SLOTS) + * [APPLICATION_SLOTS + 2 * JSProto_LIMIT, RESERVED_SLOTS) * Various one-off values: ES5 13.2.3's [[ThrowTypeError]], RegExp statics, * the original eval for this global object (implementing |var eval = * otherWindow.eval; eval(...)| as an indirect eval), a bit indicating * whether this object has been cleared (see JS_ClearScope), and a cache for * whether eval is allowed (per the global's Content Security Policy). * - * The first two JSProto_LIMIT-sized ranges are necessary to implement + * The two JSProto_LIMIT-sized ranges are necessary to implement * js::FindClassObject, and spec language speaking in terms of "the original * Array prototype object", or "as if by the expression new Array()" referring - * to the original Array constructor. The third range stores the (writable and - * even deletable) Object, Array, &c. properties (although a slot won't be used - * again if its property is deleted and readded). + * to the original Array constructor. The actual (writable and even deletable) + * Object, Array, &c. properties are not stored in reserved slots. */ class GlobalObject : public NativeObject { /* Count of slots set aside for application use. */ static const unsigned APPLICATION_SLOTS = JSCLASS_GLOBAL_APPLICATION_SLOTS; /* - * Count of slots to store built-in constructors, prototypes, and initial - * visible properties for the constructors. + * Count of slots to store built-in prototypes and initial visible + * properties for the constructors. */ - static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 3; + static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 2; enum : unsigned { /* Various function values needed by the engine. */ EVAL = APPLICATION_SLOTS + STANDARD_CLASS_SLOTS, CREATE_DATAVIEW_FOR_THIS, THROWTYPEERROR, /* @@ -179,29 +175,16 @@ class GlobalObject : public NativeObject return getSlot(APPLICATION_SLOTS + JSProto_LIMIT + key); } void setPrototype(JSProtoKey key, const Value& value) { MOZ_ASSERT(key <= JSProto_LIMIT); setSlot(APPLICATION_SLOTS + JSProto_LIMIT + key, value); } - static uint32_t constructorPropertySlot(JSProtoKey key) { - MOZ_ASSERT(key <= JSProto_LIMIT); - return APPLICATION_SLOTS + JSProto_LIMIT * 2 + key; - } - - Value getConstructorPropertySlot(JSProtoKey key) { - return getSlot(constructorPropertySlot(key)); - } - - void setConstructorPropertySlot(JSProtoKey key, const Value& ctor) { - setSlot(constructorPropertySlot(key), ctor); - } - bool classIsInitialized(JSProtoKey key) const { bool inited = !getConstructor(key).isUndefined(); MOZ_ASSERT(inited == !getPrototype(key).isUndefined()); return inited; } bool functionObjectClassesInitialized() const { bool inited = classIsInitialized(JSProto_Function);
--- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -979,17 +979,20 @@ js::EnterWithOperation(JSContext* cx, Ab return true; } static void PopEnvironment(JSContext* cx, EnvironmentIter& ei) { switch (ei.scope().kind()) { case ScopeKind::Lexical: + case ScopeKind::SimpleCatch: case ScopeKind::Catch: + case ScopeKind::NamedLambda: + case ScopeKind::StrictNamedLambda: if (MOZ_UNLIKELY(cx->compartment()->isDebuggee())) DebugEnvironments::onPopLexical(cx, ei); if (ei.scope().hasEnvironment()) ei.initialFrame().popOffEnvironmentChain<LexicalEnvironmentObject>(); break; case ScopeKind::With: if (MOZ_UNLIKELY(cx->compartment()->isDebuggee())) DebugEnvironments::onPopWith(ei.initialFrame()); @@ -1005,18 +1008,16 @@ PopEnvironment(JSContext* cx, Environmen case ScopeKind::ParameterExpressionVar: case ScopeKind::StrictEval: if (MOZ_UNLIKELY(cx->compartment()->isDebuggee())) DebugEnvironments::onPopVar(cx, ei); if (ei.scope().hasEnvironment()) ei.initialFrame().popOffEnvironmentChain<VarEnvironmentObject>(); break; case ScopeKind::Eval: - case ScopeKind::NamedLambda: - case ScopeKind::StrictNamedLambda: case ScopeKind::Global: case ScopeKind::NonSyntactic: case ScopeKind::Module: break; } } // Unwind environment chain and iterator to match the env corresponding to
--- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -51,16 +51,17 @@ js::ScopeKindString(ScopeKind kind) case ScopeKind::Function: return "function"; case ScopeKind::FunctionBodyVar: return "function body var"; case ScopeKind::ParameterExpressionVar: return "parameter expression var"; case ScopeKind::Lexical: return "lexical"; + case ScopeKind::SimpleCatch: case ScopeKind::Catch: return "catch"; case ScopeKind::NamedLambda: return "named lambda"; case ScopeKind::StrictNamedLambda: return "strict named lambda"; case ScopeKind::With: return "with"; @@ -269,16 +270,33 @@ Scope::XDRSizedBindingNames(XDRState<mod Scope::create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape) { Scope* scope = Allocate<Scope>(cx); if (scope) new (scope) Scope(kind, enclosing, envShape); return scope; } +template <typename T, typename D> +/* static */ Scope* +Scope::create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing, + HandleShape envShape, mozilla::UniquePtr<T, D> data) +{ + Scope* scope = create(cx, kind, enclosing, envShape); + if (!scope) + return nullptr; + + // It is an invariant that all Scopes that have data (currently, all + // ScopeKinds except With) must have non-null data. + MOZ_ASSERT(data); + scope->initData(Move(data)); + + return scope; +} + uint32_t Scope::chainLength() const { uint32_t length = 0; for (ScopeIter si(const_cast<Scope*>(this)); si; si++) length++; return length; } @@ -313,71 +331,65 @@ Scope::clone(JSContext* cx, HandleScope { RootedShape envShape(cx); if (scope->environmentShape()) { envShape = scope->maybeCloneEnvironmentShape(cx); if (!envShape) return nullptr; } - Scope* scopeClone = create(cx, scope->kind_, enclosing, envShape); - if (!scopeClone) - return nullptr; - switch (scope->kind_) { case ScopeKind::Function: MOZ_CRASH("Use FunctionScope::clone."); break; case ScopeKind::FunctionBodyVar: case ScopeKind::ParameterExpressionVar: { Rooted<VarScope::Data*> original(cx, &scope->as<VarScope>().data()); UniquePtr<VarScope::Data> dataClone = CopyScopeData<VarScope>(cx, original); if (!dataClone) return nullptr; - scopeClone->initData(Move(dataClone)); - break; + return create(cx, scope->kind_, enclosing, envShape, Move(dataClone)); } case ScopeKind::Lexical: + case ScopeKind::SimpleCatch: case ScopeKind::Catch: case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: { Rooted<LexicalScope::Data*> original(cx, &scope->as<LexicalScope>().data()); UniquePtr<LexicalScope::Data> dataClone = CopyScopeData<LexicalScope>(cx, original); if (!dataClone) return nullptr; - scopeClone->initData(Move(dataClone)); - break; + return create(cx, scope->kind_, enclosing, envShape, Move(dataClone)); } case ScopeKind::With: - break; + return create(cx, scope->kind_, enclosing, envShape); case ScopeKind::Eval: case ScopeKind::StrictEval: { Rooted<EvalScope::Data*> original(cx, &scope->as<EvalScope>().data()); UniquePtr<EvalScope::Data> dataClone = CopyScopeData<EvalScope>(cx, original); if (!dataClone) return nullptr; - scopeClone->initData(Move(dataClone)); - break; + return create(cx, scope->kind_, enclosing, envShape, Move(dataClone)); } case ScopeKind::Global: case ScopeKind::NonSyntactic: MOZ_CRASH("Use GlobalScope::clone."); break; case ScopeKind::Module: MOZ_CRASH("NYI"); break; } - return scopeClone; + return nullptr; } void Scope::finalize(FreeOp* fop) { if (data_) { fop->free_(reinterpret_cast<void*>(data_)); data_ = 0; @@ -403,16 +415,17 @@ Scope::dump() fprintf(stderr, "\n"); } uint32_t LexicalScope::firstFrameSlot() const { switch (kind()) { case ScopeKind::Lexical: + case ScopeKind::SimpleCatch: case ScopeKind::Catch: // For intra-frame scopes, find the enclosing scope's next frame slot. return nextFrameSlot(enclosing()); case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: // Named lambda scopes cannot have frame slots. return LOCALNO_LIMIT; default: @@ -428,16 +441,17 @@ LexicalScope::nextFrameSlot(Scope* scope for (ScopeIter si(scope); si; si++) { switch (si.kind()) { case ScopeKind::Function: return si.scope()->as<FunctionScope>().nextFrameSlot(); case ScopeKind::FunctionBodyVar: case ScopeKind::ParameterExpressionVar: return si.scope()->as<VarScope>().nextFrameSlot(); case ScopeKind::Lexical: + case ScopeKind::SimpleCatch: case ScopeKind::Catch: return si.scope()->as<LexicalScope>().nextFrameSlot(); case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: // Named lambda scopes cannot have frame slots. return 0; case ScopeKind::With: continue; @@ -472,25 +486,21 @@ LexicalScope::create(ExclusiveContext* c Rooted<UniquePtr<Data>> copy(cx, CopyScopeData<LexicalScope>(cx, bi, data, &LexicalEnvironmentObject::class_, BaseShape::NOT_EXTENSIBLE | BaseShape::DELEGATE, &envShape)); if (!copy) return nullptr; - Scope* scope = Scope::create(cx, kind, enclosing, envShape); + Scope* scope = Scope::create(cx, kind, enclosing, envShape, Move(copy.get())); if (!scope) return nullptr; - MOZ_ASSERT(scope->as<LexicalScope>().firstFrameSlot() == firstFrameSlot); - - LexicalScope* lexicalScope = &scope->as<LexicalScope>(); - lexicalScope->initData(Move(copy.get())); - return lexicalScope; + return &scope->as<LexicalScope>(); } /* static */ Shape* LexicalScope::getEmptyExtensibleEnvironmentShape(ExclusiveContext* cx) { const Class* cls = &LexicalEnvironmentObject::class_; return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), BaseShape::DELEGATE); } @@ -769,23 +779,20 @@ VarScope::create(ExclusiveContext* cx, S // - Extensible scopes (i.e., due to direct eval) // - Being a generator if (!envShape && needsEnvironment) { envShape = getEmptyEnvironmentShape(cx); if (!envShape) return nullptr; } - Scope* scope = Scope::create(cx, kind, enclosing, envShape); + Scope* scope = Scope::create(cx, kind, enclosing, envShape, Move(copy.get())); if (!scope) return nullptr; - - VarScope* varScope = &scope->as<VarScope>(); - varScope->initData(Move(copy.get())); - return varScope; + return &scope->as<VarScope>(); } /* static */ Shape* VarScope::getEmptyEnvironmentShape(ExclusiveContext* cx) { const Class* cls = &VarEnvironmentObject::class_; return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), VarScopeEnvShapeFlags); } @@ -875,40 +882,34 @@ GlobalScope::copyData(ExclusiveContext * GlobalScope::create(ExclusiveContext* cx, ScopeKind kind, Handle<Data*> data) { // The data that's passed in may be from the frontend and LifoAlloc'd. // Copy it now that we're creating a permanent VM scope. Rooted<UniquePtr<Data>> copy(cx, copyData(cx, data)); if (!copy) return nullptr; - Scope* scope = Scope::create(cx, kind, nullptr, nullptr); + Scope* scope = Scope::create(cx, kind, nullptr, nullptr, Move(copy.get())); if (!scope) return nullptr; - - GlobalScope* globalScope = &scope->as<GlobalScope>(); - globalScope->initData(Move(copy.get())); - return globalScope; + return &scope->as<GlobalScope>(); } /* static */ GlobalScope* GlobalScope::clone(JSContext* cx, Handle<GlobalScope*> scope, ScopeKind kind) { Rooted<Data*> dataOriginal(cx, &scope->as<GlobalScope>().data()); Rooted<UniquePtr<Data>> dataClone(cx, CopyScopeData<GlobalScope>(cx, dataOriginal)); if (!dataClone) return nullptr; - Scope* scopeClone = Scope::create(cx, kind, nullptr, nullptr); + Scope* scopeClone = Scope::create(cx, kind, nullptr, nullptr, Move(dataClone.get())); if (!scopeClone) return nullptr; - - GlobalScope* globalScopeClone = &scopeClone->as<GlobalScope>(); - globalScopeClone->initData(Move(dataClone.get())); - return globalScopeClone; + return &scopeClone->as<GlobalScope>(); } template <XDRMode mode> /* static */ bool GlobalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope) { MOZ_ASSERT((mode == XDR_DECODE) == !scope); @@ -993,23 +994,20 @@ EvalScope::create(ExclusiveContext* cx, // Strict eval and direct eval in parameter expressions always get their own // var environment even if there are no bindings. if (!envShape && scopeKind == ScopeKind::StrictEval) { envShape = getEmptyEnvironmentShape(cx); if (!envShape) return nullptr; } - Scope* scope = Scope::create(cx, scopeKind, enclosing, envShape); + Scope* scope = Scope::create(cx, scopeKind, enclosing, envShape, Move(copy.get())); if (!scope) return nullptr; - - EvalScope* evalScope = &scope->as<EvalScope>(); - evalScope->initData(Move(copy.get())); - return evalScope; + return &scope->as<EvalScope>(); } /* static */ Scope* EvalScope::nearestVarScopeForDirectEval(Scope* scope) { for (ScopeIter si(scope); si; si++) { switch (si.kind()) { case ScopeKind::Function: @@ -1150,16 +1148,17 @@ ScopeIter::hasSyntacticEnvironment() con { return scope()->hasEnvironment() && scope()->kind() != ScopeKind::NonSyntactic; } BindingIter::BindingIter(Scope* scope) { switch (scope->kind()) { case ScopeKind::Lexical: + case ScopeKind::SimpleCatch: case ScopeKind::Catch: init(scope->as<LexicalScope>().data(), scope->as<LexicalScope>().firstFrameSlot(), 0); break; case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: init(scope->as<LexicalScope>().data(), LOCALNO_LIMIT, IsNamedLambda); break;
--- a/js/src/vm/Scope.h +++ b/js/src/vm/Scope.h @@ -48,16 +48,17 @@ enum class ScopeKind : uint8_t Function, // VarScope FunctionBodyVar, ParameterExpressionVar, // LexicalScope Lexical, + SimpleCatch, Catch, NamedLambda, StrictNamedLambda, // WithScope With, // EvalScope @@ -67,16 +68,22 @@ enum class ScopeKind : uint8_t // GlobalScope Global, NonSyntactic, // ModuleScope Module }; +static inline bool +ScopeKindIsCatch(ScopeKind kind) +{ + return kind == ScopeKind::SimpleCatch || kind == ScopeKind::Catch; +} + const char* BindingKindString(BindingKind kind); const char* ScopeKindString(ScopeKind kind); class BindingName { // A JSAtom* with its low bit used as a tag for whether it is closed over // (i.e., exists in the environment shape). uintptr_t bits_; @@ -200,16 +207,20 @@ class Scope : public js::gc::TenuredCell enclosing_(enclosing), environmentShape_(environmentShape), data_(0) { } static Scope* create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape); + template <typename T, typename D> + static Scope* create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing, + HandleShape envShape, mozilla::UniquePtr<T, D> data); + template <typename ConcreteScope, XDRMode mode> static bool XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope, MutableHandle<typename ConcreteScope::Data*> data); Shape* maybeCloneEnvironmentShape(JSContext* cx); template <typename T, typename D> void initData(mozilla::UniquePtr<T, D> data) { @@ -293,16 +304,19 @@ class Scope : public js::gc::TenuredCell // // A lexical scope that holds let and const bindings. There are 4 kinds of // LexicalScopes. // // Lexical // A plain lexical scope. // +// SimpleCatch +// Holds the single catch parameter of a catch block. +// // Catch // Holds the catch parameters (and only the catch parameters) of a catch // block. // // NamedLambda // StrictNamedLambda // Holds the single name of the callee for a named lambda expression. // @@ -371,16 +385,17 @@ class LexicalScope : public Scope static Shape* getEmptyExtensibleEnvironmentShape(ExclusiveContext* cx); }; template <> inline bool Scope::is<LexicalScope>() const { return kind_ == ScopeKind::Lexical || + kind_ == ScopeKind::SimpleCatch || kind_ == ScopeKind::Catch || kind_ == ScopeKind::NamedLambda || kind_ == ScopeKind::StrictNamedLambda; } // // Scope corresponding to a function. Holds formal parameter names and, if the // function parameters contain no expressions that might possibly be
--- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -120,16 +120,17 @@ AssertScopeMatchesEnvironment(Scope* sco case ScopeKind::FunctionBodyVar: case ScopeKind::ParameterExpressionVar: MOZ_ASSERT(&env->as<VarEnvironmentObject>().scope() == si.scope()); env = &env->as<VarEnvironmentObject>().enclosingEnvironment(); break; case ScopeKind::Lexical: + case ScopeKind::SimpleCatch: case ScopeKind::Catch: case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: MOZ_ASSERT(&env->as<LexicalEnvironmentObject>().scope() == si.scope()); env = &env->as<LexicalEnvironmentObject>().enclosingEnvironment(); break; case ScopeKind::With:
--- a/layout/base/ServoRestyleManager.cpp +++ b/layout/base/ServoRestyleManager.cpp @@ -275,27 +275,31 @@ ServoRestyleManager::NoteRestyleHint(Ele } } void ServoRestyleManager::ProcessPendingRestyles() { MOZ_ASSERT(PresContext()->Document(), "No document? Pshaw!"); MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!"); + + if (MOZ_UNLIKELY(!PresContext()->PresShell()->DidInitialize())) { + // PresShell::FlushPendingNotifications doesn't early-return in the case + // where the PreShell hasn't yet been initialized (and therefore we haven't + // yet done the initial style traversal of the DOM tree). We should arguably + // fix up the callers and assert against this case, but we just detect and + // handle it for now. + return; + } + if (!HasPendingRestyles()) { return; } ServoStyleSet* styleSet = StyleSet(); - if (!styleSet->StylingStarted()) { - // If something caused us to restyle, and we haven't started styling yet, - // do nothing. Everything is dirty, and we'll style it all later. - return; - } - nsIDocument* doc = PresContext()->Document(); Element* root = doc->GetRootElement(); if (root) { for (auto iter = mModifiedElements.Iter(); !iter.Done(); iter.Next()) { ServoElementSnapshot* snapshot = iter.UserData(); Element* element = iter.Key(); // TODO: avoid the ComputeRestyleHint call if we already have the highest @@ -326,17 +330,17 @@ ServoRestyleManager::ProcessPendingResty RecreateStyleContexts(root, nullptr, styleSet, changeList); ProcessRestyledFrames(changeList); mInStyleRefresh = false; } } MOZ_ASSERT(!doc->IsDirtyForServo()); - MOZ_ASSERT(!doc->HasDirtyDescendantsForServo()); + doc->UnsetHasDirtyDescendantsForServo(); mModifiedElements.Clear(); IncrementRestyleGeneration(); } void ServoRestyleManager::RestyleForInsertOrChange(nsINode* aContainer, @@ -349,16 +353,30 @@ ServoRestyleManager::RestyleForInsertOrC // // Bug 1297899 tracks this work. // } void ServoRestyleManager::ContentInserted(nsINode* aContainer, nsIContent* aChild) { + if (aContainer == aContainer->OwnerDoc()) { + // If we're getting this notification for the insertion of a root element, + // that means either: + // (a) We initialized the PresShell before the root element existed, or + // (b) The root element was removed and it or another root is being + // inserted. + // + // Either way the whole tree is dirty, so we should style the document. + MOZ_ASSERT(aChild == aChild->OwnerDoc()->GetRootElement()); + MOZ_ASSERT(aChild->IsDirtyForServo()); + StyleSet()->StyleDocument(/* aLeaveDirtyBits = */ false); + return; + } + if (!aContainer->ServoData().get()) { // This can happen with display:none. Bug 1297249 tracks more investigation // and assertions here. return; } // Style the new subtree because we will most likely need it during subsequent // frame construction. Bug 1298281 tracks deferring this work in the lazy
--- a/layout/base/TouchManager.cpp +++ b/layout/base/TouchManager.cpp @@ -228,17 +228,17 @@ TouchManager::PreHandleEvent(WidgetEvent int32_t id = touch->Identifier(); TouchInfo info; if (!sCaptureTouchList->Get(id, &info)) { continue; } nsCOMPtr<EventTarget> targetPtr = info.mTouch->mTarget; nsCOMPtr<nsINode> targetNode(do_QueryInterface(targetPtr)); - if (!targetNode->IsInComposedDoc()) { + if (targetNode && !targetNode->IsInComposedDoc()) { targetPtr = do_QueryInterface(info.mNonAnonymousTarget); } aCurrentEventContent = do_QueryInterface(targetPtr); touch->SetTarget(targetPtr); sCaptureTouchList->Remove(id); } // add any touches left in the touch list, but ensure changed=false
--- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -2497,18 +2497,19 @@ nsPresContext::HasCachedStyleData() { if (!mShell) { return false; } nsStyleSet* styleSet = mShell->StyleSet()->GetAsGecko(); if (!styleSet) { // XXXheycam ServoStyleSets do not use the rule tree, so just assume for now - // that we need to restyle when e.g. dppx changes. - return true; + // that we need to restyle when e.g. dppx changes assuming we're sufficiently + // bootstrapped. + return mShell->DidInitialize(); } return styleSet->HasCachedStyleData(); } already_AddRefed<nsITimer> nsPresContext::CreateTimer(nsTimerCallbackFunc aCallback, uint32_t aDelay)
--- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1677,18 +1677,25 @@ PresShell::Initialize(nscoord aWidth, ns } #endif // XXX Do a full invalidate at the beginning so that invalidates along // the way don't have region accumulation issues? mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight)); - if (mStyleSet->IsServo()) { - mStyleSet->AsServo()->StartStyling(GetPresContext()); + if (mStyleSet->IsServo() && mDocument->GetRootElement()) { + // If we have the root element already, go ahead style it along with any + // descendants. + // + // Some things, like nsDocumentViewer::GetPageMode, recreate the PresShell + // while keeping the content tree alive (see bug 1292280) - so we + // unconditionally mark the root as dirty. + mDocument->GetRootElement()->SetIsDirtyForServo(); + mStyleSet->AsServo()->StyleDocument(/* aLeaveDirtyBits = */ false); } // Get the root frame from the frame manager // XXXbz it would be nice to move this somewhere else... like frame manager // Init(), say. But we need to make sure our views are all set up by the // time we do this! nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); NS_ASSERTION(!rootFrame, "How did that happen, exactly?");
--- a/layout/base/tests/test_bug603550.html +++ b/layout/base/tests/test_bug603550.html @@ -53,21 +53,21 @@ function fireEvent(target, event) { } function fireDrop(element) { var ds = SpecialPowers.Cc["@mozilla.org/widget/dragservice;1"]. getService(SpecialPowers.Ci.nsIDragService); ds.startDragSession(); - var event = document.createEvent("DragEvents"); + var event = document.createEvent("DragEvent"); event.initDragEvent("dragover", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, null); fireEvent(element, event); - event = document.createEvent("DragEvents"); + event = document.createEvent("DragEvent"); event.initDragEvent("drop", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, null); fireEvent(element, event); ds.endDragSession(false); ok(!ds.getCurrentSession(), "There shouldn't be a drag session anymore!"); } function runTest() {
--- a/layout/forms/test/test_bug477531.html +++ b/layout/forms/test/test_bug477531.html @@ -38,18 +38,18 @@ is(document.defaultView.getComputedStyle is(document.defaultView.getComputedStyle($("s"), null).getPropertyValue("margin-left"), "30px", "Indeterminate checkbox should have a margin of 30px"); $("s").setAttribute("type", "radio"); is(document.defaultView.getComputedStyle($("s"), null).getPropertyValue("margin-left"), - "10px", - "Only checkboxes should have indeterminate styles applied to them"); + "30px", + "Setting an indeterminate element to type radio should give it indeterminate styles"); $("s").setAttribute("type", "checkbox"); is(document.defaultView.getComputedStyle($("s"), null).getPropertyValue("margin-left"), "30px", "Setting an indeterminate element to type checkbox should give it indeterminate styles"); $("s").indeterminate = false;
--- a/layout/reftests/async-scrolling/reftest.list +++ b/layout/reftests/async-scrolling/reftest.list @@ -29,17 +29,17 @@ skip-if(!asyncPan) == fixed-pos-scrollab skip-if(!asyncPan) == culling-1.html culling-1-ref.html skip-if(!asyncPan) == position-fixed-iframe-1.html position-fixed-iframe-1-ref.html skip-if(!asyncPan) == position-fixed-iframe-2.html position-fixed-iframe-2-ref.html fuzzy-if(skiaContent,1,11300) skip-if(!asyncPan) == position-fixed-in-scroll-container.html position-fixed-in-scroll-container-ref.html skip-if(!asyncPan) == position-fixed-inside-sticky-1.html position-fixed-inside-sticky-1-ref.html fuzzy(1,60000) skip-if(!asyncPan) == group-opacity-surface-size-1.html group-opacity-surface-size-1-ref.html skip-if(!asyncPan) == position-sticky-transformed.html position-sticky-transformed-ref.html skip-if(!asyncPan) == offscreen-prerendered-active-opacity.html offscreen-prerendered-active-opacity-ref.html -fuzzy-if(Android,6,4) fuzzy-if(skiaContent,1,34) skip-if(!asyncPan) == offscreen-clipped-blendmode-1.html offscreen-clipped-blendmode-ref.html +fuzzy-if(Android,6,4) fuzzy-if(skiaContent&&!Android,1,34) skip-if(!asyncPan) == offscreen-clipped-blendmode-1.html offscreen-clipped-blendmode-ref.html fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html fuzzy-if(Android,6,4) skip == offscreen-clipped-blendmode-3.html offscreen-clipped-blendmode-ref.html # bug 1251588 - wrong AGR on mix-blend-mode item fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-4.html offscreen-clipped-blendmode-ref.html fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-1.html perspective-scrolling-1-ref.html fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-2.html perspective-scrolling-2-ref.html fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-3.html perspective-scrolling-3-ref.html fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-4.html perspective-scrolling-4-ref.html pref(apz.disable_for_scroll_linked_effects,true) skip-if(!asyncPan) == disable-apz-for-sle-pages.html disable-apz-for-sle-pages-ref.html
--- a/layout/reftests/border-image/reftest.list +++ b/layout/reftests/border-image/reftest.list @@ -41,17 +41,17 @@ fuzzy-if(asyncPan&&!layersGPUAccelerated == border-image-style-none-length.html border-image-style-none-length-ref.html == border-image-style-none-auto.html border-image-style-none-auto-ref.html # border images with gradients == border-image-linear-gradient.html border-image-linear-gradient-ref.html fuzzy(1,98) fuzzy-if(skiaContent,1,350) == border-image-linear-gradient-slice-1.html border-image-linear-gradient-slice-1-ref.html fuzzy(1,149) fuzzy-if(OSX,1,10595) == border-image-linear-gradient-slice-2.html border-image-linear-gradient-slice-2-ref.html fuzzy(1,433) fuzzy-if(skiaContent,1,2500) == border-image-linear-gradient-slice-fill-1.html border-image-linear-gradient-slice-fill-1-ref.html -fuzzy(1,177) fuzzy-if(OSX,1,25771) fuzzy-if(skiaContent,1,300) == border-image-linear-gradient-slice-fill-2.html border-image-linear-gradient-slice-fill-2-ref.html +fuzzy(1,177) fuzzy-if(OSX,1,25771) fuzzy-if(skiaContent,1,400) == border-image-linear-gradient-slice-fill-2.html border-image-linear-gradient-slice-fill-2-ref.html fuzzy(1,48) fuzzy-if(OSX,5,1676) == border-image-linear-gradient-width.html border-image-linear-gradient-width-ref.html fuzzy(1,5000) fuzzy-if(OSX,1,15000) == border-image-linear-gradient-slice-width.html border-image-linear-gradient-slice-width-ref.html fuzzy(1,3000) fuzzy-if(OSX,1,6000) == border-image-linear-gradient-outset.html border-image-linear-gradient-outset-ref.html fuzzy(1,12) fuzzy-if(skiaContent,1,400) == border-image-linear-gradient-repeat-repeat-1.html border-image-linear-gradient-repeat-repeat-1-ref.html fuzzy(1,13) fuzzy-if(skiaContent,1,300) == border-image-linear-gradient-repeat-round-1.html border-image-linear-gradient-repeat-round-1-ref.html == border-image-linear-gradient-repeat-repeat-2.html border-image-linear-gradient-repeat-repeat-2-ref.html fuzzy(1,576) fuzzy-if(skiaContent,1,2000) == border-image-linear-gradient-repeat-round-2.html border-image-linear-gradient-repeat-round-2-ref.html fuzzy(1,8533) == border-image-linear-gradient-repeat-repeat-3.html border-image-linear-gradient-repeat-repeat-3-ref.html
--- a/layout/reftests/border-radius/reftest.list +++ b/layout/reftests/border-radius/reftest.list @@ -47,17 +47,17 @@ fuzzy-if(true,1,20) fuzzy-if(d2d,64,196) fuzzy-if(Android,5,54) fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) fuzzy-if(skiaContent,1,140) == clipping-4-image.html clipping-4-ref.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) fuzzy-if(skiaContent,1,77) == clipping-4-overflow-hidden.html clipping-4-ref.html == clipping-5-canvas.html clipping-5-refc.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-image.html clipping-5-refi.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(skiaContent,1,77) == clipping-5-overflow-hidden.html clipping-5-ref.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(Android,5,21) fuzzy-if(skiaContent,1,77) == clipping-5-refi.html clipping-5-ref.html fuzzy-if(true,1,7) fuzzy-if(d2d,48,94) fuzzy-if(cocoaWidget,1,99) fuzzy-if(Android,99,115) fuzzy-if(skiaContent,1,77) == clipping-5-refc.html clipping-5-ref.html # bug 732535 fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,469) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical -fuzzy-if(true,2,29) fuzzy-if(d2d,46,50) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,16,27) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures). +fuzzy-if(true,2,29) fuzzy-if(d2d,46,50) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,19,29) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures). fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html fuzzy-if(cocoaWidget,1,4) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html == intersecting-clipping-1-image.html intersecting-clipping-1-refi.html == intersecting-clipping-1-overflow-hidden.html intersecting-clipping-1-ref.html fuzzy-if(Android,5,105) fuzzy-if(d2d,1,20) fuzzy-if(skiaContent,1,250) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html fuzzy-if(true,1,33) fuzzy-if(d2d,48,350) fuzzy-if(cocoaWidget,1,332) fuzzy-if(Android,124,440) fuzzy-if(skiaContent,1,135) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # bug 732535 # Inheritance @@ -66,17 +66,17 @@ fuzzy-if(true,1,33) fuzzy-if(d2d,48,350) # Table elements == table-collapse-1.html table-collapse-1-ref.html # border-radius is ignored on internal table elements # when border-collapse: collapse fuzzy-if(azureQuartz,1,3) skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,116) == invalidate-1a.html invalidate-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop fuzzy-if(azureQuartz,1,3) skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,117) == invalidate-1b.html invalidate-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop # test that border-radius is reduced for scrollbars -skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(asyncPan&&!layersGPUAccelerated,12,12) fuzzy-if(browserIsRemote&&layersGPUAccelerated&&/^Windows\x20NT\x206\.1/.test(http.oscpu),12,12) fuzzy-if(skiaContent,1,50) fuzzy-if(gtkWidget&&layersGPUAccelerated,12,12) == scrollbar-clamping-1.html scrollbar-clamping-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(asyncPan&&!layersGPUAccelerated,12,12) fuzzy-if(browserIsRemote&&layersGPUAccelerated&&/^Windows\x20NT\x206\.1/.test(http.oscpu),12,12) fuzzy-if(skiaContent&&!Android,1,50) fuzzy-if(gtkWidget&&layersGPUAccelerated,12,12) == scrollbar-clamping-1.html scrollbar-clamping-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fails-if(Android) == scrollbar-clamping-2.html scrollbar-clamping-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop # Test for bad corner joins. fuzzy-if(true,1,1) == corner-joins-1.xhtml corner-joins-1-ref.xhtml fuzzy(255,20) skip-if(B2G||Mulet) random-if(winWidget) fuzzy-if(skiaContent,255,610) HTTP(..) == corner-joins-2.xhtml corner-joins-2-ref.xhtml # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu),1,20) fuzzy-if(d2d,64,157) fuzzy-if(Android,166,400) fuzzy-if(skiaContent,64,70) == scroll-1.html scroll-1-ref.html # see bug 732535 #Bug 959166 # Initial mulet triage: parity with B2G/B2G Desktop
--- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -235,17 +235,17 @@ skip-if((B2G&&browserIsRemote)||Mulet) = == 234686-15.html 234686-ref.html == 234686-16.html 234686-ref.html == 234686-17.html 234686-ref.html == 234686-18.html 234686-ref.html == 234686-19.html 234686-ref.html skip-if(B2G||Mulet) == 234964-1.html 234964-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == 234964-2.html 234964-2-ref.html == 235593-1.html 235593-1-ref.html -== 236539-1.html 236539-1-ref.html +fuzzy-if(skiaContent,4,2) == 236539-1.html 236539-1-ref.html == 240029-1.html 240029-1-ref.html == 240470-1.html 240470-1-ref.html skip-if(B2G||Mulet) == 240933-1.html 240933-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(Android||B2G||Mulet) == 240933-2.html 240933-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == 243266-1.html 243266-1-ref.html == 243302-1.html 243302-1-ref.html skip-if(B2G||Mulet||(Android&&asyncPan)) == 243519-1.html 243519-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == 243519-2.html 243519-2-ref.html @@ -456,17 +456,17 @@ fuzzy-if(skiaContent,2,3) == 339289-1.ht == 343538-1.html 343538-1-ref.html == 343540-1.html 343540-1-ref.html == 345267-1a.html 345267-1-ref.html == 345267-1b.html 345267-1-ref.html == 345267-1c.html 345267-1-ref.html == 345267-1d.html 345267-1-ref.html != 345563-sub.xhtml 345563-sup.xhtml skip-if((B2G&&browserIsRemote)||Mulet) == 346189-1.xul 346189-1-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop -== 346774-1a.html 346774-1-ref.html +fuzzy-if(skiaContent,4,2) == 346774-1a.html 346774-1-ref.html == 346774-1b.html 346774-1-ref.html == 346774-1c.html 346774-1-ref.html == 347348-1.xhtml 347348-1-ref.xhtml == 347496-1.xhtml 347496-1-ref.xhtml == 347912-1.html 347912-1-ref.html skip-if((B2G&&browserIsRemote)||Mulet) == 348049-1.xhtml 348049-1-ref.xhtml # Initial mulet triage: parity with B2G/B2G Desktop == 348516-1.html 348516-1-ref.html == 348516-2.html 348516-2-ref.html @@ -653,17 +653,17 @@ skip-if(B2G||Mulet) == 372037-1.html 372 == 372063-1.html 372063-1-ref.html == 372323-1.xhtml 372323-1-ref.xhtml == 372553-1.html 372553-1-ref.html == 372632-1.html 372632-1-ref.html == 372768-1.html 372768-1-ref.html == 373295-1.html 373295-1-ref.html == 373298-1.html 373298-1-ref.html skip-if(B2G||Mulet) fails-if(Android) == 373381-1.html 373381-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,2,40) == 373381-2.html 373381-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,2,40) == 373381-2.html 373381-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fails-if(Android) random-if(d2d) == 373381-3.html 373381-3-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fails-if(Android) == 373381-4.html 373381-4-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == 373383-1.html 373383-1-ref.html == 373433-1.html 373433-1-ref.html skip-if((B2G&&browserIsRemote)||Mulet) == 373533-1.xhtml about:blank # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop skip-if((B2G&&browserIsRemote)||Mulet) == 373533-2.xhtml about:blank # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop skip-if((B2G&&browserIsRemote)||Mulet) == 373533-3.xhtml about:blank # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop skip-if((B2G&&browserIsRemote)||Mulet) == 374038-1.xul 374038-1-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop @@ -799,17 +799,17 @@ fuzzy-if(skiaContent,1,600) == 393649-1. == 393655-2.html 393655-2-ref.html == 393655-3.html 393655-3-ref.html == 393655-4.html 393655-4-ref.html == 393655-5.html 393655-5-ref.html == 393671-1.html 393671-1-ref.html == 393671-2.html 393671-2-ref.html == 393671-3.html 393671-3-ref.html == 393760-1.xml 393760-1-ref.xml -fuzzy-if(skiaContent,1,400) == 393760-2.xml 393760-2-ref.xml +fuzzy-if(skiaContent,1,500) == 393760-2.xml 393760-2-ref.xml == 394111-1.html about:blank # Really an assertion test rather than a rendering test == 394534-1.html 394534-1-ref.html skip-if((B2G&&browserIsRemote)||Mulet) == 394676-1.xhtml 394676-1-ref.xhtml # bug 975911 # Initial mulet triage: parity with B2G/B2G Desktop == 395107-1.html 395107-1-ref.html == 395107-2.html 395107-2-ref.html fuzzy-if(skiaContent,1,118) == 395107-3.html 395107-3-ref.html == 395107-4.html 395107-4-ref.html == 395107-5.html 395107-5-ref.html @@ -1497,18 +1497,18 @@ skip-if(B2G||Mulet) fuzzy-if(Android,12, # the test is not currently relevant under harfbuzz shaping. # Keeping it here for the record, and because we may evolve HB's dotted-circle # behavior further in the future, which could make this become relevant again. # Marked "random" rather than "fails" because it may (spuriously) appear to pass # on B2G or Android devices that completely lack any Sinhala font support. random != 553571-1.html 553571-1-notref.html # expect dotted circle in test, not in ref: "fails" under harfbuzz, which doesn't consider the sequence invalid fuzzy-if(!contentSameGfxBackendAsCanvas,128,91) random-if(d2d) skip-if(azureSkiaGL) fuzzy-if(skiaContent,32,150) == 555388-1.html 555388-1-ref.html == 556661-1.html 556661-1-ref.html -skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,5) == 557087-1.html 557087-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,2,5) == 557087-2.html 557087-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) fuzzy-if(skiaContent,4,5) == 557087-1.html 557087-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,2,5) == 557087-2.html 557087-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == 557736-1.html 557736-1-ref.html skip-if((B2G&&browserIsRemote)||Mulet) != 558011-1.xul 558011-1-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop == 559284-1.html 559284-1-ref.html skip-if(B2G||Mulet) fails-if(Android) == 560455-1.xul 560455-1-ref.xul # Initial mulet triage: parity with B2G/B2G Desktop fuzzy-if(skiaContent,2,5) == 561981-1.html 561981-1-ref.html == 561981-2.html 561981-2-ref.html fuzzy-if(skiaContent,1,5) == 561981-3.html 561981-3-ref.html == 561981-4.html 561981-4-ref.html @@ -1646,25 +1646,25 @@ HTTP(..) == 621253-2-externalFilter.html == 621253-2-internalFilter.html 621253-2-ref.html skip-if(B2G||Mulet) random-if(winWidget) fuzzy-if(OSX==1008,19,17) == 621918-1.svg 621918-1-ref.svg # 1-pixel diacritic positioning discrepancy in rotated text (may depend on platform fonts) # Initial mulet triage: parity with B2G/B2G Desktop random-if(winWidget) HTTP(..) == 621918-2.svg 621918-2-ref.svg # same 1px issue as above, and HTTP(..) for filters.svg, used to mask antialiasing issues where glyphs touch fuzzy-if(d2d,5,1) == 622585-1.html 622585-1-ref.html # bug 789402 fuzzy-if(Android,8,300) fuzzy-if(skiaContent,1,40000) == 625409-1.html 625409-1-ref.html == 627393-1.html about:blank fuzzy-if(skiaContent,1,500) == 630835-1.html about:blank == 631352-1.html 631352-1-ref.html -skip-if(!haveTestPlugin) skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(winWidget&&!layersGPUAccelerated,102,535) fuzzy-if(skiaContent,102,11000) == 632423-1.html 632423-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(!haveTestPlugin) skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(winWidget&&!layersGPUAccelerated,102,535) fuzzy-if(skiaContent&&!Android,102,11000) == 632423-1.html 632423-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(Android||B2G||Mulet) random-if(winWidget||OSX==1010) == 632781-verybig.html 632781-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == 632781-normalsize.html 632781-ref.html fuzzy-if(d2d&&/^Windows\x20NT\x206\.2/.test(http.oscpu),1,559) fuzzy-if(!isDebugBuild&>kWidget&&/^Linux\x20i686/.test(http.oscpu),102,140) == 633344-1.html 633344-1-ref.html # bug 1103623, Linux32 from GCC update fuzzy-if(skiaContent,1,500) == 634232-1.html 634232-1-ref.html fuzzy-if(skiaContent,3,120000) == 635302-1.html 635302-1-ref.html -fuzzy(1,68) fuzzy-if(gtkWidget,1,70) skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,1,300) == 635373-1.html 635373-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,118) fuzzy-if(skiaContent,2,550) == 635373-2.html 635373-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,116) fuzzy-if(skiaContent,2,650) == 635373-3.html 635373-3-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +fuzzy(1,68) fuzzy-if(gtkWidget,1,70) skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,1,300) == 635373-1.html 635373-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,118) fuzzy-if(skiaContent&&!Android,2,550) == 635373-2.html 635373-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,116) fuzzy-if(skiaContent&&!Android,2,650) == 635373-3.html 635373-3-ref.html # Initial mulet triage: parity with B2G/B2G Desktop HTTP(..) == 635639-1.html 635639-1-ref.html HTTP(..) == 635639-2.html 635639-2-ref.html random == 637597-1.html 637597-1-ref.html # bug 637597 was never really fixed! fuzzy-if(Android,8,500) == 637852-1.html 637852-1-ref.html fuzzy-if(Android,8,500) == 637852-2.html 637852-2-ref.html fuzzy-if(Android,8,500) == 637852-3.html 637852-3-ref.html skip-if(B2G||Mulet) == 641770-1.html 641770-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == 641856-1.html 641856-1-ref.html @@ -1673,17 +1673,17 @@ skip-if(B2G||Mulet) == 641770-1.html 641 == 645647-2.html 645647-2-ref.html == 645768-1.html 645768-1-ref.html fails-if(layersGPUAccelerated&&cocoaWidget) fuzzy-if(!layersGPUAccelerated,41,260) fuzzy-if(skiaContent,49,11000) == 650228-1.html 650228-1-ref.html # Quartz alpha blending doesn't match GL alpha blending needs-focus == 652301-1a.html 652301-1-ref.html needs-focus == 652301-1b.html 652301-1-ref.html fuzzy-if(skiaContent,2,5) == 652775-1.html 652775-1-ref.html fuzzy-if(skiaContent,1,5) == 653930-1.html 653930-1-ref.html HTTP(..) == 654057-1.html 654057-1-ref.html -fails-if(layersGPUAccelerated&&cocoaWidget&&!skiaContent) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending +fuzzy-if(skiaContent,1,4500) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending == 655549-1.html 655549-1-ref.html == 655836-1.html 655836-1-ref.html != 656875.html about:blank == 658952.html 658952-ref.html fuzzy-if(skiaContent,1,3500) == 660682-1.html 660682-1-ref.html fuzzy-if(d2d,1,256) skip-if((B2G&&browserIsRemote)||Mulet) skip-if(Android) fuzzy-if(skiaContent,1,68000) == 664127-1.xul 664127-1-ref.xul # B2G: bug 974780. Android: Intermittent failures - bug 1019131 # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) == 665597-1.html 665597-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) == 665597-2.html 665597-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop @@ -1925,17 +1925,17 @@ skip-if(!B2G) fuzzy-if(B2G,102,577) == 1 skip-if(!B2G) fuzzy-if(B2G,102,877) == 1133905-6-vh-rtl.html 1133905-ref-vh-rtl.html skip-if(B2G||Mulet) == 1150021-1.xul 1150021-1-ref.xul == 1151145-1.html 1151145-1-ref.html == 1151306-1.html 1151306-1-ref.html == 1153845-1.html 1153845-1-ref.html == 1155828-1.html 1155828-1-ref.html == 1156129-1.html 1156129-1-ref.html pref(dom.use_xbl_scopes_for_remote_xul,true) HTTP(..) == 1157127-1.html 1157127-1-ref.html -fuzzy-if(Android,1,1) == 1169331-1.html 1169331-1-ref.html +fuzzy-if(Android,2,5) == 1169331-1.html 1169331-1-ref.html fuzzy(1,74) fuzzy-if(gtkWidget,6,79) == 1174332-1.html 1174332-1-ref.html == 1179078-1.html 1179078-1-ref.html == 1179288-1.html 1179288-1-ref.html == 1190635-1.html 1190635-1-ref.html == 1202512-1.html 1202512-1-ref.html == 1202512-2.html 1202512-2-ref.html != 1207326-1.html about:blank == 1209603-1.html 1209603-1-ref.html
--- a/layout/reftests/css-break/reftest.list +++ b/layout/reftests/css-break/reftest.list @@ -1,12 +1,12 @@ default-preferences pref(layout.css.box-decoration-break.enabled,true) == box-decoration-break-1.html box-decoration-break-1-ref.html -fuzzy(1,20) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html +fuzzy(1,20) fuzzy-if(skiaContent,1,700) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html fuzzy(16,460) fuzzy-if(Android,10,3673) fuzzy-if(skiaContent,32,254) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html 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,1,5) fuzzy-if(Android,8,6627) fuzzy-if(skiaContent,1,24) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html == box-decoration-break-with-bidi.html box-decoration-break-with-bidi-ref.html == box-decoration-break-bug-1235152.html box-decoration-break-bug-1235152-ref.html == box-decoration-break-bug-1249913.html box-decoration-break-bug-1249913-ref.html
--- a/layout/reftests/css-disabled/select/reftest.list +++ b/layout/reftests/css-disabled/select/reftest.list @@ -1,9 +1,9 @@ == select-fieldset-1.html select-fieldset-ref.html -fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,17) == select-fieldset-2.html select-fieldset-ref-disabled.html # Initial mulet triage: parity with B2G/B2G Desktop -fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,17) == select-fieldset-3.html select-fieldset-ref-disabled.html # Initial mulet triage: parity with B2G/B2G Desktop -fails-if(Android) fuzzy-if(skiaContent,2,13) == select-fieldset-4.html select-fieldset-ref.html +fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,17) == select-fieldset-2.html select-fieldset-ref-disabled.html # Initial mulet triage: parity with B2G/B2G Desktop +fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,17) == select-fieldset-3.html select-fieldset-ref-disabled.html # Initial mulet triage: parity with B2G/B2G Desktop +fails-if(Android) fuzzy-if(skiaContent&&!Android,2,13) == select-fieldset-4.html select-fieldset-ref.html == select-fieldset-legend-1.html select-fieldset-legend-ref-1.html -fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,6) == select-fieldset-legend-2.html select-fieldset-legend-ref-2.html # Initial mulet triage: parity with B2G/B2G Desktop -fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,8) == select-fieldset-legend-3.html select-fieldset-legend-ref-3.html # Initial mulet triage: parity with B2G/B2G Desktop +fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,6) == select-fieldset-legend-2.html select-fieldset-legend-ref-2.html # Initial mulet triage: parity with B2G/B2G Desktop +fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,8) == select-fieldset-legend-3.html select-fieldset-legend-ref-3.html # Initial mulet triage: parity with B2G/B2G Desktop fuzzy-if(skiaContent,2,12) == select-fieldset-legend-4.html select-fieldset-legend-ref-4.html fuzzy-if(skiaContent,2,5) == select-fieldset-legend-5.html select-fieldset-legend-ref-5.html
--- a/layout/reftests/css-gradients/reftest.list +++ b/layout/reftests/css-gradients/reftest.list @@ -117,17 +117,17 @@ fuzzy-if(skiaContent,18,600) == twostops fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent&&layersGPUAccelerated,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1a.html aja-linear-1-ref.html fails-if(!d2d&&!skiaContent) == aja-linear-1b.html aja-linear-1-ref.html # bug 526694 fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1c.html aja-linear-1-ref.html fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1d.html aja-linear-1-ref.html fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1e.html aja-linear-1-ref.html fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1f.html aja-linear-1-ref.html fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1g.html aja-linear-1-ref.html fuzzy-if(!contentSameGfxBackendAsCanvas,2,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4667) == aja-linear-2a.html aja-linear-2-ref.html -fuzzy-if(!contentSameGfxBackendAsCanvas,2,20000) fuzzy-if(azureSkiaGL,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4667) == aja-linear-2b.html aja-linear-2-ref.html +fuzzy-if(!contentSameGfxBackendAsCanvas,2,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4667) == aja-linear-2b.html aja-linear-2-ref.html fails == aja-linear-2c.html aja-linear-2-ref.html # bug 522607 fails-if(!d2d&&!(skiaContent&&winWidget)) fuzzy-if(skiaContent&&!winWidget,1,200) == aja-linear-2d.html aja-linear-2-ref.html # bug 526694 fuzzy-if(!contentSameGfxBackendAsCanvas,2,19999) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz,1,10553) == aja-linear-3a.html aja-linear-3-ref.html fuzzy-if(!contentSameGfxBackendAsCanvas,2,19999) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz,1,10553) == aja-linear-3b.html aja-linear-3-ref.html fuzzy-if(!contentSameGfxBackendAsCanvas,4,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,8655) == aja-linear-4a.html aja-linear-4-ref.html fuzzy-if(!contentSameGfxBackendAsCanvas,4,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,8655) == aja-linear-4b.html aja-linear-4-ref.html fuzzy-if(!contentSameGfxBackendAsCanvas,4,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,2,7878) == aja-linear-5a.html aja-linear-5-ref.html fuzzy-if(!contentSameGfxBackendAsCanvas,2,16500) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz,2,10163) == aja-linear-6a.html aja-linear-6-ref.html # bug 526708
--- a/layout/reftests/css-invalid/select/reftest.list +++ b/layout/reftests/css-invalid/select/reftest.list @@ -2,11 +2,11 @@ needs-focus == select-valid.html select- fuzzy-if(skiaContent,1,3) needs-focus == select-invalid.html select-ref.html fuzzy-if(skiaContent,2,6) needs-focus == select-disabled.html select-disabled-ref.html skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,6) needs-focus == select-dyn-disabled.html select-disabled-ref.html # Initial mulet triage: parity with B2G/B2G Desktop fuzzy-if(skiaContent,1,3) needs-focus == select-dyn-not-disabled.html select-ref.html needs-focus == select-required-invalid.html select-required-ref.html needs-focus == select-required-valid.html select-required-ref.html needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html fuzzy-if(skiaContent,1,250) needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html -skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,1,3) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,2,3) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,1,3) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,2,3) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop fuzzy-if(skiaContent,2,5) needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html
--- a/layout/reftests/css-ui-invalid/select/reftest.list +++ b/layout/reftests/css-ui-invalid/select/reftest.list @@ -7,12 +7,12 @@ fuzzy-if(skiaContent,1,3) needs-focus == fuzzy-if(skiaContent,2,5) needs-focus == select-required-invalid-1.html select-required-ref.html fuzzy-if(skiaContent,2,5) needs-focus == select-required-invalid-2.html select-required-ref.html fuzzy-if(skiaContent,2,5) needs-focus == select-required-invalid-changed-1.html select-required-ref.html fuzzy-if(skiaContent,2,5) needs-focus == select-required-invalid-changed-2.html select-required-ref.html fuzzy-if(skiaContent,2,5) needs-focus == select-required-valid.html select-required-ref.html needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html fuzzy-if(asyncPan&&!layersGPUAccelerated,84,77) fuzzy-if(skiaContent,1,1000) needs-focus == select-required-multiple-invalid-changed.html select-required-multiple-ref.html needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html -skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,2,10) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,2,10) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,2,10) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,2,10) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop fuzzy-if(skiaContent,2,10) needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html fuzzy-if(skiaContent,1,5) needs-focus == select-novalidate.html select-required-ref.html
--- a/layout/reftests/css-ui-valid/select/reftest.list +++ b/layout/reftests/css-ui-valid/select/reftest.list @@ -8,11 +8,11 @@ fuzzy-if(skiaContent,2,5) needs-focus == fuzzy-if(skiaContent,2,5) needs-focus == select-required-valid-1.html select-required-ref.html fuzzy-if(skiaContent,2,5) needs-focus == select-required-valid-2.html select-required-ref.html fuzzy-if(skiaContent,2,5) needs-focus == select-required-valid-changed-1.html select-required-ref.html fuzzy-if(skiaContent,2,5) needs-focus == select-required-valid-changed-2.html select-required-ref.html needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html fuzzy(64,4) fuzzy-if(asyncPan&&layersGPUAccelerated,84,77) fuzzy-if(skiaContent,1,1000) needs-focus == select-required-multiple-valid-changed.html select-required-multiple-ref.html fails-if(Android||B2G||Mulet) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,10) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,10) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop fuzzy-if(skiaContent,2,10) needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html fuzzy-if(skiaContent,2,5) needs-focus == select-novalidate.html select-required-ref.html
--- a/layout/reftests/css-valid/select/reftest.list +++ b/layout/reftests/css-valid/select/reftest.list @@ -3,10 +3,10 @@ fuzzy-if(skiaContent,2,5) needs-focus == needs-focus == select-disabled.html select-disabled-ref.html fuzzy-if(skiaContent,1,5) needs-focus == select-dyn-disabled.html select-disabled-ref.html fuzzy-if(skiaContent,2,5) needs-focus == select-dyn-not-disabled.html select-ref.html needs-focus == select-required-invalid.html select-required-ref.html needs-focus == select-required-valid.html select-required-ref.html needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html fuzzy-if(skiaContent,1,250) needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html fails-if(Android||B2G||Mulet) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,1,3) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html
--- a/layout/reftests/font-inflation/reftest.list +++ b/layout/reftests/font-inflation/reftest.list @@ -44,17 +44,17 @@ skip-if(B2G||Mulet) test-pref(font.size. skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-1a.html intrinsic-fit-1a-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-1b.html intrinsic-fit-1b-ref.html # Initial mulet triage: parity with B2G/B2G Desktop test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-1c.html intrinsic-fit-1c-ref.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-2a.html intrinsic-fit-1a-ref.html skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-2b.html intrinsic-fit-1b-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-2c.html intrinsic-fit-1c-ref.html # Initial mulet triage: parity with B2G/B2G Desktop test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-listbox-1.html select-listbox-1-ref.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != select-listbox-1.html select-listbox-1.html -test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-1.html select-combobox-1-ref.html +fuzzy-if(skiaContent,4,2) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-1.html select-combobox-1-ref.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != select-combobox-1.html select-combobox-1.html skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-listbox-2.html select-listbox-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != select-listbox-2.html select-listbox-2.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-2.html select-combobox-2-ref.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != select-combobox-2.html select-combobox-2.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-3.html select-combobox-3-ref.html asserts-if(gtkWidget,0-4) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != input-checkbox.html input-checkbox.html asserts-if(gtkWidget,0-4) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != input-radio.html input-radio.html
--- a/layout/reftests/forms/select/reftest.list +++ b/layout/reftests/forms/select/reftest.list @@ -1,9 +1,9 @@ -fuzzy-if(Android,2,2) skip-if(B2G||Mulet) == out-of-bounds-selectedindex.html out-of-bounds-selectedindex-ref.html # test for bug 471741 # Initial mulet triage: parity with B2G/B2G Desktop +fuzzy-if(Android,4,11) skip-if(B2G||Mulet) == out-of-bounds-selectedindex.html out-of-bounds-selectedindex-ref.html # test for bug 471741 # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) == multiple.html multiple-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == boguskids.html boguskids-ref.html == dynamic-boguskids.html boguskids-ref.html == option-children.html option-children-ref.html fuzzy(1,4) == padding-button-placement.html padding-button-placement-ref.html HTTP(../..) == vertical-centering.html vertical-centering-ref.html == 997709-2.html 997709-2-ref.html needs-focus == focusring-1.html focusring-1-ref.html
--- a/layout/reftests/forms/textarea/reftest.list +++ b/layout/reftests/forms/textarea/reftest.list @@ -1,11 +1,11 @@ skip-if(B2G||Mulet||Android) == resize.html resize-ref.html # Initial mulet triage: parity with B2G/B2G Desktop # an offset seems to apply to the native resizer on windows so skip this test for now -skip-if(B2G||Mulet||Android) skip-if(winWidget) fuzzy-if(cocoaWidget,1,33) fuzzy-if(skiaContent&&!winWidget,5,10) == resize-background.html resize-background-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet||Android) skip-if(winWidget) fuzzy-if(cocoaWidget,1,33) fuzzy-if(skiaContent&&!winWidget&&!Android,5,10) == resize-background.html resize-background-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet||Android) != ltr.html rtl.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet||Android) != ltr-scrollbar.html rtl-scrollbar.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet||Android) != in-ltr-doc-scrollbar.html in-rtl-doc-scrollbar.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet||Android) != ltr.html no-resize.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet||Android) fails-if(xulRuntime.widgetToolkit=="gtk2") != rtl.html no-resize.html # bug 834724 # Initial mulet triage: parity with B2G/B2G Desktop == rtl.html rtl-dynamic-attr.html == rtl.html rtl-dynamic-style.html == rtl.html in-dynamic-rtl-doc.html
--- a/layout/reftests/image-element/reftest.list +++ b/layout/reftests/image-element/reftest.list @@ -10,17 +10,17 @@ skip-if(B2G||Mulet) fails-if(azureSkia) == element-paint-simple.html element-paint-simple-ref.html == element-paint-repeated.html element-paint-repeated-ref.html == element-paint-recursion.html element-paint-recursion-ref.html skip-if(B2G||Mulet) HTTP(..) == element-paint-continuation.html element-paint-continuation-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == element-paint-transform-01.html element-paint-transform-01-ref.html random-if(d2d) == element-paint-transform-02.html element-paint-transform-02-ref.html # bug 587133 fuzzy-if(d2d&&/^Windows\x20NT\x206\.1/.test(http.oscpu),16,90) == element-paint-background-size-01.html element-paint-background-size-01-ref.html == element-paint-background-size-02.html element-paint-background-size-02-ref.html -== element-paint-transform-repeated.html element-paint-transform-repeated-ref.html +fuzzy-if(skiaContent,255,4) == element-paint-transform-repeated.html element-paint-transform-repeated-ref.html fuzzy-if(d2d,255,24) == element-paint-transform-03.html element-paint-transform-03-ref.html fuzzy-if(asyncPan,2,140) fuzzy-if(skiaContent,2,106) == element-paint-native-widget.html element-paint-native-widget-ref.html # in -ref the scrollframe is active and layerized differently with APZ fails-if(usesRepeatResampling) == element-paint-subimage-sampling-restriction.html about:blank == element-paint-clippath.html element-paint-clippath-ref.html == element-paint-sharpness-01a.html element-paint-sharpness-01b.html fuzzy-if(skiaContent,1,326) == element-paint-sharpness-01b.html element-paint-sharpness-01c.html == element-paint-sharpness-01c.html element-paint-sharpness-01d.html == element-paint-sharpness-02a.html element-paint-sharpness-02b.html
--- a/layout/reftests/svg/smil/transform/reftest.list +++ b/layout/reftests/svg/smil/transform/reftest.list @@ -4,15 +4,15 @@ fuzzy(111,1802) fuzzy-if(skiaContent,130,1000) == additive-1.svg additive-1-ref.svg # bug 981344, bug 1239766 == animate-width-1.svg lime.svg fuzzy-if(cocoaWidget,1,32) fuzzy-if(winWidget,15,4) == paced-1.svg paced-1-ref.svg # bug 981640 fuzzy-if(skiaContent,1,220) == rotate-angle-1.svg rotate-angle-ref.svg == rotate-angle-2.svg rotate-angle-ref.svg fuzzy-if(skiaContent,1,130) == rotate-angle-3.svg rotate-angle-ref.svg fuzzy-if(skiaContent,1,110) == rotate-angle-4.svg rotate-angle-ref.svg fuzzy-if(skiaContent,1,130) == rotate-angle-5.svg rotate-angle-ref.svg -fuzzy(12,27) fuzzy-if(skiaContent,1,180) == scale-1.svg scale-1-ref.svg # bug 981004 +fuzzy(12,27) fuzzy-if(skiaContent,1,180) fuzzy-if(Android,16,3) == scale-1.svg scale-1-ref.svg # bug 981004 == set-transform-1.svg lime.svg -fuzzy-if(winWidget,1,3) == skew-1.svg skew-1-ref.svg # bug 983671 +fuzzy-if(winWidget,1,3) fuzzy-if(skiaContent,1,20) == skew-1.svg skew-1-ref.svg # bug 983671 == translate-clipPath-1.svg lime.svg fails-if(OSX==1006&&!skiaContent) == translate-gradient-1.svg lime.svg == translate-pattern-1.svg lime.svg == use-1.svg lime.svg
--- a/layout/reftests/table-background/reftest.list +++ b/layout/reftests/table-background/reftest.list @@ -53,10 +53,10 @@ fuzzy-if(d2d,1,37170) fuzzy-if(skiaConte skip-if(B2G||Mulet) fuzzy-if(d2d,1,12390) fuzzy-if(skiaContent,1,13000) == border-separate-opacity-table-row.html border-separate-opacity-table-row-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) fuzzy-if(d2d||skiaContent,1,95000) == border-separate-opacity-table.html border-separate-opacity-table-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop != scrollable-rowgroup-collapse-background.html scrollable-rowgroup-collapse-notref.html != scrollable-rowgroup-collapse-border.html scrollable-rowgroup-collapse-notref.html != scrollable-rowgroup-separate-background.html scrollable-rowgroup-separate-notref.html == scrollable-rowgroup-separate-border.html scrollable-rowgroup-separate-notref.html # scrolling rowgroups were removed in bug 28800 == empty-cells-default-1.html empty-cells-default-1-ref.html == empty-cells-default-2.html empty-cells-default-2-ref.html -fuzzy-if(OSX,1,113) fuzzy-if(winWidget,1,12) fuzzy-if(Android,1,39) fuzzy-if(winWidget&&!layersGPUAccelerated,82,116) fuzzy-if(skiaContent,77,5400) == table-row-opacity-dynamic-1.html table-row-opacity-dynamic-1-ref.html +fuzzy-if(OSX,1,113) fuzzy-if(winWidget,1,12) fuzzy-if(Android,1,39) fuzzy-if(winWidget&&!layersGPUAccelerated,82,116) fuzzy-if(skiaContent,77,5500) == table-row-opacity-dynamic-1.html table-row-opacity-dynamic-1-ref.html == table-row-opacity-dynamic-2.html table-row-opacity-dynamic-2-ref.html
--- a/layout/reftests/text-decoration/reftest.list +++ b/layout/reftests/text-decoration/reftest.list @@ -100,13 +100,13 @@ fuzzy-if(cocoaWidget,1,5) == decoration- == decoration-color-override-standards.html decoration-color-override-standards-ref.html != decoration-color-override-standards-ref.html decoration-color-override-quirks-ref.html == decoration-css21-block.html decoration-css21-block-ref.html != inline-baseline-almost-standards.html inline-baseline-almost-standards-ref.html != inline-baseline-quirks.html inline-baseline-quirks-ref.html == 676538-1.html 676538-1-ref.html fuzzy-if(OSX==1010,1,4) == underline-button-1.html underline-button-1-ref.html fuzzy-if(OSX==1010,1,2) == underline-button-2.html underline-button-2-ref.html -== underline-select-1.html underline-select-1-ref.html +fuzzy-if(skiaContent,4,2) == underline-select-1.html underline-select-1-ref.html == underline-select-2.html underline-select-2-ref.html == 1133392.html 1133392-ref.html != 1159729-offset-adjustment.html 1159729-offset-adjustment-notref.html == emphasis-style-dynamic.html emphasis-style-dynamic-ref.html
--- a/layout/reftests/text-shadow/reftest.list +++ b/layout/reftests/text-shadow/reftest.list @@ -21,19 +21,19 @@ HTTP(..) == blur-opacity.html blur-opaci == textindent.html textindent-ref.html == lineoverflow.html lineoverflow-ref.html == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html == overflow-not-scrollable-2.html overflow-not-scrollable-2-ref.html needs-focus != text-shadow-selected-1.html text-shadow-selected-1-notref.html -fails-if(Android||B2G) fuzzy-if(skiaContent,1,1000) needs-focus == text-shadow-selected-1.html text-shadow-selected-1-ref.html # different foreground selection color on Android/B2G +fails-if(Android||B2G) fuzzy-if(skiaContent&&!Android,1,1000) needs-focus == text-shadow-selected-1.html text-shadow-selected-1-ref.html # different foreground selection color on Android/B2G needs-focus != text-shadow-selected-2.html text-shadow-selected-2-notref.html -fails-if(Android||B2G) fuzzy-if(skiaContent,1,1400) needs-focus == text-shadow-selected-2.html text-shadow-selected-2-ref.html # different foreground selection color on Android/B2G +fails-if(Android||B2G) fuzzy-if(skiaContent&&!Android,1,1400) needs-focus == text-shadow-selected-2.html text-shadow-selected-2-ref.html # different foreground selection color on Android/B2G # bug 692744 == text-shadow-on-space-1.html text-shadow-on-space-1-ref.html # bug 721750 needs-focus == text-shadow-on-selection-1.html text-shadow-on-selection-1-ref.html needs-focus == text-shadow-on-selection-2.html text-shadow-on-selection-2-ref.html
--- a/layout/reftests/text/reftest.list +++ b/layout/reftests/text/reftest.list @@ -147,17 +147,17 @@ random-if(cocoaWidget) HTTP(..) == zwnj- HTTP(..) == zwnj-02.xhtml zwnj-02-ref.xhtml # HTTP(..) for ../filters.svg != zwnj-01.html zwnj-01-notref.html == initial-zwj-1.html initial-zwj-1-ref.html == cgj-01.html cgj-01-ref.html == 444656.html 444656-ref.html == 449555-1.html 449555-1-ref.html == 467722.html 467722-ref.html skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,600) HTTP(..) == 475092-sub.html 475092-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -fails-if(!winWidget&&!gtkWidget) skip-if(B2G||Mulet) fuzzy-if(skiaContent,89,3100) HTTP(..) == 475092-pos.html 475092-sub.html # bug 482596 # Initial mulet triage: parity with B2G/B2G Desktop +fails-if(Android) skip-if(B2G||Mulet) fuzzy-if(skiaContent&&!Android,89,3100) HTTP(..) == 475092-pos.html 475092-sub.html # bug 482596 # Initial mulet triage: parity with B2G/B2G Desktop == 476378-soft-hyphen-fallback.html 476378-soft-hyphen-fallback-ref.html # Test for bug 484954 == rgba-text.html rgba-text-ref.html # Test for bug 575695, 'kern' table support HTTP(..) != kerning-01.html kerning-01-notref.html # Test for bug 577380, support for AAT layout (on OS X only) random-if(!cocoaWidget) == 577380.html 577380-ref.html # Test for OpenType Arabic shaping support
--- a/layout/reftests/writing-mode/reftest.list +++ b/layout/reftests/writing-mode/reftest.list @@ -64,17 +64,17 @@ fuzzy(116,94) fuzzy-if(skiaContent&&dwri == ua-style-sheet-size-1.html ua-style-sheet-size-1-ref.html == ua-style-sheet-size-2.html ua-style-sheet-size-2-ref.html == ua-style-sheet-fieldset-1.html ua-style-sheet-fieldset-1-ref.html skip-if(Android||B2G||Mulet||(winWidget&&!/^Windows\x20NT\x205\.1/.test(http.oscpu))) == ua-style-sheet-textarea-1.html ua-style-sheet-textarea-1a-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(!(Android||B2G||Mulet)) == ua-style-sheet-textarea-1.html ua-style-sheet-textarea-1b-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(!winWidget||/^Windows\x20NT\x205\.1/.test(http.oscpu)) == ua-style-sheet-textarea-1.html ua-style-sheet-textarea-1c-ref.html == ua-style-sheet-checkbox-radio-1.html ua-style-sheet-checkbox-radio-1-ref.html -skip-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,6) == ua-style-sheet-button-1.html ua-style-sheet-button-1a-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,6) == ua-style-sheet-button-1.html ua-style-sheet-button-1a-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(!(Android||B2G||Mulet)) == ua-style-sheet-button-1.html ua-style-sheet-button-1b-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == ua-style-sheet-input-color-1.html ua-style-sheet-input-color-1-ref.html fuzzy-if(gtkWidget,1,15) == ua-style-sheet-input-number-1.html ua-style-sheet-input-number-1-ref.html HTTP(..) == 1127488-align-default-horizontal-tb-ltr.html 1127488-align-top-left-ref.html HTTP(..) == 1127488-align-start-horizontal-tb-ltr.html 1127488-align-top-left-ref.html HTTP(..) == 1127488-align-end-horizontal-tb-ltr.html 1127488-align-top-right-ref.html HTTP(..) == 1127488-align-left-horizontal-tb-ltr.html 1127488-align-top-left-ref.html
--- a/layout/reftests/writing-mode/tables/reftest.list +++ b/layout/reftests/writing-mode/tables/reftest.list @@ -71,18 +71,18 @@ fuzzy-if(winWidget,48,600) fuzzy-if(coco fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-003.xht multicol-count-002-ref.xht fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-004.xht multicol-count-002-ref.xht fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-005.xht multicol-count-002-ref.xht fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-006.xht multicol-count-002-ref.xht fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-007.xht multicol-count-002-ref.xht fuzzy-if(Android,255,38) == table-caption-top-1.html table-caption-top-1-ref.html fuzzy-if(Android,255,38) == table-caption-bottom-1.html table-caption-bottom-1-ref.html -== table-caption-left-1.html table-caption-left-1-ref.html -== table-caption-right-1.html table-caption-right-1-ref.html +fuzzy-if(Android,244,27) == table-caption-left-1.html table-caption-left-1-ref.html +fuzzy-if(Android,244,27) == table-caption-right-1.html table-caption-right-1-ref.html == border-collapse-bevels-1a.html border-collapse-bevels-1-ref.html fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1b.html border-collapse-bevels-1-ref.html fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1c.html border-collapse-bevels-1-ref.html fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1d.html border-collapse-bevels-1-ref.html fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1e.html border-collapse-bevels-1-ref.html == vertical-rl-row-progression-1a.html vertical-rl-row-progression-1-ref.html
--- a/layout/style/ServoStyleSet.cpp +++ b/layout/style/ServoStyleSet.cpp @@ -17,17 +17,16 @@ using namespace mozilla; using namespace mozilla::dom; ServoStyleSet::ServoStyleSet() : mPresContext(nullptr) , mRawSet(Servo_StyleSet_Init()) , mBatching(0) - , mStylingStarted(false) { } void ServoStyleSet::Init(nsPresContext* aPresContext) { mPresContext = aPresContext; } @@ -68,34 +67,16 @@ ServoStyleSet::EndUpdate() if (--mBatching > 0) { return NS_OK; } // ... do something ... return NS_OK; } -void -ServoStyleSet::StartStyling(nsPresContext* aPresContext) -{ - MOZ_ASSERT(!mStylingStarted); - - // Some things, like nsDocumentViewer::GetPageMode, recreate the presShell, - // while keeping the content tree alive. See bug 1292280. - // - // That's why we need to force a restyle. - nsIContent* root = mPresContext->Document()->GetRootElement(); - if (root) { - root->SetIsDirtyForServo(); - } - - StyleDocument(/* aLeaveDirtyBits = */ false); - mStylingStarted = true; -} - already_AddRefed<nsStyleContext> ServoStyleSet::ResolveStyleFor(Element* aElement, nsStyleContext* aParentContext) { return GetContext(aElement, aParentContext, nullptr, CSSPseudoElementType::NotPseudo); } @@ -479,31 +460,26 @@ ClearDirtyBits(nsIContent* aContent) for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) { ClearDirtyBits(n); } } void ServoStyleSet::StyleDocument(bool aLeaveDirtyBits) { - // Unconditionally clear the flag on the document so that HasPendingRestyles - // returns false. + // Grab the root. nsIDocument* doc = mPresContext->Document(); - doc->UnsetHasDirtyDescendantsForServo(); - - // Grab the root. - nsIContent* root = mPresContext->Document()->GetRootElement(); - if (!root) { - return; - } + nsIContent* root = doc->GetRootElement(); + MOZ_ASSERT(root); // Restyle the document, clearing the dirty bits if requested. Servo_RestyleSubtree(root, mRawSet.get()); if (!aLeaveDirtyBits) { ClearDirtyBits(root); + doc->UnsetHasDirtyDescendantsForServo(); } } void ServoStyleSet::StyleNewSubtree(nsIContent* aContent) { MOZ_ASSERT(aContent->IsDirtyForServo()); Servo_RestyleSubtree(aContent, mRawSet.get());
--- a/layout/style/ServoStyleSet.h +++ b/layout/style/ServoStyleSet.h @@ -50,18 +50,16 @@ public: void Shutdown(); bool GetAuthorStyleDisabled() const; nsresult SetAuthorStyleDisabled(bool aStyleDisabled); void BeginUpdate(); nsresult EndUpdate(); - void StartStyling(nsPresContext* aPresContext); - already_AddRefed<nsStyleContext> ResolveStyleFor(dom::Element* aElement, nsStyleContext* aParentContext); already_AddRefed<nsStyleContext> ResolveStyleFor(dom::Element* aElement, nsStyleContext* aParentContext, TreeMatchContext& aTreeMatchContext); @@ -123,17 +121,17 @@ public: /** * Computes a restyle hint given a element and a previous element snapshot. */ nsRestyleHint ComputeRestyleHint(dom::Element* aElement, ServoElementSnapshot* aSnapshot); /** * Performs a Servo traversal to compute style for all dirty nodes in the - * document. + * document. The root element must be non-null. * * If aLeaveDirtyBits is true, the dirty/dirty-descendant bits are not * cleared. */ void StyleDocument(bool aLeaveDirtyBits); /** * Eagerly styles a subtree of dirty nodes that were just appended to the @@ -150,32 +148,29 @@ public: * Like the above, but does not assume that the root node is dirty. When * appending multiple children to a potentially-non-dirty node, it's * preferable to call StyleNewChildren on the node rather than making multiple * calls to StyleNewSubtree on each child, since it allows for more * parallelism. */ void StyleNewChildren(nsIContent* aParent); - bool StylingStarted() const { return mStylingStarted; } - private: already_AddRefed<nsStyleContext> GetContext(already_AddRefed<ServoComputedValues>, nsStyleContext* aParentContext, nsIAtom* aPseudoTag, CSSPseudoElementType aPseudoType); already_AddRefed<nsStyleContext> GetContext(nsIContent* aContent, nsStyleContext* aParentContext, nsIAtom* aPseudoTag, CSSPseudoElementType aPseudoType); nsPresContext* mPresContext; UniquePtr<RawServoStyleSet> mRawSet; EnumeratedArray<SheetType, SheetType::Count, nsTArray<RefPtr<ServoStyleSheet>>> mSheets; int32_t mBatching; - bool mStylingStarted; }; } // namespace mozilla #endif // mozilla_ServoStyleSet_h
--- a/layout/svg/SVGTextFrame.cpp +++ b/layout/svg/SVGTextFrame.cpp @@ -5624,20 +5624,19 @@ SVGTextFrame::TransformFrameRectFromText AppUnitsToFloatCSSPixels(gfxRect(rectInTextFrame.x, rectInTextFrame.y, rectInTextFrame.width, rectInTextFrame.height), presContext); // Intersect it with the run. uint32_t flags = TextRenderedRun::eIncludeFill | TextRenderedRun::eIncludeStroke; - rectInFrameUserSpace.IntersectRect - (rectInFrameUserSpace, run.GetFrameUserSpaceRect(presContext, flags).ToThebesRect()); - - if (!rectInFrameUserSpace.IsEmpty()) { + + if (rectInFrameUserSpace.IntersectRect(rectInFrameUserSpace, + run.GetFrameUserSpaceRect(presContext, flags).ToThebesRect())) { // Transform it up to user space of the <text>, also taking into // account the font size scale. gfxMatrix m = run.GetTransformFromRunUserSpaceToUserSpace(presContext); m.Scale(mFontSizeScaleFactor, mFontSizeScaleFactor); gfxRect rectInUserSpace = m.Transform(rectInFrameUserSpace); // Union it into the result. result.UnionRect(result, rectInUserSpace);
--- a/layout/xul/test/test_bug381167.xhtml +++ b/layout/xul/test/test_bug381167.xhtml @@ -22,17 +22,17 @@ https://bugzilla.mozilla.org/show_bug.cg <pre id="test"> <script type="application/javascript"> /** Test for Bug 381167 **/ SimpleTest.waitForExplicitFinish(); function closeit() { - var evt = document.createEvent('KeyEvents'); + var evt = document.createEvent('KeyboardEvent'); evt.initKeyEvent('keypress', true, true, window, true, false, false, false, 'W'.charCodeAt(0), 0); window.dispatchEvent(evt); setTimeout(finish, 200); }
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java @@ -2678,17 +2678,18 @@ public class BrowserApp extends GeckoApp if (mFirstrunAnimationContainer == null) { final ViewStub firstrunPagerStub = (ViewStub) findViewById(R.id.firstrun_pager_stub); mFirstrunAnimationContainer = (FirstrunAnimationContainer) firstrunPagerStub.inflate(); mFirstrunAnimationContainer.load(getApplicationContext(), getSupportFragmentManager()); mFirstrunAnimationContainer.registerOnFinishListener(new FirstrunAnimationContainer.OnFinishListener() { @Override public void onFinish() { - if (mFirstrunAnimationContainer.showBrowserHint()) { + if (mFirstrunAnimationContainer.showBrowserHint() && + TextUtils.isEmpty(getHomepage())) { enterEditingMode(); } } }); } mHomeScreenContainer.setVisibility(View.VISIBLE); }
--- a/mobile/android/base/java/org/mozilla/gecko/distribution/Distribution.java +++ b/mobile/android/base/java/org/mozilla/gecko/distribution/Distribution.java @@ -218,17 +218,24 @@ public class Distribution { private static Distribution init(final Distribution distribution) { // Read/write preferences and files on the background thread. ThreadUtils.postToBackgroundThread(new Runnable() { @Override public void run() { boolean distributionSet = distribution.doInit(); if (distributionSet) { - GeckoAppShell.notifyObservers("Distribution:Set", ""); + String preferencesJSON = ""; + try { + final File descFile = distribution.getDistributionFile("preferences.json"); + preferencesJSON = FileUtils.readStringFromFile(descFile); + } catch (IOException e) { + Log.e(LOGTAG, "Error getting distribution descriptor file.", e); + } + GeckoAppShell.notifyObservers("Distribution:Set", preferencesJSON); } } }); return distribution; } /**
--- a/mobile/android/chrome/content/PermissionsHelper.js +++ b/mobile/android/chrome/content/PermissionsHelper.js @@ -1,27 +1,33 @@ /* 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"; var PermissionsHelper = { _permissonTypes: ["password", "geolocation", "popup", "indexedDB", - "offline-app", "desktop-notification", "plugins", "native-intent"], + "offline-app", "desktop-notification", "plugins", "native-intent", + "flyweb-publish-server"], _permissionStrings: { "password": { label: "password.logins", allowed: "password.save", denied: "password.dontSave" }, "geolocation": { label: "geolocation.location", allowed: "geolocation.allow", denied: "geolocation.dontAllow" }, + "flyweb-publish-server": { + label: "flyWebPublishServer.publishServer", + allowed: "flyWebPublishServer.allow", + denied: "flyWebPublishServer.dontAllow" + }, "popup": { label: "blockPopups.label2", allowed: "popup.show", denied: "popup.dontShow" }, "indexedDB": { label: "offlineApps.offlineData", allowed: "offlineApps.allow",
--- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -6783,16 +6783,18 @@ var ExternalApps = { delete this._pageActionId; }, }; var Distribution = { // File used to store campaign data _file: null, + _preferencesJSON: null, + init: function dc_init() { Services.obs.addObserver(this, "Distribution:Changed", false); Services.obs.addObserver(this, "Distribution:Set", false); Services.obs.addObserver(this, "prefservice:after-app-defaults", false); Services.obs.addObserver(this, "Campaign:Set", false); // Look for file outside the APK: // /data/data/org.mozilla.xxx/distribution.json @@ -6808,16 +6810,23 @@ var Distribution = { try { Services.search._asyncReInit(); } catch (e) { console.log("Unable to reinit search service."); } // Fall through. case "Distribution:Set": + if (aData) { + try { + this._preferencesJSON = JSON.parse(aData); + } catch (e) { + console.log("Invalid distribution JSON."); + } + } // Reload the default prefs so we can observe "prefservice:after-app-defaults" Services.prefs.QueryInterface(Ci.nsIObserver).observe(null, "reload-default-prefs", null); this.installDistroAddons(); break; case "prefservice:after-app-defaults": this.getPrefs(); break; @@ -6842,16 +6851,22 @@ var Distribution = { update: function dc_update(aData) { // Force the distribution preferences on the default branch let defaults = Services.prefs.getDefaultBranch(null); defaults.setCharPref("distribution.id", aData.id); defaults.setCharPref("distribution.version", aData.version); }, getPrefs: function dc_getPrefs() { + if (this._preferencesJSON) { + this.applyPrefs(this._preferencesJSON); + this._preferencesJSON = null; + return; + } + // Get the distribution directory, and bail if it doesn't exist. let file = FileUtils.getDir("XREAppDist", [], false); if (!file.exists()) return; file.append("preferences.json"); this.readJSON(file, this.applyPrefs); },
--- a/mobile/android/components/ContentPermissionPrompt.js +++ b/mobile/android/components/ContentPermissionPrompt.js @@ -13,22 +13,24 @@ Cu.import("resource://gre/modules/Servic const kEntities = { "contacts": "contacts", "desktop-notification": "desktopNotification2", "device-storage:music": "deviceStorageMusic", "device-storage:pictures": "deviceStoragePictures", "device-storage:sdcard": "deviceStorageSdcard", "device-storage:videos": "deviceStorageVideos", "geolocation": "geolocation", + "flyweb-publish-server": "flyWebPublishServer", }; // For these types, prompt for permission if action is unknown. const PROMPT_FOR_UNKNOWN = [ "desktop-notification", "geolocation", + "flyweb-publish-server", ]; function ContentPermissionPrompt() {} ContentPermissionPrompt.prototype = { classID: Components.ID("{C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}"), QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
--- a/mobile/android/locales/en-US/chrome/browser.properties +++ b/mobile/android/locales/en-US/chrome/browser.properties @@ -126,16 +126,28 @@ geolocation.dontAskAgain=Don't ask again # Desktop notification UI desktopNotification2.allow=Always desktopNotification2.dontAllow=Never desktopNotification2.ask=Would you like to receive notifications from this site? # LOCALIZATION NOTE (desktopNotification.notifications): Label that will be # used in site settings dialog. desktopNotification.notifications=Notifications +# FlyWeb UI +# LOCALIZATION NOTE (flyWebPublishServer.allow): This is an experimental feature only shipping in Nightly, and doesn't need translation. +flyWebPublishServer.allow=Allow +# LOCALIZATION NOTE (flyWebPublishServer.dontAllow): This is an experimental feature only shipping in Nightly, and doesn't need translation. +flyWebPublishServer.dontAllow=Deny +# LOCALIZATION NOTE (flyWebPublishServer.ask): This is an experimental feature only shipping in Nightly, and doesn't need translation. +flyWebPublishServer.ask=Would you like to let this site start a server accessible to nearby devices and people? +# LOCALIZATION NOTE (flyWebPublishServer.dontAskAgain): This is an experimental feature only shipping in Nightly, and doesn't need translation. +flyWebPublishServer.dontAskAgain=Don't ask again for this site +# LOCALIZATION NOTE (flyWebPublishServer.publishServer): This is an experimental feature only shipping in Nightly, and doesn't need translation. +flyWebPublishServer.publishServer=Publish Server + # Imageblocking imageblocking.downloadedImage=Image unblocked imageblocking.showAllImages=Show All # Device Storage API deviceStorageMusic.allow=Allow deviceStorageMusic.dontAllow=Don't allow deviceStorageMusic.ask=Allow %S access to your music?
--- a/netwerk/base/nsSocketTransportService2.cpp +++ b/netwerk/base/nsSocketTransportService2.cpp @@ -1398,17 +1398,17 @@ nsSocketTransportService::ProbeMaxCount( else gMaxCount = index; break; } ++numAllocated; } // Test - PR_STATIC_ASSERT(SOCKET_LIMIT_MIN >= 32U); + static_assert(SOCKET_LIMIT_MIN >= 32U, "Minimum Socket Limit is >= 32"); while (gMaxCount <= numAllocated) { int32_t rv = PR_Poll(pfd, gMaxCount, PR_MillisecondsToInterval(0)); SOCKET_LOG(("Socket Limit Test poll() size=%d rv=%d\n", gMaxCount, rv)); if (rv >= 0) break; @@ -1467,17 +1467,17 @@ nsSocketTransportService::DiscoverMaxCou setrlimit(RLIMIT_NOFILE, &rlimitData); if ((getrlimit(RLIMIT_NOFILE, &rlimitData) != -1) && (rlimitData.rlim_cur > SOCKET_LIMIT_MIN)) { gMaxCount = rlimitData.rlim_cur; } #elif defined(XP_WIN) && !defined(WIN_CE) // >= XP is confirmed to have at least 1000 - PR_STATIC_ASSERT(SOCKET_LIMIT_TARGET <= 1000); + static_assert(SOCKET_LIMIT_TARGET <= 1000, "SOCKET_LIMIT_TARGET max value is 1000"); gMaxCount = SOCKET_LIMIT_TARGET; #else // other platforms are harder to test - so leave at safe legacy value #endif return PR_SUCCESS; }
--- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -852,20 +852,17 @@ HttpChannelChild::MaybeDivertOnStop(cons void HttpChannelChild::OnStopRequest(const nsresult& channelStatus, const ResourceTimingStruct& timing) { LOG(("HttpChannelChild::OnStopRequest [this=%p status=%x]\n", this, channelStatus)); - if (mUploadStream) { - mUploadStream->Close(); - mUploadStream = nullptr; - } + mUploadStream = nullptr; if (mDivertingToParent) { MOZ_RELEASE_ASSERT(!mFlushedForDiversion, "Should not be processing any more callbacks from parent!"); SendDivertOnStopRequest(channelStatus); return; }
--- a/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js +++ b/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js @@ -213,17 +213,17 @@ MozMillElement.prototype.dragToElement = try { srcWindow.addEventListener("dragstart", trapDrag, true); EventUtils.synthesizeMouse(srcNode, srcCoords.x, srcCoords.y, { type: "mousedown" }, srcWindow); EventUtils.synthesizeMouse(destNode, destCoords.x, destCoords.y, { type: "mousemove" }, destWindow); - var event = destWindow.document.createEvent("DragEvents"); + var event = destWindow.document.createEvent("DragEvent"); event.initDragEvent("dragenter", true, true, destWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); event.initDragEvent("dragover", true, true, destWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); event.initDragEvent("drop", true, true, destWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); windowUtils.dispatchDOMEventViaPresShell(destNode, event, true);
--- a/testing/marionette/listener.js +++ b/testing/marionette/listener.js @@ -592,17 +592,17 @@ function emitTouchEvent(type, touch) { if (!wasInterrupted()) { let loggingInfo = "emitting Touch event of type " + type + " to element with id: " + touch.target.id + " and tag name: " + touch.target.tagName + " at coordinates (" + touch.clientX + ", " + touch.clientY + ") relative to the viewport"; dumpLog(loggingInfo); var docShell = curContainer.frame.document.defaultView. QueryInterface(Components.interfaces.nsIInterfaceRequestor). getInterface(Components.interfaces.nsIWebNavigation). QueryInterface(Components.interfaces.nsIDocShell); if (docShell.asyncPanZoomEnabled && actions.scrolling) { - // if we're in APZ and we're scrolling, we must use injectTouchEvent to dispatch our touchmove events + // if we're in APZ and we're scrolling, we must use sendNativeTouchPoint to dispatch our touchmove events let index = sendSyncMessage("MarionetteFrame:getCurrentFrameId"); // only call emitTouchEventForIFrame if we're inside an iframe. if (index != null) { sendSyncMessage("Marionette:emitTouchEvent", { index: index, type: type, id: touch.identifier, clientX: touch.clientX, clientY: touch.clientY, screenX: touch.screenX, screenY: touch.screenY, radiusX: touch.radiusX, radiusY: touch.radiusY,
deleted file mode 100644 --- a/testing/web-platform/meta/html/semantics/selectors/pseudo-classes/indeterminate.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[indeterminate.html] - type: testharness - [':progress' matches <input>s radio buttons whose radio button group contains no checked input and <progress> elements without value attribute] - expected: FAIL - - [dynamically check a radio input in a radio button group] - expected: FAIL - - [click on radio4 which is in the indeterminate state] - expected: FAIL -
--- a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-nameditem.html +++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-nameditem.html @@ -110,16 +110,21 @@ test(function() { assert_false("namedItem" in form) }, "Forms should not have a namedItem method") test(function() { var form = document.getElementsByTagName("form")[0] var button = document.getElementsByTagName("input")[0] assert_equals(button.type, "button") assert_equals(form.button, button) + var desc = Object.getOwnPropertyDescriptor(form, "button"); + assert_equals(desc.value, button); + assert_false(desc.writable); + assert_true(desc.configurable); + assert_false(desc.enumerable); assert_equals(form.button.length, undefined) }, "Name for a single element should work") test(function() { var form = document.getElementsByTagName("form")[0] assert_equals(form.radio.item(-1), null) assert_array_equals([0, 1, 2].map(function(i) { return form.radio.item(i).value @@ -217,16 +222,22 @@ test(function() { var input1 = document.getElementsByName("d")[0] assert_equals(input1.localName, "input") assert_equals(input1.getAttribute("form"), "c") var input2 = document.getElementsByName("d")[1] assert_equals(input2.localName, "input") assert_equals(input2.getAttribute("form"), "c") + var desc = Object.getOwnPropertyDescriptor(form, "d"); + assert_equals(desc.value, form.d); + assert_false(desc.writable); + assert_true(desc.configurable); + assert_false(desc.enumerable); + assert_true(form.d instanceof NodeList, "form.d should be a NodeList") assert_array_equals(form.d, [input1, input2]) }, "The form attribute should be taken into account for named getters (multiple elements)") test(function() { var f = document.body.appendChild(document.createElement("form")) f.id = "f" var g = f.appendChild(document.createElement("form"))
--- a/testing/web-platform/tests/html/semantics/selectors/pseudo-classes/indeterminate.html +++ b/testing/web-platform/tests/html/semantics/selectors/pseudo-classes/indeterminate.html @@ -19,17 +19,17 @@ <script> testSelectorIdsMatch(":indeterminate", ["radio2", "radio3", "radio4", "radio5", "progress1"], "':progress' matches <input>s radio buttons whose radio button group contains no checked input and <progress> elements without value attribute"); document.getElementById("radio2").setAttribute("checked", "checked"); testSelectorIdsMatch(":indeterminate", ["radio4", "radio5", "progress1"], "dynamically check a radio input in a radio button group"); document.getElementById("radio4").click(); - testSelectorIdsMatch(":indeterminate", ["checkbox1", "progress2"], "click on radio4 which is in the indeterminate state"); + testSelectorIdsMatch(":indeterminate", ["progress1"], "click on radio4 which is in the indeterminate state"); document.getElementById("progress1").setAttribute("value", "20"); testSelectorIdsMatch(":indeterminate", [], "adding a value to progress1 should put it in a determinate state"); document.getElementById("progress2").removeAttribute("value"); testSelectorIdsMatch(":indeterminate", ["progress2"], "removing progress2's value should put it in an indeterminate state"); document.getElementById("checkbox1").indeterminate = true; // set checkbox1 in the indeterminate state
--- a/toolkit/components/extensions/Extension.jsm +++ b/toolkit/components/extensions/Extension.jsm @@ -99,18 +99,18 @@ const LOGGER_ID_BASE = "addons.webextens const UUID_MAP_PREF = "extensions.webextensions.uuids"; const LEAVE_STORAGE_PREF = "extensions.webextensions.keepStorageOnUninstall"; const LEAVE_UUID_PREF = "extensions.webextensions.keepUuidOnUninstall"; const COMMENT_REGEXP = new RegExp(String.raw` ^ ( (?: - [^"] | - " (?:[^"\\] | \\.)* " + [^"\n] | + " (?:[^"\\\n] | \\.)* " )*? ) //.* `.replace(/\s+/g, ""), "gm"); var ExtensionContext, GlobalManager;
--- a/toolkit/components/extensions/NativeMessaging.jsm +++ b/toolkit/components/extensions/NativeMessaging.jsm @@ -372,52 +372,55 @@ this.NativeApp = class extends EventEmit } // Called from Context when the extension is shut down. close() { this._cleanup(); } portAPI() { - let api = { + let port = { name: this.name, disconnect: () => { if (this._isDisconnected) { throw new this.context.cloneScope.Error("Attempt to disconnect an already disconnected port"); } this._cleanup(); }, postMessage: msg => { this.send(msg); }, onDisconnect: new ExtensionUtils.SingletonEventManager(this.context, "native.onDisconnect", fire => { let listener = what => { - this.context.runSafe(fire); + this.context.runSafeWithoutClone(fire, port); }; this.on("disconnect", listener); return () => { this.off("disconnect", listener); }; }).api(), onMessage: new ExtensionUtils.SingletonEventManager(this.context, "native.onMessage", fire => { let listener = (what, msg) => { - this.context.runSafe(fire, msg); + msg = Cu.cloneInto(msg, this.context.cloneScope); + this.context.runSafeWithoutClone(fire, msg, port); }; this.on("message", listener); return () => { this.off("message", listener); }; }).api(), }; - return Cu.cloneInto(api, this.context.cloneScope, {cloneFunctions: true}); + port = Cu.cloneInto(port, this.context.cloneScope, {cloneFunctions: true}); + + return port; } sendMessage(msg) { let responsePromise = new Promise((resolve, reject) => { this.on("message", (what, msg) => { resolve(msg); }); this.on("disconnect", (what, err) => { reject(err); }); });
--- a/toolkit/components/extensions/Schemas.jsm +++ b/toolkit/components/extensions/Schemas.jsm @@ -543,16 +543,79 @@ class Entry { */ inject(apiImpl, path, name, dest, context) { } } // Corresponds either to a type declared in the "types" section of the // schema or else to any type object used throughout the schema. class Type extends Entry { + /** + * @property {Array<string>} EXTRA_PROPERTIES + * An array of extra properties which may be present for + * schemas of this type. + */ + static get EXTRA_PROPERTIES() { + return ["description", "deprecated", "preprocess", "restrictions"]; + } + + /** + * Parses the given schema object and returns an instance of this + * class which corresponds to its properties. + * + * @param {object} schema + * A JSON schema object which corresponds to a definition of + * this type. + * @param {Array<string>} path + * The path to this schema object from the root schema, + * corresponding to the property names and array indices + * traversed during parsing in order to arrive at this schema + * object. + * @param {Array<string>} [extraProperties] + * An array of extra property names which are valid for this + * schema in the current context. + * @returns {Type} + * An instance of this type which corresponds to the given + * schema object. + * @static + */ + static parseSchema(schema, path, extraProperties = []) { + this.checkSchemaProperties(schema, path, extraProperties); + + return new this(schema); + } + + /** + * Checks that all of the properties present in the given schema + * object are valid properties for this type, and throws if invalid. + * + * @param {object} schema + * A JSON schema object. + * @param {Array<string>} path + * The path to this schema object from the root schema, + * corresponding to the property names and array indices + * traversed during parsing in order to arrive at this schema + * object. + * @param {Array<string>} [extra] + * An array of extra property names which are valid for this + * schema in the current context. + * @throws {Error} + * An error describing the first invalid property found in the + * schema object. + */ + static checkSchemaProperties(schema, path, extra = []) { + let allowedSet = new Set([...this.EXTRA_PROPERTIES, ...extra]); + + for (let prop of Object.keys(schema)) { + if (!allowedSet.has(prop)) { + throw new Error(`Internal error: Namespace ${path.join(".")} has invalid type property "${prop}" in type "${schema.id || JSON.stringify(schema)}"`); + } + } + } + // Takes a value, checks that it has the correct type, and returns a // "normalized" version of the value. The normalized version will // include "nulls" in place of omitted optional properties. The // result of this function is either {error: "Some type error"} or // {value: <normalized-value>}. normalize(value, context) { return context.error("invalid type"); } @@ -595,16 +658,27 @@ class AnyType extends Type { checkBaseType(baseType) { return true; } } // An untagged union type. class ChoiceType extends Type { + static get EXTRA_PROPERTIES() { + return ["choices", ...super.EXTRA_PROPERTIES]; + } + + static parseSchema(schema, path, extraProperties = []) { + this.checkSchemaProperties(schema, path, extraProperties); + + let choices = schema.choices.map(t => Schemas.parseSchema(t, path)); + return new this(schema, choices); + } + constructor(schema, choices) { super(schema); this.choices = choices; } extend(type) { this.choices.push(...type.choices); @@ -643,16 +717,31 @@ class ChoiceType extends Type { checkBaseType(baseType) { return this.choices.some(t => t.checkBaseType(baseType)); } } // This is a reference to another type--essentially a typedef. class RefType extends Type { + static get EXTRA_PROPERTIES() { + return ["$ref", ...super.EXTRA_PROPERTIES]; + } + + static parseSchema(schema, path, extraProperties = []) { + this.checkSchemaProperties(schema, path, extraProperties); + + let ref = schema.$ref; + let ns = path[0]; + if (ref.includes(".")) { + [ns, ref] = ref.split("."); + } + return new this(schema, ns, ref); + } + // For a reference to a type named T declared in namespace NS, // namespaceName will be NS and reference will be T. constructor(schema, namespaceName, reference) { super(schema); this.namespaceName = namespaceName; this.reference = reference; } @@ -671,16 +760,60 @@ class RefType extends Type { } checkBaseType(baseType) { return this.targetType.checkBaseType(baseType); } } class StringType extends Type { + static get EXTRA_PROPERTIES() { + return ["enum", "minLength", "maxLength", "pattern", "format", + ...super.EXTRA_PROPERTIES]; + } + + static parseSchema(schema, path, extraProperties = []) { + this.checkSchemaProperties(schema, path, extraProperties); + + let enumeration = schema.enum || null; + if (enumeration) { + // The "enum" property is either a list of strings that are + // valid values or else a list of {name, description} objects, + // where the .name values are the valid values. + enumeration = enumeration.map(e => { + if (typeof(e) == "object") { + return e.name; + } + return e; + }); + } + + let pattern = null; + if (schema.pattern) { + try { + pattern = parsePattern(schema.pattern); + } catch (e) { + throw new Error(`Internal error: Invalid pattern ${JSON.stringify(schema.pattern)}`); + } + } + + let format = null; + if (schema.format) { + if (!(schema.format in FORMATS)) { + throw new Error(`Internal error: Invalid string format ${schema.format}`); + } + format = FORMATS[schema.format]; + } + return new this(schema, enumeration, + schema.minLength || 0, + schema.maxLength || Infinity, + pattern, + format); + } + constructor(schema, enumeration, minLength, maxLength, pattern, format) { super(schema); this.enumeration = enumeration; this.minLength = minLength; this.maxLength = maxLength; this.pattern = pattern; this.format = format; } @@ -738,17 +871,74 @@ class StringType extends Type { for (let e of this.enumeration) { let key = e.toUpperCase(); obj[key] = e; } } } } +let SubModuleType; class ObjectType extends Type { + static get EXTRA_PROPERTIES() { + return ["properties", "patternProperties", ...super.EXTRA_PROPERTIES]; + } + + static parseSchema(schema, path, extraProperties = []) { + if ("functions" in schema) { + return SubModuleType.parseSchema(schema, path, extraProperties); + } + + if (!("$extend" in schema)) { + // Only allow extending "properties" and "patternProperties". + extraProperties = ["additionalProperties", "isInstanceOf", ...extraProperties]; + } + this.checkSchemaProperties(schema, path, extraProperties); + + let parseProperty = (schema, extraProps = []) => { + return { + type: Schemas.parseSchema(schema, path, + ["unsupported", "onError", "permissions", ...extraProps]), + optional: schema.optional || false, + unsupported: schema.unsupported || false, + onError: schema.onError || null, + }; + }; + + // Parse explicit "properties" object. + let properties = Object.create(null); + for (let propName of Object.keys(schema.properties || {})) { + properties[propName] = parseProperty(schema.properties[propName], ["optional"]); + } + + // Parse regexp properties from "patternProperties" object. + let patternProperties = []; + for (let propName of Object.keys(schema.patternProperties || {})) { + let pattern; + try { + pattern = parsePattern(propName); + } catch (e) { + throw new Error(`Internal error: Invalid property pattern ${JSON.stringify(propName)}`); + } + + patternProperties.push({ + pattern, + type: parseProperty(schema.patternProperties[propName]), + }); + } + + // Parse "additionalProperties" schema. + let additionalProperties = null; + if (schema.additionalProperties) { + additionalProperties = Schemas.parseSchema(schema.additionalProperties, path); + } + + return new this(schema, properties, additionalProperties, patternProperties, schema.isInstanceOf || null); + } + constructor(schema, properties, additionalProperties, patternProperties, isInstanceOf) { super(schema); this.properties = properties; this.additionalProperties = additionalProperties; this.patternProperties = patternProperties; this.isInstanceOf = isInstanceOf; } @@ -764,160 +954,193 @@ class ObjectType extends Type { return this; } checkBaseType(baseType) { return baseType == "object"; } - // FIXME: Bug 1265371 - Refactor normalize and parseType in Schemas.jsm to reduce complexity - normalize(value, context) { // eslint-disable-line complexity - let v = this.normalizeBase("object", value, context); - if (v.error) { - return v; - } - value = v.value; - - if (this.isInstanceOf) { - if (Object.keys(this.properties).length || - this.patternProperties.length || - !(this.additionalProperties instanceof AnyType)) { - throw new Error("InternalError: isInstanceOf can only be used with objects that are otherwise unrestricted"); - } - - if (!instanceOf(value, this.isInstanceOf)) { - return context.error(`Object must be an instance of ${this.isInstanceOf}`, - `be an instance of ${this.isInstanceOf}`); - } - - // This is kind of a hack, but we can't normalize things that - // aren't JSON, so we just return them. - return {value}; - } - + /** + * Extracts the enumerable properties of the given object, including + * function properties which would normally be omitted by X-ray + * wrappers. + * + * @param {object} value + * @param {Context} context + * The current parse context. + * @returns {object} + * An object with an `error` or `value` property. + */ + extractProperties(value, context) { // |value| should be a JS Xray wrapping an object in the // extension compartment. This works well except when we need to // access callable properties on |value| since JS Xrays don't // support those. To work around the problem, we verify that // |value| is a plain JS object (i.e., not anything scary like a // Proxy). Then we copy the properties out of it into a normal // object using a waiver wrapper. let klass = Cu.getClassName(value, true); if (klass != "Object") { - return context.error(`Expected a plain JavaScript object, got a ${klass}`, - `be a plain JavaScript object`); + throw context.error(`Expected a plain JavaScript object, got a ${klass}`, + `be a plain JavaScript object`); } let properties = Object.create(null); - { - // |waived| is scoped locally to avoid accessing it when we - // don't mean to. - let waived = Cu.waiveXrays(value); - for (let prop of Object.getOwnPropertyNames(waived)) { - let desc = Object.getOwnPropertyDescriptor(waived, prop); - if (desc.get || desc.set) { - return context.error("Objects cannot have getters or setters on properties", - "contain no getter or setter properties"); - } - if (!desc.enumerable) { - // Chrome ignores non-enumerable properties. - continue; - } + + let waived = Cu.waiveXrays(value); + for (let prop of Object.getOwnPropertyNames(waived)) { + let desc = Object.getOwnPropertyDescriptor(waived, prop); + if (desc.get || desc.set) { + throw context.error("Objects cannot have getters or setters on properties", + "contain no getter or setter properties"); + } + // Chrome ignores non-enumerable properties. + if (desc.enumerable) { properties[prop] = Cu.unwaiveXrays(desc.value); } } - let remainingProps = new Set(Object.keys(properties)); + return properties; + } + + checkProperty(context, prop, propType, result, properties, remainingProps) { + let {type, optional, unsupported, onError} = propType; + let error = null; + + if (unsupported) { + if (prop in properties) { + error = context.error(`Property "${prop}" is unsupported by Firefox`, + `not contain an unsupported "${prop}" property`); + } + } else if (prop in properties) { + if (optional && (properties[prop] === null || properties[prop] === undefined)) { + result[prop] = null; + } else { + let r = context.withPath(prop, () => type.normalize(properties[prop], context)); + if (r.error) { + error = r; + } else { + result[prop] = r.value; + properties[prop] = r.value; + } + } + remainingProps.delete(prop); + } else if (!optional) { + error = context.error(`Property "${prop}" is required`, + `contain the required "${prop}" property`); + } else { + result[prop] = null; + } + + if (error) { + if (onError == "warn") { + context.logError(error.error); + } else if (onError != "ignore") { + throw error; + } + + result[prop] = null; + } + } - let checkProperty = (prop, propType, result) => { - let {type, optional, unsupported} = propType; - if (unsupported) { - if (prop in properties) { - return context.error(`Property "${prop}" is unsupported by Firefox`, - `not contain an unsupported "${prop}" property`); + normalize(value, context) { + try { + let v = this.normalizeBase("object", value, context); + if (v.error) { + return v; + } + value = v.value; + + if (this.isInstanceOf) { + if (Object.keys(this.properties).length || + this.patternProperties.length || + !(this.additionalProperties instanceof AnyType)) { + throw new Error("InternalError: isInstanceOf can only be used with objects that are otherwise unrestricted"); + } + + if (!instanceOf(value, this.isInstanceOf)) { + return context.error(`Object must be an instance of ${this.isInstanceOf}`, + `be an instance of ${this.isInstanceOf}`); } - } else if (prop in properties) { - if (optional && (properties[prop] === null || properties[prop] === undefined)) { - result[prop] = null; - } else { + + // This is kind of a hack, but we can't normalize things that + // aren't JSON, so we just return them. + return {value}; + } + + let properties = this.extractProperties(value, context); + let remainingProps = new Set(Object.keys(properties)); + + let result = {}; + for (let prop of Object.keys(this.properties)) { + this.checkProperty(context, prop, this.properties[prop], result, + properties, remainingProps); + } + + for (let prop of Object.keys(properties)) { + for (let {pattern, type} of this.patternProperties) { + if (pattern.test(prop)) { + this.checkProperty(context, prop, type, result, + properties, remainingProps); + } + } + } + + if (this.additionalProperties) { + for (let prop of remainingProps) { + let type = this.additionalProperties; let r = context.withPath(prop, () => type.normalize(properties[prop], context)); if (r.error) { return r; } result[prop] = r.value; - properties[prop] = r.value; } - remainingProps.delete(prop); - } else if (!optional) { - return context.error(`Property "${prop}" is required`, - `contain the required "${prop}" property`); - } else { - result[prop] = null; + } else if (remainingProps.size == 1) { + return context.error(`Unexpected property "${[...remainingProps]}"`, + `not contain an unexpected "${[...remainingProps]}" property`); + } else if (remainingProps.size) { + let props = [...remainingProps].sort().join(", "); + return context.error(`Unexpected properties: ${props}`, + `not contain the unexpected properties [${props}]`); } - }; - - let result = {}; - for (let prop of Object.keys(this.properties)) { - let error = checkProperty(prop, this.properties[prop], result); - if (error) { - let {onError} = this.properties[prop]; - if (onError == "warn") { - context.logError(error.error); - } else if (onError != "ignore") { - return error; - } - - result[prop] = null; - remainingProps.delete(prop); - } - } - for (let prop of Object.keys(properties)) { - for (let {pattern, type} of this.patternProperties) { - if (pattern.test(prop)) { - let error = checkProperty(prop, type, result); - if (error) { - return error; - } - } + return {value: result}; + } catch (e) { + if (e.error) { + return e; } + throw e; } - - if (this.additionalProperties) { - for (let prop of remainingProps) { - let type = this.additionalProperties; - let r = context.withPath(prop, () => type.normalize(properties[prop], context)); - if (r.error) { - return r; - } - result[prop] = r.value; - } - } else if (remainingProps.size == 1) { - return context.error(`Unexpected property "${[...remainingProps]}"`, - `not contain an unexpected "${[...remainingProps]}" property`); - } else if (remainingProps.size) { - let props = [...remainingProps].sort().join(", "); - return context.error(`Unexpected properties: ${props}`, - `not contain the unexpected properties [${props}]`); - } - - return {value: result}; } } // This type is just a placeholder to be referred to by // SubModuleProperty. No value is ever expected to have this type. -class SubModuleType extends Type { +SubModuleType = class SubModuleType extends Type { + static get EXTRA_PROPERTIES() { + return ["functions", "events", "properties", ...super.EXTRA_PROPERTIES]; + } + + static parseSchema(schema, path, extraProperties = []) { + this.checkSchemaProperties(schema, path, extraProperties); + + // The path we pass in here is only used for error messages. + path = [...path, schema.id]; + let functions = schema.functions.map(fun => Schemas.parseFunction(path, fun)); + + return new this(functions); + } + constructor(functions) { super(); this.functions = functions; } -} +}; class NumberType extends Type { normalize(value, context) { let r = this.normalizeBase("number", value, context); if (r.error) { return r; } @@ -930,16 +1153,26 @@ class NumberType extends Type { } checkBaseType(baseType) { return baseType == "number" || baseType == "integer"; } } class IntegerType extends Type { + static get EXTRA_PROPERTIES() { + return ["minimum", "maximum", ...super.EXTRA_PROPERTIES]; + } + + static parseSchema(schema, path, extraProperties = []) { + this.checkSchemaProperties(schema, path, extraProperties); + + return new this(schema, schema.minimum || -Infinity, schema.maximum || Infinity); + } + constructor(schema, minimum, maximum) { super(schema); this.minimum = minimum; this.maximum = maximum; } normalize(value, context) { let r = this.normalizeBase("integer", value, context); @@ -977,16 +1210,28 @@ class BooleanType extends Type { } checkBaseType(baseType) { return baseType == "boolean"; } } class ArrayType extends Type { + static get EXTRA_PROPERTIES() { + return ["items", "minItems", "maxItems", ...super.EXTRA_PROPERTIES]; + } + + static parseSchema(schema, path, extraProperties = []) { + this.checkSchemaProperties(schema, path, extraProperties); + + let items = Schemas.parseSchema(schema.items, path); + + return new this(schema, items, schema.minItems || 0, schema.maxItems || Infinity); + } + constructor(schema, itemType, minItems, maxItems) { super(schema); this.itemType = itemType; this.minItems = minItems; this.maxItems = maxItems; } normalize(value, context) { @@ -1019,16 +1264,56 @@ class ArrayType extends Type { } checkBaseType(baseType) { return baseType == "array"; } } class FunctionType extends Type { + static get EXTRA_PROPERTIES() { + return ["parameters", "async", "returns", ...super.EXTRA_PROPERTIES]; + } + + static parseSchema(schema, path, extraProperties = []) { + this.checkSchemaProperties(schema, path, extraProperties); + + let isAsync = !!schema.async; + let parameters = null; + if ("parameters" in schema) { + parameters = []; + for (let param of schema.parameters) { + // Callbacks default to optional for now, because of promise + // handling. + let isCallback = isAsync && param.name == schema.async; + + parameters.push({ + type: Schemas.parseSchema(param, path, ["name", "optional"]), + name: param.name, + optional: param.optional == null ? isCallback : param.optional, + }); + } + } + + let hasAsyncCallback = false; + if (isAsync) { + if (parameters && parameters.length && parameters[parameters.length - 1].name == schema.async) { + hasAsyncCallback = true; + } + if (schema.returns) { + throw new Error("Internal error: Async functions must not have return values."); + } + if (schema.allowAmbiguousOptionalArguments && !hasAsyncCallback) { + throw new Error("Internal error: Async functions with ambiguous arguments must declare the callback as the last parameter"); + } + } + + return new this(schema, parameters, isAsync, hasAsyncCallback); + } + constructor(schema, parameters, isAsync, hasAsyncCallback) { super(schema); this.parameters = parameters; this.isAsync = isAsync; this.hasAsyncCallback = hasAsyncCallback; } normalize(value, context) { @@ -1338,16 +1623,27 @@ class Event extends CallEntry { let obj = Cu.createObjectIn(dest, {defineAs: name}); Cu.exportFunction(addStub, obj, {defineAs: "addListener"}); Cu.exportFunction(removeStub, obj, {defineAs: "removeListener"}); Cu.exportFunction(hasStub, obj, {defineAs: "hasListener"}); } } +const TYPES = Object.freeze(Object.assign(Object.create(null), { + any: AnyType, + array: ArrayType, + boolean: BooleanType, + function: FunctionType, + integer: IntegerType, + number: NumberType, + object: ObjectType, + string: StringType, +})); + this.Schemas = { initialized: false, // Maps a schema URL to the JSON contained in that schema file. This // is useful for sending the JSON across processes. schemaJSON: new Map(), // Map[<schema-name> -> Map[<symbol-name> -> Entry]] @@ -1361,234 +1657,73 @@ this.Schemas = { ns.permissions = null; ns.restrictions = null; ns.defeaultRestrictions = null; this.namespaces.set(namespaceName, ns); } ns.set(symbol, value); }, - // FIXME: Bug 1265371 - Refactor normalize and parseType in Schemas.jsm to reduce complexity - parseType(path, type, extraProperties = []) { // eslint-disable-line complexity + parseSchema(schema, path, extraProperties = []) { let allowedProperties = new Set(extraProperties); - // Do some simple validation of our own schemas. - function checkTypeProperties(...extra) { - let allowedSet = new Set([...allowedProperties, ...extra, "description", "deprecated", "preprocess", "restrictions"]); - for (let prop of Object.keys(type)) { - if (!allowedSet.has(prop)) { - throw new Error(`Internal error: Namespace ${path.join(".")} has invalid type property "${prop}" in type "${type.id || JSON.stringify(type)}"`); - } - } + if ("choices" in schema) { + return ChoiceType.parseSchema(schema, path, allowedProperties); + } else if ("$ref" in schema) { + return RefType.parseSchema(schema, path, allowedProperties); } - if ("choices" in type) { - checkTypeProperties("choices"); - - let choices = type.choices.map(t => this.parseType(path, t)); - return new ChoiceType(type, choices); - } else if ("$ref" in type) { - checkTypeProperties("$ref"); - let ref = type.$ref; - let ns = path[0]; - if (ref.includes(".")) { - [ns, ref] = ref.split("."); - } - return new RefType(type, ns, ref); - } - - if (!("type" in type)) { - throw new Error(`Unexpected value for type: ${JSON.stringify(type)}`); + if (!("type" in schema)) { + throw new Error(`Unexpected value for type: ${JSON.stringify(schema)}`); } allowedProperties.add("type"); - // Otherwise it's a normal type... - if (type.type == "string") { - checkTypeProperties("enum", "minLength", "maxLength", "pattern", "format"); - - let enumeration = type.enum || null; - if (enumeration) { - // The "enum" property is either a list of strings that are - // valid values or else a list of {name, description} objects, - // where the .name values are the valid values. - enumeration = enumeration.map(e => { - if (typeof(e) == "object") { - return e.name; - } - return e; - }); - } - - let pattern = null; - if (type.pattern) { - try { - pattern = parsePattern(type.pattern); - } catch (e) { - throw new Error(`Internal error: Invalid pattern ${JSON.stringify(type.pattern)}`); - } - } - - let format = null; - if (type.format) { - if (!(type.format in FORMATS)) { - throw new Error(`Internal error: Invalid string format ${type.format}`); - } - format = FORMATS[type.format]; - } - return new StringType(type, enumeration, - type.minLength || 0, - type.maxLength || Infinity, - pattern, - format); - } else if (type.type == "object" && "functions" in type) { - // NOTE: "events" and "properties" are currently ignored, because they are used - // in the DevTools schema files, but they are not currently used by anything in the - // initial set of supported DevTools APIs. See Bug 1290901 for rationale. - // Introducing a complete support of "events" and "properties" in the SubModuleType - // will be re-evaluated as part of Bug 1293298 and Bug 1293301. - - checkTypeProperties("functions", "events", "properties"); - - // The path we pass in here is only used for error messages. - let functions = type.functions.map(fun => this.parseFunction(path.concat(type.id), fun)); - - return new SubModuleType(functions); - } else if (type.type == "object") { - let parseProperty = (type, extraProps = []) => { - return { - type: this.parseType(path, type, - ["unsupported", "onError", "permissions", ...extraProps]), - optional: type.optional || false, - unsupported: type.unsupported || false, - onError: type.onError || null, - }; - }; - - let properties = Object.create(null); - for (let propName of Object.keys(type.properties || {})) { - properties[propName] = parseProperty(type.properties[propName], ["optional"]); - } - - let patternProperties = []; - for (let propName of Object.keys(type.patternProperties || {})) { - let pattern; - try { - pattern = parsePattern(propName); - } catch (e) { - throw new Error(`Internal error: Invalid property pattern ${JSON.stringify(propName)}`); - } - - patternProperties.push({ - pattern, - type: parseProperty(type.patternProperties[propName]), - }); - } - - let additionalProperties = null; - if (type.additionalProperties) { - additionalProperties = this.parseType(path, type.additionalProperties); - } - - if ("$extend" in type) { - // Only allow extending "properties" and "patternProperties". - checkTypeProperties("properties", "patternProperties"); - } else { - checkTypeProperties("properties", "additionalProperties", "patternProperties", "isInstanceOf"); - } - return new ObjectType(type, properties, additionalProperties, patternProperties, type.isInstanceOf || null); - } else if (type.type == "array") { - checkTypeProperties("items", "minItems", "maxItems"); - return new ArrayType(type, this.parseType(path, type.items), - type.minItems || 0, type.maxItems || Infinity); - } else if (type.type == "number") { - checkTypeProperties(); - return new NumberType(type); - } else if (type.type == "integer") { - checkTypeProperties("minimum", "maximum"); - return new IntegerType(type, type.minimum || -Infinity, type.maximum || Infinity); - } else if (type.type == "boolean") { - checkTypeProperties(); - return new BooleanType(type); - } else if (type.type == "function") { - let isAsync = !!type.async; - let parameters = null; - if ("parameters" in type) { - parameters = []; - for (let param of type.parameters) { - // Callbacks default to optional for now, because of promise - // handling. - let isCallback = isAsync && param.name == type.async; - - parameters.push({ - type: this.parseType(path, param, ["name", "optional"]), - name: param.name, - optional: param.optional == null ? isCallback : param.optional, - }); - } - } - - let hasAsyncCallback = false; - if (isAsync) { - if (parameters && parameters.length && parameters[parameters.length - 1].name == type.async) { - hasAsyncCallback = true; - } - if (type.returns) { - throw new Error("Internal error: Async functions must not have return values."); - } - if (type.allowAmbiguousOptionalArguments && !hasAsyncCallback) { - throw new Error("Internal error: Async functions with ambiguous arguments must declare the callback as the last parameter"); - } - } - - checkTypeProperties("parameters", "async", "returns"); - return new FunctionType(type, parameters, isAsync, hasAsyncCallback); - } else if (type.type == "any") { - // Need to see what minimum and maximum are supposed to do here. - checkTypeProperties("minimum", "maximum"); - return new AnyType(type); + let type = TYPES[schema.type]; + if (!type) { + throw new Error(`Unexpected type ${schema.type}`); } - throw new Error(`Unexpected type ${type.type}`); + return type.parseSchema(schema, path, allowedProperties); }, parseFunction(path, fun) { let f = new FunctionEntry(fun, path, fun.name, - this.parseType(path, fun, - ["name", "unsupported", "returns", - "permissions", - "allowAmbiguousOptionalArguments"]), + this.parseSchema(fun, path, + ["name", "unsupported", "returns", + "permissions", + "allowAmbiguousOptionalArguments"]), fun.unsupported || false, fun.allowAmbiguousOptionalArguments || false, fun.returns || null, fun.permissions || null); return f; }, loadType(namespaceName, type) { if ("$extend" in type) { this.extendType(namespaceName, type); } else { - this.register(namespaceName, type.id, this.parseType([namespaceName], type, ["id"])); + this.register(namespaceName, type.id, this.parseSchema(type, [namespaceName], ["id"])); } }, extendType(namespaceName, type) { let ns = Schemas.namespaces.get(namespaceName); let targetType = ns && ns.get(type.$extend); // Only allow extending object and choices types for now. if (targetType instanceof ObjectType) { type.type = "object"; } else if (!targetType) { throw new Error(`Internal error: Attempt to extend a nonexistant type ${type.$extend}`); } else if (!(targetType instanceof ChoiceType)) { throw new Error(`Internal error: Attempt to extend a non-extensible type ${type.$extend}`); } - let parsed = this.parseType([namespaceName], type, ["$extend"]); + let parsed = this.parseSchema(type, [namespaceName], ["$extend"]); if (parsed.constructor !== targetType.constructor) { throw new Error(`Internal error: Bad attempt to extend ${type.$extend}`); } targetType.extend(parsed); }, loadProperty(namespaceName, name, prop) { @@ -1597,45 +1732,45 @@ this.Schemas = { this.register(namespaceName, name, new SubModuleProperty(prop, name, namespaceName, prop.$ref, prop.properties || {})); } } else if ("value" in prop) { this.register(namespaceName, name, new ValueProperty(prop, name, prop.value)); } else { // We ignore the "optional" attribute on properties since we // don't inject anything here anyway. - let type = this.parseType([namespaceName], prop, ["optional", "writable"]); + let type = this.parseSchema(prop, [namespaceName], ["optional", "writable"]); this.register(namespaceName, name, new TypeProperty(prop, namespaceName, name, type, prop.writable || false)); } }, loadFunction(namespaceName, fun) { let f = this.parseFunction([namespaceName], fun); this.register(namespaceName, fun.name, f); }, loadEvent(namespaceName, event) { let extras = event.extraParameters || []; extras = extras.map(param => { return { - type: this.parseType([namespaceName], param, ["name", "optional"]), + type: this.parseSchema(param, [namespaceName], ["name", "optional"]), name: param.name, optional: param.optional || false, }; }); // We ignore these properties for now. /* eslint-disable no-unused-vars */ let returns = event.returns; let filters = event.filters; /* eslint-enable no-unused-vars */ - let type = this.parseType([namespaceName], event, - ["name", "unsupported", "permissions", - "extraParameters", "returns", "filters"]); + let type = this.parseSchema(event, [namespaceName], + ["name", "unsupported", "permissions", + "extraParameters", "returns", "filters"]); let e = new Event(event, [namespaceName], event.name, type, extras, event.unsupported || false, event.permissions || null); this.register(namespaceName, event.name, e); }, init() { @@ -1678,23 +1813,23 @@ this.Schemas = { parseSchemas() { Object.defineProperty(this, "namespaces", { enumerable: true, configurable: true, value: new Map(), }); for (let json of this.schemaJSON.values()) { - this.parseSchema(json); + this.loadSchema(json); } return this.namespaces; }, - parseSchema(json) { + loadSchema(json) { for (let namespace of json) { let name = namespace.namespace; let types = namespace.types || []; for (let type of types) { this.loadType(name, type); }
--- a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js @@ -211,19 +211,24 @@ add_task(function* test_sendNativeMessag yield extension.unload(); }); // Test calling Port.disconnect() add_task(function* test_disconnect() { function background() { let port = browser.runtime.connectNative("echo"); - port.onMessage.addListener(msg => { + port.onMessage.addListener((msg, msgPort) => { + browser.test.assertEq(port, msgPort, "onMessage handler should receive the port as the second argument"); browser.test.sendMessage("message", msg); }); + port.onDisconnect.addListener(msgPort => { + browser.test.assertEq(port, msgPort, "onDisconnect handler should receive the port as the second argument"); + browser.test.sendMessage("disconnected"); + }); browser.test.onMessage.addListener((what, payload) => { if (what == "send") { if (payload._json) { let json = payload._json; payload.toJSON = () => json; delete payload._json; } port.postMessage(payload); @@ -259,16 +264,18 @@ add_task(function* test_disconnect() { let procCount = yield getSubprocessCount(); equal(procCount, 1, "subprocess is running"); extension.sendMessage("disconnect"); response = yield extension.awaitMessage("disconnect-result"); equal(response.success, true, "disconnect succeeded"); + yield extension.awaitMessage("disconnected"); + do_print("waiting for subprocess to exit"); yield waitForSubprocessExit(); procCount = yield getSubprocessCount(); equal(procCount, 0, "subprocess is no longer running"); extension.sendMessage("disconnect"); response = yield extension.awaitMessage("disconnect-result"); equal(response.success, false, "second call to disconnect failed");
--- a/toolkit/components/url-classifier/HashStore.cpp +++ b/toolkit/components/url-classifier/HashStore.cpp @@ -546,17 +546,19 @@ Merge(ChunkSet* aStoreChunks, return NS_ERROR_OUT_OF_MEMORY; } } // Chunks can be empty, but we should still report we have them // to make the chunkranges continuous. aStoreChunks->Merge(aUpdateChunks); - aStorePrefixes->AppendElements(adds, fallible); + if (!aStorePrefixes->AppendElements(adds, fallible)) + return NS_ERROR_OUT_OF_MEMORY; + EntrySort(*aStorePrefixes); return NS_OK; } nsresult HashStore::ApplyUpdate(TableUpdate &aUpdate) {
--- a/toolkit/content/tests/chrome/bug304188_window.xul +++ b/toolkit/content/tests/chrome/bug304188_window.xul @@ -74,17 +74,17 @@ find-menu appears in editor element whic ok(gFindBar.hidden, "Findfield should have stayed hidden after entering editor test"); } function* enterStringIntoEditor(aString) { for (let i = 0; i < aString.length; i++) { yield ContentTask.spawn(gBrowser, { charCode: aString.charCodeAt(i) }, function* (args) { - let event = content.document.createEvent("KeyEvents"); + let event = content.document.createEvent("KeyboardEvent"); event.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, args.charCode); content.document.body.dispatchEvent(event); }); } } ]]></script>
--- a/toolkit/content/tests/chrome/bug331215_window.xul +++ b/toolkit/content/tests/chrome/bug331215_window.xul @@ -73,17 +73,17 @@ yield enterStringIntoFindField("a"); ok(gFindBar._findField.getAttribute("status") != "notfound", "Findfield status attribute should not have been 'notfound'" + " after entering latest"); } function* enterStringIntoFindField(aString) { for (let i = 0; i < aString.length; i++) { - let event = document.createEvent("KeyEvents"); + let event = document.createEvent("KeyboardEvent"); let promise = new Promise(resolve => { let listener = { onFindResult: function() { gFindBar.browser.finder.removeResultListener(listener); resolve(); } }; gFindBar.browser.finder.addResultListener(listener);
--- a/toolkit/content/tests/chrome/bug360437_window.xul +++ b/toolkit/content/tests/chrome/bug360437_window.xul @@ -100,17 +100,17 @@ }; gFindBar.browser.finder.addResultListener(listener); }); } function promiseEnterStringIntoFindField(str) { let promise = promiseFindResult(str); for (let i = 0; i < str.length; i++) { - let event = document.createEvent("KeyEvents"); + let event = document.createEvent("KeyboardEvent"); event.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, str.charCodeAt(i)); gFindBar._findField.inputField.dispatchEvent(event); } return promise; } ]]></script> <textbox id="textbox"/>
--- a/toolkit/content/tests/chrome/bug429723_window.xul +++ b/toolkit/content/tests/chrome/bug429723_window.xul @@ -33,17 +33,17 @@ gBrowser.addEventListener("pageshow", onPageShow, false); gBrowser.loadURI("data:text/html,<h2 id='h2'>mozilla</h2>"); } setTimeout(_delayedOnLoad, 1000); } function enterStringIntoFindField(aString) { for (var i=0; i < aString.length; i++) { - var event = document.createEvent("KeyEvents"); + var event = document.createEvent("KeyboardEvent"); event.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, aString.charCodeAt(i)); gFindBar._findField.inputField.dispatchEvent(event); } } function onPageShow() { gBrowser.removeEventListener("pageshow", onPageShow, false); @@ -59,17 +59,17 @@ enterStringIntoFindField(searchStr); // Highlight search term var highlight = gFindBar.getElement("highlight"); if (!highlight.checked) highlight.click(); // Delete search term - var event = document.createEvent("KeyEvents"); + var event = document.createEvent("KeyboardEvent"); event.initKeyEvent("keypress", true, true, null, false, false, false, false, KeyEvent.DOM_VK_BACK_SPACE, 0); gFindBar._findField.inputField.dispatchEvent(event); var notRed = !findField.hasAttribute("status") || (findField.getAttribute("status") != "notfound"); ok(notRed, "Find Bar textbox is correct colour"); finish();
--- a/toolkit/content/tests/chrome/findbar_entireword_window.xul +++ b/toolkit/content/tests/chrome/findbar_entireword_window.xul @@ -149,17 +149,17 @@ yield testQuickfind(suite.testQuickfind); } var enterStringIntoFindField = Task.async(function* (str, waitForResult = true) { for (let promise, i = 0; i < str.length; i++) { if (waitForResult) { promise = promiseFindResult(); } - let event = document.createEvent("KeyEvents"); + let event = document.createEvent("KeyboardEvent"); event.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, str.charCodeAt(i)); gFindBar._findField.inputField.dispatchEvent(event); if (waitForResult) { yield promise; } } }); @@ -243,17 +243,17 @@ yield* testIterator(tests); gFindBar.close(); } function* testQuickfind(tests) { yield ContentTask.spawn(gBrowser, null, function* () { let document = content.document; - let event = document.createEvent("KeyEvents"); + let event = document.createEvent("KeyboardEvent"); event.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, "/".charCodeAt(0)); document.documentElement.dispatchEvent(event); }); ok(!gFindBar.hidden, "testQuickfind: failed to open findbar"); ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField, "testQuickfind: find field is not focused");
--- a/toolkit/content/tests/chrome/findbar_events_window.xul +++ b/toolkit/content/tests/chrome/findbar_events_window.xul @@ -106,17 +106,17 @@ } function* testFind() { info("Testing normal find."); let query = "t"; let promise = once(gFindBar, "find"); // Put some text in the find box. - let event = document.createEvent("KeyEvents"); + let event = document.createEvent("KeyboardEvent"); event.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, query.charCodeAt(0)); gFindBar._findField.inputField.dispatchEvent(event); let e = yield promise; ok(e.detail.query === query, "find event query should match '" + query + "'"); // Since we're preventing the default make sure nothing was selected. yield checkSelection();
--- a/toolkit/content/tests/chrome/findbar_window.xul +++ b/toolkit/content/tests/chrome/findbar_window.xul @@ -253,17 +253,17 @@ }); } var enterStringIntoFindField = Task.async(function* (str, waitForResult = true) { for (let promise, i = 0; i < str.length; i++) { if (waitForResult) { promise = promiseFindResult(); } - let event = document.createEvent("KeyEvents"); + let event = document.createEvent("KeyboardEvent"); event.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, str.charCodeAt(i)); gFindBar._findField.inputField.dispatchEvent(event); if (waitForResult) { yield promise; } } }); @@ -400,17 +400,17 @@ }); } function* testQuickFindLink() { yield clearFocus(); yield ContentTask.spawn(gBrowser, null, function* () { let document = content.document; - let event = document.createEvent("KeyEvents"); + let event = document.createEvent("KeyboardEvent"); event.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, "'".charCodeAt(0)); document.documentElement.dispatchEvent(event); }); ok(!gFindBar.hidden, "testQuickFindLink: failed to open findbar"); ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField, "testQuickFindLink: find field is not focused"); @@ -482,17 +482,17 @@ ok(!highlightButton.checked, "testFindWithHighlight: Highlight All should be unchecked."); } function* testQuickFindText() { yield clearFocus(); yield ContentTask.spawn(gBrowser, null, function* () { let document = content.document; - let event = document.createEvent("KeyEvents"); + let event = document.createEvent("KeyboardEvent"); event.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, "/".charCodeAt(0)); document.documentElement.dispatchEvent(event); }); ok(!gFindBar.hidden, "testQuickFindText: failed to open findbar"); ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField, "testQuickFindText: find field is not focused");
--- a/toolkit/content/tests/chrome/window_browser_drop.xul +++ b/toolkit/content/tests/chrome/window_browser_drop.xul @@ -45,17 +45,17 @@ function doDropAndStopLoad(browser, data } }, QueryInterface: XPCOMUtils.generateQI(["nsISupportsWeakReference"]) }; wp.addProgressListener(progressListener, wp.NOTIFY_STATE_WINDOW); let dataTransfer = new content.DataTransfer("dragstart", false); dataTransfer.mozSetDataAt(data.type, data.data, 0); - let event = content.document.createEvent("DragEvents"); + let event = content.document.createEvent("DragEvent"); event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); content.document.body.dispatchEvent(event); let nameGetter = {}; try { Services.droppedLinkHandler.dropLink(event, nameGetter, true); nameReturned = nameGetter.value; } catch (ex) {
--- a/toolkit/content/widgets/findbar.xml +++ b/toolkit/content/widgets/findbar.xml @@ -782,17 +782,17 @@ <method name="_dispatchKeypressEvent"> <parameter name="aTarget"/> <parameter name="aEvent"/> <body><![CDATA[ if (!aTarget) return; - let event = document.createEvent("KeyEvents"); + let event = document.createEvent("KeyboardEvent"); event.initKeyEvent(aEvent.type, aEvent.bubbles, aEvent.cancelable, aEvent.view, aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey, aEvent.metaKey, aEvent.keyCode, aEvent.charCode); aTarget.dispatchEvent(event); ]]></body> </method>
--- a/toolkit/modules/tests/browser/browser_FinderHighlighter.js +++ b/toolkit/modules/tests/browser/browser_FinderHighlighter.js @@ -41,17 +41,17 @@ function promiseFindResult(findbar, str }; findbar.browser.finder.addResultListener(listener); }); } function promiseEnterStringIntoFindField(findbar, str) { let promise = promiseFindResult(findbar, str); for (let i = 0; i < str.length; i++) { - let event = document.createEvent("KeyEvents"); + let event = document.createEvent("KeyboardEvent"); event.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, str.charCodeAt(i)); findbar._findField.inputField.dispatchEvent(event); } return promise; } function promiseTestHighlighterOutput(browser, word, expectedResult, extraTest = () => {}) {
--- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js +++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js @@ -117,16 +117,18 @@ const MAX_TIMEOUT_RUNS = 20000; // Time in seconds the helper application should sleep before exiting. The // helper can also be made to exit by writing |finish| to its input file. const HELPER_SLEEP_TIMEOUT = 180; // Maximum number of milliseconds the process that is launched can run before // the test will try to kill it. const APP_TIMER_TIMEOUT = 120000; +const FILE_IN_USE_TIMEOUT_MS = 1000; + const PIPE_TO_NULL = IS_WIN ? ">nul" : "> /dev/null 2>&1"; const LOG_FUNCTION = do_print; const gHTTPHandlerPath = "updates.xml"; // This default value will be overridden when using the http server. var gURLData = URL_HOST + "/"; @@ -1618,35 +1620,55 @@ function copyTestUpdaterForRunUsingUpdat updater.append("Contents"); updater.append("MacOS"); updater.append("org.mozilla.updater"); } return updater; } /** - * Logs the contents of an update log. + * Logs the contents of an update log and for maintenance service tests this + * will log the contents of the latest maintenanceservice.log. * * @param aLogLeafName - * The leaf name of the log. + * The leaf name of the update log. */ function logUpdateLog(aLogLeafName) { let updateLog = getUpdateLog(aLogLeafName); if (updateLog.exists()) { // xpcshell tests won't display the entire contents so log each line. let updateLogContents = readFileBytes(updateLog).replace(/\r\n/g, "\n"); updateLogContents = replaceLogPaths(updateLogContents); let aryLogContents = updateLogContents.split("\n"); logTestInfo("contents of " + updateLog.path + ":"); aryLogContents.forEach(function RU_LC_FE(aLine) { logTestInfo(aLine); }); } else { logTestInfo("update log doesn't exist, path: " + updateLog.path); } + + if (IS_SERVICE_TEST) { + let serviceLog = getMaintSvcDir(); + serviceLog.append("logs"); + serviceLog.append("maintenanceservice.log"); + if (serviceLog.exists()) { + // xpcshell tests won't display the entire contents so log each line. + let serviceLogContents = readFileBytes(serviceLog).replace(/\r\n/g, "\n"); + serviceLogContents = replaceLogPaths(serviceLogContents); + let aryLogContents = serviceLogContents.split("\n"); + logTestInfo("contents of " + serviceLog.path + ":"); + aryLogContents.forEach(function RU_LC_FE(aLine) { + logTestInfo(aLine); + }); + } else { + logTestInfo("maintenance service log doesn't exist, path: " + + serviceLog.path); + } + } } /** * Launches the updater binary or the service to apply an update for updater * tests. For non-service tests runUpdateUsingUpdater will be called and for * service tests runUpdateUsingService will be called. * * @param aExpectedStatus @@ -1899,17 +1921,26 @@ function stageUpdate() { * present after staging and update for updater tests and then calls * stageUpdateFinished. * * @param aUpdateState * The update state received by the observer notification. */ function checkUpdateStagedState(aUpdateState) { if (IS_WIN) { - waitForApplicationStop(FILE_UPDATER_BIN); + if (IS_SERVICE_TEST) { + waitForServiceStop(false); + } else { + let updater = getApplyDirFile(FILE_UPDATER_BIN, true); + if (isFileInUse(updater)) { + do_timeout(FILE_IN_USE_TIMEOUT_MS, + checkUpdateStagedState.bind(null, aUpdateState)); + return; + } + } } Assert.equal(aUpdateState, STATE_AFTER_STAGE, "the notified state" + MSG_SHOULD_EQUAL); if (!gStagingRemovedUpdate) { Assert.equal(readStatusState(), STATE_AFTER_STAGE, "the status file state" + MSG_SHOULD_EQUAL); @@ -2330,34 +2361,16 @@ function waitForApplicationStop(aApplica let args = ["wait-for-application-exit", aApplication, "120"]; let exitValue = runTestHelperSync(args); Assert.equal(exitValue, 0, "the process should have stopped, process name: " + aApplication); } /** - * Checks if an application is running. - * - * @param aApplication - * The application binary name to check if it is running. - */ -function isProcessRunning(aApplication) { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - debugDump("checking if " + aApplication + " is running"); - // Use the helper bin to ensure the application is stopped. If not stopped, - // then wait for it to stop (at most 120 seconds). - let args = ["is-process-running", aApplication]; - let exitValue = runTestHelperSync(args); - return exitValue; -} -/** * Helper function for updater tests for launching the updater using the * maintenance service to apply a mar file. When complete runUpdateFinished * will be called. * * @param aExpectedStatus * The expected value of update.status when the test finishes. * @param aSwitchApp * If true the update should switch the application with an updated @@ -2385,25 +2398,18 @@ function runUpdateUsingService(aExpected function readServiceLogFile() { let file = getMaintSvcDir(); file.append("logs"); file.append("maintenanceservice.log"); return readFile(file); } function checkServiceUpdateFinished() { - if (isProcessRunning(FILE_MAINTENANCE_SERVICE_BIN)) { - do_execute_soon(checkServiceUpdateFinished); - return; - } - - if (isProcessRunning(FILE_UPDATER_BIN)) { - do_execute_soon(checkServiceUpdateFinished); - return; - } + waitForApplicationStop(FILE_MAINTENANCE_SERVICE_BIN); + waitForApplicationStop(FILE_UPDATER_BIN); // Wait for the expected status let status; try { status = readStatusFile(); } catch (e) { do_execute_soon(checkServiceUpdateFinished); return; @@ -3484,53 +3490,75 @@ function checkCallbackServiceLog() { do_execute_soon(checkCallbackServiceLog); return; } Assert.ok(true, "the callback service log contents" + MSG_SHOULD_EQUAL); waitForFilesInUse(); } -// Waits until files that are in use that break tests are no longer in use and -// then calls doTestFinish to end the test. +/** + * Helper function to check if a file is in use on Windows by making a copy of + * a file and attempting to delete the original file. If the deletion is + * successful the copy of the original file is renamed to the original file's + * name and if the deletion is not successful the copy of the original file is + * deleted. + * + * @param aFile + * An nsIFile for the file to be checked if it is in use. + * @return true if the file can't be deleted and false otherwise. + */ +function isFileInUse(aFile) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + if (!aFile.exists()) { + debugDump("file does not exist, path: " + aFile.path); + return false; + } + + let fileBak = aFile.parent; + fileBak.append(aFile.leafName + ".bak"); + try { + if (fileBak.exists()) { + fileBak.remove(false); + } + aFile.copyTo(aFile.parent, fileBak.leafName); + aFile.remove(false); + fileBak.moveTo(aFile.parent, aFile.leafName); + debugDump("file is not in use, path: " + aFile.path); + return false; + } catch (e) { + debugDump("file in use, path: " + aFile.path + ", exception: " + e); + try { + if (fileBak.exists()) { + fileBak.remove(false); + } + } catch (e) { + logTestInfo("unable to remove backup file, path: " + + fileBak.path + ", exception: " + e); + } + } + return true; +} + +/** + * Waits until files that are in use that break tests are no longer in use and + * then calls doTestFinish to end the test. + */ function waitForFilesInUse() { if (IS_WIN) { - let appBin = getApplyDirFile(FILE_APP_BIN, true); - let maintSvcInstaller = getApplyDirFile(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, true); - let helper = getApplyDirFile("uninstall/helper.exe", true); - let updater = getApplyDirFile(FILE_UPDATER_BIN, true); - let files = [appBin, updater, maintSvcInstaller, helper]; - - for (let i = 0; i < files.length; ++i) { - let file = files[i]; - let fileBak = file.parent.clone(); - if (file.exists()) { - fileBak.append(file.leafName + ".bak"); - try { - if (fileBak.exists()) { - fileBak.remove(false); - } - file.copyTo(fileBak.parent, fileBak.leafName); - file.remove(false); - fileBak.moveTo(file.parent, file.leafName); - debugDump("file is not in use, path: " + file.path); - } catch (e) { - debugDump("will try again to remove file in use, path: " + - file.path + ", exception: " + e); - try { - if (fileBak.exists()) { - fileBak.remove(false); - } - } catch (e) { - logTestInfo("unable to remove backup file, path: " + - fileBak.path + ", exception: " + e); - } - do_execute_soon(waitForFilesInUse); - return; - } + let fileNames = [FILE_APP_BIN, FILE_UPDATER_BIN, + FILE_MAINTENANCE_SERVICE_INSTALLER_BIN]; + for (let i = 0; i < fileNames.length; ++i) { + let file = getApplyDirFile(fileNames[i], true); + if (isFileInUse(file)) { + do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForFilesInUse); + return; } } } debugDump("calling doTestFinish"); doTestFinish(); } @@ -3964,17 +3992,17 @@ function runUpdateUsingApp(aExpectedStat } Assert.equal(gProcess.exitValue, 0, "the application process exit value should be 0"); Assert.equal(aTopic, "process-finished", "the application process observer topic should be " + "process-finished"); if (IS_SERVICE_TEST) { - waitForServiceStop(); + waitForServiceStop(false); } do_execute_soon(afterAppExits); }, QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) }; function afterAppExits() { @@ -4058,23 +4086,25 @@ const gAppTimerCallback = { /** * The update-staged observer for the call to nsIUpdateProcessor:processUpdate. */ const gUpdateStagedObserver = { observe: function(aSubject, aTopic, aData) { debugDump("observe called with topic: " + aTopic + ", data: " + aData); if (aTopic == "update-staged") { + Services.obs.removeObserver(gUpdateStagedObserver, "update-staged"); // The environment is reset after the update-staged observer topic because // processUpdate in nsIUpdateProcessor uses a new thread and clearing the // environment immediately after calling processUpdate can clear the // environment before the updater is launched. resetEnvironment(); - Services.obs.removeObserver(gUpdateStagedObserver, "update-staged"); - checkUpdateStagedState(aData); + // Use do_execute_soon to prevent any failures from propagating to the + // update service. + do_execute_soon(checkUpdateStagedState.bind(null, aData)); } }, QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) }; /** * Sets the environment that will be used by the application process when it is * launched.
--- a/widget/android/ThumbnailHelper.h +++ b/widget/android/ThumbnailHelper.h @@ -131,35 +131,30 @@ class ThumbnailHelper final nsCOMPtr<nsIDocShell> docShell = win->GetDocShell(); RefPtr<nsPresContext> presContext; if (!docShell || NS_FAILED(docShell->GetPresContext( getter_AddRefs(presContext))) || !presContext) { return nullptr; } - MOZ_ASSERT(gfxPlatform::GetPlatform()-> - SupportsAzureContentForType(BackendType::CAIRO), - "Need BackendType::CAIRO support"); - uint8_t* const data = static_cast<uint8_t*>(aData->Address()); if (!data) { return nullptr; } const bool is24bit = !AndroidBridge::Bridge() || AndroidBridge::Bridge()->GetScreenDepth() == 24; const uint32_t stride = aThumbWidth * (is24bit ? 4 : 2); - RefPtr<DrawTarget> dt = gfx::Factory::CreateDrawTargetForData( - BackendType::CAIRO, + RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForData( data, IntSize(aThumbWidth, aThumbHeight), stride, - is24bit ? SurfaceFormat::B8G8R8X8 + is24bit ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::R5G6B5_UINT16); if (!dt || !dt->IsValid()) { return nullptr; } nsCOMPtr<nsIPresShell> presShell = presContext->PresShell(); RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);