mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge fx-team to mozilla-central a=merge
This commit is contained in:
commit
54a9eaebfd
@ -3,12 +3,15 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { Ci } = require('chrome');
|
||||
const system = require('sdk/system/events');
|
||||
const { frames } = require('sdk/remote/child');
|
||||
const { WorkerChild } = require('sdk/content/worker-child');
|
||||
|
||||
// map observer topics to tab event names
|
||||
const EVENTS = {
|
||||
'content-document-global-created': 'create',
|
||||
'chrome-document-global-created': 'create',
|
||||
'content-document-interactive': 'ready',
|
||||
'chrome-document-interactive': 'ready',
|
||||
'content-document-loaded': 'load',
|
||||
@ -17,12 +20,18 @@ const EVENTS = {
|
||||
}
|
||||
|
||||
function topicListener({ subject, type }) {
|
||||
let window = subject.defaultView;
|
||||
if (!window)
|
||||
// NOTE detect the window from the subject:
|
||||
// - on *-global-created the subject is the window
|
||||
// - in the other cases it is the document object
|
||||
let window = subject instanceof Ci.nsIDOMWindow ? subject : subject.defaultView;
|
||||
if (!window){
|
||||
return;
|
||||
let frame = frames.getFrameForWindow(subject.defaultView);
|
||||
if (frame)
|
||||
frame.port.emit('sdk/tab/event', EVENTS[type]);
|
||||
}
|
||||
let frame = frames.getFrameForWindow(window);
|
||||
if (frame) {
|
||||
let readyState = frame.content.document.readyState;
|
||||
frame.port.emit('sdk/tab/event', EVENTS[type], { readyState });
|
||||
}
|
||||
}
|
||||
|
||||
for (let topic in EVENTS)
|
||||
@ -31,8 +40,9 @@ for (let topic in EVENTS)
|
||||
// bug 1024105 - content-page-shown notification doesn't pass persisted param
|
||||
function eventListener({target, type, persisted}) {
|
||||
let frame = this;
|
||||
if (target === frame.content.document)
|
||||
if (target === frame.content.document) {
|
||||
frame.port.emit('sdk/tab/event', type, persisted);
|
||||
}
|
||||
}
|
||||
frames.addEventListener('pageshow', eventListener, true);
|
||||
|
||||
@ -40,3 +50,9 @@ frames.port.on('sdk/tab/attach', (frame, options) => {
|
||||
options.window = frame.content;
|
||||
new WorkerChild(options);
|
||||
});
|
||||
|
||||
// Forward the existent frames's readyState.
|
||||
for (let frame of frames) {
|
||||
let readyState = frame.content.document.readyState;
|
||||
frame.port.emit('sdk/tab/event', 'init', { readyState });
|
||||
}
|
||||
|
@ -44,6 +44,9 @@ function isClosed(tab) {
|
||||
return viewsFor.get(tab).closing;
|
||||
}
|
||||
|
||||
// private tab attribute where the remote cached value is stored
|
||||
const remoteReadyStateCached = Symbol("remoteReadyStateCached");
|
||||
|
||||
const Tab = Class({
|
||||
implements: [EventTarget],
|
||||
initialize: function(tabElement, options = null) {
|
||||
@ -125,8 +128,7 @@ const Tab = Class({
|
||||
},
|
||||
|
||||
get readyState() {
|
||||
// TODO: This will use CPOWs in e10s: bug 1146606
|
||||
return isDestroyed(this) ? undefined : browser(this).contentDocument.readyState;
|
||||
return isDestroyed(this) ? undefined : this[remoteReadyStateCached] || "uninitialized";
|
||||
},
|
||||
|
||||
pin: function() {
|
||||
@ -306,11 +308,21 @@ function tabEventListener(event, tabElement, ...args) {
|
||||
removeListItem(window.tabs, tab);
|
||||
// The tabs module will take care of removing from its internal list
|
||||
}
|
||||
else if (event == "ready" || event == "load") {
|
||||
else if (event == "init" || event == "create" || event == "ready" || event == "load") {
|
||||
// Ignore load events from before browser windows have fully loaded, these
|
||||
// are for about:blank in the initial tab
|
||||
if (isBrowser(domWindow) && !domWindow.gBrowserInit.delayedStartupFinished)
|
||||
return;
|
||||
|
||||
// update the cached remote readyState value
|
||||
let { readyState } = args[0] || {};
|
||||
tab[remoteReadyStateCached] = readyState;
|
||||
}
|
||||
|
||||
if (event == "init") {
|
||||
// Do not emit events for the detected existent tabs, we only need to cache
|
||||
// their current document.readyState value.
|
||||
return;
|
||||
}
|
||||
|
||||
tabEmit(tab, event, ...args);
|
||||
|
@ -9,7 +9,7 @@ const windows = require("sdk/windows").browserWindows;
|
||||
const app = require("sdk/system/xul-app");
|
||||
const { viewFor } = require("sdk/view/core");
|
||||
const { modelFor } = require("sdk/model/core");
|
||||
const { getTabId, isTab } = require("sdk/tabs/utils");
|
||||
const { getBrowserForTab, getTabId, isTab } = require("sdk/tabs/utils");
|
||||
const { defer } = require("sdk/lang/functional");
|
||||
|
||||
function tabExistenceInTabs(assert, found, tab, tabs) {
|
||||
@ -202,4 +202,14 @@ exports["test tab.readyState"] = (assert, done) => {
|
||||
});
|
||||
}
|
||||
|
||||
exports["test tab.readyState for existent tabs"] = (assert) => {
|
||||
assert.equal(tabs.length, 1, "tabs contains an existent tab");
|
||||
|
||||
for (let tab of tabs) {
|
||||
let browserForTab = getBrowserForTab(viewFor(tab));
|
||||
assert.equal(browserForTab.contentDocument.readyState, tab.readyState,
|
||||
"tab.readyState has the same value of the associated contentDocument.readyState CPOW");
|
||||
}
|
||||
}
|
||||
|
||||
require("sdk/test").run(module.exports);
|
||||
|
@ -1950,6 +1950,16 @@ Experiments.ExperimentEntry.prototype = {
|
||||
return changes;
|
||||
}
|
||||
|
||||
// Check permissions to see if we can enable the addon.
|
||||
if (!(addon.permissions & AddonManager.PERM_CAN_ENABLE)) {
|
||||
throw new Error("Don't have permission to enable addon " + addon.id + ", perm=" + addon.permission);
|
||||
}
|
||||
|
||||
// Experiment addons should not require a restart.
|
||||
if (!!(addon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_ENABLE)) {
|
||||
throw new Error("Experiment addon requires a restart: " + addon.id);
|
||||
}
|
||||
|
||||
let deferred = Promise.defer();
|
||||
|
||||
// Else we need to enable it.
|
||||
@ -1964,13 +1974,24 @@ Experiments.ExperimentEntry.prototype = {
|
||||
},
|
||||
};
|
||||
|
||||
this._log.info("Activating add-on: " + addon.id);
|
||||
for (let handler of ["onDisabled", "onOperationCancelled", "onUninstalled"]) {
|
||||
listener[handler] = (evtAddon) => {
|
||||
if (evtAddon.id != addon.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddonManager.removeAddonListener(listener);
|
||||
deferred.reject("Failed to enable addon " + addon.id + " due to: " + handler);
|
||||
};
|
||||
}
|
||||
|
||||
this._log.info("reconcileAddonState() - Activating add-on: " + addon.id);
|
||||
AddonManager.addAddonListener(listener);
|
||||
addon.userDisabled = false;
|
||||
yield deferred.promise;
|
||||
changes |= this.ADDON_CHANGE_ENABLE;
|
||||
|
||||
this._log.info("Add-on has been enabled: " + addon.id);
|
||||
this._log.info("reconcileAddonState() - Add-on has been enabled: " + addon.id);
|
||||
return changes;
|
||||
}),
|
||||
|
||||
|
@ -1088,11 +1088,12 @@ AnimationTimeBlock.prototype = {
|
||||
text += "\n";
|
||||
|
||||
// Adding the iteration count (the infinite symbol, or an integer).
|
||||
// XXX: see bug 1219608 to remove this if the count is 1.
|
||||
text += L10N.getStr("player.animationIterationCountLabel") + " ";
|
||||
text += state.iterationCount ||
|
||||
L10N.getStr("player.infiniteIterationCountText");
|
||||
text += "\n";
|
||||
if (state.iterationCount !== 1) {
|
||||
text += L10N.getStr("player.animationIterationCountLabel") + " ";
|
||||
text += state.iterationCount ||
|
||||
L10N.getStr("player.infiniteIterationCountText");
|
||||
text += "\n";
|
||||
}
|
||||
|
||||
// Adding the playback rate if it's different than 1.
|
||||
if (state.playbackRate !== 1) {
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {panel} = yield openAnimationInspector();
|
||||
let {panel, controller} = yield openAnimationInspector();
|
||||
|
||||
info("Getting the animation element from the panel");
|
||||
let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
|
||||
@ -17,12 +17,16 @@ add_task(function*() {
|
||||
|
||||
// Verify that each time-block's name element has a tooltip that looks sort of
|
||||
// ok. We don't need to test the actual content.
|
||||
for (let el of timeBlockNameEls) {
|
||||
ok(el.hasAttribute("title"), "The tooltip is defined");
|
||||
[...timeBlockNameEls].forEach((el, i) => {
|
||||
ok(el.hasAttribute("title"), "The tooltip is defined for animation " + i);
|
||||
|
||||
let title = el.getAttribute("title");
|
||||
ok(title.match(/Delay: [\d.-]+s/), "The tooltip shows the delay");
|
||||
ok(title.match(/Duration: [\d.]+s/), "The tooltip shows the duration");
|
||||
ok(title.match(/Repeats: /), "The tooltip shows the iterations");
|
||||
}
|
||||
if (controller.animationPlayers[i].state.iterationCount !== 1) {
|
||||
ok(title.match(/Repeats: /), "The tooltip shows the iterations");
|
||||
} else {
|
||||
ok(!title.match(/Repeats: /), "The tooltip doesn't show the iterations");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -25,6 +25,7 @@ support-files =
|
||||
doc_inspector_search.html
|
||||
doc_inspector_search-reserved.html
|
||||
doc_inspector_search-suggestions.html
|
||||
doc_inspector_search-svg.html
|
||||
doc_inspector_select-last-selected-01.html
|
||||
doc_inspector_select-last-selected-02.html
|
||||
head.js
|
||||
@ -108,6 +109,7 @@ skip-if = e10s # Test synthesize scrolling events in content. Also, see bug 1035
|
||||
[browser_inspector_search-04.js]
|
||||
[browser_inspector_search-05.js]
|
||||
[browser_inspector_search-06.js]
|
||||
[browser_inspector_search-07.js]
|
||||
[browser_inspector_search-reserved.js]
|
||||
[browser_inspector_select-docshell.js]
|
||||
[browser_inspector_select-last-selected.js]
|
||||
|
@ -0,0 +1,49 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that searching for classes on SVG elements does work (see bug 1219920).
|
||||
|
||||
const TEST_URL = TEST_URL_ROOT + "doc_inspector_search-svg.html";
|
||||
|
||||
// An array of (key, suggestions) pairs where key is a key to press and
|
||||
// suggestions is an array of suggestions that should be shown in the popup.
|
||||
const TEST_DATA = [{
|
||||
key: "c",
|
||||
suggestions: ["circle", ".class1", ".class2"]
|
||||
}, {
|
||||
key: "VK_BACK_SPACE",
|
||||
suggestions: []
|
||||
}, {
|
||||
key: ".",
|
||||
suggestions: [".class1", ".class2"]
|
||||
}];
|
||||
|
||||
add_task(function* () {
|
||||
let {inspector} = yield openInspectorForURL(TEST_URL);
|
||||
let {searchBox} = inspector;
|
||||
let popup = inspector.searchSuggestions.searchPopup;
|
||||
|
||||
yield focusSearchBoxUsingShortcut(inspector.panelWin);
|
||||
|
||||
for (let {key, suggestions} of TEST_DATA) {
|
||||
info("Pressing " + key + " to get " + suggestions);
|
||||
|
||||
let command = once(searchBox, "command");
|
||||
EventUtils.synthesizeKey(key, {}, inspector.panelWin);
|
||||
yield command;
|
||||
|
||||
info("Waiting for search query to complete and getting the suggestions");
|
||||
yield inspector.searchSuggestions._lastQuery;
|
||||
let actualSuggestions = popup.getItems().reverse();
|
||||
|
||||
is(popup.isOpen ? actualSuggestions.length : 0, suggestions.length,
|
||||
"There are expected number of suggestions.");
|
||||
|
||||
for (let i = 0; i < suggestions.length; i++) {
|
||||
is(actualSuggestions[i].label, suggestions[i],
|
||||
"The suggestion at " + i + "th index is correct.");
|
||||
}
|
||||
}
|
||||
});
|
13
devtools/client/inspector/test/doc_inspector_search-svg.html
Normal file
13
devtools/client/inspector/test/doc_inspector_search-svg.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Inspector SVG Search Box Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="class1"></div>
|
||||
<svg>
|
||||
<circle cx="0" cy="0" r="50" class="class2" />
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
@ -128,13 +128,16 @@ ul.children + .tag-line::before {
|
||||
left: -1000em;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.expander {
|
||||
display: inline-block;
|
||||
margin-left: -14px;
|
||||
vertical-align: middle;
|
||||
/* Make sure the expander still appears above the tag-state */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.child.collapsed .child {
|
||||
@ -190,6 +193,12 @@ ul.children + .tag-line::before {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.editor {
|
||||
/* Make sure the editor still appears above the tag-state */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.editor.text {
|
||||
display: inline-block;
|
||||
}
|
||||
@ -198,4 +207,3 @@ ul.children + .tag-line::before {
|
||||
.editor.comment pre {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ const { Cc, Ci, Cu, Cr } = require("chrome");
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
loader.lazyRequireGetter(this, "global",
|
||||
"devtools/client/performance/modules/global");
|
||||
const demangle = require("devtools/client/shared/demangle");
|
||||
|
||||
// Character codes used in various parsing helper functions.
|
||||
const CHAR_CODE_A = "a".charCodeAt(0);
|
||||
@ -27,12 +28,14 @@ const CHAR_CODE_T = "t".charCodeAt(0);
|
||||
const CHAR_CODE_U = "u".charCodeAt(0);
|
||||
const CHAR_CODE_0 = "0".charCodeAt(0);
|
||||
const CHAR_CODE_9 = "9".charCodeAt(0);
|
||||
const CHAR_CODE_CAP_Z = "Z".charCodeAt(0);
|
||||
|
||||
const CHAR_CODE_LPAREN = "(".charCodeAt(0);
|
||||
const CHAR_CODE_RPAREN = ")".charCodeAt(0);
|
||||
const CHAR_CODE_COLON = ":".charCodeAt(0);
|
||||
const CHAR_CODE_SLASH = "/".charCodeAt(0);
|
||||
const CHAR_CODE_SPACE = " ".charCodeAt(0);
|
||||
const CHAR_CODE_UNDERSCORE = "_".charCodeAt(0);
|
||||
|
||||
// The cache used in the `nsIURL` function.
|
||||
const gNSURLStore = new Map();
|
||||
@ -480,6 +483,13 @@ function isNumeric(c) {
|
||||
return c >= CHAR_CODE_0 && c <= CHAR_CODE_9;
|
||||
}
|
||||
|
||||
function shouldDemangle(name) {
|
||||
return name && name.charCodeAt &&
|
||||
name.charCodeAt(0) === CHAR_CODE_UNDERSCORE &&
|
||||
name.charCodeAt(1) === CHAR_CODE_UNDERSCORE &&
|
||||
name.charCodeAt(2) === CHAR_CODE_CAP_Z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the relative costs of this frame compared to a root,
|
||||
* and generates allocations information if specified. Uses caching
|
||||
@ -513,7 +523,9 @@ function getFrameInfo (node, options) {
|
||||
data.nodeType = node.nodeType;
|
||||
|
||||
// Frame name (function location or some meta information)
|
||||
data.name = data.isMetaCategory ? data.categoryData.label : data.functionName || "";
|
||||
data.name = data.isMetaCategory ? data.categoryData.label :
|
||||
shouldDemangle(data.functionName) ? demangle(data.functionName) : data.functionName;
|
||||
|
||||
data.tooltiptext = data.isMetaCategory ? data.categoryData.label : node.location || "";
|
||||
|
||||
gFrameData.set(node, data);
|
||||
@ -583,3 +595,4 @@ exports.parseLocation = parseLocation;
|
||||
exports.getInflatedFrameCache = getInflatedFrameCache;
|
||||
exports.getOrAddInflatedFrame = getOrAddInflatedFrame;
|
||||
exports.InflatedFrame = InflatedFrame;
|
||||
exports.shouldDemangle = shouldDemangle;
|
||||
|
@ -4,9 +4,12 @@
|
||||
/**
|
||||
* Tests if the profiler's tree view implementation works properly and
|
||||
* creates the correct column structure after expanding some of the nodes.
|
||||
* Also tests that demangling works.
|
||||
*/
|
||||
|
||||
var { CATEGORY_MASK } = require("devtools/client/performance/modules/global");
|
||||
var MANGLED_FN = "__Z3FooIiEvv";
|
||||
var UNMANGLED_FN = "void Foo<int>()";
|
||||
|
||||
function test() {
|
||||
let { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
|
||||
@ -94,12 +97,6 @@ function test() {
|
||||
"The .A.B node's percentage cell displays the correct value.");
|
||||
is($$sampl(2).textContent.trim(), "0",
|
||||
"The .A.B node's samples cell displays the correct value.");
|
||||
is($fun(".call-tree-name", $$(".call-tree-item")[2]).textContent.trim(), "B",
|
||||
"The .A.B node's function cell displays the correct name.");
|
||||
is($fun(".call-tree-url", $$(".call-tree-item")[2]).textContent.trim(), "baz",
|
||||
"The .A.B node's function cell displays the correct url.");
|
||||
ok($fun(".call-tree-url", $$(".call-tree-item")[2]).getAttribute("tooltiptext").includes("http://foo/bar/baz"),
|
||||
"The .A.B node's function cell displays the correct url tooltiptext.");
|
||||
is($fun(".call-tree-line", $$(".call-tree-item")[2]).textContent.trim(), ":34",
|
||||
"The .A.B node's function cell displays the correct line.");
|
||||
is($fun(".call-tree-host", $$(".call-tree-item")[2]).textContent.trim(), "foo",
|
||||
@ -107,6 +104,16 @@ function test() {
|
||||
is($fun(".call-tree-category", $$(".call-tree-item")[2]).textContent.trim(), "Styles",
|
||||
"The .A.B node's function cell displays the correct category.");
|
||||
|
||||
// Test demangling in the profiler tree
|
||||
is($fun(".call-tree-name", $$(".call-tree-item")[2]).textContent.trim(), UNMANGLED_FN,
|
||||
"The mangled function name is demangled.");
|
||||
ok($$(".call-tree-item")[2].getAttribute("tooltiptext").includes(MANGLED_FN),
|
||||
"The mangled node's row's tooltip contains the original mangled name.");
|
||||
is($fun(".call-tree-url", $$(".call-tree-item")[2]).textContent.trim(), "baz",
|
||||
"The mangled node's function cell displays the correct url.");
|
||||
ok($fun(".call-tree-url", $$(".call-tree-item")[2]).getAttribute("tooltiptext").includes("http://foo/bar/baz"),
|
||||
"The mangled node's function cell displays the url tooltiptext.");
|
||||
|
||||
is($$dur(3).textContent.trim(), "5 ms",
|
||||
"The .A.E node's duration cell displays the correct value.");
|
||||
is($$perc(3).textContent.trim(), "25%",
|
||||
@ -134,7 +141,7 @@ var gThread = synthesizeProfileForTest([{
|
||||
frames: [
|
||||
{ category: CATEGORY_MASK('other'), location: "(root)" },
|
||||
{ category: CATEGORY_MASK('other'), location: "A (http://foo/bar/baz:12)" },
|
||||
{ category: CATEGORY_MASK('css'), location: "B (http://foo/bar/baz:34)" },
|
||||
{ category: CATEGORY_MASK('css'), location: `${MANGLED_FN} (http://foo/bar/baz:34)` },
|
||||
{ category: CATEGORY_MASK('js'), location: "C (http://foo/bar/baz:56)" }
|
||||
]
|
||||
}, {
|
||||
@ -142,7 +149,7 @@ var gThread = synthesizeProfileForTest([{
|
||||
frames: [
|
||||
{ category: CATEGORY_MASK('other'), location: "(root)" },
|
||||
{ category: CATEGORY_MASK('other'), location: "A (http://foo/bar/baz:12)" },
|
||||
{ category: CATEGORY_MASK('css'), location: "B (http://foo/bar/baz:34)" },
|
||||
{ category: CATEGORY_MASK('css'), location: `${MANGLED_FN} (http://foo/bar/baz:34)` },
|
||||
{ category: CATEGORY_MASK('gc', 1), location: "D (http://foo/bar/baz:78)" }
|
||||
]
|
||||
}, {
|
||||
@ -150,7 +157,7 @@ var gThread = synthesizeProfileForTest([{
|
||||
frames: [
|
||||
{ category: CATEGORY_MASK('other'), location: "(root)" },
|
||||
{ category: CATEGORY_MASK('other'), location: "A (http://foo/bar/baz:12)" },
|
||||
{ category: CATEGORY_MASK('css'), location: "B (http://foo/bar/baz:34)" },
|
||||
{ category: CATEGORY_MASK('css'), location: `${MANGLED_FN} (http://foo/bar/baz:34)` },
|
||||
{ category: CATEGORY_MASK('gc', 1), location: "D (http://foo/bar/baz:78)" }
|
||||
]
|
||||
}, {
|
||||
|
62
devtools/client/shared/demangle.js
Normal file
62
devtools/client/shared/demangle.js
Normal file
File diff suppressed because one or more lines are too long
@ -20,6 +20,7 @@ DevToolsModules(
|
||||
'browser-loader.js',
|
||||
'css-parsing-utils.js',
|
||||
'Curl.jsm',
|
||||
'demangle.js',
|
||||
'DeveloperToolbar.jsm',
|
||||
'devices.js',
|
||||
'DOMHelpers.jsm',
|
||||
|
@ -6,7 +6,24 @@
|
||||
// Tests that the Filter Editor Widget parses filter values correctly (setCssValue)
|
||||
|
||||
const TEST_URI = "chrome://devtools/content/shared/widgets/filter-frame.xhtml";
|
||||
const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
|
||||
const {CSSFilterEditorWidget} =
|
||||
require("devtools/client/shared/widgets/FilterWidget");
|
||||
const {cssTokenizer} = require("devtools/client/shared/css-parsing-utils");
|
||||
const DOMUtils =
|
||||
Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
||||
|
||||
// Verify that the given string consists of a valid CSS URL token.
|
||||
// Return true on success, false on error.
|
||||
function verifyURL(string) {
|
||||
let lexer = DOMUtils.getCSSLexer(string);
|
||||
|
||||
let token = lexer.nextToken();
|
||||
if (!token || token.tokenType !== "url") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lexer.nextToken() === null;
|
||||
}
|
||||
|
||||
add_task(function *() {
|
||||
yield addTab("about:blank");
|
||||
@ -80,8 +97,18 @@ add_task(function *() {
|
||||
widget.setCssValue("url(ordinary)");
|
||||
is(widget.getCssValue(), "url(ordinary)",
|
||||
"setCssValue should not quote ordinary unquoted URL contents");
|
||||
widget.setCssValue("url(invalid\\ \\)\\ \\{\\ when\\ \\}\\ \\;\\ unquoted)");
|
||||
is(widget.getCssValue(),
|
||||
"url(invalid\\ \\)\\ \\{\\ when\\ \\}\\ \\;\\ unquoted)",
|
||||
|
||||
let quotedurl =
|
||||
"url(invalid\\ \\)\\ {\\\twhen\\ }\\ ;\\ \\\\unquoted\\'\\\")";
|
||||
ok(verifyURL(quotedurl), "weird URL is valid");
|
||||
widget.setCssValue(quotedurl);
|
||||
is(widget.getCssValue(), quotedurl,
|
||||
"setCssValue should re-quote weird unquoted URL contents");
|
||||
|
||||
let dataurl = "url(data:image/svg+xml;utf8,<svg\\ " +
|
||||
"xmlns=\\\"http://www.w3.org/2000/svg\\\"><filter\\ id=\\\"blur\\\">" +
|
||||
"<feGaussianBlur\\ stdDeviation=\\\"3\\\"/></filter></svg>#blur)";
|
||||
ok(verifyURL(dataurl), "data URL is valid");
|
||||
widget.setCssValue(dataurl);
|
||||
is(widget.getCssValue(), dataurl, "setCssValue should not mangle data urls");
|
||||
});
|
||||
|
@ -2,10 +2,12 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the text displayed is the function name, file name and line number
|
||||
// if applicable.
|
||||
// if applicable and demangling.
|
||||
|
||||
var {FlameGraphUtils} = require("devtools/client/shared/widgets/FlameGraph");
|
||||
var {PALLETTE_SIZE} = require("devtools/client/shared/widgets/FlameGraph");
|
||||
var MANGLED_FN = "__Z3FooIiEvv";
|
||||
var UNMANGLED_FN = "void Foo<int>()";
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab("about:blank");
|
||||
@ -49,7 +51,7 @@ var TEST_DATA = synthesizeProfileForTest([{
|
||||
frames: [{
|
||||
location: "A (http://path/to/file.js:10:5)"
|
||||
}, {
|
||||
location: "B (http://path/to/file.js:100:5)"
|
||||
location: `${MANGLED_FN} (http://path/to/file.js:100:5)`
|
||||
}],
|
||||
time: 50,
|
||||
}]);
|
||||
@ -76,31 +78,15 @@ var EXPECTED_OUTPUT = [{
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: [{
|
||||
startTime: 0,
|
||||
frameKey: "B (http://path/to/file.js:100:5)",
|
||||
frameKey: `${MANGLED_FN} (http://path/to/file.js:100:5)`,
|
||||
x: 0,
|
||||
y: 15,
|
||||
width: 50,
|
||||
height: 15,
|
||||
text: "B (file.js:100)"
|
||||
text: `${UNMANGLED_FN} (file.js:100)`
|
||||
}]
|
||||
}, {
|
||||
blocks: []
|
||||
@ -110,4 +96,20 @@ var EXPECTED_OUTPUT = [{
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}, {
|
||||
blocks: []
|
||||
}];
|
||||
|
@ -828,7 +828,7 @@ CSSFilterEditorWidget.prototype = {
|
||||
// Unquoted. This approach might change the original input -- for
|
||||
// example the original might be over-quoted. But, this is
|
||||
// correct and probably good enough.
|
||||
return filter.value.replace(/[ \t(){};]/g, "\\$&");
|
||||
return filter.value.replace(/[\\ \t()"']/g, "\\$&");
|
||||
},
|
||||
|
||||
removeAt: function(index) {
|
||||
|
@ -18,6 +18,8 @@ loader.lazyRequireGetter(this, "CATEGORY_MAPPINGS",
|
||||
"devtools/client/performance/modules/global", true);
|
||||
loader.lazyRequireGetter(this, "FrameUtils",
|
||||
"devtools/client/performance/modules/logic/frame-utils");
|
||||
loader.lazyRequireGetter(this, "demangle",
|
||||
"devtools/client/shared/demangle");
|
||||
|
||||
loader.lazyRequireGetter(this, "AbstractCanvasGraph",
|
||||
"devtools/client/shared/widgets/Graphs", true);
|
||||
@ -1242,7 +1244,7 @@ var FlameGraphUtils = {
|
||||
*/
|
||||
_formatLabel: function (key, frame) {
|
||||
let { functionName, fileName, line } = FrameUtils.parseLocation(key, frame.line);
|
||||
let label = functionName;
|
||||
let label = FrameUtils.shouldDemangle(functionName) ? demangle(functionName) : functionName;
|
||||
|
||||
if (fileName) {
|
||||
label += ` (${fileName}${line != null ? (":" + line) : ""})`;
|
||||
|
@ -64,12 +64,8 @@ var AnimationPlayerActor = ActorClass({
|
||||
/**
|
||||
* @param {AnimationsActor} The main AnimationsActor instance
|
||||
* @param {AnimationPlayer} The player object returned by getAnimationPlayers
|
||||
* @param {Number} Temporary work-around used to retrieve duration and
|
||||
* iteration count from computed-style rather than from waapi. This is needed
|
||||
* to know which duration to get, in case there are multiple css animations
|
||||
* applied to the same node.
|
||||
*/
|
||||
initialize: function(animationsActor, player, playerIndex) {
|
||||
initialize: function(animationsActor, player) {
|
||||
Actor.prototype.initialize.call(this, animationsActor.conn);
|
||||
|
||||
this.onAnimationMutation = this.onAnimationMutation.bind(this);
|
||||
@ -77,7 +73,6 @@ var AnimationPlayerActor = ActorClass({
|
||||
this.tabActor = animationsActor.tabActor;
|
||||
this.player = player;
|
||||
this.node = player.effect.target;
|
||||
this.playerIndex = playerIndex;
|
||||
|
||||
let win = this.node.ownerDocument.defaultView;
|
||||
this.styles = win.getComputedStyle(this.node);
|
||||
@ -133,42 +128,6 @@ var AnimationPlayerActor = ActorClass({
|
||||
return ANIMATION_TYPES.UNKNOWN;
|
||||
},
|
||||
|
||||
/**
|
||||
* Some of the player's properties are retrieved from the node's
|
||||
* computed-styles because the Web Animations API does not provide them yet.
|
||||
* But the computed-styles may contain multiple animations for a node and so
|
||||
* we need to know which is the index of the current animation in the style.
|
||||
* @return {Number}
|
||||
*/
|
||||
getPlayerIndex: function() {
|
||||
let names = this.styles.animationName;
|
||||
if (names === "none") {
|
||||
names = this.styles.transitionProperty;
|
||||
}
|
||||
|
||||
// If we still don't have a name, let's fall back to the provided index
|
||||
// which may, by now, be wrong, but it's the best we can do until the waapi
|
||||
// gives us a way to get duration, delay, ... directly.
|
||||
if (!names || names === "none") {
|
||||
return this.playerIndex;
|
||||
}
|
||||
|
||||
// If there's only one name.
|
||||
if (names.includes(",") === -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If there are several names, retrieve the index of the animation name in
|
||||
// the list.
|
||||
let playerName = this.getName();
|
||||
names = names.split(",").map(n => n.trim());
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
if (names[i] === playerName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the name associated with the player. This is used to match
|
||||
* up the player with values in the computed animation-name or
|
||||
@ -187,72 +146,29 @@ var AnimationPlayerActor = ActorClass({
|
||||
|
||||
/**
|
||||
* Get the animation duration from this player, in milliseconds.
|
||||
* Note that the Web Animations API doesn't yet offer a way to retrieve this
|
||||
* directly from the AnimationPlayer object, so for now, a duration is only
|
||||
* returned if found in the node's computed styles.
|
||||
* @return {Number}
|
||||
*/
|
||||
getDuration: function() {
|
||||
let durationText;
|
||||
if (this.styles.animationDuration !== "0s") {
|
||||
durationText = this.styles.animationDuration;
|
||||
} else if (this.styles.transitionDuration !== "0s") {
|
||||
durationText = this.styles.transitionDuration;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the computed duration has multiple entries, we need to find the right
|
||||
// one.
|
||||
if (durationText.indexOf(",") !== -1) {
|
||||
durationText = durationText.split(",")[this.getPlayerIndex()];
|
||||
}
|
||||
|
||||
return parseFloat(durationText) * 1000;
|
||||
return this.player.effect.getComputedTiming().duration;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the animation delay from this player, in milliseconds.
|
||||
* Note that the Web Animations API doesn't yet offer a way to retrieve this
|
||||
* directly from the AnimationPlayer object, so for now, a delay is only
|
||||
* returned if found in the node's computed styles.
|
||||
* @return {Number}
|
||||
*/
|
||||
getDelay: function() {
|
||||
let delayText;
|
||||
if (this.styles.animationDelay !== "0s") {
|
||||
delayText = this.styles.animationDelay;
|
||||
} else if (this.styles.transitionDelay !== "0s") {
|
||||
delayText = this.styles.transitionDelay;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (delayText.indexOf(",") !== -1) {
|
||||
delayText = delayText.split(",")[this.getPlayerIndex()];
|
||||
}
|
||||
|
||||
return parseFloat(delayText) * 1000;
|
||||
return this.player.effect.getComputedTiming().delay;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the animation iteration count for this player. That is, how many times
|
||||
* is the animation scheduled to run.
|
||||
* Note that the Web Animations API doesn't yet offer a way to retrieve this
|
||||
* directly from the AnimationPlayer object, so for now, check for
|
||||
* animationIterationCount in the node's computed styles, and return that.
|
||||
* This style property defaults to 1 anyway.
|
||||
* @return {Number}
|
||||
* @return {Number} The number of iterations, or null if the animation repeats
|
||||
* infinitely.
|
||||
*/
|
||||
getIterationCount: function() {
|
||||
let iterationText = this.styles.animationIterationCount;
|
||||
if (iterationText.indexOf(",") !== -1) {
|
||||
iterationText = iterationText.split(",")[this.getPlayerIndex()];
|
||||
}
|
||||
|
||||
return iterationText === "infinite"
|
||||
? null
|
||||
: parseInt(iterationText, 10);
|
||||
let iterations = this.player.effect.getComputedTiming().iterations;
|
||||
return iterations === "Infinity" ? null : iterations;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -606,9 +522,7 @@ var AnimationsActor = exports.AnimationsActor = ActorClass({
|
||||
// is assumed that the client is responsible for lifetimes of actors.
|
||||
this.actors = [];
|
||||
for (let i = 0; i < animations.length; i++) {
|
||||
// XXX: for now the index is passed along as the AnimationPlayerActor uses
|
||||
// it to retrieve animation information from CSS.
|
||||
let actor = AnimationPlayerActor(this, animations[i], i);
|
||||
let actor = AnimationPlayerActor(this, animations[i]);
|
||||
this.actors.push(actor);
|
||||
}
|
||||
|
||||
@ -686,8 +600,7 @@ var AnimationsActor = exports.AnimationsActor = ActorClass({
|
||||
this.actors.splice(index, 1);
|
||||
}
|
||||
|
||||
let actor = AnimationPlayerActor(
|
||||
this, player, player.effect.target.getAnimations().indexOf(player));
|
||||
let actor = AnimationPlayerActor(this, player);
|
||||
this.actors.push(actor);
|
||||
eventData.push({
|
||||
type: "added",
|
||||
|
@ -2149,7 +2149,7 @@ var WalkerActor = protocol.ActorClass({
|
||||
nodes = this._multiFrameQuerySelectorAll(query);
|
||||
}
|
||||
for (let node of nodes) {
|
||||
for (let className of node.className.split(" ")) {
|
||||
for (let className of node.classList) {
|
||||
sugs.classes.set(className, (sugs.classes.get(className)|0) + 1);
|
||||
}
|
||||
}
|
||||
@ -2218,7 +2218,7 @@ var WalkerActor = protocol.ActorClass({
|
||||
sugs.ids.set(node.id, (sugs.ids.get(node.id)|0) + 1);
|
||||
let tag = node.tagName.toLowerCase();
|
||||
sugs.tags.set(tag, (sugs.tags.get(tag)|0) + 1);
|
||||
for (let className of node.className.split(" ")) {
|
||||
for (let className of node.classList) {
|
||||
sugs.classes.set(className, (sugs.classes.get(className)|0) + 1);
|
||||
}
|
||||
}
|
||||
|
@ -699,7 +699,10 @@ public class BrowserApp extends GeckoApp
|
||||
mAccountsHelper = new AccountsHelper(appContext, getProfile());
|
||||
|
||||
if (AppConstants.MOZ_INSTALL_TRACKING) {
|
||||
AdjustConstants.getAdjustHelper().onCreate(this, AdjustConstants.MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN);
|
||||
final SharedPreferences prefs = GeckoSharedPrefs.forApp(this);
|
||||
if (prefs.getBoolean(GeckoPreferences.PREFS_HEALTHREPORT_UPLOAD_ENABLED, true)) {
|
||||
AdjustConstants.getAdjustHelper().onCreate(this, AdjustConstants.MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN);
|
||||
}
|
||||
}
|
||||
|
||||
if (AppConstants.MOZ_ANDROID_BEAM) {
|
||||
@ -900,9 +903,6 @@ public class BrowserApp extends GeckoApp
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// Needed for Adjust to get accurate session measurements
|
||||
AdjustConstants.getAdjustHelper().onResume(this);
|
||||
|
||||
final String args = ContextUtils.getStringExtra(getIntent(), "args");
|
||||
// If an external intent tries to start Fennec in guest mode, and it's not already
|
||||
// in guest mode, this will change modes before opening the url.
|
||||
@ -925,10 +925,6 @@ public class BrowserApp extends GeckoApp
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
// Needed for Adjust to get accurate session measurements
|
||||
AdjustConstants.getAdjustHelper().onPause(this);
|
||||
|
||||
// Register for Prompt:ShowTop so we can foreground this activity even if it's hidden.
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener) this,
|
||||
"Prompt:ShowTop");
|
||||
|
@ -5,12 +5,8 @@
|
||||
|
||||
package org.mozilla.gecko.adjust;
|
||||
|
||||
import org.mozilla.gecko.GeckoSharedPrefs;
|
||||
import org.mozilla.gecko.preferences.GeckoPreferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import com.adjust.sdk.Adjust;
|
||||
import com.adjust.sdk.AdjustConfig;
|
||||
@ -19,10 +15,6 @@ import com.adjust.sdk.LogLevel;
|
||||
|
||||
public class AdjustHelper implements AdjustHelperInterface {
|
||||
public void onCreate(final Context context, final String maybeAppToken) {
|
||||
if (isUserOptOut(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String environment;
|
||||
final String appToken;
|
||||
final LogLevel logLevel;
|
||||
@ -41,31 +33,6 @@ public class AdjustHelper implements AdjustHelperInterface {
|
||||
}
|
||||
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
if (isUserOptOut(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
new AdjustReferrerReceiver().onReceive(context, intent);
|
||||
}
|
||||
|
||||
public void onResume(final Context context) {
|
||||
if (isUserOptOut(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Adjust.onResume();
|
||||
}
|
||||
|
||||
public void onPause(final Context context) {
|
||||
if (isUserOptOut(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Adjust.onPause();
|
||||
}
|
||||
|
||||
private boolean isUserOptOut(final Context context) {
|
||||
final SharedPreferences prefs = GeckoSharedPrefs.forApp(context);
|
||||
return !prefs.getBoolean(GeckoPreferences.PREFS_HEALTHREPORT_UPLOAD_ENABLED, true);
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,4 @@ public interface AdjustHelperInterface {
|
||||
*/
|
||||
void onCreate(final Context context, final String appToken);
|
||||
void onReceive(final Context context, final Intent intent);
|
||||
void onResume(final Context context);
|
||||
void onPause(final Context context);
|
||||
}
|
||||
|
@ -16,12 +16,4 @@ public class StubAdjustHelper implements AdjustHelperInterface {
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
public void onResume(final Context context) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
public void onPause(final Context context) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,6 @@ OnSharedPreferenceChangeListener
|
||||
private static final String PREFS_CRASHREPORTER_ENABLED = "datareporting.crashreporter.submitEnabled";
|
||||
private static final String PREFS_MENU_CHAR_ENCODING = "browser.menu.showCharacterEncoding";
|
||||
private static final String PREFS_MP_ENABLED = "privacy.masterpassword.enabled";
|
||||
private static final String PREFS_ZOOMED_VIEW_ENABLED = "ui.zoomedview.enabled";
|
||||
private static final String PREFS_UPDATER_AUTODOWNLOAD = "app.update.autodownload";
|
||||
private static final String PREFS_UPDATER_URL = "app.update.url.android";
|
||||
private static final String PREFS_GEO_REPORTING = NON_PREF_PREFIX + "app.geo.reportdata";
|
||||
|
@ -31,13 +31,14 @@ constants_jar.extra_jars = [
|
||||
CONFIG['ANDROID_SUPPORT_ANNOTATIONS_JAR_LIB'],
|
||||
CONFIG['ANDROID_SUPPORT_V4_AAR_LIB'],
|
||||
CONFIG['ANDROID_SUPPORT_V4_AAR_INTERNAL_LIB'],
|
||||
CONFIG['ANDROID_APPCOMPAT_V7_AAR_LIB'],
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_INSTALL_TRACKING']:
|
||||
constants_jar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
||||
'adjust/AdjustHelper.java',
|
||||
]]
|
||||
constants_jar.extra_jars = [
|
||||
constants_jar.extra_jars += [
|
||||
'gecko-thirdparty-adjust_sdk.jar',
|
||||
]
|
||||
else:
|
||||
|
@ -65,7 +65,12 @@ stumbler_jars_dir := $(DEPTH)/mobile/android/stumbler
|
||||
ANDROID_CLASSPATH_JARS += \
|
||||
$(wildcard $(jars_dir)/*.jar) \
|
||||
$(wildcard $(stumbler_jars_dir)/*.jar) \
|
||||
$(NULL)
|
||||
# We don't have transitive dependencies: these are the browser jar
|
||||
# dependencies inserted manually.
|
||||
ANDROID_CLASSPATH_JARS += \
|
||||
$(ANDROID_SUPPORT_V4_AAR_LIB) \
|
||||
$(ANDROID_SUPPORT_V4_AAR_INTERNAL_LIB) \
|
||||
$(ANDROID_RECYCLERVIEW_V7_AAR_LIB) \
|
||||
$(ANDROID_APPCOMPAT_V7_AAR_LIB) \
|
||||
$(NULL)
|
||||
|
@ -343,6 +343,11 @@ int main(int argc, char **argv) {
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS)
|
||||
rv = mar_read_entire_file(DERFilePaths[k], MAR_MAX_CERT_SIZE,
|
||||
&certBuffers[k], &fileSizes[k]);
|
||||
|
||||
if (rv) {
|
||||
fprintf(stderr, "ERROR: could not read file %s", DERFilePaths[k]);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
/* It is somewhat circuitous to look up a CERTCertificate and then pass
|
||||
* in its DER encoding just so we can later re-create that
|
||||
@ -358,12 +363,10 @@ int main(int argc, char **argv) {
|
||||
fileSizes[k] = certs[k]->derCert.len;
|
||||
} else {
|
||||
rv = -1;
|
||||
}
|
||||
#endif
|
||||
if (rv) {
|
||||
fprintf(stderr, "ERROR: could not read file %s", DERFilePaths[k]);
|
||||
fprintf(stderr, "ERROR: could not find cert from nickname %s", certNames[k]);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!rv) {
|
||||
|
@ -16,9 +16,11 @@ var regexes = [
|
||||
/^loader\.lazyRequireGetter\(\w+, "(\w+)"/,
|
||||
/^loader\.lazyServiceGetter\(\w+, "(\w+)"/,
|
||||
/^XPCOMUtils\.defineLazyModuleGetter\(\w+, "(\w+)"/,
|
||||
/^DevToolsUtils\.defineLazyModuleGetter\(\w+, "(\w+)"/,
|
||||
/^loader\.lazyGetter\(\w+, "(\w+)"/,
|
||||
/^XPCOMUtils\.defineLazyGetter\(\w+, "(\w+)"/,
|
||||
/^XPCOMUtils\.defineLazyServiceGetter\(\w+, "(\w+)"/
|
||||
/^XPCOMUtils\.defineLazyServiceGetter\(\w+, "(\w+)"/,
|
||||
/^DevToolsUtils\.defineLazyGetter\(\w+, "(\w+)"/,
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
|
@ -4093,6 +4093,14 @@ XREMain::XRE_mainRun()
|
||||
file->AppendNative(NS_LITERAL_CSTRING("override.ini"));
|
||||
nsINIParser parser;
|
||||
nsresult rv = parser.Init(file);
|
||||
// if override.ini doesn't exist, also check for distribution.ini
|
||||
if (NS_FAILED(rv)) {
|
||||
bool persistent;
|
||||
mDirProvider.GetFile(XRE_APP_DISTRIBUTION_DIR, &persistent,
|
||||
getter_AddRefs(file));
|
||||
file->AppendNative(NS_LITERAL_CSTRING("distribution.ini"));
|
||||
rv = parser.Init(file);
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsAutoCString buf;
|
||||
rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
|
||||
|
Loading…
Reference in New Issue
Block a user