Merge m-c to mozilla-inbound
@ -96,7 +96,7 @@ package.json modified: please re-run 'cfx run'
|
|||||||
alt="Mozilla icon widget" />
|
alt="Mozilla icon widget" />
|
||||||
|
|
||||||
Run `cfx run` again, and it will run an instance of Firefox. In the
|
Run `cfx run` again, and it will run an instance of Firefox. In the
|
||||||
bottom-right corner of the browser you'll see an icon with the Firefox
|
bottom-right corner of the browser you'll see an icon with the Mozilla
|
||||||
logo. Click the icon, and a new tab will open with
|
logo. Click the icon, and a new tab will open with
|
||||||
[http://www.mozilla.org/](http://www.mozilla.org/) loaded into it.
|
[http://www.mozilla.org/](http://www.mozilla.org/) loaded into it.
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ to support private browsing, refer to the
|
|||||||
var utils = require('sdk/window/utils');
|
var utils = require('sdk/window/utils');
|
||||||
var browserWindow = utils.getMostRecentBrowserWindow();
|
var browserWindow = utils.getMostRecentBrowserWindow();
|
||||||
var window = browserWindow.content; // `window` object for the current webpage
|
var window = browserWindow.content; // `window` object for the current webpage
|
||||||
utils.getToplevelWindw(window) == browserWindow // => true
|
utils.getToplevelWindow(window) == browserWindow // => true
|
||||||
|
|
||||||
@param window {nsIDOMWindow}
|
@param window {nsIDOMWindow}
|
||||||
@returns {nsIDOMWindow}
|
@returns {nsIDOMWindow}
|
||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 15 KiB |
@ -137,6 +137,14 @@ const ContentWorker = Object.freeze({
|
|||||||
registerMethod = chromeSetInterval;
|
registerMethod = chromeSetInterval;
|
||||||
else
|
else
|
||||||
throw new Error("Unknown timer kind: " + timer.kind);
|
throw new Error("Unknown timer kind: " + timer.kind);
|
||||||
|
|
||||||
|
if (typeof timer.fun == 'string') {
|
||||||
|
let code = timer.fun;
|
||||||
|
timer.fun = () => chromeAPI.sandbox.evaluate(exports, code);
|
||||||
|
} else if (typeof timer.fun != 'function') {
|
||||||
|
throw new Error('Unsupported callback type' + typeof timer.fun);
|
||||||
|
}
|
||||||
|
|
||||||
let id = registerMethod(onFire, timer.delay);
|
let id = registerMethod(onFire, timer.delay);
|
||||||
function onFire() {
|
function onFire() {
|
||||||
try {
|
try {
|
||||||
@ -145,12 +153,47 @@ const ContentWorker = Object.freeze({
|
|||||||
timer.fun.apply(null, timer.args);
|
timer.fun.apply(null, timer.args);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.exception(e);
|
console.exception(e);
|
||||||
|
let wrapper = {
|
||||||
|
instanceOfError: instanceOf(e, Error),
|
||||||
|
value: e,
|
||||||
|
};
|
||||||
|
if (wrapper.instanceOfError) {
|
||||||
|
wrapper.value = {
|
||||||
|
message: e.message,
|
||||||
|
fileName: e.fileName,
|
||||||
|
lineNumber: e.lineNumber,
|
||||||
|
stack: e.stack,
|
||||||
|
name: e.name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pipe.emit('error', wrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_timers[id] = timer;
|
_timers[id] = timer;
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copied from sdk/lang/type.js since modules are not available here
|
||||||
|
function instanceOf(value, Type) {
|
||||||
|
var isConstructorNameSame;
|
||||||
|
var isConstructorSourceSame;
|
||||||
|
|
||||||
|
// If `instanceof` returned `true` we know result right away.
|
||||||
|
var isInstanceOf = value instanceof Type;
|
||||||
|
|
||||||
|
// If `instanceof` returned `false` we do ducktype check since `Type` may be
|
||||||
|
// from a different sandbox. If a constructor of the `value` or a constructor
|
||||||
|
// of the value's prototype has same name and source we assume that it's an
|
||||||
|
// instance of the Type.
|
||||||
|
if (!isInstanceOf && value) {
|
||||||
|
isConstructorNameSame = value.constructor.name === Type.name;
|
||||||
|
isConstructorSourceSame = String(value.constructor) == String(Type);
|
||||||
|
isInstanceOf = (isConstructorNameSame && isConstructorSourceSame) ||
|
||||||
|
instanceOf(Object.getPrototypeOf(value), Type);
|
||||||
|
}
|
||||||
|
return isInstanceOf;
|
||||||
|
}
|
||||||
|
|
||||||
function unregisterTimer(id) {
|
function unregisterTimer(id) {
|
||||||
if (!(id in _timers))
|
if (!(id in _timers))
|
||||||
return;
|
return;
|
||||||
|
@ -13,6 +13,7 @@ const { validateOptions } = require('../deprecated/api-utils');
|
|||||||
const { isValidURI, URL } = require('../url');
|
const { isValidURI, URL } = require('../url');
|
||||||
const file = require('../io/file');
|
const file = require('../io/file');
|
||||||
const { contract } = require('../util/contract');
|
const { contract } = require('../util/contract');
|
||||||
|
const { isString, instanceOf } = require('../lang/type');
|
||||||
|
|
||||||
const LOCAL_URI_SCHEMES = ['resource', 'data'];
|
const LOCAL_URI_SCHEMES = ['resource', 'data'];
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ const valid = {
|
|||||||
msg: 'The `contentURL` option must be a valid URL.'
|
msg: 'The `contentURL` option must be a valid URL.'
|
||||||
},
|
},
|
||||||
contentScriptFile: {
|
contentScriptFile: {
|
||||||
is: ['undefined', 'null', 'string', 'array'],
|
is: ['undefined', 'null', 'string', 'array', 'object'],
|
||||||
map: ensureNull,
|
map: ensureNull,
|
||||||
ok: function(value) {
|
ok: function(value) {
|
||||||
if (value === null)
|
if (value === null)
|
||||||
@ -40,8 +41,13 @@ const valid = {
|
|||||||
|
|
||||||
value = [].concat(value);
|
value = [].concat(value);
|
||||||
|
|
||||||
// Make sure every item is a local file URL.
|
// Make sure every item is a string or an
|
||||||
|
// URL instance, and also a local file URL.
|
||||||
return value.every(function (item) {
|
return value.every(function (item) {
|
||||||
|
|
||||||
|
if (!isString(item) && !(item instanceof URL))
|
||||||
|
return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return ~LOCAL_URI_SCHEMES.indexOf(URL(item).scheme);
|
return ~LOCAL_URI_SCHEMES.indexOf(URL(item).scheme);
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,27 @@ const Symbiont = Worker.resolve({
|
|||||||
|
|
||||||
this._frame = frame;
|
this._frame = frame;
|
||||||
|
|
||||||
|
if (getDocShell(frame)) {
|
||||||
|
this._reallyInitFrame(frame);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this._waitForFrame) {
|
||||||
|
observers.remove('content-document-global-created', this._waitForFrame);
|
||||||
|
}
|
||||||
|
this._waitForFrame = this.__waitForFrame.bind(this, frame);
|
||||||
|
observers.add('content-document-global-created', this._waitForFrame);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
__waitForFrame: function _waitForFrame(frame, win, topic) {
|
||||||
|
if (frame.contentWindow == win) {
|
||||||
|
observers.remove('content-document-global-created', this._waitForFrame);
|
||||||
|
delete this._waitForFrame;
|
||||||
|
this._reallyInitFrame(frame);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_reallyInitFrame: function _reallyInitFrame(frame) {
|
||||||
getDocShell(frame).allowJavascript = this.allow.script;
|
getDocShell(frame).allowJavascript = this.allow.script;
|
||||||
frame.setAttribute("src", this._contentURL);
|
frame.setAttribute("src", this._contentURL);
|
||||||
|
|
||||||
@ -179,6 +200,11 @@ const Symbiont = Worker.resolve({
|
|||||||
* This listener is registered in `Symbiont._initFrame`.
|
* This listener is registered in `Symbiont._initFrame`.
|
||||||
*/
|
*/
|
||||||
_unregisterListener: function _unregisterListener() {
|
_unregisterListener: function _unregisterListener() {
|
||||||
|
if (this._waitForFrame) {
|
||||||
|
observers.remove('content-document-global-created', this._waitForFrame);
|
||||||
|
delete this._waitForFrame;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this._loadListener)
|
if (!this._loadListener)
|
||||||
return;
|
return;
|
||||||
if (this._loadEvent == "start") {
|
if (this._loadEvent == "start") {
|
||||||
|
@ -202,8 +202,15 @@ const WorkerSandbox = EventEmitter.compose({
|
|||||||
clearInterval: 'r'
|
clearInterval: 'r'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
sandbox: {
|
||||||
|
evaluate: evaluate,
|
||||||
|
__exposedProps__: {
|
||||||
|
evaluate: 'r',
|
||||||
|
}
|
||||||
|
},
|
||||||
__exposedProps__: {
|
__exposedProps__: {
|
||||||
timers: 'r'
|
timers: 'r',
|
||||||
|
sandbox: 'r',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let onEvent = this._onContentEvent.bind(this);
|
let onEvent = this._onContentEvent.bind(this);
|
||||||
@ -233,6 +240,19 @@ const WorkerSandbox = EventEmitter.compose({
|
|||||||
self._addonWorker._onContentScriptEvent.apply(self._addonWorker, arguments);
|
self._addonWorker._onContentScriptEvent.apply(self._addonWorker, arguments);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// unwrap, recreate and propagate async Errors thrown from content-script
|
||||||
|
this.on("error", function onError({instanceOfError, value}) {
|
||||||
|
if (self._addonWorker) {
|
||||||
|
let error = value;
|
||||||
|
if (instanceOfError) {
|
||||||
|
error = new Error(value.message, value.fileName, value.lineNumber);
|
||||||
|
error.stack = value.stack;
|
||||||
|
error.name = value.name;
|
||||||
|
}
|
||||||
|
self._addonWorker._emit('error', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Inject `addon` global into target document if document is trusted,
|
// Inject `addon` global into target document if document is trusted,
|
||||||
// `addon` in document is equivalent to `self` in content script.
|
// `addon` in document is equivalent to `self` in content script.
|
||||||
if (worker._injectInDocument) {
|
if (worker._injectInDocument) {
|
||||||
|
@ -36,7 +36,7 @@ const observers = function observers(target, type) {
|
|||||||
* The listener function that processes the event.
|
* The listener function that processes the event.
|
||||||
*/
|
*/
|
||||||
function on(target, type, listener) {
|
function on(target, type, listener) {
|
||||||
if (typeof(listener) !== 'function')
|
if (typeof(listener) !== 'function')
|
||||||
throw new Error(BAD_LISTENER);
|
throw new Error(BAD_LISTENER);
|
||||||
|
|
||||||
let listeners = observers(target, type);
|
let listeners = observers(target, type);
|
||||||
@ -56,9 +56,9 @@ exports.on = on;
|
|||||||
* The listener function that processes the event.
|
* The listener function that processes the event.
|
||||||
*/
|
*/
|
||||||
function once(target, type, listener) {
|
function once(target, type, listener) {
|
||||||
on(target, type, function observer() {
|
on(target, type, function observer(...args) {
|
||||||
off(target, type, observer);
|
off(target, type, observer);
|
||||||
listener.apply(target, arguments);
|
listener.apply(target, args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.once = once;
|
exports.once = once;
|
||||||
@ -74,40 +74,24 @@ exports.once = once;
|
|||||||
* Event target object.
|
* Event target object.
|
||||||
* @param {String} type
|
* @param {String} type
|
||||||
* The type of event.
|
* The type of event.
|
||||||
* @params {Object|Number|String|Boolean} message
|
* @params {Object|Number|String|Boolean} args
|
||||||
* First argument that will be passed to listeners.
|
* Arguments that will be passed to listeners.
|
||||||
* @params {Object|Number|String|Boolean} ...
|
|
||||||
* More arguments that will be passed to listeners.
|
|
||||||
*/
|
*/
|
||||||
function emit(target, type, message /*, ...*/) {
|
function emit (target, type, ...args) {
|
||||||
for each (let item in emit.lazy.apply(emit.lazy, arguments)) {
|
|
||||||
// We just iterate, iterator take care of emitting events.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is very experimental feature that you should not use unless absolutely
|
|
||||||
* need it. Also it may be removed at any point without any further notice.
|
|
||||||
*
|
|
||||||
* Creates lazy iterator of return values of listeners. You can think of it
|
|
||||||
* as lazy array of return values of listeners for the `emit` with the given
|
|
||||||
* arguments.
|
|
||||||
*/
|
|
||||||
emit.lazy = function lazy(target, type, message /*, ...*/) {
|
|
||||||
let args = Array.slice(arguments, 2);
|
|
||||||
let state = observers(target, type);
|
let state = observers(target, type);
|
||||||
let listeners = state.slice();
|
let listeners = state.slice();
|
||||||
let index = 0;
|
|
||||||
let count = listeners.length;
|
let count = listeners.length;
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
// If error event and there are no handlers then print error message
|
// If error event and there are no handlers then print error message
|
||||||
// into a console.
|
// into a console.
|
||||||
if (count === 0 && type === 'error') console.exception(message);
|
if (count === 0 && type === 'error') console.exception(args[0]);
|
||||||
while (index < count) {
|
while (index < count) {
|
||||||
try {
|
try {
|
||||||
let listener = listeners[index];
|
let listener = listeners[index];
|
||||||
// Dispatch only if listener is still registered.
|
// Dispatch only if listener is still registered.
|
||||||
if (~state.indexOf(listener)) yield listener.apply(target, args);
|
if (~state.indexOf(listener))
|
||||||
|
listener.apply(target, args);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
// If exception is not thrown by a error listener and error listener is
|
// If exception is not thrown by a error listener and error listener is
|
||||||
@ -115,8 +99,10 @@ emit.lazy = function lazy(target, type, message /*, ...*/) {
|
|||||||
if (type !== 'error') emit(target, 'error', error);
|
if (type !== 'error') emit(target, 'error', error);
|
||||||
else console.exception(error);
|
else console.exception(error);
|
||||||
}
|
}
|
||||||
index = index + 1;
|
index++;
|
||||||
}
|
}
|
||||||
|
// Also emit on `"*"` so that one could listen for all events.
|
||||||
|
if (type !== '*') emit(target, '*', type, ...args);
|
||||||
}
|
}
|
||||||
exports.emit = emit;
|
exports.emit = emit;
|
||||||
|
|
||||||
@ -145,7 +131,7 @@ function off(target, type, listener) {
|
|||||||
}
|
}
|
||||||
else if (length === 1) {
|
else if (length === 1) {
|
||||||
let listeners = event(target);
|
let listeners = event(target);
|
||||||
Object.keys(listeners).forEach(function(type) delete listeners[type]);
|
Object.keys(listeners).forEach(type => delete listeners[type]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.off = off;
|
exports.off = off;
|
||||||
@ -171,7 +157,7 @@ exports.count = count;
|
|||||||
* Dictionary of listeners.
|
* Dictionary of listeners.
|
||||||
*/
|
*/
|
||||||
function setListeners(target, listeners) {
|
function setListeners(target, listeners) {
|
||||||
Object.keys(listeners || {}).forEach(function onEach(key) {
|
Object.keys(listeners || {}).forEach(key => {
|
||||||
let match = EVENT_TYPE_PATTERN.exec(key);
|
let match = EVENT_TYPE_PATTERN.exec(key);
|
||||||
let type = match && match[1].toLowerCase();
|
let type = match && match[1].toLowerCase();
|
||||||
let listener = listeners[key];
|
let listener = listeners[key];
|
||||||
|
@ -11,6 +11,10 @@ module.metadata = {
|
|||||||
const { Cc, Ci, Cr } = require("chrome");
|
const { Cc, Ci, Cr } = require("chrome");
|
||||||
const apiUtils = require("./deprecated/api-utils");
|
const apiUtils = require("./deprecated/api-utils");
|
||||||
const errors = require("./deprecated/errors");
|
const errors = require("./deprecated/errors");
|
||||||
|
const { isString, isUndefined, instanceOf } = require('./lang/type');
|
||||||
|
const { URL } = require('./url');
|
||||||
|
|
||||||
|
const NOTIFICATION_DIRECTIONS = ["auto", "ltr", "rtl"];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let alertServ = Cc["@mozilla.org/alerts-service;1"].
|
let alertServ = Cc["@mozilla.org/alerts-service;1"].
|
||||||
@ -36,7 +40,7 @@ exports.notify = function notifications_notify(options) {
|
|||||||
};
|
};
|
||||||
function notifyWithOpts(notifyFn) {
|
function notifyWithOpts(notifyFn) {
|
||||||
notifyFn(valOpts.iconURL, valOpts.title, valOpts.text, !!clickObserver,
|
notifyFn(valOpts.iconURL, valOpts.title, valOpts.text, !!clickObserver,
|
||||||
valOpts.data, clickObserver);
|
valOpts.data, clickObserver, valOpts.tag, valOpts.dir, valOpts.lang);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
notifyWithOpts(notify);
|
notifyWithOpts(notify);
|
||||||
@ -66,15 +70,32 @@ function validateOptions(options) {
|
|||||||
is: ["string", "undefined"]
|
is: ["string", "undefined"]
|
||||||
},
|
},
|
||||||
iconURL: {
|
iconURL: {
|
||||||
is: ["string", "undefined"]
|
is: ["string", "undefined", "object"],
|
||||||
|
ok: function(value) {
|
||||||
|
return isUndefined(value) || isString(value) || (value instanceof URL);
|
||||||
|
},
|
||||||
|
msg: "`iconURL` must be a string or an URL instance."
|
||||||
},
|
},
|
||||||
onClick: {
|
onClick: {
|
||||||
is: ["function", "undefined"]
|
is: ["function", "undefined"]
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
is: ["string", "undefined"]
|
is: ["string", "undefined", "number"]
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
|
is: ["string", "undefined", "number"]
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
is: ["string", "undefined", "number"]
|
||||||
|
},
|
||||||
|
dir: {
|
||||||
|
is: ["string", "undefined"],
|
||||||
|
ok: function(value) {
|
||||||
|
return isUndefined(value) || ~NOTIFICATION_DIRECTIONS.indexOf(value);
|
||||||
|
},
|
||||||
|
msg: '`dir` option must be one of: "auto", "ltr" or "rtl".'
|
||||||
|
},
|
||||||
|
lang: {
|
||||||
is: ["string", "undefined"]
|
is: ["string", "undefined"]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -136,18 +136,18 @@ const PageMod = Loader.compose(EventEmitter, {
|
|||||||
|
|
||||||
_applyOnExistingDocuments: function _applyOnExistingDocuments() {
|
_applyOnExistingDocuments: function _applyOnExistingDocuments() {
|
||||||
let mod = this;
|
let mod = this;
|
||||||
// Returns true if the tab match one rule
|
let tabs = getAllTabs();
|
||||||
let tabs = getAllTabs().filter(function (tab) {
|
|
||||||
return mod.include.matchesAny(getTabURI(tab));
|
|
||||||
});
|
|
||||||
|
|
||||||
tabs.forEach(function (tab) {
|
tabs.forEach(function (tab) {
|
||||||
// Fake a newly created document
|
// Fake a newly created document
|
||||||
let window = getTabContentWindow(tab);
|
let window = getTabContentWindow(tab);
|
||||||
if (has(mod.attachTo, "top"))
|
if (has(mod.attachTo, "top") && mod.include.matchesAny(getTabURI(tab)))
|
||||||
mod._onContent(window);
|
mod._onContent(window);
|
||||||
if (has(mod.attachTo, "frame"))
|
if (has(mod.attachTo, "frame")) {
|
||||||
getFrames(window).forEach(mod._onContent);
|
getFrames(window).
|
||||||
|
filter((iframe) => mod.include.matchesAny(iframe.location.href)).
|
||||||
|
forEach(mod._onContent);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -130,6 +130,10 @@ const Request = Class({
|
|||||||
request(this).contentType = validateSingleOption('contentType', value);
|
request(this).contentType = validateSingleOption('contentType', value);
|
||||||
},
|
},
|
||||||
get response() { return request(this).response; },
|
get response() { return request(this).response; },
|
||||||
|
delete: function() {
|
||||||
|
runRequest('DELETE', this);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
get: function() {
|
get: function() {
|
||||||
runRequest('GET', this);
|
runRequest('GET', this);
|
||||||
return this;
|
return this;
|
||||||
|
@ -13,6 +13,7 @@ const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL, getTabConten
|
|||||||
const { emit } = require('../event/core');
|
const { emit } = require('../event/core');
|
||||||
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
|
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
|
||||||
const { when: unload } = require('../system/unload');
|
const { when: unload } = require('../system/unload');
|
||||||
|
const { viewFor } = require('../event/core');
|
||||||
const { EVENTS } = require('./events');
|
const { EVENTS } = require('./events');
|
||||||
|
|
||||||
const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec';
|
const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec';
|
||||||
@ -176,6 +177,10 @@ const Tab = Class({
|
|||||||
});
|
});
|
||||||
exports.Tab = Tab;
|
exports.Tab = Tab;
|
||||||
|
|
||||||
|
// Implement `viewFor` polymorphic function for the Tab
|
||||||
|
// instances.
|
||||||
|
viewFor.define(Tab, x => tabNS(x).tab);
|
||||||
|
|
||||||
function cleanupTab(tab) {
|
function cleanupTab(tab) {
|
||||||
let tabInternals = tabNS(tab);
|
let tabInternals = tabNS(tab);
|
||||||
if (!tabInternals.tab)
|
if (!tabInternals.tab)
|
||||||
|
@ -13,9 +13,10 @@ const { getFaviconURIForLocation } = require("../io/data");
|
|||||||
const { activateTab, getOwnerWindow, getBrowserForTab, getTabTitle, setTabTitle,
|
const { activateTab, getOwnerWindow, getBrowserForTab, getTabTitle, setTabTitle,
|
||||||
getTabURL, setTabURL, getTabContentType, getTabId } = require('./utils');
|
getTabURL, setTabURL, getTabContentType, getTabId } = require('./utils');
|
||||||
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
|
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
|
||||||
const viewNS = require('sdk/core/namespace').ns();
|
const viewNS = require('../core/namespace').ns();
|
||||||
const { deprecateUsage } = require('sdk/util/deprecate');
|
const { deprecateUsage } = require('../util/deprecate');
|
||||||
const { getURL } = require('sdk/url/utils');
|
const { getURL } = require('../url/utils');
|
||||||
|
const { viewFor } = require('../view/core');
|
||||||
|
|
||||||
// Array of the inner instances of all the wrapped tabs.
|
// Array of the inner instances of all the wrapped tabs.
|
||||||
const TABS = [];
|
const TABS = [];
|
||||||
@ -64,6 +65,7 @@ const TabTrait = Trait.compose(EventEmitter, {
|
|||||||
|
|
||||||
viewNS(this._public).tab = this._tab;
|
viewNS(this._public).tab = this._tab;
|
||||||
getPBOwnerWindow.implement(this._public, getChromeTab);
|
getPBOwnerWindow.implement(this._public, getChromeTab);
|
||||||
|
viewFor.implement(this._public, getTabView);
|
||||||
|
|
||||||
// Add tabs to getURL method
|
// Add tabs to getURL method
|
||||||
getURL.implement(this._public, (function (obj) this._public.url).bind(this));
|
getURL.implement(this._public, (function (obj) this._public.url).bind(this));
|
||||||
@ -272,6 +274,10 @@ function getChromeTab(tab) {
|
|||||||
return getOwnerWindow(viewNS(tab).tab);
|
return getOwnerWindow(viewNS(tab).tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implement `viewFor` polymorphic function for the Tab
|
||||||
|
// instances.
|
||||||
|
const getTabView = tab => viewNS(tab).tab;
|
||||||
|
|
||||||
function Tab(options, existingOnly) {
|
function Tab(options, existingOnly) {
|
||||||
let chromeTab = options.tab;
|
let chromeTab = options.tab;
|
||||||
for each (let tab in TABS) {
|
for each (let tab in TABS) {
|
||||||
|
@ -16,13 +16,12 @@ var method = require("method/core");
|
|||||||
// it returns `null`. You can implement this method for
|
// it returns `null`. You can implement this method for
|
||||||
// this type to define what the result should be for it.
|
// this type to define what the result should be for it.
|
||||||
let getNodeView = method("getNodeView");
|
let getNodeView = method("getNodeView");
|
||||||
getNodeView.define(function(value) {
|
getNodeView.define(x =>
|
||||||
if (value instanceof Ci.nsIDOMNode)
|
x instanceof Ci.nsIDOMNode ? x :
|
||||||
return value;
|
x instanceof Ci.nsIDOMWindow ? x :
|
||||||
return null;
|
null);
|
||||||
});
|
|
||||||
|
|
||||||
exports.getNodeView = getNodeView;
|
exports.getNodeView = getNodeView;
|
||||||
|
exports.viewFor = getNodeView;
|
||||||
|
|
||||||
let getActiveView = method("getActiveView");
|
let getActiveView = method("getActiveView");
|
||||||
exports.getActiveView = getActiveView;
|
exports.getActiveView = getActiveView;
|
||||||
|
@ -26,6 +26,8 @@ const ERR_CONTENT = "No content or contentURL property found. Widgets must "
|
|||||||
"position.",
|
"position.",
|
||||||
ERR_DESTROYED = "The widget has been destroyed and can no longer be used.";
|
ERR_DESTROYED = "The widget has been destroyed and can no longer be used.";
|
||||||
|
|
||||||
|
const INSERTION_PREF_ROOT = "extensions.sdk-widget-inserted.";
|
||||||
|
|
||||||
// Supported events, mapping from DOM event names to our event names
|
// Supported events, mapping from DOM event names to our event names
|
||||||
const EVENTS = {
|
const EVENTS = {
|
||||||
"click": "click",
|
"click": "click",
|
||||||
@ -33,6 +35,11 @@ const EVENTS = {
|
|||||||
"mouseout": "mouseout",
|
"mouseout": "mouseout",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// In the Australis menu panel, normally widgets should be treated like
|
||||||
|
// normal toolbarbuttons. If they're any wider than this margin, we'll
|
||||||
|
// treat them as wide widgets instead, which fill up the width of the panel:
|
||||||
|
const AUSTRALIS_PANEL_WIDE_WIDGET_CUTOFF = 70;
|
||||||
|
|
||||||
const { validateOptions } = require("./deprecated/api-utils");
|
const { validateOptions } = require("./deprecated/api-utils");
|
||||||
const panels = require("./panel");
|
const panels = require("./panel");
|
||||||
const { EventEmitter, EventEmitterTrait } = require("./deprecated/events");
|
const { EventEmitter, EventEmitterTrait } = require("./deprecated/events");
|
||||||
@ -45,8 +52,8 @@ const { WindowTracker } = require("./deprecated/window-utils");
|
|||||||
const { isBrowser } = require("./window/utils");
|
const { isBrowser } = require("./window/utils");
|
||||||
const { setTimeout } = require("./timers");
|
const { setTimeout } = require("./timers");
|
||||||
const unload = require("./system/unload");
|
const unload = require("./system/unload");
|
||||||
const { uuid } = require("./util/uuid");
|
|
||||||
const { getNodeView } = require("./view/core");
|
const { getNodeView } = require("./view/core");
|
||||||
|
const prefs = require('./preferences/service');
|
||||||
|
|
||||||
// Data types definition
|
// Data types definition
|
||||||
const valid = {
|
const valid = {
|
||||||
@ -215,6 +222,13 @@ let model = {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function saveInserted(widgetId) {
|
||||||
|
prefs.set(INSERTION_PREF_ROOT + widgetId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function haveInserted(widgetId) {
|
||||||
|
return prefs.has(INSERTION_PREF_ROOT + widgetId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main Widget class: entry point of the widget API
|
* Main Widget class: entry point of the widget API
|
||||||
@ -555,6 +569,9 @@ let browserManager = {
|
|||||||
let idx = this.items.indexOf(item);
|
let idx = this.items.indexOf(item);
|
||||||
if (idx > -1)
|
if (idx > -1)
|
||||||
this.items.splice(idx, 1);
|
this.items.splice(idx, 1);
|
||||||
|
},
|
||||||
|
propagateCurrentset: function browserManager_propagateCurrentset(id, currentset) {
|
||||||
|
this.windows.forEach(function (w) w.doc.getElementById(id).setAttribute("currentset", currentset));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -605,36 +622,14 @@ BrowserWindow.prototype = {
|
|||||||
if (this.window.CustomizableUI) {
|
if (this.window.CustomizableUI) {
|
||||||
let placement = this.window.CustomizableUI.getPlacementOfWidget(node.id);
|
let placement = this.window.CustomizableUI.getPlacementOfWidget(node.id);
|
||||||
if (!placement) {
|
if (!placement) {
|
||||||
|
if (haveInserted(node.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
placement = {area: 'nav-bar', position: undefined};
|
placement = {area: 'nav-bar', position: undefined};
|
||||||
|
saveInserted(node.id);
|
||||||
}
|
}
|
||||||
this.window.CustomizableUI.addWidgetToArea(node.id, placement.area, placement.position);
|
this.window.CustomizableUI.addWidgetToArea(node.id, placement.area, placement.position);
|
||||||
|
this.window.CustomizableUI.ensureWidgetPlacedInWindow(node.id, this.window);
|
||||||
// Depending on when this gets called, we might be in the right place now. In that case,
|
|
||||||
// don't run the following code.
|
|
||||||
if (node.parentNode != palette) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Otherwise, insert:
|
|
||||||
let container = this.doc.getElementById(placement.area);
|
|
||||||
if (container.customizationTarget) {
|
|
||||||
container = container.customizationTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (placement.position !== undefined) {
|
|
||||||
// Find a position:
|
|
||||||
let items = this.window.CustomizableUI.getWidgetIdsInArea(placement.area);
|
|
||||||
let itemIndex = placement.position;
|
|
||||||
for (let l = items.length; itemIndex < l; itemIndex++) {
|
|
||||||
let realItems = container.getElementsByAttribute("id", items[itemIndex]);
|
|
||||||
if (realItems[0]) {
|
|
||||||
container.insertBefore(node, realItems[0]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (node.parentNode != container) {
|
|
||||||
container.appendChild(node);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,10 +645,14 @@ BrowserWindow.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if widget isn't in any toolbar, add it to the addon-bar
|
// if widget isn't in any toolbar, add it to the addon-bar
|
||||||
// TODO: we may want some "first-launch" module to do this only on very
|
let needToPropagateCurrentset = false;
|
||||||
// first execution
|
|
||||||
if (!container) {
|
if (!container) {
|
||||||
|
if (haveInserted(node.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
container = this.doc.getElementById("addon-bar");
|
container = this.doc.getElementById("addon-bar");
|
||||||
|
saveInserted(node.id);
|
||||||
|
needToPropagateCurrentset = true;
|
||||||
// TODO: find a way to make the following code work when we use "cfx run":
|
// TODO: find a way to make the following code work when we use "cfx run":
|
||||||
// http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#8586
|
// http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#8586
|
||||||
// until then, force display of addon bar directly from sdk code
|
// until then, force display of addon bar directly from sdk code
|
||||||
@ -684,9 +683,11 @@ BrowserWindow.prototype = {
|
|||||||
// Otherwise, this code will collide with other instance of Widget module
|
// Otherwise, this code will collide with other instance of Widget module
|
||||||
// during Firefox startup. See bug 685929.
|
// during Firefox startup. See bug 685929.
|
||||||
if (ids.indexOf(id) == -1) {
|
if (ids.indexOf(id) == -1) {
|
||||||
container.setAttribute("currentset", container.currentSet);
|
let set = container.currentSet;
|
||||||
|
container.setAttribute("currentset", set);
|
||||||
// Save DOM attribute in order to save position on new window opened
|
// Save DOM attribute in order to save position on new window opened
|
||||||
this.window.document.persist(container.id, "currentset");
|
this.window.document.persist(container.id, "currentset");
|
||||||
|
browserManager.propagateCurrentset(container.id, set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -736,7 +737,6 @@ WidgetChrome.prototype.update = function WC_update(updatedItem, property, value)
|
|||||||
WidgetChrome.prototype._createNode = function WC__createNode() {
|
WidgetChrome.prototype._createNode = function WC__createNode() {
|
||||||
// XUL element container for widget
|
// XUL element container for widget
|
||||||
let node = this._doc.createElement("toolbaritem");
|
let node = this._doc.createElement("toolbaritem");
|
||||||
let guid = String(uuid());
|
|
||||||
|
|
||||||
// Temporary work around require("self") failing on unit-test execution ...
|
// Temporary work around require("self") failing on unit-test execution ...
|
||||||
let jetpackID = "testID";
|
let jetpackID = "testID";
|
||||||
@ -753,6 +753,14 @@ WidgetChrome.prototype._createNode = function WC__createNode() {
|
|||||||
// Bug 626326: Prevent customize toolbar context menu to appear
|
// Bug 626326: Prevent customize toolbar context menu to appear
|
||||||
node.setAttribute("context", "");
|
node.setAttribute("context", "");
|
||||||
|
|
||||||
|
// For use in styling by the browser
|
||||||
|
node.setAttribute("sdkstylewidget", "true");
|
||||||
|
// Mark wide widgets as such:
|
||||||
|
if (this.window.CustomizableUI &&
|
||||||
|
this._widget.width > AUSTRALIS_PANEL_WIDE_WIDGET_CUTOFF) {
|
||||||
|
node.classList.add("panel-wide-item");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO move into a stylesheet, configurable by consumers.
|
// TODO move into a stylesheet, configurable by consumers.
|
||||||
// Either widget.style, exposing the style object, or a URL
|
// Either widget.style, exposing the style object, or a URL
|
||||||
// (eg, can load local stylesheet file).
|
// (eg, can load local stylesheet file).
|
||||||
@ -784,6 +792,13 @@ WidgetChrome.prototype.fill = function WC_fill() {
|
|||||||
// until the node is attached to a document.
|
// until the node is attached to a document.
|
||||||
this.node.appendChild(iframe);
|
this.node.appendChild(iframe);
|
||||||
|
|
||||||
|
var label = this._doc.createElement("label");
|
||||||
|
label.setAttribute("value", this._widget.label);
|
||||||
|
label.className = "toolbarbutton-text";
|
||||||
|
label.setAttribute("crop", "right");
|
||||||
|
label.setAttribute("flex", "1");
|
||||||
|
this.node.appendChild(label);
|
||||||
|
|
||||||
// add event handlers
|
// add event handlers
|
||||||
this.addEventHandlers();
|
this.addEventHandlers();
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ const unload = require('../system/unload');
|
|||||||
const { isWindowPrivate } = require('../window/utils');
|
const { isWindowPrivate } = require('../window/utils');
|
||||||
const { EventTarget } = require('../event/target');
|
const { EventTarget } = require('../event/target');
|
||||||
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
|
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
|
||||||
|
const { viewFor } = require('../view/core');
|
||||||
const { deprecateUsage } = require('../util/deprecate');
|
const { deprecateUsage } = require('../util/deprecate');
|
||||||
|
|
||||||
const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec, consider using require("sdk/tabs") instead';
|
const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec, consider using require("sdk/tabs") instead';
|
||||||
@ -48,6 +49,7 @@ const BrowserWindow = Class({
|
|||||||
});
|
});
|
||||||
exports.BrowserWindow = BrowserWindow;
|
exports.BrowserWindow = BrowserWindow;
|
||||||
|
|
||||||
getPBOwnerWindow.define(BrowserWindow, function(window) {
|
const getWindowView = window => windowNS(window).window;
|
||||||
return windowNS(window).window;
|
|
||||||
});
|
getPBOwnerWindow.define(BrowserWindow, getWindowView);
|
||||||
|
viewFor.define(BrowserWindow, getWindowView);
|
||||||
|
@ -22,6 +22,7 @@ const { Cc, Ci, Cr } = require('chrome'),
|
|||||||
const { windowNS } = require('../window/namespace');
|
const { windowNS } = require('../window/namespace');
|
||||||
const { isPrivateBrowsingSupported } = require('../self');
|
const { isPrivateBrowsingSupported } = require('../self');
|
||||||
const { ignoreWindow } = require('sdk/private-browsing/utils');
|
const { ignoreWindow } = require('sdk/private-browsing/utils');
|
||||||
|
const { viewFor } = require('../view/core');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Window trait composes safe wrappers for browser window that are E10S
|
* Window trait composes safe wrappers for browser window that are E10S
|
||||||
@ -76,6 +77,7 @@ const BrowserWindowTrait = Trait.compose(
|
|||||||
|
|
||||||
windowNS(this._public).window = this._window;
|
windowNS(this._public).window = this._window;
|
||||||
getOwnerWindow.implement(this._public, getChromeWindow);
|
getOwnerWindow.implement(this._public, getChromeWindow);
|
||||||
|
viewFor.implement(this._public, getChromeWindow);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
@ -84,6 +86,7 @@ const BrowserWindowTrait = Trait.compose(
|
|||||||
_onLoad: function() {
|
_onLoad: function() {
|
||||||
try {
|
try {
|
||||||
this._initWindowTabTracker();
|
this._initWindowTabTracker();
|
||||||
|
this._loaded = true;
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
this._emit('error', e);
|
this._emit('error', e);
|
||||||
@ -94,9 +97,12 @@ const BrowserWindowTrait = Trait.compose(
|
|||||||
_onUnload: function() {
|
_onUnload: function() {
|
||||||
if (!this._window)
|
if (!this._window)
|
||||||
return;
|
return;
|
||||||
this._destroyWindowTabTracker();
|
if (this._loaded)
|
||||||
|
this._destroyWindowTabTracker();
|
||||||
|
|
||||||
this._emitOnObject(browserWindows, 'close', this._public);
|
this._emitOnObject(browserWindows, 'close', this._public);
|
||||||
this._window = null;
|
this._window = null;
|
||||||
|
windowNS(this._public).window = null;
|
||||||
// Removing reference from the windows array.
|
// Removing reference from the windows array.
|
||||||
windows.splice(windows.indexOf(this), 1);
|
windows.splice(windows.indexOf(this), 1);
|
||||||
this._removeAllListeners();
|
this._removeAllListeners();
|
||||||
|
@ -76,9 +76,6 @@ function Worker(options) {
|
|||||||
["pageshow", "pagehide", "detach", "message", "error"].forEach(function(key) {
|
["pageshow", "pagehide", "detach", "message", "error"].forEach(function(key) {
|
||||||
trait.on(key, function() {
|
trait.on(key, function() {
|
||||||
emit.apply(emit, [worker, key].concat(Array.slice(arguments)));
|
emit.apply(emit, [worker, key].concat(Array.slice(arguments)));
|
||||||
// Workaround lack of ability to listen on all events by emulating
|
|
||||||
// such ability. This will become obsolete once Bug 821065 is fixed.
|
|
||||||
emit.apply(emit, [worker, "*", key].concat(Array.slice(arguments)));
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
traits.set(worker, trait);
|
traits.set(worker, trait);
|
||||||
|
5
addon-sdk/source/test/fixtures/test-contentScriptFile.js
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
self.postMessage("msg from contentScriptFile");
|
@ -44,16 +44,9 @@ exports["test multiple tabs"] = function(assert, done) {
|
|||||||
|
|
||||||
on(events, "data", handler);
|
on(events, "data", handler);
|
||||||
function handler ({type, target, timeStamp}) {
|
function handler ({type, target, timeStamp}) {
|
||||||
// ignore about:blank pages and *-document-global-created
|
eventFilter(type, target, () => {
|
||||||
// events that are not very consistent.
|
|
||||||
// ignore http:// requests, as Fennec's `about:home` page
|
|
||||||
// displays add-ons a user could install
|
|
||||||
if (target.URL !== "about:blank" &&
|
|
||||||
target.URL !== "about:home" &&
|
|
||||||
!target.URL.match(/^https?:\/\//i) &&
|
|
||||||
type !== "chrome-document-global-created" &&
|
|
||||||
type !== "content-document-global-created")
|
|
||||||
actual.push(type + " -> " + target.URL)
|
actual.push(type + " -> " + target.URL)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let window = getMostRecentBrowserWindow();
|
let window = getMostRecentBrowserWindow();
|
||||||
@ -92,12 +85,9 @@ exports["test nested frames"] = function(assert, done) {
|
|||||||
let actual = [];
|
let actual = [];
|
||||||
on(events, "data", handler);
|
on(events, "data", handler);
|
||||||
function handler ({type, target, timeStamp}) {
|
function handler ({type, target, timeStamp}) {
|
||||||
// ignore about:blank pages and *-global-created
|
eventFilter(type, target, () => {
|
||||||
// events that are not very consistent.
|
|
||||||
if (target.URL !== "about:blank" &&
|
|
||||||
type !== "chrome-document-global-created" &&
|
|
||||||
type !== "content-document-global-created")
|
|
||||||
actual.push(type + " -> " + target.URL)
|
actual.push(type + " -> " + target.URL)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let window = getMostRecentBrowserWindow();
|
let window = getMostRecentBrowserWindow();
|
||||||
@ -126,4 +116,20 @@ exports["test nested frames"] = function(assert, done) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ignore about:blank pages and *-document-global-created
|
||||||
|
// events that are not very consistent.
|
||||||
|
// ignore http:// requests, as Fennec's `about:home` page
|
||||||
|
// displays add-ons a user could install
|
||||||
|
// ignore local `searchplugins` files loaded
|
||||||
|
// Calls callback if passes filter
|
||||||
|
function eventFilter (type, target, callback) {
|
||||||
|
if (target.URL !== "about:blank" &&
|
||||||
|
target.URL !== "about:home" &&
|
||||||
|
!target.URL.match(/^https?:\/\//i) &&
|
||||||
|
!target.URL.match(/searchplugins/) &&
|
||||||
|
type !== "chrome-document-global-created" &&
|
||||||
|
type !== "content-document-global-created")
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}
|
||||||
require("test").run(exports);
|
require("test").run(exports);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
const { Loader } = require('sdk/content/loader');
|
const { Loader } = require('sdk/content/loader');
|
||||||
const self = require("sdk/self");
|
const self = require("sdk/self");
|
||||||
const fixtures = require("./fixtures");
|
const fixtures = require("./fixtures");
|
||||||
|
const { URL } = require('sdk/url');
|
||||||
|
|
||||||
exports['test:contentURL'] = function(assert) {
|
exports['test:contentURL'] = function(assert) {
|
||||||
let loader = Loader(),
|
let loader = Loader(),
|
||||||
@ -204,6 +205,28 @@ exports['test:contentScriptFile'] = function(assert) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let data = 'data:text/html,test';
|
||||||
|
try {
|
||||||
|
loader.contentScriptFile = [ { toString: () => data } ];
|
||||||
|
test.fail('must throw when non-URL object is set');
|
||||||
|
} catch(e) {
|
||||||
|
assert.equal(
|
||||||
|
'The `contentScriptFile` option must be a local URL or an array of URLs.',
|
||||||
|
e.message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
loader.contentScriptFile = new URL(data);
|
||||||
|
assert.ok(
|
||||||
|
loader.contentScriptFile instanceof URL,
|
||||||
|
'must be able to set `contentScriptFile` to an instance of URL'
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
data,
|
||||||
|
loader.contentScriptFile.toString(),
|
||||||
|
'setting `contentScriptFile` to an instance of URL should preserve the url'
|
||||||
|
);
|
||||||
|
|
||||||
loader.contentScriptFile = undefined;
|
loader.contentScriptFile = undefined;
|
||||||
assert.equal(
|
assert.equal(
|
||||||
null,
|
null,
|
||||||
|
@ -17,6 +17,10 @@ const { LoaderWithHookedConsole } = require("sdk/test/loader");
|
|||||||
const { Worker } = require("sdk/content/worker");
|
const { Worker } = require("sdk/content/worker");
|
||||||
const { close } = require("sdk/window/helpers");
|
const { close } = require("sdk/window/helpers");
|
||||||
const { set: setPref } = require("sdk/preferences/service");
|
const { set: setPref } = require("sdk/preferences/service");
|
||||||
|
const { isArray } = require("sdk/lang/type");
|
||||||
|
const { URL } = require('sdk/url');
|
||||||
|
const fixtures = require("./fixtures");
|
||||||
|
|
||||||
const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
|
const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
|
||||||
|
|
||||||
const DEFAULT_CONTENT_URL = "data:text/html;charset=utf-8,foo";
|
const DEFAULT_CONTENT_URL = "data:text/html;charset=utf-8,foo";
|
||||||
@ -396,8 +400,116 @@ exports["test:ensure console.xxx works in cs"] = WorkerTest(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
exports["test:setTimeout works with string argument"] = WorkerTest(
|
||||||
|
"data:text/html;charset=utf-8,<script>var docVal=5;</script>",
|
||||||
|
function(assert, browser, done) {
|
||||||
|
let worker = Worker({
|
||||||
|
window: browser.contentWindow,
|
||||||
|
contentScript: "new " + function ContentScriptScope() {
|
||||||
|
// must use "window.scVal" instead of "var csVal"
|
||||||
|
// since we are inside ContentScriptScope function.
|
||||||
|
// i'm NOT putting code-in-string inside code-in-string </YO DAWG>
|
||||||
|
window.csVal = 13;
|
||||||
|
setTimeout("self.postMessage([" +
|
||||||
|
"csVal, " +
|
||||||
|
"window.docVal, " +
|
||||||
|
"'ContentWorker' in window, " +
|
||||||
|
"'UNWRAP_ACCESS_KEY' in window, " +
|
||||||
|
"'getProxyForObject' in window, " +
|
||||||
|
"])", 1);
|
||||||
|
},
|
||||||
|
contentScriptWhen: "ready",
|
||||||
|
onMessage: function([csVal, docVal, chrome1, chrome2, chrome3]) {
|
||||||
|
// test timer code is executed in the correct context
|
||||||
|
assert.equal(csVal, 13, "accessing content-script values");
|
||||||
|
assert.notEqual(docVal, 5, "can't access document values (directly)");
|
||||||
|
assert.ok(!chrome1 && !chrome2 && !chrome3, "nothing is leaked from chrome");
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
exports["test:setTimeout can\"t be cancelled by content"] = WorkerTest(
|
exports["test:setInterval works with string argument"] = WorkerTest(
|
||||||
|
DEFAULT_CONTENT_URL,
|
||||||
|
function(assert, browser, done) {
|
||||||
|
let count = 0;
|
||||||
|
let worker = Worker({
|
||||||
|
window: browser.contentWindow,
|
||||||
|
contentScript: "setInterval('self.postMessage(1)', 50)",
|
||||||
|
contentScriptWhen: "ready",
|
||||||
|
onMessage: function(one) {
|
||||||
|
count++;
|
||||||
|
assert.equal(one, 1, "got " + count + " message(s) from setInterval");
|
||||||
|
if (count >= 3) done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports["test:setInterval async Errors passed to .onError"] = WorkerTest(
|
||||||
|
DEFAULT_CONTENT_URL,
|
||||||
|
function(assert, browser, done) {
|
||||||
|
let count = 0;
|
||||||
|
let worker = Worker({
|
||||||
|
window: browser.contentWindow,
|
||||||
|
contentScript: "setInterval(() => { throw Error('ubik') }, 50)",
|
||||||
|
contentScriptWhen: "ready",
|
||||||
|
onError: function(err) {
|
||||||
|
count++;
|
||||||
|
assert.equal(err.message, "ubik",
|
||||||
|
"error (corectly) propagated " + count + " time(s)");
|
||||||
|
if (count >= 3) done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports["test:setTimeout throws array, passed to .onError"] = WorkerTest(
|
||||||
|
DEFAULT_CONTENT_URL,
|
||||||
|
function(assert, browser, done) {
|
||||||
|
let worker = Worker({
|
||||||
|
window: browser.contentWindow,
|
||||||
|
contentScript: "setTimeout(function() { throw ['array', 42] }, 1)",
|
||||||
|
contentScriptWhen: "ready",
|
||||||
|
onError: function(arr) {
|
||||||
|
assert.ok(isArray(arr),
|
||||||
|
"the type of thrown/propagated object is array");
|
||||||
|
assert.ok(arr.length==2,
|
||||||
|
"the propagated thrown array is the right length");
|
||||||
|
assert.equal(arr[1], 42,
|
||||||
|
"element inside the thrown array correctly propagated");
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports["test:setTimeout string arg with SyntaxError to .onError"] = WorkerTest(
|
||||||
|
DEFAULT_CONTENT_URL,
|
||||||
|
function(assert, browser, done) {
|
||||||
|
let worker = Worker({
|
||||||
|
window: browser.contentWindow,
|
||||||
|
contentScript: "setTimeout('syntax 123 error', 1)",
|
||||||
|
contentScriptWhen: "ready",
|
||||||
|
onError: function(err) {
|
||||||
|
assert.equal(err.name, "SyntaxError",
|
||||||
|
"received SyntaxError thrown from bad code in string argument to setTimeout");
|
||||||
|
assert.ok('fileName' in err,
|
||||||
|
"propagated SyntaxError contains a fileName property");
|
||||||
|
assert.ok('stack' in err,
|
||||||
|
"propagated SyntaxError contains a stack property");
|
||||||
|
assert.equal(err.message, "missing ; before statement",
|
||||||
|
"propagated SyntaxError has the correct (helpful) message");
|
||||||
|
assert.equal(err.lineNumber, 1,
|
||||||
|
"propagated SyntaxError was thrown on the right lineNumber");
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports["test:setTimeout can't be cancelled by content"] = WorkerTest(
|
||||||
"data:text/html;charset=utf-8,<script>var documentValue=true;</script>",
|
"data:text/html;charset=utf-8,<script>var documentValue=true;</script>",
|
||||||
function(assert, browser, done) {
|
function(assert, browser, done) {
|
||||||
|
|
||||||
@ -700,4 +812,21 @@ exports["test:global postMessage"] = WorkerTest(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
exports['test:conentScriptFile as URL instance'] = WorkerTest(
|
||||||
|
DEFAULT_CONTENT_URL,
|
||||||
|
function(assert, browser, done) {
|
||||||
|
|
||||||
|
let url = new URL(fixtures.url("test-contentScriptFile.js"));
|
||||||
|
let worker = Worker({
|
||||||
|
window: browser.contentWindow,
|
||||||
|
contentScriptFile: url,
|
||||||
|
onMessage: function(msg) {
|
||||||
|
assert.equal(msg, "msg from contentScriptFile",
|
||||||
|
"received a wrong message from contentScriptFile");
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
require("test").run(exports);
|
require("test").run(exports);
|
||||||
|
@ -222,23 +222,24 @@ exports['test count'] = function(assert) {
|
|||||||
assert.equal(count(target, 'foo'), 0, 'listeners unregistered');
|
assert.equal(count(target, 'foo'), 0, 'listeners unregistered');
|
||||||
};
|
};
|
||||||
|
|
||||||
exports['test emit.lazy'] = function(assert) {
|
exports['test listen to all events'] = function(assert) {
|
||||||
let target = {}, boom = Error('boom!'), errors = [], actual = []
|
let actual = [];
|
||||||
|
let target = {};
|
||||||
|
|
||||||
on(target, 'error', function error(e) errors.push(e))
|
on(target, 'foo', message => actual.push(message));
|
||||||
|
on(target, '*', (type, ...message) => {
|
||||||
|
actual.push([type].concat(message));
|
||||||
|
});
|
||||||
|
|
||||||
on(target, 'a', function() 1);
|
emit(target, 'foo', 'hello');
|
||||||
on(target, 'a', function() {});
|
assert.equal(actual[0], 'hello',
|
||||||
on(target, 'a', function() 2);
|
'non-wildcard listeners still work');
|
||||||
on(target, 'a', function() { throw boom });
|
assert.deepEqual(actual[1], ['foo', 'hello'],
|
||||||
on(target, 'a', function() 3);
|
'wildcard listener called');
|
||||||
|
|
||||||
for each (let value in emit.lazy(target, 'a'))
|
emit(target, 'bar', 'goodbye');
|
||||||
actual.push(value);
|
assert.deepEqual(actual[2], ['bar', 'goodbye'],
|
||||||
|
'wildcard listener called for unbound event name');
|
||||||
assert.deepEqual(actual, [ 1, undefined, 2, 3 ],
|
|
||||||
'all results were collected');
|
|
||||||
assert.deepEqual(errors, [ boom ], 'errors reporetd');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
require('test').run(exports);
|
require('test').run(exports);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { on, emit } = require("sdk/event/core");
|
const { on, emit } = require("sdk/event/core");
|
||||||
const { filter, map, merge, expand } = require("sdk/event/utils");
|
const { filter, map, merge, expand, pipe } = require("sdk/event/utils");
|
||||||
const $ = require("./event/helpers");
|
const $ = require("./event/helpers");
|
||||||
|
|
||||||
function isEven(x) !(x % 2)
|
function isEven(x) !(x % 2)
|
||||||
@ -163,7 +163,96 @@ exports["test expand"] = function(assert) {
|
|||||||
|
|
||||||
assert.deepEqual(actual, ["a1", "b1", "a2", "c1", "c2", "b2", "a3"],
|
assert.deepEqual(actual, ["a1", "b1", "a2", "c1", "c2", "b2", "a3"],
|
||||||
"all inputs data merged into one");
|
"all inputs data merged into one");
|
||||||
}
|
};
|
||||||
|
|
||||||
|
exports["test pipe"] = function (assert, done) {
|
||||||
|
let src = {};
|
||||||
|
let dest = {};
|
||||||
|
|
||||||
|
let aneventCount = 0, multiargsCount = 0;
|
||||||
|
let wildcardCount = {};
|
||||||
|
|
||||||
|
on(dest, 'an-event', arg => {
|
||||||
|
assert.equal(arg, 'my-arg', 'piped argument to event');
|
||||||
|
++aneventCount;
|
||||||
|
check();
|
||||||
|
});
|
||||||
|
on(dest, 'multiargs', (...data) => {
|
||||||
|
assert.equal(data[0], 'a', 'multiple arguments passed via pipe');
|
||||||
|
assert.equal(data[1], 'b', 'multiple arguments passed via pipe');
|
||||||
|
assert.equal(data[2], 'c', 'multiple arguments passed via pipe');
|
||||||
|
++multiargsCount;
|
||||||
|
check();
|
||||||
|
});
|
||||||
|
|
||||||
|
on(dest, '*', (name, ...data) => {
|
||||||
|
wildcardCount[name] = (wildcardCount[name] || 0) + 1;
|
||||||
|
if (name === 'multiargs') {
|
||||||
|
assert.equal(data[0], 'a', 'multiple arguments passed via pipe, wildcard');
|
||||||
|
assert.equal(data[1], 'b', 'multiple arguments passed via pipe, wildcard');
|
||||||
|
assert.equal(data[2], 'c', 'multiple arguments passed via pipe, wildcard');
|
||||||
|
}
|
||||||
|
if (name === 'an-event')
|
||||||
|
assert.equal(data[0], 'my-arg', 'argument passed via pipe, wildcard');
|
||||||
|
check();
|
||||||
|
});
|
||||||
|
|
||||||
|
pipe(src, dest);
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++)
|
||||||
|
emit(src, 'an-event', 'my-arg');
|
||||||
|
|
||||||
|
emit(src, 'multiargs', 'a', 'b', 'c');
|
||||||
|
|
||||||
|
function check () {
|
||||||
|
if (aneventCount === 3 && multiargsCount === 1 &&
|
||||||
|
wildcardCount['an-event'] === 3 &&
|
||||||
|
wildcardCount['multiargs'] === 1)
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports["test pipe multiple targets"] = function (assert) {
|
||||||
|
let src1 = {};
|
||||||
|
let src2 = {};
|
||||||
|
let middle = {};
|
||||||
|
let dest = {};
|
||||||
|
|
||||||
|
pipe(src1, middle);
|
||||||
|
pipe(src2, middle);
|
||||||
|
pipe(middle, dest);
|
||||||
|
|
||||||
|
let middleFired = 0;
|
||||||
|
let destFired = 0;
|
||||||
|
let src1Fired = 0;
|
||||||
|
let src2Fired = 0;
|
||||||
|
|
||||||
|
on(src1, '*', () => src1Fired++);
|
||||||
|
on(src2, '*', () => src2Fired++);
|
||||||
|
on(middle, '*', () => middleFired++);
|
||||||
|
on(dest, '*', () => destFired++);
|
||||||
|
|
||||||
|
emit(src1, 'ev');
|
||||||
|
assert.equal(src1Fired, 1, 'event triggers in source in pipe chain');
|
||||||
|
assert.equal(middleFired, 1, 'event passes through the middle of pipe chain');
|
||||||
|
assert.equal(destFired, 1, 'event propagates to end of pipe chain');
|
||||||
|
assert.equal(src2Fired, 0, 'event does not fire on alternative chain routes');
|
||||||
|
|
||||||
|
emit(src2, 'ev');
|
||||||
|
assert.equal(src2Fired, 1, 'event triggers in source in pipe chain');
|
||||||
|
assert.equal(middleFired, 2,
|
||||||
|
'event passes through the middle of pipe chain from different src');
|
||||||
|
assert.equal(destFired, 2,
|
||||||
|
'event propagates to end of pipe chain from different src');
|
||||||
|
assert.equal(src1Fired, 1, 'event does not fire on alternative chain routes');
|
||||||
|
|
||||||
|
emit(middle, 'ev');
|
||||||
|
assert.equal(middleFired, 3,
|
||||||
|
'event triggers in source of pipe chain');
|
||||||
|
assert.equal(destFired, 3,
|
||||||
|
'event propagates to end of pipe chain from middle src');
|
||||||
|
assert.equal(src1Fired, 1, 'event does not fire on alternative chain routes');
|
||||||
|
assert.equal(src2Fired, 1, 'event does not fire on alternative chain routes');
|
||||||
|
};
|
||||||
|
|
||||||
require('test').run(exports);
|
require('test').run(exports);
|
||||||
|
@ -24,6 +24,53 @@ exports.testOnClick = function (assert) {
|
|||||||
loader.unload();
|
loader.unload();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports['test:numbers and URLs in options'] = function(assert) {
|
||||||
|
let [loader] = makeLoader(module);
|
||||||
|
let notifs = loader.require('sdk/notifications');
|
||||||
|
let opts = {
|
||||||
|
title: 123,
|
||||||
|
text: 45678,
|
||||||
|
// must use in-loader `sdk/url` module for the validation type check to work
|
||||||
|
iconURL: loader.require('sdk/url').URL('data:image/png,blah')
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
notifs.notify(opts);
|
||||||
|
assert.pass('using numbers and URLs in options works');
|
||||||
|
} catch (e) {
|
||||||
|
assert.fail('using numbers and URLs in options must not throw');
|
||||||
|
}
|
||||||
|
loader.unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
exports['test:new tag, dir and lang options'] = function(assert) {
|
||||||
|
let [loader] = makeLoader(module);
|
||||||
|
let notifs = loader.require('sdk/notifications');
|
||||||
|
let opts = {
|
||||||
|
title: 'best',
|
||||||
|
tag: 'tagging',
|
||||||
|
lang: 'en'
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
opts.dir = 'ttb';
|
||||||
|
notifs.notify(opts);
|
||||||
|
assert.fail('`dir` option must not accept TopToBottom direction.');
|
||||||
|
} catch (e) {
|
||||||
|
assert.equal(e.message,
|
||||||
|
'`dir` option must be one of: "auto", "ltr" or "rtl".');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
opts.dir = 'rtl';
|
||||||
|
notifs.notify(opts);
|
||||||
|
assert.pass('`dir` option accepts "rtl" direction.');
|
||||||
|
} catch (e) {
|
||||||
|
assert.fail('`dir` option must accept "rtl" direction.');
|
||||||
|
}
|
||||||
|
|
||||||
|
loader.unload();
|
||||||
|
}
|
||||||
|
|
||||||
// Returns [loader, mockAlertService].
|
// Returns [loader, mockAlertService].
|
||||||
function makeLoader(module) {
|
function makeLoader(module) {
|
||||||
let loader = Loader(module);
|
let loader = Loader(module);
|
||||||
|
@ -430,6 +430,50 @@ exports.testWorksWithExistingTabs = function(assert, done) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.testExistingFrameDoesntMatchInclude = function(assert, done) {
|
||||||
|
let iframeURL = 'data:text/html;charset=utf-8,UNIQUE-TEST-STRING-42';
|
||||||
|
let iframe = '<iframe src="' + iframeURL + '" />';
|
||||||
|
let url = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframe);
|
||||||
|
tabs.open({
|
||||||
|
url: url,
|
||||||
|
onReady: function onReady(tab) {
|
||||||
|
let pagemod = new PageMod({
|
||||||
|
include: url,
|
||||||
|
attachTo: ['existing', 'frame'],
|
||||||
|
onAttach: function() {
|
||||||
|
assert.fail("Existing iframe URL doesn't match include, must not attach to anything");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
timer.setTimeout(function() {
|
||||||
|
assert.pass("PageMod didn't attach to anything")
|
||||||
|
pagemod.destroy();
|
||||||
|
tab.close(done);
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.testExistingOnlyFrameMatchesInclude = function(assert, done) {
|
||||||
|
let iframeURL = 'data:text/html;charset=utf-8,UNIQUE-TEST-STRING-43';
|
||||||
|
let iframe = '<iframe src="' + iframeURL + '" />';
|
||||||
|
let url = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframe);
|
||||||
|
tabs.open({
|
||||||
|
url: url,
|
||||||
|
onReady: function onReady(tab) {
|
||||||
|
let pagemod = new PageMod({
|
||||||
|
include: iframeURL,
|
||||||
|
attachTo: ['existing', 'frame'],
|
||||||
|
onAttach: function(worker) {
|
||||||
|
assert.equal(iframeURL, worker.url,
|
||||||
|
"PageMod attached to existing iframe when only it matches include rules");
|
||||||
|
pagemod.destroy();
|
||||||
|
tab.close(done);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
exports.testTabWorkerOnMessage = function(assert, done) {
|
exports.testTabWorkerOnMessage = function(assert, done) {
|
||||||
let { browserWindows } = require("sdk/windows");
|
let { browserWindows } = require("sdk/windows");
|
||||||
let tabs = require("sdk/tabs");
|
let tabs = require("sdk/tabs");
|
||||||
|
@ -245,15 +245,14 @@ exports.testMultipleOnMessageCallbacks = function(assert, done) {
|
|||||||
let page = Page({
|
let page = Page({
|
||||||
contentScript: "self.postMessage('')",
|
contentScript: "self.postMessage('')",
|
||||||
contentScriptWhen: "end",
|
contentScriptWhen: "end",
|
||||||
onMessage: function() count += 1
|
onMessage: () => count += 1
|
||||||
});
|
});
|
||||||
page.on('message', function() count += 2);
|
page.on('message', () => count += 2);
|
||||||
page.on('message', function() count *= 3);
|
page.on('message', () => count *= 3);
|
||||||
page.on('message', function()
|
page.on('message', () =>
|
||||||
assert.equal(count, 9, "All callbacks were called, in order."));
|
assert.equal(count, 9, "All callbacks were called, in order."));
|
||||||
page.on('message', function() done());
|
page.on('message', done);
|
||||||
|
};
|
||||||
}
|
|
||||||
|
|
||||||
exports.testLoadContentPage = function(assert, done) {
|
exports.testLoadContentPage = function(assert, done) {
|
||||||
let page = Page({
|
let page = Page({
|
||||||
|
@ -210,6 +210,27 @@ exports.testInvalidJSON = function (assert, done) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.testDelete = function (assert, done) {
|
||||||
|
let srv = startServerAsync(port, basePath);
|
||||||
|
|
||||||
|
srv.registerPathHandler("/test-delete",
|
||||||
|
function handle(request, response) {
|
||||||
|
response.setHeader("Content-Type", "text/plain", false);
|
||||||
|
});
|
||||||
|
|
||||||
|
Request({
|
||||||
|
url: "http://localhost:" + port + "/test-delete",
|
||||||
|
onComplete: function (response) {
|
||||||
|
// We cannot access the METHOD of the request to verify it's set
|
||||||
|
// correctly.
|
||||||
|
assert.equal(response.text, "");
|
||||||
|
assert.equal(response.statusText, "OK");
|
||||||
|
assert.equal(response.headers["Content-Type"], "text/plain");
|
||||||
|
srv.stop(done);
|
||||||
|
}
|
||||||
|
}).delete();
|
||||||
|
};
|
||||||
|
|
||||||
exports.testHead = function (assert, done) {
|
exports.testHead = function (assert, done) {
|
||||||
let srv = startServerAsync(port, basePath);
|
let srv = startServerAsync(port, basePath);
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ exports.testSetGetBool = function(assert) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// TEST: setting and getting preferences with special characters work
|
// TEST: setting and getting preferences with special characters work
|
||||||
exports.testSpecialChars = function(assert) {
|
exports.testSpecialChars = function(assert, done) {
|
||||||
let chars = specialChars.split("");
|
let chars = specialChars.split("");
|
||||||
let len = chars.length;
|
let len = chars.length;
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ exports.testSpecialChars = function(assert) {
|
|||||||
|
|
||||||
// end test
|
// end test
|
||||||
if (++count == len)
|
if (++count == len)
|
||||||
test.done();
|
done();
|
||||||
})
|
})
|
||||||
sp[char] = rand;
|
sp[char] = rand;
|
||||||
});
|
});
|
||||||
|
@ -7,6 +7,8 @@ const tabs = require("sdk/tabs"); // From addon-kit
|
|||||||
const windowUtils = require("sdk/deprecated/window-utils");
|
const windowUtils = require("sdk/deprecated/window-utils");
|
||||||
const { getTabForWindow } = require('sdk/tabs/helpers');
|
const { getTabForWindow } = require('sdk/tabs/helpers');
|
||||||
const app = require("sdk/system/xul-app");
|
const app = require("sdk/system/xul-app");
|
||||||
|
const { viewFor } = require("sdk/view/core");
|
||||||
|
const { getTabId } = require("sdk/tabs/utils");
|
||||||
|
|
||||||
// The primary test tab
|
// The primary test tab
|
||||||
var primaryTab;
|
var primaryTab;
|
||||||
@ -136,4 +138,17 @@ exports["test behavior on close"] = function(assert, done) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports["test viewFor(tab)"] = (assert, done) => {
|
||||||
|
tabs.once("open", tab => {
|
||||||
|
const view = viewFor(tab);
|
||||||
|
assert.ok(view, "view is returned");
|
||||||
|
assert.equal(getTabId(view), tab.id, "tab has a same id");
|
||||||
|
|
||||||
|
tab.close();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
tabs.open({ url: "about:mozilla" });
|
||||||
|
}
|
||||||
|
|
||||||
require("test").run(exports);
|
require("test").run(exports);
|
||||||
|
@ -18,6 +18,7 @@ const self = require("sdk/self");
|
|||||||
const windowUtils = require("sdk/deprecated/window-utils");
|
const windowUtils = require("sdk/deprecated/window-utils");
|
||||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||||
const { close } = require("sdk/window/helpers");
|
const { close } = require("sdk/window/helpers");
|
||||||
|
const unload = require("sdk/system/unload");
|
||||||
const fixtures = require("./fixtures");
|
const fixtures = require("./fixtures");
|
||||||
|
|
||||||
let jetpackID = "testID";
|
let jetpackID = "testID";
|
||||||
@ -51,7 +52,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// Test basic construct/destroy
|
// Test basic construct/destroy
|
||||||
AddonsMgrListener.onInstalling();
|
AddonsMgrListener.onInstalling();
|
||||||
let w = widgets.Widget({ id: "fooID", label: "foo", content: "bar" });
|
let w = widgets.Widget({ id: "basic-construct-destroy", label: "foo", content: "bar" });
|
||||||
AddonsMgrListener.onInstalled();
|
AddonsMgrListener.onInstalled();
|
||||||
assert.equal(widgetCount(), widgetStartCount + 1, "panel has correct number of child elements after widget construction");
|
assert.equal(widgetCount(), widgetStartCount + 1, "panel has correct number of child elements after widget construction");
|
||||||
|
|
||||||
@ -69,7 +70,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
let loader = Loader(module);
|
let loader = Loader(module);
|
||||||
let widgetsFromLoader = loader.require("sdk/widget");
|
let widgetsFromLoader = loader.require("sdk/widget");
|
||||||
let widgetStartCount = widgetCount();
|
let widgetStartCount = widgetCount();
|
||||||
let w = widgetsFromLoader.Widget({ id: "fooID", label: "foo", content: "bar" });
|
let w = widgetsFromLoader.Widget({ id: "destroy-on-unload", label: "foo", content: "bar" });
|
||||||
assert.equal(widgetCount(), widgetStartCount + 1, "widget has been correctly added");
|
assert.equal(widgetCount(), widgetStartCount + 1, "widget has been correctly added");
|
||||||
loader.unload();
|
loader.unload();
|
||||||
assert.equal(widgetCount(), widgetStartCount, "widget has been destroyed on module unload");
|
assert.equal(widgetCount(), widgetStartCount, "widget has been destroyed on module unload");
|
||||||
@ -94,25 +95,25 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// Test no content or image
|
// Test no content or image
|
||||||
assert.throws(
|
assert.throws(
|
||||||
function() widgets.Widget({id: "fooID", label: "foo"}),
|
function() widgets.Widget({id: "no-content-throws", label: "foo"}),
|
||||||
/^No content or contentURL property found\. Widgets must have one or the other\.$/,
|
/^No content or contentURL property found\. Widgets must have one or the other\.$/,
|
||||||
"throws on no content");
|
"throws on no content");
|
||||||
|
|
||||||
// Test empty content, no image
|
// Test empty content, no image
|
||||||
assert.throws(
|
assert.throws(
|
||||||
function() widgets.Widget({id:"fooID", label: "foo", content: ""}),
|
function() widgets.Widget({id:"empty-content-throws", label: "foo", content: ""}),
|
||||||
/^No content or contentURL property found\. Widgets must have one or the other\.$/,
|
/^No content or contentURL property found\. Widgets must have one or the other\.$/,
|
||||||
"throws on empty content");
|
"throws on empty content");
|
||||||
|
|
||||||
// Test empty image, no content
|
// Test empty image, no content
|
||||||
assert.throws(
|
assert.throws(
|
||||||
function() widgets.Widget({id:"fooID", label: "foo", image: ""}),
|
function() widgets.Widget({id:"empty-image-throws", label: "foo", image: ""}),
|
||||||
/^No content or contentURL property found\. Widgets must have one or the other\.$/,
|
/^No content or contentURL property found\. Widgets must have one or the other\.$/,
|
||||||
"throws on empty content");
|
"throws on empty content");
|
||||||
|
|
||||||
// Test empty content, empty image
|
// Test empty content, empty image
|
||||||
assert.throws(
|
assert.throws(
|
||||||
function() widgets.Widget({id:"fooID", label: "foo", content: "", image: ""}),
|
function() widgets.Widget({id:"empty-image-and-content-throws", label: "foo", content: "", image: ""}),
|
||||||
/^No content or contentURL property found. Widgets must have one or the other\.$/,
|
/^No content or contentURL property found. Widgets must have one or the other\.$/,
|
||||||
"throws on empty content");
|
"throws on empty content");
|
||||||
|
|
||||||
@ -138,14 +139,14 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// Test position restore on create/destroy/create
|
// Test position restore on create/destroy/create
|
||||||
// Create 3 ordered widgets
|
// Create 3 ordered widgets
|
||||||
let w1 = widgets.Widget({id: "first", label:"first", content: "bar"});
|
let w1 = widgets.Widget({id: "position-first", label:"first", content: "bar"});
|
||||||
let w2 = widgets.Widget({id: "second", label:"second", content: "bar"});
|
let w2 = widgets.Widget({id: "position-second", label:"second", content: "bar"});
|
||||||
let w3 = widgets.Widget({id: "third", label:"third", content: "bar"});
|
let w3 = widgets.Widget({id: "position-third", label:"third", content: "bar"});
|
||||||
// Remove the middle widget
|
// Remove the middle widget
|
||||||
assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is the second widget inserted");
|
assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is the second widget inserted");
|
||||||
w2.destroy();
|
w2.destroy();
|
||||||
assert.equal(widgetNode(1).getAttribute("label"), "third", "second widget is removed, so second widget is now the third one");
|
assert.equal(widgetNode(1).getAttribute("label"), "third", "second widget is removed, so second widget is now the third one");
|
||||||
w2 = widgets.Widget({id: "second", label:"second", content: "bar"});
|
w2 = widgets.Widget({id: "position-second", label:"second", content: "bar"});
|
||||||
assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is created again, at the same location");
|
assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is created again, at the same location");
|
||||||
// Cleanup this testcase
|
// Cleanup this testcase
|
||||||
AddonsMgrListener.onUninstalling();
|
AddonsMgrListener.onUninstalling();
|
||||||
@ -160,14 +161,14 @@ exports.testConstructor = function(assert, done) {
|
|||||||
let anotherWidgetsInstance = loader.require("sdk/widget");
|
let anotherWidgetsInstance = loader.require("sdk/widget");
|
||||||
assert.ok(container().collapsed, "UI is hidden when no widgets");
|
assert.ok(container().collapsed, "UI is hidden when no widgets");
|
||||||
AddonsMgrListener.onInstalling();
|
AddonsMgrListener.onInstalling();
|
||||||
let w1 = widgets.Widget({id: "foo", label: "foo", content: "bar"});
|
let w1 = widgets.Widget({id: "ui-unhide", label: "foo", content: "bar"});
|
||||||
// Ideally we would let AddonsMgrListener display the addon bar
|
// Ideally we would let AddonsMgrListener display the addon bar
|
||||||
// But, for now, addon bar is immediatly displayed by sdk code
|
// But, for now, addon bar is immediatly displayed by sdk code
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=627484
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=627484
|
||||||
assert.ok(!container().collapsed, "UI is already visible when we just added the widget");
|
assert.ok(!container().collapsed, "UI is already visible when we just added the widget");
|
||||||
AddonsMgrListener.onInstalled();
|
AddonsMgrListener.onInstalled();
|
||||||
assert.ok(!container().collapsed, "UI become visible when we notify AddonsMgrListener about end of addon installation");
|
assert.ok(!container().collapsed, "UI become visible when we notify AddonsMgrListener about end of addon installation");
|
||||||
let w2 = anotherWidgetsInstance.Widget({id: "bar", label: "bar", content: "foo"});
|
let w2 = anotherWidgetsInstance.Widget({id: "ui-stay-open", label: "bar", content: "foo"});
|
||||||
assert.ok(!container().collapsed, "UI still visible when we add a second widget");
|
assert.ok(!container().collapsed, "UI still visible when we add a second widget");
|
||||||
AddonsMgrListener.onUninstalling();
|
AddonsMgrListener.onUninstalling();
|
||||||
w1.destroy();
|
w1.destroy();
|
||||||
@ -214,7 +215,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// text widget
|
// text widget
|
||||||
tests.push(function testTextWidget() testSingleWidget({
|
tests.push(function testTextWidget() testSingleWidget({
|
||||||
id: "text",
|
id: "text-single",
|
||||||
label: "text widget",
|
label: "text widget",
|
||||||
content: "oh yeah",
|
content: "oh yeah",
|
||||||
contentScript: "self.postMessage(document.body.innerHTML);",
|
contentScript: "self.postMessage(document.body.innerHTML);",
|
||||||
@ -278,7 +279,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// event: onclick + content
|
// event: onclick + content
|
||||||
tests.push(function testOnclickEventContent() testSingleWidget({
|
tests.push(function testOnclickEventContent() testSingleWidget({
|
||||||
id: "click",
|
id: "click-content",
|
||||||
label: "click test widget - content",
|
label: "click test widget - content",
|
||||||
content: "<div id='me'>foo</div>",
|
content: "<div id='me'>foo</div>",
|
||||||
contentScript: "var evt = new MouseEvent('click', {button: 0});" +
|
contentScript: "var evt = new MouseEvent('click', {button: 0});" +
|
||||||
@ -293,7 +294,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// event: onmouseover + content
|
// event: onmouseover + content
|
||||||
tests.push(function testOnmouseoverEventContent() testSingleWidget({
|
tests.push(function testOnmouseoverEventContent() testSingleWidget({
|
||||||
id: "mouseover",
|
id: "mouseover-content",
|
||||||
label: "mouseover test widget - content",
|
label: "mouseover test widget - content",
|
||||||
content: "<div id='me'>foo</div>",
|
content: "<div id='me'>foo</div>",
|
||||||
contentScript: "var evt = new MouseEvent('mouseover'); " +
|
contentScript: "var evt = new MouseEvent('mouseover'); " +
|
||||||
@ -308,7 +309,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// event: onmouseout + content
|
// event: onmouseout + content
|
||||||
tests.push(function testOnmouseoutEventContent() testSingleWidget({
|
tests.push(function testOnmouseoutEventContent() testSingleWidget({
|
||||||
id: "mouseout",
|
id: "mouseout-content",
|
||||||
label: "mouseout test widget - content",
|
label: "mouseout test widget - content",
|
||||||
content: "<div id='me'>foo</div>",
|
content: "<div id='me'>foo</div>",
|
||||||
contentScript: "var evt = new MouseEvent('mouseout');" +
|
contentScript: "var evt = new MouseEvent('mouseout');" +
|
||||||
@ -323,7 +324,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// event: onclick + image
|
// event: onclick + image
|
||||||
tests.push(function testOnclickEventImage() testSingleWidget({
|
tests.push(function testOnclickEventImage() testSingleWidget({
|
||||||
id: "click",
|
id: "click-image",
|
||||||
label: "click test widget - image",
|
label: "click test widget - image",
|
||||||
contentURL: fixtures.url("moz_favicon.ico"),
|
contentURL: fixtures.url("moz_favicon.ico"),
|
||||||
contentScript: "var evt = new MouseEvent('click'); " +
|
contentScript: "var evt = new MouseEvent('click'); " +
|
||||||
@ -338,7 +339,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// event: onmouseover + image
|
// event: onmouseover + image
|
||||||
tests.push(function testOnmouseoverEventImage() testSingleWidget({
|
tests.push(function testOnmouseoverEventImage() testSingleWidget({
|
||||||
id: "mouseover",
|
id: "mouseover-image",
|
||||||
label: "mouseover test widget - image",
|
label: "mouseover test widget - image",
|
||||||
contentURL: fixtures.url("moz_favicon.ico"),
|
contentURL: fixtures.url("moz_favicon.ico"),
|
||||||
contentScript: "var evt = new MouseEvent('mouseover');" +
|
contentScript: "var evt = new MouseEvent('mouseover');" +
|
||||||
@ -353,7 +354,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// event: onmouseout + image
|
// event: onmouseout + image
|
||||||
tests.push(function testOnmouseoutEventImage() testSingleWidget({
|
tests.push(function testOnmouseoutEventImage() testSingleWidget({
|
||||||
id: "mouseout",
|
id: "mouseout-image",
|
||||||
label: "mouseout test widget - image",
|
label: "mouseout test widget - image",
|
||||||
contentURL: fixtures.url("moz_favicon.ico"),
|
contentURL: fixtures.url("moz_favicon.ico"),
|
||||||
contentScript: "var evt = new MouseEvent('mouseout'); " +
|
contentScript: "var evt = new MouseEvent('mouseout'); " +
|
||||||
@ -380,7 +381,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
// test updating widget content
|
// test updating widget content
|
||||||
let loads = 0;
|
let loads = 0;
|
||||||
tests.push(function testUpdatingWidgetContent() testSingleWidget({
|
tests.push(function testUpdatingWidgetContent() testSingleWidget({
|
||||||
id: "content",
|
id: "content-updating",
|
||||||
label: "content update test widget",
|
label: "content update test widget",
|
||||||
content: "<div id='me'>foo</div>",
|
content: "<div id='me'>foo</div>",
|
||||||
contentScript: "self.postMessage(1)",
|
contentScript: "self.postMessage(1)",
|
||||||
@ -403,7 +404,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
let url2 = "data:text/html;charset=utf-8,<body>nistel</body>";
|
let url2 = "data:text/html;charset=utf-8,<body>nistel</body>";
|
||||||
|
|
||||||
tests.push(function testUpdatingContentURL() testSingleWidget({
|
tests.push(function testUpdatingContentURL() testSingleWidget({
|
||||||
id: "content",
|
id: "content-url-updating",
|
||||||
label: "content update test widget",
|
label: "content update test widget",
|
||||||
contentURL: url1,
|
contentURL: url1,
|
||||||
contentScript: "self.postMessage(document.location.href);",
|
contentScript: "self.postMessage(document.location.href);",
|
||||||
@ -426,7 +427,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// test tooltip
|
// test tooltip
|
||||||
tests.push(function testTooltip() testSingleWidget({
|
tests.push(function testTooltip() testSingleWidget({
|
||||||
id: "text",
|
id: "text-with-tooltip",
|
||||||
label: "text widget",
|
label: "text widget",
|
||||||
content: "oh yeah",
|
content: "oh yeah",
|
||||||
tooltip: "foo",
|
tooltip: "foo",
|
||||||
@ -456,7 +457,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
// test updating widget tooltip
|
// test updating widget tooltip
|
||||||
let updated = false;
|
let updated = false;
|
||||||
tests.push(function testUpdatingTooltip() testSingleWidget({
|
tests.push(function testUpdatingTooltip() testSingleWidget({
|
||||||
id: "tooltip",
|
id: "tooltip-updating",
|
||||||
label: "tooltip update test widget",
|
label: "tooltip update test widget",
|
||||||
tooltip: "foo",
|
tooltip: "foo",
|
||||||
content: "<div id='me'>foo</div>",
|
content: "<div id='me'>foo</div>",
|
||||||
@ -472,7 +473,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// test allow attribute
|
// test allow attribute
|
||||||
tests.push(function testDefaultAllow() testSingleWidget({
|
tests.push(function testDefaultAllow() testSingleWidget({
|
||||||
id: "allow",
|
id: "allow-default",
|
||||||
label: "allow.script attribute",
|
label: "allow.script attribute",
|
||||||
content: "<script>document.title = 'ok';</script>",
|
content: "<script>document.title = 'ok';</script>",
|
||||||
contentScript: "self.postMessage(document.title)",
|
contentScript: "self.postMessage(document.title)",
|
||||||
@ -484,7 +485,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
tests.push(function testExplicitAllow() testSingleWidget({
|
tests.push(function testExplicitAllow() testSingleWidget({
|
||||||
id: "allow",
|
id: "allow-explicit",
|
||||||
label: "allow.script attribute",
|
label: "allow.script attribute",
|
||||||
allow: {script: true},
|
allow: {script: true},
|
||||||
content: "<script>document.title = 'ok';</script>",
|
content: "<script>document.title = 'ok';</script>",
|
||||||
@ -497,7 +498,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
tests.push(function testExplicitDisallow() testSingleWidget({
|
tests.push(function testExplicitDisallow() testSingleWidget({
|
||||||
id: "allow",
|
id: "allow-explicit-disallow",
|
||||||
label: "allow.script attribute",
|
label: "allow.script attribute",
|
||||||
content: "<script>document.title = 'ok';</script>",
|
content: "<script>document.title = 'ok';</script>",
|
||||||
allow: {script: false},
|
allow: {script: false},
|
||||||
@ -521,11 +522,11 @@ exports.testConstructor = function(assert, done) {
|
|||||||
function widgetCount2() container() ? container().querySelectorAll('[id^="widget\:"]').length : 0;
|
function widgetCount2() container() ? container().querySelectorAll('[id^="widget\:"]').length : 0;
|
||||||
let widgetStartCount2 = widgetCount2();
|
let widgetStartCount2 = widgetCount2();
|
||||||
|
|
||||||
let w1Opts = {id:"first", label: "first widget", content: "first content"};
|
let w1Opts = {id:"first-multi-window", label: "first widget", content: "first content"};
|
||||||
let w1 = testSingleWidget(w1Opts);
|
let w1 = testSingleWidget(w1Opts);
|
||||||
assert.equal(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first widget");
|
assert.equal(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first widget");
|
||||||
|
|
||||||
let w2Opts = {id:"second", label: "second widget", content: "second content"};
|
let w2Opts = {id:"second-multi-window", label: "second widget", content: "second content"};
|
||||||
let w2 = testSingleWidget(w2Opts);
|
let w2 = testSingleWidget(w2Opts);
|
||||||
assert.equal(widgetCount2(), widgetStartCount2 + 2, "2nd window has correct number of child elements after second widget");
|
assert.equal(widgetCount2(), widgetStartCount2 + 2, "2nd window has correct number of child elements after second widget");
|
||||||
|
|
||||||
@ -542,7 +543,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
tests.push(function testWindowClosing() {
|
tests.push(function testWindowClosing() {
|
||||||
// 1/ Create a new widget
|
// 1/ Create a new widget
|
||||||
let w1Opts = {
|
let w1Opts = {
|
||||||
id:"first",
|
id:"first-win-closing",
|
||||||
label: "first widget",
|
label: "first widget",
|
||||||
content: "first content",
|
content: "first content",
|
||||||
contentScript: "self.port.on('event', function () self.port.emit('event'))"
|
contentScript: "self.port.on('event', function () self.port.emit('event'))"
|
||||||
@ -595,7 +596,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!australis) {
|
if (false) {
|
||||||
tests.push(function testAddonBarHide() {
|
tests.push(function testAddonBarHide() {
|
||||||
const tabBrowser = require("sdk/deprecated/tab-browser");
|
const tabBrowser = require("sdk/deprecated/tab-browser");
|
||||||
|
|
||||||
@ -614,11 +615,13 @@ exports.testConstructor = function(assert, done) {
|
|||||||
assert.ok(container2().collapsed,
|
assert.ok(container2().collapsed,
|
||||||
"2nd window starts with an hidden addon-bar");
|
"2nd window starts with an hidden addon-bar");
|
||||||
|
|
||||||
let w1Opts = {id:"first", label: "first widget", content: "first content"};
|
let w1Opts = {id:"first-addonbar-hide", label: "first widget", content: "first content"};
|
||||||
let w1 = testSingleWidget(w1Opts);
|
let w1 = testSingleWidget(w1Opts);
|
||||||
assert.equal(widgetCount2(), widgetStartCount2 + 1,
|
assert.equal(widgetCount2(), widgetStartCount2 + 1,
|
||||||
"2nd window has correct number of child elements after" +
|
"2nd window has correct number of child elements after" +
|
||||||
"widget creation");
|
"widget creation");
|
||||||
|
assert.ok(!container().collapsed, "1st window has a visible addon-bar");
|
||||||
|
assert.ok(!container2().collapsed, "2nd window has a visible addon-bar");
|
||||||
w1.destroy();
|
w1.destroy();
|
||||||
assert.equal(widgetCount2(), widgetStartCount2,
|
assert.equal(widgetCount2(), widgetStartCount2,
|
||||||
"2nd window has correct number of child elements after" +
|
"2nd window has correct number of child elements after" +
|
||||||
@ -637,7 +640,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
|
|
||||||
// test widget.width
|
// test widget.width
|
||||||
tests.push(function testWidgetWidth() testSingleWidget({
|
tests.push(function testWidgetWidth() testSingleWidget({
|
||||||
id: "text",
|
id: "text-test-width",
|
||||||
label: "test widget.width",
|
label: "test widget.width",
|
||||||
content: "test width",
|
content: "test width",
|
||||||
width: 200,
|
width: 200,
|
||||||
@ -661,7 +664,7 @@ exports.testConstructor = function(assert, done) {
|
|||||||
// test click handler not respond to right-click
|
// test click handler not respond to right-click
|
||||||
let clickCount = 0;
|
let clickCount = 0;
|
||||||
tests.push(function testNoRightClick() testSingleWidget({
|
tests.push(function testNoRightClick() testSingleWidget({
|
||||||
id: "click-content",
|
id: "right-click-content",
|
||||||
label: "click test widget - content",
|
label: "click test widget - content",
|
||||||
content: "<div id='me'>foo</div>",
|
content: "<div id='me'>foo</div>",
|
||||||
contentScript: // Left click
|
contentScript: // Left click
|
||||||
@ -762,7 +765,7 @@ exports.testWidgetMessaging = function testWidgetMessaging(assert, done) {
|
|||||||
let origMessage = "foo";
|
let origMessage = "foo";
|
||||||
const widgets = require("sdk/widget");
|
const widgets = require("sdk/widget");
|
||||||
let widget = widgets.Widget({
|
let widget = widgets.Widget({
|
||||||
id: "foo",
|
id: "widget-messaging",
|
||||||
label: "foo",
|
label: "foo",
|
||||||
content: "<bar>baz</bar>",
|
content: "<bar>baz</bar>",
|
||||||
contentScriptWhen: "end",
|
contentScriptWhen: "end",
|
||||||
@ -782,7 +785,7 @@ exports.testWidgetMessaging = function testWidgetMessaging(assert, done) {
|
|||||||
exports.testWidgetViews = function testWidgetViews(assert, done) {
|
exports.testWidgetViews = function testWidgetViews(assert, done) {
|
||||||
const widgets = require("sdk/widget");
|
const widgets = require("sdk/widget");
|
||||||
let widget = widgets.Widget({
|
let widget = widgets.Widget({
|
||||||
id: "foo",
|
id: "widget-views",
|
||||||
label: "foo",
|
label: "foo",
|
||||||
content: "<bar>baz</bar>",
|
content: "<bar>baz</bar>",
|
||||||
contentScriptWhen: "ready",
|
contentScriptWhen: "ready",
|
||||||
@ -805,7 +808,7 @@ exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(assert, done)
|
|||||||
const widgets = require("sdk/widget");
|
const widgets = require("sdk/widget");
|
||||||
let view = null;
|
let view = null;
|
||||||
let widget = widgets.Widget({
|
let widget = widgets.Widget({
|
||||||
id: "foo",
|
id: "widget-view-ui-events",
|
||||||
label: "foo",
|
label: "foo",
|
||||||
content: "<div id='me'>foo</div>",
|
content: "<div id='me'>foo</div>",
|
||||||
contentScript: "var evt = new MouseEvent('click', {button: 0});" +
|
contentScript: "var evt = new MouseEvent('click', {button: 0});" +
|
||||||
@ -830,7 +833,7 @@ exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(assert, done)
|
|||||||
exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(assert, done) {
|
exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(assert, done) {
|
||||||
const widgets = require("sdk/widget");
|
const widgets = require("sdk/widget");
|
||||||
let widget = widgets.Widget({
|
let widget = widgets.Widget({
|
||||||
id: "foo",
|
id: "widget-view-custom-events",
|
||||||
label: "foo",
|
label: "foo",
|
||||||
content: "<div id='me'>foo</div>",
|
content: "<div id='me'>foo</div>",
|
||||||
contentScript: "self.port.emit('event', 'ok');",
|
contentScript: "self.port.emit('event', 'ok');",
|
||||||
@ -853,7 +856,7 @@ exports.testWidgetViewsTooltip = function testWidgetViewsTooltip(assert, done) {
|
|||||||
const widgets = require("sdk/widget");
|
const widgets = require("sdk/widget");
|
||||||
|
|
||||||
let widget = new widgets.Widget({
|
let widget = new widgets.Widget({
|
||||||
id: "foo",
|
id: "widget-views-tooltip",
|
||||||
label: "foo",
|
label: "foo",
|
||||||
content: "foo"
|
content: "foo"
|
||||||
});
|
});
|
||||||
@ -879,7 +882,7 @@ exports.testWidgetMove = function testWidgetMove(assert, done) {
|
|||||||
let gotFirstReady = false;
|
let gotFirstReady = false;
|
||||||
|
|
||||||
let widget = widgets.Widget({
|
let widget = widgets.Widget({
|
||||||
id: "foo",
|
id: "widget-move",
|
||||||
label: label,
|
label: label,
|
||||||
content: "<bar>baz</bar>",
|
content: "<bar>baz</bar>",
|
||||||
contentScriptWhen: "ready",
|
contentScriptWhen: "ready",
|
||||||
@ -947,7 +950,7 @@ exports.testWidgetWithPound = function testWidgetWithPound(assert, done) {
|
|||||||
|
|
||||||
exports.testContentScriptOptionsOption = function(assert, done) {
|
exports.testContentScriptOptionsOption = function(assert, done) {
|
||||||
let widget = require("sdk/widget").Widget({
|
let widget = require("sdk/widget").Widget({
|
||||||
id: "fooz",
|
id: "widget-script-options",
|
||||||
label: "fooz",
|
label: "fooz",
|
||||||
content: "fooz",
|
content: "fooz",
|
||||||
contentScript: "self.postMessage( [typeof self.options.d, self.options] );",
|
contentScript: "self.postMessage( [typeof self.options.d, self.options] );",
|
||||||
@ -1051,6 +1054,34 @@ exports.testSVGWidget = function(assert, done) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.testReinsertion = function(assert, done) {
|
||||||
|
const WIDGETID = "test-reinsertion";
|
||||||
|
let windowUtils = require("sdk/deprecated/window-utils");
|
||||||
|
let browserWindow = windowUtils.activeBrowserWindow;
|
||||||
|
let widget = require("sdk/widget").Widget({
|
||||||
|
id: "test-reinsertion",
|
||||||
|
label: "test reinsertion",
|
||||||
|
content: "Test",
|
||||||
|
});
|
||||||
|
let realWidgetId = "widget:" + jetpackID + "-" + WIDGETID;
|
||||||
|
// Remove the widget:
|
||||||
|
if (australis) {
|
||||||
|
browserWindow.CustomizableUI.removeWidgetFromArea(realWidgetId);
|
||||||
|
} else {
|
||||||
|
let widget = browserWindow.document.getElementById(realWidgetId);
|
||||||
|
let container = widget.parentNode;
|
||||||
|
container.currentSet = container.currentSet.replace("," + realWidgetId, "");
|
||||||
|
container.setAttribute("currentset", container.currentSet);
|
||||||
|
container.ownerDocument.persist(container.id, "currentset");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabBrowser = require("sdk/deprecated/tab-browser");
|
||||||
|
tabBrowser.addTab("about:blank", { inNewWindow: true, onLoad: function(e) {
|
||||||
|
assert.equal(e.target.defaultView.document.getElementById(realWidgetId), null);
|
||||||
|
close(e.target.defaultView).then(done);
|
||||||
|
}});
|
||||||
|
};
|
||||||
|
|
||||||
if (!australis) {
|
if (!australis) {
|
||||||
exports.testNavigationBarWidgets = function testNavigationBarWidgets(assert, done) {
|
exports.testNavigationBarWidgets = function testNavigationBarWidgets(assert, done) {
|
||||||
let w1 = widgets.Widget({id: "1st", label: "1st widget", content: "1"});
|
let w1 = widgets.Widget({id: "1st", label: "1st widget", content: "1"});
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
const { Loader } = require('sdk/test/loader');
|
const { Loader } = require('sdk/test/loader');
|
||||||
const { browserWindows } = require('sdk/windows');
|
const { browserWindows } = require('sdk/windows');
|
||||||
|
const { viewFor } = require('sdk/view/core');
|
||||||
|
const { Ci } = require("chrome");
|
||||||
|
const { isBrowser, getWindowTitle } = require("sdk/window/utils");
|
||||||
|
|
||||||
// TEST: browserWindows Iterator
|
// TEST: browserWindows Iterator
|
||||||
exports.testBrowserWindowsIterator = function(assert) {
|
exports.testBrowserWindowsIterator = function(assert) {
|
||||||
@ -55,4 +58,23 @@ exports.testWindowActivateMethod_simple = function(assert) {
|
|||||||
'Active tab is active after window.activate() call');
|
'Active tab is active after window.activate() call');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports["test getView(window)"] = function(assert, done) {
|
||||||
|
browserWindows.once("open", window => {
|
||||||
|
const view = viewFor(window);
|
||||||
|
|
||||||
|
assert.ok(view instanceof Ci.nsIDOMWindow, "view is a window");
|
||||||
|
assert.ok(isBrowser(view), "view is a browser window");
|
||||||
|
assert.equal(getWindowTitle(view), window.title,
|
||||||
|
"window has a right title");
|
||||||
|
|
||||||
|
window.close();
|
||||||
|
window.destroy();
|
||||||
|
assert.equal(viewFor(window), null, "window view is gone");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
browserWindows.open({ url: "data:text/html,<title>yo</title>" });
|
||||||
|
};
|
||||||
|
|
||||||
require('sdk/test').run(exports);
|
require('sdk/test').run(exports);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"revision": "9ba62e3061abd5521ffbbee5386a0654f972f73b",
|
"revision": "3fe38577e17209728a54b14624143dbf99ade2df",
|
||||||
"repo_path": "/integration/gaia-central"
|
"repo_path": "/integration/gaia-central"
|
||||||
}
|
}
|
||||||
|
@ -121,8 +121,13 @@ var FeedHandler = {
|
|||||||
var haveFeeds = feeds && feeds.length > 0;
|
var haveFeeds = feeds && feeds.length > 0;
|
||||||
|
|
||||||
var feedButton = document.getElementById("feed-button");
|
var feedButton = document.getElementById("feed-button");
|
||||||
if (feedButton)
|
if (feedButton) {
|
||||||
feedButton.disabled = !haveFeeds;
|
if (haveFeeds) {
|
||||||
|
feedButton.removeAttribute("disabled");
|
||||||
|
} else {
|
||||||
|
feedButton.setAttribute("disabled", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!haveFeeds) {
|
if (!haveFeeds) {
|
||||||
this._feedMenuitem.setAttribute("disabled", "true");
|
this._feedMenuitem.setAttribute("disabled", "true");
|
||||||
|
@ -1267,6 +1267,10 @@ SocialSidebar = {
|
|||||||
sbrowser.stop();
|
sbrowser.stop();
|
||||||
sbrowser.removeAttribute("origin");
|
sbrowser.removeAttribute("origin");
|
||||||
sbrowser.setAttribute("src", "about:blank");
|
sbrowser.setAttribute("src", "about:blank");
|
||||||
|
// We need to explicitly create a new content viewer because the old one
|
||||||
|
// doesn't get destroyed until about:blank has loaded (which does not happen
|
||||||
|
// as long as the element is hidden).
|
||||||
|
sbrowser.docShell.createAboutBlankContentViewer(null);
|
||||||
SocialFlyout.unload();
|
SocialFlyout.unload();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1072,20 +1072,10 @@ function waitForMessages(aOptions)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aRule.type) {
|
// The rule tries to match the newer types of messages, based on their
|
||||||
// The rule tries to match the newer types of messages, based on their
|
// object constructor.
|
||||||
// object constructor.
|
if (aRule.type && (!aElement._messageObject ||
|
||||||
if (!aElement._messageObject ||
|
!(aElement._messageObject instanceof aRule.type))) {
|
||||||
!(aElement._messageObject instanceof aRule.type)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (aElement._messageObject) {
|
|
||||||
// If the message element holds a reference to its object, it means this
|
|
||||||
// is a newer message type. All of the older waitForMessages() rules do
|
|
||||||
// not expect this kind of messages. We return false here.
|
|
||||||
// TODO: we keep this behavior until bug 778766 is fixed. After that we
|
|
||||||
// will not require |type| to match newer types of messages.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,10 +52,6 @@ const CONSOLE_DIR_VIEW_HEIGHT = 0.6;
|
|||||||
|
|
||||||
const IGNORED_SOURCE_URLS = ["debugger eval code", "self-hosted"];
|
const IGNORED_SOURCE_URLS = ["debugger eval code", "self-hosted"];
|
||||||
|
|
||||||
// The amount of time in milliseconds that must pass between messages to
|
|
||||||
// trigger the display of a new group.
|
|
||||||
const NEW_GROUP_DELAY = 5000;
|
|
||||||
|
|
||||||
// The amount of time in milliseconds that we wait before performing a live
|
// The amount of time in milliseconds that we wait before performing a live
|
||||||
// search.
|
// search.
|
||||||
const SEARCH_DELAY = 200;
|
const SEARCH_DELAY = 200;
|
||||||
@ -166,9 +162,6 @@ const FILTER_PREFS_PREFIX = "devtools.webconsole.filter.";
|
|||||||
// The minimum font size.
|
// The minimum font size.
|
||||||
const MIN_FONT_SIZE = 10;
|
const MIN_FONT_SIZE = 10;
|
||||||
|
|
||||||
// The maximum length of strings to be displayed by the Web Console.
|
|
||||||
const MAX_LONG_STRING_LENGTH = 200000;
|
|
||||||
|
|
||||||
const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout";
|
const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout";
|
||||||
const PREF_PERSISTLOG = "devtools.webconsole.persistlog";
|
const PREF_PERSISTLOG = "devtools.webconsole.persistlog";
|
||||||
const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
|
const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
|
||||||
@ -1162,6 +1155,7 @@ WebConsoleFrame.prototype = {
|
|||||||
let level = aMessage.level;
|
let level = aMessage.level;
|
||||||
let args = aMessage.arguments;
|
let args = aMessage.arguments;
|
||||||
let objectActors = new Set();
|
let objectActors = new Set();
|
||||||
|
let node = null;
|
||||||
|
|
||||||
// Gather the actor IDs.
|
// Gather the actor IDs.
|
||||||
args.forEach((aValue) => {
|
args.forEach((aValue) => {
|
||||||
@ -1175,7 +1169,11 @@ WebConsoleFrame.prototype = {
|
|||||||
case "info":
|
case "info":
|
||||||
case "warn":
|
case "warn":
|
||||||
case "error":
|
case "error":
|
||||||
case "debug":
|
case "debug": {
|
||||||
|
let msg = new Messages.ConsoleGeneric(aMessage);
|
||||||
|
node = msg.init(this.output).render().element;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "dir": {
|
case "dir": {
|
||||||
body = { arguments: args };
|
body = { arguments: args };
|
||||||
let clipboardArray = [];
|
let clipboardArray = [];
|
||||||
@ -1283,18 +1281,22 @@ WebConsoleFrame.prototype = {
|
|||||||
return null; // no need to continue
|
return null; // no need to continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = this.createMessageNode(CATEGORY_WEBDEV, LEVELS[level], body,
|
if (!node) {
|
||||||
sourceURL, sourceLine, clipboardText,
|
node = this.createMessageNode(CATEGORY_WEBDEV, LEVELS[level], body,
|
||||||
level, aMessage.timeStamp);
|
sourceURL, sourceLine, clipboardText,
|
||||||
if (aMessage.private) {
|
level, aMessage.timeStamp);
|
||||||
node.setAttribute("private", true);
|
if (aMessage.private) {
|
||||||
|
node.setAttribute("private", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objectActors.size > 0) {
|
if (objectActors.size > 0) {
|
||||||
node._objectActors = objectActors;
|
node._objectActors = objectActors;
|
||||||
|
|
||||||
let repeatNode = node.getElementsByClassName("repeats")[0];
|
if (!node._messageObject) {
|
||||||
repeatNode._uid += [...objectActors].join("-");
|
let repeatNode = node.getElementsByClassName("repeats")[0];
|
||||||
|
repeatNode._uid += [...objectActors].join("-");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level == "trace") {
|
if (level == "trace") {
|
||||||
@ -1316,26 +1318,6 @@ WebConsoleFrame.prototype = {
|
|||||||
this.outputMessage(CATEGORY_WEBDEV, this.logConsoleAPIMessage, [aMessage]);
|
this.outputMessage(CATEGORY_WEBDEV, this.logConsoleAPIMessage, [aMessage]);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* The click event handler for objects shown inline coming from the
|
|
||||||
* window.console API.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param nsIDOMNode aAnchor
|
|
||||||
* The object inspector anchor element. This is the clickable element
|
|
||||||
* in the console.log message we display.
|
|
||||||
* @param object aObjectActor
|
|
||||||
* The object actor grip.
|
|
||||||
*/
|
|
||||||
_consoleLogClick: function WCF__consoleLogClick(aAnchor, aObjectActor)
|
|
||||||
{
|
|
||||||
this.jsterm.openVariablesView({
|
|
||||||
label: aAnchor.textContent,
|
|
||||||
objectActor: aObjectActor,
|
|
||||||
autofocus: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reports an error in the page source, either JavaScript or CSS.
|
* Reports an error in the page source, either JavaScript or CSS.
|
||||||
*
|
*
|
||||||
@ -1540,7 +1522,7 @@ WebConsoleFrame.prototype = {
|
|||||||
|
|
||||||
aLinkNode.appendChild(mixedContentWarningNode);
|
aLinkNode.appendChild(mixedContentWarningNode);
|
||||||
|
|
||||||
this._addMessageLinkCallback(mixedContentWarningNode, (aNode, aEvent) => {
|
this._addMessageLinkCallback(mixedContentWarningNode, (aEvent) => {
|
||||||
aEvent.stopPropagation();
|
aEvent.stopPropagation();
|
||||||
this.owner.openLink(MIXED_CONTENT_LEARN_MORE);
|
this.owner.openLink(MIXED_CONTENT_LEARN_MORE);
|
||||||
});
|
});
|
||||||
@ -1601,7 +1583,7 @@ WebConsoleFrame.prototype = {
|
|||||||
warningNode.textContent = moreInfoLabel;
|
warningNode.textContent = moreInfoLabel;
|
||||||
warningNode.className = "learn-more-link";
|
warningNode.className = "learn-more-link";
|
||||||
|
|
||||||
this._addMessageLinkCallback(warningNode, (aNode, aEvent) => {
|
this._addMessageLinkCallback(warningNode, (aEvent) => {
|
||||||
aEvent.stopPropagation();
|
aEvent.stopPropagation();
|
||||||
this.owner.openLink(aURL);
|
this.owner.openLink(aURL);
|
||||||
});
|
});
|
||||||
@ -1694,16 +1676,6 @@ WebConsoleFrame.prototype = {
|
|||||||
this.outputMessage(CATEGORY_JS, node);
|
this.outputMessage(CATEGORY_JS, node);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Inform user that the string he tries to view is too long.
|
|
||||||
*/
|
|
||||||
logWarningAboutStringTooLong: function WCF_logWarningAboutStringTooLong()
|
|
||||||
{
|
|
||||||
let node = this.createMessageNode(CATEGORY_JS, SEVERITY_WARNING,
|
|
||||||
l10n.getStr("longStringTooLong"));
|
|
||||||
this.outputMessage(CATEGORY_JS, node);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the network events coming from the remote Web Console.
|
* Handle the network events coming from the remote Web Console.
|
||||||
*
|
*
|
||||||
@ -2302,6 +2274,9 @@ WebConsoleFrame.prototype = {
|
|||||||
*/
|
*/
|
||||||
_pruneItemFromQueue: function WCF__pruneItemFromQueue(aItem)
|
_pruneItemFromQueue: function WCF__pruneItemFromQueue(aItem)
|
||||||
{
|
{
|
||||||
|
// TODO: handle object releasing in a more elegant way once all console
|
||||||
|
// messages use the new API - bug 778766.
|
||||||
|
|
||||||
let [category, methodOrNode, args] = aItem;
|
let [category, methodOrNode, args] = aItem;
|
||||||
if (typeof methodOrNode != "function" && methodOrNode._objectActors) {
|
if (typeof methodOrNode != "function" && methodOrNode._objectActors) {
|
||||||
for (let actor of methodOrNode._objectActors) {
|
for (let actor of methodOrNode._objectActors) {
|
||||||
@ -2310,6 +2285,19 @@ WebConsoleFrame.prototype = {
|
|||||||
methodOrNode._objectActors.clear();
|
methodOrNode._objectActors.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (methodOrNode == this.output._flushMessageQueue &&
|
||||||
|
args[0]._objectActors) {
|
||||||
|
for (let arg of args) {
|
||||||
|
if (!arg._objectActors) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (let actor of arg._objectActors) {
|
||||||
|
this._releaseObject(actor);
|
||||||
|
}
|
||||||
|
arg._objectActors.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (category == CATEGORY_NETWORK) {
|
if (category == CATEGORY_NETWORK) {
|
||||||
let connectionId = null;
|
let connectionId = null;
|
||||||
if (methodOrNode == this.logNetEvent) {
|
if (methodOrNode == this.logNetEvent) {
|
||||||
@ -2482,10 +2470,6 @@ WebConsoleFrame.prototype = {
|
|||||||
if (aLevel == "dir") {
|
if (aLevel == "dir") {
|
||||||
str = VariablesView.getString(aBody.arguments[0]);
|
str = VariablesView.getString(aBody.arguments[0]);
|
||||||
}
|
}
|
||||||
else if (["log", "info", "warn", "error", "debug"].indexOf(aLevel) > -1 &&
|
|
||||||
typeof aBody == "object") {
|
|
||||||
this._makeConsoleLogMessageBody(node, bodyNode, aBody);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
str = aBody;
|
str = aBody;
|
||||||
}
|
}
|
||||||
@ -2561,126 +2545,6 @@ WebConsoleFrame.prototype = {
|
|||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Make the message body for console.log() calls.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param nsIDOMElement aMessage
|
|
||||||
* The message element that holds the output for the given call.
|
|
||||||
* @param nsIDOMElement aContainer
|
|
||||||
* The specific element that will hold each part of the console.log
|
|
||||||
* output.
|
|
||||||
* @param object aBody
|
|
||||||
* The object given by this.logConsoleAPIMessage(). This object holds
|
|
||||||
* the call information that we need to display - mainly the arguments
|
|
||||||
* array of the given API call.
|
|
||||||
*/
|
|
||||||
_makeConsoleLogMessageBody:
|
|
||||||
function WCF__makeConsoleLogMessageBody(aMessage, aContainer, aBody)
|
|
||||||
{
|
|
||||||
Object.defineProperty(aMessage, "_panelOpen", {
|
|
||||||
get: function() {
|
|
||||||
let nodes = aContainer.getElementsByTagName("a");
|
|
||||||
return Array.prototype.some.call(nodes, function(aNode) {
|
|
||||||
return aNode._panelOpen;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
enumerable: true,
|
|
||||||
configurable: false
|
|
||||||
});
|
|
||||||
|
|
||||||
aBody.arguments.forEach(function(aItem) {
|
|
||||||
if (aContainer.firstChild) {
|
|
||||||
aContainer.appendChild(this.document.createTextNode(" "));
|
|
||||||
}
|
|
||||||
|
|
||||||
let text = VariablesView.getString(aItem);
|
|
||||||
let inspectable = !VariablesView.isPrimitive({ value: aItem });
|
|
||||||
|
|
||||||
if (aItem && typeof aItem != "object" || !inspectable) {
|
|
||||||
aContainer.appendChild(this.document.createTextNode(text));
|
|
||||||
|
|
||||||
if (aItem.type && aItem.type == "longString") {
|
|
||||||
let ellipsis = this.document.createElementNS(XHTML_NS, "a");
|
|
||||||
ellipsis.classList.add("longStringEllipsis");
|
|
||||||
ellipsis.textContent = l10n.getStr("longStringEllipsis");
|
|
||||||
ellipsis.href = "#";
|
|
||||||
ellipsis.draggable = false;
|
|
||||||
|
|
||||||
let formatter = function(s) '"' + s + '"';
|
|
||||||
|
|
||||||
this._addMessageLinkCallback(ellipsis,
|
|
||||||
this._longStringClick.bind(this, aMessage, aItem, formatter));
|
|
||||||
|
|
||||||
aContainer.appendChild(ellipsis);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For inspectable objects.
|
|
||||||
let elem = this.document.createElementNS(XHTML_NS, "a");
|
|
||||||
elem.setAttribute("aria-haspopup", "true");
|
|
||||||
elem.textContent = text;
|
|
||||||
elem.href = "#";
|
|
||||||
elem.draggable = false;
|
|
||||||
|
|
||||||
this._addMessageLinkCallback(elem,
|
|
||||||
this._consoleLogClick.bind(this, elem, aItem));
|
|
||||||
|
|
||||||
aContainer.appendChild(elem);
|
|
||||||
}, this);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Click event handler for the ellipsis shown immediately after a long string.
|
|
||||||
* This method retrieves the full string and updates the console output to
|
|
||||||
* show it.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param nsIDOMElement aMessage
|
|
||||||
* The message element.
|
|
||||||
* @param object aActor
|
|
||||||
* The LongStringActor instance we work with.
|
|
||||||
* @param [function] aFormatter
|
|
||||||
* Optional function you can use to format the string received from the
|
|
||||||
* server, before being displayed in the console.
|
|
||||||
* @param nsIDOMElement aEllipsis
|
|
||||||
* The DOM element the user can click on to expand the string.
|
|
||||||
*/
|
|
||||||
_longStringClick:
|
|
||||||
function WCF__longStringClick(aMessage, aActor, aFormatter, aEllipsis)
|
|
||||||
{
|
|
||||||
if (!aFormatter) {
|
|
||||||
aFormatter = function(s) s;
|
|
||||||
}
|
|
||||||
|
|
||||||
let longString = this.webConsoleClient.longString(aActor);
|
|
||||||
let toIndex = Math.min(longString.length, MAX_LONG_STRING_LENGTH);
|
|
||||||
longString.substring(longString.initial.length, toIndex,
|
|
||||||
function WCF__onSubstring(aResponse) {
|
|
||||||
if (aResponse.error) {
|
|
||||||
Cu.reportError("WCF__longStringClick substring failure: " +
|
|
||||||
aResponse.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let node = aEllipsis.previousSibling;
|
|
||||||
node.textContent = aFormatter(longString.initial + aResponse.substring);
|
|
||||||
aEllipsis.parentNode.removeChild(aEllipsis);
|
|
||||||
|
|
||||||
if (aMessage.category == CATEGORY_WEBDEV ||
|
|
||||||
aMessage.category == CATEGORY_OUTPUT) {
|
|
||||||
aMessage.clipboardText = aMessage.textContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit("messages-updated", new Set([aMessage]));
|
|
||||||
|
|
||||||
if (toIndex != longString.length) {
|
|
||||||
this.logWarningAboutStringTooLong();
|
|
||||||
}
|
|
||||||
}.bind(this));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the anchor that displays the textual location of an incoming
|
* Creates the anchor that displays the textual location of an incoming
|
||||||
* message.
|
* message.
|
||||||
@ -2807,7 +2671,7 @@ WebConsoleFrame.prototype = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
aCallback(this, aEvent);
|
aCallback.call(this, aEvent);
|
||||||
}, false);
|
}, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -3196,8 +3060,8 @@ JSTerm.prototype = {
|
|||||||
* The JavaScript evaluation response handler.
|
* The JavaScript evaluation response handler.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param nsIDOMElement [aAfterNode]
|
* @param object [aAfterMessage]
|
||||||
* Optional DOM element after which the evaluation result will be
|
* Optional message after which the evaluation result will be
|
||||||
* inserted.
|
* inserted.
|
||||||
* @param function [aCallback]
|
* @param function [aCallback]
|
||||||
* Optional function to invoke when the evaluation result is added to
|
* Optional function to invoke when the evaluation result is added to
|
||||||
@ -3206,7 +3070,7 @@ JSTerm.prototype = {
|
|||||||
* The message received from the server.
|
* The message received from the server.
|
||||||
*/
|
*/
|
||||||
_executeResultCallback:
|
_executeResultCallback:
|
||||||
function JST__executeResultCallback(aAfterNode, aCallback, aResponse)
|
function JST__executeResultCallback(aAfterMessage, aCallback, aResponse)
|
||||||
{
|
{
|
||||||
if (!this.hud) {
|
if (!this.hud) {
|
||||||
return;
|
return;
|
||||||
@ -3218,13 +3082,8 @@ JSTerm.prototype = {
|
|||||||
}
|
}
|
||||||
let errorMessage = aResponse.exceptionMessage;
|
let errorMessage = aResponse.exceptionMessage;
|
||||||
let result = aResponse.result;
|
let result = aResponse.result;
|
||||||
let inspectable = false;
|
|
||||||
if (result && !VariablesView.isPrimitive({ value: result })) {
|
|
||||||
inspectable = true;
|
|
||||||
}
|
|
||||||
let helperResult = aResponse.helperResult;
|
let helperResult = aResponse.helperResult;
|
||||||
let helperHasRawOutput = !!(helperResult || {}).rawOutput;
|
let helperHasRawOutput = !!(helperResult || {}).rawOutput;
|
||||||
let resultString = VariablesView.getString(result);
|
|
||||||
|
|
||||||
if (helperResult && helperResult.type) {
|
if (helperResult && helperResult.type) {
|
||||||
switch (helperResult.type) {
|
switch (helperResult.type) {
|
||||||
@ -3232,11 +3091,11 @@ JSTerm.prototype = {
|
|||||||
this.clearOutput();
|
this.clearOutput();
|
||||||
break;
|
break;
|
||||||
case "inspectObject":
|
case "inspectObject":
|
||||||
if (aAfterNode) {
|
if (aAfterMessage) {
|
||||||
if (!aAfterNode._objectActors) {
|
if (!aAfterMessage._objectActors) {
|
||||||
aAfterNode._objectActors = new Set();
|
aAfterMessage._objectActors = new Set();
|
||||||
}
|
}
|
||||||
aAfterNode._objectActors.add(helperResult.object.actor);
|
aAfterMessage._objectActors.add(helperResult.object.actor);
|
||||||
}
|
}
|
||||||
this.openVariablesView({
|
this.openVariablesView({
|
||||||
label: VariablesView.getString(helperResult.object),
|
label: VariablesView.getString(helperResult.object),
|
||||||
@ -3265,26 +3124,13 @@ JSTerm.prototype = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let node;
|
let msg = new Messages.JavaScriptEvalOutput(aResponse, errorMessage);
|
||||||
|
this.hud.output.addMessage(msg);
|
||||||
if (errorMessage) {
|
|
||||||
node = this.writeOutput(errorMessage, CATEGORY_OUTPUT, SEVERITY_ERROR,
|
|
||||||
aAfterNode, aResponse.timestamp);
|
|
||||||
}
|
|
||||||
else if (inspectable) {
|
|
||||||
node = this.writeOutputJS(resultString,
|
|
||||||
this._evalOutputClick.bind(this, aResponse),
|
|
||||||
aAfterNode, aResponse.timestamp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
node = this.writeOutput(resultString, CATEGORY_OUTPUT, SEVERITY_LOG,
|
|
||||||
aAfterNode, aResponse.timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aCallback) {
|
if (aCallback) {
|
||||||
let oldFlushCallback = this.hud._flushCallback;
|
let oldFlushCallback = this.hud._flushCallback;
|
||||||
this.hud._flushCallback = () => {
|
this.hud._flushCallback = () => {
|
||||||
aCallback(node);
|
aCallback(msg.element);
|
||||||
if (oldFlushCallback) {
|
if (oldFlushCallback) {
|
||||||
oldFlushCallback();
|
oldFlushCallback();
|
||||||
this.hud._flushCallback = oldFlushCallback;
|
this.hud._flushCallback = oldFlushCallback;
|
||||||
@ -3295,36 +3141,15 @@ JSTerm.prototype = {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
node._objectActors = new Set();
|
msg._afterMessage = aAfterMessage;
|
||||||
|
msg._objectActors = new Set();
|
||||||
|
|
||||||
let error = aResponse.exception;
|
if (WebConsoleUtils.isActorGrip(aResponse.exception)) {
|
||||||
if (WebConsoleUtils.isActorGrip(error)) {
|
msg._objectActors.add(aResponse.exception.actor);
|
||||||
node._objectActors.add(error.actor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WebConsoleUtils.isActorGrip(result)) {
|
if (WebConsoleUtils.isActorGrip(result)) {
|
||||||
node._objectActors.add(result.actor);
|
msg._objectActors.add(result.actor);
|
||||||
|
|
||||||
if (result.type == "longString") {
|
|
||||||
// Add an ellipsis to expand the short string if the object is not
|
|
||||||
// inspectable.
|
|
||||||
|
|
||||||
let body = node.getElementsByClassName("body")[0];
|
|
||||||
let ellipsis = this.hud.document.createElementNS(XHTML_NS, "a");
|
|
||||||
ellipsis.classList.add("longStringEllipsis");
|
|
||||||
ellipsis.textContent = l10n.getStr("longStringEllipsis");
|
|
||||||
ellipsis.href = "#";
|
|
||||||
ellipsis.draggable = false;
|
|
||||||
|
|
||||||
let formatter = function(s) '"' + s + '"';
|
|
||||||
let onclick = this.hud._longStringClick.bind(this.hud, node, result,
|
|
||||||
formatter);
|
|
||||||
this.hud._addMessageLinkCallback(ellipsis, onclick);
|
|
||||||
|
|
||||||
body.appendChild(ellipsis);
|
|
||||||
|
|
||||||
node.clipboardText += " " + ellipsis.textContent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -3345,8 +3170,12 @@ JSTerm.prototype = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = this.writeOutput(aExecuteString, CATEGORY_INPUT, SEVERITY_LOG);
|
let message = new Messages.Simple(aExecuteString, {
|
||||||
let onResult = this._executeResultCallback.bind(this, node, aCallback);
|
category: "input",
|
||||||
|
severity: "log",
|
||||||
|
});
|
||||||
|
this.hud.output.addMessage(message);
|
||||||
|
let onResult = this._executeResultCallback.bind(this, message, aCallback);
|
||||||
|
|
||||||
let options = { frame: this.SELECTED_FRAME };
|
let options = { frame: this.SELECTED_FRAME };
|
||||||
this.requestEvaluation(aExecuteString, options).then(onResult, onResult);
|
this.requestEvaluation(aExecuteString, options).then(onResult, onResult);
|
||||||
@ -3782,14 +3611,16 @@ JSTerm.prototype = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let exception = aResponse.exception;
|
if (aResponse.exceptionMessage) {
|
||||||
if (exception) {
|
let message = new Messages.Simple(aResponse.exceptionMessage, {
|
||||||
let node = this.writeOutput(aResponse.exceptionMessage,
|
category: "output",
|
||||||
CATEGORY_OUTPUT, SEVERITY_ERROR,
|
severity: "error",
|
||||||
null, aResponse.timestamp);
|
timestamp: aResponse.timestamp,
|
||||||
node._objectActors = new Set();
|
});
|
||||||
if (WebConsoleUtils.isActorGrip(exception)) {
|
this.hud.output.addMessage(message);
|
||||||
node._objectActors.add(exception.actor);
|
message._objectActors = new Set();
|
||||||
|
if (WebConsoleUtils.isActorGrip(aResponse.exception)) {
|
||||||
|
message._objectActors.add(aResponse.exception.actor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3810,74 +3641,6 @@ JSTerm.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a JS object to the JSTerm outputNode.
|
|
||||||
*
|
|
||||||
* @param string aOutputMessage
|
|
||||||
* The message to display.
|
|
||||||
* @param function [aCallback]
|
|
||||||
* Optional function to invoke when users click the message.
|
|
||||||
* @param nsIDOMNode [aNodeAfter]
|
|
||||||
* Optional DOM node after which you want to insert the new message.
|
|
||||||
* This is used when execution results need to be inserted immediately
|
|
||||||
* after the user input.
|
|
||||||
* @param number [aTimestamp]
|
|
||||||
* Optional timestamp to show for the output message (millisconds since
|
|
||||||
* the UNIX epoch). If no timestamp is provided then Date.now() is
|
|
||||||
* used.
|
|
||||||
* @return nsIDOMNode
|
|
||||||
* The new message node.
|
|
||||||
*/
|
|
||||||
writeOutputJS:
|
|
||||||
function JST_writeOutputJS(aOutputMessage, aCallback, aNodeAfter, aTimestamp)
|
|
||||||
{
|
|
||||||
let link = null;
|
|
||||||
if (aCallback) {
|
|
||||||
link = this.hud.document.createElementNS(XHTML_NS, "a");
|
|
||||||
link.setAttribute("aria-haspopup", true);
|
|
||||||
link.textContent = aOutputMessage;
|
|
||||||
link.href = "#";
|
|
||||||
link.draggable = false;
|
|
||||||
this.hud._addMessageLinkCallback(link, aCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.writeOutput(link || aOutputMessage, CATEGORY_OUTPUT,
|
|
||||||
SEVERITY_LOG, aNodeAfter, aTimestamp);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a message to the HUD that originates from the interactive
|
|
||||||
* JavaScript console.
|
|
||||||
*
|
|
||||||
* @param nsIDOMNode|string aOutputMessage
|
|
||||||
* The message to display.
|
|
||||||
* @param number aCategory
|
|
||||||
* The category of message: one of the CATEGORY_ constants.
|
|
||||||
* @param number aSeverity
|
|
||||||
* The severity of message: one of the SEVERITY_ constants.
|
|
||||||
* @param nsIDOMNode [aNodeAfter]
|
|
||||||
* Optional DOM node after which you want to insert the new message.
|
|
||||||
* This is used when execution results need to be inserted immediately
|
|
||||||
* after the user input.
|
|
||||||
* @param number [aTimestamp]
|
|
||||||
* Optional timestamp to show for the output message (millisconds since
|
|
||||||
* the UNIX epoch). If no timestamp is provided then Date.now() is
|
|
||||||
* used.
|
|
||||||
* @return nsIDOMNode
|
|
||||||
* The new message node.
|
|
||||||
*/
|
|
||||||
writeOutput:
|
|
||||||
function JST_writeOutput(aOutputMessage, aCategory, aSeverity, aNodeAfter,
|
|
||||||
aTimestamp)
|
|
||||||
{
|
|
||||||
let node = this.hud.createMessageNode(aCategory, aSeverity, aOutputMessage,
|
|
||||||
null, null, null, null, aTimestamp);
|
|
||||||
node._outputAfterNode = aNodeAfter;
|
|
||||||
this.hud.outputMessage(aCategory, node);
|
|
||||||
return node;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the Web Console output.
|
* Clear the Web Console output.
|
||||||
*
|
*
|
||||||
@ -4562,21 +4325,6 @@ JSTerm.prototype = {
|
|||||||
this.completeNode.value = prefix + aSuffix;
|
this.completeNode.value = prefix + aSuffix;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* The click event handler for evaluation results in the output.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param object aResponse
|
|
||||||
* The JavaScript evaluation response received from the server.
|
|
||||||
*/
|
|
||||||
_evalOutputClick: function JST__evalOutputClick(aResponse)
|
|
||||||
{
|
|
||||||
this.openVariablesView({
|
|
||||||
label: VariablesView.getString(aResponse.result),
|
|
||||||
objectActor: aResponse.result,
|
|
||||||
autofocus: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the sidebar.
|
* Destroy the sidebar.
|
||||||
|
@ -540,8 +540,6 @@
|
|||||||
<property name="matchCount" readonly="true" onget="return this.input.controller.matchCount;"/>
|
<property name="matchCount" readonly="true" onget="return this.input.controller.matchCount;"/>
|
||||||
<property name="popupOpen" readonly="true" onget="return !this.hidden"/>
|
<property name="popupOpen" readonly="true" onget="return !this.hidden"/>
|
||||||
<property name="overrideValue" readonly="true" onget="return null;"/>
|
<property name="overrideValue" readonly="true" onget="return null;"/>
|
||||||
<!-- Alias of popupOpen, for compatibility with global/content/bindings/autocomplete.xml -->
|
|
||||||
<property name="mPopupOpen" readonly="true" onget="return this.popupOpen"/>
|
|
||||||
|
|
||||||
<property name="selectedItem">
|
<property name="selectedItem">
|
||||||
<getter>
|
<getter>
|
||||||
@ -551,7 +549,9 @@
|
|||||||
</getter>
|
</getter>
|
||||||
<setter>
|
<setter>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
return this._isGridBound(this._results) ? this._results.selectedItem : null;
|
if (this._isGridBound(this._results)) {
|
||||||
|
this._results.selectedItem = val;
|
||||||
|
}
|
||||||
]]>
|
]]>
|
||||||
</setter>
|
</setter>
|
||||||
</property>
|
</property>
|
||||||
@ -564,7 +564,9 @@
|
|||||||
</getter>
|
</getter>
|
||||||
<setter>
|
<setter>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
return this._isGridBound(this._results) ? this._results.selectedIndex : -1;
|
if (this._isGridBound(this._results)) {
|
||||||
|
this._results.selectedIndex = val;
|
||||||
|
}
|
||||||
]]>
|
]]>
|
||||||
</setter>
|
</setter>
|
||||||
</property>
|
</property>
|
||||||
|
@ -369,6 +369,10 @@ gTests.push({
|
|||||||
|
|
||||||
EventUtils.synthesizeKey("VK_UP", {}, window);
|
EventUtils.synthesizeKey("VK_UP", {}, window);
|
||||||
is(gEdit.popup._results.selectedIndex, 0, "Pressing arrow up selects first item.");
|
is(gEdit.popup._results.selectedIndex, 0, "Pressing arrow up selects first item.");
|
||||||
|
|
||||||
|
EventUtils.synthesizeKey("VK_BACK_SPACE", {}, window);
|
||||||
|
yield waitForEvent(document.getElementById("urlbar-edit"), "input");
|
||||||
|
is(gEdit.popup._results.selectedIndex, -1, "backspace: autocomplete de-selected");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.5 KiB |
@ -118,6 +118,11 @@ this.UITour = {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "hideMenu": {
|
||||||
|
this.hideMenu(window, data.name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case "startUrlbarCapture": {
|
case "startUrlbarCapture": {
|
||||||
if (typeof data.text != "string" || !data.text ||
|
if (typeof data.text != "string" || !data.text ||
|
||||||
typeof data.url != "string" || !data.url) {
|
typeof data.url != "string" || !data.url) {
|
||||||
@ -393,6 +398,19 @@ this.UITour = {
|
|||||||
openMenuButton("bookmarks-menu-button");
|
openMenuButton("bookmarks-menu-button");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
hideMenu: function(aWindow, aMenuName) {
|
||||||
|
function closeMenuButton(aId) {
|
||||||
|
let menuBtn = aWindow.document.getElementById(aId);
|
||||||
|
if (menuBtn && menuBtn.boxObject)
|
||||||
|
menuBtn.boxObject.QueryInterface(Ci.nsIMenuBoxObject).openMenu(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aMenuName == "appmenu")
|
||||||
|
aWindow.PanelUI.hide();
|
||||||
|
else if (aMenuName == "bookmarks")
|
||||||
|
closeMenuButton("bookmarks-menu-button");
|
||||||
|
},
|
||||||
|
|
||||||
startUrlbarCapture: function(aWindow, aExpectedText, aUrl) {
|
startUrlbarCapture: function(aWindow, aExpectedText, aUrl) {
|
||||||
let urlbar = aWindow.document.getElementById("urlbar");
|
let urlbar = aWindow.document.getElementById("urlbar");
|
||||||
this.urlbarCapture.set(aWindow, {
|
this.urlbarCapture.set(aWindow, {
|
||||||
|
@ -233,6 +233,18 @@ let tests = [
|
|||||||
gContentAPI.addPinnedTab();
|
gContentAPI.addPinnedTab();
|
||||||
is(gBrowser.tabs[1].pinned, false, "After multiple calls of addPinnedTab, should still only have one pinned tab");
|
is(gBrowser.tabs[1].pinned, false, "After multiple calls of addPinnedTab, should still only have one pinned tab");
|
||||||
|
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
function test_menu(done) {
|
||||||
|
let bookmarksMenuButton = document.getElementById("bookmarks-menu-button");
|
||||||
|
ise(bookmarksMenuButton.open, false, "Menu should initially be closed");
|
||||||
|
|
||||||
|
gContentAPI.showMenu("bookmarks");
|
||||||
|
ise(bookmarksMenuButton.open, true, "Menu should be shown after showMenu()");
|
||||||
|
|
||||||
|
gContentAPI.hideMenu("bookmarks");
|
||||||
|
ise(bookmarksMenuButton.open, false, "Menu should be closed after hideMenu()");
|
||||||
|
|
||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -112,4 +112,10 @@ if (typeof Mozilla == 'undefined') {
|
|||||||
name: name
|
name: name
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Mozilla.UITour.hideMenu = function(name) {
|
||||||
|
_sendEvent('hideMenu', {
|
||||||
|
name: name
|
||||||
|
});
|
||||||
|
};
|
||||||
})();
|
})();
|
@ -682,7 +682,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
|||||||
-moz-margin-start: -4px;
|
-moz-margin-start: -4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#urlbar-search-splitter + #urlbar-container > #urlbar-wrapper > #urlbar,
|
|
||||||
#urlbar-search-splitter + #search-container > #searchbar > .searchbar-textbox {
|
#urlbar-search-splitter + #search-container > #searchbar > .searchbar-textbox {
|
||||||
-moz-margin-start: 0;
|
-moz-margin-start: 0;
|
||||||
}
|
}
|
||||||
|
@ -2549,6 +2549,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||||||
min-height: @tabHeight@;
|
min-height: @tabHeight@;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#main-window:not(:-moz-any([privatebrowsingmode=temporary],[customizing])) #navigator-toolbox[inFullscreen]:not(:-moz-lwtheme)::before,
|
||||||
#main-window:not(:-moz-any([privatebrowsingmode=temporary],[customizing],[tabsintitlebar])) #navigator-toolbox:not(:-moz-lwtheme)::before {
|
#main-window:not(:-moz-any([privatebrowsingmode=temporary],[customizing],[tabsintitlebar])) #navigator-toolbox:not(:-moz-lwtheme)::before {
|
||||||
/* We want the titlebar to be unified, but we still want to be able
|
/* We want the titlebar to be unified, but we still want to be able
|
||||||
* to give #TabsToolbar a background. So we can't set -moz-appearance:
|
* to give #TabsToolbar a background. So we can't set -moz-appearance:
|
||||||
|
@ -940,7 +940,6 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
#urlbar-search-splitter + #urlbar-container > #urlbar-wrapper > #urlbar,
|
|
||||||
#urlbar-search-splitter + #search-container > #searchbar > .searchbar-textbox {
|
#urlbar-search-splitter + #search-container > #searchbar > .searchbar-textbox {
|
||||||
-moz-margin-start: 0;
|
-moz-margin-start: 0;
|
||||||
}
|
}
|
||||||
|
@ -5,19 +5,31 @@
|
|||||||
####################
|
####################
|
||||||
|
|
||||||
{
|
{
|
||||||
PR_SetEnv requires its argument to be leaked, but does not appear on stacks. (See bug 793534 and see bug 793549.)
|
PR_SetEnv requires its argument to be leaked, but does not appear on stacks. (See bug 793534.)
|
||||||
Memcheck:Leak
|
Memcheck:Leak
|
||||||
...
|
...
|
||||||
fun:_ZL9SaveToEnvPKc
|
fun:_ZL9SaveToEnvPKc
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PR_SetEnv requires its argument to be leaked, but does not appear on stacks. (See bug 793534 and see bug 793549.)
|
PR_SetEnv requires its argument to be leaked, but does not appear on stacks. (See bug 793549.)
|
||||||
Memcheck:Leak
|
Memcheck:Leak
|
||||||
...
|
...
|
||||||
fun:_ZL13SaveWordToEnvPKcRK19nsACString_internal
|
fun:_ZL13SaveWordToEnvPKcRK19nsACString_internal
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
PR_SetEnv requires its argument to be leaked, but does not appear on stacks. (See bug 944133.)
|
||||||
|
Memcheck:Leak
|
||||||
|
...
|
||||||
|
fun:_ZN13CrashReporter14SetRestartArgsEiPPc
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
####################################
|
||||||
|
# Leaks in third party libraries #
|
||||||
|
####################################
|
||||||
|
|
||||||
{
|
{
|
||||||
See bug 793535
|
See bug 793535
|
||||||
Memcheck:Leak
|
Memcheck:Leak
|
||||||
@ -47,245 +59,246 @@
|
|||||||
# Other leaks #
|
# Other leaks #
|
||||||
#################
|
#################
|
||||||
|
|
||||||
{
|
# XXX: temporary disabling
|
||||||
Bug 793532
|
#{
|
||||||
Memcheck:Leak
|
# Bug 793532
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:_ZN8JSObject25allocateSlowArrayElementsEP9JSContext
|
# fun:malloc
|
||||||
...
|
# fun:_ZN8JSObject25allocateSlowArrayElementsEP9JSContext
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 793533 (all 64-bit systems)
|
#{
|
||||||
Memcheck:Leak
|
# Bug 793533 (all 64-bit systems)
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:moz_xmalloc
|
# fun:malloc
|
||||||
fun:_ZN3xpc18CreateGlobalObjectEP9JSContextP7JSClassP12nsIPrincipalbPP8JSObjectPP13JSCompartment
|
# fun:moz_xmalloc
|
||||||
...
|
# fun:_ZN3xpc18CreateGlobalObjectEP9JSContextP7JSClassP12nsIPrincipalbPP8JSObjectPP13JSCompartment
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 793533 (all 64-bit systems)
|
#{
|
||||||
Memcheck:Leak
|
# Bug 793533 (all 64-bit systems)
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:moz_xmalloc
|
# fun:malloc
|
||||||
fun:_ZN3xpc18CreateGlobalObjectEP9JSContextP7JSClassP12nsIPrincipalm
|
# fun:moz_xmalloc
|
||||||
...
|
# fun:_ZN3xpc18CreateGlobalObjectEP9JSContextP7JSClassP12nsIPrincipalm
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 793536 (all 64-bit systems)
|
#{
|
||||||
Memcheck:Leak
|
# Bug 793536 (all 64-bit systems)
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:moz_xmalloc
|
# fun:malloc
|
||||||
fun:_ZNSt11_Deque_baseIN11MessageLoop11PendingTaskESaIS1_EE17_M_initialize_mapEm
|
# fun:moz_xmalloc
|
||||||
...
|
# fun:_ZNSt11_Deque_baseIN11MessageLoop11PendingTaskESaIS1_EE17_M_initialize_mapEm
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 793536 (all 32-bit systems)
|
#{
|
||||||
Memcheck:Leak
|
# Bug 793536 (all 32-bit systems)
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:moz_xmalloc
|
# fun:malloc
|
||||||
fun:_ZNSt11_Deque_baseIN11MessageLoop11PendingTaskESaIS1_EE17_M_initialize_mapEj
|
# fun:moz_xmalloc
|
||||||
...
|
# fun:_ZNSt11_Deque_baseIN11MessageLoop11PendingTaskESaIS1_EE17_M_initialize_mapEj
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 793548
|
#{
|
||||||
Memcheck:Leak
|
# Bug 793548
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
...
|
# fun:malloc
|
||||||
fun:_Z12ToNewCStringRK19nsACString_internal
|
# ...
|
||||||
fun:_ZN13CrashReporter14SetupExtraDataEP7nsIFileRK19nsACString_internal
|
# fun:_Z12ToNewCStringRK19nsACString_internal
|
||||||
...
|
# fun:_ZN13CrashReporter14SetupExtraDataEP7nsIFileRK19nsACString_internal
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 793608
|
#{
|
||||||
Memcheck:Leak
|
# Bug 793608
|
||||||
...
|
# Memcheck:Leak
|
||||||
fun:gaih_inet
|
# ...
|
||||||
fun:getaddrinfo
|
# fun:gaih_inet
|
||||||
fun:PR_GetAddrInfoByName
|
# fun:getaddrinfo
|
||||||
fun:_ZN14nsHostResolver10ThreadFuncEPv
|
# fun:PR_GetAddrInfoByName
|
||||||
fun:_pt_root
|
# fun:_ZN14nsHostResolver10ThreadFuncEPv
|
||||||
fun:start_thread
|
# fun:_pt_root
|
||||||
fun:clone
|
# fun:start_thread
|
||||||
}
|
# fun:clone
|
||||||
{
|
#}
|
||||||
Bug 793608 variant
|
#{
|
||||||
Memcheck:Leak
|
# Bug 793608 variant
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:__libc_res_nsend
|
# fun:malloc
|
||||||
fun:__libc_res_nquery
|
# fun:__libc_res_nsend
|
||||||
fun:__libc_res_nquerydomain
|
# fun:__libc_res_nquery
|
||||||
fun:__libc_res_nsearch
|
# fun:__libc_res_nquerydomain
|
||||||
obj:*
|
# fun:__libc_res_nsearch
|
||||||
...
|
# obj:*
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 793608 variant 2
|
#{
|
||||||
Memcheck:Leak
|
# Bug 793608 variant 2
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:make_request
|
# fun:malloc
|
||||||
fun:__check_pf
|
# fun:make_request
|
||||||
fun:getaddrinfo
|
# fun:__check_pf
|
||||||
fun:PR_GetAddrInfoByName
|
# fun:getaddrinfo
|
||||||
fun:_ZN14nsHostResolver10ThreadFuncEPv
|
# fun:PR_GetAddrInfoByName
|
||||||
fun:_pt_root
|
# fun:_ZN14nsHostResolver10ThreadFuncEPv
|
||||||
fun:start_thread
|
# fun:_pt_root
|
||||||
fun:clone
|
# fun:start_thread
|
||||||
}
|
# fun:clone
|
||||||
{
|
#}
|
||||||
Bug 793615
|
#{
|
||||||
Memcheck:Leak
|
# Bug 793615
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:sqlite3MemMalloc
|
# fun:malloc
|
||||||
...
|
# fun:sqlite3MemMalloc
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 794350
|
#{
|
||||||
Memcheck:Leak
|
# Bug 794350
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:moz_xmalloc
|
# fun:malloc
|
||||||
fun:_ZN11MessageLoopC1ENS_4TypeE
|
# fun:moz_xmalloc
|
||||||
fun:_ZN4base6Thread10ThreadMainEv
|
# fun:_ZN11MessageLoopC1ENS_4TypeE
|
||||||
fun:_ZL10ThreadFuncPv
|
# fun:_ZN4base6Thread10ThreadMainEv
|
||||||
fun:start_thread
|
# fun:_ZL10ThreadFuncPv
|
||||||
fun:clone
|
# fun:start_thread
|
||||||
}
|
# fun:clone
|
||||||
{
|
#}
|
||||||
Bug 794354
|
#{
|
||||||
Memcheck:Leak
|
# Bug 794354
|
||||||
...
|
# Memcheck:Leak
|
||||||
fun:_ZN7mozilla12safebrowsing10Classifier12ApplyUpdatesEP8nsTArrayIPNS0_11TableUpdateE24nsTArrayDefaultAllocatorE
|
# ...
|
||||||
fun:_ZN30nsUrlClassifierDBServiceWorker11ApplyUpdateEv
|
# fun:_ZN7mozilla12safebrowsing10Classifier12ApplyUpdatesEP8nsTArrayIPNS0_11TableUpdateE24nsTArrayDefaultAllocatorE
|
||||||
fun:_ZN30nsUrlClassifierDBServiceWorker12FinishUpdateEv
|
# fun:_ZN30nsUrlClassifierDBServiceWorker11ApplyUpdateEv
|
||||||
...
|
# fun:_ZN30nsUrlClassifierDBServiceWorker12FinishUpdateEv
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 794358
|
#{
|
||||||
Memcheck:Leak
|
# Bug 794358
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
...
|
# fun:malloc
|
||||||
fun:PK11_InitPin
|
# ...
|
||||||
fun:_ZN11nsPK11Token12InitPasswordEPKt
|
# fun:PK11_InitPin
|
||||||
...
|
# fun:_ZN11nsPK11Token12InitPasswordEPKt
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 794369
|
#{
|
||||||
Memcheck:Leak
|
# Bug 794369
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:moz_xmalloc
|
# fun:malloc
|
||||||
fun:_ZN20mozJSComponentLoader10LoadModuleERN7mozilla12FileLocationE
|
# fun:moz_xmalloc
|
||||||
...
|
# fun:_ZN20mozJSComponentLoader10LoadModuleERN7mozilla12FileLocationE
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 794370
|
#{
|
||||||
Memcheck:Leak
|
# Bug 794370
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:moz_xmalloc
|
# fun:malloc
|
||||||
fun:_ZN22nsComponentManagerImpl15RegisterFactoryERK4nsIDPKcS4_P10nsIFactory
|
# fun:moz_xmalloc
|
||||||
...
|
# fun:_ZN22nsComponentManagerImpl15RegisterFactoryERK4nsIDPKcS4_P10nsIFactory
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 794372
|
#{
|
||||||
Memcheck:Leak
|
# Bug 794372
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:moz_xmalloc
|
# fun:malloc
|
||||||
fun:_ZN22nsComponentManagerImpl16RegisterCIDEntryEPKN7mozilla6Module8CIDEntryEPNS_11KnownModuleE
|
# fun:moz_xmalloc
|
||||||
...
|
# fun:_ZN22nsComponentManagerImpl16RegisterCIDEntryEPKN7mozilla6Module8CIDEntryEPNS_11KnownModuleE
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 794372
|
#{
|
||||||
Memcheck:Leak
|
# Bug 794372
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:moz_xmalloc
|
# fun:malloc
|
||||||
fun:_ZN22nsComponentManagerImpl22RegisterCIDEntryLockedEPKN7mozilla6Module8CIDEntryEPNS_11KnownModuleE
|
# fun:moz_xmalloc
|
||||||
...
|
# fun:_ZN22nsComponentManagerImpl22RegisterCIDEntryLockedEPKN7mozilla6Module8CIDEntryEPNS_11KnownModuleE
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 794374
|
#{
|
||||||
Memcheck:Leak
|
# Bug 794374
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:moz_xmalloc
|
# fun:malloc
|
||||||
fun:_ZN22nsComponentManagerImpl17ManifestComponentERNS_25ManifestProcessingContextEiPKPc
|
# fun:moz_xmalloc
|
||||||
...
|
# fun:_ZN22nsComponentManagerImpl17ManifestComponentERNS_25ManifestProcessingContextEiPKPc
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 803386
|
#{
|
||||||
Memcheck:Free
|
# Bug 803386
|
||||||
fun:_ZdlPv
|
# Memcheck:Free
|
||||||
fun:_ZN16SkMallocPixelRefD0Ev
|
# fun:_ZdlPv
|
||||||
fun:_ZNK8SkRefCnt16internal_disposeEv
|
# fun:_ZN16SkMallocPixelRefD0Ev
|
||||||
fun:_ZN8SkBitmap10freePixelsEv
|
# fun:_ZNK8SkRefCnt16internal_disposeEv
|
||||||
fun:_ZN8SkBitmapD1Ev
|
# fun:_ZN8SkBitmap10freePixelsEv
|
||||||
fun:_ZN7mozilla3gfx5ScaleEPhiiiS1_iiiNS0_13SurfaceFormatE
|
# fun:_ZN8SkBitmapD1Ev
|
||||||
...
|
# fun:_ZN7mozilla3gfx5ScaleEPhiiiS1_iiiNS0_13SurfaceFormatE
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 812422
|
#{
|
||||||
Memcheck:Leak
|
# Bug 812422
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:moz_xmalloc
|
# fun:malloc
|
||||||
fun:_Z22NS_NewComputedDOMStylePN7mozilla3dom7ElementERK18nsAString_internalP12nsIPresShellN18nsComputedDOMStyle9StyleTypeE
|
# fun:moz_xmalloc
|
||||||
fun:_ZN14nsGlobalWindow22GetComputedStyleHelperEP13nsIDOMElementRK18nsAString_internalbPP25nsIDOMCSSStyleDeclaration
|
# fun:_Z22NS_NewComputedDOMStylePN7mozilla3dom7ElementERK18nsAString_internalP12nsIPresShellN18nsComputedDOMStyle9StyleTypeE
|
||||||
...
|
# fun:_ZN14nsGlobalWindow22GetComputedStyleHelperEP13nsIDOMElementRK18nsAString_internalbPP25nsIDOMCSSStyleDeclaration
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 812423
|
#{
|
||||||
Memcheck:Leak
|
# Bug 812423
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:_ZN2js15ArgumentsObject6createI18CopyStackFrameArgsEEPS0_P9JSContextN2JS6HandleIP8JSScriptEENS7_IP10JSFunctionEEjRT_
|
# fun:malloc
|
||||||
fun:_ZN2js15ArgumentsObject14createExpectedEP9JSContextPNS_10StackFrameE
|
# fun:_ZN2js15ArgumentsObject6createI18CopyStackFrameArgsEEPS0_P9JSContextN2JS6HandleIP8JSScriptEENS7_IP10JSFunctionEEjRT_
|
||||||
...
|
# fun:_ZN2js15ArgumentsObject14createExpectedEP9JSContextPNS_10StackFrameE
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 812423
|
#{
|
||||||
Memcheck:Leak
|
# Bug 812423
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:_ZN2js15ArgumentsObject6createI13CopyFrameArgsEEPS0_P9JSContextN2JS6HandleIP8JSScriptEENS7_IP10JSFunctionEEjRT_
|
# fun:malloc
|
||||||
fun:_ZN2js15ArgumentsObject14createExpectedEP9JSContextNS_16AbstractFramePtrE
|
# fun:_ZN2js15ArgumentsObject6createI13CopyFrameArgsEEPS0_P9JSContextN2JS6HandleIP8JSScriptEENS7_IP10JSFunctionEEjRT_
|
||||||
...
|
# fun:_ZN2js15ArgumentsObject14createExpectedEP9JSContextNS_16AbstractFramePtrE
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 823782
|
#{
|
||||||
Memcheck:Leak
|
# Bug 823782
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
...
|
# fun:malloc
|
||||||
fun:_ZN2js6ctypes7LibraryL7DeclareEP9JSContextjPN2JS5ValueE
|
# ...
|
||||||
...
|
# fun:_ZN2js6ctypes7LibraryL7DeclareEP9JSContextjPN2JS5ValueE
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 823782
|
#{
|
||||||
Memcheck:Leak
|
# Bug 823782
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:_ZN2js6ctypes5CData6CreateEP9JSContextN2JS6HandleIP8JSObjectEES8_Pvb
|
# fun:malloc
|
||||||
...
|
# fun:_ZN2js6ctypes5CData6CreateEP9JSContextN2JS6HandleIP8JSObjectEES8_Pvb
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 823782
|
#{
|
||||||
Memcheck:Leak
|
# Bug 823782
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
...
|
# fun:malloc
|
||||||
fun:_ZN2js6ctypes10StructTypeL6CreateEP9JSContextjPN2JS5ValueE
|
# ...
|
||||||
...
|
# fun:_ZN2js6ctypes10StructTypeL6CreateEP9JSContextjPN2JS5ValueE
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 823782
|
#{
|
||||||
Memcheck:Leak
|
# Bug 823782
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
fun:_ZN2js6ctypes9Int64Base9ConstructEP9JSContextN2JS6HandleIP8JSObjectEEmb
|
# fun:malloc
|
||||||
...
|
# fun:_ZN2js6ctypes9Int64Base9ConstructEP9JSContextN2JS6HandleIP8JSObjectEEmb
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 824323
|
#{
|
||||||
Memcheck:Leak
|
# Bug 824323
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
...
|
# fun:malloc
|
||||||
fun:_ZN7mozilla3dom7workers13WorkerPrivate9DoRunLoopEP9JSContext
|
# ...
|
||||||
...
|
# fun:_ZN7mozilla3dom7workers13WorkerPrivate9DoRunLoopEP9JSContext
|
||||||
}
|
# ...
|
||||||
{
|
#}
|
||||||
Bug 874658
|
#{
|
||||||
Memcheck:Leak
|
# Bug 874658
|
||||||
fun:malloc
|
# Memcheck:Leak
|
||||||
...
|
# fun:malloc
|
||||||
fun:_Z31mozilla_sampler_register_threadPKc
|
# ...
|
||||||
...
|
# fun:_Z31mozilla_sampler_register_threadPKc
|
||||||
}
|
# ...
|
||||||
|
#}
|
||||||
|
@ -49,12 +49,13 @@
|
|||||||
obj:/lib/libgobject-2.0.so.0.2200.5
|
obj:/lib/libgobject-2.0.so.0.2200.5
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
{
|
# XXX: temporary disabling
|
||||||
Bug 850134
|
#{
|
||||||
Memcheck:Leak
|
# Bug 850134
|
||||||
fun:realloc
|
# Memcheck:Leak
|
||||||
fun:_ZN2js6VectorIyLj0ENS_15TempAllocPolicyEE13growStorageByEj
|
# fun:realloc
|
||||||
fun:_ZN2js8SCOutput5writeEy
|
# fun:_ZN2js6VectorIyLj0ENS_15TempAllocPolicyEE13growStorageByEj
|
||||||
fun:_ZN2js8SCOutput9writePairEjj
|
# fun:_ZN2js8SCOutput5writeEy
|
||||||
...
|
# fun:_ZN2js8SCOutput9writePairEjj
|
||||||
}
|
# ...
|
||||||
|
#}
|
||||||
|
@ -49,12 +49,13 @@
|
|||||||
obj:/lib64/libgobject-2.0.so.0.2200.5
|
obj:/lib64/libgobject-2.0.so.0.2200.5
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
{
|
# XXX: temporary disabling
|
||||||
Bug 850134
|
#{
|
||||||
Memcheck:Leak
|
# Bug 850134
|
||||||
fun:realloc
|
# Memcheck:Leak
|
||||||
fun:_ZN2js6VectorImLm0ENS_15TempAllocPolicyEE13growStorageByEm
|
# fun:realloc
|
||||||
fun:_ZN2js8SCOutput5writeEm
|
# fun:_ZN2js6VectorImLm0ENS_15TempAllocPolicyEE13growStorageByEm
|
||||||
fun:_ZN2js8SCOutput9writePairEjj
|
# fun:_ZN2js8SCOutput5writeEm
|
||||||
...
|
# fun:_ZN2js8SCOutput9writePairEjj
|
||||||
}
|
# ...
|
||||||
|
#}
|
||||||
|
@ -2861,51 +2861,14 @@ ContentParent::RecvAddGeolocationListener(const IPC::Principal& aPrincipal,
|
|||||||
const bool& aHighAccuracy)
|
const bool& aHighAccuracy)
|
||||||
{
|
{
|
||||||
#ifdef MOZ_CHILD_PERMISSIONS
|
#ifdef MOZ_CHILD_PERMISSIONS
|
||||||
if (Preferences::GetBool("geo.testing.ignore_ipc_principal", false) == false) {
|
if (!Preferences::GetBool("geo.testing.ignore_ipc_principal", false)) {
|
||||||
nsIPrincipal* principal = aPrincipal;
|
uint32_t permission = mozilla::CheckPermission(this, aPrincipal,
|
||||||
if (principal == nullptr) {
|
"geolocation");
|
||||||
KillHard();
|
if (permission != nsIPermissionManager::ALLOW_ACTION) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t principalAppId;
|
|
||||||
nsresult rv = principal->GetAppId(&principalAppId);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
const InfallibleTArray<PBrowserParent*>& browsers = ManagedPBrowserParent();
|
|
||||||
for (uint32_t i = 0; i < browsers.Length(); ++i) {
|
|
||||||
TabParent* tab = static_cast<TabParent*>(browsers[i]);
|
|
||||||
nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
|
|
||||||
uint32_t appId;
|
|
||||||
app->GetLocalId(&appId);
|
|
||||||
if (appId == principalAppId) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to ensure that this permission has been set.
|
|
||||||
// If it hasn't, just noop
|
|
||||||
nsCOMPtr<nsIPermissionManager> pm = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
|
||||||
if (!pm) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
|
|
||||||
rv = pm->TestPermissionFromPrincipal(principal, "geolocation", &permission);
|
|
||||||
if (NS_FAILED(rv) || permission != nsIPermissionManager::ALLOW_ACTION) {
|
|
||||||
KillHard();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* MOZ_CHILD_PERMISSIONS */
|
||||||
|
|
||||||
// To ensure no geolocation updates are skipped, we always force the
|
// To ensure no geolocation updates are skipped, we always force the
|
||||||
// creation of a new listener.
|
// creation of a new listener.
|
||||||
|
@ -1431,9 +1431,10 @@ MmsService.prototype = {
|
|||||||
* @param intermediate
|
* @param intermediate
|
||||||
* Intermediate MMS message parsed from PDU.
|
* Intermediate MMS message parsed from PDU.
|
||||||
*/
|
*/
|
||||||
convertIntermediateToSavable: function convertIntermediateToSavable(mmsConnection,
|
convertIntermediateToSavable:
|
||||||
intermediate,
|
function convertIntermediateToSavable(mmsConnection,
|
||||||
retrievalMode) {
|
intermediate,
|
||||||
|
retrievalMode) {
|
||||||
intermediate.type = "mms";
|
intermediate.type = "mms";
|
||||||
intermediate.delivery = DELIVERY_NOT_DOWNLOADED;
|
intermediate.delivery = DELIVERY_NOT_DOWNLOADED;
|
||||||
|
|
||||||
@ -1682,11 +1683,12 @@ MmsService.prototype = {
|
|||||||
/**
|
/**
|
||||||
* Callback for saveReceivedMessage.
|
* Callback for saveReceivedMessage.
|
||||||
*/
|
*/
|
||||||
saveReceivedMessageCallback: function saveReceivedMessageCallback(mmsConnection,
|
saveReceivedMessageCallback:
|
||||||
retrievalMode,
|
function saveReceivedMessageCallback(mmsConnection,
|
||||||
savableMessage,
|
retrievalMode,
|
||||||
rv,
|
savableMessage,
|
||||||
domMessage) {
|
rv,
|
||||||
|
domMessage) {
|
||||||
let success = Components.isSuccessCode(rv);
|
let success = Components.isSuccessCode(rv);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
// At this point we could send a message to content to notify the
|
// At this point we could send a message to content to notify the
|
||||||
@ -1706,21 +1708,13 @@ MmsService.prototype = {
|
|||||||
|
|
||||||
this.broadcastReceivedMessageEvent(domMessage);
|
this.broadcastReceivedMessageEvent(domMessage);
|
||||||
|
|
||||||
// In the roaming environment, we send notify response only for the
|
// To avoid costing money, we only send notify response when it's under
|
||||||
// automatic retrieval mode.
|
// the "automatic" retrieval mode or it's not in the roaming environment.
|
||||||
if ((retrievalMode !== RETRIEVAL_MODE_AUTOMATIC) &&
|
if (retrievalMode !== RETRIEVAL_MODE_AUTOMATIC &&
|
||||||
mmsConnection.isVoiceRoaming()) {
|
mmsConnection.isVoiceRoaming()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Under the "automatic" retrieval mode, for the non-active SIM, we have to
|
|
||||||
// download the MMS as if it is downloaded by the "manual" retrieval mode.
|
|
||||||
if ((retrievalMode == RETRIEVAL_MODE_AUTOMATIC ||
|
|
||||||
retrievalMode == RETRIEVAL_MODE_AUTOMATIC_HOME) &&
|
|
||||||
mmsConnection.serviceId != this.mmsDefaultServiceId) {
|
|
||||||
retrievalMode = RETRIEVAL_MODE_MANUAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RETRIEVAL_MODE_MANUAL === retrievalMode ||
|
if (RETRIEVAL_MODE_MANUAL === retrievalMode ||
|
||||||
RETRIEVAL_MODE_NEVER === retrievalMode) {
|
RETRIEVAL_MODE_NEVER === retrievalMode) {
|
||||||
let mmsStatus = RETRIEVAL_MODE_NEVER === retrievalMode
|
let mmsStatus = RETRIEVAL_MODE_NEVER === retrievalMode
|
||||||
@ -1777,17 +1771,33 @@ MmsService.prototype = {
|
|||||||
retrievalMode = Services.prefs.getCharPref(kPrefRetrievalMode);
|
retrievalMode = Services.prefs.getCharPref(kPrefRetrievalMode);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
|
// Under the "automatic"/"automatic-home" retrieval mode, we switch to
|
||||||
|
// the "manual" retrieval mode to download MMS for non-active SIM.
|
||||||
|
if ((retrievalMode == RETRIEVAL_MODE_AUTOMATIC ||
|
||||||
|
retrievalMode == RETRIEVAL_MODE_AUTOMATIC_HOME) &&
|
||||||
|
serviceId != this.mmsDefaultServiceId) {
|
||||||
|
if (DEBUG) {
|
||||||
|
debug("Switch to 'manual' mode to download MMS for non-active SIM: " +
|
||||||
|
"serviceId = " + serviceId + " doesn't equal to " +
|
||||||
|
"mmsDefaultServiceId = " + this.mmsDefaultServiceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
retrievalMode = RETRIEVAL_MODE_MANUAL;
|
||||||
|
}
|
||||||
|
|
||||||
let mmsConnection = gMmsConnections.getConnByServiceId(serviceId);
|
let mmsConnection = gMmsConnections.getConnByServiceId(serviceId);
|
||||||
|
|
||||||
let savableMessage = this.convertIntermediateToSavable(mmsConnection,
|
let savableMessage = this.convertIntermediateToSavable(mmsConnection,
|
||||||
notification,
|
notification,
|
||||||
retrievalMode);
|
retrievalMode);
|
||||||
|
|
||||||
gMobileMessageDatabaseService
|
gMobileMessageDatabaseService
|
||||||
.saveReceivedMessage(savableMessage,
|
.saveReceivedMessage(savableMessage,
|
||||||
this.saveReceivedMessageCallback.bind(this,
|
this.saveReceivedMessageCallback
|
||||||
mmsConnection,
|
.bind(this,
|
||||||
retrievalMode,
|
mmsConnection,
|
||||||
savableMessage));
|
retrievalMode,
|
||||||
|
savableMessage));
|
||||||
}).bind(this));
|
}).bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -2857,7 +2857,7 @@ let RIL = {
|
|||||||
ComprehensionTlvHelper.writeLength(
|
ComprehensionTlvHelper.writeLength(
|
||||||
Math.ceil(options.address.length/2) + 1 // address BCD + TON
|
Math.ceil(options.address.length/2) + 1 // address BCD + TON
|
||||||
);
|
);
|
||||||
GsmPDUHelper.writeDiallingNumber(options.address);
|
ICCPDUHelper.writeDiallingNumber(options.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cause of disconnection.
|
// Cause of disconnection.
|
||||||
@ -6684,96 +6684,6 @@ let GsmPDUHelper = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Read GSM 8-bit unpacked octets,
|
|
||||||
* which are SMS default 7-bit alphabets with bit 8 set to 0.
|
|
||||||
*
|
|
||||||
* @param numOctets
|
|
||||||
* Number of octets to be read.
|
|
||||||
*/
|
|
||||||
read8BitUnpackedToString: function read8BitUnpackedToString(numOctets) {
|
|
||||||
let ret = "";
|
|
||||||
let escapeFound = false;
|
|
||||||
let i;
|
|
||||||
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
|
||||||
const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
|
||||||
|
|
||||||
for(i = 0; i < numOctets; i++) {
|
|
||||||
let octet = this.readHexOctet();
|
|
||||||
if (octet == 0xff) {
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (escapeFound) {
|
|
||||||
escapeFound = false;
|
|
||||||
if (octet == PDU_NL_EXTENDED_ESCAPE) {
|
|
||||||
// According to 3GPP TS 23.038, section 6.2.1.1, NOTE 1, "On
|
|
||||||
// receipt of this code, a receiving entity shall display a space
|
|
||||||
// until another extensiion table is defined."
|
|
||||||
ret += " ";
|
|
||||||
} else if (octet == PDU_NL_RESERVED_CONTROL) {
|
|
||||||
// According to 3GPP TS 23.038 B.2, "This code represents a control
|
|
||||||
// character and therefore must not be used for language specific
|
|
||||||
// characters."
|
|
||||||
ret += " ";
|
|
||||||
} else {
|
|
||||||
ret += langShiftTable[octet];
|
|
||||||
}
|
|
||||||
} else if (octet == PDU_NL_EXTENDED_ESCAPE) {
|
|
||||||
escapeFound = true;
|
|
||||||
} else {
|
|
||||||
ret += langTable[octet];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE);
|
|
||||||
return ret;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write GSM 8-bit unpacked octets.
|
|
||||||
*
|
|
||||||
* @param numOctets Number of total octets to be writen, including trailing
|
|
||||||
* 0xff.
|
|
||||||
* @param str String to be written. Could be null.
|
|
||||||
*/
|
|
||||||
writeStringTo8BitUnpacked: function writeStringTo8BitUnpacked(numOctets, str) {
|
|
||||||
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
|
||||||
const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
|
||||||
|
|
||||||
// If the character is GSM extended alphabet, two octets will be written.
|
|
||||||
// So we need to keep track of number of octets to be written.
|
|
||||||
let i, j;
|
|
||||||
let len = str ? str.length : 0;
|
|
||||||
for (i = 0, j = 0; i < len && j < numOctets; i++) {
|
|
||||||
let c = str.charAt(i);
|
|
||||||
let octet = langTable.indexOf(c);
|
|
||||||
|
|
||||||
if (octet == -1) {
|
|
||||||
// Make sure we still have enough space to write two octets.
|
|
||||||
if (j + 2 > numOctets) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
octet = langShiftTable.indexOf(c);
|
|
||||||
if (octet == -1) {
|
|
||||||
// Fallback to ASCII space.
|
|
||||||
octet = langTable.indexOf(' ');
|
|
||||||
}
|
|
||||||
this.writeHexOctet(PDU_NL_EXTENDED_ESCAPE);
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
this.writeHexOctet(octet);
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// trailing 0xff
|
|
||||||
while (j++ < numOctets) {
|
|
||||||
this.writeHexOctet(0xff);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read user data and decode as a UCS2 string.
|
* Read user data and decode as a UCS2 string.
|
||||||
*
|
*
|
||||||
@ -6809,103 +6719,6 @@ let GsmPDUHelper = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Read UCS2 String on UICC.
|
|
||||||
*
|
|
||||||
* @see TS 101.221, Annex A.
|
|
||||||
* @param scheme
|
|
||||||
* Coding scheme for UCS2 on UICC. One of 0x80, 0x81 or 0x82.
|
|
||||||
* @param numOctets
|
|
||||||
* Number of octets to be read as UCS2 string.
|
|
||||||
*/
|
|
||||||
readICCUCS2String: function readICCUCS2String(scheme, numOctets) {
|
|
||||||
let str = "";
|
|
||||||
switch (scheme) {
|
|
||||||
/**
|
|
||||||
* +------+---------+---------+---------+---------+------+------+
|
|
||||||
* | 0x80 | Ch1_msb | Ch1_lsb | Ch2_msb | Ch2_lsb | 0xff | 0xff |
|
|
||||||
* +------+---------+---------+---------+---------+------+------+
|
|
||||||
*/
|
|
||||||
case 0x80:
|
|
||||||
let isOdd = numOctets % 2;
|
|
||||||
let i;
|
|
||||||
for (i = 0; i < numOctets - isOdd; i += 2) {
|
|
||||||
let code = (this.readHexOctet() << 8) | this.readHexOctet();
|
|
||||||
if (code == 0xffff) {
|
|
||||||
i += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str += String.fromCharCode(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip trailing 0xff
|
|
||||||
Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE);
|
|
||||||
break;
|
|
||||||
case 0x81: // Fall through
|
|
||||||
case 0x82:
|
|
||||||
/**
|
|
||||||
* +------+-----+--------+-----+-----+-----+--------+------+
|
|
||||||
* | 0x81 | len | offset | Ch1 | Ch2 | ... | Ch_len | 0xff |
|
|
||||||
* +------+-----+--------+-----+-----+-----+--------+------+
|
|
||||||
*
|
|
||||||
* len : The length of characters.
|
|
||||||
* offset : 0hhh hhhh h000 0000
|
|
||||||
* Ch_n: bit 8 = 0
|
|
||||||
* GSM default alphabets
|
|
||||||
* bit 8 = 1
|
|
||||||
* UCS2 character whose char code is (Ch_n & 0x7f) + offset
|
|
||||||
*
|
|
||||||
* +------+-----+------------+------------+-----+-----+-----+--------+
|
|
||||||
* | 0x82 | len | offset_msb | offset_lsb | Ch1 | Ch2 | ... | Ch_len |
|
|
||||||
* +------+-----+------------+------------+-----+-----+-----+--------+
|
|
||||||
*
|
|
||||||
* len : The length of characters.
|
|
||||||
* offset_msb, offset_lsn: offset
|
|
||||||
* Ch_n: bit 8 = 0
|
|
||||||
* GSM default alphabets
|
|
||||||
* bit 8 = 1
|
|
||||||
* UCS2 character whose char code is (Ch_n & 0x7f) + offset
|
|
||||||
*/
|
|
||||||
let len = this.readHexOctet();
|
|
||||||
let offset, headerLen;
|
|
||||||
if (scheme == 0x81) {
|
|
||||||
offset = this.readHexOctet() << 7;
|
|
||||||
headerLen = 2;
|
|
||||||
} else {
|
|
||||||
offset = (this.readHexOctet() << 8) | this.readHexOctet();
|
|
||||||
headerLen = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < len; i++) {
|
|
||||||
let ch = this.readHexOctet();
|
|
||||||
if (ch & 0x80) {
|
|
||||||
// UCS2
|
|
||||||
str += String.fromCharCode((ch & 0x7f) + offset);
|
|
||||||
} else {
|
|
||||||
// GSM 8bit
|
|
||||||
let count = 0, gotUCS2 = 0;
|
|
||||||
while ((i + count + 1 < len)) {
|
|
||||||
count++;
|
|
||||||
if (this.readHexOctet() & 0x80) {
|
|
||||||
gotUCS2 = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Unread.
|
|
||||||
// +1 for the GSM alphabet indexed at i,
|
|
||||||
Buf.seekIncoming(-1 * (count + 1) * Buf.PDU_HEX_OCTET_SIZE);
|
|
||||||
str += this.read8BitUnpackedToString(count + 1 - gotUCS2);
|
|
||||||
i += count - gotUCS2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skipping trailing 0xff
|
|
||||||
Buf.seekIncoming((numOctets - len - headerLen) * Buf.PDU_HEX_OCTET_SIZE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read 1 + UDHL octets and construct user data header.
|
* Read 1 + UDHL octets and construct user data header.
|
||||||
*
|
*
|
||||||
@ -7156,219 +6969,6 @@ let GsmPDUHelper = {
|
|||||||
return addr;
|
return addr;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Read Alpha Id and Dialling number from TS TS 151.011 clause 10.5.1
|
|
||||||
*
|
|
||||||
* @param recordSize The size of linear fixed record.
|
|
||||||
*/
|
|
||||||
readAlphaIdDiallingNumber: function readAlphaIdDiallingNumber(recordSize) {
|
|
||||||
let length = Buf.readInt32();
|
|
||||||
|
|
||||||
let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES;
|
|
||||||
let alphaId = this.readAlphaIdentifier(alphaLen);
|
|
||||||
|
|
||||||
let number = this.readNumberWithLength();
|
|
||||||
|
|
||||||
// Skip 2 unused octets, CCP and EXT1.
|
|
||||||
Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
|
|
||||||
Buf.readStringDelimiter(length);
|
|
||||||
|
|
||||||
let contact = null;
|
|
||||||
if (alphaId || number) {
|
|
||||||
contact = {alphaId: alphaId,
|
|
||||||
number: number};
|
|
||||||
}
|
|
||||||
return contact;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write Alpha Identifier and Dialling number from TS 151.011 clause 10.5.1
|
|
||||||
*
|
|
||||||
* @param recordSize The size of linear fixed record.
|
|
||||||
* @param alphaId Alpha Identifier to be written.
|
|
||||||
* @param number Dialling Number to be written.
|
|
||||||
*/
|
|
||||||
writeAlphaIdDiallingNumber: function writeAlphaIdDiallingNumber(recordSize,
|
|
||||||
alphaId,
|
|
||||||
number) {
|
|
||||||
// Write String length
|
|
||||||
let strLen = recordSize * 2;
|
|
||||||
Buf.writeInt32(strLen);
|
|
||||||
|
|
||||||
let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES;
|
|
||||||
this.writeAlphaIdentifier(alphaLen, alphaId);
|
|
||||||
this.writeNumberWithLength(number);
|
|
||||||
|
|
||||||
// Write unused octets 0xff, CCP and EXT1.
|
|
||||||
this.writeHexOctet(0xff);
|
|
||||||
this.writeHexOctet(0xff);
|
|
||||||
Buf.writeStringDelimiter(strLen);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read Alpha Identifier.
|
|
||||||
*
|
|
||||||
* @see TS 131.102
|
|
||||||
*
|
|
||||||
* @param numOctets
|
|
||||||
* Number of octets to be read.
|
|
||||||
*
|
|
||||||
* It uses either
|
|
||||||
* 1. SMS default 7-bit alphabet with bit 8 set to 0.
|
|
||||||
* 2. UCS2 string.
|
|
||||||
*
|
|
||||||
* Unused bytes should be set to 0xff.
|
|
||||||
*/
|
|
||||||
readAlphaIdentifier: function readAlphaIdentifier(numOctets) {
|
|
||||||
if (numOctets === 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
let temp;
|
|
||||||
// Read the 1st octet to determine the encoding.
|
|
||||||
if ((temp = GsmPDUHelper.readHexOctet()) == 0x80 ||
|
|
||||||
temp == 0x81 ||
|
|
||||||
temp == 0x82) {
|
|
||||||
numOctets--;
|
|
||||||
return this.readICCUCS2String(temp, numOctets);
|
|
||||||
} else {
|
|
||||||
Buf.seekIncoming(-1 * Buf.PDU_HEX_OCTET_SIZE);
|
|
||||||
return this.read8BitUnpackedToString(numOctets);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write Alpha Identifier.
|
|
||||||
*
|
|
||||||
* @param numOctets
|
|
||||||
* Total number of octets to be written. This includes the length of
|
|
||||||
* alphaId and the length of trailing unused octets(0xff).
|
|
||||||
* @param alphaId
|
|
||||||
* Alpha Identifier to be written.
|
|
||||||
*
|
|
||||||
* Unused octets will be written as 0xff.
|
|
||||||
*/
|
|
||||||
writeAlphaIdentifier: function writeAlphaIdentifier(numOctets, alphaId) {
|
|
||||||
if (numOctets === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If alphaId is empty or it's of GSM 8 bit.
|
|
||||||
if (!alphaId || ICCUtilsHelper.isGsm8BitAlphabet(alphaId)) {
|
|
||||||
this.writeStringTo8BitUnpacked(numOctets, alphaId);
|
|
||||||
} else {
|
|
||||||
// Currently only support UCS2 coding scheme 0x80.
|
|
||||||
this.writeHexOctet(0x80);
|
|
||||||
numOctets--;
|
|
||||||
// Now the alphaId is UCS2 string, each character will take 2 octets.
|
|
||||||
if (alphaId.length * 2 > numOctets) {
|
|
||||||
alphaId = alphaId.substring(0, Math.floor(numOctets / 2));
|
|
||||||
}
|
|
||||||
this.writeUCS2String(alphaId);
|
|
||||||
for (let i = alphaId.length * 2; i < numOctets; i++) {
|
|
||||||
this.writeHexOctet(0xff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read Dialling number.
|
|
||||||
*
|
|
||||||
* @see TS 131.102
|
|
||||||
*
|
|
||||||
* @param len
|
|
||||||
* The Length of BCD number.
|
|
||||||
*
|
|
||||||
* From TS 131.102, in EF_ADN, EF_FDN, the field 'Length of BCD number'
|
|
||||||
* means the total bytes should be allocated to store the TON/NPI and
|
|
||||||
* the dialing number.
|
|
||||||
* For example, if the dialing number is 1234567890,
|
|
||||||
* and the TON/NPI is 0x81,
|
|
||||||
* The field 'Length of BCD number' should be 06, which is
|
|
||||||
* 1 byte to store the TON/NPI, 0x81
|
|
||||||
* 5 bytes to store the BCD number 2143658709.
|
|
||||||
*
|
|
||||||
* Here the definition of the length is different from SMS spec,
|
|
||||||
* TS 23.040 9.1.2.5, which the length means
|
|
||||||
* "number of useful semi-octets within the Address-Value field".
|
|
||||||
*/
|
|
||||||
readDiallingNumber: function readDiallingNumber(len) {
|
|
||||||
if (DEBUG) debug("PDU: Going to read Dialling number: " + len);
|
|
||||||
if (len === 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// TOA = TON + NPI
|
|
||||||
let toa = this.readHexOctet();
|
|
||||||
|
|
||||||
let number = this.readSwappedNibbleBcdString(len - 1);
|
|
||||||
if (number.length <= 0) {
|
|
||||||
if (DEBUG) debug("No number provided");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
if ((toa >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) {
|
|
||||||
number = '+' + number;
|
|
||||||
}
|
|
||||||
return number;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write Dialling Number.
|
|
||||||
*
|
|
||||||
* @param number The Dialling number
|
|
||||||
*/
|
|
||||||
writeDiallingNumber: function writeDiallingNumber(number) {
|
|
||||||
let toa = PDU_TOA_ISDN; // 81
|
|
||||||
if (number[0] == '+') {
|
|
||||||
toa = PDU_TOA_INTERNATIONAL | PDU_TOA_ISDN; // 91
|
|
||||||
number = number.substring(1);
|
|
||||||
}
|
|
||||||
this.writeHexOctet(toa);
|
|
||||||
this.writeSwappedNibbleBCD(number);
|
|
||||||
},
|
|
||||||
|
|
||||||
readNumberWithLength: function readNumberWithLength() {
|
|
||||||
let number;
|
|
||||||
let numLen = this.readHexOctet();
|
|
||||||
if (numLen != 0xff) {
|
|
||||||
if (numLen > ADN_MAX_BCD_NUMBER_BYTES) {
|
|
||||||
throw new Error("invalid length of BCD number/SSC contents - " + numLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
number = this.readDiallingNumber(numLen);
|
|
||||||
Buf.seekIncoming((ADN_MAX_BCD_NUMBER_BYTES - numLen) * Buf.PDU_HEX_OCTET_SIZE);
|
|
||||||
} else {
|
|
||||||
Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return number;
|
|
||||||
},
|
|
||||||
|
|
||||||
writeNumberWithLength: function writeNumberWithLength(number) {
|
|
||||||
if (number) {
|
|
||||||
let numStart = number[0] == "+" ? 1 : 0;
|
|
||||||
let numDigits = number.length - numStart;
|
|
||||||
if (numDigits > ADN_MAX_NUMBER_DIGITS) {
|
|
||||||
number = number.substring(0, ADN_MAX_NUMBER_DIGITS + numStart);
|
|
||||||
numDigits = number.length - numStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
// +1 for TON/NPI
|
|
||||||
let numLen = Math.ceil(numDigits / 2) + 1;
|
|
||||||
this.writeHexOctet(numLen);
|
|
||||||
this.writeDiallingNumber(number);
|
|
||||||
// Write trailing 0xff of Dialling Number.
|
|
||||||
for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES - numLen; i++) {
|
|
||||||
this.writeHexOctet(0xff);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// +1 for numLen
|
|
||||||
for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES + 1; i++) {
|
|
||||||
this.writeHexOctet(0xff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read TP-Protocol-Indicator(TP-PID).
|
* Read TP-Protocol-Indicator(TP-PID).
|
||||||
*
|
*
|
||||||
@ -9590,6 +9190,411 @@ let CdmaPDUHelper = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for processing ICC PDUs.
|
||||||
|
*/
|
||||||
|
let ICCPDUHelper = {
|
||||||
|
/**
|
||||||
|
* Read GSM 8-bit unpacked octets,
|
||||||
|
* which are default 7-bit alphabets with bit 8 set to 0.
|
||||||
|
*
|
||||||
|
* @param numOctets
|
||||||
|
* Number of octets to be read.
|
||||||
|
*/
|
||||||
|
read8BitUnpackedToString: function read8BitUnpackedToString(numOctets) {
|
||||||
|
let ret = "";
|
||||||
|
let escapeFound = false;
|
||||||
|
let i;
|
||||||
|
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
||||||
|
const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
||||||
|
|
||||||
|
for(i = 0; i < numOctets; i++) {
|
||||||
|
let octet = GsmPDUHelper.readHexOctet();
|
||||||
|
if (octet == 0xff) {
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (escapeFound) {
|
||||||
|
escapeFound = false;
|
||||||
|
if (octet == PDU_NL_EXTENDED_ESCAPE) {
|
||||||
|
// According to 3GPP TS 23.038, section 6.2.1.1, NOTE 1, "On
|
||||||
|
// receipt of this code, a receiving entity shall display a space
|
||||||
|
// until another extensiion table is defined."
|
||||||
|
ret += " ";
|
||||||
|
} else if (octet == PDU_NL_RESERVED_CONTROL) {
|
||||||
|
// According to 3GPP TS 23.038 B.2, "This code represents a control
|
||||||
|
// character and therefore must not be used for language specific
|
||||||
|
// characters."
|
||||||
|
ret += " ";
|
||||||
|
} else {
|
||||||
|
ret += langShiftTable[octet];
|
||||||
|
}
|
||||||
|
} else if (octet == PDU_NL_EXTENDED_ESCAPE) {
|
||||||
|
escapeFound = true;
|
||||||
|
} else {
|
||||||
|
ret += langTable[octet];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE);
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write GSM 8-bit unpacked octets.
|
||||||
|
*
|
||||||
|
* @param numOctets Number of total octets to be writen, including trailing
|
||||||
|
* 0xff.
|
||||||
|
* @param str String to be written. Could be null.
|
||||||
|
*/
|
||||||
|
writeStringTo8BitUnpacked: function writeStringTo8BitUnpacked(numOctets, str) {
|
||||||
|
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
||||||
|
const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
||||||
|
|
||||||
|
// If the character is GSM extended alphabet, two octets will be written.
|
||||||
|
// So we need to keep track of number of octets to be written.
|
||||||
|
let i, j;
|
||||||
|
let len = str ? str.length : 0;
|
||||||
|
for (i = 0, j = 0; i < len && j < numOctets; i++) {
|
||||||
|
let c = str.charAt(i);
|
||||||
|
let octet = langTable.indexOf(c);
|
||||||
|
|
||||||
|
if (octet == -1) {
|
||||||
|
// Make sure we still have enough space to write two octets.
|
||||||
|
if (j + 2 > numOctets) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
octet = langShiftTable.indexOf(c);
|
||||||
|
if (octet == -1) {
|
||||||
|
// Fallback to ASCII space.
|
||||||
|
octet = langTable.indexOf(' ');
|
||||||
|
}
|
||||||
|
GsmPDUHelper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
GsmPDUHelper.writeHexOctet(octet);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trailing 0xff
|
||||||
|
while (j++ < numOctets) {
|
||||||
|
GsmPDUHelper.writeHexOctet(0xff);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read UCS2 String on UICC.
|
||||||
|
*
|
||||||
|
* @see TS 101.221, Annex A.
|
||||||
|
* @param scheme
|
||||||
|
* Coding scheme for UCS2 on UICC. One of 0x80, 0x81 or 0x82.
|
||||||
|
* @param numOctets
|
||||||
|
* Number of octets to be read as UCS2 string.
|
||||||
|
*/
|
||||||
|
readICCUCS2String: function readICCUCS2String(scheme, numOctets) {
|
||||||
|
let str = "";
|
||||||
|
switch (scheme) {
|
||||||
|
/**
|
||||||
|
* +------+---------+---------+---------+---------+------+------+
|
||||||
|
* | 0x80 | Ch1_msb | Ch1_lsb | Ch2_msb | Ch2_lsb | 0xff | 0xff |
|
||||||
|
* +------+---------+---------+---------+---------+------+------+
|
||||||
|
*/
|
||||||
|
case 0x80:
|
||||||
|
let isOdd = numOctets % 2;
|
||||||
|
let i;
|
||||||
|
for (i = 0; i < numOctets - isOdd; i += 2) {
|
||||||
|
let code = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet();
|
||||||
|
if (code == 0xffff) {
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str += String.fromCharCode(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip trailing 0xff
|
||||||
|
Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE);
|
||||||
|
break;
|
||||||
|
case 0x81: // Fall through
|
||||||
|
case 0x82:
|
||||||
|
/**
|
||||||
|
* +------+-----+--------+-----+-----+-----+--------+------+
|
||||||
|
* | 0x81 | len | offset | Ch1 | Ch2 | ... | Ch_len | 0xff |
|
||||||
|
* +------+-----+--------+-----+-----+-----+--------+------+
|
||||||
|
*
|
||||||
|
* len : The length of characters.
|
||||||
|
* offset : 0hhh hhhh h000 0000
|
||||||
|
* Ch_n: bit 8 = 0
|
||||||
|
* GSM default alphabets
|
||||||
|
* bit 8 = 1
|
||||||
|
* UCS2 character whose char code is (Ch_n & 0x7f) + offset
|
||||||
|
*
|
||||||
|
* +------+-----+------------+------------+-----+-----+-----+--------+
|
||||||
|
* | 0x82 | len | offset_msb | offset_lsb | Ch1 | Ch2 | ... | Ch_len |
|
||||||
|
* +------+-----+------------+------------+-----+-----+-----+--------+
|
||||||
|
*
|
||||||
|
* len : The length of characters.
|
||||||
|
* offset_msb, offset_lsn: offset
|
||||||
|
* Ch_n: bit 8 = 0
|
||||||
|
* GSM default alphabets
|
||||||
|
* bit 8 = 1
|
||||||
|
* UCS2 character whose char code is (Ch_n & 0x7f) + offset
|
||||||
|
*/
|
||||||
|
let len = GsmPDUHelper.readHexOctet();
|
||||||
|
let offset, headerLen;
|
||||||
|
if (scheme == 0x81) {
|
||||||
|
offset = GsmPDUHelper.readHexOctet() << 7;
|
||||||
|
headerLen = 2;
|
||||||
|
} else {
|
||||||
|
offset = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet();
|
||||||
|
headerLen = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
let ch = GsmPDUHelper.readHexOctet();
|
||||||
|
if (ch & 0x80) {
|
||||||
|
// UCS2
|
||||||
|
str += String.fromCharCode((ch & 0x7f) + offset);
|
||||||
|
} else {
|
||||||
|
// GSM 8bit
|
||||||
|
let count = 0, gotUCS2 = 0;
|
||||||
|
while ((i + count + 1 < len)) {
|
||||||
|
count++;
|
||||||
|
if (GsmPDUHelper.readHexOctet() & 0x80) {
|
||||||
|
gotUCS2 = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Unread.
|
||||||
|
// +1 for the GSM alphabet indexed at i,
|
||||||
|
Buf.seekIncoming(-1 * (count + 1) * Buf.PDU_HEX_OCTET_SIZE);
|
||||||
|
str += this.read8BitUnpackedToString(count + 1 - gotUCS2);
|
||||||
|
i += count - gotUCS2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skipping trailing 0xff
|
||||||
|
Buf.seekIncoming((numOctets - len - headerLen) * Buf.PDU_HEX_OCTET_SIZE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read Alpha Id and Dialling number from TS TS 151.011 clause 10.5.1
|
||||||
|
*
|
||||||
|
* @param recordSize The size of linear fixed record.
|
||||||
|
*/
|
||||||
|
readAlphaIdDiallingNumber: function readAlphaIdDiallingNumber(recordSize) {
|
||||||
|
let length = Buf.readInt32();
|
||||||
|
|
||||||
|
let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES;
|
||||||
|
let alphaId = this.readAlphaIdentifier(alphaLen);
|
||||||
|
|
||||||
|
let number = this.readNumberWithLength();
|
||||||
|
|
||||||
|
// Skip 2 unused octets, CCP and EXT1.
|
||||||
|
Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
|
||||||
|
Buf.readStringDelimiter(length);
|
||||||
|
|
||||||
|
let contact = null;
|
||||||
|
if (alphaId || number) {
|
||||||
|
contact = {alphaId: alphaId,
|
||||||
|
number: number};
|
||||||
|
}
|
||||||
|
return contact;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write Alpha Identifier and Dialling number from TS 151.011 clause 10.5.1
|
||||||
|
*
|
||||||
|
* @param recordSize The size of linear fixed record.
|
||||||
|
* @param alphaId Alpha Identifier to be written.
|
||||||
|
* @param number Dialling Number to be written.
|
||||||
|
*/
|
||||||
|
writeAlphaIdDiallingNumber: function writeAlphaIdDiallingNumber(recordSize,
|
||||||
|
alphaId,
|
||||||
|
number) {
|
||||||
|
// Write String length
|
||||||
|
let strLen = recordSize * 2;
|
||||||
|
Buf.writeInt32(strLen);
|
||||||
|
|
||||||
|
let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES;
|
||||||
|
this.writeAlphaIdentifier(alphaLen, alphaId);
|
||||||
|
this.writeNumberWithLength(number);
|
||||||
|
|
||||||
|
// Write unused octets 0xff, CCP and EXT1.
|
||||||
|
GsmPDUHelper.writeHexOctet(0xff);
|
||||||
|
GsmPDUHelper.writeHexOctet(0xff);
|
||||||
|
Buf.writeStringDelimiter(strLen);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read Alpha Identifier.
|
||||||
|
*
|
||||||
|
* @see TS 131.102
|
||||||
|
*
|
||||||
|
* @param numOctets
|
||||||
|
* Number of octets to be read.
|
||||||
|
*
|
||||||
|
* It uses either
|
||||||
|
* 1. SMS default 7-bit alphabet with bit 8 set to 0.
|
||||||
|
* 2. UCS2 string.
|
||||||
|
*
|
||||||
|
* Unused bytes should be set to 0xff.
|
||||||
|
*/
|
||||||
|
readAlphaIdentifier: function readAlphaIdentifier(numOctets) {
|
||||||
|
if (numOctets === 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
let temp;
|
||||||
|
// Read the 1st octet to determine the encoding.
|
||||||
|
if ((temp = GsmPDUHelper.readHexOctet()) == 0x80 ||
|
||||||
|
temp == 0x81 ||
|
||||||
|
temp == 0x82) {
|
||||||
|
numOctets--;
|
||||||
|
return this.readICCUCS2String(temp, numOctets);
|
||||||
|
} else {
|
||||||
|
Buf.seekIncoming(-1 * Buf.PDU_HEX_OCTET_SIZE);
|
||||||
|
return this.read8BitUnpackedToString(numOctets);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write Alpha Identifier.
|
||||||
|
*
|
||||||
|
* @param numOctets
|
||||||
|
* Total number of octets to be written. This includes the length of
|
||||||
|
* alphaId and the length of trailing unused octets(0xff).
|
||||||
|
* @param alphaId
|
||||||
|
* Alpha Identifier to be written.
|
||||||
|
*
|
||||||
|
* Unused octets will be written as 0xff.
|
||||||
|
*/
|
||||||
|
writeAlphaIdentifier: function writeAlphaIdentifier(numOctets, alphaId) {
|
||||||
|
if (numOctets === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If alphaId is empty or it's of GSM 8 bit.
|
||||||
|
if (!alphaId || ICCUtilsHelper.isGsm8BitAlphabet(alphaId)) {
|
||||||
|
this.writeStringTo8BitUnpacked(numOctets, alphaId);
|
||||||
|
} else {
|
||||||
|
// Currently only support UCS2 coding scheme 0x80.
|
||||||
|
GsmPDUHelper.writeHexOctet(0x80);
|
||||||
|
numOctets--;
|
||||||
|
// Now the alphaId is UCS2 string, each character will take 2 octets.
|
||||||
|
if (alphaId.length * 2 > numOctets) {
|
||||||
|
alphaId = alphaId.substring(0, Math.floor(numOctets / 2));
|
||||||
|
}
|
||||||
|
GsmPDUHelper.writeUCS2String(alphaId);
|
||||||
|
for (let i = alphaId.length * 2; i < numOctets; i++) {
|
||||||
|
GsmPDUHelper.writeHexOctet(0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read Dialling number.
|
||||||
|
*
|
||||||
|
* @see TS 131.102
|
||||||
|
*
|
||||||
|
* @param len
|
||||||
|
* The Length of BCD number.
|
||||||
|
*
|
||||||
|
* From TS 131.102, in EF_ADN, EF_FDN, the field 'Length of BCD number'
|
||||||
|
* means the total bytes should be allocated to store the TON/NPI and
|
||||||
|
* the dialing number.
|
||||||
|
* For example, if the dialing number is 1234567890,
|
||||||
|
* and the TON/NPI is 0x81,
|
||||||
|
* The field 'Length of BCD number' should be 06, which is
|
||||||
|
* 1 byte to store the TON/NPI, 0x81
|
||||||
|
* 5 bytes to store the BCD number 2143658709.
|
||||||
|
*
|
||||||
|
* Here the definition of the length is different from SMS spec,
|
||||||
|
* TS 23.040 9.1.2.5, which the length means
|
||||||
|
* "number of useful semi-octets within the Address-Value field".
|
||||||
|
*/
|
||||||
|
readDiallingNumber: function readDiallingNumber(len) {
|
||||||
|
if (DEBUG) debug("PDU: Going to read Dialling number: " + len);
|
||||||
|
if (len === 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOA = TON + NPI
|
||||||
|
let toa = GsmPDUHelper.readHexOctet();
|
||||||
|
|
||||||
|
let number = GsmPDUHelper.readSwappedNibbleBcdString(len - 1);
|
||||||
|
if (number.length <= 0) {
|
||||||
|
if (DEBUG) debug("No number provided");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if ((toa >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) {
|
||||||
|
number = '+' + number;
|
||||||
|
}
|
||||||
|
return number;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write Dialling Number.
|
||||||
|
*
|
||||||
|
* @param number The Dialling number
|
||||||
|
*/
|
||||||
|
writeDiallingNumber: function writeDiallingNumber(number) {
|
||||||
|
let toa = PDU_TOA_ISDN; // 81
|
||||||
|
if (number[0] == '+') {
|
||||||
|
toa = PDU_TOA_INTERNATIONAL | PDU_TOA_ISDN; // 91
|
||||||
|
number = number.substring(1);
|
||||||
|
}
|
||||||
|
GsmPDUHelper.writeHexOctet(toa);
|
||||||
|
GsmPDUHelper.writeSwappedNibbleBCD(number);
|
||||||
|
},
|
||||||
|
|
||||||
|
readNumberWithLength: function readNumberWithLength() {
|
||||||
|
let number;
|
||||||
|
let numLen = GsmPDUHelper.readHexOctet();
|
||||||
|
if (numLen != 0xff) {
|
||||||
|
if (numLen > ADN_MAX_BCD_NUMBER_BYTES) {
|
||||||
|
throw new Error("invalid length of BCD number/SSC contents - " + numLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
number = this.readDiallingNumber(numLen);
|
||||||
|
Buf.seekIncoming((ADN_MAX_BCD_NUMBER_BYTES - numLen) * Buf.PDU_HEX_OCTET_SIZE);
|
||||||
|
} else {
|
||||||
|
Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return number;
|
||||||
|
},
|
||||||
|
|
||||||
|
writeNumberWithLength: function writeNumberWithLength(number) {
|
||||||
|
if (number) {
|
||||||
|
let numStart = number[0] == "+" ? 1 : 0;
|
||||||
|
let numDigits = number.length - numStart;
|
||||||
|
if (numDigits > ADN_MAX_NUMBER_DIGITS) {
|
||||||
|
number = number.substring(0, ADN_MAX_NUMBER_DIGITS + numStart);
|
||||||
|
numDigits = number.length - numStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// +1 for TON/NPI
|
||||||
|
let numLen = Math.ceil(numDigits / 2) + 1;
|
||||||
|
GsmPDUHelper.writeHexOctet(numLen);
|
||||||
|
this.writeDiallingNumber(number);
|
||||||
|
// Write trailing 0xff of Dialling Number.
|
||||||
|
for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES - numLen; i++) {
|
||||||
|
GsmPDUHelper.writeHexOctet(0xff);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// +1 for numLen
|
||||||
|
for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES + 1; i++) {
|
||||||
|
GsmPDUHelper.writeHexOctet(0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let StkCommandParamsFactory = {
|
let StkCommandParamsFactory = {
|
||||||
createParam: function createParam(cmdDetails, ctlvs) {
|
createParam: function createParam(cmdDetails, ctlvs) {
|
||||||
let method = StkCommandParamsFactory[cmdDetails.typeOfCommand];
|
let method = StkCommandParamsFactory[cmdDetails.typeOfCommand];
|
||||||
@ -10157,7 +10162,7 @@ let StkProactiveCmdHelper = {
|
|||||||
*/
|
*/
|
||||||
retrieveAlphaId: function retrieveAlphaId(length) {
|
retrieveAlphaId: function retrieveAlphaId(length) {
|
||||||
let alphaId = {
|
let alphaId = {
|
||||||
identifier: GsmPDUHelper.readAlphaIdentifier(length)
|
identifier: ICCPDUHelper.readAlphaIdentifier(length)
|
||||||
};
|
};
|
||||||
return alphaId;
|
return alphaId;
|
||||||
},
|
},
|
||||||
@ -10191,7 +10196,7 @@ let StkProactiveCmdHelper = {
|
|||||||
*/
|
*/
|
||||||
retrieveAddress: function retrieveAddress(length) {
|
retrieveAddress: function retrieveAddress(length) {
|
||||||
let address = {
|
let address = {
|
||||||
number : GsmPDUHelper.readDiallingNumber(length)
|
number : ICCPDUHelper.readDiallingNumber(length)
|
||||||
};
|
};
|
||||||
return address;
|
return address;
|
||||||
},
|
},
|
||||||
@ -10222,7 +10227,7 @@ let StkProactiveCmdHelper = {
|
|||||||
text.textString = GsmPDUHelper.readSeptetsToString(length * 8 / 7, 0, 0, 0);
|
text.textString = GsmPDUHelper.readSeptetsToString(length * 8 / 7, 0, 0, 0);
|
||||||
break;
|
break;
|
||||||
case STK_TEXT_CODING_GSM_8BIT:
|
case STK_TEXT_CODING_GSM_8BIT:
|
||||||
text.textString = GsmPDUHelper.read8BitUnpackedToString(length);
|
text.textString = ICCPDUHelper.read8BitUnpackedToString(length);
|
||||||
break;
|
break;
|
||||||
case STK_TEXT_CODING_UCS2:
|
case STK_TEXT_CODING_UCS2:
|
||||||
text.textString = GsmPDUHelper.readUCS2String(length);
|
text.textString = GsmPDUHelper.readUCS2String(length);
|
||||||
@ -10266,7 +10271,7 @@ let StkProactiveCmdHelper = {
|
|||||||
}
|
}
|
||||||
let item = {
|
let item = {
|
||||||
identifier: GsmPDUHelper.readHexOctet(),
|
identifier: GsmPDUHelper.readHexOctet(),
|
||||||
text: GsmPDUHelper.readAlphaIdentifier(length - 1)
|
text: ICCPDUHelper.readAlphaIdentifier(length - 1)
|
||||||
};
|
};
|
||||||
return item;
|
return item;
|
||||||
},
|
},
|
||||||
@ -11246,7 +11251,7 @@ let ICCRecordHelper = {
|
|||||||
*/
|
*/
|
||||||
readMSISDN: function readMSISDN() {
|
readMSISDN: function readMSISDN() {
|
||||||
function callback(options) {
|
function callback(options) {
|
||||||
let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
|
let contact = ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
|
||||||
if (!contact ||
|
if (!contact ||
|
||||||
(RIL.iccInfo.msisdn !== undefined &&
|
(RIL.iccInfo.msisdn !== undefined &&
|
||||||
RIL.iccInfo.msisdn === contact.number)) {
|
RIL.iccInfo.msisdn === contact.number)) {
|
||||||
@ -11304,7 +11309,7 @@ let ICCRecordHelper = {
|
|||||||
let octetLen = strLen / 2;
|
let octetLen = strLen / 2;
|
||||||
let spnDisplayCondition = GsmPDUHelper.readHexOctet();
|
let spnDisplayCondition = GsmPDUHelper.readHexOctet();
|
||||||
// Minus 1 because the first octet is used to store display condition.
|
// Minus 1 because the first octet is used to store display condition.
|
||||||
let spn = GsmPDUHelper.readAlphaIdentifier(octetLen - 1);
|
let spn = ICCPDUHelper.readAlphaIdentifier(octetLen - 1);
|
||||||
Buf.readStringDelimiter(strLen);
|
Buf.readStringDelimiter(strLen);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -11416,7 +11421,7 @@ let ICCRecordHelper = {
|
|||||||
*/
|
*/
|
||||||
readADNLike: function readADNLike(fileId, onsuccess, onerror) {
|
readADNLike: function readADNLike(fileId, onsuccess, onerror) {
|
||||||
function callback(options) {
|
function callback(options) {
|
||||||
let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
|
let contact = ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
|
||||||
if (contact) {
|
if (contact) {
|
||||||
contact.recordId = options.p1;
|
contact.recordId = options.p1;
|
||||||
contacts.push(contact);
|
contacts.push(contact);
|
||||||
@ -11453,7 +11458,7 @@ let ICCRecordHelper = {
|
|||||||
*/
|
*/
|
||||||
updateADNLike: function updateADNLike(fileId, contact, pin2, onsuccess, onerror) {
|
updateADNLike: function updateADNLike(fileId, contact, pin2, onsuccess, onerror) {
|
||||||
function dataWriter(recordSize) {
|
function dataWriter(recordSize) {
|
||||||
GsmPDUHelper.writeAlphaIdDiallingNumber(recordSize,
|
ICCPDUHelper.writeAlphaIdDiallingNumber(recordSize,
|
||||||
contact.alphaId,
|
contact.alphaId,
|
||||||
contact.number);
|
contact.number);
|
||||||
}
|
}
|
||||||
@ -11485,7 +11490,7 @@ let ICCRecordHelper = {
|
|||||||
*/
|
*/
|
||||||
readMBDN: function readMBDN() {
|
readMBDN: function readMBDN() {
|
||||||
function callback(options) {
|
function callback(options) {
|
||||||
let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
|
let contact = ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
|
||||||
if (!contact ||
|
if (!contact ||
|
||||||
(RIL.iccInfoPrivate.mbdn !== undefined &&
|
(RIL.iccInfoPrivate.mbdn !== undefined &&
|
||||||
RIL.iccInfoPrivate.mbdn === contact.number)) {
|
RIL.iccInfoPrivate.mbdn === contact.number)) {
|
||||||
@ -11658,9 +11663,9 @@ let ICCRecordHelper = {
|
|||||||
// Note: The fields marked as C above are mandatort if the file
|
// Note: The fields marked as C above are mandatort if the file
|
||||||
// is not type 1 (as specified in EF_PBR)
|
// is not type 1 (as specified in EF_PBR)
|
||||||
if (fileType == ICC_USIM_TYPE1_TAG) {
|
if (fileType == ICC_USIM_TYPE1_TAG) {
|
||||||
email = GsmPDUHelper.read8BitUnpackedToString(octetLen);
|
email = ICCPDUHelper.read8BitUnpackedToString(octetLen);
|
||||||
} else {
|
} else {
|
||||||
email = GsmPDUHelper.read8BitUnpackedToString(octetLen - 2);
|
email = ICCPDUHelper.read8BitUnpackedToString(octetLen - 2);
|
||||||
|
|
||||||
// Consumes the remaining buffer
|
// Consumes the remaining buffer
|
||||||
Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); // For ADN SFI and Record Identifier
|
Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); // For ADN SFI and Record Identifier
|
||||||
@ -11701,9 +11706,9 @@ let ICCRecordHelper = {
|
|||||||
Buf.writeInt32(strLen);
|
Buf.writeInt32(strLen);
|
||||||
|
|
||||||
if (fileType == ICC_USIM_TYPE1_TAG) {
|
if (fileType == ICC_USIM_TYPE1_TAG) {
|
||||||
GsmPDUHelper.writeStringTo8BitUnpacked(recordSize, email);
|
ICCPDUHelper.writeStringTo8BitUnpacked(recordSize, email);
|
||||||
} else {
|
} else {
|
||||||
GsmPDUHelper.writeStringTo8BitUnpacked(recordSize - 2, email);
|
ICCPDUHelper.writeStringTo8BitUnpacked(recordSize - 2, email);
|
||||||
GsmPDUHelper.writeHexOctet(pbr.adn.sfi || 0xff);
|
GsmPDUHelper.writeHexOctet(pbr.adn.sfi || 0xff);
|
||||||
GsmPDUHelper.writeHexOctet(adnRecordId);
|
GsmPDUHelper.writeHexOctet(adnRecordId);
|
||||||
}
|
}
|
||||||
@ -11743,7 +11748,7 @@ let ICCRecordHelper = {
|
|||||||
// Skip EF_AAS Record ID.
|
// Skip EF_AAS Record ID.
|
||||||
Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE);
|
Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE);
|
||||||
|
|
||||||
number = GsmPDUHelper.readNumberWithLength();
|
number = ICCPDUHelper.readNumberWithLength();
|
||||||
|
|
||||||
// Skip 2 unused octets, CCP and EXT1.
|
// Skip 2 unused octets, CCP and EXT1.
|
||||||
Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
|
Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
|
||||||
@ -11790,7 +11795,7 @@ let ICCRecordHelper = {
|
|||||||
// EF_AAS record Id. Unused for now.
|
// EF_AAS record Id. Unused for now.
|
||||||
GsmPDUHelper.writeHexOctet(0xff);
|
GsmPDUHelper.writeHexOctet(0xff);
|
||||||
|
|
||||||
GsmPDUHelper.writeNumberWithLength(number);
|
ICCPDUHelper.writeNumberWithLength(number);
|
||||||
|
|
||||||
// Write unused octets 0xff, CCP and EXT1.
|
// Write unused octets 0xff, CCP and EXT1.
|
||||||
GsmPDUHelper.writeHexOctet(0xff);
|
GsmPDUHelper.writeHexOctet(0xff);
|
||||||
|
@ -33,11 +33,12 @@ function newUint8Worker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify GsmPDUHelper#readICCUCS2String()
|
* Verify ICCPDUHelper#readICCUCS2String()
|
||||||
*/
|
*/
|
||||||
add_test(function test_read_icc_ucs2_string() {
|
add_test(function test_read_icc_ucs2_string() {
|
||||||
let worker = newUint8Worker();
|
let worker = newUint8Worker();
|
||||||
let helper = worker.GsmPDUHelper;
|
let helper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
|
|
||||||
// 0x80
|
// 0x80
|
||||||
let text = "TEST";
|
let text = "TEST";
|
||||||
@ -47,7 +48,7 @@ add_test(function test_read_icc_ucs2_string() {
|
|||||||
for (let i = 0; i < ffLen; i++) {
|
for (let i = 0; i < ffLen; i++) {
|
||||||
helper.writeHexOctet(0xff);
|
helper.writeHexOctet(0xff);
|
||||||
}
|
}
|
||||||
do_check_eq(helper.readICCUCS2String(0x80, (2 * text.length) + ffLen), text);
|
do_check_eq(iccHelper.readICCUCS2String(0x80, (2 * text.length) + ffLen), text);
|
||||||
|
|
||||||
// 0x81
|
// 0x81
|
||||||
let array = [0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca,
|
let array = [0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca,
|
||||||
@ -56,7 +57,7 @@ add_test(function test_read_icc_ucs2_string() {
|
|||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
helper.writeHexOctet(array[i]);
|
helper.writeHexOctet(array[i]);
|
||||||
}
|
}
|
||||||
do_check_eq(helper.readICCUCS2String(0x81, len), "Mozilla\u694a");
|
do_check_eq(iccHelper.readICCUCS2String(0x81, len), "Mozilla\u694a");
|
||||||
|
|
||||||
// 0x82
|
// 0x82
|
||||||
let array2 = [0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61,
|
let array2 = [0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61,
|
||||||
@ -65,17 +66,18 @@ add_test(function test_read_icc_ucs2_string() {
|
|||||||
for (let i = 0; i < len2; i++) {
|
for (let i = 0; i < len2; i++) {
|
||||||
helper.writeHexOctet(array2[i]);
|
helper.writeHexOctet(array2[i]);
|
||||||
}
|
}
|
||||||
do_check_eq(helper.readICCUCS2String(0x82, len2), "Mozilla\u694a");
|
do_check_eq(iccHelper.readICCUCS2String(0x82, len2), "Mozilla\u694a");
|
||||||
|
|
||||||
run_next_test();
|
run_next_test();
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify GsmPDUHelper#readDiallingNumber
|
* Verify ICCPDUHelper#readDiallingNumber
|
||||||
*/
|
*/
|
||||||
add_test(function test_read_dialling_number() {
|
add_test(function test_read_dialling_number() {
|
||||||
let worker = newUint8Worker();
|
let worker = newUint8Worker();
|
||||||
let helper = worker.GsmPDUHelper;
|
let helper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
let str = "123456789";
|
let str = "123456789";
|
||||||
|
|
||||||
helper.readHexOctet = function () {
|
helper.readHexOctet = function () {
|
||||||
@ -88,18 +90,19 @@ add_test(function test_read_dialling_number() {
|
|||||||
|
|
||||||
for (let i = 0; i < str.length; i++) {
|
for (let i = 0; i < str.length; i++) {
|
||||||
do_check_eq(str.substring(0, i - 1), // -1 for the TON
|
do_check_eq(str.substring(0, i - 1), // -1 for the TON
|
||||||
helper.readDiallingNumber(i));
|
iccHelper.readDiallingNumber(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
run_next_test();
|
run_next_test();
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify GsmPDUHelper#read8BitUnpackedToString
|
* Verify ICCPDUHelper#read8BitUnpackedToString
|
||||||
*/
|
*/
|
||||||
add_test(function test_read_8bit_unpacked_to_string() {
|
add_test(function test_read_8bit_unpacked_to_string() {
|
||||||
let worker = newUint8Worker();
|
let worker = newUint8Worker();
|
||||||
let helper = worker.GsmPDUHelper;
|
let helper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
||||||
const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
||||||
|
|
||||||
@ -123,10 +126,10 @@ add_test(function test_read_8bit_unpacked_to_string() {
|
|||||||
helper.writeHexOctet(0xff);
|
helper.writeHexOctet(0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
do_check_eq(helper.read8BitUnpackedToString(PDU_NL_EXTENDED_ESCAPE),
|
do_check_eq(iccHelper.read8BitUnpackedToString(PDU_NL_EXTENDED_ESCAPE),
|
||||||
langTable.substring(0, PDU_NL_EXTENDED_ESCAPE));
|
langTable.substring(0, PDU_NL_EXTENDED_ESCAPE));
|
||||||
do_check_eq(helper.read8BitUnpackedToString(2), " ");
|
do_check_eq(iccHelper.read8BitUnpackedToString(2), " ");
|
||||||
do_check_eq(helper.read8BitUnpackedToString(langTable.length -
|
do_check_eq(iccHelper.read8BitUnpackedToString(langTable.length -
|
||||||
PDU_NL_EXTENDED_ESCAPE - 1 + ffLen),
|
PDU_NL_EXTENDED_ESCAPE - 1 + ffLen),
|
||||||
langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1));
|
langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1));
|
||||||
|
|
||||||
@ -137,19 +140,19 @@ add_test(function test_read_8bit_unpacked_to_string() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read string before RESERVED_CONTROL.
|
// Read string before RESERVED_CONTROL.
|
||||||
do_check_eq(helper.read8BitUnpackedToString(PDU_NL_RESERVED_CONTROL * 2),
|
do_check_eq(iccHelper.read8BitUnpackedToString(PDU_NL_RESERVED_CONTROL * 2),
|
||||||
langShiftTable.substring(0, PDU_NL_RESERVED_CONTROL));
|
langShiftTable.substring(0, PDU_NL_RESERVED_CONTROL));
|
||||||
// ESCAPE + RESERVED_CONTROL will become ' '.
|
// ESCAPE + RESERVED_CONTROL will become ' '.
|
||||||
do_check_eq(helper.read8BitUnpackedToString(2), " ");
|
do_check_eq(iccHelper.read8BitUnpackedToString(2), " ");
|
||||||
// Read string between RESERVED_CONTROL and EXTENDED_ESCAPE.
|
// Read string between RESERVED_CONTROL and EXTENDED_ESCAPE.
|
||||||
do_check_eq(helper.read8BitUnpackedToString(
|
do_check_eq(iccHelper.read8BitUnpackedToString(
|
||||||
(PDU_NL_EXTENDED_ESCAPE - PDU_NL_RESERVED_CONTROL - 1) * 2),
|
(PDU_NL_EXTENDED_ESCAPE - PDU_NL_RESERVED_CONTROL - 1) * 2),
|
||||||
langShiftTable.substring(PDU_NL_RESERVED_CONTROL + 1,
|
langShiftTable.substring(PDU_NL_RESERVED_CONTROL + 1,
|
||||||
PDU_NL_EXTENDED_ESCAPE));
|
PDU_NL_EXTENDED_ESCAPE));
|
||||||
// ESCAPE + ESCAPE will become ' '.
|
// ESCAPE + ESCAPE will become ' '.
|
||||||
do_check_eq(helper.read8BitUnpackedToString(2), " ");
|
do_check_eq(iccHelper.read8BitUnpackedToString(2), " ");
|
||||||
// Read remaining string.
|
// Read remaining string.
|
||||||
do_check_eq(helper.read8BitUnpackedToString(
|
do_check_eq(iccHelper.read8BitUnpackedToString(
|
||||||
(langShiftTable.length - PDU_NL_EXTENDED_ESCAPE - 1) * 2),
|
(langShiftTable.length - PDU_NL_EXTENDED_ESCAPE - 1) * 2),
|
||||||
langShiftTable.substring(PDU_NL_EXTENDED_ESCAPE + 1));
|
langShiftTable.substring(PDU_NL_EXTENDED_ESCAPE + 1));
|
||||||
|
|
||||||
@ -157,13 +160,14 @@ add_test(function test_read_8bit_unpacked_to_string() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify GsmPDUHelper#writeStringTo8BitUnpacked.
|
* Verify ICCPDUHelper#writeStringTo8BitUnpacked.
|
||||||
*
|
*
|
||||||
* Test writing GSM 8 bit alphabets.
|
* Test writing GSM 8 bit alphabets.
|
||||||
*/
|
*/
|
||||||
add_test(function test_write_string_to_8bit_unpacked() {
|
add_test(function test_write_string_to_8bit_unpacked() {
|
||||||
let worker = newUint8Worker();
|
let worker = newUint8Worker();
|
||||||
let helper = worker.GsmPDUHelper;
|
let helper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
||||||
const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
||||||
// Length of trailing 0xff.
|
// Length of trailing 0xff.
|
||||||
@ -171,7 +175,7 @@ add_test(function test_write_string_to_8bit_unpacked() {
|
|||||||
let str;
|
let str;
|
||||||
|
|
||||||
// Test 1, write GSM alphabets.
|
// Test 1, write GSM alphabets.
|
||||||
helper.writeStringTo8BitUnpacked(langTable.length + ffLen, langTable);
|
iccHelper.writeStringTo8BitUnpacked(langTable.length + ffLen, langTable);
|
||||||
|
|
||||||
for (let i = 0; i < langTable.length; i++) {
|
for (let i = 0; i < langTable.length; i++) {
|
||||||
do_check_eq(helper.readHexOctet(), i);
|
do_check_eq(helper.readHexOctet(), i);
|
||||||
@ -183,9 +187,9 @@ add_test(function test_write_string_to_8bit_unpacked() {
|
|||||||
|
|
||||||
// Test 2, write GSM extended alphabets.
|
// Test 2, write GSM extended alphabets.
|
||||||
str = "\u000c\u20ac";
|
str = "\u000c\u20ac";
|
||||||
helper.writeStringTo8BitUnpacked(4, str);
|
iccHelper.writeStringTo8BitUnpacked(4, str);
|
||||||
|
|
||||||
do_check_eq(helper.read8BitUnpackedToString(4), str);
|
do_check_eq(iccHelper.read8BitUnpackedToString(4), str);
|
||||||
|
|
||||||
// Test 3, write GSM and GSM extended alphabets.
|
// Test 3, write GSM and GSM extended alphabets.
|
||||||
// \u000c, \u20ac are from gsm extended alphabets.
|
// \u000c, \u20ac are from gsm extended alphabets.
|
||||||
@ -196,25 +200,26 @@ add_test(function test_write_string_to_8bit_unpacked() {
|
|||||||
// 1 octet for 1 gsm alphabet,
|
// 1 octet for 1 gsm alphabet,
|
||||||
// 2 octes for trailing 0xff.
|
// 2 octes for trailing 0xff.
|
||||||
// "Totally 7 octets are to be written."
|
// "Totally 7 octets are to be written."
|
||||||
helper.writeStringTo8BitUnpacked(7, str);
|
iccHelper.writeStringTo8BitUnpacked(7, str);
|
||||||
|
|
||||||
do_check_eq(helper.read8BitUnpackedToString(7), str);
|
do_check_eq(iccHelper.read8BitUnpackedToString(7), str);
|
||||||
|
|
||||||
run_next_test();
|
run_next_test();
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify GsmPDUHelper#writeStringTo8BitUnpacked with maximum octets written.
|
* Verify ICCPDUHelper#writeStringTo8BitUnpacked with maximum octets written.
|
||||||
*/
|
*/
|
||||||
add_test(function test_write_string_to_8bit_unpacked_with_max_octets_written() {
|
add_test(function test_write_string_to_8bit_unpacked_with_max_octets_written() {
|
||||||
let worker = newUint8Worker();
|
let worker = newUint8Worker();
|
||||||
let helper = worker.GsmPDUHelper;
|
let helper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
||||||
const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
||||||
|
|
||||||
// The maximum of the number of octets that can be written is 3.
|
// The maximum of the number of octets that can be written is 3.
|
||||||
// Only 3 characters shall be written even the length of the string is 4.
|
// Only 3 characters shall be written even the length of the string is 4.
|
||||||
helper.writeStringTo8BitUnpacked(3, langTable.substring(0, 4));
|
iccHelper.writeStringTo8BitUnpacked(3, langTable.substring(0, 4));
|
||||||
helper.writeHexOctet(0xff); // dummy octet.
|
helper.writeHexOctet(0xff); // dummy octet.
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
do_check_eq(helper.readHexOctet(), i);
|
do_check_eq(helper.readHexOctet(), i);
|
||||||
@ -224,74 +229,159 @@ add_test(function test_write_string_to_8bit_unpacked_with_max_octets_written() {
|
|||||||
// \u000c is GSM extended alphabet, 2 octets.
|
// \u000c is GSM extended alphabet, 2 octets.
|
||||||
// \u00a3 is GSM alphabet, 1 octet.
|
// \u00a3 is GSM alphabet, 1 octet.
|
||||||
let str = "\u000c\u00a3";
|
let str = "\u000c\u00a3";
|
||||||
helper.writeStringTo8BitUnpacked(3, str);
|
iccHelper.writeStringTo8BitUnpacked(3, str);
|
||||||
do_check_eq(helper.read8BitUnpackedToString(3), str);
|
do_check_eq(iccHelper.read8BitUnpackedToString(3), str);
|
||||||
|
|
||||||
str = "\u00a3\u000c";
|
str = "\u00a3\u000c";
|
||||||
helper.writeStringTo8BitUnpacked(3, str);
|
iccHelper.writeStringTo8BitUnpacked(3, str);
|
||||||
do_check_eq(helper.read8BitUnpackedToString(3), str);
|
do_check_eq(iccHelper.read8BitUnpackedToString(3), str);
|
||||||
|
|
||||||
// 2 GSM extended alphabets cost 4 octets, but maximum is 3, so only the 1st
|
// 2 GSM extended alphabets cost 4 octets, but maximum is 3, so only the 1st
|
||||||
// alphabet can be written.
|
// alphabet can be written.
|
||||||
str = "\u000c\u000c";
|
str = "\u000c\u000c";
|
||||||
helper.writeStringTo8BitUnpacked(3, str);
|
iccHelper.writeStringTo8BitUnpacked(3, str);
|
||||||
helper.writeHexOctet(0xff); // dummy octet.
|
helper.writeHexOctet(0xff); // dummy octet.
|
||||||
do_check_eq(helper.read8BitUnpackedToString(4), str.substring(0, 1));
|
do_check_eq(iccHelper.read8BitUnpackedToString(4), str.substring(0, 1));
|
||||||
|
|
||||||
run_next_test();
|
run_next_test();
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify GsmPDUHelper.writeAlphaIdentifier
|
* Verify ICCPDUHelper.readAlphaIdentifier
|
||||||
|
*/
|
||||||
|
add_test(function test_read_alpha_identifier() {
|
||||||
|
let worker = newUint8Worker();
|
||||||
|
let helper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
|
|
||||||
|
// UCS2: 0x80
|
||||||
|
let text = "TEST";
|
||||||
|
helper.writeHexOctet(0x80);
|
||||||
|
helper.writeUCS2String(text);
|
||||||
|
// Also write two unused octets.
|
||||||
|
let ffLen = 2;
|
||||||
|
for (let i = 0; i < ffLen; i++) {
|
||||||
|
helper.writeHexOctet(0xff);
|
||||||
|
}
|
||||||
|
do_check_eq(iccHelper.readAlphaIdentifier(1 + (2 * text.length) + ffLen), text);
|
||||||
|
|
||||||
|
// UCS2: 0x81
|
||||||
|
let array = [0x81, 0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff];
|
||||||
|
for (let i = 0; i < array.length; i++) {
|
||||||
|
helper.writeHexOctet(array[i]);
|
||||||
|
}
|
||||||
|
do_check_eq(iccHelper.readAlphaIdentifier(array.length), "Mozilla\u694a");
|
||||||
|
|
||||||
|
// UCS2: 0x82
|
||||||
|
let array2 = [0x82, 0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff];
|
||||||
|
for (let i = 0; i < array2.length; i++) {
|
||||||
|
helper.writeHexOctet(array2[i]);
|
||||||
|
}
|
||||||
|
do_check_eq(iccHelper.readAlphaIdentifier(array2.length), "Mozilla\u694a");
|
||||||
|
|
||||||
|
// GSM 8 Bit Unpacked
|
||||||
|
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
|
||||||
|
for (let i = 0; i < PDU_NL_EXTENDED_ESCAPE; i++) {
|
||||||
|
helper.writeHexOctet(i);
|
||||||
|
}
|
||||||
|
do_check_eq(iccHelper.readAlphaIdentifier(PDU_NL_EXTENDED_ESCAPE),
|
||||||
|
langTable.substring(0, PDU_NL_EXTENDED_ESCAPE));
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify ICCPDUHelper.writeAlphaIdentifier
|
||||||
*/
|
*/
|
||||||
add_test(function test_write_alpha_identifier() {
|
add_test(function test_write_alpha_identifier() {
|
||||||
let worker = newUint8Worker();
|
let worker = newUint8Worker();
|
||||||
let helper = worker.GsmPDUHelper;
|
let helper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
// Length of trailing 0xff.
|
// Length of trailing 0xff.
|
||||||
let ffLen = 2;
|
let ffLen = 2;
|
||||||
|
|
||||||
// Removal
|
// Removal
|
||||||
helper.writeAlphaIdentifier(10, null);
|
iccHelper.writeAlphaIdentifier(10, null);
|
||||||
do_check_eq(helper.readAlphaIdentifier(10), "");
|
do_check_eq(iccHelper.readAlphaIdentifier(10), "");
|
||||||
|
|
||||||
// GSM 8 bit
|
// GSM 8 bit
|
||||||
let str = "Mozilla";
|
let str = "Mozilla";
|
||||||
helper.writeAlphaIdentifier(str.length + ffLen, str);
|
iccHelper.writeAlphaIdentifier(str.length + ffLen, str);
|
||||||
do_check_eq(helper.readAlphaIdentifier(str.length + ffLen), str);
|
do_check_eq(iccHelper.readAlphaIdentifier(str.length + ffLen), str);
|
||||||
|
|
||||||
// UCS2
|
// UCS2
|
||||||
str = "Mozilla\u694a";
|
str = "Mozilla\u694a";
|
||||||
helper.writeAlphaIdentifier(str.length * 2 + ffLen, str);
|
iccHelper.writeAlphaIdentifier(str.length * 2 + ffLen, str);
|
||||||
// * 2 for each character will be encoded to UCS2 alphabets.
|
// * 2 for each character will be encoded to UCS2 alphabets.
|
||||||
do_check_eq(helper.readAlphaIdentifier(str.length * 2 + ffLen), str);
|
do_check_eq(iccHelper.readAlphaIdentifier(str.length * 2 + ffLen), str);
|
||||||
|
|
||||||
// Test with maximum octets written.
|
// Test with maximum octets written.
|
||||||
// 1 coding scheme (0x80) and 1 UCS2 character, total 3 octets.
|
// 1 coding scheme (0x80) and 1 UCS2 character, total 3 octets.
|
||||||
str = "\u694a";
|
str = "\u694a";
|
||||||
helper.writeAlphaIdentifier(3, str);
|
iccHelper.writeAlphaIdentifier(3, str);
|
||||||
do_check_eq(helper.readAlphaIdentifier(3), str);
|
do_check_eq(iccHelper.readAlphaIdentifier(3), str);
|
||||||
|
|
||||||
// 1 coding scheme (0x80) and 2 UCS2 characters, total 5 octets.
|
// 1 coding scheme (0x80) and 2 UCS2 characters, total 5 octets.
|
||||||
// numOctets is limited to 4, so only 1 UCS2 character can be written.
|
// numOctets is limited to 4, so only 1 UCS2 character can be written.
|
||||||
str = "\u694a\u694a";
|
str = "\u694a\u694a";
|
||||||
helper.writeAlphaIdentifier(4, str);
|
iccHelper.writeAlphaIdentifier(4, str);
|
||||||
helper.writeHexOctet(0xff); // dummy octet.
|
helper.writeHexOctet(0xff); // dummy octet.
|
||||||
do_check_eq(helper.readAlphaIdentifier(5), str.substring(0, 1));
|
do_check_eq(iccHelper.readAlphaIdentifier(5), str.substring(0, 1));
|
||||||
|
|
||||||
// Write 0 octet.
|
// Write 0 octet.
|
||||||
helper.writeAlphaIdentifier(0, "1");
|
iccHelper.writeAlphaIdentifier(0, "1");
|
||||||
helper.writeHexOctet(0xff); // dummy octet.
|
helper.writeHexOctet(0xff); // dummy octet.
|
||||||
do_check_eq(helper.readAlphaIdentifier(1), "");
|
do_check_eq(iccHelper.readAlphaIdentifier(1), "");
|
||||||
|
|
||||||
run_next_test();
|
run_next_test();
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify GsmPDUHelper.writeAlphaIdDiallingNumber
|
* Verify ICCPDUHelper.readAlphaIdDiallingNumber
|
||||||
|
*/
|
||||||
|
add_test(function test_read_alpha_id_dialling_number() {
|
||||||
|
let worker = newUint8Worker();
|
||||||
|
let helper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
|
let buf = worker.Buf;
|
||||||
|
const recordSize = 32;
|
||||||
|
|
||||||
|
function testReadAlphaIdDiallingNumber(contact) {
|
||||||
|
iccHelper.readAlphaIdentifier = function () {
|
||||||
|
return contact.alphaId;
|
||||||
|
};
|
||||||
|
|
||||||
|
iccHelper.readNumberWithLength = function () {
|
||||||
|
return contact.number;
|
||||||
|
};
|
||||||
|
|
||||||
|
let strLen = recordSize * 2;
|
||||||
|
buf.writeInt32(strLen); // fake length
|
||||||
|
helper.writeHexOctet(0xff); // fake CCP
|
||||||
|
helper.writeHexOctet(0xff); // fake EXT1
|
||||||
|
buf.writeStringDelimiter(strLen);
|
||||||
|
|
||||||
|
let contactR = iccHelper.readAlphaIdDiallingNumber(recordSize);
|
||||||
|
if (contact.alphaId == "" && contact.number == "") {
|
||||||
|
do_check_eq(contactR, null);
|
||||||
|
} else {
|
||||||
|
do_check_eq(contactR.alphaId, contact.alphaId);
|
||||||
|
do_check_eq(contactR.number, contact.number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testReadAlphaIdDiallingNumber({alphaId: "AlphaId", number: "0987654321"});
|
||||||
|
testReadAlphaIdDiallingNumber({alphaId: "", number: ""});
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify ICCPDUHelper.writeAlphaIdDiallingNumber
|
||||||
*/
|
*/
|
||||||
add_test(function test_write_alpha_id_dialling_number() {
|
add_test(function test_write_alpha_id_dialling_number() {
|
||||||
let worker = newUint8Worker();
|
let worker = newUint8Worker();
|
||||||
let helper = worker.GsmPDUHelper;
|
let helper = worker.ICCPDUHelper;
|
||||||
const recordSize = 32;
|
const recordSize = 32;
|
||||||
|
|
||||||
// Write a normal contact.
|
// Write a normal contact.
|
||||||
@ -349,11 +439,11 @@ add_test(function test_write_alpha_id_dialling_number() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify GsmPDUHelper.writeDiallingNumber
|
* Verify ICCPDUHelper.writeDiallingNumber
|
||||||
*/
|
*/
|
||||||
add_test(function test_write_dialling_number() {
|
add_test(function test_write_dialling_number() {
|
||||||
let worker = newUint8Worker();
|
let worker = newUint8Worker();
|
||||||
let helper = worker.GsmPDUHelper;
|
let helper = worker.ICCPDUHelper;
|
||||||
|
|
||||||
// with +
|
// with +
|
||||||
let number = "+123456";
|
let number = "+123456";
|
||||||
@ -375,6 +465,65 @@ add_test(function test_write_dialling_number() {
|
|||||||
run_next_test();
|
run_next_test();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify ICCPDUHelper.readNumberWithLength
|
||||||
|
*/
|
||||||
|
add_test(function test_read_number_with_length() {
|
||||||
|
let worker = newUint8Worker();
|
||||||
|
let helper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
|
let number = "123456789";
|
||||||
|
|
||||||
|
iccHelper.readDiallingNumber = function (numLen) {
|
||||||
|
return number.substring(0, numLen);
|
||||||
|
};
|
||||||
|
|
||||||
|
helper.writeHexOctet(number.length + 1);
|
||||||
|
helper.writeHexOctet(PDU_TOA_ISDN);
|
||||||
|
do_check_eq(iccHelper.readNumberWithLength(), number);
|
||||||
|
|
||||||
|
helper.writeHexOctet(0xff);
|
||||||
|
do_check_eq(iccHelper.readNumberWithLength(), null);
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify ICCPDUHelper.writeNumberWithLength
|
||||||
|
*/
|
||||||
|
add_test(function test_write_number_with_length() {
|
||||||
|
let worker = newUint8Worker();
|
||||||
|
let helper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
|
|
||||||
|
// without +
|
||||||
|
let number_1 = "123456789";
|
||||||
|
iccHelper.writeNumberWithLength(number_1);
|
||||||
|
let numLen = helper.readHexOctet();
|
||||||
|
do_check_eq(number_1, iccHelper.readDiallingNumber(numLen));
|
||||||
|
for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) {
|
||||||
|
do_check_eq(0xff, helper.readHexOctet());
|
||||||
|
}
|
||||||
|
|
||||||
|
// with +
|
||||||
|
let number_2 = "+987654321";
|
||||||
|
iccHelper.writeNumberWithLength(number_2);
|
||||||
|
numLen = helper.readHexOctet();
|
||||||
|
do_check_eq(number_2, iccHelper.readDiallingNumber(numLen));
|
||||||
|
for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) {
|
||||||
|
do_check_eq(0xff, helper.readHexOctet());
|
||||||
|
}
|
||||||
|
|
||||||
|
// null
|
||||||
|
let number_3;
|
||||||
|
iccHelper.writeNumberWithLength(number_3);
|
||||||
|
for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES + 1); i++) {
|
||||||
|
do_check_eq(0xff, helper.readHexOctet());
|
||||||
|
}
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify GsmPDUHelper.writeTimestamp
|
* Verify GsmPDUHelper.writeTimestamp
|
||||||
*/
|
*/
|
||||||
@ -648,7 +797,6 @@ add_test(function test_path_id_for_spid_and_spn() {
|
|||||||
add_test(function test_parse_pbr_tlvs() {
|
add_test(function test_parse_pbr_tlvs() {
|
||||||
let worker = newUint8Worker();
|
let worker = newUint8Worker();
|
||||||
let buf = worker.Buf;
|
let buf = worker.Buf;
|
||||||
let pduHelper = worker.GsmPDUHelper;
|
|
||||||
|
|
||||||
let pbrTlvs = [
|
let pbrTlvs = [
|
||||||
{tag: ICC_USIM_TYPE1_TAG,
|
{tag: ICC_USIM_TYPE1_TAG,
|
||||||
@ -864,6 +1012,7 @@ add_test(function test_update_email() {
|
|||||||
const NUM_TESTS = 2;
|
const NUM_TESTS = 2;
|
||||||
let worker = newUint8Worker();
|
let worker = newUint8Worker();
|
||||||
let pduHelper = worker.GsmPDUHelper;
|
let pduHelper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
let ril = worker.RIL;
|
let ril = worker.RIL;
|
||||||
ril.appType = CARD_APPTYPE_USIM;
|
ril.appType = CARD_APPTYPE_USIM;
|
||||||
let recordHelper = worker.ICCRecordHelper;
|
let recordHelper = worker.ICCRecordHelper;
|
||||||
@ -916,9 +1065,9 @@ add_test(function test_update_email() {
|
|||||||
let strLen = this.readInt32();
|
let strLen = this.readInt32();
|
||||||
let email;
|
let email;
|
||||||
if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) {
|
if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) {
|
||||||
email = pduHelper.read8BitUnpackedToString(recordSize);
|
email = iccHelper.read8BitUnpackedToString(recordSize);
|
||||||
} else {
|
} else {
|
||||||
email = pduHelper.read8BitUnpackedToString(recordSize - 2);
|
email = iccHelper.read8BitUnpackedToString(recordSize - 2);
|
||||||
do_check_eq(pduHelper.readHexOctet(), pbr.adn.sfi);
|
do_check_eq(pduHelper.readHexOctet(), pbr.adn.sfi);
|
||||||
do_check_eq(pduHelper.readHexOctet(), expectedAdnRecordId);
|
do_check_eq(pduHelper.readHexOctet(), expectedAdnRecordId);
|
||||||
}
|
}
|
||||||
@ -1005,6 +1154,7 @@ add_test(function test_update_anr() {
|
|||||||
const NUM_TESTS = 2;
|
const NUM_TESTS = 2;
|
||||||
let worker = newUint8Worker();
|
let worker = newUint8Worker();
|
||||||
let pduHelper = worker.GsmPDUHelper;
|
let pduHelper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
let ril = worker.RIL;
|
let ril = worker.RIL;
|
||||||
ril.appType = CARD_APPTYPE_USIM;
|
ril.appType = CARD_APPTYPE_USIM;
|
||||||
let recordHelper = worker.ICCRecordHelper;
|
let recordHelper = worker.ICCRecordHelper;
|
||||||
@ -1057,7 +1207,7 @@ add_test(function test_update_anr() {
|
|||||||
let strLen = this.readInt32();
|
let strLen = this.readInt32();
|
||||||
// EF_AAS, ignore.
|
// EF_AAS, ignore.
|
||||||
pduHelper.readHexOctet();
|
pduHelper.readHexOctet();
|
||||||
do_check_eq(pduHelper.readNumberWithLength(), expectedANR);
|
do_check_eq(iccHelper.readNumberWithLength(), expectedANR);
|
||||||
// EF_CCP, ignore.
|
// EF_CCP, ignore.
|
||||||
pduHelper.readHexOctet();
|
pduHelper.readHexOctet();
|
||||||
// EF_EXT1, ignore.
|
// EF_EXT1, ignore.
|
||||||
@ -1227,7 +1377,7 @@ add_test(function test_update_adn_like() {
|
|||||||
let ril = worker.RIL;
|
let ril = worker.RIL;
|
||||||
let record = worker.ICCRecordHelper;
|
let record = worker.ICCRecordHelper;
|
||||||
let io = worker.ICCIOHelper;
|
let io = worker.ICCIOHelper;
|
||||||
let pdu = worker.GsmPDUHelper;
|
let pdu = worker.ICCPDUHelper;
|
||||||
let buf = worker.Buf;
|
let buf = worker.Buf;
|
||||||
|
|
||||||
ril.appType = CARD_APPTYPE_SIM;
|
ril.appType = CARD_APPTYPE_SIM;
|
||||||
|
@ -997,6 +997,7 @@ add_test(function test_stk_event_download_language_selection() {
|
|||||||
let worker = newUint8SupportOutgoingIndexWorker();
|
let worker = newUint8SupportOutgoingIndexWorker();
|
||||||
let buf = worker.Buf;
|
let buf = worker.Buf;
|
||||||
let pduHelper = worker.GsmPDUHelper;
|
let pduHelper = worker.GsmPDUHelper;
|
||||||
|
let iccHelper = worker.ICCPDUHelper;
|
||||||
|
|
||||||
buf.sendParcel = function () {
|
buf.sendParcel = function () {
|
||||||
// Type
|
// Type
|
||||||
@ -1034,7 +1035,7 @@ add_test(function test_stk_event_download_language_selection() {
|
|||||||
// Language, Type-Length-Value
|
// Language, Type-Length-Value
|
||||||
do_check_eq(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_LANGUAGE);
|
do_check_eq(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_LANGUAGE);
|
||||||
do_check_eq(pduHelper.readHexOctet(), 2);
|
do_check_eq(pduHelper.readHexOctet(), 2);
|
||||||
do_check_eq(pduHelper.read8BitUnpackedToString(2), "zh");
|
do_check_eq(iccHelper.read8BitUnpackedToString(2), "zh");
|
||||||
|
|
||||||
run_next_test();
|
run_next_test();
|
||||||
};
|
};
|
||||||
|
@ -2872,6 +2872,9 @@ RequiredLayerStateForChildrenInternal(nsDisplayListBuilder* aBuilder,
|
|||||||
state > result) {
|
state > result) {
|
||||||
result = state;
|
result = state;
|
||||||
}
|
}
|
||||||
|
if (state == LAYER_ACTIVE_EMPTY && state > result) {
|
||||||
|
result = LAYER_ACTIVE_FORCE;
|
||||||
|
}
|
||||||
if (state == LAYER_NONE) {
|
if (state == LAYER_NONE) {
|
||||||
nsDisplayList* list = i->GetSameCoordinateSystemChildren();
|
nsDisplayList* list = i->GetSameCoordinateSystemChildren();
|
||||||
if (list) {
|
if (list) {
|
||||||
|
@ -208,13 +208,9 @@ abstract public class BrowserApp extends GeckoApp
|
|||||||
|
|
||||||
Log.d(LOGTAG, "BrowserApp.onTabChanged: " + tab.getId() + ": " + msg);
|
Log.d(LOGTAG, "BrowserApp.onTabChanged: " + tab.getId() + ": " + msg);
|
||||||
switch(msg) {
|
switch(msg) {
|
||||||
// We don't get a LOCATION_CHANGE event for the first about:home
|
|
||||||
// load, because the previous and current URIs are the
|
|
||||||
// same. That means it's OK to trigger a new favicon load
|
|
||||||
// at this point.
|
|
||||||
case LOCATION_CHANGE:
|
case LOCATION_CHANGE:
|
||||||
if (Tabs.getInstance().isSelectedTab(tab)) {
|
if (Tabs.getInstance().isSelectedTab(tab)) {
|
||||||
loadFavicon(tab);
|
maybeCancelFaviconLoad(tab);
|
||||||
}
|
}
|
||||||
// fall through
|
// fall through
|
||||||
case SELECTED:
|
case SELECTED:
|
||||||
@ -255,6 +251,9 @@ abstract public class BrowserApp extends GeckoApp
|
|||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PAGE_SHOW:
|
||||||
|
loadFavicon(tab);
|
||||||
|
break;
|
||||||
case LINK_FAVICON:
|
case LINK_FAVICON:
|
||||||
// If tab is not loading and the favicon is updated, we
|
// If tab is not loading and the favicon is updated, we
|
||||||
// want to load the image straight away. If tab is still
|
// want to load the image straight away. If tab is still
|
||||||
|
@ -126,6 +126,9 @@ public class GeckoAppShell
|
|||||||
static private final HashMap<String, String>
|
static private final HashMap<String, String>
|
||||||
mAlertCookies = new HashMap<String, String>();
|
mAlertCookies = new HashMap<String, String>();
|
||||||
|
|
||||||
|
// See also HardwareUtils.LOW_MEMORY_THRESHOLD_MB.
|
||||||
|
static private final int HIGH_MEMORY_DEVICE_THRESHOLD_MB = 768;
|
||||||
|
|
||||||
/* Keep in sync with constants found here:
|
/* Keep in sync with constants found here:
|
||||||
http://mxr.mozilla.org/mozilla-central/source/uriloader/base/nsIWebProgressListener.idl
|
http://mxr.mozilla.org/mozilla-central/source/uriloader/base/nsIWebProgressListener.idl
|
||||||
*/
|
*/
|
||||||
@ -199,6 +202,7 @@ public class GeckoAppShell
|
|||||||
}
|
}
|
||||||
public static native Message getNextMessageFromQueue(MessageQueue queue);
|
public static native Message getNextMessageFromQueue(MessageQueue queue);
|
||||||
public static native void onSurfaceTextureFrameAvailable(Object surfaceTexture, int id);
|
public static native void onSurfaceTextureFrameAvailable(Object surfaceTexture, int id);
|
||||||
|
public static native void dispatchMemoryPressure();
|
||||||
|
|
||||||
public static void registerGlobalExceptionHandler() {
|
public static void registerGlobalExceptionHandler() {
|
||||||
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||||
@ -1377,29 +1381,7 @@ public class GeckoAppShell
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isHighMemoryDevice() {
|
private static boolean isHighMemoryDevice() {
|
||||||
BufferedReader br = null;
|
return HardwareUtils.getMemSize() > HIGH_MEMORY_DEVICE_THRESHOLD_MB;
|
||||||
FileReader fr = null;
|
|
||||||
try {
|
|
||||||
fr = new FileReader("/proc/meminfo");
|
|
||||||
if (fr == null)
|
|
||||||
return false;
|
|
||||||
br = new BufferedReader(fr);
|
|
||||||
String line = br.readLine();
|
|
||||||
while (line != null && !line.startsWith("MemTotal")) {
|
|
||||||
line = br.readLine();
|
|
||||||
}
|
|
||||||
String[] tokens = line.split("\\s+");
|
|
||||||
if (tokens.length >= 2 && Long.parseLong(tokens[1]) >= 786432 /* 768MB in kb*/) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (fr != null)
|
|
||||||
fr.close();
|
|
||||||
} catch (IOException ioe) {}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -152,7 +152,7 @@ class MemoryMonitor extends BroadcastReceiver {
|
|||||||
if (level >= MEMORY_PRESSURE_MEDIUM) {
|
if (level >= MEMORY_PRESSURE_MEDIUM) {
|
||||||
//Only send medium or higher events because that's all that is used right now
|
//Only send medium or higher events because that's all that is used right now
|
||||||
if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
|
if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createLowMemoryEvent(level));
|
GeckoAppShell.dispatchMemoryPressure();
|
||||||
}
|
}
|
||||||
|
|
||||||
Favicons.clearMemCache();
|
Favicons.clearMemCache();
|
||||||
|
@ -6,16 +6,14 @@
|
|||||||
|
|
||||||
package org.mozilla.gecko;
|
package org.mozilla.gecko;
|
||||||
|
|
||||||
|
import org.mozilla.gecko.util.HardwareUtils;
|
||||||
|
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,7 +28,6 @@ public final class SysInfo {
|
|||||||
// avoid inconsistency, so we don't bother with synchronization for
|
// avoid inconsistency, so we don't bother with synchronization for
|
||||||
// these.
|
// these.
|
||||||
private static volatile int cpuCount = -1;
|
private static volatile int cpuCount = -1;
|
||||||
private static volatile int totalRAM = -1;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of cores on the device.
|
* Get the number of cores on the device.
|
||||||
@ -80,58 +77,10 @@ public final class SysInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the total memory of the device in MB by parsing /proc/meminfo.
|
* Wraps HardwareUtils so callers don't need to know about it.
|
||||||
*
|
|
||||||
* Of course, Android doesn't have a neat and tidy way to find total
|
|
||||||
* RAM, so we do it by parsing /proc/meminfo.
|
|
||||||
*
|
|
||||||
* @return 0 if a problem occurred, or memory size in MB.
|
|
||||||
*/
|
*/
|
||||||
public static int getMemSize() {
|
public static int getMemSize() {
|
||||||
if (totalRAM >= 0) {
|
return HardwareUtils.getMemSize();
|
||||||
return totalRAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r");
|
|
||||||
try {
|
|
||||||
// MemTotal will be one of the first three lines.
|
|
||||||
int i = 0;
|
|
||||||
String memTotal = null;
|
|
||||||
while (i++ < 3) {
|
|
||||||
memTotal = reader.readLine();
|
|
||||||
if (memTotal == null ||
|
|
||||||
memTotal.startsWith("MemTotal: ")) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
memTotal = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memTotal == null) {
|
|
||||||
return totalRAM = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse a line like this:
|
|
||||||
// MemTotal: 1605324 kB
|
|
||||||
Matcher m = Pattern.compile("^MemTotal:\\s+([0-9]+) kB\\s*$")
|
|
||||||
.matcher(memTotal);
|
|
||||||
if (m.matches()) {
|
|
||||||
String kb = m.group(1);
|
|
||||||
if (kb != null) {
|
|
||||||
return totalRAM = (Integer.parseInt(kb) / 1024);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.w(LOG_TAG, "Got unexpected MemTotal line: " + memTotal);
|
|
||||||
return totalRAM = 0;
|
|
||||||
} finally {
|
|
||||||
reader.close();
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException f) {
|
|
||||||
return totalRAM = 0;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return totalRAM = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
package org.mozilla.gecko.home;
|
package org.mozilla.gecko.home;
|
||||||
|
|
||||||
import org.mozilla.gecko.EditBookmarkDialog;
|
import org.mozilla.gecko.EditBookmarkDialog;
|
||||||
|
import org.mozilla.gecko.favicons.Favicons;
|
||||||
import org.mozilla.gecko.GeckoAppShell;
|
import org.mozilla.gecko.GeckoAppShell;
|
||||||
import org.mozilla.gecko.GeckoEvent;
|
import org.mozilla.gecko.GeckoEvent;
|
||||||
import org.mozilla.gecko.GeckoProfile;
|
import org.mozilla.gecko.GeckoProfile;
|
||||||
@ -40,6 +41,9 @@ abstract class HomeFragment extends Fragment {
|
|||||||
// Log Tag.
|
// Log Tag.
|
||||||
private static final String LOGTAG="GeckoHomeFragment";
|
private static final String LOGTAG="GeckoHomeFragment";
|
||||||
|
|
||||||
|
// Share MIME type.
|
||||||
|
private static final String SHARE_MIME_TYPE = "text/plain";
|
||||||
|
|
||||||
// Whether the fragment can load its content or not
|
// Whether the fragment can load its content or not
|
||||||
// This is used to defer data loading until the editing
|
// This is used to defer data loading until the editing
|
||||||
// mode animation ends.
|
// mode animation ends.
|
||||||
@ -91,6 +95,8 @@ abstract class HomeFragment extends Fragment {
|
|||||||
menu.findItem(R.id.home_remove).setVisible(false);
|
menu.findItem(R.id.home_remove).setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
menu.findItem(R.id.home_share).setVisible(!GeckoProfile.get(getActivity()).inGuestMode());
|
||||||
|
|
||||||
final boolean canOpenInReader = (info.display == Combined.DISPLAY_READER);
|
final boolean canOpenInReader = (info.display == Combined.DISPLAY_READER);
|
||||||
menu.findItem(R.id.home_open_in_reader).setVisible(canOpenInReader);
|
menu.findItem(R.id.home_open_in_reader).setVisible(canOpenInReader);
|
||||||
}
|
}
|
||||||
@ -111,6 +117,25 @@ abstract class HomeFragment extends Fragment {
|
|||||||
final Context context = getActivity().getApplicationContext();
|
final Context context = getActivity().getApplicationContext();
|
||||||
|
|
||||||
final int itemId = item.getItemId();
|
final int itemId = item.getItemId();
|
||||||
|
if (itemId == R.id.home_share) {
|
||||||
|
if (info.url == null) {
|
||||||
|
Log.e(LOGTAG, "Can't share because URL is null");
|
||||||
|
} else {
|
||||||
|
GeckoAppShell.openUriExternal(info.url, SHARE_MIME_TYPE, "", "",
|
||||||
|
Intent.ACTION_SEND, info.getDisplayTitle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemId == R.id.home_add_to_launcher) {
|
||||||
|
if (info.url == null) {
|
||||||
|
Log.e(LOGTAG, "Can't add to home screen because URL is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the largest cacheable icon size.
|
||||||
|
Favicons.getLargestFaviconForPage(info.url, new GeckoAppShell.CreateShortcutFaviconLoadedListener(info.url, info.getDisplayTitle()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (itemId == R.id.home_open_private_tab || itemId == R.id.home_open_new_tab) {
|
if (itemId == R.id.home_open_private_tab || itemId == R.id.home_open_new_tab) {
|
||||||
if (info.url == null) {
|
if (info.url == null) {
|
||||||
|
@ -178,10 +178,13 @@ size. -->
|
|||||||
<!ENTITY datareporting_wifi_title "&vendorShortName; location services">
|
<!ENTITY datareporting_wifi_title "&vendorShortName; location services">
|
||||||
<!ENTITY datareporting_wifi_summary "Help improve geolocation services for the Open Web by letting &brandShortName; collect and send anonymous cellular tower data">
|
<!ENTITY datareporting_wifi_summary "Help improve geolocation services for the Open Web by letting &brandShortName; collect and send anonymous cellular tower data">
|
||||||
|
|
||||||
<!ENTITY pref_update_autodownload "Automatic updates">
|
<!-- Localization note (pref_update_autodownload2) : This should mention downloading
|
||||||
|
specifically, since the pref only prevents automatic downloads and not the
|
||||||
|
actual notification that an update is available. -->
|
||||||
|
<!ENTITY pref_update_autodownload2 "Download updates automatically">
|
||||||
<!ENTITY pref_update_autodownload_wifi "Only over Wi-Fi">
|
<!ENTITY pref_update_autodownload_wifi "Only over Wi-Fi">
|
||||||
<!ENTITY pref_update_autodownload_disabled "Disabled">
|
<!ENTITY pref_update_autodownload_never "Never">
|
||||||
<!ENTITY pref_update_autodownload_enabled "Enabled">
|
<!ENTITY pref_update_autodownload_always "Always">
|
||||||
|
|
||||||
<!ENTITY quit "Quit">
|
<!ENTITY quit "Quit">
|
||||||
|
|
||||||
|
@ -14,10 +14,16 @@
|
|||||||
<item android:id="@+id/home_open_in_reader"
|
<item android:id="@+id/home_open_in_reader"
|
||||||
android:title="@string/contextmenu_open_in_reader"/>
|
android:title="@string/contextmenu_open_in_reader"/>
|
||||||
|
|
||||||
|
<item android:id="@+id/home_share"
|
||||||
|
android:title="@string/contextmenu_share"/>
|
||||||
|
|
||||||
<item android:id="@+id/home_edit_bookmark"
|
<item android:id="@+id/home_edit_bookmark"
|
||||||
android:title="@string/contextmenu_edit_bookmark"/>
|
android:title="@string/contextmenu_edit_bookmark"/>
|
||||||
|
|
||||||
<item android:id="@+id/home_remove"
|
<item android:id="@+id/home_remove"
|
||||||
android:title="@string/contextmenu_remove"/>
|
android:title="@string/contextmenu_remove"/>
|
||||||
|
|
||||||
|
<item android:id="@+id/home_add_to_launcher"
|
||||||
|
android:title="@string/contextmenu_add_to_launcher"/>
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -145,10 +145,10 @@
|
|||||||
<string name="pref_private_data_siteSettings">&pref_private_data_siteSettings2;</string>
|
<string name="pref_private_data_siteSettings">&pref_private_data_siteSettings2;</string>
|
||||||
<string name="pref_private_data_downloadFiles">&pref_private_data_downloadFiles;</string>
|
<string name="pref_private_data_downloadFiles">&pref_private_data_downloadFiles;</string>
|
||||||
<string name="pref_import_android">&pref_import_android;</string>
|
<string name="pref_import_android">&pref_import_android;</string>
|
||||||
<string name="pref_update_autodownload">&pref_update_autodownload;</string>
|
<string name="pref_update_autodownload">&pref_update_autodownload2;</string>
|
||||||
<string name="pref_update_autodownload_wifi">&pref_update_autodownload_wifi;</string>
|
<string name="pref_update_autodownload_wifi">&pref_update_autodownload_wifi;</string>
|
||||||
<string name="pref_update_autodownload_disabled">&pref_update_autodownload_disabled;</string>
|
<string name="pref_update_autodownload_disabled">&pref_update_autodownload_never;</string>
|
||||||
<string name="pref_update_autodownload_enabled">&pref_update_autodownload_enabled;</string>
|
<string name="pref_update_autodownload_enabled">&pref_update_autodownload_always;</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="pref_about_firefox">&pref_about_firefox;</string>
|
<string name="pref_about_firefox">&pref_about_firefox;</string>
|
||||||
|
@ -43,7 +43,9 @@ class StringHelper {
|
|||||||
"Open in New Tab",
|
"Open in New Tab",
|
||||||
"Open in Private Tab",
|
"Open in Private Tab",
|
||||||
"Edit",
|
"Edit",
|
||||||
"Remove"
|
"Remove",
|
||||||
|
"Share",
|
||||||
|
"Add to Home Screen"
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final String TITLE_PLACE_HOLDER = "Enter Search or Address";
|
public static final String TITLE_PLACE_HOLDER = "Enter Search or Address";
|
||||||
|
@ -151,7 +151,7 @@ public class testSettingsMenuItems extends PixelTest {
|
|||||||
|
|
||||||
// Automatic updates
|
// Automatic updates
|
||||||
if (AppConstants.MOZ_UPDATER) {
|
if (AppConstants.MOZ_UPDATER) {
|
||||||
String[] autoUpdateUi = { "Automatic updates", "Only over Wi-Fi", "Enabled", "Only over Wi-Fi", "Disabled" };
|
String[] autoUpdateUi = { "Download updates automatically", "Only over Wi-Fi", "Always", "Only over Wi-Fi", "Never" };
|
||||||
settingsMap.get("Customize").add(autoUpdateUi);
|
settingsMap.get("Customize").add(autoUpdateUi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,9 +21,9 @@ import java.util.List;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This test covers the opening and content of the Share Link pop-up list
|
* This test covers the opening and content of the Share Link pop-up list
|
||||||
* The test opens the Share menu from the app menu, the URL bar, and a link context menu.
|
* The test opens the Share menu from the app menu, the URL bar, a link context menu and the Awesomescreen tabs
|
||||||
*/
|
*/
|
||||||
public class testShareLink extends BaseTest {
|
public class testShareLink extends AboutHomeTest {
|
||||||
String url;
|
String url;
|
||||||
String urlTitle = "Big Link";
|
String urlTitle = "Big Link";
|
||||||
|
|
||||||
@ -37,6 +37,9 @@ public class testShareLink extends BaseTest {
|
|||||||
ArrayList<String> shareOptions;
|
ArrayList<String> shareOptions;
|
||||||
blockForGeckoReady();
|
blockForGeckoReady();
|
||||||
|
|
||||||
|
// FIXME: This is a temporary hack workaround for a permissions problem.
|
||||||
|
openAboutHomeTab(AboutHomeTabs.READING_LIST);
|
||||||
|
|
||||||
inputAndLoadUrl(url);
|
inputAndLoadUrl(url);
|
||||||
verifyPageTitle(urlTitle); // Waiting for page title to ensure the page is loaded
|
verifyPageTitle(urlTitle); // Waiting for page title to ensure the page is loaded
|
||||||
|
|
||||||
@ -66,6 +69,71 @@ public class testShareLink extends BaseTest {
|
|||||||
float left = mDriver.getGeckoLeft() + mDriver.getGeckoWidth() / 2;
|
float left = mDriver.getGeckoLeft() + mDriver.getGeckoWidth() / 2;
|
||||||
mSolo.clickLongOnScreen(left, top);
|
mSolo.clickLongOnScreen(left, top);
|
||||||
verifySharePopup("Share Link",shareOptions,"Link");
|
verifySharePopup("Share Link",shareOptions,"Link");
|
||||||
|
|
||||||
|
// Test the share popup in the Bookmarks page
|
||||||
|
openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
|
||||||
|
|
||||||
|
final ListView bookmarksList = findListViewWithTag("bookmarks");
|
||||||
|
mAsserter.is(waitForNonEmptyListToLoad(bookmarksList), true, "list is properly loaded");
|
||||||
|
|
||||||
|
int headerViewsCount = bookmarksList.getHeaderViewsCount();
|
||||||
|
View bookmarksItem = bookmarksList.getChildAt(headerViewsCount);
|
||||||
|
if (bookmarksItem == null) {
|
||||||
|
mAsserter.dumpLog("no child at index " + headerViewsCount + "; waiting for one...");
|
||||||
|
Condition listWaitCondition = new Condition() {
|
||||||
|
@Override
|
||||||
|
public boolean isSatisfied() {
|
||||||
|
if (bookmarksList.getChildAt(bookmarksList.getHeaderViewsCount()) == null)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
waitForCondition(listWaitCondition, MAX_WAIT_MS);
|
||||||
|
headerViewsCount = bookmarksList.getHeaderViewsCount();
|
||||||
|
bookmarksItem = bookmarksList.getChildAt(headerViewsCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
mSolo.clickLongOnView(bookmarksItem);
|
||||||
|
verifySharePopup(shareOptions,"bookmarks");
|
||||||
|
|
||||||
|
// Prepopulate top sites with history items to overflow tiles.
|
||||||
|
// We are trying to move away from using reflection and doing more black-box testing.
|
||||||
|
inputAndLoadUrl(getAbsoluteUrl("/robocop/robocop_blank_01.html"));
|
||||||
|
inputAndLoadUrl(getAbsoluteUrl("/robocop/robocop_blank_02.html"));
|
||||||
|
inputAndLoadUrl(getAbsoluteUrl("/robocop/robocop_blank_03.html"));
|
||||||
|
inputAndLoadUrl(getAbsoluteUrl("/robocop/robocop_blank_04.html"));
|
||||||
|
if (mDevice.type.equals("tablet")) {
|
||||||
|
// Tablets have more tile spaces to fill.
|
||||||
|
inputAndLoadUrl(getAbsoluteUrl("/robocop/robocop_blank_05.html"));
|
||||||
|
inputAndLoadUrl(getAbsoluteUrl("/robocop/robocop_boxes.html"));
|
||||||
|
inputAndLoadUrl(getAbsoluteUrl("/robocop/robocop_search.html"));
|
||||||
|
inputAndLoadUrl(getAbsoluteUrl("/robocop/robocop_text_page.html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the share popup in Top Sites.
|
||||||
|
openAboutHomeTab(AboutHomeTabs.TOP_SITES);
|
||||||
|
|
||||||
|
// Scroll down a bit so that the top sites list has more items on screen.
|
||||||
|
int width = mDriver.getGeckoWidth();
|
||||||
|
int height = mDriver.getGeckoHeight();
|
||||||
|
mActions.drag(width / 2, width / 2, height - 10, height / 2);
|
||||||
|
|
||||||
|
ListView topSitesList = findListViewWithTag("top_sites");
|
||||||
|
mAsserter.is(waitForNonEmptyListToLoad(topSitesList), true, "list is properly loaded");
|
||||||
|
View mostVisitedItem = topSitesList.getChildAt(topSitesList.getHeaderViewsCount());
|
||||||
|
mSolo.clickLongOnView(mostVisitedItem);
|
||||||
|
verifySharePopup(shareOptions,"top_sites");
|
||||||
|
|
||||||
|
// Test the share popup in the Most Recent tab
|
||||||
|
openAboutHomeTab(AboutHomeTabs.MOST_RECENT);
|
||||||
|
|
||||||
|
ListView mostRecentList = findListViewWithTag("most_recent");
|
||||||
|
mAsserter.is(waitForNonEmptyListToLoad(mostRecentList), true, "list is properly loaded");
|
||||||
|
|
||||||
|
// Getting second child after header views because the first is the "Today" label
|
||||||
|
View mostRecentItem = mostRecentList.getChildAt(mostRecentList.getHeaderViewsCount() + 1);
|
||||||
|
mSolo.clickLongOnView(mostRecentItem);
|
||||||
|
verifySharePopup(shareOptions,"most recent");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void verifySharePopup(ArrayList<String> shareOptions, String openedFrom) {
|
public void verifySharePopup(ArrayList<String> shareOptions, String openedFrom) {
|
||||||
|
@ -546,6 +546,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
|||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case ADDED:
|
case ADDED:
|
||||||
|
case CLOSED:
|
||||||
updateTabCount(tabs.getDisplayCount());
|
updateTabCount(tabs.getDisplayCount());
|
||||||
break;
|
break;
|
||||||
case RESTORED:
|
case RESTORED:
|
||||||
@ -588,12 +589,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
|||||||
case LOCATION_CHANGE:
|
case LOCATION_CHANGE:
|
||||||
// A successful location change will cause Tab to notify
|
// A successful location change will cause Tab to notify
|
||||||
// us of a title change, so we don't update the title here.
|
// us of a title change, so we don't update the title here.
|
||||||
// And there's no point in refreshing the UI
|
refresh();
|
||||||
// if the page is the same.
|
|
||||||
final String oldURL = (String) data;
|
|
||||||
if (!TextUtils.equals(oldURL, tab.getURL())) {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CLOSED:
|
case CLOSED:
|
||||||
|
@ -12,6 +12,7 @@ import android.os.Build;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ViewConfiguration;
|
import android.view.ViewConfiguration;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
@ -21,17 +22,13 @@ public final class HardwareUtils {
|
|||||||
private static final String LOGTAG = "GeckoHardwareUtils";
|
private static final String LOGTAG = "GeckoHardwareUtils";
|
||||||
|
|
||||||
// Minimum memory threshold for a device to be considered
|
// Minimum memory threshold for a device to be considered
|
||||||
// a low memory platform (see sIsLowMemoryPlatform). This value
|
// a low memory platform (see isLowMemoryPlatform). This value
|
||||||
// has be in sync with Gecko's equivalent threshold (defined in
|
// has be in sync with Gecko's equivalent threshold (defined in
|
||||||
// xpcom/base/nsMemoryImpl.cpp) and should only be used in cases
|
// xpcom/base/nsMemoryImpl.cpp) and should only be used in cases
|
||||||
// where we can't depend on Gecko to be up and running e.g. show/hide
|
// where we can't depend on Gecko to be up and running e.g. show/hide
|
||||||
// reading list capabilities in HomePager.
|
// reading list capabilities in HomePager.
|
||||||
private static final int LOW_MEMORY_THRESHOLD_KB = 384 * 1024;
|
private static final int LOW_MEMORY_THRESHOLD_MB = 384;
|
||||||
|
private static volatile int sTotalRAM = -1;
|
||||||
private static final String PROC_MEMINFO_FILE = "/proc/meminfo";
|
|
||||||
|
|
||||||
private static final Pattern PROC_MEMTOTAL_FORMAT =
|
|
||||||
Pattern.compile("^MemTotal:[ \t]*([0-9]*)[ \t]kB");
|
|
||||||
|
|
||||||
private static Context sContext;
|
private static Context sContext;
|
||||||
|
|
||||||
@ -39,7 +36,6 @@ public final class HardwareUtils {
|
|||||||
private static Boolean sIsSmallTablet;
|
private static Boolean sIsSmallTablet;
|
||||||
private static Boolean sIsTelevision;
|
private static Boolean sIsTelevision;
|
||||||
private static Boolean sHasMenuButton;
|
private static Boolean sHasMenuButton;
|
||||||
private static Boolean sIsLowMemoryPlatform;
|
|
||||||
|
|
||||||
private HardwareUtils() {
|
private HardwareUtils() {
|
||||||
}
|
}
|
||||||
@ -93,42 +89,73 @@ public final class HardwareUtils {
|
|||||||
return sHasMenuButton;
|
return sHasMenuButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isLowMemoryPlatform() {
|
/**
|
||||||
if (sIsLowMemoryPlatform == null) {
|
* Fetch the total memory of the device in MB by parsing /proc/meminfo.
|
||||||
RandomAccessFile fileReader = null;
|
*
|
||||||
try {
|
* Of course, Android doesn't have a neat and tidy way to find total
|
||||||
fileReader = new RandomAccessFile(PROC_MEMINFO_FILE, "r");
|
* RAM, so we do it by parsing /proc/meminfo.
|
||||||
|
*
|
||||||
// Defaults to false
|
* @return 0 if a problem occurred, or memory size in MB.
|
||||||
long totalMem = LOW_MEMORY_THRESHOLD_KB;
|
*/
|
||||||
|
public static int getMemSize() {
|
||||||
String line = null;
|
if (sTotalRAM >= 0) {
|
||||||
while ((line = fileReader.readLine()) != null) {
|
return sTotalRAM;
|
||||||
final Matcher matcher = PROC_MEMTOTAL_FORMAT.matcher(line);
|
|
||||||
if (matcher.find()) {
|
|
||||||
totalMem = Long.parseLong(matcher.group(1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sIsLowMemoryPlatform = (totalMem < LOW_MEMORY_THRESHOLD_KB);
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Fallback to false if we fail to read meminfo
|
|
||||||
// for some reason.
|
|
||||||
Log.w(LOGTAG, "Could not read " + PROC_MEMINFO_FILE + "." +
|
|
||||||
"Falling back to isLowMemoryPlatform = false", e);
|
|
||||||
sIsLowMemoryPlatform = false;
|
|
||||||
} finally {
|
|
||||||
if (fileReader != null) {
|
|
||||||
try {
|
|
||||||
fileReader.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sIsLowMemoryPlatform;
|
try {
|
||||||
|
RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r");
|
||||||
|
try {
|
||||||
|
// MemTotal will be one of the first three lines.
|
||||||
|
int i = 0;
|
||||||
|
String memTotal = null;
|
||||||
|
while (i++ < 3) {
|
||||||
|
memTotal = reader.readLine();
|
||||||
|
if (memTotal == null ||
|
||||||
|
memTotal.startsWith("MemTotal: ")) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memTotal = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memTotal == null) {
|
||||||
|
return sTotalRAM = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a line like this:
|
||||||
|
// MemTotal: 1605324 kB
|
||||||
|
Matcher m = Pattern.compile("^MemTotal:\\s+([0-9]+) kB\\s*$")
|
||||||
|
.matcher(memTotal);
|
||||||
|
if (m.matches()) {
|
||||||
|
String kb = m.group(1);
|
||||||
|
if (kb != null) {
|
||||||
|
sTotalRAM = (Integer.parseInt(kb) / 1024);
|
||||||
|
Log.d(LOGTAG, "System memory: " + sTotalRAM + "MB.");
|
||||||
|
return sTotalRAM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.w(LOGTAG, "Got unexpected MemTotal line: " + memTotal);
|
||||||
|
return sTotalRAM = 0;
|
||||||
|
} finally {
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
|
} catch (FileNotFoundException f) {
|
||||||
|
return sTotalRAM = 0;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return sTotalRAM = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLowMemoryPlatform() {
|
||||||
|
final int memSize = getMemSize();
|
||||||
|
|
||||||
|
// Fallback to false if we fail to read meminfo
|
||||||
|
// for some reason.
|
||||||
|
if (memSize == 0) {
|
||||||
|
Log.w(LOGTAG, "Could not compute system memory. Falling back to isLowMemoryPlatform = false.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return memSize < LOW_MEMORY_THRESHOLD_MB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,25 @@ Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable(JNIEnv * arg
|
|||||||
|
|
||||||
#ifdef JNI_STUBS
|
#ifdef JNI_STUBS
|
||||||
|
|
||||||
|
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure_t)(JNIEnv *, jclass);
|
||||||
|
static Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure_t f_Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure;
|
||||||
|
extern "C" NS_EXPORT void JNICALL
|
||||||
|
Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure(JNIEnv * arg0, jclass arg1) {
|
||||||
|
if (!f_Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure) {
|
||||||
|
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
|
||||||
|
"JNI Function called before it was loaded");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
f_Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure(arg0, arg1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JNI_BINDINGS
|
||||||
|
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure", &f_Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JNI_STUBS
|
||||||
|
|
||||||
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash_t)(JNIEnv *, jclass, jstring);
|
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash_t)(JNIEnv *, jclass, jstring);
|
||||||
static Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash_t f_Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash;
|
static Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash_t f_Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash;
|
||||||
extern "C" NS_EXPORT void JNICALL
|
extern "C" NS_EXPORT void JNICALL
|
||||||
|
@ -23,11 +23,11 @@ var popup = window.open("seek_with_sound.ogg");
|
|||||||
popup.addEventListener("load", function onLoad() {
|
popup.addEventListener("load", function onLoad() {
|
||||||
popup.removeEventListener("load", onLoad);
|
popup.removeEventListener("load", onLoad);
|
||||||
var video = getMediaElement(popup);
|
var video = getMediaElement(popup);
|
||||||
if (video.readyState >= video.HAVE_METADATA)
|
if (!video.paused)
|
||||||
runTestVideo(video);
|
runTestVideo(video);
|
||||||
else {
|
else {
|
||||||
video.addEventListener("loadedmetadata", function onLoadedMetaData() {
|
video.addEventListener("play", function onPlay() {
|
||||||
video.removeEventListener("loadedmetadata", onLoadedMetaData);
|
video.removeEventListener("play", onPlay);
|
||||||
runTestVideo(video);
|
runTestVideo(video);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -46,11 +46,11 @@ function runTestAudioPre() {
|
|||||||
popup.addEventListener("load", function onLoad() {
|
popup.addEventListener("load", function onLoad() {
|
||||||
popup.removeEventListener("load", onLoad);
|
popup.removeEventListener("load", onLoad);
|
||||||
var audio = getMediaElement(popup);
|
var audio = getMediaElement(popup);
|
||||||
if (audio.readyState >= audio.HAVE_METADATA)
|
if (!audio.paused)
|
||||||
runTestAudio(audio);
|
runTestAudio(audio);
|
||||||
else {
|
else {
|
||||||
audio.addEventListener("loadedmetadata", function onLoadedMetaData() {
|
audio.addEventListener("play", function onPlay() {
|
||||||
audio.removeEventListener("loadedmetadata", onLoadedMetaData);
|
audio.removeEventListener("play", onPlay);
|
||||||
runTestAudio(audio);
|
runTestAudio(audio);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -59,8 +59,9 @@ function runTestAudioPre() {
|
|||||||
|
|
||||||
function runTestAudio(aAudio) {
|
function runTestAudio(aAudio) {
|
||||||
var boundingRect = aAudio.getBoundingClientRect();
|
var boundingRect = aAudio.getBoundingClientRect();
|
||||||
var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
|
var isAndroid = navigator.userAgent.contains("Android");
|
||||||
var expectedHeight = isAndroid ? 123 : 28;
|
var expectedHeight = isAndroid ? 123 : 28;
|
||||||
|
info("User agent (help diagnose bug #943556): " + navigator.userAgent);
|
||||||
is(boundingRect.height, expectedHeight,
|
is(boundingRect.height, expectedHeight,
|
||||||
"Height of audio element should be " + expectedHeight + ", which is equal to the controls bar.");
|
"Height of audio element should be " + expectedHeight + ", which is equal to the controls bar.");
|
||||||
popup.close();
|
popup.close();
|
||||||
|
@ -404,7 +404,7 @@
|
|||||||
|
|
||||||
<method name="toggleHistoryPopup">
|
<method name="toggleHistoryPopup">
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
if (!this.popup.mPopupOpen)
|
if (!this.popup.popupOpen)
|
||||||
this.showHistoryPopup();
|
this.showHistoryPopup();
|
||||||
else
|
else
|
||||||
this.closePopup();
|
this.closePopup();
|
||||||
@ -460,7 +460,7 @@
|
|||||||
if (!this.disableKeyNavigation && !aEvent.ctrlKey && !aEvent.altKey) {
|
if (!this.disableKeyNavigation && !aEvent.ctrlKey && !aEvent.altKey) {
|
||||||
switch (aEvent.keyCode) {
|
switch (aEvent.keyCode) {
|
||||||
case KeyEvent.DOM_VK_TAB:
|
case KeyEvent.DOM_VK_TAB:
|
||||||
if (this.tabScrolling && this.popup.mPopupOpen)
|
if (this.tabScrolling && this.popup.popupOpen)
|
||||||
cancel = this.mController.handleKeyNavigation(aEvent.shiftKey ?
|
cancel = this.mController.handleKeyNavigation(aEvent.shiftKey ?
|
||||||
KeyEvent.DOM_VK_UP :
|
KeyEvent.DOM_VK_UP :
|
||||||
KeyEvent.DOM_VK_DOWN);
|
KeyEvent.DOM_VK_DOWN);
|
||||||
|
@ -1180,17 +1180,20 @@ WebGLProxy.prototype = {
|
|||||||
* Returns the framebuffer property value for the specified WebGL parameter.
|
* Returns the framebuffer property value for the specified WebGL parameter.
|
||||||
* If no framebuffer binding is available, null is returned.
|
* If no framebuffer binding is available, null is returned.
|
||||||
*
|
*
|
||||||
|
* @param string type
|
||||||
|
* The framebuffer object attachment point, for example "COLOR_ATTACHMENT0".
|
||||||
* @param string name
|
* @param string name
|
||||||
* The WebGL parameter name, for example "BLEND_COLOR".
|
* The WebGL parameter name, for example "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME".
|
||||||
|
* If unspecified, defaults to "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE".
|
||||||
* @return any
|
* @return any
|
||||||
* The corresponding parameter's value.
|
* The corresponding parameter's value.
|
||||||
*/
|
*/
|
||||||
_getFramebufferAttachmentParameter: function(type, name) {
|
_getFramebufferAttachmentParameter: function(type, name = "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE") {
|
||||||
if (!this._getParameter("FRAMEBUFFER_BINDING")) {
|
if (!this._getParameter("FRAMEBUFFER_BINDING")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let gl = this._gl;
|
let gl = this._gl;
|
||||||
return gl.getFramebufferAttachmentParameter(gl.RENDERBUFFER, gl[type], gl[name]);
|
return gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl[type], gl[name]);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1281,9 +1284,19 @@ WebGLProxy.prototype = {
|
|||||||
_enableHighlighting: function() {
|
_enableHighlighting: function() {
|
||||||
let gl = this._gl;
|
let gl = this._gl;
|
||||||
|
|
||||||
// Avoid changing the blending params when rendering to a depth texture.
|
// Avoid changing the blending params when "rendering to texture".
|
||||||
let format = this._getRenderbufferParameter("RENDERBUFFER_INTERNAL_FORMAT");
|
|
||||||
if (format == gl.DEPTH_COMPONENT16) {
|
// Check drawing to a custom framebuffer bound to the default renderbuffer.
|
||||||
|
let hasFramebuffer = this._getParameter("FRAMEBUFFER_BINDING");
|
||||||
|
let hasRenderbuffer = this._getParameter("RENDERBUFFER_BINDING");
|
||||||
|
if (hasFramebuffer && !hasRenderbuffer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check drawing to a depth or stencil component of the framebuffer.
|
||||||
|
let writesDepth = this._getFramebufferAttachmentParameter("DEPTH_ATTACHMENT");
|
||||||
|
let writesStencil = this._getFramebufferAttachmentParameter("STENCIL_ATTACHMENT");
|
||||||
|
if (writesDepth || writesStencil) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,8 +41,7 @@
|
|||||||
#include "nsPluginInstanceOwner.h"
|
#include "nsPluginInstanceOwner.h"
|
||||||
#include "nsSurfaceTexture.h"
|
#include "nsSurfaceTexture.h"
|
||||||
#include "GeckoProfiler.h"
|
#include "GeckoProfiler.h"
|
||||||
|
#include "nsMemoryPressure.h"
|
||||||
#include "GeckoProfiler.h"
|
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
@ -839,6 +838,12 @@ Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable(JNIEnv* jenv
|
|||||||
st->NotifyFrameAvailable();
|
st->NotifyFrameAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_EXPORT void JNICALL
|
||||||
|
Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure(JNIEnv* jenv, jclass)
|
||||||
|
{
|
||||||
|
NS_DispatchMemoryPressure(MemPressure_New);
|
||||||
|
}
|
||||||
|
|
||||||
NS_EXPORT jdouble JNICALL
|
NS_EXPORT jdouble JNICALL
|
||||||
Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(JNIEnv *jenv, jclass jc)
|
Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(JNIEnv *jenv, jclass jc)
|
||||||
{
|
{
|
||||||
|
@ -496,9 +496,6 @@ MetroInput::OnPointerPressed(UI::Core::ICoreWindow* aSender,
|
|||||||
mRecognizerWantsEvents = true;
|
mRecognizerWantsEvents = true;
|
||||||
mCancelable = true;
|
mCancelable = true;
|
||||||
mCanceledIds.Clear();
|
mCanceledIds.Clear();
|
||||||
} else {
|
|
||||||
// Only the first touchstart can be canceled.
|
|
||||||
mCancelable = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InitTouchEventTouchList(touchEvent);
|
InitTouchEventTouchList(touchEvent);
|
||||||
@ -1144,7 +1141,7 @@ MetroInput::DeliverNextQueuedTouchEvent()
|
|||||||
// Test for chrome vs. content target. To do this we only use the first touch
|
// Test for chrome vs. content target. To do this we only use the first touch
|
||||||
// point since that will be the input batch target. Cache this for touch events
|
// point since that will be the input batch target. Cache this for touch events
|
||||||
// since HitTestChrome has to send a dom event.
|
// since HitTestChrome has to send a dom event.
|
||||||
if (mCancelable && event->message == NS_TOUCH_START) {
|
if (mCancelable && event->message == NS_TOUCH_START && mTouches.Count() == 1) {
|
||||||
nsRefPtr<Touch> touch = event->touches[0];
|
nsRefPtr<Touch> touch = event->touches[0];
|
||||||
LayoutDeviceIntPoint pt = LayoutDeviceIntPoint::FromUntyped(touch->mRefPoint);
|
LayoutDeviceIntPoint pt = LayoutDeviceIntPoint::FromUntyped(touch->mRefPoint);
|
||||||
bool apzIntersect = mWidget->ApzHitTest(mozilla::ScreenIntPoint(pt.x, pt.y));
|
bool apzIntersect = mWidget->ApzHitTest(mozilla::ScreenIntPoint(pt.x, pt.y));
|
||||||
@ -1153,7 +1150,7 @@ MetroInput::DeliverNextQueuedTouchEvent()
|
|||||||
|
|
||||||
// If this event is destined for chrome, deliver it directly there bypassing
|
// If this event is destined for chrome, deliver it directly there bypassing
|
||||||
// the apz.
|
// the apz.
|
||||||
if (!mCancelable && mChromeHitTestCacheForTouch) {
|
if (mChromeHitTestCacheForTouch) {
|
||||||
DUMP_TOUCH_IDS("DOM(1)", event);
|
DUMP_TOUCH_IDS("DOM(1)", event);
|
||||||
mWidget->DispatchEvent(event, status);
|
mWidget->DispatchEvent(event, status);
|
||||||
return;
|
return;
|
||||||
@ -1167,7 +1164,7 @@ MetroInput::DeliverNextQueuedTouchEvent()
|
|||||||
DUMP_TOUCH_IDS("APZC(1)", event);
|
DUMP_TOUCH_IDS("APZC(1)", event);
|
||||||
mWidget->ApzReceiveInputEvent(event, &mTargetAPZCGuid, &transformedEvent);
|
mWidget->ApzReceiveInputEvent(event, &mTargetAPZCGuid, &transformedEvent);
|
||||||
DUMP_TOUCH_IDS("DOM(2)", event);
|
DUMP_TOUCH_IDS("DOM(2)", event);
|
||||||
mWidget->DispatchEvent(mChromeHitTestCacheForTouch ? event : &transformedEvent, status);
|
mWidget->DispatchEvent(&transformedEvent, status);
|
||||||
if (event->message == NS_TOUCH_START) {
|
if (event->message == NS_TOUCH_START) {
|
||||||
mContentConsumingTouch = (nsEventStatus_eConsumeNoDefault == status);
|
mContentConsumingTouch = (nsEventStatus_eConsumeNoDefault == status);
|
||||||
// If we know content wants touch here, we can bail early on mCancelable
|
// If we know content wants touch here, we can bail early on mCancelable
|
||||||
@ -1210,9 +1207,7 @@ MetroInput::DeliverNextQueuedTouchEvent()
|
|||||||
if (mContentConsumingTouch) {
|
if (mContentConsumingTouch) {
|
||||||
// Only translate if we're dealing with web content that's transformed
|
// Only translate if we're dealing with web content that's transformed
|
||||||
// by the apzc.
|
// by the apzc.
|
||||||
if (!mChromeHitTestCacheForTouch) {
|
TransformTouchEvent(event);
|
||||||
TransformTouchEvent(event);
|
|
||||||
}
|
|
||||||
DUMP_TOUCH_IDS("DOM(3)", event);
|
DUMP_TOUCH_IDS("DOM(3)", event);
|
||||||
mWidget->DispatchEvent(event, status);
|
mWidget->DispatchEvent(event, status);
|
||||||
return;
|
return;
|
||||||
@ -1228,9 +1223,7 @@ MetroInput::DeliverNextQueuedTouchEvent()
|
|||||||
DispatchTouchCancel(event);
|
DispatchTouchCancel(event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!mChromeHitTestCacheForTouch) {
|
TransformTouchEvent(event);
|
||||||
TransformTouchEvent(event);
|
|
||||||
}
|
|
||||||
DUMP_TOUCH_IDS("DOM(4)", event);
|
DUMP_TOUCH_IDS("DOM(4)", event);
|
||||||
mWidget->DispatchEvent(event, status);
|
mWidget->DispatchEvent(event, status);
|
||||||
}
|
}
|
||||||
|