Merge fx-team to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-02-02 17:06:25 -05:00
commit 86d6f59c45
85 changed files with 49882 additions and 46981 deletions

View File

@ -1,11 +1,21 @@
const TEST_PAGE = "http://mochi.test:8888/browser/browser/base/content/test/general/file_double_close_tab.html";
let expectingDialog = false;
let wantToClose = true;
let resolveDialogPromise;
function onTabModalDialogLoaded(node) {
ok(expectingDialog, "Should be expecting this dialog.");
expectingDialog = false;
// This accepts the dialog, closing it
node.Dialog.ui.button0.click();
if (wantToClose) {
// This accepts the dialog, closing it
node.Dialog.ui.button0.click();
} else {
// This keeps the page open
node.Dialog.ui.button1.click();
}
if (resolveDialogPromise) {
resolveDialogPromise();
}
}
@ -41,4 +51,25 @@ add_task(function* closeWindowWithMultipleTabsIncludingOneBeforeUnload() {
yield windowClosedPromise;
ok(!expectingDialog, "There should have been a dialog.");
ok(newWin.closed, "Window should be closed.");
Services.prefs.clearUserPref("browser.tabs.warnOnClose");
});
add_task(function* closeWindoWithSingleTabTwice() {
let newWin = yield promiseOpenAndLoadWindow({}, true);
let firstTab = newWin.gBrowser.selectedTab;
yield promiseTabLoadEvent(firstTab, TEST_PAGE);
let windowClosedPromise = promiseWindowWillBeClosed(newWin);
expectingDialog = true;
wantToClose = false;
let firstDialogShownPromise = new Promise((resolve, reject) => { resolveDialogPromise = resolve; });
document.getAnonymousElementByAttribute(firstTab, "anonid", "close-button").click();
yield firstDialogShownPromise;
info("Got initial dialog, now trying again");
expectingDialog = true;
wantToClose = true;
resolveDialogPromise = null;
document.getAnonymousElementByAttribute(firstTab, "anonid", "close-button").click();
yield windowClosedPromise;
ok(!expectingDialog, "There should have been a dialog.");
ok(newWin.closed, "Window should be closed.");
});

View File

@ -108,7 +108,9 @@ loop.conversation = (function(mozL10n) {
callback(null, navigator.mozLoop.getLoopPref("ot.guid"));
},
set: function(guid, callback) {
navigator.mozLoop.setLoopPref("ot.guid", guid);
// See nsIPrefBranch
const PREF_STRING = 32;
navigator.mozLoop.setLoopPref("ot.guid", guid, PREF_STRING);
callback(null);
}
});

View File

@ -108,7 +108,9 @@ loop.conversation = (function(mozL10n) {
callback(null, navigator.mozLoop.getLoopPref("ot.guid"));
},
set: function(guid, callback) {
navigator.mozLoop.setLoopPref("ot.guid", guid);
// See nsIPrefBranch
const PREF_STRING = 32;
navigator.mozLoop.setLoopPref("ot.guid", guid, PREF_STRING);
callback(null);
}
});

View File

@ -32,7 +32,9 @@ loop.store.FxOSActiveRoomStore = (function() {
roomState: ROOM_STATES.INIT,
audioMuted: false,
videoMuted: false,
failureReason: undefined
failureReason: undefined,
localVideoDimensions: {},
remoteVideoDimensions: {}
};
},

View File

@ -580,9 +580,6 @@ BrowserGlue.prototype = {
if (Services.prefs.getBoolPref("dom.identity.enabled")) {
SignInToWebsiteUX.init();
}
#endif
#ifdef NIGHTLY_BUILD
ShumwayUtils.init();
#endif
webrtcUI.init();
AboutHome.init();
@ -756,6 +753,12 @@ BrowserGlue.prototype = {
// With older versions of the extension installed, this load will fail
// passively.
aWindow.messageManager.loadFrameScript("resource://pdf.js/pdfjschildbootstrap.js", true);
#ifdef NIGHTLY_BUILD
// Registering Shumway bootstrap script the child processes.
aWindow.messageManager.loadFrameScript("chrome://shumway/content/bootstrap-content.js", true);
// Initializing Shumway (shall be run after child script registration).
ShumwayUtils.init();
#endif
#ifdef XP_WIN
// For windows seven, initialize the jump list module.
const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";

View File

@ -272,42 +272,6 @@ function promiseIsURIVisited(aURI) {
return deferred.promise;
}
/**
* Waits for all pending async statements on the default connection.
*
* @return {Promise}
* @resolves When all pending async statements finished.
* @rejects Never.
*
* @note The result is achieved by asynchronously executing a query requiring
* a write lock. Since all statements on the same connection are
* serialized, the end of this write operation means that all writes are
* complete. Note that WAL makes so that writers don't block readers, but
* this is a problem only across different connections.
*/
function promiseAsyncUpdates()
{
let deferred = Promise.defer();
let db = DBConn();
let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
begin.executeAsync();
begin.finalize();
let commit = db.createAsyncStatement("COMMIT");
commit.executeAsync({
handleResult: function () {},
handleError: function () {},
handleCompletion: function(aReason)
{
deferred.resolve();
}
});
commit.finalize();
return deferred.promise;
}
function promiseBookmarksNotification(notification, conditionFn) {
info(`Waiting for ${notification}`);
return new Promise((resolve, reject) => {

View File

@ -22,7 +22,7 @@ function waitForImportAndSmartBookmarks(aCallback) {
Services.obs.removeObserver(waitImport, "bookmarks-restore-success");
// Delay to test eventual smart bookmarks creation.
do_execute_soon(function () {
promiseAsyncUpdates().then(aCallback);
PlacesTestUtils.promiseAsyncUpdates().then(aCallback);
});
}, "bookmarks-restore-success", false);
}

View File

@ -345,7 +345,7 @@ function waitForImportAndSmartBookmarks(aCallback) {
Services.obs.removeObserver(waitImport, "bookmarks-restore-success");
// Delay to test eventual smart bookmarks creation.
do_execute_soon(function () {
promiseAsyncUpdates().then(aCallback);
PlacesTestUtils.promiseAsyncUpdates().then(aCallback);
});
}, "bookmarks-restore-success", false);
}

View File

@ -1 +1,2 @@
content shumway chrome/
resource shumway content/

View File

@ -0,0 +1,192 @@
/*
* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var EXPORTED_SYMBOLS = ['RtmpUtils'];
Components.utils.import('resource://gre/modules/Services.jsm');
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
var RtmpUtils = {
get isRtmpEnabled() {
try {
return Services.prefs.getBoolPref('shumway.rtmp.enabled');
} catch (ex) {
return false;
}
},
createSocket: function (sandbox, params) {
var host = params.host, port = params.port, ssl = params.ssl;
var baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
var socket = baseSocket.open(host, port, {useSecureTransport: ssl, binaryType: 'arraybuffer'});
if (!socket) {
return null;
}
var wrapperOnOpen = null, wrapperOnData = null, wrapperOnDrain = null;
var wrapperOnError = null, wrapperOnClose = null;
socket.onopen = function () {
if (wrapperOnOpen) {
wrapperOnOpen.call(wrapper, new sandbox.Object());
}
};
socket.ondata = function (e) {
if (wrapperOnData) {
var wrappedE = new sandbox.Object();
wrappedE.data = Components.utils.cloneInto(e.data, sandbox);
wrapperOnData.call(wrapper, wrappedE);
}
};
socket.ondrain = function () {
if (wrapperOnDrain) {
wrapperOnDrain.call(wrapper, new sandbox.Object());
}
};
socket.onerror = function (e) {
if (wrapperOnError) {
var wrappedE = new sandbox.Object();
wrappedE.data = Components.utils.cloneInto(e.data, sandbox);
wrapperOnError.call(wrapper, wrappedE);
}
};
socket.onclose = function () {
if (wrapperOnClose) {
wrapperOnClose.call(wrapper, new sandbox.Object());
}
};
var wrapper = new sandbox.Object();
var waived = Components.utils.waiveXrays(wrapper);
Object.defineProperties(waived, {
onopen: {
get: function () { return wrapperOnOpen; },
set: function (value) { wrapperOnOpen = value; },
enumerable: true
},
ondata: {
get: function () { return wrapperOnData; },
set: function (value) { wrapperOnData = value; },
enumerable: true
},
ondrain: {
get: function () { return wrapperOnDrain; },
set: function (value) { wrapperOnDrain = value; },
enumerable: true
},
onerror: {
get: function () { return wrapperOnError; },
set: function (value) { wrapperOnError = value; },
enumerable: true
},
onclose: {
get: function () { return wrapperOnClose; },
set: function (value) { wrapperOnClose = value; },
enumerable: true
},
send: {
value: function (buffer, offset, count) {
return socket.send(buffer, offset, count);
}
},
close: {
value: function () {
socket.close();
}
}
});
return wrapper;
},
createXHR: function (sandbox) {
var xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
var wrapperOnLoad = null, wrapperOnError = null;
xhr.onload = function () {
if (wrapperOnLoad) {
wrapperOnLoad.call(wrapper, new sandbox.Object());
}
};
xhr.onerror = function () {
if (wrappedOnError) {
wrappedOnError.call(wrapper, new sandbox.Object());
}
};
var wrapper = new sandbox.Object();
var waived = Components.utils.waiveXrays(wrapper);
Object.defineProperties(waived, {
status: {
get: function () { return xhr.status; },
enumerable: true
},
response: {
get: function () { return Components.utils.cloneInto(xhr.response, sandbox); },
enumerable: true
},
responseType: {
get: function () { return xhr.responseType; },
set: function (value) {
if (value !== 'arraybuffer') {
throw new Error('Invalid responseType.');
}
},
enumerable: true
},
onload: {
get: function () { return wrapperOnLoad; },
set: function (value) { wrapperOnLoad = value; },
enumerable: true
},
onerror: {
get: function () { return wrapperOnError; },
set: function (value) { wrapperOnError = value; },
enumerable: true
},
open: {
value: function (method, path, async) {
if (method !== 'POST' || !path || (async !== undefined && !async)) {
throw new Error('invalid open() arguments');
}
// TODO check path
xhr.open('POST', path, true);
xhr.responseType = 'arraybuffer';
xhr.setRequestHeader('Content-Type', 'application/x-fcs');
}
},
setRequestHeader: {
value: function (header, value) {
if (header !== 'Content-Type' || value !== 'application/x-fcs') {
throw new Error('invalid setRequestHeader() arguments');
}
}
},
send: {
value: function (data) {
xhr.send(data);
}
}
});
return wrapper;
}
};

View File

@ -0,0 +1,132 @@
/*
* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var EXPORTED_SYMBOLS = ['SpecialInflate', 'SpecialInflateUtils'];
Components.utils.import('resource://gre/modules/Services.jsm');
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
function SimpleStreamListener() {
this.binaryStream = Cc['@mozilla.org/binaryinputstream;1']
.createInstance(Ci.nsIBinaryInputStream);
this.onData = null;
this.buffer = null;
}
SimpleStreamListener.prototype = {
QueryInterface: function (iid) {
if (iid.equals(Ci.nsIStreamListener) ||
iid.equals(Ci.nsIRequestObserver) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
onStartRequest: function (aRequest, aContext) {
return Cr.NS_OK;
},
onStopRequest: function (aRequest, aContext, sStatusCode) {
return Cr.NS_OK;
},
onDataAvailable: function (aRequest, aContext, aInputStream, aOffset, aCount) {
this.binaryStream.setInputStream(aInputStream);
if (!this.buffer || aCount > this.buffer.byteLength) {
this.buffer = new ArrayBuffer(aCount);
}
this.binaryStream.readArrayBuffer(aCount, this.buffer);
this.onData(new Uint8Array(this.buffer, 0, aCount));
return Cr.NS_OK;
}
};
function SpecialInflate() {
var listener = new SimpleStreamListener();
listener.onData = function (data) {
this.onData(data);
}.bind(this);
var converterService = Cc["@mozilla.org/streamConverters;1"].getService(Ci.nsIStreamConverterService);
var converter = converterService.asyncConvertData("deflate", "uncompressed", listener, null);
converter.onStartRequest(null, null);
this.converter = converter;
var binaryStream = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
var pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
pipe.init(true, true, 0, 0xFFFFFFFF, null);
binaryStream.setOutputStream(pipe.outputStream);
this.binaryStream = binaryStream;
this.pipeInputStream = pipe.inputStream;
this.onData = null;
}
SpecialInflate.prototype = {
push: function (data) {
this.binaryStream.writeByteArray(data, data.length);
this.converter.onDataAvailable(null, null, this.pipeInputStream, 0, data.length);
},
close: function () {
this.binaryStream.close();
this.converter.onStopRequest(null, null, Cr.NS_OK);
}
};
var SpecialInflateUtils = {
get isSpecialInflateEnabled() {
try {
return Services.prefs.getBoolPref('shumway.specialInflate');
} catch (ex) {
return false; // TODO true;
}
},
createWrappedSpecialInflate: function (sandbox) {
var wrapped = new SpecialInflate();
var wrapperOnData = null;
wrapped.onData = function(data) {
if (wrapperOnData) {
wrapperOnData.call(wrapper, Components.utils.cloneInto(data, sandbox));
}
};
// We will return object created in the sandbox/content, with some exposed
// properties/methods, so we can send data between wrapped object and
// and sandbox/content.
var wrapper = new sandbox.Object();
var waived = Components.utils.waiveXrays(wrapper);
Object.defineProperties(waived, {
onData: {
get: function () { return wrapperOnData; },
set: function (value) { wrapperOnData = value; },
enumerable: true
},
push: {
value: function (data) {
// Uint8Array is expected in the data parameter.
// SpecialInflate.push() fails with other argument types.
return wrapped.push(data);
}
},
close: {
value: function () {
return wrapped.close();
}
}
});
return wrapper;
}
};

View File

@ -0,0 +1,80 @@
/*
* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
(function contentScriptClosure() {
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cm = Components.manager;
const Cu = Components.utils;
const Cr = Components.results;
// we need to use closure here -- we are running in the global context
Cu.import('resource://gre/modules/Services.jsm');
var isRemote = Services.appinfo.processType ===
Services.appinfo.PROCESS_TYPE_CONTENT;
var isStarted = false;
function startup() {
if (isStarted) {
return;
}
isStarted = true;
Cu.import('resource://shumway/ShumwayBootstrapUtils.jsm');
ShumwayBootstrapUtils.register();
}
function shutdown() {
if (!isStarted) {
return;
}
isStarted = false;
ShumwayBootstrapUtils.unregister();
Cu.unload('resource://shumway/ShumwayBootstrapUtils.jsm');
}
function updateSettings() {
let mm = Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(Ci.nsISyncMessageSender);
var results = mm.sendSyncMessage('Shumway:Chrome:isEnabled');
var isEnabled = results.some(function (item) {
return item;
});
if (isEnabled) {
startup();
} else {
shutdown();
}
}
if (isRemote) {
addMessageListener('Shumway:Child:refreshSettings', updateSettings);
updateSettings();
addMessageListener('Shumway:Child:shutdown', function shutdownListener(e) {
removeMessageListener('Shumway:Child:refreshSettings', updateSettings);
removeMessageListener('Shumway:Child:shutdown', shutdownListener);
shutdown();
});
}
})();

View File

@ -0,0 +1,98 @@
/*
* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Components.utils.import('resource://gre/modules/Services.jsm');
Components.utils.import('chrome://shumway/content/SpecialInflate.jsm');
Components.utils.import('chrome://shumway/content/RtmpUtils.jsm');
var externalInterfaceWrapper = {
callback: function (call) {
if (!shumwayComAdapter.onExternalCallback) {
return undefined;
}
return shumwayComAdapter.onExternalCallback(
Components.utils.cloneInto(JSON.parse(call), content));
}
};
// The object allows resending of external interface, clipboard and other
// control messages between unprivileged content and ShumwayStreamConverter.
var shumwayComAdapter;
function sendMessage(action, data, sync, callbackCookie) {
var detail = {action: action, data: data, sync: sync};
if (callbackCookie !== undefined) {
detail.callback = true;
detail.cookie = callbackCookie;
}
if (!sync) {
sendAsyncMessage('Shumway:message', detail);
return;
}
var result = sendSyncMessage('Shumway:message', detail);
return Components.utils.cloneInto(result, content);
}
addMessageListener('Shumway:init', function (message) {
sendAsyncMessage('Shumway:running', {}, {
externalInterface: externalInterfaceWrapper
});
// Exposing ShumwayCom object/adapter to the unprivileged content -- setting
// up Xray wrappers.
shumwayComAdapter = Components.utils.createObjectIn(content, {defineAs: 'ShumwayCom'});
Components.utils.exportFunction(sendMessage, shumwayComAdapter, {defineAs: 'sendMessage'});
Object.defineProperties(shumwayComAdapter, {
onLoadFileCallback: { value: null, writable: true },
onExternalCallback: { value: null, writable: true },
onMessageCallback: { value: null, writable: true }
});
Components.utils.makeObjectPropsNormal(shumwayComAdapter);
// Exposing createSpecialInflate function for DEFLATE stream decoding using
// Gecko API.
if (SpecialInflateUtils.isSpecialInflateEnabled) {
Components.utils.exportFunction(function () {
return SpecialInflateUtils.createWrappedSpecialInflate(content);
}, content, {defineAs: 'createSpecialInflate'});
}
if (RtmpUtils.isRtmpEnabled) {
Components.utils.exportFunction(function (params) {
return RtmpUtils.createSocket(content, params);
}, content, {defineAs: 'createRtmpSocket'});
Components.utils.exportFunction(function () {
return RtmpUtils.createXHR(content);
}, content, {defineAs: 'createRtmpXHR'});
}
content.wrappedJSObject.runViewer();
});
addMessageListener('Shumway:loadFile', function (message) {
if (!shumwayComAdapter.onLoadFileCallback) {
return;
}
shumwayComAdapter.onLoadFileCallback(Components.utils.cloneInto(message.data, content));
});
addMessageListener('Shumway:messageCallback', function (message) {
if (!shumwayComAdapter.onMessageCallback) {
return;
}
shumwayComAdapter.onMessageCallback(message.data.cookie,
Components.utils.cloneInto(message.data.response, content));
});

View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<!--
Copyright 2013 Mozilla Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<style>
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: transparent;
}
iframe {
position:fixed !important;
left:0;top:0;bottom:0;right:0;
overflow: hidden;
line-height: 0;
border: 0px none;
}
</style>
</head>
<body>
<iframe id="viewer" src="resource://shumway/web/viewer.html" width="100%" height="100%" mozbrowser remote="true"></iframe>
<script src="chrome://shumway/content/viewerWrapper.js"></script>
</body>
</html>

View File

@ -0,0 +1,145 @@
/*
* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
window.notifyShumwayMessage = function (detail) { };
window.onExternalCallback = null;
window.onMessageCallback = null;
window.onLoadFileCallback = null;
var viewer = document.getElementById('viewer'), onLoaded;
var promise = new Promise(function (resolve) {
onLoaded = resolve;
});
viewer.addEventListener('load', function () {
onLoaded(false);
});
viewer.addEventListener('mozbrowserloadend', function () {
onLoaded(true);
});
Components.utils.import('chrome://shumway/content/SpecialInflate.jsm');
Components.utils.import('chrome://shumway/content/RtmpUtils.jsm');
function runViewer() {
function handler() {
function sendMessage(action, data, sync, callbackCookie) {
var detail = {action: action, data: data, sync: sync};
if (callbackCookie !== undefined) {
detail.callback = true;
detail.cookie = callbackCookie;
}
var result = window.notifyShumwayMessage(detail);
return Components.utils.cloneInto(result, childWindow);
}
var childWindow = viewer.contentWindow.wrappedJSObject;
// Exposing ShumwayCom object/adapter to the unprivileged content -- setting
// up Xray wrappers. This allows resending of external interface, clipboard
// and other control messages between unprivileged content and
// ShumwayStreamConverter.
var shumwayComAdapter = Components.utils.createObjectIn(childWindow, {defineAs: 'ShumwayCom'});
Components.utils.exportFunction(sendMessage, shumwayComAdapter, {defineAs: 'sendMessage'});
Object.defineProperties(shumwayComAdapter, {
onLoadFileCallback: { value: null, writable: true },
onExternalCallback: { value: null, writable: true },
onMessageCallback: { value: null, writable: true }
});
Components.utils.makeObjectPropsNormal(shumwayComAdapter);
// Exposing createSpecialInflate function for DEFLATE stream decoding using
// Gecko API.
if (SpecialInflateUtils.isSpecialInflateEnabled) {
Components.utils.exportFunction(function () {
return SpecialInflateUtils.createWrappedSpecialInflate(childWindow);
}, childWindow, {defineAs: 'createSpecialInflate'});
}
if (RtmpUtils.isRtmpEnabled) {
Components.utils.exportFunction(function (params) {
return RtmpUtils.createSocket(childWindow, params);
}, childWindow, {defineAs: 'createRtmpSocket'});
Components.utils.exportFunction(function () {
return RtmpUtils.createXHR(childWindow);
}, childWindow, {defineAs: 'createRtmpXHR'});
}
window.onExternalCallback = function (call) {
return shumwayComAdapter.onExternalCallback(Components.utils.cloneInto(call, childWindow));
};
window.onMessageCallback = function (response) {
shumwayComAdapter.onMessageCallback(Components.utils.cloneInto(response, childWindow));
};
window.onLoadFileCallback = function (args) {
shumwayComAdapter.onLoadFileCallback(Components.utils.cloneInto(args, childWindow));
};
childWindow.runViewer();
}
function handlerOOP() {
var frameLoader = viewer.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
var messageManager = frameLoader.messageManager;
messageManager.loadFrameScript('chrome://shumway/content/content.js', false);
var externalInterface;
messageManager.addMessageListener('Shumway:running', function (message) {
externalInterface = message.objects.externalInterface;
});
messageManager.addMessageListener('Shumway:message', function (message) {
var detail = {
action: message.data.action,
data: message.data.data,
sync: message.data.sync
};
if (message.data.callback) {
detail.callback = true;
detail.cookie = message.data.cookie;
}
return window.notifyShumwayMessage(detail);
});
window.onExternalCallback = function (call) {
return externalInterface.callback(JSON.stringify(call));
};
window.onMessageCallback = function (response) {
messageManager.sendAsyncMessage('Shumway:messageCallback', {
cookie: response.cookie,
response: response.response
});
};
window.onLoadFileCallback = function (args) {
messageManager.sendAsyncMessage('Shumway:loadFile', args);
};
messageManager.sendAsyncMessage('Shumway:init', {});
}
promise.then(function (oop) {
if (oop) {
handlerOOP();
} else {
handler();
}
});
}

View File

@ -0,0 +1,95 @@
/*
* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var EXPORTED_SYMBOLS = ['ShumwayBootstrapUtils'];
const PREF_PREFIX = 'shumway.';
const PREF_IGNORE_CTP = PREF_PREFIX + 'ignoreCTP';
const SWF_CONTENT_TYPE = 'application/x-shockwave-flash';
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cm = Components.manager;
let Cu = Components.utils;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://shumway/ShumwayStreamConverter.jsm');
let Ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let registerOverlayPreview = 'registerPlayPreviewMimeType' in Ph;
function getBoolPref(pref, def) {
try {
return Services.prefs.getBoolPref(pref);
} catch (ex) {
return def;
}
}
function log(str) {
dump(str + '\n');
}
// Register/unregister a constructor as a factory.
function Factory() {}
Factory.prototype = {
register: function register(targetConstructor) {
var proto = targetConstructor.prototype;
this._classID = proto.classID;
var factory = XPCOMUtils._getFactory(targetConstructor);
this._factory = factory;
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(proto.classID, proto.classDescription,
proto.contractID, factory);
},
unregister: function unregister() {
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.unregisterFactory(this._classID, this._factory);
}
};
let converterFactory = new Factory();
let overlayConverterFactory = new Factory();
var ShumwayBootstrapUtils = {
register: function () {
// Register the components.
converterFactory.register(ShumwayStreamConverter);
overlayConverterFactory.register(ShumwayStreamOverlayConverter);
if (registerOverlayPreview) {
var ignoreCTP = getBoolPref(PREF_IGNORE_CTP, true);
Ph.registerPlayPreviewMimeType(SWF_CONTENT_TYPE, ignoreCTP);
}
},
unregister: function () {
// Remove the contract/component.
converterFactory.unregister();
overlayConverterFactory.unregister();
if (registerOverlayPreview) {
Ph.unregisterPlayPreviewMimeType(SWF_CONTENT_TYPE);
}
}
};

View File

@ -184,9 +184,17 @@ function fetchPolicyFile(url, cache, callback) {
xhr.send(null);
}
function isContentWindowPrivate(win) {
if (!('isContentWindowPrivate' in PrivateBrowsingUtils)) {
return PrivateBrowsingUtils.isWindowPrivate(win);
}
return PrivateBrowsingUtils.isContentWindowPrivate(win);
}
function isShumwayEnabledFor(actions) {
// disabled for PrivateBrowsing windows
if (PrivateBrowsingUtils.isWindowPrivate(actions.window)) {
if (isContentWindowPrivate(actions.window) &&
!getBoolPref('shumway.enableForPrivate', false)) {
return false;
}
// disabled if embed tag specifies shumwaymode (for testing purpose)
@ -212,13 +220,15 @@ function isShumwayEnabledFor(actions) {
function getVersionInfo() {
var deferred = Promise.defer();
var versionInfo = {
geckoMstone : 'unknown',
version: 'unknown',
geckoBuildID: 'unknown',
shumwayVersion: 'unknown'
};
try {
versionInfo.geckoMstone = Services.prefs.getCharPref('gecko.mstone');
versionInfo.geckoBuildID = Services.prefs.getCharPref('gecko.buildID');
var appInfo = Components.classes["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULAppInfo);
versionInfo.geckoVersion = appInfo.version;
versionInfo.geckoBuildID = appInfo.appBuildID;
} catch (e) {
log('Error encountered while getting platform version info:', e);
}
@ -275,11 +285,11 @@ ChromeActions.prototype = {
return getBoolPref(data.pref, data.def);
},
getCompilerSettings: function getCompilerSettings() {
return JSON.stringify({
return {
appCompiler: getBoolPref('shumway.appCompiler', true),
sysCompiler: getBoolPref('shumway.sysCompiler', false),
verifier: getBoolPref('shumway.verifier', true)
});
};
},
addProfilerMarker: function (marker) {
if ('nsIProfiler' in Ci) {
@ -288,14 +298,14 @@ ChromeActions.prototype = {
}
},
getPluginParams: function getPluginParams() {
return JSON.stringify({
return {
url: this.url,
baseUrl : this.baseUrl,
movieParams: this.movieParams,
objectParams: this.objectParams,
isOverlay: this.isOverlay,
isPausedAtStart: this.isPausedAtStart
});
};
},
_canDownloadFile: function canDownloadFile(data, callback) {
var url = data.url, checkPolicyFile = data.checkPolicyFile;
@ -352,6 +362,13 @@ ChromeActions.prototype = {
}.bind(this));
},
loadFile: function loadFile(data) {
function notifyLoadFileListener(data) {
if (!win.wrappedJSObject.onLoadFileCallback) {
return;
}
win.wrappedJSObject.onLoadFileCallback(data);
}
var url = data.url;
var checkPolicyFile = data.checkPolicyFile;
var sessionId = data.sessionId;
@ -381,8 +398,8 @@ ChromeActions.prototype = {
xhr.onprogress = function (e) {
var position = e.loaded;
var data = new Uint8Array(xhr.response);
win.postMessage({callback:"loadFile", sessionId: sessionId, topic: "progress",
array: data, loaded: e.loaded, total: e.total}, "*");
notifyLoadFileListener({callback:"loadFile", sessionId: sessionId,
topic: "progress", array: data, loaded: e.loaded, total: e.total});
lastPosition = position;
if (limit && e.total >= limit) {
xhr.abort();
@ -391,16 +408,15 @@ ChromeActions.prototype = {
xhr.onreadystatechange = function(event) {
if (xhr.readyState === 4) {
if (xhr.status !== 200 && xhr.status !== 0) {
win.postMessage({callback:"loadFile", sessionId: sessionId, topic: "error",
error: xhr.statusText}, "*");
notifyLoadFileListener({callback:"loadFile", sessionId: sessionId, topic: "error", error: xhr.statusText});
}
win.postMessage({callback:"loadFile", sessionId: sessionId, topic: "close"}, "*");
notifyLoadFileListener({callback:"loadFile", sessionId: sessionId, topic: "close"});
}
};
if (mimeType)
xhr.setRequestHeader("Content-Type", mimeType);
xhr.send(postData);
win.postMessage({callback:"loadFile", sessionId: sessionId, topic: "open"}, "*");
notifyLoadFileListener({callback:"loadFile", sessionId: sessionId, topic: "open"});
};
this._canDownloadFile({url: url, checkPolicyFile: checkPolicyFile}, function (data) {
@ -408,28 +424,65 @@ ChromeActions.prototype = {
performXHR();
} else {
log("data access id prohibited to " + url + " from " + baseUrl);
win.postMessage({callback:"loadFile", sessionId: sessionId, topic: "error",
error: "only original swf file or file from the same origin loading supported"}, "*");
notifyLoadFileListener({callback:"loadFile", sessionId: sessionId, topic: "error",
error: "only original swf file or file from the same origin loading supported"});
}
});
},
navigateTo: function (data) {
var embedTag = this.embedTag.wrappedJSObject;
var window = embedTag ? embedTag.ownerDocument.defaultView : this.window;
window.open(data.url, data.target || '_self');
},
fallback: function(automatic) {
automatic = !!automatic;
fallbackToNativePlugin(this.window, !automatic, automatic);
},
setClipboard: function (data) {
userInput: function() {
var win = this.window;
var winUtils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
getInterface(Components.interfaces.nsIDOMWindowUtils);
if (winUtils.isHandlingUserInput) {
this.lastUserInput = Date.now();
}
},
isUserInputInProgress: function () {
// TODO userInput does not work for OOP
if (!getBoolPref('shumway.userInputSecurity', true)) {
return true;
}
// We don't trust our Shumway non-privileged code just yet to verify the
// user input -- using monitorUserInput function below to track that.
if (typeof data !== 'string' ||
(Date.now() - this.lastUserInput) > MAX_USER_INPUT_TIMEOUT) {
return;
// user input -- using userInput function above to track that.
if ((Date.now() - this.lastUserInput) > MAX_USER_INPUT_TIMEOUT) {
return false;
}
// TODO other security checks?
return true;
},
setClipboard: function (data) {
if (typeof data !== 'string' || !this.isUserInputInProgress()) {
return;
}
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper);
clipboard.copyString(data);
},
setFullscreen: function (enabled) {
enabled = !!enabled;
if (!this.isUserInputInProgress()) {
return;
}
var target = this.embedTag || this.document.body;
if (enabled) {
target.mozRequestFullScreen();
} else {
target.ownerDocument.mozCancelFullScreen();
}
},
endActivation: function () {
if (ActivationQueue.currentNonActive === this) {
ActivationQueue.activateNext();
@ -487,20 +540,15 @@ ChromeActions.prototype = {
getVersionInfo().then(function (versions) {
params.versions = versions;
}).then(function () {
params.ffbuild = encodeURIComponent(params.versions.geckoMstone +
' (' + params.versions.geckoBuildID + ')');
params.shubuild = encodeURIComponent(params.versions.shumwayVersion);
params.exceptions = encodeURIComponent(exceptions);
var comment = '%2B%2B%2B This bug was initially via the problem reporting functionality in ' +
'Shumway %2B%2B%2B%0A%0A' +
'Please add any further information that you deem helpful here:%0A%0A%0A' +
'----------------------%0A%0A' +
'Technical Information:%0A' +
'Firefox version: ' + params.ffbuild + '%0A' +
'Shumway version: ' + params.shubuild;
url = url.split('{comment}').join(comment);
//this.window.openDialog('chrome://browser/content', '_blank', 'all,dialog=no', url);
dump(111);
var ffbuild = params.versions.geckoVersion + ' (' + params.versions.geckoBuildID + ')';
//params.exceptions = encodeURIComponent(exceptions);
var comment = '+++ Initially filed via the problem reporting functionality in Shumway +++\n' +
'Please add any further information that you deem helpful here:\n\n\n\n' +
'----------------------\n\n' +
'Technical Information:\n' +
'Firefox version: ' + ffbuild + '\n' +
'Shumway version: ' + params.versions.shumwayVersion;
url = url.split('{comment}').join(encodeURIComponent(comment));
this.window.open(url);
}.bind(this));
},
@ -517,8 +565,7 @@ ChromeActions.prototype = {
return;
this.externalComInitialized = true;
var eventTarget = this.window.document;
initExternalCom(parentWindow, embedTag, eventTarget);
initExternalCom(parentWindow, embedTag, this.window);
return;
case 'getId':
return embedTag.id;
@ -537,33 +584,15 @@ ChromeActions.prototype = {
}
};
function monitorUserInput(actions) {
function notifyUserInput() {
var win = actions.window;
var winUtils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
getInterface(Components.interfaces.nsIDOMWindowUtils);
if (winUtils.isHandlingUserInput) {
actions.lastUserInput = Date.now();
}
}
var document = actions.document;
document.addEventListener('mousedown', notifyUserInput, false);
document.addEventListener('mouseup', notifyUserInput, false);
document.addEventListener('keydown', notifyUserInput, false);
document.addEventListener('keyup', notifyUserInput, false);
}
// Event listener to trigger chrome privedged code.
function RequestListener(actions) {
this.actions = actions;
}
// Receive an event and synchronously or asynchronously responds.
RequestListener.prototype.receive = function(event) {
var message = event.target;
var action = event.detail.action;
var data = event.detail.data;
var sync = event.detail.sync;
RequestListener.prototype.receive = function(detail) {
var action = detail.action;
var data = detail.data;
var sync = detail.sync;
var actions = this.actions;
if (!(action in actions)) {
log('Unknown action: ' + action);
@ -571,30 +600,23 @@ RequestListener.prototype.receive = function(event) {
}
if (sync) {
var response = actions[action].call(this.actions, data);
event.detail.response = response;
} else {
var response;
if (event.detail.callback) {
var cookie = event.detail.cookie;
response = function sendResponse(response) {
var doc = actions.document;
try {
var listener = doc.createEvent('CustomEvent');
listener.initCustomEvent('shumway.response', true, false,
makeContentReadable({
response: response,
cookie: cookie
}, doc.defaultView));
return message.dispatchEvent(listener);
} catch (e) {
// doc is no longer accessible because the requestor is already
// gone. unloaded content cannot receive the response anyway.
}
};
}
actions[action].call(this.actions, data, response);
return response === undefined ? undefined : JSON.stringify(response);
}
var responseCallback;
if (detail.callback) {
var cookie = detail.cookie;
response = function sendResponse(response) {
var win = actions.window;
if (win.wrappedJSObject.onMessageCallback) {
win.wrappedJSObject.onMessageCallback({
response: response === undefined ? undefined : JSON.stringify(response),
cookie: cookie
});
}
};
}
actions[action].call(this.actions, data, responseCallback);
};
var ActivationQueue = {
@ -696,7 +718,7 @@ var ActivationQueue = {
}
};
function activateShumwayScripts(window, preview) {
function activateShumwayScripts(window, requestListener) {
function loadScripts(scripts, callback) {
function loadScript(i) {
if (i >= scripts.length) {
@ -717,14 +739,12 @@ function activateShumwayScripts(window, preview) {
}
function initScripts() {
loadScripts(['resource://shumway/shumway.gfx.js',
'resource://shumway/web/viewer.js'], function () {
window.wrappedJSObject.runViewer();
});
window.wrappedJSObject.notifyShumwayMessage = function () {
return requestListener.receive.apply(requestListener, arguments);
};
window.wrappedJSObject.runViewer();
}
window.wrappedJSObject.SHUMWAY_ROOT = "resource://shumway/";
if (window.document.readyState === "interactive" ||
window.document.readyState === "complete") {
initScripts();
@ -733,7 +753,7 @@ function activateShumwayScripts(window, preview) {
}
}
function initExternalCom(wrappedWindow, wrappedObject, targetDocument) {
function initExternalCom(wrappedWindow, wrappedObject, targetWindow) {
if (!wrappedWindow.__flash__initialized) {
wrappedWindow.__flash__initialized = true;
wrappedWindow.__flash__toXML = function __flash__toXML(obj) {
@ -777,18 +797,15 @@ function initExternalCom(wrappedWindow, wrappedObject, targetDocument) {
}
wrappedObject.__flash__registerCallback = function (functionName) {
wrappedWindow.console.log('__flash__registerCallback: ' + functionName);
this[functionName] = function () {
Components.utils.exportFunction(function () {
var args = Array.prototype.slice.call(arguments, 0);
wrappedWindow.console.log('__flash__callIn: ' + functionName);
var e = targetDocument.createEvent('CustomEvent');
e.initCustomEvent('shumway.remote', true, false, makeContentReadable({
functionName: functionName,
args: args,
result: undefined
}, targetDocument.defaultView));
targetDocument.dispatchEvent(e);
return e.detail.result;
};
var result;
if (targetWindow.wrappedJSObject.onExternalCallback) {
result = targetWindow.wrappedJSObject.onExternalCallback({functionName: functionName, args: args});
}
return wrappedWindow.eval(result);
}, this, { defineAs: functionName });
};
wrappedObject.__flash__unregisterCallback = function (functionName) {
wrappedWindow.console.log('__flash__unregisterCallback: ' + functionName);
@ -849,6 +866,12 @@ ShumwayStreamConverterBase.prototype = {
}
if (isOverlay) {
// HACK For Facebook, CSS embed tag rescaling -- iframe (our overlay)
// has no styling in document. Shall removed with jsplugins.
for (var child = window.frameElement; child !== element; child = child.parentNode) {
child.setAttribute('style', 'max-width: 100%; max-height: 100%');
}
// Checking if overlay is a proper PlayPreview overlay.
for (var i = 0; i < element.children.length; i++) {
if (element.children[i] === containerElement) {
@ -860,7 +883,7 @@ ShumwayStreamConverterBase.prototype = {
if (element) {
// Getting absolute URL from the EMBED tag
url = element.srcURI.spec;
url = element.srcURI && element.srcURI.spec;
pageUrl = element.ownerDocument.location.href; // proper page url?
@ -961,14 +984,8 @@ ShumwayStreamConverterBase.prototype = {
var originalURI = aRequest.URI;
// checking if the plug-in shall be run in simple mode
var isSimpleMode = originalURI.spec === EXPECTED_PLAYPREVIEW_URI_PREFIX &&
getBoolPref('shumway.simpleMode', false);
// Create a new channel that loads the viewer as a resource.
var viewerUrl = isSimpleMode ?
'resource://shumway/web/simple.html' :
'resource://shumway/web/viewer.html';
// Create a new channel that loads the viewer as a chrome resource.
var viewerUrl = 'chrome://shumway/content/viewer.wrapper.html';
var channel = Services.io.newChannel(viewerUrl, null, null);
var converter = this;
@ -1008,17 +1025,13 @@ ShumwayStreamConverterBase.prototype = {
ShumwayTelemetry.onPageIndex(0);
}
actions.activationCallback = function(domWindow, isSimpleMode) {
delete this.activationCallback;
activateShumwayScripts(domWindow, isSimpleMode);
}.bind(actions, domWindow, isSimpleMode);
ActivationQueue.enqueue(actions);
let requestListener = new RequestListener(actions);
domWindow.addEventListener('shumway.message', function(event) {
requestListener.receive(event);
}, false, true);
monitorUserInput(actions);
actions.activationCallback = function(domWindow, requestListener) {
delete this.activationCallback;
activateShumwayScripts(domWindow, requestListener);
}.bind(actions, domWindow, requestListener);
ActivationQueue.enqueue(actions);
listener.onStopRequest(aRequest, context, statusCode);
}
@ -1028,12 +1041,11 @@ ShumwayStreamConverterBase.prototype = {
channel.originalURI = aRequest.URI;
channel.loadGroup = aRequest.loadGroup;
// We can use resource principal when data is fetched by the chrome
// e.g. useful for NoScript
// We can use all powerful principal: we are opening chrome:// web page,
// which will need lots of permission.
var securityManager = Cc['@mozilla.org/scriptsecuritymanager;1']
.getService(Ci.nsIScriptSecurityManager);
var uri = Services.io.newURI(viewerUrl, null, null);
var resourcePrincipal = securityManager.getNoAppCodebasePrincipal(uri);
var resourcePrincipal = securityManager.getSystemPrincipal();
aRequest.owner = resourcePrincipal;
channel.asyncOpen(proxy, aContext);
},

View File

@ -15,12 +15,8 @@
var EXPORTED_SYMBOLS = ["ShumwayUtils"];
const RESOURCE_NAME = 'shumway';
const EXT_PREFIX = 'shumway@research.mozilla.org';
const SWF_CONTENT_TYPE = 'application/x-shockwave-flash';
const PREF_PREFIX = 'shumway.';
const PREF_DISABLED = PREF_PREFIX + 'disabled';
const PREF_IGNORE_CTP = PREF_PREFIX + 'ignoreCTP';
let Cc = Components.classes;
let Ci = Components.interfaces;
@ -30,14 +26,6 @@ let Cu = Components.utils;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
let Svc = {};
XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
'@mozilla.org/mime;1',
'nsIMIMEService');
XPCOMUtils.defineLazyServiceGetter(Svc, 'pluginHost',
'@mozilla.org/plugin/host;1',
'nsIPluginHost');
function getBoolPref(pref, def) {
try {
return Services.prefs.getBoolPref(pref);
@ -50,31 +38,6 @@ function log(str) {
dump(str + '\n');
}
// Register/unregister a constructor as a factory.
function Factory() {}
Factory.prototype = {
register: function register(targetConstructor) {
var proto = targetConstructor.prototype;
this._classID = proto.classID;
var factory = XPCOMUtils._getFactory(targetConstructor);
this._factory = factory;
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(proto.classID, proto.classDescription,
proto.contractID, factory);
},
unregister: function unregister() {
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.unregisterFactory(this._classID, this._factory);
this._factory = null;
}
};
let converterFactory = new Factory();
let overlayConverterFactory = new Factory();
let ShumwayUtils = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
_registered: false,
@ -85,6 +48,10 @@ let ShumwayUtils = {
else
this._ensureUnregistered();
Cc["@mozilla.org/parentprocessmessagemanager;1"]
.getService(Ci.nsIMessageBroadcaster)
.addMessageListener('Shumway:Chrome:isEnabled', this);
// Listen for when shumway is completely disabled.
Services.prefs.addObserver(PREF_DISABLED, this, false);
},
@ -96,6 +63,13 @@ let ShumwayUtils = {
else
this._ensureUnregistered();
},
receiveMessage: function(message) {
switch (message.name) {
case 'Shumway:Chrome:isEnabled':
return this.enabled;
}
},
/**
* shumway is only enabled if the global switch enabling is true.
@ -110,17 +84,16 @@ let ShumwayUtils = {
return;
// Load the component and register it.
Cu.import('resource://shumway/ShumwayStreamConverter.jsm');
converterFactory.register(ShumwayStreamConverter);
overlayConverterFactory.register(ShumwayStreamOverlayConverter);
var ignoreCTP = getBoolPref(PREF_IGNORE_CTP, true);
Svc.pluginHost.registerPlayPreviewMimeType(SWF_CONTENT_TYPE, ignoreCTP);
Cu.import('resource://shumway/ShumwayBootstrapUtils.jsm');
ShumwayBootstrapUtils.register();
this._registered = true;
log('Shumway is registered');
let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
.getService(Ci.nsIFrameScriptLoader);
globalMM.broadcastAsyncMessage('Shumway:Child:refreshSettings');
},
_ensureUnregistered: function _ensureUnregistered() {
@ -128,14 +101,15 @@ let ShumwayUtils = {
return;
// Remove the contract/component.
converterFactory.unregister();
overlayConverterFactory.unregister();
Cu.unload('resource://shumway/ShumwayStreamConverter.jsm');
Svc.pluginHost.unregisterPlayPreviewMimeType(SWF_CONTENT_TYPE);
ShumwayBootstrapUtils.unregister();
Cu.unload('resource://shumway/ShumwayBootstrapUtils.jsm');
this._registered = false;
log('Shumway is unregistered');
let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
.getService(Ci.nsIFrameScriptLoader);
globalMM.broadcastAsyncMessage('Shumway:Child:refreshSettings');
}
};

View File

@ -1,127 +0,0 @@
/*
precision mediump float;
varying vec4 vColor;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
out vec4 FragmentColor;
uniform float offset[5] = float[]( 0.0, 1.0, 2.0, 3.0, 4.0 );
uniform float weight[5] = float[]( 0.2270270270, 0.1945945946, 0.1216216216,
0.0540540541, 0.0162162162 );
void main(void)
{
FragmentColor = texture2D( uSampler, vec2(vCoordinate) * weight[0];
for (int i=1; i<5; i++) {
FragmentColor +=
texture2D( uSampler, ( vec2(gl_FragCoord)+vec2(0.0, offset[i]) )/1024.0 )
* weight[i];
FragmentColor +=
texture2D( uSampler, ( vec2(gl_FragCoord)-vec2(0.0, offset[i]) )/1024.0 )
* weight[i];
}
}
*/
/*
precision mediump float;
varying vec4 vColor;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
void main() {
const int sampleRadius = 16;
const int samples = sampleRadius * 2 + 1;
float dy = 1.0 / 512.0;
vec4 sample = vec4(0, 0, 0, 0);
for (int i = -sampleRadius; i <= sampleRadius; i++) {
sample += texture2D(uSampler, vCoordinate + vec2(0, float(i) * dy));
}
gl_FragColor = sample / float(samples);
// gl_FragColor = texture2D(uSampler, vCoordinate);
}
*/
precision mediump float;
varying vec4 vColor;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
void main() {
vec4 sum = vec4(0.0);
float blur = 1.0 / 512.0 * 1.0;
sum += texture2D(uSampler, vec2(vCoordinate.x - 4.0 * blur, vCoordinate.y)) * 0.05;
sum += texture2D(uSampler, vec2(vCoordinate.x - 3.0 * blur, vCoordinate.y)) * 0.09;
sum += texture2D(uSampler, vec2(vCoordinate.x - 2.0 * blur, vCoordinate.y)) * 0.12;
sum += texture2D(uSampler, vec2(vCoordinate.x - blur, vCoordinate.y)) * 0.15;
sum += texture2D(uSampler, vec2(vCoordinate.x, vCoordinate.y)) * 0.16;
sum += texture2D(uSampler, vec2(vCoordinate.x + blur, vCoordinate.y)) * 0.15;
sum += texture2D(uSampler, vec2(vCoordinate.x + 2.0 * blur, vCoordinate.y)) * 0.12;
sum += texture2D(uSampler, vec2(vCoordinate.x + 3.0 * blur, vCoordinate.y)) * 0.09;
sum += texture2D(uSampler, vec2(vCoordinate.x + 4.0 * blur, vCoordinate.y)) * 0.05;
gl_FragColor = sum;
// gl_FragColor = texture2D(uSampler, vCoordinate);
}
/*
precision mediump float;
varying vec4 vColor;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
void main() {
vec4 sum = vec4(0.0);
float blur = 0.1;
sum += texture2D(uSampler, vec2(vCoordinate.x - 4.0 * blur, vCoordinate.y)) * 0.05;
sum += texture2D(uSampler, vec2(vCoordinate.x - 3.0 * blur, vCoordinate.y)) * 0.09;
sum += texture2D(uSampler, vec2(vCoordinate.x - 2.0 * blur, vCoordinate.y)) * 0.12;
sum += texture2D(uSampler, vec2(vCoordinate.x - blur, vCoordinate.y)) * 0.15;
sum += texture2D(uSampler, vec2(vCoordinate.x, vCoordinate.y)) * 0.16;
sum += texture2D(uSampler, vec2(vCoordinate.x + blur, vCoordinate.y)) * 0.15;
sum += texture2D(uSampler, vec2(vCoordinate.x + 2.0 * blur, vCoordinate.y)) * 0.12;
sum += texture2D(uSampler, vec2(vCoordinate.x + 3.0 * blur, vCoordinate.y)) * 0.09;
sum += texture2D(uSampler, vec2(vCoordinate.x + 4.0 * blur, vCoordinate.y)) * 0.05;
gl_FragColor = sum;
// gl_FragColor = texture2D(uSampler, vCoordinate);
}
*/
/*
precision mediump float;
varying vec4 vColor;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
void main() {
gl_FragColor = texture2D(uSampler, vCoordinate);
}
*/
/*
precision mediump float;
varying vec2 vCoordinate;
varying float vColor;
uniform float blur;
uniform sampler2D uSampler;
void main(void) {
vec4 sum = vec4(0.0);
sum += texture2D(uSampler, vec2(vCoordinate.x - 4.0*blur, vCoordinate.y)) * 0.05;
sum += texture2D(uSampler, vec2(vCoordinate.x - 3.0*blur, vCoordinate.y)) * 0.09;
sum += texture2D(uSampler, vec2(vCoordinate.x - 2.0*blur, vCoordinate.y)) * 0.12;
sum += texture2D(uSampler, vec2(vCoordinate.x - blur, vCoordinate.y)) * 0.15;
sum += texture2D(uSampler, vec2(vCoordinate.x, vCoordinate.y)) * 0.16;
sum += texture2D(uSampler, vec2(vCoordinate.x + blur, vCoordinate.y)) * 0.15;
sum += texture2D(uSampler, vec2(vCoordinate.x + 2.0*blur, vCoordinate.y)) * 0.12;
sum += texture2D(uSampler, vec2(vCoordinate.x + 3.0*blur, vCoordinate.y)) * 0.09;
sum += texture2D(uSampler, vec2(vCoordinate.x + 4.0*blur, vCoordinate.y)) * 0.05;
gl_FragColor = sum;
}
*/

View File

@ -1,16 +0,0 @@
precision mediump float;
varying vec4 vColor;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
void main() {
const int sampleRadius = 8;
const int samples = sampleRadius * 2 + 1;
float dx = 0.01;
vec4 sample = vec4(0, 0, 0, 0);
for (int i = -sampleRadius; i <= sampleRadius; i++) {
sample += texture2D(uSampler, vCoordinate + vec2(0, float(i) * dy));
}
gl_FragColor = sample / float(samples);
}

View File

@ -1,19 +0,0 @@
uniform vec2 uResolution;
uniform mat3 uTransformMatrix;
uniform float uZ;
attribute vec2 aPosition;
attribute vec4 aColor;
attribute vec2 aCoordinate;
varying vec4 vColor;
varying vec2 vCoordinate;
void main() {
vec2 position = ((uTransformMatrix * vec3(aPosition, 1.0)).xy / uResolution) * 2.0 - 1.0;
position *= vec2(1.0, -1.0);
// position *= vec2(40.0, -4.0);
gl_Position = vec4(vec3(position, uZ), 1.0);
vColor = aColor;
vCoordinate = aCoordinate;
}

View File

@ -1,18 +0,0 @@
precision mediump float;
uniform vec4 uColor;
varying vec2 vTextureCoordinate;
void main() {
gl_FragColor = uColor;
gl_FragColor = vec4(vTextureCoordinate.x, vTextureCoordinate.y, 0, 0.5);
float u = vTextureCoordinate.x;
float v = vTextureCoordinate.y;
float r = u * u - v;
if (r < 0.0) {
gl_FragColor = vec4(1, 0, 0, 1);
} else {
gl_FragColor = vec4(1, 0, 0, 0.2);
}
}

View File

@ -1,7 +0,0 @@
precision mediump float;
varying vec4 vColor;
void main() {
gl_FragColor = vColor;
}

View File

@ -1,15 +0,0 @@
uniform vec2 uResolution;
uniform mat3 uTransformMatrix;
uniform float uZ;
attribute vec2 aPosition;
attribute vec4 aColor;
varying vec4 vColor;
void main() {
vec2 position = ((uTransformMatrix * vec3(aPosition, 1.0)).xy / uResolution) * 2.0 - 1.0;
position *= vec2(1.0, -1.0);
gl_Position = vec4(vec3(position, uZ), 1.0);
vColor = aColor;
}

View File

@ -1,12 +0,0 @@
precision mediump float;
varying vec4 vColor;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
void main() {
// gl_FragColor = vColor;
// gl_FragColor = vec4(vTextureCoordinate.x, vTextureCoordinate.y, 0, 0.5);
// gl_FragColor = gl_FragColor; // + texture2D(uSampler, vCoordinate);
gl_FragColor = texture2D(uSampler, vCoordinate);
}

View File

@ -1,19 +0,0 @@
uniform vec2 uResolution;
uniform mat3 uTransformMatrix;
uniform float uZ;
attribute vec2 aPosition;
attribute vec4 aColor;
attribute vec2 aCoordinate;
varying vec4 vColor;
varying vec2 vCoordinate;
void main() {
vec2 position = ((uTransformMatrix * vec3(aPosition, 1.0)).xy / uResolution) * 2.0 - 1.0;
position *= vec2(1.0, -1.0);
// position *= vec2(40.0, -4.0);
gl_Position = vec4(vec3(position, uZ), 1.0);
vColor = aColor;
vCoordinate = aCoordinate;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +1,2 @@
0.9.2970
22f884f
0.9.3693
217e2e2

View File

@ -35,7 +35,7 @@ limitations under the License.
display: none;
}
#stageContainer {
#easelContainer {
position:fixed !important;
left:0;top:0;bottom:0;right:0;
overflow: hidden;
@ -49,7 +49,7 @@ limitations under the License.
#overlay.enabled {
display: block;
position:fixed;
bottom: 0;
top: 0;
right: 0;
}
@ -58,7 +58,7 @@ limitations under the License.
width: 70px; height: 16px;
padding: 8px 4px 4px;
color: white;
background-color: rgba(0, 0, 0, 0.62);
background-color: rgba(218, 56, 7, 0.63);
font: bold 10px sans-serif;
text-align: center;
text-decoration: none;
@ -100,7 +100,7 @@ limitations under the License.
<body contextmenu="shumwayMenu">
<iframe id="playerWindow" width="9" height="9" src=""></iframe>
<div id="stageContainer"></div>
<div id="easelContainer"></div>
<section>
<div id="overlay">
<a id="fallback" href="#">Shumway <span class="icon">&times;</span></a>
@ -114,5 +114,8 @@ limitations under the License.
<menuitem label="About Shumway" id="aboutMenu"></menuitem>
</menu>
</section>
<script src='resource://shumway/shumway.gfx.js'></script>
<script src='resource://shumway/web/viewer.js'></script>
</body>
</html>

View File

@ -27,11 +27,8 @@ var FirefoxCom = (function FirefoxComClosure() {
* @return {*} The response.
*/
requestSync: function(action, data) {
var e = document.createEvent('CustomEvent');
e.initCustomEvent('shumway.message', true, false,
{action: action, data: data, sync: true});
document.dispatchEvent(e);
return e.detail.response;
var result = String(ShumwayCom.sendMessage(action, data, true, undefined));
return result !== 'undefined' ? JSON.parse(result) : undefined;
},
/**
* Creates an event that the extension is listening for and will
@ -42,38 +39,45 @@ var FirefoxCom = (function FirefoxComClosure() {
* with one data argument.
*/
request: function(action, data, callback) {
var e = document.createEvent('CustomEvent');
e.initCustomEvent('shumway.message', true, false,
{action: action, data: data, sync: false});
var cookie = undefined;
if (callback) {
if ('nextId' in FirefoxCom.request) {
FirefoxCom.request.nextId = 1;
cookie = "requestId" + (this._nextRequestId++);
if (!ShumwayCom.onMessageCallback) {
ShumwayCom.onMessageCallback = this._notifyMessageCallback.bind(this);
}
var cookie = "requestId" + (FirefoxCom.request.nextId++);
e.detail.cookie = cookie;
e.detail.callback = true;
document.addEventListener('shumway.response', function listener(event) {
if (cookie !== event.detail.cookie)
return;
document.removeEventListener('shumway.response', listener, false);
var response = event.detail.response;
return callback(response);
}, false);
this._requestCallbacks[cookie] = callback;
}
return document.dispatchEvent(e);
ShumwayCom.sendMessage(action, data, false, cookie);
},
_notifyMessageCallback: function (cookie, response) {
var callback = this._requestCallbacks[cookie];
if (!callback) {
return;
}
delete this._requestCallbacks[cookie];
callback(response !== 'undefined' ? JSON.parse(response) : undefined);
},
_nextRequestId: 1,
_requestCallbacks: Object.create(null),
initJS: function (callback) {
FirefoxCom.request('externalCom', {action: 'init'});
document.addEventListener('shumway.remote', function (e) {
e.detail.result = callback(e.detail.functionName, e.detail.args);
}, false);
ShumwayCom.onExternalCallback = function (call) {
return callback(call.functionName, call.args);
};
}
};
})();
function notifyUserInput() {
ShumwayCom.sendMessage('userInput', null, true, undefined);
}
document.addEventListener('mousedown', notifyUserInput, true);
document.addEventListener('mouseup', notifyUserInput, true);
document.addEventListener('keydown', notifyUserInput, true);
document.addEventListener('keyup', notifyUserInput, true);
function fallback() {
FirefoxCom.requestSync('fallback', null)
}
@ -82,13 +86,14 @@ window.print = function(msg) {
console.log(msg);
};
var SHUMWAY_ROOT = "resource://shumway/";
var viewerPlayerglobalInfo = {
abcs: SHUMWAY_ROOT + "playerglobal/playerglobal.abcs",
catalog: SHUMWAY_ROOT + "playerglobal/playerglobal.json"
};
var builtinPath = SHUMWAY_ROOT + "avm2/generated/builtin/builtin.abc";
var avm1Path = SHUMWAY_ROOT + "avm2/generated/avm1lib/avm1lib.abc";
var playerWindow;
var playerWindowLoaded = new Promise(function(resolve) {
@ -101,7 +106,14 @@ var playerWindowLoaded = new Promise(function(resolve) {
});
function runViewer() {
var flashParams = JSON.parse(FirefoxCom.requestSync('getPluginParams', null));
ShumwayCom.onLoadFileCallback = function (data) {
playerWindow.postMessage({
type: "loadFileResponse",
args: data
}, '*');
};
var flashParams = FirefoxCom.requestSync('getPluginParams', null);
movieUrl = flashParams.url;
if (!movieUrl) {
@ -112,6 +124,7 @@ function runViewer() {
movieParams = flashParams.movieParams;
objectParams = flashParams.objectParams;
var baseUrl = flashParams.baseUrl;
var isOverlay = flashParams.isOverlay;
pauseExecution = flashParams.isPausedAtStart;
@ -125,7 +138,7 @@ function runViewer() {
}
playerWindowLoaded.then(function () {
parseSwf(movieUrl, movieParams, objectParams);
parseSwf(movieUrl, baseUrl, movieParams, objectParams);
});
if (isOverlay) {
@ -193,12 +206,6 @@ var movieUrl, movieParams, objectParams;
window.addEventListener("message", function handlerMessage(e) {
var args = e.data;
switch (args.callback) {
case 'loadFile':
playerWindow.postMessage({
type: "loadFileResponse",
args: args
}, '*');
break;
case 'loadFileRequest':
FirefoxCom.request('loadFile', args.data, null);
break;
@ -208,6 +215,9 @@ window.addEventListener("message", function handlerMessage(e) {
case 'setClipboard':
FirefoxCom.request('setClipboard', args.data, null);
break;
case 'navigateTo':
FirefoxCom.request('navigateTo', args.data, null);
break;
case 'started':
document.body.classList.add('started');
break;
@ -232,13 +242,11 @@ function processExternalCommand(command) {
}
}
function parseSwf(url, movieParams, objectParams) {
var compilerSettings = JSON.parse(
FirefoxCom.requestSync('getCompilerSettings', null));
function parseSwf(url, baseUrl, movieParams, objectParams) {
var compilerSettings = FirefoxCom.requestSync('getCompilerSettings', null);
// init misc preferences
var turboMode = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.turboMode', def: false});
Shumway.GFX.backend.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.webgl', def: false}) ? 1 : 0;
Shumway.GFX.hud.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.hud', def: false});
//forceHidpi.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.force_hidpi', def: false});
//dummyAnimation.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.dummyMode', def: false});
@ -249,22 +257,23 @@ function parseSwf(url, movieParams, objectParams) {
FirefoxCom.request('endActivation', null);
}
var bgcolor;
var backgroundColor;
if (objectParams) {
var m;
if (objectParams.bgcolor && (m = /#([0-9A-F]{6})/i.exec(objectParams.bgcolor))) {
var hexColor = parseInt(m[1], 16);
bgcolor = hexColor << 8 | 0xff;
backgroundColor = hexColor << 8 | 0xff;
}
if (objectParams.wmode === 'transparent') {
bgcolor = 0;
backgroundColor = 0;
}
}
var easel = createEasel(bgcolor);
var easel = createEasel(backgroundColor);
easelHost = new Shumway.GFX.Window.WindowEaselHost(easel, playerWindow, window);
easelHost.processExternalCommand = processExternalCommand;
var displayParameters = easel.getDisplayParameters();
var data = {
type: 'runSwf',
settings: Shumway.Settings.getSettings(),
@ -272,21 +281,21 @@ function parseSwf(url, movieParams, objectParams) {
compilerSettings: compilerSettings,
movieParams: movieParams,
objectParams: objectParams,
displayParameters: displayParameters,
turboMode: turboMode,
bgcolor: bgcolor,
bgcolor: backgroundColor,
url: url,
baseUrl: url
baseUrl: baseUrl || url
}
};
playerWindow.postMessage(data, '*');
}
function createEasel(bgcolor) {
function createEasel(backgroundColor) {
var Stage = Shumway.GFX.Stage;
var Easel = Shumway.GFX.Easel;
var Canvas2DStageRenderer = Shumway.GFX.Canvas2DStageRenderer;
var Canvas2DRenderer = Shumway.GFX.Canvas2DRenderer;
Shumway.GFX.WebGL.SHADER_ROOT = SHUMWAY_ROOT + "gfx/gl/shaders/";
var backend = Shumway.GFX.backend.value | 0;
return new Easel(document.getElementById("stageContainer"), backend, false, bgcolor);
return new Easel(document.getElementById("easelContainer"), false, backgroundColor);
}

View File

@ -24,7 +24,6 @@ var viewerPlayerglobalInfo = {
var avm2Root = SHUMWAY_ROOT + "avm2/";
var builtinPath = avm2Root + "generated/builtin/builtin.abc";
var avm1Path = avm2Root + "generated/avm1lib/avm1lib.abc";
window.print = function(msg) {
console.log(msg);
@ -38,29 +37,32 @@ function runSwfPlayer(flashParams) {
var appMode = compilerSettings.appCompiler ? EXECUTION_MODE.COMPILE : EXECUTION_MODE.INTERPRET;
var asyncLoading = true;
var baseUrl = flashParams.baseUrl;
var movieParams = flashParams.movieParams;
var objectParams = flashParams.objectParams;
var movieUrl = flashParams.url;
Shumway.frameRateOption.value = flashParams.turboMode ? 60 : -1;
Shumway.AVM2.Verifier.enabled.value = compilerSettings.verifier;
Shumway.createAVM2(builtinPath, viewerPlayerglobalInfo, avm1Path, sysMode, appMode, function (avm2) {
Shumway.createAVM2(builtinPath, viewerPlayerglobalInfo, sysMode, appMode, function (avm2) {
function runSWF(file) {
var player = new Shumway.Player.Window.WindowPlayer(window, window.parent);
player.defaultStageColor = flashParams.bgcolor;
player.movieParams = flashParams.movieParams;
player.stageAlign = (objectParams && (objectParams.salign || objectParams.align)) || '';
player.stageScale = (objectParams && objectParams.scale) || 'showall';
player.displayParameters = flashParams.displayParameters;
Shumway.ExternalInterfaceService.instance = player.createExternalInterfaceService();
player.load(file);
}
file = Shumway.FileLoadingService.instance.setBaseUrl(baseUrl);
Shumway.FileLoadingService.instance.setBaseUrl(baseUrl);
if (asyncLoading) {
runSWF(movieUrl);
} else {
new Shumway.BinaryFileReader(movieUrl).readAll(null, function(buffer, error) {
if (!buffer) {
throw "Unable to open the file " + file + ": " + error;
throw "Unable to open the file " + movieUrl + ": " + error;
}
runSWF(movieUrl, buffer);
});
@ -129,32 +131,34 @@ function setupServices() {
};
},
setBaseUrl: function (url) {
var baseUrl;
if (typeof URL !== 'undefined') {
baseUrl = new URL(url, document.location.href).href;
} else {
var a = document.createElement('a');
a.href = url || '#';
a.setAttribute('style', 'display: none;');
document.body.appendChild(a);
baseUrl = a.href;
document.body.removeChild(a);
}
Shumway.FileLoadingService.instance.baseUrl = baseUrl;
return baseUrl;
Shumway.FileLoadingService.instance.baseUrl = url;
},
resolveUrl: function (url) {
if (url.indexOf('://') >= 0) return url;
var base = Shumway.FileLoadingService.instance.baseUrl;
base = base.lastIndexOf('/') >= 0 ? base.substring(0, base.lastIndexOf('/') + 1) : '';
if (url.indexOf('/') === 0) {
var m = /^[^:]+:\/\/[^\/]+/.exec(base);
if (m) base = m[0];
}
return base + url;
return new URL(url, Shumway.FileLoadingService.instance.baseUrl).href;
},
navigateTo: function (url, target) {
window.parent.postMessage({
callback: 'navigateTo',
data: {
url: this.resolveUrl(url),
target: target
}
}, '*');
}
};
// Using SpecialInflate when chrome code provides it.
if (parent.createSpecialInflate) {
window.SpecialInflate = function () {
return parent.createSpecialInflate();
};
}
// Using createRtmpXHR/createRtmpSocket when chrome code provides it.
if (parent.createRtmpXHR) {
window.createRtmpSocket = parent.createRtmpSocket;
window.createRtmpXHR = parent.createRtmpXHR;
}
}
window.addEventListener('message', function onWindowMessage(e) {

View File

@ -58,6 +58,11 @@ filefield + button {
border-bottom: none;
}
#advancedPrefs {
margin-right: 0; /*override margin from normal preferences.css */
margin-left: 0;
}
/**
* Dialog
*/

View File

@ -202,10 +202,6 @@ description > html|a {
-moz-margin-start: 0;
}
#advancedPrefs {
padding-bottom: 0; /* no padding needed in inContent prefs */
}
#tabsElement {
-moz-margin-end: 4px; /* add the 4px end-margin of other elements */
}

View File

@ -2,6 +2,10 @@
* 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/. */
#defaultEngine {
-moz-margin-start: 0;
}
#defaultEngine > .menulist-label-box > .menulist-icon {
height: 16px;
}
@ -12,7 +16,7 @@
}
#engineList {
margin: .5em 6px;
margin: .5em 0;
}
#engineList treechildren::-moz-tree-image(engineShown, checked) {
@ -51,3 +55,9 @@
#addEnginesBox {
margin-bottom: 1em;
}
#removeEngineButton,
#restoreDefaultSearchEngines {
margin-right: 0;
margin-left: 0;
}

View File

@ -13,6 +13,10 @@ filefield + button {
-moz-margin-start: -4px;
}
#advancedPrefs {
padding-bottom: 0; /* override padding from normal preferences.css */
}
/**
* Dialog
*/

View File

@ -1,24 +1,29 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
package org.mozilla.gecko;
import java.text.DecimalFormat;
import java.nio.ByteBuffer;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PanZoomController;
import org.mozilla.gecko.gfx.PointUtils;
import org.mozilla.gecko.mozglue.DirectBufferAllocator;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.mozglue.DirectBufferAllocator;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@ -28,8 +33,11 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;
public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChangedListener,
LayerView.OnZoomedViewListener, GeckoEventListener {
LayerView.ZoomedViewListener, GeckoEventListener {
private static final String LOGTAG = "Gecko" + ZoomedView.class.getSimpleName();
private static final int ZOOM_FACTOR = 2;
@ -40,27 +48,26 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
private ImageView zoomedImageView;
private LayerView layerView;
private MotionEvent actionDownEvent;
private int viewWidth;
private int viewHeight;
private int xLastPosition;
private int yLastPosition;
private Point lastPosition;
private boolean shouldSetVisibleOnUpdate;
private PointF returnValue;
private boolean stopUpdateView;
private int lastOrientation = 0;
private int lastOrientation;
private ByteBuffer buffer;
private Runnable requestRenderRunnable;
private long startTimeReRender = 0;
private long lastStartTimeReRender = 0;
private long startTimeReRender;
private long lastStartTimeReRender;
private class ZoomedViewTouchListener implements View.OnTouchListener {
private float originRawX;
private float originRawY;
private int touchState;
private boolean dragged;
private MotionEvent actionDownEvent;
@Override
public boolean onTouch(View view, MotionEvent event) {
@ -71,13 +78,13 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
if (moveZoomedView(event)) {
touchState = MotionEvent.ACTION_MOVE;
dragged = true;
}
break;
case MotionEvent.ACTION_UP:
if (touchState == MotionEvent.ACTION_MOVE) {
touchState = -1;
if (dragged) {
dragged = false;
} else {
layerView.dispatchTouchEvent(actionDownEvent);
actionDownEvent.recycle();
@ -91,7 +98,7 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
break;
case MotionEvent.ACTION_DOWN:
touchState = -1;
dragged = false;
originRawX = event.getRawX();
originRawY = event.getRawY();
PointF convertedPosition = getUnzoomedPositionFromPointInZoomedView(event.getX(), event.getY());
@ -105,8 +112,8 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
private boolean moveZoomedView(MotionEvent event) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) ZoomedView.this.getLayoutParams();
if ((touchState != MotionEvent.ACTION_MOVE) && (Math.abs((int) (event.getRawX() - originRawX)) < 1)
&& (Math.abs((int) (event.getRawY() - originRawY)) < 1)) {
if ((!dragged) && (Math.abs((int) (event.getRawX() - originRawX)) < PanZoomController.CLICK_THRESHOLD)
&& (Math.abs((int) (event.getRawY() - originRawY)) < PanZoomController.CLICK_THRESHOLD)) {
// When the user just touches the screen ACTION_MOVE can be detected for a very small delta on position.
// In this case, the move is ignored if the delta is lower than 1 unit.
return false;
@ -236,10 +243,6 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
}
private void moveZoomedView(ImmutableViewportMetrics metrics, float newLeftMargin, float newTopMargin) {
if (layerView == null) {
return;
}
final float parentWidth = metrics.getWidth();
final float parentHeight = metrics.getHeight();
RelativeLayout.LayoutParams newLayoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
@ -253,7 +256,7 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
if (newTopMargin < topMarginMin) {
newLayoutParams.topMargin = topMarginMin;
} else if (newTopMargin + viewHeight >= parentHeight) {
} else if (newTopMargin + viewHeight > parentHeight) {
newLayoutParams.topMargin = (int) (parentHeight - viewHeight);
}
@ -265,8 +268,7 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
setLayoutParams(newLayoutParams);
PointF convertedPosition = getUnzoomedPositionFromPointInZoomedView(0, 0);
xLastPosition = Math.round(convertedPosition.x);
yLastPosition = Math.round(convertedPosition.y);
lastPosition = PointUtils.round(convertedPosition);
requestZoomedViewRender();
}
@ -282,7 +284,7 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
}
}
public void refreshZoomedViewSize(ImmutableViewportMetrics viewport) {
private void refreshZoomedViewSize(ImmutableViewportMetrics viewport) {
if (layerView == null) {
return;
}
@ -292,27 +294,24 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
moveZoomedView(viewport, params.leftMargin, params.topMargin);
}
public void setCapturedSize(ImmutableViewportMetrics metrics) {
if (layerView == null) {
return;
}
private void setCapturedSize(ImmutableViewportMetrics metrics) {
float parentMinSize = Math.min(metrics.getWidth(), metrics.getHeight());
viewWidth = (int) (parentMinSize * W_CAPTURED_VIEW_IN_PERCENT / (ZOOM_FACTOR * 100.0)) * ZOOM_FACTOR;
viewHeight = (int) (parentMinSize * H_CAPTURED_VIEW_IN_PERCENT / (ZOOM_FACTOR * 100.0)) * ZOOM_FACTOR;
}
public void shouldBlockUpdate(boolean shouldBlockUpdate) {
private void shouldBlockUpdate(boolean shouldBlockUpdate) {
stopUpdateView = shouldBlockUpdate;
}
public Bitmap.Config getBitmapConfig() {
private Bitmap.Config getBitmapConfig() {
return (GeckoAppShell.getScreenDepth() == 24) ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
}
public void startZoomDisplay(LayerView aLayerView, final int leftFromGecko, final int topFromGecko) {
private void startZoomDisplay(LayerView aLayerView, final int leftFromGecko, final int topFromGecko) {
if (layerView == null) {
layerView = aLayerView;
layerView.addOnZoomedViewListener(this);
layerView.addZoomedViewListener(this);
layerView.setOnMetricsChangedZoomedViewportListener(this);
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
setCapturedSize(metrics);
@ -322,13 +321,13 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
moveUsingGeckoPosition(leftFromGecko, topFromGecko);
}
public void stopZoomDisplay() {
private void stopZoomDisplay() {
shouldSetVisibleOnUpdate = false;
this.setVisibility(View.GONE);
ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);
if (layerView != null) {
layerView.setOnMetricsChangedZoomedViewportListener(null);
layerView.removeOnZoomedViewListener(this);
layerView.removeZoomedViewListener(this);
layerView = null;
}
}
@ -362,9 +361,6 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
}
private void moveUsingGeckoPosition(int leftFromGecko, int topFromGecko) {
if (layerView == null) {
return;
}
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
PointF convertedPosition = getZoomedViewTopLeftPositionFromTouchPosition((leftFromGecko * metrics.zoomFactor),
(topFromGecko * metrics.zoomFactor));
@ -379,9 +375,6 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
if (layerView == null) {
return;
}
shouldBlockUpdate(false);
refreshZoomedViewSize(viewport);
}
@ -477,11 +470,11 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
PointF origin = metrics.getOrigin();
PointF offset = metrics.getMarginOffset();
final int xPos = (int) (origin.x - offset.x) + xLastPosition;
final int yPos = (int) (origin.y - offset.y) + yLastPosition;
final int xPos = (int) (origin.x - offset.x) + lastPosition.x;
final int yPos = (int) (origin.y - offset.y) + lastPosition.y;
GeckoEvent e = GeckoEvent.createZoomedViewEvent(tabId, xPos, yPos, viewWidth,
viewHeight, (float) (2.0 * metrics.zoomFactor), buffer);
viewHeight, ZOOM_FACTOR * metrics.zoomFactor, buffer);
GeckoAppShell.sendEventToGecko(e);
}

View File

@ -915,10 +915,10 @@ class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
@Override
public void panZoomStopped() {
if (mDynamicToolbarViewportChangeListener != null) {
mDynamicToolbarViewportChangeListener.onPanZoomStopped();
mDynamicToolbarViewportChangeListener.onPanZoomStopped();
}
if (mZoomedViewViewportChangeListener != null) {
mZoomedViewViewportChangeListener.onPanZoomStopped();
mZoomedViewViewportChangeListener.onPanZoomStopped();
}
}

View File

@ -96,9 +96,9 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
private int mSampleHandle;
private int mTMatrixHandle;
private List<LayerView.OnZoomedViewListener> mZoomedViewListeners;
private float mViewLeft = 0.0f;
private float mViewTop = 0.0f;
private List<LayerView.ZoomedViewListener> mZoomedViewListeners;
private float mLastViewLeft;
private float mLastViewTop;
// column-major matrix applied to each vertex to shift the viewport from
// one ranging from (-1, -1),(1,1) to (0,0),(1,1) and to scale all sizes by
@ -168,7 +168,7 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
mCoordBuffer = mCoordByteBuffer.asFloatBuffer();
Tabs.registerOnTabsChangedListener(this);
mZoomedViewListeners = new ArrayList<LayerView.OnZoomedViewListener>();
mZoomedViewListeners = new ArrayList<LayerView.ZoomedViewListener>();
}
private Bitmap expandCanvasToPowerOfTwo(Bitmap image, IntSize size) {
@ -598,7 +598,7 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
}
public void maybeRequestZoomedViewRender(RenderContext context){
private void maybeRequestZoomedViewRender(RenderContext context) {
// Concurrently update of mZoomedViewListeners should not be an issue here
// because the following line is just a short-circuit
if (mZoomedViewListeners.size() == 0) {
@ -612,13 +612,13 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
final float viewTop = context.viewport.top - context.offset.y;
boolean shouldWaitToRender = false;
if (Math.abs(mViewLeft - viewLeft) > MAX_SCROLL_SPEED_TO_REQUEST_ZOOM_RENDER ||
Math.abs(mViewTop - viewTop) > MAX_SCROLL_SPEED_TO_REQUEST_ZOOM_RENDER) {
if (Math.abs(mLastViewLeft - viewLeft) > MAX_SCROLL_SPEED_TO_REQUEST_ZOOM_RENDER ||
Math.abs(mLastViewTop - viewTop) > MAX_SCROLL_SPEED_TO_REQUEST_ZOOM_RENDER) {
shouldWaitToRender = true;
}
mViewLeft = viewLeft;
mViewTop = viewTop;
mLastViewLeft = viewLeft;
mLastViewTop = viewTop;
if (shouldWaitToRender) {
return;
@ -627,7 +627,7 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
for (LayerView.OnZoomedViewListener listener : mZoomedViewListeners) {
for (LayerView.ZoomedViewListener listener : mZoomedViewListeners) {
listener.requestZoomedViewRender();
}
}
@ -697,19 +697,20 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
for (LayerView.OnZoomedViewListener listener : mZoomedViewListeners) {
for (LayerView.ZoomedViewListener listener : mZoomedViewListeners) {
data.position(0);
listener.updateView(data);
}
}
});
}
public void addOnZoomedViewListener(LayerView.OnZoomedViewListener listener) {
public void addZoomedViewListener(LayerView.ZoomedViewListener listener) {
ThreadUtils.assertOnUiThread();
mZoomedViewListeners.add(listener);
}
public void removeOnZoomedViewListener(LayerView.OnZoomedViewListener listener) {
public void removeZoomedViewListener(LayerView.ZoomedViewListener listener) {
ThreadUtils.assertOnUiThread();
mZoomedViewListeners.remove(listener);
}

View File

@ -532,17 +532,16 @@ public class LayerView extends FrameLayout implements Tabs.OnTabsChangedListener
}
}
//This method is called on the Gecko main thread.
@WrapElementForJNI(allowMultithread = true, stubName = "updateZoomedView")
public static void updateZoomedView(ByteBuffer data) {
data.position(0);
LayerView layerView = GeckoAppShell.getLayerView();
if (layerView != null) {
LayerRenderer layerRenderer = layerView.getRenderer();
if (layerRenderer != null){
if (layerRenderer != null) {
layerRenderer.updateZoomedView(data);
}
}
return;
}
public interface Listener {
@ -687,17 +686,17 @@ public class LayerView extends FrameLayout implements Tabs.OnTabsChangedListener
// Public hooks for zoomed view
public interface OnZoomedViewListener {
public interface ZoomedViewListener {
public void requestZoomedViewRender();
public void updateView(ByteBuffer data);
}
public void addOnZoomedViewListener(OnZoomedViewListener listener) {
mRenderer.addOnZoomedViewListener(listener);
public void addZoomedViewListener(ZoomedViewListener listener) {
mRenderer.addZoomedViewListener(listener);
}
public void removeOnZoomedViewListener(OnZoomedViewListener listener) {
mRenderer.removeOnZoomedViewListener(listener);
public void removeZoomedViewListener(ZoomedViewListener listener) {
mRenderer.removeZoomedViewListener(listener);
}
}

View File

@ -91,5 +91,39 @@ this.PlacesTestUtils = Object.freeze({
});
return Promise.all([expirationFinished, PlacesUtils.history.clear()]);
},
/**
* Waits for all pending async statements on the default connection.
*
* @return {Promise}
* @resolves When all pending async statements finished.
* @rejects Never.
*
* @note The result is achieved by asynchronously executing a query requiring
* a write lock. Since all statements on the same connection are
* serialized, the end of this write operation means that all writes are
* complete. Note that WAL makes so that writers don't block readers, but
* this is a problem only across different connections.
*/
promiseAsyncUpdates() {
return new Promise(resolve => {
let db = PlacesUtils.history.DBConnection;
let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
begin.executeAsync();
begin.finalize();
let commit = db.createAsyncStatement("COMMIT");
commit.executeAsync({
handleResult: function () {},
handleError: function () {},
handleCompletion: function(aReason)
{
resolve();
}
});
commit.finalize();
});
}
});

View File

@ -277,7 +277,7 @@ function run_test() {
// At this point frecency could still be updating due to latest pages
// updates. This is not a problem in real life, but autocomplete tests
// should return reliable resultsets, thus we have to wait.
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
}).then(function () ensure_results(search, expected),
do_report_unexpected_exception);

View File

@ -12,7 +12,7 @@ added or removed and also the maintenance task to fix wrong counts.
const T_URI = NetUtil.newURI("https://www.mozilla.org/firefox/nightly/firstrun/");
function* getForeignCountForURL(conn, url) {
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
url = url instanceof Ci.nsIURI ? url.spec : url;
let rows = yield conn.executeCached(
"SELECT foreign_count FROM moz_places WHERE url = :t_url ", { t_url: url });

View File

@ -56,7 +56,7 @@ add_task(function* test_eraseEverything() {
PlacesUtils.annotations.setItemAnnotation((yield PlacesUtils.promiseItemId(toolbarBookmarkInFolder.guid)),
"testanno1", "testvalue1", 0, 0);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
Assert.ok(frecencyForUrl("http://example.com/") > frecencyForExample);
Assert.ok(frecencyForUrl("http://example.com/") > frecencyForMozilla);

View File

@ -277,7 +277,7 @@ add_task(function* create_bookmark_frecency() {
title: "a bookmark" });
checkBookmarkObject(bm);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
Assert.ok(frecencyForUrl(bm.url) > 0, "Check frecency has been updated")
});

View File

@ -77,7 +77,7 @@ add_test(function test_addBookmarkWithKeyword()
check_bookmark_keyword(itemId, "keyword");
check_uri_keyword(URIS[0], "keyword");
promiseAsyncUpdates().then(function() {
PlacesTestUtils.promiseAsyncUpdates().then(() => {
check_orphans();
run_next_test();
});
@ -94,7 +94,7 @@ add_test(function test_addBookmarkToURIHavingKeyword()
check_bookmark_keyword(itemId, null);
check_uri_keyword(URIS[0], "keyword");
promiseAsyncUpdates().then(function() {
PlacesTestUtils.promiseAsyncUpdates().then(() => {
check_orphans();
run_next_test();
});
@ -120,7 +120,7 @@ add_test(function test_addSameKeywordToOtherURI()
check_uri_keyword(URIS[1], "keyword");
check_uri_keyword(URIS[0], "keyword");
promiseAsyncUpdates().then(function() {
PlacesTestUtils.promiseAsyncUpdates().then(() => {
check_orphans();
run_next_test();
});
@ -143,7 +143,7 @@ add_test(function test_removeBookmarkWithKeyword()
check_uri_keyword(URIS[1], "keyword");
check_uri_keyword(URIS[0], "keyword");
promiseAsyncUpdates().then(function() {
PlacesTestUtils.promiseAsyncUpdates().then(() => {
check_orphans();
run_next_test();
});
@ -157,7 +157,7 @@ add_test(function test_removeFolderWithKeywordedBookmarks()
check_uri_keyword(URIS[1], null);
check_uri_keyword(URIS[0], null);
promiseAsyncUpdates().then(function() {
PlacesTestUtils.promiseAsyncUpdates().then(() => {
check_orphans();
run_next_test();
});

View File

@ -55,7 +55,7 @@ function errorListener() {
"Docshell URI is the original URI.");
// Global history does not record URI of a failed request.
promiseAsyncUpdates().then(function() {
PlacesTestUtils.promiseAsyncUpdates().then(() => {
gAsyncHistory.isURIVisited(kUniqueURI, errorAsyncListener);
});
}
@ -91,7 +91,7 @@ function reloadListener() {
"Document URI is not the offline-error page, but the original URI.");
// Check if global history remembers the successfully-requested URI.
promiseAsyncUpdates().then(function() {
PlacesTestUtils.promiseAsyncUpdates().then(() => {
gAsyncHistory.isURIVisited(kUniqueURI, reloadAsyncListener);
});
}

View File

@ -18,43 +18,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
/**
* Waits for all pending async statements on the default connection.
*
* @return {Promise}
* @resolves When all pending async statements finished.
* @rejects Never.
*
* @note The result is achieved by asynchronously executing a query requiring
* a write lock. Since all statements on the same connection are
* serialized, the end of this write operation means that all writes are
* complete. Note that WAL makes so that writers don't block readers, but
* this is a problem only across different connections.
*/
function promiseAsyncUpdates()
{
let deferred = Promise.defer();
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
begin.executeAsync();
begin.finalize();
let commit = db.createAsyncStatement("COMMIT");
commit.executeAsync({
handleResult: function() {},
handleError: function() {},
handleCompletion: function(aReason)
{
deferred.resolve();
}
});
commit.finalize();
return deferred.promise;
}
/**
* Returns a moz_places field value for a url.
*

View File

@ -69,7 +69,7 @@ add_test(function test_query_result_favicon_changed_on_child()
// operation, and then for the main thread to process any pending
// notifications that came from the asynchronous thread, before we can be
// sure that nodeIconChanged was not invoked in the meantime.
promiseAsyncUpdates().then(function QRFCOC_asyncUpdates() {
PlacesTestUtils.promiseAsyncUpdates().then(function QRFCOC_asyncUpdates() {
do_execute_soon(function QRFCOC_soon() {
result.removeObserver(resultObserver);

View File

@ -139,7 +139,7 @@ add_task(function test_replaceFaviconData_replaceExisting() {
iconsvc.replaceFaviconData(
firstFavicon.uri, secondFavicon.data, secondFavicon.data.length,
secondFavicon.mimetype);
promiseAsyncUpdates().then(function() {
PlacesTestUtils.promiseAsyncUpdates().then(() => {
checkFaviconDataForPage(
pageURI, secondFavicon.mimetype, secondFavicon.data,
function test_replaceFaviconData_overrideDefaultFavicon_secondCallback() {

View File

@ -598,42 +598,6 @@ function is_time_ordered(before, after) {
return after - before > -skew;
}
/**
* Waits for all pending async statements on the default connection.
*
* @return {Promise}
* @resolves When all pending async statements finished.
* @rejects Never.
*
* @note The result is achieved by asynchronously executing a query requiring
* a write lock. Since all statements on the same connection are
* serialized, the end of this write operation means that all writes are
* complete. Note that WAL makes so that writers don't block readers, but
* this is a problem only across different connections.
*/
function promiseAsyncUpdates()
{
let deferred = Promise.defer();
let db = DBConn();
let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
begin.executeAsync();
begin.finalize();
let commit = db.createAsyncStatement("COMMIT");
commit.executeAsync({
handleResult: function () {},
handleError: function () {},
handleCompletion: function(aReason)
{
deferred.resolve();
}
});
commit.finalize();
return deferred.promise;
}
/**
* Shutdowns Places, invoking the callback when the connection has been closed.
*

View File

@ -166,8 +166,8 @@ function run_test() {
// updates.
// This is not a problem in real life, but autocomplete tests should
// return reliable resultsets, thus we have to wait.
promiseAsyncUpdates().then(function () ensure_results(searchString,
expectedValue));
PlacesTestUtils.promiseAsyncUpdates()
.then(() => ensure_results(searchString, expectedValue));
})
}, this);

View File

@ -20,7 +20,7 @@ add_task(function* test_moz_hosts() {
yield db.execute("SELECT host, frecency, typed, prefix FROM moz_hosts");
// moz_hosts is populated asynchronously, so we need to wait.
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
// check the number of entries in moz_hosts equals the number of
// unique rev_host in moz_places

View File

@ -283,7 +283,7 @@ add_task(function test_add_visits_to_database()
add_task(function test_redirects()
{
// Frecency and hidden are updated asynchronously, wait for them.
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
// This array will be used by cartProd to generate a matrix of all possible
// combinations.

View File

@ -1266,7 +1266,7 @@ add_task(function test_sorting()
{
for (let [, test] in Iterator(tests)) {
yield test.setup();
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
test.check();
// sorting reversed, usually SORT_BY have ASC and DESC
test.check_reverse();

View File

@ -101,7 +101,7 @@ function* check_autocomplete(test) {
// updates.
// This is not a problem in real life, but autocomplete tests should
// return reliable resultsets, thus we have to wait.
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
// Make an AutoCompleteInput that uses our searches and confirms results.
let input = new AutoCompleteInput(["unifiedcomplete"]);

View File

@ -52,7 +52,7 @@ add_task(function* test_searchEngine_autoFill() {
}
yield promiseAddVisits(visits);
addBookmark({ uri: uri, title: "Example bookmark" });
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
ok(frecencyForUrl(uri) > 10000, "Added URI should have expected high frecency");
do_print("Check search domain is autoFilled even if there's an higher frecency match");

View File

@ -216,7 +216,7 @@ add_task(function test_frecency()
// DEBUG
//results.every(function(el) { dump("result: " + el[1] + ": " + el[0].spec + " (" + el[2] + ")\n"); return true; })
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
var controller = Components.classes["@mozilla.org/autocomplete/controller;1"].
getService(Components.interfaces.nsIAutoCompleteController);

View File

@ -53,7 +53,7 @@ function run_test() {
// 2. run the test-suite
Task.spawn(function() {
yield validate();
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
// Test exporting a Places canonical json file.
// 1. export to bookmarks.exported.json
@ -73,7 +73,7 @@ function run_test() {
yield validate();
LOG("validated import");
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_test_finished();
});
}

View File

@ -21,14 +21,14 @@ add_task(function changeuri_unvisited_bookmark()
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
PlacesUtils.bookmarks.changeBookmarkURI(id, uri("http://example.com/2"));
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Unvisited URI no longer bookmarked => frecency should = 0");
do_check_eq(frecencyForUrl(TEST_URI), 0);
@ -47,18 +47,18 @@ add_task(function changeuri_visited_bookmark()
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
yield promiseAddVisits(TEST_URI);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
PlacesUtils.bookmarks.changeBookmarkURI(id, uri("http://example.com/2"));
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("*Visited* URI no longer bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
@ -82,14 +82,14 @@ add_task(function changeuri_bookmark_still_bookmarked()
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark 2 title");
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
PlacesUtils.bookmarks.changeBookmarkURI(id1, uri("http://example.com/2"));
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("URI still bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);

View File

@ -40,7 +40,7 @@ add_test(function test_keywordRemovedOnUniqueItemRemoval() {
// remove bookmark
bmsvc.removeItem(bookmarkId);
promiseAsyncUpdates().then(function() {
PlacesTestUtils.promiseAsyncUpdates().then(() => {
// Check that keyword has been removed from the database.
// The removal is asynchronous.
var sql = "SELECT id FROM moz_keywords WHERE keyword = ?1";
@ -77,7 +77,7 @@ add_test(function test_keywordNotRemovedOnNonUniqueItemRemoval() {
// remove first bookmark
bmsvc.removeItem(bookmarkId1);
promiseAsyncUpdates().then(function() {
PlacesTestUtils.promiseAsyncUpdates().then(() => {
// check that keyword is still there
var sql = "SELECT id FROM moz_keywords WHERE keyword = ?1";
var stmt = mDBConn.createStatement(sql);

View File

@ -388,7 +388,7 @@ add_task(function* test_non_addable_uri_errors() {
do_check_eq(place.resultCode, Cr.NS_ERROR_INVALID_ARG);
do_check_false(yield promiseIsURIVisited(place.info.uri));
}
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_duplicate_guid_errors() {
@ -426,7 +426,7 @@ add_task(function* test_duplicate_guid_errors() {
do_check_eq(badPlaceInfo.resultCode, Cr.NS_ERROR_STORAGE_CONSTRAINT);
do_check_false(yield promiseIsURIVisited(badPlaceInfo.info.uri));
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_invalid_referrerURI_ignored() {
@ -462,7 +462,7 @@ add_task(function* test_invalid_referrerURI_ignored() {
do_check_eq(stmt.row.from_visit, 0);
stmt.finalize();
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_nonnsIURI_referrerURI_ignored() {
@ -494,7 +494,7 @@ add_task(function* test_nonnsIURI_referrerURI_ignored() {
do_check_eq(stmt.row.from_visit, 0);
stmt.finalize();
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_old_referrer_ignored() {
@ -553,7 +553,7 @@ add_task(function* test_old_referrer_ignored() {
do_check_eq(stmt.row.count, 1);
stmt.finalize();
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_place_id_ignored() {
@ -593,7 +593,7 @@ add_task(function* test_place_id_ignored() {
do_check_neq(placeInfo.placeId, placeId);
do_check_true(yield promiseIsURIVisited(badPlace.uri));
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_handleCompletion_called_when_complete() {
@ -634,7 +634,7 @@ add_task(function* test_handleCompletion_called_when_complete() {
do_check_eq(callbackCountSuccess, EXPECTED_COUNT_SUCCESS);
do_check_eq(callbackCountFailure, EXPECTED_COUNT_FAILURE);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_add_visit() {
@ -695,7 +695,7 @@ add_task(function* test_add_visit() {
// If we have had all of our callbacks, continue running tests.
if (++callbackCount == place.visits.length) {
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
}
}
});
@ -778,7 +778,7 @@ add_task(function* test_properties_saved() {
// If we have had all of our callbacks, continue running tests.
if (++callbackCount == places.length) {
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
}
}
});
@ -803,7 +803,7 @@ add_task(function* test_guid_saved() {
do_check_true(yield promiseIsURIVisited(uri));
do_check_eq(placeInfo.guid, place.guid);
do_check_guid_for_uri(uri, place.guid);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_referrer_saved() {
@ -853,7 +853,7 @@ add_task(function* test_referrer_saved() {
do_check_eq(stmt.row.count, 1);
stmt.finalize();
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
}
}
});
@ -881,7 +881,7 @@ add_task(function* test_guid_change_saved() {
}
do_check_guid_for_uri(place.uri, place.guid);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_title_change_saved() {
@ -927,7 +927,7 @@ add_task(function* test_title_change_saved() {
}
do_check_title_for_uri(place.uri, place.title);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_no_title_does_not_clear_title() {
@ -955,7 +955,7 @@ add_task(function* test_no_title_does_not_clear_title() {
}
do_check_title_for_uri(place.uri, TITLE);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_title_change_notifies() {
@ -1011,7 +1011,7 @@ add_task(function* test_title_change_notifies() {
}
yield promiseTitleChangedObserver(place);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function* test_visit_notifies() {
@ -1059,7 +1059,7 @@ add_task(function* test_visit_notifies() {
}
yield promiseVisitObserver(place);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
// test with empty mozIVisitInfoCallback object
@ -1089,7 +1089,7 @@ add_task(function* test_callbacks_not_supplied() {
});
PlacesUtils.asyncHistory.updatePlaces(places, {});
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
// Test that we don't wrongly overwrite typed and hidden when adding new visits.

View File

@ -99,11 +99,11 @@ add_task(function* setup() {
// 2. run the test-suite
// Note: we do not empty the db before this import to catch bugs like 380999
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileOld, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield testImportedBookmarks();
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
remove_all_bookmarks();
});
@ -113,10 +113,10 @@ add_task(function* test_import_new()
// 1. import bookmarks.exported.html
// 2. run the test-suite
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield testImportedBookmarks();
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
remove_all_bookmarks();
});
@ -135,7 +135,7 @@ add_task(function* test_emptytitle_export()
// 9. empty bookmarks db and continue
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
const NOTITLE_URL = "http://notitle.mozilla.org/";
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
@ -145,11 +145,11 @@ add_task(function* test_emptytitle_export()
test_bookmarks.unfiled.push({ title: "", url: NOTITLE_URL });
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
remove_all_bookmarks();
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield testImportedBookmarks();
// Cleanup.
@ -157,7 +157,7 @@ add_task(function* test_emptytitle_export()
PlacesUtils.bookmarks.removeItem(id);
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
remove_all_bookmarks();
});
@ -179,7 +179,7 @@ add_task(function* test_import_chromefavicon()
const CHROME_FAVICON_URI_2 = NetUtil.newURI("chrome://global/skin/icons/error-16.png");
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
PAGE_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
@ -204,7 +204,7 @@ add_task(function* test_import_chromefavicon()
{ title: "Test", url: PAGE_URI.spec, icon: base64Icon });
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
// Change the favicon to check it's really imported again later.
deferred = Promise.defer();
@ -217,7 +217,7 @@ add_task(function* test_import_chromefavicon()
remove_all_bookmarks();
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield testImportedBookmarks();
// Cleanup.
@ -225,7 +225,7 @@ add_task(function* test_import_chromefavicon()
PlacesUtils.bookmarks.removeItem(id);
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
remove_all_bookmarks();
});
@ -240,14 +240,14 @@ add_task(function* test_import_ontop()
// 4. run the test-suite
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield testImportedBookmarks();
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
remove_all_bookmarks();
});

View File

@ -78,7 +78,7 @@ add_task(function test_import_bookmarks() {
let bookmarksFile = OS.Path.join(do_get_cwd().path, "bookmarks.json");
yield BookmarkJSONUtils.importFromFile(bookmarksFile, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield testImportedBookmarks();
});
@ -86,24 +86,24 @@ add_task(function test_export_bookmarks() {
bookmarksExportedFile = OS.Path.join(OS.Constants.Path.profileDir,
"bookmarks.exported.json");
yield BookmarkJSONUtils.exportToFile(bookmarksExportedFile);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
});
add_task(function test_import_exported_bookmarks() {
remove_all_bookmarks();
yield BookmarkJSONUtils.importFromFile(bookmarksExportedFile, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield testImportedBookmarks();
});
add_task(function test_import_ontop() {
remove_all_bookmarks();
yield BookmarkJSONUtils.importFromFile(bookmarksExportedFile, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield BookmarkJSONUtils.exportToFile(bookmarksExportedFile);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield BookmarkJSONUtils.importFromFile(bookmarksExportedFile, true);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
yield testImportedBookmarks();
});

View File

@ -73,8 +73,8 @@ AutoCompleteInput.prototype = {
function ensure_results(uris, searchTerm)
{
promiseAsyncUpdates().then(function () ensure_results_internal(uris,
searchTerm));
PlacesTestUtils.promiseAsyncUpdates()
.then(() => ensure_results_internal(uris, searchTerm));
}
function ensure_results_internal(uris, searchTerm)

View File

@ -15,13 +15,13 @@ add_task(function ()
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"A title");
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_check_true(frecencyForUrl(TEST_URI) > 0);
// Removing the bookmark should leave an orphan page with zero frecency.
// Note this would usually be expired later by expiration.
PlacesUtils.bookmarks.removeItem(id);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_check_eq(frecencyForUrl(TEST_URI), 0);
// Now add a valid visit to the page, frecency should increase.

View File

@ -91,7 +91,7 @@ add_task(function* test_history_clear()
{ uri: uri("http://frecency.mozilla.org/"),
transition: TRANSITION_LINK },
]);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
// Clear history and wait for the onClearHistory notification.
let promiseWaitClearHistory = promiseOnClearHistoryObserved();
@ -102,7 +102,7 @@ add_task(function* test_history_clear()
do_check_eq(0, PlacesUtils.history.hasHistoryEntries);
yield promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
// Check that frecency for not cleared items (bookmarks) has been converted
// to -MAX(visit_count, 1), so we will be able to recalculate frecency

View File

@ -151,7 +151,7 @@ add_test(function check_history_query() {
do_check_eq(resultObserver.closedContainer, resultObserver.openedContainer);
result.removeObserver(resultObserver);
resultObserver.reset();
promiseAsyncUpdates().then(run_next_test);
PlacesTestUtils.promiseAsyncUpdates().then(run_next_test);
});
});
});
@ -219,7 +219,7 @@ add_test(function check_bookmarks_query() {
do_check_eq(resultObserver.closedContainer, resultObserver.openedContainer);
result.removeObserver(resultObserver);
resultObserver.reset();
promiseAsyncUpdates().then(run_next_test);
PlacesTestUtils.promiseAsyncUpdates().then(run_next_test);
});
add_test(function check_mixed_query() {
@ -252,5 +252,5 @@ add_test(function check_mixed_query() {
do_check_eq(resultObserver.closedContainer, resultObserver.openedContainer);
result.removeObserver(resultObserver);
resultObserver.reset();
promiseAsyncUpdates().then(run_next_test);
PlacesTestUtils.promiseAsyncUpdates().then(run_next_test);
});

View File

@ -27,7 +27,7 @@ add_task(function remove_visits_outside_unbookmarked_uri() {
do_print("Remove visits using timerange outside the URI's visits.");
PlacesUtils.history.removeVisitsByTimeframe(NOW - 10, NOW);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("URI should still exist in moz_places.");
do_check_true(page_in_database(TEST_URI.spec));
@ -49,7 +49,7 @@ add_task(function remove_visits_outside_unbookmarked_uri() {
do_print("asyncHistory.isURIVisited should return true.");
do_check_true(yield promiseIsURIVisited(TEST_URI));
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Frecency should be positive.")
do_check_true(frecencyForUrl(TEST_URI) > 0);
@ -70,11 +70,11 @@ add_task(function remove_visits_outside_bookmarked_uri() {
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Remove visits using timerange outside the URI's visits.");
PlacesUtils.history.removeVisitsByTimeframe(NOW - 10, NOW);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("URI should still exist in moz_places.");
do_check_true(page_in_database(TEST_URI.spec));
@ -95,7 +95,7 @@ add_task(function remove_visits_outside_bookmarked_uri() {
do_print("asyncHistory.isURIVisited should return true.");
do_check_true(yield promiseIsURIVisited(TEST_URI));
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Frecency should be positive.")
do_check_true(frecencyForUrl(TEST_URI) > 0);
@ -115,7 +115,7 @@ add_task(function remove_visits_unbookmarked_uri() {
do_print("Remove the 5 most recent visits.");
PlacesUtils.history.removeVisitsByTimeframe(NOW - 4, NOW);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("URI should still exist in moz_places.");
do_check_true(page_in_database(TEST_URI.spec));
@ -136,7 +136,7 @@ add_task(function remove_visits_unbookmarked_uri() {
do_print("asyncHistory.isURIVisited should return true.");
do_check_true(yield promiseIsURIVisited(TEST_URI));
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Frecency should be positive.")
do_check_true(frecencyForUrl(TEST_URI) > 0);
@ -158,11 +158,11 @@ add_task(function remove_visits_bookmarked_uri() {
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Remove the 5 most recent visits.");
PlacesUtils.history.removeVisitsByTimeframe(NOW - 4, NOW);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("URI should still exist in moz_places.");
do_check_true(page_in_database(TEST_URI.spec));
@ -183,7 +183,7 @@ add_task(function remove_visits_bookmarked_uri() {
do_print("asyncHistory.isURIVisited should return true.");
do_check_true(yield promiseIsURIVisited(TEST_URI));
yield promiseAsyncUpdates()
yield PlacesTestUtils.promiseAsyncUpdates()
do_print("Frecency should be positive.")
do_check_true(frecencyForUrl(TEST_URI) > 0);
@ -203,7 +203,7 @@ add_task(function remove_all_visits_unbookmarked_uri() {
do_print("Remove all visits.");
PlacesUtils.history.removeVisitsByTimeframe(NOW - 10, NOW);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("URI should no longer exist in moz_places.");
do_check_false(page_in_database(TEST_URI.spec));
@ -235,7 +235,7 @@ add_task(function remove_all_visits_unbookmarked_place_uri() {
do_print("Remove all visits.");
PlacesUtils.history.removeVisitsByTimeframe(NOW - 10, NOW);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("URI should still exist in moz_places.");
do_check_true(page_in_database(PLACE_URI.spec));
@ -252,7 +252,7 @@ add_task(function remove_all_visits_unbookmarked_place_uri() {
do_print("asyncHistory.isURIVisited should return false.");
do_check_false(yield promiseIsURIVisited(PLACE_URI));
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Frecency should be zero.")
do_check_eq(frecencyForUrl(PLACE_URI.spec), 0);
@ -274,11 +274,11 @@ add_task(function remove_all_visits_bookmarked_uri() {
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Remove all visits.");
PlacesUtils.history.removeVisitsByTimeframe(NOW - 10, NOW);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("URI should still exist in moz_places.");
do_check_true(page_in_database(TEST_URI.spec));
@ -298,7 +298,7 @@ add_task(function remove_all_visits_bookmarked_uri() {
do_print("nsINavBookmarksService.isBookmarked should return true.");
do_check_true(PlacesUtils.bookmarks.isBookmarked(TEST_URI));
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("Frecency should be negative.")
do_check_true(frecencyForUrl(TEST_URI) < 0);
@ -317,7 +317,7 @@ add_task(function remove_all_visits_bookmarked_uri() {
do_print("Remove newer visit.");
PlacesUtils.history.removeVisitsByTimeframe(NOW - 10, NOW);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
do_print("URI should still exist in moz_places.");
do_check_true(page_in_database(TEST_URI.spec));

View File

@ -59,7 +59,7 @@ add_task(function test_execute()
.getService(Ci.nsIObserver)
.observe(null, "gather-telemetry", null);
yield promiseAsyncUpdates();
yield PlacesTestUtils.promiseAsyncUpdates();
// Test expiration probes.
for (let i = 0; i < 2; i++) {

View File

@ -21,15 +21,13 @@ add_test(function removed_bookmark()
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
promiseAsyncUpdates().then(function ()
{
PlacesTestUtils.promiseAsyncUpdates().then(() => {
do_print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
PlacesUtils.bookmarks.removeItem(id);
promiseAsyncUpdates().then(function ()
{
PlacesTestUtils.promiseAsyncUpdates().then(() => {
do_print("Unvisited URI no longer bookmarked => frecency should = 0");
do_check_eq(frecencyForUrl(TEST_URI), 0);
@ -48,16 +46,14 @@ add_test(function removed_but_visited_bookmark()
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
promiseAsyncUpdates().then(function ()
{
PlacesTestUtils.promiseAsyncUpdates().then(() => {
do_print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
promiseAddVisits(TEST_URI).then(function () {
PlacesUtils.bookmarks.removeItem(id);
promiseAsyncUpdates().then(function ()
{
PlacesTestUtils.promiseAsyncUpdates().then(() => {
do_print("*Visited* URI no longer bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
@ -81,15 +77,13 @@ add_test(function remove_bookmark_still_bookmarked()
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark 2 title");
promiseAsyncUpdates().then(function ()
{
PlacesTestUtils.promiseAsyncUpdates().then(() => {
do_print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
PlacesUtils.bookmarks.removeItem(id1);
promiseAsyncUpdates().then(function ()
{
PlacesTestUtils.promiseAsyncUpdates().then(() => {
do_print("URI still bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
@ -108,16 +102,14 @@ add_test(function cleared_parent_of_visited_bookmark()
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
promiseAsyncUpdates().then(function ()
{
PlacesTestUtils.promiseAsyncUpdates().then(() => {
do_print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
promiseAddVisits(TEST_URI).then(function () {
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
promiseAsyncUpdates().then(function ()
{
PlacesTestUtils.promiseAsyncUpdates().then(() => {
do_print("*Visited* URI no longer bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
@ -143,15 +135,13 @@ add_test(function cleared_parent_of_bookmark_still_bookmarked()
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark 2 title");
promiseAsyncUpdates().then(function ()
{
PlacesTestUtils.promiseAsyncUpdates().then(() => {
do_print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
promiseAsyncUpdates().then(function ()
{
PlacesTestUtils.promiseAsyncUpdates().then(() => {
// URI still bookmarked => frecency should != 0.
do_check_neq(frecencyForUrl(TEST_URI), 0);

View File

@ -28,9 +28,11 @@ function closeWindow(aClose, aPromptFunction)
if (typeof(aPromptFunction) == "function" && !aPromptFunction())
return false;
if (aClose)
if (aClose) {
window.close();
return window.closed;
}
return true;
}

View File

@ -297,7 +297,7 @@
}
#header-utils-btn {
list-style-image: url("chrome://mozapps/skin/extensions/utilities.png");
list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities");
-moz-margin-end: 18px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -32,7 +32,7 @@ toolkit.jar:
skin/classic/mozapps/extensions/rating-won.png (extensions/rating-won.png)
skin/classic/mozapps/extensions/rating-not-won.png (extensions/rating-not-won.png)
skin/classic/mozapps/extensions/cancel.png (extensions/cancel.png)
skin/classic/mozapps/extensions/utilities.png (extensions/utilities.png)
skin/classic/mozapps/extensions/utilities.svg (../../shared/extensions/utilities.svg)
skin/classic/mozapps/extensions/toolbarbutton-dropmarker.png (extensions/toolbarbutton-dropmarker.png)
skin/classic/mozapps/extensions/heart.png (extensions/heart.png)
skin/classic/mozapps/extensions/navigation.png (extensions/navigation.png)

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0"
y="0"
width="16"
height="16"
viewBox="0 0 16 16">
<style>
use:not(:target) {
display: none;
}
use {
fill: #424f5a;
}
use[id$="-native"] {
fill: GrayText;
}
</style>
<defs style="display: none;">
<path id="utilities-shape" d="m11.5,13.9l-.6-1.5c.3-.2 .5-.4 .8-.6 .2-.2 .4-.5 .6-.7l1.5,.6c.3,.1 .6,0 .7-.3l.4-1c.1-.3 0-.6-.3-.7l-1.5-.6c.1-.6 .1-1.3 0-2l1.5-.6c.3-.1 .4-.4 .3-.7l-.4-1c-.1-.3-.4-.4-.7-.3l-1.5,.6c-.2-.3-.4-.5-.6-.8-.2-.1-.5-.3-.7-.5l.6-1.5c.1-.3 0-.6-.3-.7l-.9-.4c-.3-.1-.6,0-.7,.3l-.6,1.5c-.6-.1-1.3-.1-2,0l-.6-1.5c-.1-.3-.4-.4-.7-.3l-1,.4c-.2,.1-.3,.4-.2,.6l.6,1.5c-.3,.3-.5,.5-.8,.7-.2,.3-.4,.5-.6,.8l-1.5-.7c-.3-.1-.6,0-.7,.3l-.4,.9c-.1,.3 0,.6 .3,.7l1.5,.7c-.1,.6-.1,1.3 0,1.9l-1.5,.6c-.3,.1-.4,.4-.3,.7l.4,1c.1,.3 .4,.4 .7,.3l1.5-.6c.2,.3 .4,.5 .6,.8 .2,.2 .5,.4 .7,.6l-.6,1.5c-.1,.3 0,.6 .3,.7l1,.4c.3,.1 .6,0 .7-.3l.6-1.5c.6,.1 1.3,.1 2,0l.6,1.5c.1,.3 .4,.4 .7,.3l1-.4c.1-.1 .3-.4 .1-.7zm-5.1-4.2c-.9-.9-.9-2.4 0-3.3 .9-.9 2.4-.9 3.3,0 .9,.9 .9,2.4 0,3.3-.9,.9-2.4,.9-3.3,0z"/>
</defs>
<use id="utilities" xlink:href="#utilities-shape"/>
<use id="utilities-native" xlink:href="#utilities-shape"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -332,10 +332,16 @@
}
#header-utils-btn {
list-style-image: url("chrome://mozapps/skin/extensions/utilities.png");
list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities");
-moz-margin-end: 16px;
}
@media not all and (-moz-windows-default-theme) {
#header-utils-btn {
list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities-native");
}
}
.view-header {
background-color: rgba(251, 252, 253, 0.25);
padding: 4px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 B

View File

@ -40,7 +40,7 @@ toolkit.jar:
skin/classic/mozapps/extensions/rating-won.png (extensions/rating-won.png)
skin/classic/mozapps/extensions/rating-not-won.png (extensions/rating-not-won.png)
skin/classic/mozapps/extensions/cancel.png (extensions/cancel.png)
skin/classic/mozapps/extensions/utilities.png (extensions/utilities.png)
skin/classic/mozapps/extensions/utilities.svg (../../shared/extensions/utilities.svg)
skin/classic/mozapps/extensions/heart.png (extensions/heart.png)
skin/classic/mozapps/extensions/navigation.png (extensions/navigation.png)
skin/classic/mozapps/extensions/stripes-warning.png (extensions/stripes-warning.png)
@ -122,7 +122,7 @@ toolkit.jar:
skin/classic/aero/mozapps/extensions/rating-won.png (extensions/rating-won.png)
skin/classic/aero/mozapps/extensions/rating-not-won.png (extensions/rating-not-won.png)
skin/classic/aero/mozapps/extensions/cancel.png (extensions/cancel.png)
skin/classic/aero/mozapps/extensions/utilities.png (extensions/utilities.png)
skin/classic/aero/mozapps/extensions/utilities.svg (../../shared/extensions/utilities.svg)
skin/classic/aero/mozapps/extensions/heart.png (extensions/heart.png)
skin/classic/aero/mozapps/extensions/navigation.png (extensions/navigation.png)
skin/classic/aero/mozapps/extensions/stripes-warning.png (extensions/stripes-warning.png)

View File

@ -1705,88 +1705,86 @@ AndroidBridge::GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId,
}
static float
GetScaleFactor(nsPresContext* mPresContext) {
nsIPresShell* presShell = mPresContext->PresShell();
LayoutDeviceToLayerScale cumulativeResolution(presShell->GetCumulativeResolution().width);
return cumulativeResolution.scale;
GetScaleFactor(nsPresContext* aPresContext) {
nsIPresShell* presShell = aPresContext->PresShell();
LayoutDeviceToLayerScale cumulativeResolution(presShell->GetCumulativeResolution().width);
return cumulativeResolution.scale;
}
nsresult
AndroidBridge::CaptureZoomedView (nsIDOMWindow *window, nsIntRect zoomedViewRect, Object::Param buffer,
AndroidBridge::CaptureZoomedView(nsIDOMWindow *window, nsIntRect zoomedViewRect, Object::Param buffer,
float zoomFactor) {
nsresult rv;
struct timeval timeStart;
gettimeofday (&timeStart, NULL);
nsresult rv;
if (!buffer)
return NS_ERROR_FAILURE;
if (!buffer)
return NS_ERROR_FAILURE;
nsCOMPtr < nsIDOMWindowUtils > utils = do_GetInterface (window);
if (!utils)
return NS_ERROR_FAILURE;
nsCOMPtr <nsIDOMWindowUtils> utils = do_GetInterface(window);
if (!utils)
return NS_ERROR_FAILURE;
JNIEnv* env = GetJNIEnv ();
JNIEnv* env = GetJNIEnv();
AutoLocalJNIFrame jniFrame (env, 0);
AutoLocalJNIFrame jniFrame(env, 0);
nsCOMPtr < nsPIDOMWindow > win = do_QueryInterface (window);
if (!win) {
return NS_ERROR_FAILURE;
}
nsRefPtr < nsPresContext > presContext;
nsCOMPtr <nsPIDOMWindow> win = do_QueryInterface(window);
if (!win) {
return NS_ERROR_FAILURE;
}
nsRefPtr <nsPresContext> presContext;
nsIDocShell* docshell = win->GetDocShell ();
nsIDocShell* docshell = win->GetDocShell();
if (docshell) {
docshell->GetPresContext (getter_AddRefs (presContext));
}
if (docshell) {
docshell->GetPresContext(getter_AddRefs(presContext));
}
if (!presContext) {
return NS_ERROR_FAILURE;
}
nsCOMPtr < nsIPresShell > presShell = presContext->PresShell ();
if (!presContext) {
return NS_ERROR_FAILURE;
}
nsCOMPtr <nsIPresShell> presShell = presContext->PresShell();
float scaleFactor = GetScaleFactor(presContext) ;
float scaleFactor = GetScaleFactor(presContext) ;
nscolor bgColor = NS_RGB (255, 255, 255);
uint32_t renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING | nsIPresShell::RENDER_DOCUMENT_RELATIVE);
nsRect r (presContext->DevPixelsToAppUnits(zoomedViewRect.x / scaleFactor),
presContext->DevPixelsToAppUnits(zoomedViewRect.y / scaleFactor ),
presContext->DevPixelsToAppUnits(zoomedViewRect.width / scaleFactor ),
presContext->DevPixelsToAppUnits(zoomedViewRect.height / scaleFactor ));
nscolor bgColor = NS_RGB(255, 255, 255);
uint32_t renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING | nsIPresShell::RENDER_DOCUMENT_RELATIVE);
nsRect r(presContext->DevPixelsToAppUnits(zoomedViewRect.x / scaleFactor),
presContext->DevPixelsToAppUnits(zoomedViewRect.y / scaleFactor ),
presContext->DevPixelsToAppUnits(zoomedViewRect.width / scaleFactor ),
presContext->DevPixelsToAppUnits(zoomedViewRect.height / scaleFactor ));
bool is24bit = (GetScreenDepth () == 24);
SurfaceFormat format = is24bit ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::R5G6B5;
gfxImageFormat iFormat = gfx::SurfaceFormatToImageFormat(format);
uint32_t stride = gfxASurface::FormatStrideForWidth(iFormat, zoomedViewRect.width);
bool is24bit = (GetScreenDepth() == 24);
SurfaceFormat format = is24bit ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::R5G6B5;
gfxImageFormat iFormat = gfx::SurfaceFormatToImageFormat(format);
uint32_t stride = gfxASurface::FormatStrideForWidth(iFormat, zoomedViewRect.width);
uint8_t* data = static_cast<uint8_t*> (env->GetDirectBufferAddress (buffer.Get()));
if (!data) {
return NS_ERROR_FAILURE;
}
uint8_t* data = static_cast<uint8_t*> (env->GetDirectBufferAddress(buffer.Get()));
if (!data) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT (gfxPlatform::GetPlatform ()->SupportsAzureContentForType (BackendType::CAIRO),
MOZ_ASSERT (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO),
"Need BackendType::CAIRO support");
RefPtr < DrawTarget > dt = Factory::CreateDrawTargetForData (
BackendType::CAIRO, data, IntSize (zoomedViewRect.width, zoomedViewRect.height), stride,
format);
if (!dt) {
ALOG_BRIDGE ("Error creating DrawTarget");
return NS_ERROR_FAILURE;
}
nsRefPtr < gfxContext > context = new gfxContext (dt);
context->SetMatrix (context->CurrentMatrix ().Scale(zoomFactor, zoomFactor));
RefPtr < DrawTarget > dt = Factory::CreateDrawTargetForData(
BackendType::CAIRO, data, IntSize(zoomedViewRect.width, zoomedViewRect.height), stride,
format);
if (!dt) {
ALOG_BRIDGE("Error creating DrawTarget");
return NS_ERROR_FAILURE;
}
nsRefPtr <gfxContext> context = new gfxContext(dt);
context->SetMatrix(context->CurrentMatrix().Scale(zoomFactor, zoomFactor));
rv = presShell->RenderDocument (r, renderDocFlags, bgColor, context);
rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context);
if (is24bit) {
gfxUtils::ConvertBGRAtoRGBA (data, stride * zoomedViewRect.height);
}
if (is24bit) {
gfxUtils::ConvertBGRAtoRGBA(data, stride * zoomedViewRect.height);
}
LayerView::updateZoomedView(buffer);
LayerView::updateZoomedView(buffer);
NS_ENSURE_SUCCESS (rv, rv);
return NS_OK;
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult AndroidBridge::CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, Object::Param buffer, bool &shouldStore)