зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound.
This commit is contained in:
Коммит
d6257fa5cd
|
@ -13,7 +13,6 @@ const { exit, env, staticArgs } = require('../system');
|
|||
const { when: unload } = require('../system/unload');
|
||||
const { loadReason } = require('../self');
|
||||
const { rootURI } = require("@loader/options");
|
||||
const cfxArgs = require("@test/options");
|
||||
const globals = require('../system/globals');
|
||||
const xulApp = require('../system/xul-app');
|
||||
const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
|
||||
|
@ -102,11 +101,7 @@ function startup(reason, options) {
|
|||
// Run the addon even in case of error (best effort approach)
|
||||
require('../l10n/loader').
|
||||
load(rootURI).
|
||||
then(function l10nSuccess() {
|
||||
if (cfxArgs.parseable) {
|
||||
console.info("localization information has loaded successfully.");
|
||||
}
|
||||
}, function l10nFailure(error) {
|
||||
then(null, function failure(error) {
|
||||
console.info("Error while loading localization: " + error.message);
|
||||
}).
|
||||
then(function onLocalizationReady(data) {
|
||||
|
@ -115,10 +110,6 @@ function startup(reason, options) {
|
|||
definePseudo(options.loader, '@l10n/data', data ? data : null);
|
||||
return ready;
|
||||
}).then(function() {
|
||||
if (cfxArgs.parseable) {
|
||||
console.info("addon window has loaded successfully.");
|
||||
}
|
||||
|
||||
run(options);
|
||||
}).then(null, console.exception);
|
||||
}
|
||||
|
@ -137,7 +128,6 @@ function run(options) {
|
|||
catch(error) {
|
||||
console.exception(error);
|
||||
}
|
||||
|
||||
// Initialize inline options localization, without preventing addon to be
|
||||
// run in case of error
|
||||
try {
|
||||
|
@ -167,8 +157,7 @@ function run(options) {
|
|||
quit: exit
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
} catch (error) {
|
||||
console.exception(error);
|
||||
throw error;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
/* 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";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
var obsvc = require("../deprecated/observer-service");
|
||||
var { exit, stdout } = require("../system");
|
||||
var cfxArgs = require("@test/options");
|
||||
var { Cc, Ci} = require("chrome");
|
||||
|
||||
function runTests(findAndRunTests) {
|
||||
var harness = require("./harness");
|
||||
|
@ -62,7 +59,7 @@ function printFailedTests(tests, print) {
|
|||
iterationNumber++;
|
||||
|
||||
if (!singleIteration)
|
||||
print(" Iteration " + iterationNumber + ":\n");
|
||||
print(" Iteration " + iterationNumber + ":\n");
|
||||
|
||||
for each (let test in testRun) {
|
||||
if (test.failed > 0) {
|
||||
|
|
|
@ -48,6 +48,20 @@ const prototypeOf = Object.getPrototypeOf;
|
|||
const create = Object.create;
|
||||
const keys = Object.keys;
|
||||
|
||||
|
||||
const COMPONENT_ERROR = '`Components` is not available in this context.\n' +
|
||||
'Functionality provided by Components may be available in an SDK\n' +
|
||||
'module: https://jetpack.mozillalabs.com/sdk/latest/docs/ \n\n' +
|
||||
'However, if you still need to import Components, you may use the\n' +
|
||||
'`chrome` module\'s properties for shortcuts to Component properties:\n\n' +
|
||||
'Shortcuts: \n' +
|
||||
' Cc = Components' + '.classes \n' +
|
||||
' Ci = Components' + '.interfaces \n' +
|
||||
' Cu = Components' + '.utils \n' +
|
||||
' CC = Components' + '.Constructor \n' +
|
||||
'Example: \n' +
|
||||
' let { Cc, Ci } = require(\'chrome\');\n';
|
||||
|
||||
// Workaround for bug 674195. Freezing objects from other compartments fail,
|
||||
// so we use `Object.freeze` from the same component instead.
|
||||
function freeze(object) {
|
||||
|
@ -216,19 +230,26 @@ const load = iced(function load(loader, module) {
|
|||
let { sandboxes, globals } = loader;
|
||||
let require = Require(loader, module);
|
||||
|
||||
// We expose set of properties defined by `CommonJS` specification via
|
||||
// prototype of the sandbox. Also globals are deeper in the prototype
|
||||
// chain so that each module has access to them as well.
|
||||
let descriptors = descriptor({
|
||||
require: require,
|
||||
module: module,
|
||||
exports: module.exports,
|
||||
get Components() {
|
||||
// Expose `Components` property to throw error on usage with
|
||||
// additional information
|
||||
throw new ReferenceError(COMPONENT_ERROR);
|
||||
}
|
||||
});
|
||||
|
||||
let sandbox = sandboxes[module.uri] = Sandbox({
|
||||
name: module.uri,
|
||||
// Get an existing module sandbox, if any, so we can reuse its compartment
|
||||
// when creating the new one to reduce memory consumption.
|
||||
sandbox: sandboxes[keys(sandboxes).shift()],
|
||||
// We expose set of properties defined by `CommonJS` specification via
|
||||
// prototype of the sandbox. Also globals are deeper in the prototype
|
||||
// chain so that each module has access to them as well.
|
||||
prototype: create(globals, descriptor({
|
||||
require: require,
|
||||
module: module,
|
||||
exports: module.exports
|
||||
})),
|
||||
prototype: create(globals, descriptors),
|
||||
wantXrays: false
|
||||
});
|
||||
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
/* 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';
|
||||
|
||||
"use strict";
|
||||
const { List } = require('sdk/deprecated/list');
|
||||
|
||||
function assertList(test, array, list) {
|
||||
for (let i = 0, ii = array.length; i < ii; i < ii, i++) {
|
||||
test.assertEqual(
|
||||
function assertList(assert, array, list) {
|
||||
for (let i = 0, l = array.length; i < l; i++) {
|
||||
assert.equal(
|
||||
array.length,
|
||||
list.length,
|
||||
'list must contain same amount of elements as array'
|
||||
);
|
||||
test.assertEqual(
|
||||
assert.equal(
|
||||
'List(' + array + ')',
|
||||
list + '',
|
||||
'toString must output array like result'
|
||||
);
|
||||
test.assert(
|
||||
i in list,
|
||||
'must contain element with index: ' + i
|
||||
);
|
||||
test.assertEqual(
|
||||
assert.ok(i in list, 'must contain element with index: ' + i);
|
||||
assert.equal(
|
||||
array[i],
|
||||
list[i],
|
||||
'element with index: ' + i + ' should match'
|
||||
|
@ -28,89 +26,83 @@ function assertList(test, array, list) {
|
|||
}
|
||||
}
|
||||
|
||||
const { List } = require('sdk/deprecated/list');
|
||||
|
||||
exports['test:test for'] = function(test) {
|
||||
exports['test:test for'] = function(assert) {
|
||||
let fixture = List(3, 2, 1);
|
||||
|
||||
test.assertEqual(3, fixture.length, 'length is 3');
|
||||
assert.equal(3, fixture.length, 'length is 3');
|
||||
let i = 0;
|
||||
for (let key in fixture) {
|
||||
test.assertEqual(i++, key, 'key should match');
|
||||
assert.equal(i++, key, 'key should match');
|
||||
}
|
||||
};
|
||||
|
||||
exports['test:test for each'] = function(test) {
|
||||
exports['test:test for each'] = function(assert) {
|
||||
let fixture = new List(3, 2, 1);
|
||||
|
||||
test.assertEqual(3, fixture.length, 'length is 3');
|
||||
let i = 3;
|
||||
for each (let value in fixture) {
|
||||
test.assertEqual(i--, value, 'value should match');
|
||||
}
|
||||
};
|
||||
|
||||
exports['test:test for of'] = function(test) {
|
||||
let fixture = new List(3, 2, 1);
|
||||
|
||||
test.assertEqual(3, fixture.length, 'length is 3');
|
||||
assert.equal(3, fixture.length, 'length is 3');
|
||||
let i = 3;
|
||||
for (let value of fixture) {
|
||||
test.assertEqual(i--, value, 'value should match');
|
||||
assert.equal(i--, value, 'value should match');
|
||||
}
|
||||
};
|
||||
|
||||
exports['test:test toString'] = function(test) {
|
||||
exports['test:test for of'] = function(assert) {
|
||||
let fixture = new List(3, 2, 1);
|
||||
|
||||
assert.equal(3, fixture.length, 'length is 3');
|
||||
let i = 3;
|
||||
for (let value of fixture) {
|
||||
assert.equal(i--, value, 'value should match');
|
||||
}
|
||||
};
|
||||
|
||||
exports['test:test toString'] = function(assert) {
|
||||
let fixture = List(3, 2, 1);
|
||||
|
||||
test.assertEqual(
|
||||
assert.equal(
|
||||
'List(3,2,1)',
|
||||
fixture + '',
|
||||
'toString must output array like result'
|
||||
)
|
||||
};
|
||||
|
||||
exports['test:test constructor with apply'] = function(test) {
|
||||
exports['test:test constructor with apply'] = function(assert) {
|
||||
let array = ['a', 'b', 'c'];
|
||||
let fixture = List.apply(null, array);
|
||||
|
||||
test.assertEqual(
|
||||
assert.equal(
|
||||
3,
|
||||
fixture.length,
|
||||
'should have applied arguments'
|
||||
);
|
||||
};
|
||||
|
||||
exports['test:direct element access'] = function(test) {
|
||||
let array = [1, 'foo', 2, 'bar', {}, 'bar', function a() {}, test, 1];
|
||||
exports['test:direct element access'] = function(assert) {
|
||||
let array = [1, 'foo', 2, 'bar', {}, 'bar', function a() {}, assert, 1];
|
||||
let fixture = List.apply(null, array);
|
||||
array.splice(5, 1);
|
||||
array.splice(7, 1);
|
||||
|
||||
test.assertEqual(
|
||||
assert.equal(
|
||||
array.length,
|
||||
fixture.length,
|
||||
'list should omit duplicate elements'
|
||||
);
|
||||
|
||||
test.assertEqual(
|
||||
assert.equal(
|
||||
'List(' + array + ')',
|
||||
fixture.toString(),
|
||||
'elements should not be rearranged'
|
||||
);
|
||||
|
||||
for (let key in array) {
|
||||
test.assert(key in fixture,'should contain key for index:' + key);
|
||||
test.assertEqual(
|
||||
array[key],
|
||||
fixture[key],
|
||||
'values should match for: ' + key
|
||||
);
|
||||
assert.ok(key in fixture,'should contain key for index:' + key);
|
||||
assert.equal(array[key], fixture[key], 'values should match for: ' + key);
|
||||
}
|
||||
};
|
||||
|
||||
exports['test:removing adding elements'] = function(test) {
|
||||
let array = [1, 'foo', 2, 'bar', {}, 'bar', function a() {}, test, 1];
|
||||
exports['test:removing adding elements'] = function(assert) {
|
||||
let array = [1, 'foo', 2, 'bar', {}, 'bar', function a() {}, assert, 1];
|
||||
let fixture = List.compose({
|
||||
add: function() this._add.apply(this, arguments),
|
||||
remove: function() this._remove.apply(this, arguments),
|
||||
|
@ -119,11 +111,11 @@ exports['test:removing adding elements'] = function(test) {
|
|||
array.splice(5, 1);
|
||||
array.splice(7, 1);
|
||||
|
||||
assertList(test, array, fixture);
|
||||
assertList(assert, array, fixture);
|
||||
|
||||
array.splice(array.indexOf(2), 1);
|
||||
fixture.remove(2);
|
||||
assertList(test, array, fixture);
|
||||
assertList(assert, array, fixture);
|
||||
|
||||
array.splice(array.indexOf('foo'), 1);
|
||||
fixture.remove('foo');
|
||||
|
@ -131,11 +123,11 @@ exports['test:removing adding elements'] = function(test) {
|
|||
fixture.remove(1);
|
||||
array.push('foo');
|
||||
fixture.add('foo');
|
||||
assertList(test, array, fixture);
|
||||
assertList(assert, array, fixture);
|
||||
|
||||
array.splice(0);
|
||||
fixture.clear(0);
|
||||
assertList(test, array, fixture);
|
||||
assertList(assert, array, fixture);
|
||||
|
||||
array.push(1, 'foo', 2, 'bar', 3);
|
||||
fixture.add(1);
|
||||
|
@ -144,26 +136,26 @@ exports['test:removing adding elements'] = function(test) {
|
|||
fixture.add('bar');
|
||||
fixture.add(3);
|
||||
|
||||
assertList(test, array, fixture);
|
||||
assertList(assert, array, fixture);
|
||||
};
|
||||
|
||||
exports['test: remove does not leave invalid numerical properties'] = function(test) {
|
||||
exports['test: remove does not leave invalid numerical properties'] = function(assert) {
|
||||
let fixture = List.compose({
|
||||
remove: function() this._remove.apply(this, arguments),
|
||||
}).apply(null, [1, 2, 3]);
|
||||
|
||||
fixture.remove(1);
|
||||
test.assertEqual(fixture[fixture.length], undefined);
|
||||
assert.equal(fixture[fixture.length], undefined);
|
||||
}
|
||||
|
||||
exports['test:add list item from Iterator'] = function(test) {
|
||||
exports['test:add list item from Iterator'] = function(assert) {
|
||||
let array = [1, 2, 3, 4], sum = 0, added = false;
|
||||
|
||||
let fixture = List.compose({
|
||||
add: function() this._add.apply(this, arguments),
|
||||
}).apply(null, array);
|
||||
|
||||
for each (let item in fixture) {
|
||||
for (let item of fixture) {
|
||||
sum += item;
|
||||
|
||||
if (!added) {
|
||||
|
@ -172,35 +164,37 @@ exports['test:add list item from Iterator'] = function(test) {
|
|||
}
|
||||
}
|
||||
|
||||
test.assertEqual(sum, 1 + 2 + 3 + 4);
|
||||
assert.equal(sum, 1 + 2 + 3 + 4, 'sum = 1 + 2 + 3 + 4');
|
||||
};
|
||||
|
||||
exports['test:remove list item from Iterator'] = function(test) {
|
||||
exports['test:remove list item from Iterator'] = function(assert) {
|
||||
let array = [1, 2, 3, 4], sum = 0;
|
||||
|
||||
let fixture = List.compose({
|
||||
remove: function() this._remove.apply(this, arguments),
|
||||
}).apply(null, array);
|
||||
|
||||
for each (let item in fixture) {
|
||||
for (let item of fixture) {
|
||||
sum += item;
|
||||
fixture.remove(item);
|
||||
}
|
||||
|
||||
test.assertEqual(sum, 1 + 2 + 3 + 4);
|
||||
assert.equal(sum, 1 + 2 + 3 + 4, 'sum = 1 + 2 + 3 + 4');
|
||||
};
|
||||
|
||||
exports['test:clear list from Iterator'] = function(test) {
|
||||
exports['test:clear list from Iterator'] = function(assert) {
|
||||
let array = [1, 2, 3, 4], sum = 0;
|
||||
|
||||
let fixture = List.compose({
|
||||
clear: function() this._clear()
|
||||
}).apply(null, array);
|
||||
|
||||
for each (let item in fixture) {
|
||||
for (let item of fixture) {
|
||||
sum += item;
|
||||
fixture.clear();
|
||||
}
|
||||
|
||||
test.assertEqual(sum, 1 + 2 + 3 + 4);
|
||||
assert.equal(sum, 1 + 2 + 3 + 4, 'sum = 1 + 2 + 3 + 4');
|
||||
};
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
|
|
|
@ -7,17 +7,24 @@ Object.defineProperty(this, 'global', { value: this });
|
|||
|
||||
exports.testGlobals = function(assert) {
|
||||
// the only globals in module scope should be:
|
||||
assert.equal(typeof module, 'object', 'have "module" global');
|
||||
assert.equal(typeof exports, 'object', 'have "exports" global');
|
||||
assert.equal(typeof require, 'function', 'have "require" global');
|
||||
assert.equal(typeof dump, 'function', 'have "dump" global');
|
||||
assert.equal(typeof console, 'object', 'have "console" global');
|
||||
// module, exports, require, dump, console
|
||||
assert.equal(typeof module, 'object', 'have "module", good');
|
||||
assert.equal(typeof exports, 'object', 'have "exports", good');
|
||||
assert.equal(typeof require, 'function', 'have "require", good');
|
||||
assert.equal(typeof dump, 'function', 'have "dump", good');
|
||||
assert.equal(typeof console, 'object', 'have "console", good');
|
||||
|
||||
// in particular, these old globals should no longer be present
|
||||
assert.ok(!('packaging' in global), 'no "packaging" global was found');
|
||||
assert.ok(!('memory' in global), 'no "memory" global was found');
|
||||
|
||||
assert.ok(/test-globals\.js$/.test(module.uri), 'should contain filename');
|
||||
assert.ok(!('packaging' in global), "no 'packaging', good");
|
||||
assert.ok(!('memory' in global), "no 'memory', good");
|
||||
assert.ok(/test-globals\.js$/.test(module.uri),
|
||||
'should contain filename');
|
||||
};
|
||||
|
||||
require("test").run(exports);
|
||||
exports.testComponent = function (assert) {
|
||||
assert.throws(() => {
|
||||
Components;
|
||||
}, /`Components` is not available/, 'using `Components` throws');
|
||||
};
|
||||
|
||||
require('test').run(exports);
|
||||
|
|
|
@ -6,32 +6,32 @@
|
|||
const { List, addListItem, removeListItem } = require('sdk/util/list');
|
||||
const { Class } = require('sdk/core/heritage');
|
||||
|
||||
exports.testList = function(test) {
|
||||
exports.testList = function(assert) {
|
||||
let list = List();
|
||||
addListItem(list, 1);
|
||||
|
||||
for (let key in list) {
|
||||
test.assertEqual(key, 0, 'key is correct');
|
||||
test.assertEqual(list[key], 1, 'value is correct');
|
||||
assert.equal(key, 0, 'key is correct');
|
||||
assert.equal(list[key], 1, 'value is correct');
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
for each (let ele in list) {
|
||||
test.assertEqual(ele, 1, 'ele is correct');
|
||||
test.assertEqual(++count, 1, 'count is correct');
|
||||
assert.equal(ele, 1, 'ele is correct');
|
||||
assert.equal(++count, 1, 'count is correct');
|
||||
}
|
||||
|
||||
count = 0;
|
||||
for (let ele of list) {
|
||||
test.assertEqual(ele, 1, 'ele is correct');
|
||||
test.assertEqual(++count, 1, 'count is correct');
|
||||
assert.equal(ele, 1, 'ele is correct');
|
||||
assert.equal(++count, 1, 'count is correct');
|
||||
}
|
||||
|
||||
removeListItem(list, 1);
|
||||
test.assertEqual(list.length, 0, 'remove worked');
|
||||
assert.equal(list.length, 0, 'remove worked');
|
||||
};
|
||||
|
||||
exports.testImplementsList = function(test) {
|
||||
exports.testImplementsList = function(assert) {
|
||||
let List2 = Class({
|
||||
implements: [List],
|
||||
initialize: function() {
|
||||
|
@ -42,15 +42,17 @@ exports.testImplementsList = function(test) {
|
|||
let count = 0;
|
||||
|
||||
for each (let ele in list2) {
|
||||
test.assertEqual(ele, count++, 'ele is correct');
|
||||
assert.equal(ele, count++, 'ele is correct');
|
||||
}
|
||||
|
||||
count = 0;
|
||||
for (let ele of list2) {
|
||||
test.assertEqual(ele, count++, 'ele is correct');
|
||||
assert.equal(ele, count++, 'ele is correct');
|
||||
}
|
||||
|
||||
addListItem(list2, 3);
|
||||
test.assertEqual(list2.length, 4, '3 was added');
|
||||
test.assertEqual(list2[list2.length-1], 3, '3 was added');
|
||||
assert.equal(list2.length, 4, '3 was added');
|
||||
assert.equal(list2[list2.length-1], 3, '3 was added');
|
||||
}
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const tmp = require("sdk/test/tmp-file");
|
||||
const file = require("sdk/io/file");
|
||||
|
||||
const testFolderURL = module.uri.split('test-tmp-file.js')[0];
|
||||
|
||||
exports.testCreateFromString = function (test) {
|
||||
exports.testCreateFromString = function (assert) {
|
||||
let expectedContent = "foo";
|
||||
let path = tmp.createFromString(expectedContent);
|
||||
let content = file.read(path);
|
||||
test.assertEqual(content, expectedContent,
|
||||
"Temporary file contains the expected content");
|
||||
assert.equal(content, expectedContent,
|
||||
"Temporary file contains the expected content");
|
||||
}
|
||||
|
||||
exports.testCreateFromURL = function (test) {
|
||||
exports.testCreateFromURL = function (assert) {
|
||||
let url = testFolderURL + "test-tmp-file.txt";
|
||||
let path = tmp.createFromURL(url);
|
||||
let content = file.read(path);
|
||||
test.assertEqual(content, "foo",
|
||||
"Temporary file contains the expected content");
|
||||
assert.equal(content, "foo",
|
||||
"Temporary file contains the expected content");
|
||||
}
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
function createRootActor(connection)
|
||||
{
|
||||
let parameters = {
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
tabList: new ContentTabList(connection),
|
||||
#else
|
||||
tabList: [],
|
||||
#endif
|
||||
tabList: {
|
||||
getList: function() {
|
||||
return promise.resolve([]);
|
||||
}
|
||||
},
|
||||
globalActorFactories: DebuggerServer.globalActorFactories,
|
||||
onShutdown: sendShutdownEvent
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "abcc2f6a74c69d6ed28ea29681f86ef1f4fd90ba",
|
||||
"revision": "22cb357f03833f5ce63ba567c2fd4610a4c8061c",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -171,7 +171,7 @@ var tests = {
|
|||
domwindow.removeEventListener("load", _load, false);
|
||||
|
||||
domwindow.addEventListener("unload", function _close(event) {
|
||||
if (event.target != doc)
|
||||
if (event.target != doc)
|
||||
return;
|
||||
domwindow.removeEventListener("unload", _close, false);
|
||||
ok(true, "window has been closed");
|
||||
|
|
|
@ -466,7 +466,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
|
||||
let container = document.createElement("hbox");
|
||||
container.id = "breakpoint-" + aOptions.actor;
|
||||
container.className = "dbg-breakpoint side-menu-widget-item-other";
|
||||
container.className = "dbg-breakpoint devtools-monospace" +
|
||||
" side-menu-widget-item-other";
|
||||
container.setAttribute("align", "center");
|
||||
container.setAttribute("flex", "1");
|
||||
|
||||
|
@ -1429,7 +1430,7 @@ WatchExpressionsView.prototype = Heritage.extend(WidgetMethods, {
|
|||
arrowNode.className = "dbg-expression-arrow";
|
||||
|
||||
let inputNode = document.createElement("textbox");
|
||||
inputNode.className = "plain dbg-expression-input";
|
||||
inputNode.className = "plain dbg-expression-input devtools-monospace";
|
||||
inputNode.setAttribute("value", aAttachment.initialExpression);
|
||||
inputNode.setAttribute("flex", "1");
|
||||
|
||||
|
@ -2194,9 +2195,10 @@ LineResults.prototype = {
|
|||
let lineLength = 0;
|
||||
let firstMatch = null;
|
||||
|
||||
lineNumberNode.className = "plain dbg-results-line-number";
|
||||
lineNumberNode.className = "plain dbg-results-line-number devtools-monospace";
|
||||
lineNumberNode.setAttribute("value", aLineNumber + 1);
|
||||
lineContentsNode.className = "light list-widget-item dbg-results-line-contents";
|
||||
lineContentsNode.className = "light list-widget-item devtools-monospace" +
|
||||
" dbg-results-line-contents";
|
||||
lineContentsNode.setAttribute("flex", "1");
|
||||
|
||||
for (let chunk of this._store) {
|
||||
|
|
|
@ -347,35 +347,35 @@
|
|||
value="&debuggerUI.searchPanelOperators;"/>
|
||||
<hbox align="center">
|
||||
<button id="global-operator-button"
|
||||
class="searchbox-panel-operator-button"
|
||||
class="searchbox-panel-operator-button devtools-monospace"
|
||||
command="globalSearchCommand"/>
|
||||
<label id="global-operator-label"
|
||||
class="plain searchbox-panel-operator-label"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<button id="function-operator-button"
|
||||
class="searchbox-panel-operator-button"
|
||||
class="searchbox-panel-operator-button devtools-monospace"
|
||||
command="functionSearchCommand"/>
|
||||
<label id="function-operator-label"
|
||||
class="plain searchbox-panel-operator-label"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<button id="token-operator-button"
|
||||
class="searchbox-panel-operator-button"
|
||||
class="searchbox-panel-operator-button devtools-monospace"
|
||||
command="tokenSearchCommand"/>
|
||||
<label id="token-operator-label"
|
||||
class="plain searchbox-panel-operator-label"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<button id="line-operator-button"
|
||||
class="searchbox-panel-operator-button"
|
||||
class="searchbox-panel-operator-button devtools-monospace"
|
||||
command="lineSearchCommand"/>
|
||||
<label id="line-operator-label"
|
||||
class="plain searchbox-panel-operator-label"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<button id="variable-operator-button"
|
||||
class="searchbox-panel-operator-button"
|
||||
class="searchbox-panel-operator-button devtools-monospace"
|
||||
command="variableSearchCommand"/>
|
||||
<label id="variable-operator-label"
|
||||
class="plain searchbox-panel-operator-label"/>
|
||||
|
|
|
@ -15,7 +15,6 @@ body {
|
|||
|
||||
#header {
|
||||
-moz-box-sizing: border-box;
|
||||
font: 12px/16px monospace;
|
||||
width: 100%;
|
||||
padding: 6px 9px;
|
||||
display: -moz-box;
|
||||
|
@ -44,7 +43,6 @@ body {
|
|||
width: calc(100% - 2 * 10px);
|
||||
position: absolute;
|
||||
border-width: 1px;
|
||||
font: 10px/12px monospace;
|
||||
}
|
||||
|
||||
@media (min-width: 320px) {
|
||||
|
|
|
@ -65,11 +65,12 @@
|
|||
]]>
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/common.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/layoutview.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="view.css" type="text/css"/>
|
||||
|
||||
</head>
|
||||
<body class="theme-body">
|
||||
<body class="theme-body devtools-monospace">
|
||||
|
||||
<p id="header">
|
||||
<span id="element-size"></span>
|
||||
|
|
|
@ -22,6 +22,10 @@ function test() {
|
|||
getInplaceEditorForSpan: inplaceEditor
|
||||
} = devtools.require("devtools/shared/inplace-editor");
|
||||
|
||||
// Prevent intermittent "test exceeded the timeout threshold" since this is
|
||||
// a slow test: https://bugzilla.mozilla.org/show_bug.cgi?id=904953.
|
||||
requestLongerTimeout(2);
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Will hold the doc we're viewing
|
||||
|
|
|
@ -288,7 +288,7 @@
|
|||
<label class="plain tabpanel-summary-label"
|
||||
value="&netmonitorUI.summary.url;"/>
|
||||
<label id="headers-summary-url-value"
|
||||
class="plain tabpanel-summary-value"
|
||||
class="plain tabpanel-summary-value devtools-monospace"
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
|
@ -298,7 +298,7 @@
|
|||
<label class="plain tabpanel-summary-label"
|
||||
value="&netmonitorUI.summary.method;"/>
|
||||
<label id="headers-summary-method-value"
|
||||
class="plain tabpanel-summary-value"
|
||||
class="plain tabpanel-summary-value devtools-monospace"
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
|
@ -310,7 +310,7 @@
|
|||
<box id="headers-summary-status-circle"
|
||||
class="requests-menu-status"/>
|
||||
<label id="headers-summary-status-value"
|
||||
class="plain tabpanel-summary-value"
|
||||
class="plain tabpanel-summary-value devtools-monospace"
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
<button id="headers-summary-resend"
|
||||
|
@ -324,7 +324,7 @@
|
|||
<label class="plain tabpanel-summary-label"
|
||||
value="&netmonitorUI.summary.version;"/>
|
||||
<label id="headers-summary-version-value"
|
||||
class="plain tabpanel-summary-value"
|
||||
class="plain tabpanel-summary-value devtools-monospace"
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
|
@ -364,7 +364,7 @@
|
|||
<label class="plain tabpanel-summary-label"
|
||||
value="&netmonitorUI.response.name;"/>
|
||||
<label id="response-content-image-name-value"
|
||||
class="plain tabpanel-summary-value"
|
||||
class="plain tabpanel-summary-value devtools-monospace"
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
|
@ -372,7 +372,7 @@
|
|||
<label class="plain tabpanel-summary-label"
|
||||
value="&netmonitorUI.response.dimensions;"/>
|
||||
<label id="response-content-image-dimensions-value"
|
||||
class="plain tabpanel-summary-value"
|
||||
class="plain tabpanel-summary-value devtools-monospace"
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
|
@ -380,7 +380,7 @@
|
|||
<label class="plain tabpanel-summary-label"
|
||||
value="&netmonitorUI.response.mime;"/>
|
||||
<label id="response-content-image-mime-value"
|
||||
class="plain tabpanel-summary-value"
|
||||
class="plain tabpanel-summary-value devtools-monospace"
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
|
@ -388,7 +388,7 @@
|
|||
<label class="plain tabpanel-summary-label"
|
||||
value="&netmonitorUI.response.encoding;"/>
|
||||
<label id="response-content-image-encoding-value"
|
||||
class="plain tabpanel-summary-value"
|
||||
class="plain tabpanel-summary-value devtools-monospace"
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
|
|
|
@ -59,7 +59,8 @@ function AutocompletePopup(aDocument, aOptions = {})
|
|||
if (!this._panel) {
|
||||
this._panel = this._document.createElementNS(XUL_NS, "panel");
|
||||
this._panel.setAttribute("id", id);
|
||||
this._panel.className = "devtools-autocomplete-popup " + theme + "-theme";
|
||||
this._panel.className = "devtools-autocomplete-popup devtools-monospace "
|
||||
+ theme + "-theme";
|
||||
|
||||
this._panel.setAttribute("noautofocus", "true");
|
||||
this._panel.setAttribute("level", "top");
|
||||
|
|
|
@ -228,6 +228,7 @@ Messages.BaseMessage.prototype = {
|
|||
let body = doc.createElementNS(XUL_NS, "description");
|
||||
body.flex = 1;
|
||||
body.classList.add("webconsole-msg-body");
|
||||
body.classList.add("devtools-monospace");
|
||||
container.appendChild(body);
|
||||
|
||||
return container;
|
||||
|
|
|
@ -2319,6 +2319,7 @@ WebConsoleFrame.prototype = {
|
|||
let bodyNode = this.document.createElementNS(XUL_NS, "description");
|
||||
bodyNode.flex = 1;
|
||||
bodyNode.classList.add("webconsole-msg-body");
|
||||
bodyNode.classList.add("devtools-monospace");
|
||||
|
||||
// Store the body text, since it is needed later for the variables view.
|
||||
let body = aBody;
|
||||
|
@ -2365,6 +2366,8 @@ WebConsoleFrame.prototype = {
|
|||
// Create the timestamp.
|
||||
let timestampNode = this.document.createElementNS(XUL_NS, "label");
|
||||
timestampNode.classList.add("webconsole-timestamp");
|
||||
timestampNode.classList.add("devtools-monospace");
|
||||
|
||||
let timestamp = aTimeStamp || Date.now();
|
||||
let timestampString = l10n.timestampString(timestamp);
|
||||
timestampNode.setAttribute("value", timestampString);
|
||||
|
@ -2589,6 +2592,7 @@ WebConsoleFrame.prototype = {
|
|||
locationNode.setAttribute("tooltiptext", aSourceURL);
|
||||
locationNode.classList.add("webconsole-location");
|
||||
locationNode.classList.add("text-link");
|
||||
locationNode.classList.add("devtools-monospace");
|
||||
|
||||
// Make the location clickable.
|
||||
locationNode.addEventListener("click", () => {
|
||||
|
|
|
@ -169,9 +169,10 @@ function goUpdateConsoleCommands() {
|
|||
|
||||
<hbox class="jsterm-input-container" style="direction:ltr">
|
||||
<stack class="jsterm-stack-node" flex="1">
|
||||
<textbox class="jsterm-complete-node" multiline="true" rows="1"
|
||||
tabindex="-1"/>
|
||||
<textbox class="jsterm-input-node" multiline="true" rows="1" tabindex="0"/>
|
||||
<textbox class="jsterm-complete-node devtools-monospace"
|
||||
multiline="true" rows="1" tabindex="-1"/>
|
||||
<textbox class="jsterm-input-node devtools-monospace"
|
||||
multiline="true" rows="1" tabindex="0"/>
|
||||
</stack>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
|
|
@ -598,7 +598,7 @@ var BrowserUI = {
|
|||
}
|
||||
break;
|
||||
case "metro_viewstate_changed":
|
||||
this._adjustDOMforViewState();
|
||||
this._adjustDOMforViewState(aData);
|
||||
if (aData == "snapped") {
|
||||
FlyoutPanelsUI.hide();
|
||||
Elements.autocomplete.setAttribute("orient", "vertical");
|
||||
|
@ -646,9 +646,9 @@ var BrowserUI = {
|
|||
pullDesktopControlledPrefType(Ci.nsIPrefBranch.PREF_STRING, "setCharPref");
|
||||
},
|
||||
|
||||
_adjustDOMforViewState: function() {
|
||||
if (MetroUtils.immersive) {
|
||||
let currViewState = "";
|
||||
_adjustDOMforViewState: function(aState) {
|
||||
let currViewState = aState;
|
||||
if (!currViewState && MetroUtils.immersive) {
|
||||
switch (MetroUtils.snappedState) {
|
||||
case Ci.nsIWinMetroUtils.fullScreenLandscape:
|
||||
currViewState = "landscape";
|
||||
|
@ -663,8 +663,9 @@ var BrowserUI = {
|
|||
currViewState = "snapped";
|
||||
break;
|
||||
}
|
||||
Elements.windowState.setAttribute("viewstate", currViewState);
|
||||
}
|
||||
|
||||
Elements.windowState.setAttribute("viewstate", currViewState);
|
||||
},
|
||||
|
||||
_titleChanged: function(aBrowser) {
|
||||
|
|
|
@ -415,8 +415,7 @@
|
|||
|
||||
#if MOZ_UPDATE_CHANNEL != release
|
||||
#ifdef MOZ_UPDATER
|
||||
<description class="text-blurb" id="currentChannelText">&channel.description.start;<label id="currentChannel"/></description>
|
||||
<description class="text-blurb" id="currentChannelText2">&channel.description.end;</description>
|
||||
<description class="text-blurb" id="currentChannelText">&channel.description.start;<label id="currentChannel"/>&channel.description.end;</description>
|
||||
#endif
|
||||
#endif
|
||||
<label id="about-policy-label"
|
||||
|
|
|
@ -109,9 +109,9 @@ var StartUI = {
|
|||
}
|
||||
},
|
||||
|
||||
_adjustDOMforViewState: function() {
|
||||
if (this.chromeWin.MetroUtils.immersive) {
|
||||
let currViewState = "";
|
||||
_adjustDOMforViewState: function(aState) {
|
||||
let currViewState = aState;
|
||||
if (!currViewState && this.chromeWin.MetroUtils.immersive) {
|
||||
switch (this.chromeWin.MetroUtils.snappedState) {
|
||||
case Ci.nsIWinMetroUtils.fullScreenLandscape:
|
||||
currViewState = "landscape";
|
||||
|
@ -126,19 +126,20 @@ var StartUI = {
|
|||
currViewState = "snapped";
|
||||
break;
|
||||
}
|
||||
document.getElementById("bcast_windowState").setAttribute("viewstate", currViewState);
|
||||
if (currViewState == "snapped") {
|
||||
document.getElementById("start-topsites-grid").removeAttribute("tiletype");
|
||||
} else {
|
||||
document.getElementById("start-topsites-grid").setAttribute("tiletype", "thumbnail");
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("bcast_windowState").setAttribute("viewstate", currViewState);
|
||||
if (currViewState == "snapped") {
|
||||
document.getElementById("start-topsites-grid").removeAttribute("tiletype");
|
||||
} else {
|
||||
document.getElementById("start-topsites-grid").setAttribute("tiletype", "thumbnail");
|
||||
}
|
||||
},
|
||||
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "metro_viewstate_changed":
|
||||
this._adjustDOMforViewState();
|
||||
this._adjustDOMforViewState(aData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,11 @@ include $(DEPTH)/config/autoconf.mk
|
|||
|
||||
MOCHITEST_METRO_FILES = \
|
||||
head.js \
|
||||
browser_urlbar.js \
|
||||
helpers/ViewStateHelper.js \
|
||||
browser_bookmarks.js \
|
||||
browser_canonizeURL.js \
|
||||
browser_circular_progress_indicator.js \
|
||||
browser_crashprompt.js \
|
||||
browser_context_menu_tests.js \
|
||||
browser_context_menu_tests_01.html \
|
||||
browser_context_menu_tests_02.html \
|
||||
|
@ -25,21 +26,22 @@ MOCHITEST_METRO_FILES = \
|
|||
browser_downloads.js \
|
||||
browser_findbar.js \
|
||||
browser_findbar.html \
|
||||
browser_form_auto_complete.js \
|
||||
browser_form_auto_complete.html \
|
||||
browser_history.js \
|
||||
browser_inputsource.js \
|
||||
browser_onscreen_keyboard.js \
|
||||
browser_onscreen_keyboard.html \
|
||||
browser_prefs_ui.js \
|
||||
browser_progress_indicator.xul \
|
||||
browser_remotetabs.js \
|
||||
browser_snappedState.js \
|
||||
browser_tabs.js \
|
||||
browser_test.js \
|
||||
browser_tiles.js \
|
||||
browser_tilegrid.xul \
|
||||
browser_topsites.js \
|
||||
browser_form_auto_complete.js \
|
||||
browser_form_auto_complete.html \
|
||||
browser_crashprompt.js \
|
||||
browser_inputsource.js \
|
||||
browser_urlbar.js \
|
||||
$(NULL)
|
||||
|
||||
ifndef MOZ_DEBUG
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var gStartDoc = null;
|
||||
|
||||
function test() {
|
||||
if (!isLandscapeMode()) {
|
||||
todo(false, "browser_snapped_tests need landscape mode to run.");
|
||||
return;
|
||||
}
|
||||
|
||||
runTests();
|
||||
}
|
||||
|
||||
function showStartUI() {
|
||||
if (!BrowserUI.isStartTabVisible) {
|
||||
let tab = yield addTab("about:start");
|
||||
gStartDoc = tab.browser.contentWindow.document;
|
||||
} else {
|
||||
gStartDoc = Browser.selectedBrowser.contentWindow.document;
|
||||
}
|
||||
}
|
||||
|
||||
function setUpSnapped() {
|
||||
yield showStartUI();
|
||||
yield setSnappedViewstate();
|
||||
}
|
||||
|
||||
function setUpPortrait() {
|
||||
yield showStartUI();
|
||||
yield setPortraitViewstate();
|
||||
}
|
||||
|
||||
function getNarrowTitle(aVboxId) {
|
||||
let vbox = gStartDoc.getElementById(aVboxId);
|
||||
return vbox.querySelector(".narrow-title");
|
||||
}
|
||||
|
||||
function narrowTitleVisible(aVboxId) {
|
||||
let title = getNarrowTitle(aVboxId);
|
||||
let display = getComputedStyle(title).getPropertyValue("display");
|
||||
|
||||
return display !== "none";
|
||||
}
|
||||
|
||||
function wideTitleVisible(aVboxId) {
|
||||
let vbox = gStartDoc.getElementById(aVboxId);
|
||||
let title = vbox.querySelector(".wide-title");
|
||||
let display = getComputedStyle(title).getPropertyValue("display");
|
||||
|
||||
return display !== "none";
|
||||
}
|
||||
|
||||
gTests.push({
|
||||
desc: "Test Snapped titles",
|
||||
setUp: setUpSnapped,
|
||||
run: function() {
|
||||
ok(narrowTitleVisible("start-topsites"), "topsites narrow title is visible");
|
||||
ok(narrowTitleVisible("start-bookmarks"), "bookmarks narrow title is visible");
|
||||
ok(narrowTitleVisible("start-history"), "history narrow title is visible");
|
||||
|
||||
ok(!wideTitleVisible("start-topsites"), "topsites wide title is not visible");
|
||||
ok(!wideTitleVisible("start-bookmarks"), "bookmarks wide title is not visible");
|
||||
ok(!wideTitleVisible("start-history"), "history wide title is not visible");
|
||||
},
|
||||
tearDown: restoreViewstate
|
||||
});
|
||||
|
||||
gTests.push({
|
||||
desc: "Test Snapped titles",
|
||||
setUp: setUpSnapped,
|
||||
run: function() {
|
||||
let topsites = gStartDoc.getElementById("start-topsites");
|
||||
let bookmarks = gStartDoc.getElementById("start-bookmarks");
|
||||
let history = gStartDoc.getElementById("start-history");
|
||||
|
||||
ok(topsites.hasAttribute("expanded"), "topsites is expanded");
|
||||
ok(!bookmarks.hasAttribute("expanded"), "bookmarks is collapsed");
|
||||
ok(!history.hasAttribute("expanded"), "history is collapsed");
|
||||
|
||||
// Expand bookmarks
|
||||
sendElementTap(Browser.selectedBrowser.contentWindow, getNarrowTitle("start-bookmarks"));
|
||||
|
||||
yield waitForCondition(() => bookmarks.hasAttribute("expanded"));
|
||||
|
||||
ok(!topsites.hasAttribute("expanded"), "topsites is collapsed");
|
||||
ok(bookmarks.hasAttribute("expanded"), "bookmarks is expanded");
|
||||
ok(!history.hasAttribute("expanded"), "history is collapsed");
|
||||
},
|
||||
tearDown: restoreViewstate
|
||||
});
|
||||
|
||||
gTests.push({
|
||||
desc: "Test Snapped scrolls vertically",
|
||||
setUp: setUpSnapped,
|
||||
run: function() {
|
||||
todo(false, "We need to populate startUI to verify that it's scrollable");
|
||||
},
|
||||
tearDown: restoreViewstate
|
||||
});
|
||||
|
||||
gTests.push({
|
||||
desc: "Test Portrait titles",
|
||||
setUp: setUpPortrait,
|
||||
run: function() {
|
||||
// Check title visibility
|
||||
ok(!narrowTitleVisible("start-topsites"), "topsites narrow title is not visible");
|
||||
ok(!narrowTitleVisible("start-bookmarks"), "bookmarks narrow title is not visible");
|
||||
ok(!narrowTitleVisible("start-history"), "history narrow title is not visible");
|
||||
|
||||
ok(wideTitleVisible("start-topsites"), "topsites wide title is visible");
|
||||
ok(wideTitleVisible("start-bookmarks"), "bookmarks wide title is visible");
|
||||
ok(wideTitleVisible("start-history"), "history wide title is visible");
|
||||
},
|
||||
tearDown: restoreViewstate
|
||||
});
|
|
@ -18,6 +18,27 @@ const chromeRoot = getRootDirectory(gTestPath);
|
|||
const kDefaultWait = 2000;
|
||||
const kDefaultInterval = 50;
|
||||
|
||||
/*=============================================================================
|
||||
Load Helpers
|
||||
=============================================================================*/
|
||||
|
||||
let splitPath = chromeRoot.split('/');
|
||||
if (!splitPath[splitPath.length-1]) {
|
||||
splitPath.pop();
|
||||
}
|
||||
// ../mochitest to make sure we're looking for the libs on the right path
|
||||
// even for mochiperf tests.
|
||||
splitPath.pop();
|
||||
splitPath.push('mochitest');
|
||||
|
||||
const mochitestPath = splitPath.join('/') + '/';
|
||||
|
||||
[
|
||||
"ViewStateHelper.js"
|
||||
].forEach(function(lib) {
|
||||
Services.scriptloader.loadSubScript(mochitestPath + lib, this);
|
||||
}, this);
|
||||
|
||||
/*=============================================================================
|
||||
Metro ui helpers
|
||||
=============================================================================*/
|
||||
|
@ -147,7 +168,7 @@ function getSelection(aElement) {
|
|||
|
||||
// browser
|
||||
return aElement.contentWindow.getSelection();
|
||||
};
|
||||
}
|
||||
|
||||
function getTrimmedSelection(aElement) {
|
||||
let sel = getSelection(aElement);
|
||||
|
@ -841,7 +862,7 @@ function stubMethod(aObj, aMethod) {
|
|||
let func = function() {
|
||||
func.calledWith = Array.slice(arguments);
|
||||
func.callCount++;
|
||||
}
|
||||
};
|
||||
func.callCount = 0;
|
||||
func.restore = function() {
|
||||
return (aObj[aMethod] = origFunc);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const snappedSize = 330;
|
||||
const portraitSize = 660;
|
||||
|
||||
function setSnappedViewstate() {
|
||||
ok(isLandscapeMode(), "setSnappedViewstate expects landscape mode to work.");
|
||||
|
||||
// Communicate viewstate change
|
||||
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'snapped');
|
||||
|
||||
let browser = Browser.selectedBrowser;
|
||||
|
||||
// Reduce browser width to simulate small screen size.
|
||||
let fullWidth = browser.clientWidth;
|
||||
let padding = fullWidth - snappedSize;
|
||||
|
||||
browser.style.borderRight = padding + "px solid gray";
|
||||
|
||||
// Make sure it renders the new mode properly
|
||||
yield waitForMs(0);
|
||||
}
|
||||
|
||||
function setPortraitViewstate() {
|
||||
ok(isLandscapeMode(), "setPortraitViewstate expects landscape mode to work.");
|
||||
|
||||
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'portrait');
|
||||
|
||||
let browser = Browser.selectedBrowser;
|
||||
|
||||
let fullWidth = browser.clientWidth;
|
||||
let padding = fullWidth - portraitSize;
|
||||
|
||||
browser.style.borderRight = padding + "px solid gray";
|
||||
|
||||
// Make sure it renders the new mode properly
|
||||
yield waitForMs(0);
|
||||
}
|
||||
|
||||
function restoreViewstate() {
|
||||
ok(isLandscapeMode(), "restoreViewstate expects landscape mode to work.");
|
||||
|
||||
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'landscape');
|
||||
|
||||
Browser.selectedBrowser.style.removeProperty("border-right");
|
||||
|
||||
yield waitForMs(0);
|
||||
}
|
|
@ -792,3 +792,8 @@ appbar toolbar[labelled] toolbarbutton > .toolbarbutton-text {
|
|||
.appbar-secondary {
|
||||
list-style-image: url(chrome://browser/skin/images/appbar-icons.png);
|
||||
}
|
||||
|
||||
.flyout-narrow description,
|
||||
.flyout-narrow label {
|
||||
max-width: 266px; /* Accounts for a 40px padding on each side of the flyout */
|
||||
}
|
||||
|
|
|
@ -455,10 +455,10 @@ SocialErrorListener.prototype = {
|
|||
},
|
||||
|
||||
onLocationChange: function SPL_onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
|
||||
let failure = aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE;
|
||||
if (failure && Social.provider.errorState != "frameworker-error") {
|
||||
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
|
||||
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
|
||||
Social.provider.errorState = "content-error";
|
||||
if (!Social.provider.errorState)
|
||||
Social.provider.errorState = "content-error";
|
||||
schedule(function() {
|
||||
this.setErrorMessage(aWebProgress.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler);
|
||||
|
|
|
@ -114,9 +114,15 @@ this.webappsUI = {
|
|||
|
||||
DOMApplicationRegistry.confirmInstall(aData, false, localDir, null,
|
||||
function (aManifest) {
|
||||
if (WebappsInstaller.install(aData, aManifest)) {
|
||||
installationSuccessNotification(aData, app, chromeWin);
|
||||
}
|
||||
WebappsInstaller.install(aData, aManifest).then(
|
||||
function() {
|
||||
installationSuccessNotification(aData, app, chromeWin);
|
||||
},
|
||||
function(error) {
|
||||
Cu.reportError("Error installing webapp: " + error);
|
||||
// TODO: Notify user that the installation has failed
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
.devtools-monospace {
|
||||
font-family: monospace;
|
||||
font-size: 85%;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/* Toolbar and Toolbar items */
|
||||
|
|
|
@ -132,7 +132,6 @@
|
|||
/* Sources and breakpoints view */
|
||||
|
||||
.dbg-breakpoint {
|
||||
font-family: monospace;
|
||||
-moz-margin-start: -14px;
|
||||
}
|
||||
|
||||
|
@ -164,7 +163,6 @@
|
|||
|
||||
.dbg-expression-input {
|
||||
-moz-padding-start: 2px !important;
|
||||
font-family: Menlo, Monaco, monospace;
|
||||
}
|
||||
|
||||
/* Searchbox and the search operations help panel */
|
||||
|
@ -191,7 +189,6 @@
|
|||
-moz-margin-start: 2px;
|
||||
-moz-margin-end: 6px;
|
||||
text-align: center;
|
||||
font-family: Menlo, Monaco, monospace;
|
||||
}
|
||||
|
||||
.searchbox-panel-operator-label {
|
||||
|
@ -289,7 +286,6 @@
|
|||
-moz-padding-end: 4px;
|
||||
padding-top: 2px;
|
||||
text-align: end;
|
||||
font-family: monospace;
|
||||
color: #8c8c8c;
|
||||
}
|
||||
|
||||
|
@ -297,7 +293,6 @@
|
|||
-moz-padding-start: 4px;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.dbg-results-line-contents-string {
|
||||
|
|
|
@ -8,7 +8,7 @@ body {
|
|||
}
|
||||
|
||||
#all-fonts {
|
||||
padding: 0 5px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,7 @@ body {
|
|||
}
|
||||
|
||||
.font {
|
||||
padding: 10px 5px;
|
||||
font-size: 0;
|
||||
padding: 10px 10px;
|
||||
}
|
||||
|
||||
.theme-dark .font {
|
||||
|
@ -51,7 +50,6 @@ body {
|
|||
}
|
||||
|
||||
.font-info {
|
||||
font-size: 1rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
|
|
@ -365,7 +365,6 @@ box.requests-menu-status[code^="5"] {
|
|||
|
||||
.tabpanel-summary-value {
|
||||
-moz-padding-start: 3px;
|
||||
font-family: Menlo, Monaco, monospace;
|
||||
}
|
||||
|
||||
.variable-or-property:not(:focus) > .title > .token-string {
|
||||
|
|
|
@ -4,20 +4,6 @@
|
|||
|
||||
%include ../../shared/devtools/webconsole.inc.css
|
||||
|
||||
.webconsole-timestamp,
|
||||
.webconsole-msg-body {
|
||||
font-family: "DejaVu Sans Mono", monospace;
|
||||
}
|
||||
|
||||
.jsterm-input-node,
|
||||
.jsterm-complete-node {
|
||||
font: 0.9em "DejaVu Sans Mono", monospace;
|
||||
}
|
||||
|
||||
.hud-output-node {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.jsterm-input-node {
|
||||
width: 98%;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
.devtools-monospace {
|
||||
font-family: monospace;
|
||||
font-size: 108%;
|
||||
}
|
||||
|
||||
/* Toolbar and Toolbar items */
|
||||
|
|
|
@ -130,7 +130,6 @@
|
|||
/* Sources and breakpoints view */
|
||||
|
||||
.dbg-breakpoint {
|
||||
font-family: monospace;
|
||||
-moz-margin-start: -14px;
|
||||
}
|
||||
|
||||
|
@ -162,7 +161,6 @@
|
|||
|
||||
.dbg-expression-input {
|
||||
-moz-padding-start: 2px !important;
|
||||
font-family: Menlo, Monaco, monospace;
|
||||
}
|
||||
|
||||
/* Searchbox and the search operations help panel */
|
||||
|
@ -189,7 +187,6 @@
|
|||
-moz-margin-start: 2px;
|
||||
-moz-margin-end: 6px;
|
||||
text-align: center;
|
||||
font-family: Menlo, Monaco, monospace;
|
||||
}
|
||||
|
||||
.searchbox-panel-operator-label {
|
||||
|
@ -287,7 +284,6 @@
|
|||
-moz-padding-end: 4px;
|
||||
padding-top: 2px;
|
||||
text-align: end;
|
||||
font-family: monospace;
|
||||
color: #8c8c8c;
|
||||
}
|
||||
|
||||
|
@ -295,7 +291,6 @@
|
|||
-moz-padding-start: 4px;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.dbg-results-line-contents-string {
|
||||
|
|
|
@ -8,7 +8,7 @@ body {
|
|||
}
|
||||
|
||||
#all-fonts {
|
||||
padding: 0 5px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,7 @@ body {
|
|||
}
|
||||
|
||||
.font {
|
||||
padding: 10px 5px;
|
||||
font-size: 0;
|
||||
padding: 10px 10px;
|
||||
}
|
||||
|
||||
.theme-dark .font {
|
||||
|
@ -51,7 +50,6 @@ body {
|
|||
}
|
||||
|
||||
.font-info {
|
||||
font-size: 1rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
|
|
@ -365,7 +365,6 @@ box.requests-menu-status[code^="5"] {
|
|||
|
||||
.tabpanel-summary-value {
|
||||
-moz-padding-start: 3px;
|
||||
font-family: Menlo, Monaco, monospace;
|
||||
}
|
||||
|
||||
.variable-or-property:not(:focus) > .title > .token-string {
|
||||
|
|
|
@ -3,16 +3,4 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%include ../shared.inc
|
||||
%include ../../shared/devtools/webconsole.inc.css
|
||||
|
||||
/* General output styles */
|
||||
|
||||
.webconsole-timestamp,
|
||||
.webconsole-msg-body {
|
||||
font-family: Menlo, Monaco, monospace;
|
||||
}
|
||||
|
||||
.jsterm-input-node,
|
||||
.jsterm-complete-node {
|
||||
font: 1em Menlo, Monaco, monospace;
|
||||
}
|
||||
%include ../../shared/devtools/webconsole.inc.css
|
|
@ -8,7 +8,6 @@
|
|||
color: GrayText;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.hud-msg-node {
|
||||
|
@ -33,7 +32,6 @@
|
|||
-moz-margin-start: 3px;
|
||||
-moz-margin-end: 6px;
|
||||
white-space: pre-wrap;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.webconsole-msg-body-piece {
|
||||
|
@ -93,11 +91,6 @@
|
|||
background: white;
|
||||
}
|
||||
|
||||
.jsterm-input-node,
|
||||
.jsterm-complete-node {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.hud-output-node {
|
||||
-moz-appearance: none;
|
||||
border-bottom: 1px solid ThreeDShadow;
|
||||
|
|
|
@ -128,7 +128,6 @@
|
|||
/* Sources and breakpoints view */
|
||||
|
||||
.dbg-breakpoint {
|
||||
font-family: monospace;
|
||||
-moz-margin-start: -14px;
|
||||
}
|
||||
|
||||
|
@ -160,7 +159,6 @@
|
|||
|
||||
.dbg-expression-input {
|
||||
-moz-padding-start: 2px !important;
|
||||
font-family: Menlo, Monaco, monospace;
|
||||
}
|
||||
|
||||
/* Searchbox and the search operations help panel */
|
||||
|
@ -187,7 +185,6 @@
|
|||
-moz-margin-start: 2px;
|
||||
-moz-margin-end: 6px;
|
||||
text-align: center;
|
||||
font-family: Menlo, Monaco, monospace;
|
||||
}
|
||||
|
||||
.searchbox-panel-operator-label {
|
||||
|
@ -285,7 +282,6 @@
|
|||
-moz-padding-end: 4px;
|
||||
padding-top: 2px;
|
||||
text-align: end;
|
||||
font-family: monospace;
|
||||
color: #8c8c8c;
|
||||
}
|
||||
|
||||
|
@ -293,7 +289,6 @@
|
|||
-moz-padding-start: 4px;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.dbg-results-line-contents-string {
|
||||
|
|
|
@ -8,7 +8,7 @@ body {
|
|||
}
|
||||
|
||||
#all-fonts {
|
||||
padding: 0 5px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,7 @@ body {
|
|||
}
|
||||
|
||||
.font {
|
||||
padding: 10px 5px;
|
||||
font-size: 0;
|
||||
padding: 10px 10px;
|
||||
}
|
||||
|
||||
.theme-dark .font {
|
||||
|
@ -51,7 +50,6 @@ body {
|
|||
}
|
||||
|
||||
.font-info {
|
||||
font-size: 1rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
|
|
@ -365,7 +365,6 @@ box.requests-menu-status[code^="5"] {
|
|||
|
||||
.tabpanel-summary-value {
|
||||
-moz-padding-start: 3px;
|
||||
font-family: Menlo, Monaco, monospace;
|
||||
}
|
||||
|
||||
.variable-or-property:not(:focus) > .title > .token-string {
|
||||
|
|
|
@ -4,13 +4,6 @@
|
|||
|
||||
%include ../../shared/devtools/webconsole.inc.css
|
||||
|
||||
.webconsole-timestamp,
|
||||
.webconsole-msg-body,
|
||||
.jsterm-input-node,
|
||||
.jsterm-complete-node {
|
||||
font-family: Consolas, Lucida Console, monospace;
|
||||
}
|
||||
|
||||
/*
|
||||
* This hardcoded width likely due to a toolkit Windows specific bug.
|
||||
* See http://hg.mozilla.org/mozilla-central/annotate/f38d6df93cad/toolkit/themes/winstripe/global/textbox-aero.css#l7
|
||||
|
|
|
@ -139,12 +139,14 @@ void MediaDecoder::SetDormantIfNecessary(bool aDormant)
|
|||
mNextState = PLAY_STATE_PAUSED;
|
||||
}
|
||||
mNextState = mPlayState;
|
||||
mIsDormant = aDormant;
|
||||
mIsDormant = true;
|
||||
mIsExitingDormant = false;
|
||||
ChangeState(PLAY_STATE_LOADING);
|
||||
} else if ((aDormant != true) && (mPlayState == PLAY_STATE_LOADING)) {
|
||||
// exit dormant state
|
||||
// just trigger to state machine.
|
||||
// trigger to state machine.
|
||||
mDecoderStateMachine->SetDormant(false);
|
||||
mIsExitingDormant = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,6 +373,7 @@ MediaDecoder::MediaDecoder() :
|
|||
mSameOriginMedia(false),
|
||||
mReentrantMonitor("media.decoder"),
|
||||
mIsDormant(false),
|
||||
mIsExitingDormant(false),
|
||||
mPlayState(PLAY_STATE_PAUSED),
|
||||
mNextState(PLAY_STATE_PAUSED),
|
||||
mCalledResourceLoaded(false),
|
||||
|
@ -724,8 +727,11 @@ void MediaDecoder::MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool
|
|||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
if (mPlayState == PLAY_STATE_LOADING && mIsDormant) {
|
||||
if (mPlayState == PLAY_STATE_LOADING && mIsDormant && !mIsExitingDormant) {
|
||||
return;
|
||||
} else if (mPlayState == PLAY_STATE_LOADING && mIsDormant && mIsExitingDormant) {
|
||||
mIsDormant = false;
|
||||
mIsExitingDormant = false;
|
||||
}
|
||||
mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1;
|
||||
// Duration has changed so we should recompute playback rate
|
||||
|
@ -1187,6 +1193,7 @@ void MediaDecoder::ChangeState(PlayState aState)
|
|||
|
||||
if (aState!= PLAY_STATE_LOADING) {
|
||||
mIsDormant = false;
|
||||
mIsExitingDormant = false;
|
||||
}
|
||||
|
||||
GetReentrantMonitor().NotifyAll();
|
||||
|
|
|
@ -1035,6 +1035,10 @@ public:
|
|||
// Should be true only when PlayState is PLAY_STATE_LOADING.
|
||||
bool mIsDormant;
|
||||
|
||||
// True if this decoder is exiting from dormant state.
|
||||
// Should be true only when PlayState is PLAY_STATE_LOADING.
|
||||
bool mIsExitingDormant;
|
||||
|
||||
// Set to one of the valid play states.
|
||||
// This can only be changed on the main thread while holding the decoder
|
||||
// monitor. Thus, it can be safely read while holding the decoder monitor
|
||||
|
|
|
@ -627,6 +627,15 @@ InitDirs()
|
|||
getter_AddRefs(sDirs->music));
|
||||
#endif
|
||||
|
||||
// Eventually, on desktop, we want to do something smarter -- for example,
|
||||
// detect when an sdcard is inserted, and use that instead of this.
|
||||
dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
|
||||
getter_AddRefs(sDirs->sdcard));
|
||||
if (sDirs->sdcard) {
|
||||
sDirs->sdcard->AppendRelativeNativePath(NS_LITERAL_CSTRING("fake-sdcard"));
|
||||
}
|
||||
#endif // !MOZ_WIDGET_GONK
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
NS_NewLocalFile(NS_LITERAL_STRING("/data"),
|
||||
false,
|
||||
|
@ -639,15 +648,6 @@ InitDirs()
|
|||
}
|
||||
#endif
|
||||
|
||||
// Eventually, on desktop, we want to do something smarter -- for example,
|
||||
// detect when an sdcard is inserted, and use that instead of this.
|
||||
dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
|
||||
getter_AddRefs(sDirs->sdcard));
|
||||
if (sDirs->sdcard) {
|
||||
sDirs->sdcard->AppendRelativeNativePath(NS_LITERAL_CSTRING("fake-sdcard"));
|
||||
}
|
||||
#endif // !MOZ_WIDGET_GONK
|
||||
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
||||
NS_GetSpecialDirectory("UAppData", getter_AddRefs(sDirs->crashes));
|
||||
if (sDirs->crashes) {
|
||||
|
|
|
@ -54,6 +54,7 @@ using RemoteDOMEvent;
|
|||
using mozilla::dom::ScreenOrientation;
|
||||
using mozilla::layers::TextureFactoryIdentifier;
|
||||
using mozilla::CSSIntPoint;
|
||||
using mozilla::CSSToScreenScale;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -287,7 +288,7 @@ parent:
|
|||
* Updates any zoom constraints on the parent and anything tied to it. This
|
||||
* is useful for control logic that resides outside of the remote browser.
|
||||
*/
|
||||
UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom);
|
||||
UpdateZoomConstraints(bool aAllowZoom, CSSToScreenScale aMinZoom, CSSToScreenScale aMaxZoom);
|
||||
|
||||
/**
|
||||
* Notifies the parent about a scroll event. The pres shell ID and
|
||||
|
|
|
@ -421,16 +421,15 @@ TabChild::Observe(nsISupports *aSubject,
|
|||
// Calculate a really simple resolution that we probably won't
|
||||
// be keeping, as well as putting the scroll offset back to
|
||||
// the top-left of the page.
|
||||
mLastMetrics.mZoom = ScreenToScreenScale(1.0);
|
||||
mLastMetrics.mViewport = CSSRect(CSSPoint(), kDefaultViewportSize);
|
||||
mLastMetrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize);
|
||||
CSSToScreenScale resolution = mLastMetrics.CalculateResolution();
|
||||
// We use ScreenToLayerScale(1) below in order to ask gecko to render
|
||||
// what's currently visible on the screen. This is effectively turning
|
||||
// the async zoom amount into the gecko zoom amount.
|
||||
mLastMetrics.mZoom = mLastMetrics.CalculateIntrinsicScale();
|
||||
// We use ScreenToLayerScale(1) below in order to turn the
|
||||
// async zoom amount into the gecko zoom amount.
|
||||
mLastMetrics.mResolution =
|
||||
resolution / mLastMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
|
||||
mLastMetrics.mZoom / mLastMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
|
||||
mLastMetrics.mScrollOffset = CSSPoint(0, 0);
|
||||
|
||||
utils->SetResolution(mLastMetrics.mResolution.scale,
|
||||
mLastMetrics.mResolution.scale);
|
||||
|
||||
|
@ -572,8 +571,8 @@ TabChild::HandlePossibleViewportChange()
|
|||
nsViewportInfo viewportInfo =
|
||||
nsContentUtils::GetViewportInfo(document, mInnerSize.width, mInnerSize.height);
|
||||
SendUpdateZoomConstraints(viewportInfo.IsZoomAllowed(),
|
||||
viewportInfo.GetMinZoom(),
|
||||
viewportInfo.GetMaxZoom());
|
||||
CSSToScreenScale(viewportInfo.GetMinZoom()),
|
||||
CSSToScreenScale(viewportInfo.GetMaxZoom()));
|
||||
|
||||
float screenW = mInnerSize.width;
|
||||
float screenH = mInnerSize.height;
|
||||
|
@ -647,6 +646,16 @@ TabChild::HandlePossibleViewportChange()
|
|||
viewport.height = std::max(viewport.height, screenH / minScale);
|
||||
SetCSSViewport(viewport);
|
||||
|
||||
float oldScreenWidth = mLastMetrics.mCompositionBounds.width;
|
||||
if (!oldScreenWidth) {
|
||||
oldScreenWidth = mInnerSize.width;
|
||||
}
|
||||
|
||||
FrameMetrics metrics(mLastMetrics);
|
||||
metrics.mViewport = CSSRect(CSSPoint(), viewport);
|
||||
metrics.mScrollableRect = CSSRect(CSSPoint(), pageSize);
|
||||
metrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize);
|
||||
|
||||
// This change to the zoom accounts for all types of changes I can conceive:
|
||||
// 1. screen size changes, CSS viewport does not (pages with no meta viewport
|
||||
// or a fixed size viewport)
|
||||
|
@ -659,15 +668,8 @@ TabChild::HandlePossibleViewportChange()
|
|||
// In all of these cases, we maintain how much actual content is visible
|
||||
// within the screen width. Note that "actual content" may be different with
|
||||
// respect to CSS pixels because of the CSS viewport size changing.
|
||||
int32_t oldScreenWidth = mLastMetrics.mCompositionBounds.width;
|
||||
if (!oldScreenWidth) {
|
||||
oldScreenWidth = mInnerSize.width;
|
||||
}
|
||||
|
||||
FrameMetrics metrics(mLastMetrics);
|
||||
metrics.mViewport = CSSRect(CSSPoint(), viewport);
|
||||
metrics.mScrollableRect = CSSRect(CSSPoint(), pageSize);
|
||||
metrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize);
|
||||
float oldIntrinsicScale = oldScreenWidth / oldBrowserWidth;
|
||||
metrics.mZoom.scale *= metrics.CalculateIntrinsicScale().scale / oldIntrinsicScale;
|
||||
|
||||
// Changing the zoom when we're not doing a first paint will get ignored
|
||||
// by AsyncPanZoomController and causes a blurry flash.
|
||||
|
@ -675,20 +677,17 @@ TabChild::HandlePossibleViewportChange()
|
|||
nsresult rv = utils->GetIsFirstPaint(&isFirstPaint);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (NS_FAILED(rv) || isFirstPaint) {
|
||||
CSSToScreenScale intrinsicScale = metrics.CalculateIntrinsicScale();
|
||||
// FIXME/bug 799585(?): GetViewportInfo() returns a defaultZoom of
|
||||
// 0.0 to mean "did not calculate a zoom". In that case, we default
|
||||
// it to the intrinsic scale.
|
||||
if (viewportInfo.GetDefaultZoom() < 0.01f) {
|
||||
viewportInfo.SetDefaultZoom(intrinsicScale.scale);
|
||||
viewportInfo.SetDefaultZoom(metrics.CalculateIntrinsicScale().scale);
|
||||
}
|
||||
|
||||
double defaultZoom = viewportInfo.GetDefaultZoom();
|
||||
MOZ_ASSERT(viewportInfo.GetMinZoom() <= defaultZoom &&
|
||||
defaultZoom <= viewportInfo.GetMaxZoom());
|
||||
// GetViewportInfo() returns a resolution-dependent scale factor.
|
||||
// Convert that to a resolution-indepedent zoom.
|
||||
metrics.mZoom = ScreenToScreenScale(defaultZoom / intrinsicScale.scale);
|
||||
metrics.mZoom = CSSToScreenScale(defaultZoom);
|
||||
}
|
||||
|
||||
metrics.mDisplayPort = AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
|
@ -696,8 +695,7 @@ TabChild::HandlePossibleViewportChange()
|
|||
// new CSS viewport, so we know that there's no velocity, acceleration, and
|
||||
// we have no idea how long painting will take.
|
||||
metrics, gfx::Point(0.0f, 0.0f), gfx::Point(0.0f, 0.0f), 0.0);
|
||||
CSSToScreenScale resolution = metrics.CalculateResolution();
|
||||
metrics.mResolution = resolution / metrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
|
||||
metrics.mResolution = metrics.mZoom / metrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
|
||||
utils->SetResolution(metrics.mResolution.scale, metrics.mResolution.scale);
|
||||
|
||||
// Force a repaint with these metrics. This, among other things, sets the
|
||||
|
@ -1617,7 +1615,7 @@ TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
|
|||
}
|
||||
|
||||
// set the resolution
|
||||
LayoutDeviceToLayerScale resolution = aFrameMetrics.CalculateResolution()
|
||||
LayoutDeviceToLayerScale resolution = aFrameMetrics.mZoom
|
||||
/ aFrameMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
|
||||
utils->SetResolution(resolution.scale, resolution.scale);
|
||||
|
||||
|
|
|
@ -300,7 +300,7 @@ public:
|
|||
void GetDPI(float* aDPI);
|
||||
void GetDefaultScale(double *aScale);
|
||||
|
||||
ScreenToScreenScale GetZoom() { return mLastMetrics.mZoom; }
|
||||
CSSToScreenScale GetZoom() { return mLastMetrics.mZoom; }
|
||||
|
||||
ScreenOrientation GetOrientation() { return mOrientation; }
|
||||
|
||||
|
|
|
@ -1552,8 +1552,8 @@ TabParent::RecvZoomToRect(const CSSRect& aRect)
|
|||
|
||||
bool
|
||||
TabParent::RecvUpdateZoomConstraints(const bool& aAllowZoom,
|
||||
const float& aMinZoom,
|
||||
const float& aMaxZoom)
|
||||
const CSSToScreenScale& aMinZoom,
|
||||
const CSSToScreenScale& aMaxZoom)
|
||||
{
|
||||
if (RenderFrameParent* rfp = GetRenderFrame()) {
|
||||
rfp->UpdateZoomConstraints(aAllowZoom, aMinZoom, aMaxZoom);
|
||||
|
|
|
@ -158,8 +158,8 @@ public:
|
|||
virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
|
||||
virtual bool RecvZoomToRect(const CSSRect& aRect);
|
||||
virtual bool RecvUpdateZoomConstraints(const bool& aAllowZoom,
|
||||
const float& aMinZoom,
|
||||
const float& aMaxZoom);
|
||||
const CSSToScreenScale& aMinZoom,
|
||||
const CSSToScreenScale& aMaxZoom);
|
||||
virtual bool RecvUpdateScrollOffset(const uint32_t& aPresShellId, const ViewID& aViewId, const CSSIntPoint& aScrollOffset);
|
||||
virtual bool RecvContentReceivedTouch(const bool& aPreventDefault);
|
||||
virtual PContentDialogParent* AllocPContentDialogParent(const uint32_t& aType,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id={770731}
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=770731
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug {770731} Permissions</title>
|
||||
|
@ -11,7 +11,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={770731}
|
|||
</head>
|
||||
<body>
|
||||
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={770731}">Mozilla Bug {674720}</a>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=770731">Mozilla Bug 770731</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
|
@ -21,6 +21,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={770731}
|
|||
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var testPrivApp = {
|
||||
'manifestURL' : 'https://aprivileged.com/manifest.webapp'
|
||||
};
|
||||
|
@ -29,93 +31,79 @@ var testCertApp = {
|
|||
'manifestURL' : 'https://acertified.com/manifest.webapp'
|
||||
};
|
||||
|
||||
SpecialPowers.addPermission("permissions", true, document);
|
||||
SpecialPowers.pushPrefEnv({ "set": [["dom.mozPermissionSettings.enabled", true]] },
|
||||
function() {
|
||||
SpecialPowers.removePermission("permissions", document);
|
||||
});
|
||||
// Any permission explicit for privileged and implicit for certified serves
|
||||
var testPerm = "contacts-read";
|
||||
// Any permission explicit for privileged and certified apps
|
||||
var explicitPerm = "geolocation";
|
||||
|
||||
SpecialPowers.Cu.import("resource://gre/modules/PermissionSettings.jsm");
|
||||
var mozPermissions = window.navigator.mozPermissionSettings;
|
||||
// Simulate that the app requested the permissions
|
||||
SpecialPowers.pushPermissions([{'type': 'permissions', 'allow': true, 'context': document}, {'type': testPerm, 'allow': true, 'context': testPrivApp}, {'type': testPerm, 'allow': true, 'context': testCertApp}, {'type': explicitPerm, 'allow': true, 'context': testPrivApp}, {'type': explicitPerm, 'allow': true, 'context': testCertApp}], function() {
|
||||
SpecialPowers.pushPrefEnv({ "set": [["dom.mozPermissionSettings.enabled", true]] }, permissionTest);
|
||||
});
|
||||
|
||||
function permissionTest() {
|
||||
// Any permission explicit for privileged and implicit for certified serves
|
||||
var testPerm = "contacts-read";
|
||||
// Any permission explicit for privileged and certified apps
|
||||
var explicitPerm = "geolocation";
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/PermissionSettings.jsm");
|
||||
}
|
||||
|
||||
// Simulate that the app requested the permissions
|
||||
SpecialPowers.addPermission(testPerm, true, testPrivApp);
|
||||
SpecialPowers.addPermission(testPerm, true, testCertApp);
|
||||
SpecialPowers.addPermission(explicitPerm, true, testPrivApp);
|
||||
SpecialPowers.addPermission(explicitPerm, true, testCertApp);
|
||||
var mozPermissions = window.navigator.mozPermissionSettings;
|
||||
isnot(mozPermissions, null, "mozPermissionSettings is null when not enabled.");
|
||||
|
||||
if (gPermissionsEnabled) {
|
||||
var certAppManifest = testCertApp.manifestURL;
|
||||
var privAppManifest = testPrivApp.manifestURL;
|
||||
var originPriv = "https://aprivileged.com";
|
||||
var originCert = "https://acertified.com";
|
||||
var originOther = "http://test";
|
||||
var certAppManifest = testCertApp.manifestURL;
|
||||
var privAppManifest = testPrivApp.manifestURL;
|
||||
var originPriv = "https://aprivileged.com";
|
||||
var originCert = "https://acertified.com";
|
||||
var originOther = "http://test";
|
||||
|
||||
// Trying to make any change to implicit permissions should fail
|
||||
// Trying to make any change to implicit permissions should fail
|
||||
try {
|
||||
mozPermissions.set(testPerm, "allow", certAppManifest, originCert, false);
|
||||
ok(false, "Change implicit permission");
|
||||
} catch (e) {
|
||||
ok(true, "Change implicit permission");
|
||||
}
|
||||
|
||||
var result=mozPermissions.get(testPerm, certAppManifest, originCert, false);
|
||||
is(result, "allow", "same result");
|
||||
|
||||
// Removing a permission from the same origin, even an explicit one, should fail
|
||||
try {
|
||||
mozPermissions.set(testPerm, "unknown", privAppManifest, originPriv);
|
||||
ok(false, "Setting a permission to unknown");
|
||||
} catch (e) {
|
||||
ok(true, "Setting a permission to unknown");
|
||||
}
|
||||
|
||||
// Removing an explicit permission from a different origin should work
|
||||
var testRemove = function(aPerm, aManifest, aOrigin, aTestMsg) {
|
||||
try {
|
||||
mozPermissions.set(testPerm, "allow", certAppManifest, originCert, false);
|
||||
ok(false, "Change implicit permission");
|
||||
mozPermissions.remove(aPerm, aManifest, aOrigin);
|
||||
var status = mozPermissions.get(aPerm, aManifest, aOrigin, false);
|
||||
is(status, "unknown", aTestMsg);
|
||||
} catch (e) {
|
||||
ok(true, "Change implicit permission");
|
||||
ok(false, aTestMsg);
|
||||
}
|
||||
}
|
||||
|
||||
var result=mozPermissions.get(testPerm, certAppManifest, originCert, false);
|
||||
is(result, "allow", "same result");
|
||||
|
||||
// Removing a permission from the same origin, even an explicit one, should fail
|
||||
try {
|
||||
mozPermissions.set(testPerm, "unknown", privAppManifest, originPriv);
|
||||
ok(false, "Setting a permission to unknown");
|
||||
} catch (e) {
|
||||
ok(true, "Setting a permission to unknown");
|
||||
}
|
||||
|
||||
// Removing an explicit permission from a different origin should work
|
||||
var testRemove = function(aPerm, aManifest, aOrigin, aTestMsg) {
|
||||
try {
|
||||
mozPermissions.remove(aPerm, aManifest, aOrigin);
|
||||
var status = mozPermissions.get(aPerm, aManifest, aOrigin, false);
|
||||
is(status, "unknown", aTestMsg);
|
||||
} catch (e) {
|
||||
ok(false, aTestMsg);
|
||||
}
|
||||
}
|
||||
|
||||
testRemove(explicitPerm, privAppManifest, originOther,
|
||||
testRemove(explicitPerm, privAppManifest, originOther,
|
||||
"Remove explicit permission of privileged app");
|
||||
testRemove(explicitPerm, certAppManifest, originOther,
|
||||
testRemove(explicitPerm, certAppManifest, originOther,
|
||||
"Remove explicit permission of certified app");
|
||||
|
||||
mozPermissions.set(testPerm, "allow", privAppManifest, originPriv, false);
|
||||
result = mozPermissions.get(testPerm, privAppManifest, originPriv, false);
|
||||
is(result, "allow", "Set to allow");
|
||||
mozPermissions.set(testPerm, "deny", privAppManifest, originPriv, false);
|
||||
result = mozPermissions.get(testPerm, privAppManifest, originPriv, false);
|
||||
is(result, "deny", "Set to deny");
|
||||
mozPermissions.set(testPerm, "prompt", privAppManifest, originPriv, false);
|
||||
result = mozPermissions.get(testPerm, privAppManifest, originPriv, false);
|
||||
is(result, "prompt", "Set to prompt");
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
is(mozPermissions, null, "mozPermissionSettings is null when not enabled.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
SpecialPowers.removePermission(testPerm, testPrivApp);
|
||||
SpecialPowers.removePermission(testPerm, testCertApp);
|
||||
mozPermissions.set(testPerm, "allow", privAppManifest, originPriv, false);
|
||||
result = mozPermissions.get(testPerm, privAppManifest, originPriv, false);
|
||||
is(result, "allow", "Set to allow");
|
||||
mozPermissions.set(testPerm, "deny", privAppManifest, originPriv, false);
|
||||
result = mozPermissions.get(testPerm, privAppManifest, originPriv, false);
|
||||
is(result, "deny", "Set to deny");
|
||||
mozPermissions.set(testPerm, "prompt", privAppManifest, originPriv, false);
|
||||
result = mozPermissions.get(testPerm, privAppManifest, originPriv, false);
|
||||
is(result, "prompt", "Set to prompt");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
var gPermissionsEnabled = SpecialPowers.getBoolPref("dom.mozPermissionSettings.enabled");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(permissionTest);
|
||||
|
||||
ok(true, "test passed");
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
|
@ -50,6 +50,22 @@ struct ScaleFactor {
|
|||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
bool operator<(const ScaleFactor<src, dst>& aOther) const {
|
||||
return scale < aOther.scale;
|
||||
}
|
||||
|
||||
bool operator<=(const ScaleFactor<src, dst>& aOther) const {
|
||||
return scale <= aOther.scale;
|
||||
}
|
||||
|
||||
bool operator>(const ScaleFactor<src, dst>& aOther) const {
|
||||
return scale > aOther.scale;
|
||||
}
|
||||
|
||||
bool operator>=(const ScaleFactor<src, dst>& aOther) const {
|
||||
return scale >= aOther.scale;
|
||||
}
|
||||
|
||||
template<class other>
|
||||
ScaleFactor<other, dst> operator/(const ScaleFactor<src, other>& aOther) const {
|
||||
return ScaleFactor<other, dst>(scale / aOther.scale);
|
||||
|
|
|
@ -103,20 +103,9 @@ public:
|
|||
return CSSToScreenScale(float(mCompositionBounds.width) / float(mViewport.width));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resolution that content should be rendered at given
|
||||
* the configuration in this metrics object: viewport dimensions,
|
||||
* zoom factor, etc. (The mResolution member of this metrics is
|
||||
* ignored.)
|
||||
*/
|
||||
CSSToScreenScale CalculateResolution() const
|
||||
{
|
||||
return CalculateIntrinsicScale() * mZoom;
|
||||
}
|
||||
|
||||
CSSRect CalculateCompositedRectInCssPixels() const
|
||||
{
|
||||
return CSSRect(gfx::RoundedIn(mCompositionBounds / CalculateResolution()));
|
||||
return CSSRect(gfx::RoundedIn(mCompositionBounds / mZoom));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -232,19 +221,11 @@ public:
|
|||
// resolution of parent layers is opaque to this metric.
|
||||
LayoutDeviceToLayerScale mResolution;
|
||||
|
||||
// The resolution-independent "user zoom". For example, if a page
|
||||
// configures the viewport to a zoom value of 2x, then this member
|
||||
// will always be 2.0 no matter what the viewport or composition
|
||||
// bounds.
|
||||
//
|
||||
// In the steady state (no animations), the following is usually true
|
||||
//
|
||||
// intrinsicScale = (mCompositionBounds / mViewport)
|
||||
// mResolution = mZoom * intrinsicScale / mDevPixelsPerCSSPixel
|
||||
//
|
||||
// When this is not true, we're probably asynchronously sampling a
|
||||
// zoom animation for content.
|
||||
ScreenToScreenScale mZoom;
|
||||
// The "user zoom". Content is painted by gecko at mResolution * mDevPixelsPerCSSPixel,
|
||||
// but will be drawn to the screen at mZoom. In the steady state, the
|
||||
// two will be the same, but during an async zoom action the two may
|
||||
// diverge.
|
||||
CSSToScreenScale mZoom;
|
||||
|
||||
// The conversion factor between CSS pixels and device pixels for this frame.
|
||||
// This can vary based on a variety of things, such as reflowing-zoom. The
|
||||
|
|
|
@ -401,8 +401,8 @@ APZCTreeManager::ContentReceivedTouch(const ScrollableLayerGuid& aGuid,
|
|||
void
|
||||
APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
|
||||
bool aAllowZoom,
|
||||
float aMinScale,
|
||||
float aMaxScale)
|
||||
const CSSToScreenScale& aMinScale,
|
||||
const CSSToScreenScale& aMaxScale)
|
||||
{
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
|
||||
if (apzc) {
|
||||
|
|
|
@ -208,8 +208,8 @@ public:
|
|||
*/
|
||||
void UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
|
||||
bool aAllowZoom,
|
||||
float aMinScale,
|
||||
float aMaxScale);
|
||||
const CSSToScreenScale& aMinScale,
|
||||
const CSSToScreenScale& aMaxScale);
|
||||
|
||||
/**
|
||||
* Update mFrameMetrics.mScrollOffset to the given offset.
|
||||
|
|
|
@ -98,12 +98,12 @@ StaticAutoPtr<ComputedTimingFunction> gComputedTimingFunction;
|
|||
/**
|
||||
* Maximum zoom amount, always used, even if a page asks for higher.
|
||||
*/
|
||||
static const float MAX_ZOOM = 8.0f;
|
||||
static const CSSToScreenScale MAX_ZOOM(8.0f);
|
||||
|
||||
/**
|
||||
* Minimum zoom amount, always used, even if a page asks for lower.
|
||||
*/
|
||||
static const float MIN_ZOOM = 0.125f;
|
||||
static const CSSToScreenScale MIN_ZOOM(0.125f);
|
||||
|
||||
/**
|
||||
* Amount of time before we timeout touch event listeners. For example, if
|
||||
|
@ -536,16 +536,15 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
|||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
float spanRatio = aEvent.mCurrentSpan / aEvent.mPreviousSpan;
|
||||
ScreenToScreenScale spanRatio(aEvent.mCurrentSpan / aEvent.mPreviousSpan);
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
gfxFloat userZoom = mFrameMetrics.mZoom.scale;
|
||||
CSSToScreenScale userZoom = mFrameMetrics.mZoom;
|
||||
ScreenPoint focusPoint = aEvent.mFocusPoint;
|
||||
|
||||
CSSPoint focusChange = (mLastZoomFocus - focusPoint) / resolution;
|
||||
CSSPoint focusChange = (mLastZoomFocus - focusPoint) / userZoom;
|
||||
// If displacing by the change in focus point will take us off page bounds,
|
||||
// then reduce the displacement such that it doesn't.
|
||||
if (mX.DisplacementWillOverscroll(focusChange.x) != Axis::OVERSCROLL_NONE) {
|
||||
|
@ -561,18 +560,13 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
|||
// either axis such that we don't overscroll the boundaries when zooming.
|
||||
gfx::Point neededDisplacement;
|
||||
|
||||
float maxZoom = mMaxZoom / mFrameMetrics.CalculateIntrinsicScale().scale;
|
||||
float minZoom = mMinZoom / mFrameMetrics.CalculateIntrinsicScale().scale;
|
||||
|
||||
bool doScale = (spanRatio > 1.0 && userZoom < maxZoom) ||
|
||||
(spanRatio < 1.0 && userZoom > minZoom);
|
||||
bool doScale = (spanRatio > ScreenToScreenScale(1.0) && userZoom < mMaxZoom) ||
|
||||
(spanRatio < ScreenToScreenScale(1.0) && userZoom > mMinZoom);
|
||||
|
||||
if (doScale) {
|
||||
if (userZoom * spanRatio > maxZoom) {
|
||||
spanRatio = maxZoom / userZoom;
|
||||
} else if (userZoom * spanRatio < minZoom) {
|
||||
spanRatio = minZoom / userZoom;
|
||||
}
|
||||
spanRatio.scale = clamped(spanRatio.scale,
|
||||
mMinZoom.scale / userZoom.scale,
|
||||
mMaxZoom.scale / userZoom.scale);
|
||||
|
||||
switch (mX.ScaleWillOverscroll(spanRatio, focusPoint.x))
|
||||
{
|
||||
|
@ -643,8 +637,7 @@ nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent)
|
|||
if (controller) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
|
||||
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, mFrameMetrics.mZoom);
|
||||
controller->HandleLongTap(gfx::RoundedToInt(point));
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
@ -660,8 +653,7 @@ nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput
|
|||
if (controller) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
|
||||
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, mFrameMetrics.mZoom);
|
||||
controller->HandleSingleTap(gfx::RoundedToInt(point));
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
@ -674,8 +666,7 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent)
|
|||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
if (mAllowZoom) {
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
|
||||
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, mFrameMetrics.mZoom);
|
||||
controller->HandleDoubleTap(gfx::RoundedToInt(point));
|
||||
}
|
||||
|
||||
|
@ -741,7 +732,7 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
|||
|
||||
// We want to inversely scale it because when you're zoomed further in, a
|
||||
// larger swipe should move you a shorter distance.
|
||||
ScreenToCSSScale inverseResolution = mFrameMetrics.CalculateResolution().Inverse();
|
||||
ScreenToCSSScale inverseResolution = mFrameMetrics.mZoom.Inverse();
|
||||
|
||||
gfx::Point displacement(mX.GetDisplacementForDuration(inverseResolution.scale,
|
||||
timeDelta),
|
||||
|
@ -785,7 +776,7 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
|
|||
|
||||
// We want to inversely scale it because when you're zoomed further in, a
|
||||
// larger swipe should move you a shorter distance.
|
||||
ScreenToCSSScale inverseResolution = mFrameMetrics.CalculateResolution().Inverse();
|
||||
ScreenToCSSScale inverseResolution = mFrameMetrics.mZoom.Inverse();
|
||||
|
||||
ScrollBy(CSSPoint::FromUnknownPoint(gfx::Point(
|
||||
mX.GetDisplacementForDuration(inverseResolution.scale, aDelta),
|
||||
|
@ -812,20 +803,18 @@ void AsyncPanZoomController::ScrollBy(const CSSPoint& aOffset) {
|
|||
mFrameMetrics.mScrollOffset += aOffset;
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ScaleWithFocus(float aZoom,
|
||||
void AsyncPanZoomController::ScaleWithFocus(const CSSToScreenScale& aZoom,
|
||||
const ScreenPoint& aFocus) {
|
||||
float zoomFactor = aZoom / mFrameMetrics.mZoom.scale;
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
ScreenToScreenScale zoomFactor(aZoom.scale / mFrameMetrics.mZoom.scale);
|
||||
CSSToScreenScale resolution = mFrameMetrics.mZoom;
|
||||
|
||||
SetZoomAndResolution(ScreenToScreenScale(aZoom));
|
||||
SetZoomAndResolution(aZoom);
|
||||
|
||||
// If the new scale is very small, we risk multiplying in huge rounding
|
||||
// errors, so don't bother adjusting the scroll offset.
|
||||
if (resolution.scale >= 0.01f) {
|
||||
mFrameMetrics.mScrollOffset.x +=
|
||||
aFocus.x * (zoomFactor - 1.0) / resolution.scale;
|
||||
mFrameMetrics.mScrollOffset.y +=
|
||||
aFocus.y * (zoomFactor - 1.0) / resolution.scale;
|
||||
zoomFactor.scale -= 1.0;
|
||||
mFrameMetrics.mScrollOffset += aFocus * zoomFactor / resolution;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -877,8 +866,7 @@ const CSSRect AsyncPanZoomController::CalculatePendingDisplayPort(
|
|||
double estimatedPaintDuration =
|
||||
aEstimatedPaintDuration > EPSILON ? aEstimatedPaintDuration : 1.0;
|
||||
|
||||
CSSToScreenScale resolution = aFrameMetrics.CalculateResolution();
|
||||
CSSIntRect compositionBounds = gfx::RoundedIn(aFrameMetrics.mCompositionBounds / resolution);
|
||||
CSSIntRect compositionBounds = gfx::RoundedIn(aFrameMetrics.mCompositionBounds / aFrameMetrics.mZoom);
|
||||
CSSRect scrollableRect = aFrameMetrics.mScrollableRect;
|
||||
|
||||
// Ensure the scrollableRect is at least as big as the compositionBounds
|
||||
|
@ -983,11 +971,11 @@ void AsyncPanZoomController::RequestContentRepaint() {
|
|||
|
||||
// Cache the zoom since we're temporarily changing it for
|
||||
// acceleration-scaled painting.
|
||||
ScreenToScreenScale actualZoom = mFrameMetrics.mZoom;
|
||||
CSSToScreenScale actualZoom = mFrameMetrics.mZoom;
|
||||
// Calculate the factor of acceleration based on the faster of the two axes.
|
||||
float accelerationFactor =
|
||||
clamped(std::max(mX.GetAccelerationFactor(), mY.GetAccelerationFactor()),
|
||||
MIN_ZOOM / 2.0f, MAX_ZOOM);
|
||||
MIN_ZOOM.scale / 2.0f, MAX_ZOOM.scale);
|
||||
// Scale down the resolution a bit based on acceleration.
|
||||
mFrameMetrics.mZoom.scale /= accelerationFactor;
|
||||
|
||||
|
@ -1048,10 +1036,9 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
|||
// will affect the final computed resolution.
|
||||
double sampledPosition = gComputedTimingFunction->GetValue(animPosition);
|
||||
|
||||
ScreenToScreenScale startZoom = mStartZoomToMetrics.mZoom;
|
||||
ScreenToScreenScale endZoom = mEndZoomToMetrics.mZoom;
|
||||
mFrameMetrics.mZoom = ScreenToScreenScale(endZoom.scale * sampledPosition +
|
||||
startZoom.scale * (1 - sampledPosition));
|
||||
mFrameMetrics.mZoom = CSSToScreenScale(
|
||||
mEndZoomToMetrics.mZoom.scale * sampledPosition +
|
||||
mStartZoomToMetrics.mZoom.scale * (1 - sampledPosition));
|
||||
|
||||
mFrameMetrics.mScrollOffset = CSSPoint::FromUnknownPoint(gfx::Point(
|
||||
mEndZoomToMetrics.mScrollOffset.x * sampledPosition +
|
||||
|
@ -1076,7 +1063,7 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
|||
break;
|
||||
}
|
||||
|
||||
aScrollOffset = mFrameMetrics.mScrollOffset * mFrameMetrics.CalculateResolution();
|
||||
aScrollOffset = mFrameMetrics.mScrollOffset * mFrameMetrics.mZoom;
|
||||
*aNewTransform = GetCurrentAsyncTransform();
|
||||
|
||||
mCurrentAsyncScrollOffset = mFrameMetrics.mScrollOffset;
|
||||
|
@ -1121,10 +1108,10 @@ ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
|
|||
if (mLastContentPaintMetrics.IsScrollable()) {
|
||||
lastPaintScrollOffset = mLastContentPaintMetrics.mScrollOffset;
|
||||
}
|
||||
CSSToScreenScale localScale = mFrameMetrics.CalculateResolution();
|
||||
LayerPoint translation = (mFrameMetrics.mScrollOffset - lastPaintScrollOffset)
|
||||
* mLastContentPaintMetrics.LayersPixelsPerCSSPixel();
|
||||
return ViewTransform(-translation, localScale / mLastContentPaintMetrics.mDevPixelsPerCSSPixel);
|
||||
return ViewTransform(-translation,
|
||||
mFrameMetrics.mZoom / mLastContentPaintMetrics.mDevPixelsPerCSSPixel);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) {
|
||||
|
@ -1141,10 +1128,13 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
|||
aLayerMetrics.mCompositionBounds.height == mFrameMetrics.mCompositionBounds.height) {
|
||||
// Remote content has sync'd up to the composition geometry
|
||||
// change, so we can accept the viewport it's calculated.
|
||||
CSSToScreenScale previousResolution = mFrameMetrics.CalculateResolution();
|
||||
CSSToScreenScale previousResolution = mFrameMetrics.CalculateIntrinsicScale();
|
||||
mFrameMetrics.mViewport = aLayerMetrics.mViewport;
|
||||
CSSToScreenScale newResolution = mFrameMetrics.CalculateResolution();
|
||||
needContentRepaint |= (previousResolution != newResolution);
|
||||
CSSToScreenScale newResolution = mFrameMetrics.CalculateIntrinsicScale();
|
||||
if (previousResolution != newResolution) {
|
||||
needContentRepaint = true;
|
||||
mFrameMetrics.mZoom.scale *= newResolution.scale / previousResolution.scale;
|
||||
}
|
||||
}
|
||||
|
||||
if (aIsFirstPaint || isDefault) {
|
||||
|
@ -1187,7 +1177,8 @@ void AsyncPanZoomController::UpdateCompositionBounds(const ScreenIntRect& aCompo
|
|||
// has gone out of view, the buffer will be cleared elsewhere anyways.
|
||||
if (aCompositionBounds.width && aCompositionBounds.height &&
|
||||
oldCompositionBounds.width && oldCompositionBounds.height) {
|
||||
SetZoomAndResolution(mFrameMetrics.mZoom);
|
||||
ScreenToScreenScale adjustmentFactor(float(aCompositionBounds.width) / float(oldCompositionBounds.width));
|
||||
SetZoomAndResolution(mFrameMetrics.mZoom * adjustmentFactor);
|
||||
|
||||
// Repaint on a rotation so that our new resolution gets properly updated.
|
||||
RequestContentRepaint();
|
||||
|
@ -1215,28 +1206,24 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
|
|||
ScreenIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
|
||||
CSSRect cssPageRect = mFrameMetrics.mScrollableRect;
|
||||
CSSPoint scrollOffset = mFrameMetrics.mScrollOffset;
|
||||
float currentZoom = mFrameMetrics.mZoom.scale;
|
||||
float targetZoom;
|
||||
float intrinsicScale = mFrameMetrics.CalculateIntrinsicScale().scale;
|
||||
CSSToScreenScale currentZoom = mFrameMetrics.mZoom;
|
||||
CSSToScreenScale targetZoom;
|
||||
|
||||
// The minimum zoom to prevent over-zoom-out.
|
||||
// If the zoom factor is lower than this (i.e. we are zoomed more into the page),
|
||||
// then the CSS content rect, in layers pixels, will be smaller than the
|
||||
// composition bounds. If this happens, we can't fill the target composited
|
||||
// area with this frame.
|
||||
float localMinZoom = std::max(mMinZoom,
|
||||
std::max(compositionBounds.width / cssPageRect.width,
|
||||
compositionBounds.height / cssPageRect.height))
|
||||
/ intrinsicScale;
|
||||
float localMaxZoom = mMaxZoom / intrinsicScale;
|
||||
CSSToScreenScale localMinZoom(std::max(mMinZoom.scale,
|
||||
std::max(compositionBounds.width / cssPageRect.width,
|
||||
compositionBounds.height / cssPageRect.height)));
|
||||
CSSToScreenScale localMaxZoom = mMaxZoom;
|
||||
|
||||
if (!aRect.IsEmpty()) {
|
||||
// Intersect the zoom-to-rect to the CSS rect to make sure it fits.
|
||||
aRect = aRect.Intersect(cssPageRect);
|
||||
float targetResolution =
|
||||
std::min(compositionBounds.width / aRect.width,
|
||||
compositionBounds.height / aRect.height);
|
||||
targetZoom = targetResolution / intrinsicScale;
|
||||
targetZoom = CSSToScreenScale(std::min(compositionBounds.width / aRect.width,
|
||||
compositionBounds.height / aRect.height));
|
||||
}
|
||||
// 1. If the rect is empty, request received from browserElementScrolling.js
|
||||
// 2. currentZoom is equal to mMaxZoom and user still double-tapping it
|
||||
|
@ -1256,14 +1243,12 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
|
|||
cssPageRect.width,
|
||||
newHeight);
|
||||
aRect = aRect.Intersect(cssPageRect);
|
||||
float targetResolution =
|
||||
std::min(compositionBounds.width / aRect.width,
|
||||
compositionBounds.height / aRect.height);
|
||||
targetZoom = targetResolution / intrinsicScale;
|
||||
targetZoom = CSSToScreenScale(std::min(compositionBounds.width / aRect.width,
|
||||
compositionBounds.height / aRect.height));
|
||||
}
|
||||
|
||||
targetZoom = clamped(targetZoom, localMinZoom, localMaxZoom);
|
||||
mEndZoomToMetrics.mZoom = ScreenToScreenScale(targetZoom);
|
||||
targetZoom.scale = clamped(targetZoom.scale, localMinZoom.scale, localMaxZoom.scale);
|
||||
mEndZoomToMetrics.mZoom = targetZoom;
|
||||
|
||||
// Adjust the zoomToRect to a sensible position to prevent overscrolling.
|
||||
FrameMetrics metricsAfterZoom = mFrameMetrics;
|
||||
|
@ -1360,22 +1345,21 @@ void AsyncPanZoomController::TimeoutTouchListeners() {
|
|||
ContentReceivedTouch(false);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::SetZoomAndResolution(const ScreenToScreenScale& aZoom) {
|
||||
void AsyncPanZoomController::SetZoomAndResolution(const CSSToScreenScale& aZoom) {
|
||||
mMonitor.AssertCurrentThreadIn();
|
||||
mFrameMetrics.mZoom = aZoom;
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
// We use ScreenToLayerScale(1) below in order to ask gecko to render
|
||||
// what's currently visible on the screen. This is effectively turning
|
||||
// the async zoom amount into the gecko zoom amount.
|
||||
mFrameMetrics.mResolution = resolution / mFrameMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
|
||||
mFrameMetrics.mResolution = aZoom / mFrameMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::UpdateZoomConstraints(bool aAllowZoom,
|
||||
float aMinZoom,
|
||||
float aMaxZoom) {
|
||||
const CSSToScreenScale& aMinZoom,
|
||||
const CSSToScreenScale& aMaxZoom) {
|
||||
mAllowZoom = aAllowZoom;
|
||||
mMinZoom = std::max(MIN_ZOOM, aMinZoom);
|
||||
mMaxZoom = std::min(MAX_ZOOM, aMaxZoom);
|
||||
mMinZoom = (MIN_ZOOM > aMinZoom ? MIN_ZOOM : aMinZoom);
|
||||
mMaxZoom = (MAX_ZOOM > aMaxZoom ? aMaxZoom : MAX_ZOOM);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::PostDelayedTask(Task* aTask, int aDelayMs) {
|
||||
|
|
|
@ -145,7 +145,9 @@ public:
|
|||
* We try to obey everything it asks us elsewhere, but here we only handle
|
||||
* minimum-scale, maximum-scale, and user-scalable.
|
||||
*/
|
||||
void UpdateZoomConstraints(bool aAllowZoom, float aMinScale, float aMaxScale);
|
||||
void UpdateZoomConstraints(bool aAllowZoom,
|
||||
const mozilla::CSSToScreenScale& aMinScale,
|
||||
const mozilla::CSSToScreenScale& aMaxScale);
|
||||
|
||||
/**
|
||||
* Schedules a runnable to run on the controller/UI thread at some time
|
||||
|
@ -348,7 +350,8 @@ protected:
|
|||
*
|
||||
* XXX: Fix focus point calculations.
|
||||
*/
|
||||
void ScaleWithFocus(float aScale, const ScreenPoint& aFocus);
|
||||
void ScaleWithFocus(const mozilla::CSSToScreenScale& aScale,
|
||||
const ScreenPoint& aFocus);
|
||||
|
||||
/**
|
||||
* Schedules a composite on the compositor thread. Wrapper for
|
||||
|
@ -453,7 +456,7 @@ protected:
|
|||
*
|
||||
* *** The monitor must be held while calling this.
|
||||
*/
|
||||
void SetZoomAndResolution(const ScreenToScreenScale& aZoom);
|
||||
void SetZoomAndResolution(const mozilla::CSSToScreenScale& aZoom);
|
||||
|
||||
/**
|
||||
* Timeout function for mozbrowserasyncscroll event. Because we throttle
|
||||
|
@ -543,8 +546,8 @@ private:
|
|||
// values; for example, allowing a min zoom of 0.0 can cause very bad things
|
||||
// to happen.
|
||||
bool mAllowZoom;
|
||||
float mMinZoom;
|
||||
float mMaxZoom;
|
||||
mozilla::CSSToScreenScale mMinZoom;
|
||||
mozilla::CSSToScreenScale mMaxZoom;
|
||||
|
||||
// The last time the compositor has sampled the content transform for this
|
||||
// frame.
|
||||
|
|
|
@ -252,12 +252,12 @@ float Axis::DisplacementWillOverscrollAmount(float aDisplacement) {
|
|||
}
|
||||
}
|
||||
|
||||
Axis::Overscroll Axis::ScaleWillOverscroll(float aScale, float aFocus) {
|
||||
float originAfterScale = (GetOrigin() + aFocus) * aScale - aFocus;
|
||||
Axis::Overscroll Axis::ScaleWillOverscroll(ScreenToScreenScale aScale, float aFocus) {
|
||||
float originAfterScale = (GetOrigin() + aFocus) * aScale.scale - aFocus;
|
||||
|
||||
bool both = ScaleWillOverscrollBothSides(aScale);
|
||||
bool minus = originAfterScale < GetPageStart() * aScale;
|
||||
bool plus = (originAfterScale + GetCompositionLength()) > GetPageEnd() * aScale;
|
||||
bool minus = originAfterScale < GetPageStart() * aScale.scale;
|
||||
bool plus = (originAfterScale + GetCompositionLength()) > GetPageEnd() * aScale.scale;
|
||||
|
||||
if ((minus && plus) || both) {
|
||||
return OVERSCROLL_BOTH;
|
||||
|
@ -271,12 +271,12 @@ Axis::Overscroll Axis::ScaleWillOverscroll(float aScale, float aFocus) {
|
|||
return OVERSCROLL_NONE;
|
||||
}
|
||||
|
||||
float Axis::ScaleWillOverscrollAmount(float aScale, float aFocus) {
|
||||
float originAfterScale = (GetOrigin() + aFocus) * aScale - aFocus;
|
||||
float Axis::ScaleWillOverscrollAmount(ScreenToScreenScale aScale, float aFocus) {
|
||||
float originAfterScale = (GetOrigin() + aFocus) * aScale.scale - aFocus;
|
||||
switch (ScaleWillOverscroll(aScale, aFocus)) {
|
||||
case OVERSCROLL_MINUS: return originAfterScale - GetPageStart() * aScale;
|
||||
case OVERSCROLL_MINUS: return originAfterScale - GetPageStart() * aScale.scale;
|
||||
case OVERSCROLL_PLUS: return (originAfterScale + GetCompositionLength()) -
|
||||
NS_lround(GetPageEnd() * aScale);
|
||||
NS_lround(GetPageEnd() * aScale.scale);
|
||||
// Don't handle OVERSCROLL_BOTH. Client code is expected to deal with it.
|
||||
default: return 0;
|
||||
}
|
||||
|
@ -319,12 +319,12 @@ float Axis::GetPageLength() {
|
|||
return GetRectLength(pageRect);
|
||||
}
|
||||
|
||||
bool Axis::ScaleWillOverscrollBothSides(float aScale) {
|
||||
bool Axis::ScaleWillOverscrollBothSides(ScreenToScreenScale aScale) {
|
||||
const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
|
||||
|
||||
CSSRect cssContentRect = metrics.mScrollableRect;
|
||||
|
||||
CSSToScreenScale scale(metrics.CalculateResolution().scale * aScale);
|
||||
CSSToScreenScale scale = metrics.mZoom * aScale;
|
||||
CSSIntRect cssCompositionBounds = RoundedIn(metrics.mCompositionBounds / scale);
|
||||
|
||||
return GetRectLength(cssContentRect) < GetRectLength(CSSRect(cssCompositionBounds));
|
||||
|
|
|
@ -142,7 +142,7 @@ public:
|
|||
* scroll offset in such a way that it remains in the same place on the page
|
||||
* relative.
|
||||
*/
|
||||
Overscroll ScaleWillOverscroll(float aScale, float aFocus);
|
||||
Overscroll ScaleWillOverscroll(ScreenToScreenScale aScale, float aFocus);
|
||||
|
||||
/**
|
||||
* If a scale will overscroll the axis, this returns the amount and in what
|
||||
|
@ -152,7 +152,7 @@ public:
|
|||
* scroll offset in such a way that it remains in the same place on the page
|
||||
* relative.
|
||||
*/
|
||||
float ScaleWillOverscrollAmount(float aScale, float aFocus);
|
||||
float ScaleWillOverscrollAmount(ScreenToScreenScale aScale, float aFocus);
|
||||
|
||||
/**
|
||||
* Checks if an axis will overscroll in both directions by computing the
|
||||
|
@ -161,7 +161,7 @@ public:
|
|||
*
|
||||
* This gets called by ScaleWillOverscroll().
|
||||
*/
|
||||
bool ScaleWillOverscrollBothSides(float aScale);
|
||||
bool ScaleWillOverscrollBothSides(ScreenToScreenScale aScale);
|
||||
|
||||
float GetOrigin();
|
||||
float GetCompositionLength();
|
||||
|
|
|
@ -178,7 +178,7 @@ TEST(AsyncPanZoomController, ComplexTransform) {
|
|||
metrics.mScrollOffset = CSSPoint(10, 10);
|
||||
metrics.mScrollableRect = CSSRect(0, 0, 50, 50);
|
||||
metrics.mResolution = LayoutDeviceToLayerScale(2);
|
||||
metrics.mZoom = ScreenToScreenScale(1);
|
||||
metrics.mZoom = CSSToScreenScale(6);
|
||||
metrics.mDevPixelsPerCSSPixel = CSSToLayoutDeviceScale(3);
|
||||
metrics.mScrollId = FrameMetrics::ROOT_SCROLL_ID;
|
||||
|
||||
|
|
|
@ -118,7 +118,12 @@ if (!isWindows) {
|
|||
tests.push([ 'bug240933-2.html' , 'bug240933-1-ref.html' ]); // bug 681162
|
||||
tests.push([ 'bug389321-1.html' , 'bug389321-1-ref.html' ]); // bug 683163
|
||||
tests.push([ 'bug482484.html' , 'bug482484-ref.html' ]); // bug 688575
|
||||
tests.push([ 'bug512295-2.html' , 'bug512295-2-ref.html' ]); // bug 681331
|
||||
if (navigator.appVersion.indexOf("Android") == -1 &&
|
||||
SpecialPowers.Services.appinfo.name != "B2G") {
|
||||
tests.push([ 'bug512295-2.html' , 'bug512295-2-ref.html' ]); // bug 681331
|
||||
} else {
|
||||
is(SpecialPowers.getIntPref("layout.spellcheckDefault"), 0, "Spellcheck should be turned off for this platrom or this if..else check removed");
|
||||
}
|
||||
tests.push([ 'bug597519-1.html' , 'bug597519-1-ref.html' ]); // bug 680579
|
||||
tests.push([ 'bug602141-1.html' , 'bug602141-1-ref.html' ]); // bug 681334
|
||||
tests.push([ 'bug602141-2.html' , 'bug602141-2-ref.html' ]); // bug 682836
|
||||
|
|
|
@ -1008,7 +1008,9 @@ RenderFrameParent::ContentReceivedTouch(bool aPreventDefault)
|
|||
}
|
||||
|
||||
void
|
||||
RenderFrameParent::UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom)
|
||||
RenderFrameParent::UpdateZoomConstraints(bool aAllowZoom,
|
||||
const CSSToScreenScale& aMinZoom,
|
||||
const CSSToScreenScale& aMaxZoom)
|
||||
{
|
||||
if (GetApzcTreeManager()) {
|
||||
GetApzcTreeManager()->UpdateZoomConstraints(ScrollableLayerGuid(mLayersId),
|
||||
|
|
|
@ -102,7 +102,9 @@ public:
|
|||
|
||||
void ContentReceivedTouch(bool aPreventDefault);
|
||||
|
||||
void UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom);
|
||||
void UpdateZoomConstraints(bool aAllowZoom,
|
||||
const CSSToScreenScale& aMinZoom,
|
||||
const CSSToScreenScale& aMaxZoom);
|
||||
|
||||
void UpdateScrollOffset(uint32_t aPresShellId,
|
||||
ViewID aViewId,
|
||||
|
|
|
@ -493,12 +493,10 @@ RES_LAYOUT = \
|
|||
res/layout/pin_bookmark_dialog.xml \
|
||||
res/layout/preference_rightalign_icon.xml \
|
||||
res/layout/preference_search_tip.xml \
|
||||
res/layout/search_engine_row.xml \
|
||||
res/layout/site_setting_item.xml \
|
||||
res/layout/site_setting_title.xml \
|
||||
res/layout/shared_ui_components.xml \
|
||||
res/layout/site_identity.xml \
|
||||
res/layout/suggestion_item.xml \
|
||||
res/layout/remote_tabs_child.xml \
|
||||
res/layout/remote_tabs_group.xml \
|
||||
res/layout/search_engine_row.xml \
|
||||
|
|
|
@ -141,6 +141,7 @@ class PromptInput {
|
|||
"week",
|
||||
"time",
|
||||
"datetime-local",
|
||||
"datetime",
|
||||
"month"
|
||||
};
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ public class BookmarksPage extends HomeFragment {
|
|||
mList = (BookmarksListView) view.findViewById(R.id.bookmarks_list);
|
||||
mList.setTag(HomePager.LIST_TAG_BOOKMARKS);
|
||||
mList.setOnUrlOpenListener(listener);
|
||||
mList.setHeaderDividersEnabled(false);
|
||||
|
||||
mTopBookmarks.setOnUrlOpenListener(listener);
|
||||
mTopBookmarks.setOnPinBookmarkListener(mPinBookmarkListener);
|
||||
|
@ -406,6 +407,7 @@ public class BookmarksPage extends HomeFragment {
|
|||
case LOADER_ID_BOOKMARKS_LIST: {
|
||||
mListAdapter.swapCursor(c);
|
||||
loadFavicons(c);
|
||||
mList.setHeaderDividersEnabled(c != null && c.getCount() > 0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -165,7 +165,13 @@ public class ReadingListPage extends HomeFragment {
|
|||
if (imageSpanIndex != -1) {
|
||||
final ImageSpan readingListIcon = new ImageSpan(getActivity(), R.drawable.reader_cropped, ImageSpan.ALIGN_BOTTOM);
|
||||
final SpannableStringBuilder hintBuilder = new SpannableStringBuilder(readingListHint);
|
||||
hintBuilder.setSpan(readingListIcon, imageSpanIndex, imageSpanIndex + 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
|
||||
// Add additional spacing.
|
||||
hintBuilder.insert(imageSpanIndex + 2, " ");
|
||||
hintBuilder.insert(imageSpanIndex, " ");
|
||||
|
||||
// Add icon.
|
||||
hintBuilder.setSpan(readingListIcon, imageSpanIndex + 1, imageSpanIndex + 3, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
|
||||
emptyHint.setText(hintBuilder, TextView.BufferType.SPANNABLE);
|
||||
}
|
||||
|
|
|
@ -281,7 +281,7 @@ size. -->
|
|||
<!-- Localization note (home_reading_list_hint): The "TIP" string is synonymous to "hint", "clue", etc. This string is displayed
|
||||
as an advisory message on how to add content to the reading list when the reading list empty.
|
||||
The "%I" in the string will be replaced by a small image of the icon described, and can be moved to wherever
|
||||
it is applicable.. -->
|
||||
it is applicable. Please keep the spacing around the "%I" string. -->
|
||||
<!ENTITY home_reading_list_hint "TIP: Save articles to your reading list by long pressing the %I icon when it appears in the title bar.">
|
||||
|
||||
<!ENTITY home_most_visited_empty "Websites you visit most frequently show up here.">
|
||||
|
|
|
@ -31,6 +31,7 @@ import android.widget.TextView;
|
|||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.mozilla.gecko.animation.PropertyAnimator;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.gfx.BitmapUtils;
|
||||
|
||||
|
@ -123,11 +124,9 @@ public class ButtonToast {
|
|||
mView.setVisibility(View.VISIBLE);
|
||||
int duration = immediate ? 0 : mView.getResources().getInteger(android.R.integer.config_longAnimTime);
|
||||
|
||||
mView.clearAnimation();
|
||||
AlphaAnimation alpha = new AlphaAnimation(0.0f, 1.0f);
|
||||
alpha.setDuration(duration);
|
||||
alpha.setFillAfter(true);
|
||||
mView.startAnimation(alpha);
|
||||
PropertyAnimator animator = new PropertyAnimator(duration);
|
||||
animator.attach(mView, PropertyAnimator.Property.ALPHA, 1.0f);
|
||||
animator.start();
|
||||
}
|
||||
|
||||
public void hide(boolean immediate, ReasonHidden reason) {
|
||||
|
@ -149,20 +148,20 @@ public class ButtonToast {
|
|||
mView.setVisibility(View.GONE);
|
||||
showNextInQueue();
|
||||
} else {
|
||||
AlphaAnimation alpha = new AlphaAnimation(1.0f, 0.0f);
|
||||
alpha.setDuration(duration);
|
||||
alpha.setFillAfter(true);
|
||||
alpha.setAnimationListener(new Animation.AnimationListener () {
|
||||
// Using Android's animation frameworks will not correctly turn off clicking.
|
||||
// See bug 885717.
|
||||
PropertyAnimator animator = new PropertyAnimator(duration);
|
||||
animator.attach(mView, PropertyAnimator.Property.ALPHA, 0.0f);
|
||||
animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener () {
|
||||
// If we are showing a toast and go in the background
|
||||
// onAnimationEnd will be called when the app is restored
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
public void onPropertyAnimationEnd() {
|
||||
mView.setVisibility(View.GONE);
|
||||
showNextInQueue();
|
||||
}
|
||||
public void onAnimationRepeat(Animation animation) { }
|
||||
public void onAnimationStart(Animation animation) { }
|
||||
public void onPropertyAnimationStart() { }
|
||||
});
|
||||
mView.startAnimation(alpha);
|
||||
animator.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,6 @@
|
|||
"docshell/test/navigation/test_popup-navigates-children.html": "bug 783589",
|
||||
"docshell/test/navigation/test_sessionhistory.html": "RANDOM",
|
||||
"docshell/test/navigation/test_bug344861.html": "",
|
||||
"docshell/test/test_bug94514.html": "TIMED_OUT",
|
||||
"docshell/test/test_bug413310.html": "",
|
||||
"docshell/test/test_bug590573.html": "bug 823022",
|
||||
"docshell/test/test_bug598895.html": "",
|
||||
|
@ -147,7 +146,7 @@
|
|||
"dom/indexedDB/test/test_webapp_clearBrowserData_oop_inproc.html": "No test app installed",
|
||||
"dom/network/tests/test_network_basics.html": "",
|
||||
"dom/permission/tests/test_permission_basics.html": "",
|
||||
"dom/mobilemessage/tests/test_sms_basics.html": "",
|
||||
"dom/mobilemessage/tests/test_sms_basics.html": "Bug 909036",
|
||||
"dom/tests/mochitest/ajax/jquery/test_jQuery.html": "bug 775227",
|
||||
"dom/tests/mochitest/ajax/offline/test_simpleManifest.html": "TIMED_OUT",
|
||||
"dom/tests/mochitest/ajax/offline/test_updatingManifest.html": "TIMED_OUT",
|
||||
|
@ -240,11 +239,11 @@
|
|||
"layout/base/tests/test_bug629838.html": "",
|
||||
"layout/base/tests/test_flush_on_paint.html": "",
|
||||
"layout/base/tests/test_mozPaintCount.html": "",
|
||||
"layout/base/tests/test_reftests_with_caret.html": "",
|
||||
"layout/base/tests/test_reftests_with_caret.html": "1 test failing because of spellcheck, rest passes",
|
||||
"layout/forms/test/test_bug348236.html": "",
|
||||
"layout/forms/test/test_bug378670.html": "TIMED_OUT",
|
||||
"layout/forms/test/test_bug446663.html": "",
|
||||
"layout/forms/test/test_bug478219.xhtml": "",
|
||||
"layout/forms/test/test_bug478219.xhtml": "window.closed not working, bug 907795",
|
||||
"layout/forms/test/test_bug564115.html": "TIMED_OUT",
|
||||
"layout/forms/test/test_bug571352.html": "TIMED_OUT",
|
||||
"layout/forms/test/test_bug572649.html": "TIMED_OUT",
|
||||
|
|
|
@ -115,7 +115,6 @@
|
|||
"docshell/test/navigation/test_popup-navigates-children.html": "bug 783589",
|
||||
"docshell/test/navigation/test_sessionhistory.html": "RANDOM",
|
||||
"docshell/test/navigation/test_bug344861.html": "",
|
||||
"docshell/test/test_bug94514.html": "TIMED_OUT",
|
||||
"docshell/test/test_bug413310.html": "",
|
||||
"docshell/test/test_bug590573.html": "bug 823022",
|
||||
"docshell/test/test_bug598895.html": "",
|
||||
|
@ -151,7 +150,7 @@
|
|||
"dom/indexedDB/test/test_webapp_clearBrowserData_oop_inproc.html": "No test app installed",
|
||||
"dom/network/tests/test_network_basics.html": "",
|
||||
"dom/permission/tests/test_permission_basics.html": "",
|
||||
"dom/mobilemessage/tests/test_sms_basics.html": "",
|
||||
"dom/mobilemessage/tests/test_sms_basics.html": "Bug 909036",
|
||||
"dom/tests/mochitest/ajax/jquery/test_jQuery.html": "bug 775227",
|
||||
"dom/tests/mochitest/ajax/offline/test_simpleManifest.html": "TIMED_OUT",
|
||||
"dom/tests/mochitest/ajax/offline/test_updatingManifest.html": "TIMED_OUT",
|
||||
|
@ -244,11 +243,11 @@
|
|||
"layout/base/tests/test_bug629838.html": "",
|
||||
"layout/base/tests/test_flush_on_paint.html": "",
|
||||
"layout/base/tests/test_mozPaintCount.html": "",
|
||||
"layout/base/tests/test_reftests_with_caret.html": "",
|
||||
"layout/base/tests/test_reftests_with_caret.html": "1 test failing because of spellcheck, rest passes",
|
||||
"layout/forms/test/test_bug348236.html": "",
|
||||
"layout/forms/test/test_bug378670.html": "TIMED_OUT",
|
||||
"layout/forms/test/test_bug446663.html": "",
|
||||
"layout/forms/test/test_bug478219.xhtml": "",
|
||||
"layout/forms/test/test_bug478219.xhtml": "window.closed not working, bug 907795",
|
||||
"layout/forms/test/test_bug564115.html": "TIMED_OUT",
|
||||
"layout/forms/test/test_bug571352.html": "TIMED_OUT",
|
||||
"layout/forms/test/test_bug572649.html": "TIMED_OUT",
|
||||
|
|
|
@ -11,26 +11,8 @@
|
|||
"layout/xul" : "",
|
||||
"dom/tests/mochitest/general/test_focusrings.xul":"",
|
||||
"layout/base/tests/test_bug465448.xul":"",
|
||||
"content/base/test/test_bug590870.html":"",
|
||||
"content/base/test/test_classList.html":"1806 tests, 1 test failing because of xul",
|
||||
"content/base/test/test_title.html":"",
|
||||
"content/events/test/test_bug547996-2.xhtml":"16 tests total",
|
||||
"content/html/content/test/test_bug458037.xhtml":"",
|
||||
|
||||
"content/xbl/":"tests that use xbl",
|
||||
"layout/style/test/test_media_queries_dynamic_xbl.html":"",
|
||||
"content/base/test/test_xbl_userdata.xhtml":"",
|
||||
"content/base/test/test_base.xhtml":"",
|
||||
"content/base/test/test_bug330925.xhtml":"",
|
||||
"content/base/test/test_bug372086.html":"",
|
||||
"content/base/test/test_bug419527.xhtml":"",
|
||||
"content/base/test/test_bug444030.xhtml":"",
|
||||
"content/events/test/test_bug391568.xhtml":"",
|
||||
"layout/inspector/tests/test_bug522601.xhtml":"",
|
||||
"layout/style/test/test_selectors_on_anonymous_content.html":"",
|
||||
"layout/forms/test/test_bug478219.xhtml":"",
|
||||
"layout/inspector/tests/test_bug609549.xhtml":"",
|
||||
"content/xslt/tests/mochitest/test_bug319374.xhtml":"",
|
||||
"layout/forms/test/test_bug478219.xhtml":"window.closed not working, bug 907795",
|
||||
|
||||
"content/media/test/test_bug448534.html": "Timed out, bug 894922? Bug 902677 is for the timing out of a lot of media tests",
|
||||
"content/media/mediasource/test/test_MediaSource.html": " ReferenceError: MediaSource is not defined",
|
||||
|
@ -135,6 +117,8 @@
|
|||
"dom/tests/mochitest/ajax/offline/test_lowDeviceStorageDuringUpdate.html":"",
|
||||
"dom/tests/mochitest/ajax/offline/test_missingFile.html":"",
|
||||
"dom/tests/mochitest/ajax/offline/test_missingManifest.html":"",
|
||||
"dom/tests/mochitest/ajax/offline/test_noManifest.html":"",
|
||||
"dom/tests/mochitest/general/test_bug629535.html":"bug 908439",
|
||||
"dom/tests/mochitest/ajax/offline/test_obsolete.html":"",
|
||||
"dom/tests/mochitest/ajax/offline/test_offlineIFrame.html":"",
|
||||
"dom/tests/mochitest/ajax/offline/test_overlap.html":"",
|
||||
|
@ -179,8 +163,6 @@
|
|||
|
||||
"content/html/content/test/forms/test_input_file_picker.html":"5 failures out of 139 and timing out, bug 901581",
|
||||
"content/html/content/test/forms/test_validation.html":"374 total, bug 901848, no keygen support",
|
||||
"content/html/content/test/test_bug209275.xhtml":"timed out, 47 tests, bug 870262, :visited support",
|
||||
"content/html/content/test/test_bug481335.xhtml":"timed out, bug 870262, :visited support",
|
||||
|
||||
"content/html/content/test/test_bug430351.html":"13 failing out of 700, not focusable iframes? bug 902207",
|
||||
|
||||
|
@ -202,27 +184,24 @@
|
|||
|
||||
"content/html/content/test/test_iframe_sandbox_plugins.html":"plugins not supported",
|
||||
"content/html/content/test/test_object_plugin_nav.html":"plugins not supported",
|
||||
"content/html/document/test/test_bug199692.html":"",
|
||||
"content/html/document/test/test_bug741266.html":"",
|
||||
"docshell/test/navigation/test_popup-navigates-children.html":"",
|
||||
"docshell/test/test_bug590573.html":"",
|
||||
"dom/devicestorage/ipc/test_ipc.html":"",
|
||||
"dom/file/test/test_progress_events.html":"",
|
||||
"dom/file/test/test_request_readyState.html":"",
|
||||
"dom/file/test/test_stream_tracking.html":"",
|
||||
"dom/indexedDB/ipc/test_ipc.html":"",
|
||||
"dom/indexedDB/test/test_lowDiskSpace.html":"",
|
||||
"dom/tests/mochitest/ajax/offline/test_noManifest.html":"",
|
||||
"dom/tests/mochitest/general/test_bug629535.html":"",
|
||||
"content/base/test/test_object.html":"",
|
||||
"content/base/test/test_CSP_evalscript.html":"",
|
||||
"content/base/test/test_CSP_evalscript_getCRMFRequest.html":"",
|
||||
"content/base/test/test_CSP_frameancestors.html":"",
|
||||
"content/svg/content/test/test_text_selection.html":"",
|
||||
"content/base/test/test_CSP.html":"",
|
||||
"content/base/test/test_CrossSiteXHR_origin.html":"",
|
||||
"content/base/test/test_bug326337.html":"",
|
||||
"content/base/test/test_bug564863.xhtml":"",
|
||||
"content/html/document/test/test_bug199692.html":"needs popup to be sized to 600*600",
|
||||
"content/html/document/test/test_bug741266.html":"needs control of popup window size",
|
||||
"docshell/test/navigation/test_popup-navigates-children.html":"Needs multiple window.open support, also uses docshelltreenode",
|
||||
"docshell/test/test_bug590573.html":"queryinterfaces into webnavigation, might suffer from something similar as bug 823022",
|
||||
"dom/devicestorage/ipc/test_ipc.html":"nested ipc not working",
|
||||
|
||||
"dom/indexedDB/ipc/test_ipc.html":"nested ipc not working",
|
||||
"dom/indexedDB/test/test_lowDiskSpace.html":"this needs probably modification for notifyObserversInParentProcess to be similar as pushPermissions",
|
||||
|
||||
"content/base/test/test_object.html":"needs plugin support",
|
||||
|
||||
"content/base/test/test_CSP_evalscript.html":"observer not working",
|
||||
"content/base/test/test_CSP_evalscript_getCRMFRequest.html":"observer not working",
|
||||
"content/base/test/test_CSP_frameancestors.html":"observer not working",
|
||||
"content/base/test/test_CSP.html":"observer not working",
|
||||
|
||||
"content/base/test/test_CrossSiteXHR_origin.html":"https not working, bug 907770",
|
||||
"content/base/test/test_bug326337.html":"popup windows don't have specialpowers installed, could be solved with sendmessage/receivemessage",
|
||||
"content/base/test/test_plugin_freezing.html":"",
|
||||
"content/base/test/test_bug466409.html":"",
|
||||
"content/base/test/test_bug482935.html":"",
|
||||
|
@ -257,6 +236,7 @@
|
|||
"content/events/test/test_wheel_default_action.html":"",
|
||||
"content/base/test/test_bug682592.html":"",
|
||||
"content/html/document/test/test_bug369370.html":"",
|
||||
"content/svg/content/test/test_text_selection.html":"Mouse selection not workin on b2g",
|
||||
"content/svg/content/test/test_SVGAnimatedImageSMILDisabled.html":"",
|
||||
"content/xml/document/test/test_bug392338.html":"",
|
||||
"content/base/test/test_bothCSPheaders.html":"",
|
||||
|
@ -274,9 +254,7 @@
|
|||
"docshell/test/navigation/test_bug386782.html":"",
|
||||
"docshell/test/navigation/test_not-opener.html":"",
|
||||
"docshell/test/navigation/test_reserved.html":"",
|
||||
"docshell/test/test_bug369814.html":"",
|
||||
"docshell/test/test_bug413310.html":"",
|
||||
"docshell/test/test_bug94514.html":"",
|
||||
|
||||
"dom/imptests/html/webgl":"",
|
||||
"dom/battery/test/test_battery_basics.html":"",
|
||||
|
@ -289,6 +267,9 @@
|
|||
"dom/browser-element/mochitest/test_browserElement_inproc_CloseFromOpener.html":"",
|
||||
"dom/browser-element/":"",
|
||||
|
||||
"dom/file/test/test_progress_events.html":"All of these fail fairly regularly with: UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:126",
|
||||
"dom/file/test/test_request_readyState.html":"",
|
||||
"dom/file/test/test_stream_tracking.html":"",
|
||||
"dom/file/test/test_append_read_data.html":"",
|
||||
"dom/file/test/test_archivereader.html":"",
|
||||
"dom/file/test/test_archivereader_nonUnicode.html":"",
|
||||
|
@ -303,10 +284,11 @@
|
|||
"dom/file/test/test_truncate.html":"",
|
||||
"dom/file/test/test_workers.html":"",
|
||||
"dom/file/test/test_write_read_data.html":"",
|
||||
"dom/imptests/editing/conformancetest/test_event.html":"",
|
||||
"dom/imptests/editing/conformancetest/test_runtest.html":"",
|
||||
|
||||
"dom/media/tests/mochitest/test_dataChannel_basicAudio.html":"",
|
||||
"dom/imptests/editing/conformancetest/test_event.html":"1 failure, bug 908879",
|
||||
"dom/imptests/editing/conformancetest/test_runtest.html":"takes too long",
|
||||
|
||||
"dom/media/tests/mochitest/test_dataChannel_basicAudio.html":"bug 908473",
|
||||
"dom/media/tests/mochitest/test_dataChannel_basicAudioVideo.html":"",
|
||||
"dom/media/tests/mochitest/test_dataChannel_basicAudioVideoCombined.html":"",
|
||||
"dom/media/tests/mochitest/test_dataChannel_basicDataOnly.html":"",
|
||||
|
@ -334,9 +316,9 @@
|
|||
"dom/media/tests/mochitest/test_peerConnection_setRemoteOfferInHaveLocalOffer.html":"",
|
||||
"dom/media/tests/mochitest/test_peerConnection_throwInCallbacks.html":"",
|
||||
|
||||
"dom/mobilemessage/tests/test_sms_basics.html":"",
|
||||
"dom/network/tests/test_networkstats_basics.html":"",
|
||||
"dom/permission/tests/test_permission_basics.html":"",
|
||||
"dom/mobilemessage/tests/test_sms_basics.html":"Bug 909036",
|
||||
"dom/network/tests/test_networkstats_basics.html":"Bug 908935",
|
||||
"dom/permission/tests/test_permission_basics.html":"Bug 908912 and bug 907770",
|
||||
|
||||
"dom/tests/mochitest/bugs/test_bug265203.html":"",
|
||||
|
||||
|
@ -430,7 +412,7 @@
|
|||
"layout/base/tests/test_mozPaintCount.html":"",
|
||||
"layout/base/tests/test_scroll_selection_into_view.html":"",
|
||||
"layout/base/tests/test_bug761572.html":"",
|
||||
"layout/base/tests/test_reftests_with_caret.html":"",
|
||||
"layout/base/tests/test_reftests_with_caret.html":"Bug 909043, 1 test failing because of spellcheck",
|
||||
"layout/base/tests/test_scroll_event_ordering.html":"",
|
||||
"layout/forms/test/test_bug287446.html":"",
|
||||
"layout/forms/test/test_bug348236.html":"",
|
||||
|
@ -500,11 +482,15 @@
|
|||
"layout/style/test/test_value_storage.html":"",
|
||||
"layout/style/test/test_viewport_units.html":"",
|
||||
"layout/style/test/test_viewport_units.html":"",
|
||||
"layout/style/test/test_visited_image_loading.html":"",
|
||||
"layout/style/test/test_visited_image_loading_empty.html":"",
|
||||
"layout/style/test/test_visited_lying.html" : "timed out",
|
||||
"layout/style/test/test_visited_pref.html" : "timed out",
|
||||
"layout/style/test/test_visited_reftests.html":"",
|
||||
|
||||
"content/html/content/test/test_bug209275.xhtml":"timed out, 47 tests, bug 870262, :visited support",
|
||||
"content/html/content/test/test_bug481335.xhtml":"timed out, bug 870262, :visited support",
|
||||
"layout/style/test/test_visited_image_loading.html":"bug 870262, :visited support",
|
||||
"layout/style/test/test_visited_image_loading_empty.html":"bug 870262, :visited support",
|
||||
"layout/style/test/test_visited_lying.html" : "bug 870262, :visited support",
|
||||
"layout/style/test/test_visited_pref.html" : "bug 870262, :visited support",
|
||||
"layout/style/test/test_visited_reftests.html":"bug 870262, :visited support",
|
||||
|
||||
"layout/tables/test/test_bug541668_table_event_delivery.html":"",
|
||||
|
||||
"Harness_sanity/test_sanityEventUtils.html": "bug 688052",
|
||||
|
|
|
@ -20,6 +20,7 @@ function starttest(){
|
|||
SpecialPowers.addPermission("pPROMPT", PROMPT_ACTION, document);
|
||||
SpecialPowers.addPermission("pALLOW", ALLOW_ACTION, document);
|
||||
SpecialPowers.addPermission("pDENY", DENY_ACTION, document);
|
||||
SpecialPowers.addPermission("pREMOVE", ALLOW_ACTION, document);
|
||||
|
||||
setTimeout(test1, 0);
|
||||
}
|
||||
|
@ -36,6 +37,9 @@ function test1() {
|
|||
} else if (!SpecialPowers.testPermission('pPROMPT', PROMPT_ACTION, document)) {
|
||||
dump('/**** prompt not set ****/\n');
|
||||
setTimeout(test1, 0);
|
||||
} else if (!SpecialPowers.testPermission('pREMOVE', ALLOW_ACTION, document)) {
|
||||
dump('/**** remove not set ****/\n');
|
||||
setTimeout(test1, 0);
|
||||
} else {
|
||||
test2();
|
||||
}
|
||||
|
@ -43,20 +47,29 @@ function test1() {
|
|||
|
||||
function test2() {
|
||||
ok(SpecialPowers.testPermission('pUNKNOWN', UNKNOWN_ACTION, document), 'pUNKNOWN value should have UNKOWN permission');
|
||||
SpecialPowers.pushPermissions([{'type': 'pUNKNOWN', 'allow': true, 'context': document}, {'type': 'pALLOW', 'allow': false, 'context': document}, {'type': 'pDENY', 'allow': true, 'context': document}, {'type': 'pPROMPT', 'allow': true, 'context': document}], test3);
|
||||
SpecialPowers.pushPermissions([{'type': 'pUNKNOWN', 'allow': true, 'context': document}, {'type': 'pALLOW', 'allow': false, 'context': document}, {'type': 'pDENY', 'allow': true, 'context': document}, {'type': 'pPROMPT', 'allow': true, 'context': document}, {'type': 'pREMOVE', 'remove': true, 'context': document}], test3);
|
||||
}
|
||||
|
||||
function test3() {
|
||||
ok(SpecialPowers.testPermission('pUNKNOWN', ALLOW_ACTION, document), 'pUNKNOWN value should have ALLOW permission');
|
||||
ok(SpecialPowers.testPermission('pPROMPT', ALLOW_ACTION, document), 'pUNKNOWN value should have ALLOW permission');
|
||||
ok(SpecialPowers.testPermission('pPROMPT', ALLOW_ACTION, document), 'pPROMPT value should have ALLOW permission');
|
||||
ok(SpecialPowers.testPermission('pALLOW', DENY_ACTION, document), 'pALLOW should have DENY permission');
|
||||
ok(SpecialPowers.testPermission('pDENY', ALLOW_ACTION, document), 'pDENY should have ALLOW permission');
|
||||
ok(SpecialPowers.testPermission('pREMOVE', UNKNOWN_ACTION, document), 'pREMOVE should have REMOVE permission');
|
||||
// only pPROMPT (last one) is different, the other stuff is just to see if it doesn't cause test failures
|
||||
SpecialPowers.pushPermissions([{'type': 'pUNKNOWN', 'allow': true, 'context': document}, {'type': 'pALLOW', 'allow': false, 'context': document}, {'type': 'pDENY', 'allow': true, 'context': document}, {'type': 'pPROMPT', 'allow': false, 'context': document}], test4);
|
||||
SpecialPowers.pushPermissions([{'type': 'pUNKNOWN', 'allow': true, 'context': document}, {'type': 'pALLOW', 'allow': false, 'context': document}, {'type': 'pDENY', 'allow': true, 'context': document}, {'type': 'pPROMPT', 'allow': false, 'context': document}], test3b);
|
||||
}
|
||||
|
||||
function test3b() {
|
||||
ok(SpecialPowers.testPermission('pPROMPT', DENY_ACTION, document), 'pPROMPT value should have DENY permission');
|
||||
SpecialPowers.pushPermissions([{'type': 'pUNKNOWN', 'allow': DENY_ACTION, 'context': document}, {'type': 'pALLOW', 'allow': PROMPT_ACTION, 'context': document}, {'type': 'pDENY', 'allow': PROMPT_ACTION, 'context': document}, {'type': 'pPROMPT', 'allow': ALLOW_ACTION, 'context': document}], test4);
|
||||
}
|
||||
|
||||
function test4() {
|
||||
ok(SpecialPowers.testPermission('pPROMPT', DENY_ACTION, document), 'pPROMPT value should have DENY permission');
|
||||
ok(SpecialPowers.testPermission('pUNKNOWN', DENY_ACTION, document), 'pUNKNOWN value should have DENY permission');
|
||||
ok(SpecialPowers.testPermission('pPROMPT', ALLOW_ACTION, document), 'pPROMPT value should have ALLOW permission');
|
||||
ok(SpecialPowers.testPermission('pALLOW', PROMPT_ACTION, document), 'pALLOW should have PROMPT permission');
|
||||
ok(SpecialPowers.testPermission('pDENY', PROMPT_ACTION, document), 'pDENY should have PROMPT permission');
|
||||
//this should reset all the permissions to before all the pushPermissions calls
|
||||
SpecialPowers.flushPermissions(test5);
|
||||
}
|
||||
|
@ -67,10 +80,12 @@ function test5() {
|
|||
ok(SpecialPowers.testPermission('pALLOW', ALLOW_ACTION, document), 'pALLOW should have ALLOW permission');
|
||||
ok(SpecialPowers.testPermission('pDENY', DENY_ACTION, document), 'pDENY should have DENY permission');
|
||||
ok(SpecialPowers.testPermission('pPROMPT', PROMPT_ACTION, document), 'pPROMPT should have PROMPT permission');
|
||||
ok(SpecialPowers.testPermission('pREMOVE', ALLOW_ACTION, document), 'pREMOVE should have ALLOW permission');
|
||||
|
||||
SpecialPowers.removePermission("pPROMPT", document);
|
||||
SpecialPowers.removePermission("pALLOW", document);
|
||||
SpecialPowers.removePermission("pDENY", document);
|
||||
SpecialPowers.removePermission("pREMOVE", document);
|
||||
|
||||
setTimeout(test6, 0);
|
||||
}
|
||||
|
@ -85,6 +100,9 @@ function test6() {
|
|||
} else if (!SpecialPowers.testPermission('pPROMPT', UNKNOWN_ACTION, document)) {
|
||||
dump('/**** prompt still set ****/\n');
|
||||
setTimeout(test6, 0);
|
||||
} else if (!SpecialPowers.testPermission('pREMOVE', UNKNOWN_ACTION, document)) {
|
||||
dump('/**** remove still set ****/\n');
|
||||
setTimeout(test6, 0);
|
||||
} else {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
|
|
@ -561,7 +561,7 @@ SpecialPowersAPI.prototype = {
|
|||
[{'type': 'SystemXHR', 'allow': 1, 'context': document},
|
||||
{'type': 'SystemXHR', 'allow': Ci.nsIPermissionManager.PROMPT_ACTION, 'context': document}]
|
||||
|
||||
allow is a boolean and can be true/false or 1/0
|
||||
Allow can be a boolean value of true/false or ALLOW_ACTION/DENY_ACTION/PROMPT_ACTION/UNKNOWN_ACTION
|
||||
*/
|
||||
pushPermissions: function(inPermissions, callback) {
|
||||
var pendingPermissions = [];
|
||||
|
@ -591,7 +591,12 @@ SpecialPowersAPI.prototype = {
|
|||
if (originalValue == perm) {
|
||||
continue;
|
||||
}
|
||||
pendingPermissions.push({'op': 'add', 'type': permission.type, 'permission': perm, 'value': perm, 'url': url, 'appId': appId, 'isInBrowserElement': isInBrowserElement});
|
||||
|
||||
var todo = {'op': 'add', 'type': permission.type, 'permission': perm, 'value': perm, 'url': url, 'appId': appId, 'isInBrowserElement': isInBrowserElement};
|
||||
if (permission.remove == true)
|
||||
todo.op = 'remove';
|
||||
|
||||
pendingPermissions.push(todo);
|
||||
|
||||
/* Push original permissions value or clear into cleanup array */
|
||||
var cleanupTodo = {'op': 'add', 'type': permission.type, 'permission': perm, 'value': perm, 'url': url, 'appId': appId, 'isInBrowserElement': isInBrowserElement};
|
||||
|
|
|
@ -160,6 +160,11 @@ let Scheduler = {
|
|||
if (!("durationMs" in data)) {
|
||||
return data.ok;
|
||||
}
|
||||
// Bug 874425 demonstrates that two successive calls to Date.now()
|
||||
// can actually produce an interval with negative duration.
|
||||
// We assume that this is due to an operation that is so short
|
||||
// that Date.now() is not monotonic, so we round this up to 0.
|
||||
let durationMs = Math.max(0, data.durationMs);
|
||||
// Accumulate (or initialize) outExecutionDuration
|
||||
if (typeof options.outExecutionDuration == "number") {
|
||||
options.outExecutionDuration += data.durationMs;
|
||||
|
|
|
@ -902,7 +902,8 @@ DebuggerServerConnection.prototype = {
|
|||
let actor = this.getActor(aPacket.to);
|
||||
if (!actor) {
|
||||
this.transport.send({ from: aPacket.to ? aPacket.to : "root",
|
||||
error: "noSuchActor" });
|
||||
error: "noSuchActor",
|
||||
message: "No such actor for ID: " + aPacket.to });
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2131,6 +2131,15 @@ this.AddonManagerPrivate = {
|
|||
|
||||
getSimpleMeasures: function AMP_getSimpleMeasures() {
|
||||
return this._simpleMeasures;
|
||||
},
|
||||
|
||||
// Start a timer, record a simple measure of the time interval when
|
||||
// timer.done() is called
|
||||
simpleTimer: function(aName) {
|
||||
let startTime = Date.now();
|
||||
return {
|
||||
done: () => AddonManagerPrivate.recordSimpleMeasure(aName, Date.now() - startTime)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -94,11 +94,8 @@ const KEY_APP_SYSTEM_LOCAL = "app-system-local";
|
|||
const KEY_APP_SYSTEM_SHARE = "app-system-share";
|
||||
const KEY_APP_SYSTEM_USER = "app-system-user";
|
||||
|
||||
const UNKNOWN_XPCOM_ABI = "unknownABI";
|
||||
const XPI_PERMISSION = "install";
|
||||
|
||||
const PREFIX_ITEM_URI = "urn:mozilla:item:";
|
||||
const RDFURI_ITEM_ROOT = "urn:mozilla:item:root"
|
||||
const RDFURI_INSTALL_MANIFEST_ROOT = "urn:mozilla:install-manifest";
|
||||
const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#";
|
||||
|
||||
|
@ -159,6 +156,14 @@ const TYPES = {
|
|||
dictionary: 64
|
||||
};
|
||||
|
||||
// Keep track of where we are in startup for telemetry
|
||||
// event happened during XPIDatabase.startup()
|
||||
const XPI_STARTING = "XPIStarting";
|
||||
// event happened after startup() but before the final-ui-startup event
|
||||
const XPI_BEFORE_UI_STARTUP = "BeforeFinalUIStartup";
|
||||
// event happened after final-ui-startup
|
||||
const XPI_AFTER_UI_STARTUP = "AfterFinalUIStartup";
|
||||
|
||||
const COMPATIBLE_BY_DEFAULT_TYPES = {
|
||||
extension: true,
|
||||
dictionary: true
|
||||
|
@ -1538,6 +1543,8 @@ var XPIProvider = {
|
|||
inactiveAddonIDs: [],
|
||||
// Count of unpacked add-ons
|
||||
unpackedAddons: 0,
|
||||
// Keep track of startup phases for telemetry
|
||||
runPhase: XPI_STARTING,
|
||||
|
||||
/**
|
||||
* Adds or updates a URI mapping for an Addon.id.
|
||||
|
@ -1674,6 +1681,7 @@ var XPIProvider = {
|
|||
*/
|
||||
startup: function XPI_startup(aAppChanged, aOldAppVersion, aOldPlatformVersion) {
|
||||
LOG("startup");
|
||||
this.runPhase = XPI_STARTING;
|
||||
this.installs = [];
|
||||
this.installLocations = [];
|
||||
this.installLocationsByName = {};
|
||||
|
@ -1848,9 +1856,19 @@ var XPIProvider = {
|
|||
}
|
||||
}, "quit-application-granted", false);
|
||||
|
||||
// Detect final-ui-startup for telemetry reporting
|
||||
Services.obs.addObserver({
|
||||
observe: function uiStartupObserver(aSubject, aTopic, aData) {
|
||||
AddonManagerPrivate.recordTimestamp("XPI_finalUIStartup");
|
||||
XPIProvider.runPhase = XPI_AFTER_UI_STARTUP;
|
||||
Services.obs.removeObserver(this, "final-ui-startup");
|
||||
}
|
||||
}, "final-ui-startup", false);
|
||||
|
||||
AddonManagerPrivate.recordTimestamp("XPI_startup_end");
|
||||
|
||||
this.extensionsActive = true;
|
||||
this.runPhase = XPI_BEFORE_UI_STARTUP;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1935,7 +1953,7 @@ var XPIProvider = {
|
|||
var variant = Cc["@mozilla.org/variant;1"].
|
||||
createInstance(Ci.nsIWritableVariant);
|
||||
variant.setFromVariant(this.inactiveAddonIDs);
|
||||
|
||||
|
||||
// This *must* be modal as it has to block startup.
|
||||
var features = "chrome,centerscreen,dialog,titlebar,modal";
|
||||
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
|
@ -1979,7 +1997,7 @@ var XPIProvider = {
|
|||
Services.appinfo.annotateCrashReport("Add-ons", data);
|
||||
}
|
||||
catch (e) { }
|
||||
|
||||
|
||||
const TelemetryPing = Cc["@mozilla.org/base/telemetry-ping;1"].getService(Ci.nsITelemetryPing);
|
||||
TelemetryPing.setAddOns(data);
|
||||
},
|
||||
|
@ -3143,9 +3161,12 @@ var XPIProvider = {
|
|||
if (aAppChanged !== false)
|
||||
this.importPermissions();
|
||||
|
||||
// If the application version has changed then the database information
|
||||
// needs to be updated
|
||||
let updateDatabase = aAppChanged;
|
||||
// Keep track of whether and why we need to open and update the database at
|
||||
// startup time.
|
||||
let updateReasons = [];
|
||||
if (aAppChanged) {
|
||||
updateReasons.push("appChanged");
|
||||
}
|
||||
|
||||
// Load the list of bootstrapped add-ons first so processFileChanges can
|
||||
// modify it
|
||||
|
@ -3160,7 +3181,10 @@ var XPIProvider = {
|
|||
// changes then we must update the database with the information in the
|
||||
// install locations
|
||||
let manifests = {};
|
||||
updateDatabase = this.processPendingFileChanges(manifests) || updateDatabase;
|
||||
let updated = this.processPendingFileChanges(manifests);
|
||||
if (updated) {
|
||||
updateReasons.push("pendingFileChanges");
|
||||
}
|
||||
|
||||
// This will be true if the previous session made changes that affect the
|
||||
// active state of add-ons but didn't commit them properly (normally due
|
||||
|
@ -3168,33 +3192,41 @@ var XPIProvider = {
|
|||
let hasPendingChanges = Prefs.getBoolPref(PREF_PENDING_OPERATIONS);
|
||||
|
||||
// If the schema appears to have changed then we should update the database
|
||||
updateDatabase = updateDatabase || DB_SCHEMA != Prefs.getIntPref(PREF_DB_SCHEMA, 0);
|
||||
if (DB_SCHEMA != Prefs.getIntPref(PREF_DB_SCHEMA, 0)) {
|
||||
updateReasons.push("schemaChanged");
|
||||
}
|
||||
|
||||
// If the application has changed then check for new distribution add-ons
|
||||
if (aAppChanged !== false &&
|
||||
Prefs.getBoolPref(PREF_INSTALL_DISTRO_ADDONS, true))
|
||||
updateDatabase = this.installDistributionAddons(manifests) || updateDatabase;
|
||||
{
|
||||
updated = this.installDistributionAddons(manifests);
|
||||
if (updated) {
|
||||
updateReasons.push("installDistributionAddons");
|
||||
}
|
||||
}
|
||||
|
||||
// Telemetry probe added around getInstallLocationStates() to check perf
|
||||
let telemetryCaptureTime = new Date();
|
||||
let telemetryCaptureTime = Date.now();
|
||||
let state = this.getInstallLocationStates();
|
||||
let telemetry = Services.telemetry;
|
||||
telemetry.getHistogramById("CHECK_ADDONS_MODIFIED_MS").add(new Date() - telemetryCaptureTime);
|
||||
telemetry.getHistogramById("CHECK_ADDONS_MODIFIED_MS").add(Date.now() - telemetryCaptureTime);
|
||||
|
||||
if (!updateDatabase) {
|
||||
// If the state has changed then we must update the database
|
||||
let cache = Prefs.getCharPref(PREF_INSTALL_CACHE, null);
|
||||
updateDatabase = cache != JSON.stringify(state);
|
||||
// If the install directory state has changed then we must update the database
|
||||
let cache = Prefs.getCharPref(PREF_INSTALL_CACHE, null);
|
||||
if (cache != JSON.stringify(state)) {
|
||||
updateReasons.push("directoryState");
|
||||
}
|
||||
|
||||
// If the database doesn't exist and there are add-ons installed then we
|
||||
// must update the database however if there are no add-ons then there is
|
||||
// no need to update the database.
|
||||
let dbFile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_DATABASE], true);
|
||||
if (!dbFile.exists())
|
||||
updateDatabase = state.length > 0;
|
||||
if (!dbFile.exists() && state.length > 0) {
|
||||
updateReasons.push("needNewDatabase");
|
||||
}
|
||||
|
||||
if (!updateDatabase) {
|
||||
if (updateReasons.length == 0) {
|
||||
let bootstrapDescriptors = [this.bootstrappedAddons[b].descriptor
|
||||
for (b in this.bootstrappedAddons)];
|
||||
|
||||
|
@ -3208,7 +3240,7 @@ var XPIProvider = {
|
|||
|
||||
if (bootstrapDescriptors.length > 0) {
|
||||
WARN("Bootstrap state is invalid (missing add-ons: " + bootstrapDescriptors.toSource() + ")");
|
||||
updateDatabase = true;
|
||||
updateReasons.push("missingBootstrapAddon");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3217,7 +3249,11 @@ var XPIProvider = {
|
|||
let extensionListChanged = false;
|
||||
// If the database needs to be updated then open it and then update it
|
||||
// from the filesystem
|
||||
if (updateDatabase || hasPendingChanges) {
|
||||
if (hasPendingChanges) {
|
||||
updateReasons.push("hasPendingChanges");
|
||||
}
|
||||
if (updateReasons.length > 0) {
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startup_load_reasons", updateReasons);
|
||||
XPIDatabase.syncLoadDB(false);
|
||||
try {
|
||||
extensionListChanged = this.processFileChanges(state, manifests,
|
||||
|
|
|
@ -68,24 +68,6 @@ const DB_BOOL_METADATA = ["visible", "active", "userDisabled", "appDisabled",
|
|||
"softDisabled", "isForeignInstall",
|
||||
"hasBinaryComponents", "strictCompatibility"];
|
||||
|
||||
const FIELDS_ADDON = "internal_id, id, syncGUID, location, version, type, " +
|
||||
"internalName, updateURL, updateKey, optionsURL, " +
|
||||
"optionsType, aboutURL, iconURL, icon64URL, " +
|
||||
"defaultLocale, visible, active, userDisabled, " +
|
||||
"appDisabled, pendingUninstall, descriptor, " +
|
||||
"installDate, updateDate, applyBackgroundUpdates, bootstrap, " +
|
||||
"skinnable, size, sourceURI, releaseNotesURI, softDisabled, " +
|
||||
"isForeignInstall, hasBinaryComponents, strictCompatibility";
|
||||
|
||||
|
||||
// Properties that exist in the install manifest
|
||||
const PROP_METADATA = ["id", "version", "type", "internalName", "updateURL",
|
||||
"updateKey", "optionsURL", "optionsType", "aboutURL",
|
||||
"iconURL", "icon64URL"];
|
||||
const PROP_LOCALE_SINGLE = ["name", "description", "creator", "homepageURL"];
|
||||
const PROP_LOCALE_MULTI = ["developers", "translators", "contributors"];
|
||||
const PROP_TARGETAPP = ["id", "minVersion", "maxVersion"];
|
||||
|
||||
// Properties to save in JSON file
|
||||
const PROP_JSON_FIELDS = ["id", "syncGUID", "location", "version", "type",
|
||||
"internalName", "updateURL", "updateKey", "optionsURL",
|
||||
|
@ -549,11 +531,11 @@ this.XPIDatabase = {
|
|||
* (if false, caller is XPIProvider.checkForChanges() which will rebuild)
|
||||
*/
|
||||
syncLoadDB: function XPIDB_syncLoadDB(aRebuildOnError) {
|
||||
// XXX TELEMETRY report synchronous opens (startup time) vs. delayed opens
|
||||
this.migrateData = null;
|
||||
let fstream = null;
|
||||
let data = "";
|
||||
try {
|
||||
let readTimer = AddonManagerPrivate.simpleTimer("XPIDB_syncRead_MS");
|
||||
LOG("Opening XPI database " + this.jsonFile.path);
|
||||
fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
|
@ -570,11 +552,14 @@ this.XPIDatabase = {
|
|||
data += str.value;
|
||||
} while (read != 0);
|
||||
}
|
||||
readTimer.done();
|
||||
this.parseDB(data, aRebuildOnError);
|
||||
}
|
||||
catch(e) {
|
||||
ERROR("Failed to load XPI JSON data from profile", e);
|
||||
let rebuildTimer = AddonManagerPrivate.simpleTimer("XPIDB_rebuildReadFailed_MS");
|
||||
this.rebuildDatabase(aRebuildOnError);
|
||||
rebuildTimer.done();
|
||||
}
|
||||
finally {
|
||||
if (cstream)
|
||||
|
@ -582,7 +567,7 @@ this.XPIDatabase = {
|
|||
}
|
||||
}
|
||||
catch (e) {
|
||||
if (e.result == Cr.NS_ERROR_FILE_NOT_FOUND) {
|
||||
if (e.result === Cr.NS_ERROR_FILE_NOT_FOUND) {
|
||||
this.upgradeDB(aRebuildOnError);
|
||||
}
|
||||
else {
|
||||
|
@ -595,8 +580,10 @@ this.XPIDatabase = {
|
|||
}
|
||||
// If an async load was also in progress, resolve that promise with our DB;
|
||||
// otherwise create a resolved promise
|
||||
if (this._dbPromise)
|
||||
if (this._dbPromise) {
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_overlapped_load", 1);
|
||||
this._dbPromise.resolve(this.addonDB);
|
||||
}
|
||||
else
|
||||
this._dbPromise = Promise.resolve(this.addonDB);
|
||||
},
|
||||
|
@ -607,20 +594,27 @@ this.XPIDatabase = {
|
|||
* If true, synchronously reconstruct the database from installed add-ons
|
||||
*/
|
||||
parseDB: function(aData, aRebuildOnError) {
|
||||
let parseTimer = AddonManagerPrivate.simpleTimer("XPIDB_parseDB_MS");
|
||||
try {
|
||||
// dump("Loaded JSON:\n" + aData + "\n");
|
||||
let inputAddons = JSON.parse(aData);
|
||||
// Now do some sanity checks on our JSON db
|
||||
if (!("schemaVersion" in inputAddons) || !("addons" in inputAddons)) {
|
||||
parseTimer.done();
|
||||
// Content of JSON file is bad, need to rebuild from scratch
|
||||
ERROR("bad JSON file contents");
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "badJSON");
|
||||
let rebuildTimer = AddonManagerPrivate.simpleTimer("XPIDB_rebuildBadJSON_MS");
|
||||
this.rebuildDatabase(aRebuildOnError);
|
||||
rebuildTimer.done();
|
||||
return;
|
||||
}
|
||||
if (inputAddons.schemaVersion != DB_SCHEMA) {
|
||||
// Handle mismatched JSON schema version. For now, we assume
|
||||
// compatibility for JSON data, though we throw away any fields we
|
||||
// don't know about
|
||||
// don't know about (bug 902956)
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError",
|
||||
"schemaMismatch-" + inputAddons.schemaVersion);
|
||||
LOG("JSON schema mismatch: expected " + DB_SCHEMA +
|
||||
", actual " + inputAddons.schemaVersion);
|
||||
}
|
||||
|
@ -631,6 +625,7 @@ this.XPIDatabase = {
|
|||
let newAddon = new DBAddonInternal(loadedAddon);
|
||||
addonDB.set(newAddon._key, newAddon);
|
||||
};
|
||||
parseTimer.done();
|
||||
this.addonDB = addonDB;
|
||||
LOG("Successfully read XPI database");
|
||||
this.initialized = true;
|
||||
|
@ -638,13 +633,18 @@ this.XPIDatabase = {
|
|||
catch(e) {
|
||||
// If we catch and log a SyntaxError from the JSON
|
||||
// parser, the xpcshell test harness fails the test for us: bug 870828
|
||||
parseTimer.done();
|
||||
if (e.name == "SyntaxError") {
|
||||
ERROR("Syntax error parsing saved XPI JSON data");
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "syntax");
|
||||
}
|
||||
else {
|
||||
ERROR("Failed to load XPI JSON data from profile", e);
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "other");
|
||||
}
|
||||
let rebuildTimer = AddonManagerPrivate.simpleTimer("XPIDB_rebuildReadFailed_MS");
|
||||
this.rebuildDatabase(aRebuildOnError);
|
||||
rebuildTimer.done();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -652,14 +652,18 @@ this.XPIDatabase = {
|
|||
* Upgrade database from earlier (sqlite or RDF) version if available
|
||||
*/
|
||||
upgradeDB: function(aRebuildOnError) {
|
||||
let upgradeTimer = AddonManagerPrivate.simpleTimer("XPIDB_upgradeDB_MS");
|
||||
try {
|
||||
let schemaVersion = Services.prefs.getIntPref(PREF_DB_SCHEMA);
|
||||
if (schemaVersion <= LAST_SQLITE_DB_SCHEMA) {
|
||||
// we should have an older SQLITE database
|
||||
this.migrateData = this.getMigrateDataFromSQLITE();
|
||||
}
|
||||
// else we've upgraded before but the JSON file is gone, fall through
|
||||
// and rebuild from scratch
|
||||
else {
|
||||
// we've upgraded before but the JSON file is gone, fall through
|
||||
// and rebuild from scratch
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "dbMissing");
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
// No schema version pref means either a really old upgrade (RDF) or
|
||||
|
@ -668,6 +672,7 @@ this.XPIDatabase = {
|
|||
}
|
||||
|
||||
this.rebuildDatabase(aRebuildOnError);
|
||||
upgradeTimer.done();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -675,13 +680,15 @@ this.XPIDatabase = {
|
|||
* (for example because read permission is denied)
|
||||
*/
|
||||
rebuildUnreadableDB: function(aError, aRebuildOnError) {
|
||||
let rebuildTimer = AddonManagerPrivate.simpleTimer("XPIDB_rebuildUnreadableDB_MS");
|
||||
WARN("Extensions database " + this.jsonFile.path +
|
||||
" exists but is not readable; rebuilding in memory", aError);
|
||||
" exists but is not readable; rebuilding", aError);
|
||||
// Remember the error message until we try and write at least once, so
|
||||
// we know at shutdown time that there was a problem
|
||||
this._loadError = aError;
|
||||
// XXX TELEMETRY report when this happens?
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "unreadable");
|
||||
this.rebuildDatabase(aRebuildOnError);
|
||||
rebuildTimer.done();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -692,22 +699,31 @@ this.XPIDatabase = {
|
|||
* @return Promise<Map> resolves to the Map of loaded JSON data stored
|
||||
* in this.addonDB; never rejects.
|
||||
*/
|
||||
asyncLoadDB: function XPIDB_asyncLoadDB(aDBCallback) {
|
||||
asyncLoadDB: function XPIDB_asyncLoadDB() {
|
||||
// Already started (and possibly finished) loading
|
||||
if (this._dbPromise) {
|
||||
return this._dbPromise;
|
||||
}
|
||||
|
||||
LOG("Starting async load of XPI database " + this.jsonFile.path);
|
||||
return this._dbPromise = OS.File.read(this.jsonFile.path).then(
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_async_load", XPIProvider.runPhase);
|
||||
let readOptions = {
|
||||
outExecutionDuration: 0
|
||||
};
|
||||
return this._dbPromise = OS.File.read(this.jsonFile.path, null, readOptions).then(
|
||||
byteArray => {
|
||||
LOG("Async JSON file read took " + readOptions.outExecutionDuration + " MS");
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_asyncRead_MS",
|
||||
readOptions.outExecutionDuration);
|
||||
if (this._addonDB) {
|
||||
LOG("Synchronous load completed while waiting for async load");
|
||||
return this.addonDB;
|
||||
}
|
||||
LOG("Finished async read of XPI database, parsing...");
|
||||
let decodeTimer = AddonManagerPrivate.simpleTimer("XPIDB_decode_MS");
|
||||
let decoder = new TextDecoder();
|
||||
let data = decoder.decode(byteArray);
|
||||
decodeTimer.done();
|
||||
this.parseDB(data, true);
|
||||
return this.addonDB;
|
||||
})
|
||||
|
@ -973,11 +989,21 @@ this.XPIDatabase = {
|
|||
|
||||
this.initialized = false;
|
||||
|
||||
if (this._deferredSave) {
|
||||
AddonManagerPrivate.recordSimpleMeasure(
|
||||
"XPIDB_saves_total", this._deferredSave.totalSaves);
|
||||
AddonManagerPrivate.recordSimpleMeasure(
|
||||
"XPIDB_saves_overlapped", this._deferredSave.overlappedSaves);
|
||||
AddonManagerPrivate.recordSimpleMeasure(
|
||||
"XPIDB_saves_late", this._deferredSave.dirty ? 1 : 0);
|
||||
}
|
||||
|
||||
// Make sure any pending writes of the DB are complete, and we
|
||||
// finish cleaning up, and then call back
|
||||
this.flush()
|
||||
.then(null, error => {
|
||||
ERROR("Flush of XPI database failed", error);
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_shutdownFlush_failed", 1);
|
||||
return 0;
|
||||
})
|
||||
.then(count => {
|
||||
|
@ -1137,6 +1163,7 @@ this.XPIDatabase = {
|
|||
// an XPI theme to a lightweight theme before the DB has loaded,
|
||||
// because we're called from sync XPIProvider.addonChanged
|
||||
WARN("Synchronous load of XPI database due to getAddonsByType(" + aType + ")");
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_byType", XPIProvider.runPhase);
|
||||
this.syncLoadDB(true);
|
||||
}
|
||||
return _filterDB(this.addonDB, aAddon => (aAddon.type == aType));
|
||||
|
@ -1152,8 +1179,9 @@ this.XPIDatabase = {
|
|||
getVisibleAddonForInternalName: function XPIDB_getVisibleAddonForInternalName(aInternalName) {
|
||||
if (!this.addonDB) {
|
||||
// This may be called when the DB hasn't otherwise been loaded
|
||||
// XXX TELEMETRY
|
||||
WARN("Synchronous load of XPI database due to getVisibleAddonForInternalName");
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_forInternalName",
|
||||
XPIProvider.runPhase);
|
||||
this.syncLoadDB(true);
|
||||
}
|
||||
|
||||
|
@ -1225,7 +1253,8 @@ this.XPIDatabase = {
|
|||
*/
|
||||
addAddonMetadata: function XPIDB_addAddonMetadata(aAddon, aDescriptor) {
|
||||
if (!this.addonDB) {
|
||||
// XXX telemetry. Should never happen on platforms that have a default theme
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_addMetadata",
|
||||
XPIProvider.runPhase);
|
||||
this.syncLoadDB(false);
|
||||
}
|
||||
|
||||
|
@ -1371,7 +1400,9 @@ this.XPIDatabase = {
|
|||
*/
|
||||
writeAddonsList: function XPIDB_writeAddonsList() {
|
||||
if (!this.addonDB) {
|
||||
// Unusual condition, force the DB to load
|
||||
// force the DB to load
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_writeList",
|
||||
XPIProvider.runPhase);
|
||||
this.syncLoadDB(true);
|
||||
}
|
||||
Services.appinfo.invalidateCachesOnRestart();
|
||||
|
|
|
@ -998,19 +998,19 @@ function prepare_test(aExpectedEvents, aExpectedInstalls, aNext) {
|
|||
// Checks if all expected events have been seen and if so calls the callback
|
||||
function check_test_completed(aArgs) {
|
||||
if (!gNext)
|
||||
return;
|
||||
return undefined;
|
||||
|
||||
if (gExpectedInstalls instanceof Array &&
|
||||
gExpectedInstalls.length > 0)
|
||||
return;
|
||||
return undefined;
|
||||
else for each (let installList in gExpectedInstalls) {
|
||||
if (installList.length > 0)
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
for (let id in gExpectedEvents) {
|
||||
if (gExpectedEvents[id].length > 0)
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return gNext.apply(null, aArgs);
|
||||
|
@ -1186,6 +1186,7 @@ if ("nsIWindowsRegKey" in AM_Ci) {
|
|||
if (value.name == aName)
|
||||
return value.value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1290,7 +1291,7 @@ do_register_cleanup(function addon_cleanup() {
|
|||
var dirEntries = gTmpD.directoryEntries
|
||||
.QueryInterface(AM_Ci.nsIDirectoryEnumerator);
|
||||
var entry;
|
||||
while (entry = dirEntries.nextFile) {
|
||||
while ((entry = dirEntries.nextFile)) {
|
||||
do_throw("Found unexpected file in temporary directory: " + entry.leafName);
|
||||
}
|
||||
dirEntries.close();
|
||||
|
|
|
@ -16,7 +16,7 @@ const IGNORE_PRIVATE = ["AddonAuthor", "AddonCompatibilityOverride",
|
|||
"registerProvider", "unregisterProvider",
|
||||
"addStartupChange", "removeStartupChange",
|
||||
"recordTimestamp", "recordSimpleMeasure",
|
||||
"getSimpleMeasures"];
|
||||
"getSimpleMeasures", "simpleTimer"];
|
||||
|
||||
function test_functions() {
|
||||
for (let prop in AddonManager) {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const DEFAULT_ICON_URL = "chrome://global/skin/icons/webapps-64.png";
|
||||
|
||||
/**
|
||||
* This function receives a list of icon sizes
|
||||
* and URLs and returns the url string for the biggest icon.
|
||||
|
@ -17,95 +19,83 @@
|
|||
*/
|
||||
function getBiggestIconURL(aIcons) {
|
||||
if (!aIcons) {
|
||||
return "chrome://global/skin/icons/webapps-64.png";
|
||||
return DEFAULT_ICON_URL;
|
||||
}
|
||||
|
||||
let iconSizes = Object.keys(aIcons);
|
||||
if (iconSizes.length == 0) {
|
||||
return "chrome://global/skin/icons/webapps-64.png";
|
||||
return DEFAULT_ICON_URL;
|
||||
}
|
||||
iconSizes.sort(function(a, b) a - b);
|
||||
return aIcons[iconSizes.pop()];
|
||||
}
|
||||
|
||||
/**
|
||||
* This function retrieves the icon for an app as specified
|
||||
* in the iconURI on the shell object.
|
||||
* Upon completion it will call aShell.processIcon()
|
||||
*
|
||||
* @param aShell The shell that specifies the properties
|
||||
* of the native app. Three properties from this
|
||||
* shell will be used in this function:
|
||||
* - iconURI
|
||||
* - useTmpForIcon
|
||||
* - processIcon()
|
||||
*/
|
||||
function getIconForApp(aShell, callback) {
|
||||
let iconURI = aShell.iconURI;
|
||||
let mimeService = Cc["@mozilla.org/mime;1"]
|
||||
.getService(Ci.nsIMIMEService);
|
||||
// Download an icon using either a temp file or a pipe.
|
||||
function downloadIcon(aIconURI) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
|
||||
let mimeType;
|
||||
try {
|
||||
let tIndex = iconURI.path.indexOf(";");
|
||||
if("data" == iconURI.scheme && tIndex != -1) {
|
||||
mimeType = iconURI.path.substring(0, tIndex);
|
||||
let tIndex = aIconURI.path.indexOf(";");
|
||||
if("data" == aIconURI.scheme && tIndex != -1) {
|
||||
mimeType = aIconURI.path.substring(0, tIndex);
|
||||
} else {
|
||||
mimeType = mimeService.getTypeFromURI(iconURI);
|
||||
}
|
||||
mimeType = mimeService.getTypeFromURI(aIconURI);
|
||||
}
|
||||
} catch(e) {
|
||||
throw("getIconFromURI - Failed to determine MIME type");
|
||||
deferred.reject("Failed to determine icon MIME type: " + e);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function onIconDownloaded(aStatusCode, aIcon) {
|
||||
if (Components.isSuccessCode(aStatusCode)) {
|
||||
deferred.resolve([ mimeType, aIcon ]);
|
||||
} else {
|
||||
deferred.reject("Failure downloading icon: " + aStatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
let listener;
|
||||
if(aShell.useTmpForIcon) {
|
||||
let downloadObserver = {
|
||||
onDownloadComplete: function(downloader, request, cx, aStatus, file) {
|
||||
// pass downloader just to keep reference around
|
||||
onIconDownloaded(aShell, mimeType, aStatus, file, callback, downloader);
|
||||
}
|
||||
};
|
||||
#ifdef XP_MACOSX
|
||||
let downloadObserver = {
|
||||
onDownloadComplete: function(downloader, request, cx, aStatus, file) {
|
||||
onIconDownloaded(aStatus, file);
|
||||
}
|
||||
};
|
||||
|
||||
let tmpIcon = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
tmpIcon.append("tmpicon." + mimeService.getPrimaryExtension(mimeType, ""));
|
||||
tmpIcon.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
|
||||
let tmpIcon = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
tmpIcon.append("tmpicon." + mimeService.getPrimaryExtension(mimeType, ""));
|
||||
tmpIcon.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("666", 8));
|
||||
|
||||
listener = Cc["@mozilla.org/network/downloader;1"]
|
||||
.createInstance(Ci.nsIDownloader);
|
||||
listener.init(downloadObserver, tmpIcon);
|
||||
} else {
|
||||
let pipe = Cc["@mozilla.org/pipe;1"]
|
||||
.createInstance(Ci.nsIPipe);
|
||||
pipe.init(true, true, 0, 0xffffffff, null);
|
||||
let listener = Cc["@mozilla.org/network/downloader;1"]
|
||||
.createInstance(Ci.nsIDownloader);
|
||||
listener.init(downloadObserver, tmpIcon);
|
||||
#else
|
||||
let pipe = Cc["@mozilla.org/pipe;1"]
|
||||
.createInstance(Ci.nsIPipe);
|
||||
pipe.init(true, true, 0, 0xffffffff, null);
|
||||
|
||||
listener = Cc["@mozilla.org/network/simple-stream-listener;1"]
|
||||
.createInstance(Ci.nsISimpleStreamListener);
|
||||
listener.init(pipe.outputStream, {
|
||||
onStartRequest: function() {},
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
pipe.outputStream.close();
|
||||
onIconDownloaded(aShell, mimeType, aStatusCode, pipe.inputStream, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
let listener = Cc["@mozilla.org/network/simple-stream-listener;1"]
|
||||
.createInstance(Ci.nsISimpleStreamListener);
|
||||
listener.init(pipe.outputStream, {
|
||||
onStartRequest: function() {},
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
pipe.outputStream.close();
|
||||
onIconDownloaded(aStatusCode, pipe.inputStream);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
let channel = NetUtil.newChannel(iconURI);
|
||||
let CertUtils = { };
|
||||
Cu.import("resource://gre/modules/CertUtils.jsm", CertUtils);
|
||||
let channel = NetUtil.newChannel(aIconURI);
|
||||
let { BadCertHandler } = Cu.import("resource://gre/modules/CertUtils.jsm", {});
|
||||
// Pass true to avoid optional redirect-cert-checking behavior.
|
||||
channel.notificationCallbacks = new CertUtils.BadCertHandler(true);
|
||||
channel.notificationCallbacks = new BadCertHandler(true);
|
||||
|
||||
channel.asyncOpen(listener, null);
|
||||
} catch(e) {
|
||||
throw("getIconFromURI - Failure getting icon (" + e + ")");
|
||||
deferred.reject("Failure initiating download of icon: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
function onIconDownloaded(aShell, aMimeType, aStatusCode, aIcon, aCallback) {
|
||||
if (Components.isSuccessCode(aStatusCode)) {
|
||||
aShell.processIcon(aMimeType, aIcon, aCallback);
|
||||
} else {
|
||||
aCallback.call(aShell);
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ Cu.import("resource://gre/modules/osfile.jsm");
|
|||
Cu.import("resource://gre/modules/WebappOSUtils.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
this.WebappsInstaller = {
|
||||
shell: null,
|
||||
|
@ -60,35 +61,27 @@ this.WebappsInstaller = {
|
|||
*
|
||||
* @param aData the data provided to the install function
|
||||
* @param aManifest the manifest data provided by the web app
|
||||
*
|
||||
* @returns true on success, false if an error was thrown
|
||||
*/
|
||||
install: function(aData, aManifest) {
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("browser.mozApps.installer.dry_run")) {
|
||||
return true;
|
||||
return Promise.resolve();
|
||||
}
|
||||
} catch (ex) {}
|
||||
|
||||
this.shell.init(aData, aManifest);
|
||||
|
||||
try {
|
||||
this.shell.install();
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error installing app: " + ex);
|
||||
return false;
|
||||
}
|
||||
return this.shell.install().then(() => {
|
||||
let data = {
|
||||
"installDir": this.shell.installDir.path,
|
||||
"app": {
|
||||
"manifest": aManifest,
|
||||
"origin": aData.app.origin
|
||||
}
|
||||
};
|
||||
|
||||
let data = {
|
||||
"installDir": this.shell.installDir.path,
|
||||
"app": {
|
||||
"manifest": aManifest,
|
||||
"origin": aData.app.origin
|
||||
}
|
||||
};
|
||||
Services.obs.notifyObservers(null, "webapp-installed", JSON.stringify(data));
|
||||
|
||||
return true;
|
||||
Services.obs.notifyObservers(null, "webapp-installed", JSON.stringify(data));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,6 +115,7 @@ NativeApp.prototype = {
|
|||
categories: null,
|
||||
webappJson: null,
|
||||
runtimeFolder: null,
|
||||
manifest: null,
|
||||
|
||||
/**
|
||||
* This function reads and parses the data from the app
|
||||
|
@ -132,7 +126,8 @@ NativeApp.prototype = {
|
|||
*
|
||||
*/
|
||||
init: function(aData, aManifest) {
|
||||
let manifest = new ManifestHelper(aManifest, aData.app.origin);
|
||||
let manifest = this.manifest = new ManifestHelper(aManifest,
|
||||
aData.app.origin);
|
||||
|
||||
let origin = Services.io.newURI(aData.app.origin, null, null);
|
||||
|
||||
|
@ -151,10 +146,16 @@ NativeApp.prototype = {
|
|||
catch (ex) {}
|
||||
}
|
||||
|
||||
if (manifest.developer && manifest.developer.name) {
|
||||
let devName = sanitize(manifest.developer.name.substr(0, 128));
|
||||
if (devName) {
|
||||
this.developerName = devName;
|
||||
if (manifest.developer) {
|
||||
if (manifest.developer.name) {
|
||||
let devName = sanitize(manifest.developer.name.substr(0, 128));
|
||||
if (devName) {
|
||||
this.developerName = devName;
|
||||
}
|
||||
}
|
||||
|
||||
if (manifest.developer.url) {
|
||||
this.developerUrl = manifest.developer.url;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,7 +185,30 @@ NativeApp.prototype = {
|
|||
};
|
||||
|
||||
this.runtimeFolder = Services.dirsvc.get("GreD", Ci.nsIFile);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function retrieves the icon for an app.
|
||||
* If the retrieving fails, it uses the default chrome icon.
|
||||
*/
|
||||
getIcon: function() {
|
||||
try {
|
||||
let [ mimeType, icon ] = yield downloadIcon(this.iconURI);
|
||||
yield this.processIcon(mimeType, icon);
|
||||
}
|
||||
catch(e) {
|
||||
Cu.reportError("Failure retrieving icon: " + e);
|
||||
|
||||
let iconURI = Services.io.newURI(DEFAULT_ICON_URL, null, null);
|
||||
|
||||
let [ mimeType, icon ] = yield downloadIcon(iconURI);
|
||||
yield this.processIcon(mimeType, icon);
|
||||
|
||||
// Set the iconURI property so that the user notification will have the
|
||||
// correct icon.
|
||||
this.iconURI = iconURI;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
@ -218,28 +242,35 @@ NativeApp.prototype = {
|
|||
*/
|
||||
function WinNativeApp(aData) {
|
||||
NativeApp.call(this, aData);
|
||||
|
||||
if (aData.isPackage) {
|
||||
this.size = aData.app.updateManifest.size / 1024;
|
||||
}
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
WinNativeApp.prototype = {
|
||||
__proto__: NativeApp.prototype,
|
||||
size: null,
|
||||
|
||||
/**
|
||||
* Install the app in the system
|
||||
*
|
||||
*/
|
||||
install: function() {
|
||||
try {
|
||||
this._copyPrebuiltFiles();
|
||||
this._createShortcutFiles();
|
||||
this._createConfigFiles();
|
||||
this._writeSystemKeys();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
throw(ex);
|
||||
}
|
||||
|
||||
getIconForApp(this, function() {});
|
||||
return Task.spawn(function() {
|
||||
try {
|
||||
this._copyPrebuiltFiles();
|
||||
this._createShortcutFiles();
|
||||
this._createConfigFiles();
|
||||
this._writeSystemKeys();
|
||||
yield this.getIcon();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
throw(ex);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -452,6 +483,28 @@ WinNativeApp.prototype = {
|
|||
subKey.writeStringValue("DisplayIcon", this.iconFile.path);
|
||||
}
|
||||
|
||||
let date = new Date();
|
||||
let year = date.getYear().toString();
|
||||
let month = date.getMonth();
|
||||
if (month < 10) {
|
||||
month = "0" + month;
|
||||
}
|
||||
let day = date.getDate();
|
||||
if (day < 10) {
|
||||
day = "0" + day;
|
||||
}
|
||||
subKey.writeStringValue("InstallDate", year + month + day);
|
||||
if (this.manifest.version) {
|
||||
subKey.writeStringValue("DisplayVersion", this.manifest.version);
|
||||
}
|
||||
if (this.developerName) {
|
||||
subKey.writeStringValue("Publisher", this.developerName);
|
||||
}
|
||||
subKey.writeStringValue("URLInfoAbout", this.developerUrl);
|
||||
if (this.size) {
|
||||
subKey.writeIntValue("EstimatedSize", this.size);
|
||||
}
|
||||
|
||||
subKey.writeIntValue("NoModify", 1);
|
||||
subKey.writeIntValue("NoRepair", 1);
|
||||
} catch(ex) {
|
||||
|
@ -490,14 +543,6 @@ WinNativeApp.prototype = {
|
|||
shortcut.remove(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* This variable specifies if the icon retrieval process should
|
||||
* use a temporary file in the system or a binary stream. This
|
||||
* is accessed by a common function in WebappsIconHelpers.js and
|
||||
* is different for each platform.
|
||||
*/
|
||||
useTmpForIcon: false,
|
||||
|
||||
/**
|
||||
* Process the icon from the imageStream as retrieved from
|
||||
* the URL by getIconForApp(). This will save the icon to the
|
||||
|
@ -505,28 +550,31 @@ WinNativeApp.prototype = {
|
|||
*
|
||||
* @param aMimeType ahe icon mimetype
|
||||
* @param aImageStream the stream for the image data
|
||||
* @param aCallback a callback function to be called
|
||||
* after the process finishes
|
||||
*/
|
||||
processIcon: function(aMimeType, aImageStream, aCallback) {
|
||||
let iconStream;
|
||||
try {
|
||||
let imgTools = Cc["@mozilla.org/image/tools;1"]
|
||||
.createInstance(Ci.imgITools);
|
||||
let imgContainer = { value: null };
|
||||
processIcon: function(aMimeType, aImageStream) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
imgTools.decodeImageData(aImageStream, aMimeType, imgContainer);
|
||||
iconStream = imgTools.encodeImage(imgContainer.value,
|
||||
"image/vnd.microsoft.icon",
|
||||
"format=bmp;bpp=32");
|
||||
} catch (e) {
|
||||
throw("processIcon - Failure converting icon (" + e + ")");
|
||||
let imgTools = Cc["@mozilla.org/image/tools;1"]
|
||||
.createInstance(Ci.imgITools);
|
||||
|
||||
let imgContainer = imgTools.decodeImage(aImageStream, aMimeType);
|
||||
let iconStream = imgTools.encodeImage(imgContainer,
|
||||
"image/vnd.microsoft.icon",
|
||||
"format=bmp;bpp=32");
|
||||
|
||||
if (!this.iconFile.parent.exists()) {
|
||||
this.iconFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
|
||||
}
|
||||
|
||||
if (!this.iconFile.parent.exists())
|
||||
this.iconFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
let outputStream = FileUtils.openSafeFileOutputStream(this.iconFile);
|
||||
NetUtil.asyncCopy(iconStream, outputStream);
|
||||
NetUtil.asyncCopy(iconStream, outputStream, function(aResult) {
|
||||
if (Components.isSuccessCode(aResult)) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject("Failure copying icon: " + aResult);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -577,15 +625,17 @@ MacNativeApp.prototype = {
|
|||
},
|
||||
|
||||
install: function() {
|
||||
try {
|
||||
this._copyPrebuiltFiles();
|
||||
this._createConfigFiles();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
throw(ex);
|
||||
}
|
||||
|
||||
getIconForApp(this, this._moveToApplicationsFolder);
|
||||
return Task.spawn(function() {
|
||||
try {
|
||||
this._copyPrebuiltFiles();
|
||||
this._createConfigFiles();
|
||||
yield this.getIcon();
|
||||
this._moveToApplicationsFolder();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
throw(ex);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_removeInstallation: function(keepProfile) {
|
||||
|
@ -686,19 +736,11 @@ MacNativeApp.prototype = {
|
|||
this.appNameAsFilename,
|
||||
".app");
|
||||
if (!destinationName) {
|
||||
return false;
|
||||
throw("No available filename");
|
||||
}
|
||||
this.installDir.moveTo(appDir, destinationName);
|
||||
},
|
||||
|
||||
/**
|
||||
* This variable specifies if the icon retrieval process should
|
||||
* use a temporary file in the system or a binary stream. This
|
||||
* is accessed by a common function in WebappsIconHelpers.js and
|
||||
* is different for each platform.
|
||||
*/
|
||||
useTmpForIcon: true,
|
||||
|
||||
/**
|
||||
* Process the icon from the imageStream as retrieved from
|
||||
* the URL by getIconForApp(). This will bundle the icon to the
|
||||
|
@ -706,29 +748,33 @@ MacNativeApp.prototype = {
|
|||
*
|
||||
* @param aMimeType the icon mimetype
|
||||
* @param aImageStream the stream for the image data
|
||||
* @param aCallback a callback function to be called
|
||||
* after the process finishes
|
||||
*/
|
||||
processIcon: function(aMimeType, aIcon, aCallback) {
|
||||
try {
|
||||
let process = Cc["@mozilla.org/process/util;1"]
|
||||
.createInstance(Ci.nsIProcess);
|
||||
let sipsFile = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsILocalFile);
|
||||
sipsFile.initWithPath("/usr/bin/sips");
|
||||
processIcon: function(aMimeType, aIcon) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
process.init(sipsFile);
|
||||
process.run(true, ["-s",
|
||||
"format", "icns",
|
||||
aIcon.path,
|
||||
"--out", this.iconFile.path,
|
||||
"-z", "128", "128"],
|
||||
9);
|
||||
} catch(e) {
|
||||
throw(e);
|
||||
} finally {
|
||||
aCallback.call(this);
|
||||
function conversionDone(aSubject, aTopic) {
|
||||
if (aTopic == "process-finished") {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject("Failure converting icon.");
|
||||
}
|
||||
}
|
||||
|
||||
let process = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
let sipsFile = Cc["@mozilla.org/file/local;1"].
|
||||
createInstance(Ci.nsILocalFile);
|
||||
sipsFile.initWithPath("/usr/bin/sips");
|
||||
|
||||
process.init(sipsFile);
|
||||
process.runAsync(["-s",
|
||||
"format", "icns",
|
||||
aIcon.path,
|
||||
"--out", this.iconFile.path,
|
||||
"-z", "128", "128"],
|
||||
9, conversionDone);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -786,15 +832,16 @@ LinuxNativeApp.prototype = {
|
|||
},
|
||||
|
||||
install: function() {
|
||||
try {
|
||||
this._copyPrebuiltFiles();
|
||||
this._createConfigFiles();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
throw(ex);
|
||||
}
|
||||
|
||||
getIconForApp(this, function() {});
|
||||
return Task.spawn(function() {
|
||||
try {
|
||||
this._copyPrebuiltFiles();
|
||||
this._createConfigFiles();
|
||||
yield this.getIcon();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
throw(ex);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_removeInstallation: function(keepProfile) {
|
||||
|
@ -913,38 +960,32 @@ LinuxNativeApp.prototype = {
|
|||
writer.writeFile();
|
||||
},
|
||||
|
||||
/**
|
||||
* This variable specifies if the icon retrieval process should
|
||||
* use a temporary file in the system or a binary stream. This
|
||||
* is accessed by a common function in WebappsIconHelpers.js and
|
||||
* is different for each platform.
|
||||
*/
|
||||
useTmpForIcon: false,
|
||||
|
||||
/**
|
||||
* Process the icon from the imageStream as retrieved from
|
||||
* the URL by getIconForApp().
|
||||
*
|
||||
* @param aMimeType ahe icon mimetype
|
||||
* @param aImageStream the stream for the image data
|
||||
* @param aCallback a callback function to be called
|
||||
* after the process finishes
|
||||
*/
|
||||
processIcon: function(aMimeType, aImageStream, aCallback) {
|
||||
let iconStream;
|
||||
try {
|
||||
let imgTools = Cc["@mozilla.org/image/tools;1"]
|
||||
.createInstance(Ci.imgITools);
|
||||
let imgContainer = { value: null };
|
||||
processIcon: function(aMimeType, aImageStream) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
imgTools.decodeImageData(aImageStream, aMimeType, imgContainer);
|
||||
iconStream = imgTools.encodeImage(imgContainer.value, "image/png");
|
||||
} catch (e) {
|
||||
throw("processIcon - Failure converting icon (" + e + ")");
|
||||
}
|
||||
let imgTools = Cc["@mozilla.org/image/tools;1"]
|
||||
.createInstance(Ci.imgITools);
|
||||
|
||||
let imgContainer = imgTools.decodeImage(aImageStream, aMimeType);
|
||||
let iconStream = imgTools.encodeImage(imgContainer, "image/png");
|
||||
|
||||
let outputStream = FileUtils.openSafeFileOutputStream(this.iconFile);
|
||||
NetUtil.asyncCopy(iconStream, outputStream);
|
||||
NetUtil.asyncCopy(iconStream, outputStream, function(aResult) {
|
||||
if (Components.isSuccessCode(aResult)) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject("Failure copying icon: " + aResult);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -190,6 +190,7 @@ using mozilla::scache::StartupCache;
|
|||
#include "nsICrashReporter.h"
|
||||
#define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
|
||||
#include "nsIPrefService.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#endif
|
||||
|
||||
#include "base/command_line.h"
|
||||
|
@ -3756,6 +3757,13 @@ XREMain::XRE_mainRun()
|
|||
|
||||
mDirProvider.DoStartup();
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
nsCString userAgentLocale;
|
||||
if (NS_SUCCEEDED(Preferences::GetCString("general.useragent.locale", &userAgentLocale))) {
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("useragent_locale"), userAgentLocale);
|
||||
}
|
||||
#endif
|
||||
|
||||
appStartup->GetShuttingDown(&mShuttingDown);
|
||||
|
||||
nsCOMPtr<nsICommandLineRunner> cmdLine;
|
||||
|
|
|
@ -58,6 +58,10 @@ function onLoad() {
|
|||
// This doesn't capture clicks so content can capture them itself and do
|
||||
// something different if it doesn't want the default behavior.
|
||||
gAppBrowser.addEventListener("click", onContentClick, false, true);
|
||||
|
||||
if (WebappRT.config.app.manifest.fullscreen) {
|
||||
enterFullScreen();
|
||||
}
|
||||
}
|
||||
window.addEventListener("load", onLoad, false);
|
||||
|
||||
|
@ -66,6 +70,33 @@ function onUnload() {
|
|||
}
|
||||
window.addEventListener("unload", onUnload, false);
|
||||
|
||||
// Fullscreen handling.
|
||||
|
||||
function enterFullScreen() {
|
||||
// We call mozRequestFullScreen here so that the app window goes in
|
||||
// fullscreen mode as soon as it's loaded and not after the <browser>
|
||||
// content is loaded.
|
||||
gAppBrowser.mozRequestFullScreen();
|
||||
|
||||
// We need to call mozRequestFullScreen on the document element too,
|
||||
// otherwise the app isn't aware of the fullscreen status.
|
||||
gAppBrowser.addEventListener("load", function onLoad() {
|
||||
gAppBrowser.removeEventListener("load", onLoad, true);
|
||||
gAppBrowser.contentDocument.
|
||||
documentElement.wrappedJSObject.mozRequestFullScreen();
|
||||
}, true);
|
||||
}
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
document.addEventListener('mozfullscreenchange', function() {
|
||||
if (document.mozFullScreenElement) {
|
||||
document.getElementById("main-menubar").style.display = "none";
|
||||
} else {
|
||||
document.getElementById("main-menubar").style.display = "";
|
||||
}
|
||||
}, false);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Direct a click on <a target="_blank"> to the user's default browser.
|
||||
*
|
||||
|
@ -216,15 +247,5 @@ nsContextMenu.prototype = {
|
|||
this.hasPageMenu = PageMenu.maybeBuildAndAttachMenu(document.popupNode,
|
||||
aXULMenu);
|
||||
this.shouldDisplay = this.hasPageMenu;
|
||||
|
||||
this.showItem("page-menu-separator", this.hasPageMenu);
|
||||
},
|
||||
|
||||
showItem: function(aItemOrID, aShow) {
|
||||
let item = aItemOrID.constructor == String ?
|
||||
document.getElementById(aItemOrID) : aItemOrID;
|
||||
if (item) {
|
||||
item.hidden = !aShow;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
id="default"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
width="1024" height="768"
|
||||
fullscreenbutton="true"
|
||||
persist="screenX screenY width height sizemode"
|
||||
>
|
||||
|
||||
|
@ -157,7 +158,6 @@
|
|||
<browser type="content-primary" id="content" flex="1" context="contentAreaContextMenu" />
|
||||
|
||||
<popupset>
|
||||
<menuseparator id="page-menu-separator"/>
|
||||
<menupopup id="contentAreaContextMenu" pagemenu="start"
|
||||
onpopupshowing="return showContextMenu(event, this)"
|
||||
onpopuphiding="hideContextMenu(event, this)">
|
||||
|
|
|
@ -2824,7 +2824,7 @@ AndroidBridge::RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrame
|
|||
return;
|
||||
}
|
||||
|
||||
CSSToScreenScale resolution = aFrameMetrics.CalculateResolution();
|
||||
CSSToScreenScale resolution = aFrameMetrics.mZoom;
|
||||
ScreenRect dp = (aFrameMetrics.mDisplayPort + aFrameMetrics.mScrollOffset) * resolution;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env, 0);
|
||||
|
|
|
@ -1360,7 +1360,7 @@ public:
|
|||
// This event shuts down the worker thread and so must be main thread.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
CSSToScreenScale resolution = mFrameMetrics.mZoom;
|
||||
CSSRect compositedRect = mFrameMetrics.CalculateCompositedRectInCssPixels();
|
||||
|
||||
NS_ConvertASCIItoUTF16 data(nsPrintfCString("{ " \
|
||||
|
@ -1490,4 +1490,4 @@ MetroWidget::Observe(nsISupports *subject, const char *topic, const PRUnichar *d
|
|||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче