Merge m-c to b2g-inbound a=merge

This commit is contained in:
Wes Kocher 2014-06-27 17:52:52 -07:00
commit 6736a62c9f
246 changed files with 5286 additions and 19210 deletions

View File

@ -22,4 +22,6 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Clobber to make sure any residual damage from bug 975011 is gone.
Bug 800200: Removing the old JavaScript debugging API, js/jsd. I'm advised
that our build system doesn't cope well with deletions, and that a spoonful
of clobber helps the medicine go down (in a most delightful way).

View File

@ -24,14 +24,14 @@ add_task(function() {
ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
is(bookmarksToolbar.collapsed, true, "Test should start with bookmarks toolbar collapsed");
is(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should have height=0");
isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
ok(bookmarksToolbar.collapsed, "bookmarksToolbar should be collapsed");
ok(!tabsToolbar.collapsed, "TabsToolbar should not be collapsed");
is(navbar.collapsed, false, "The nav-bar should be shown by default");
setToolbarVisibility(bookmarksToolbar, true);
setToolbarVisibility(navbar, false);
isnot(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should be visible now");
ok(navbar.getBoundingClientRect().height <= 1, "navbar should have height=0 or 1 (due to border)");
ok(!bookmarksToolbar.collapsed, "bookmarksToolbar should be visible now");
ok(navbar.collapsed, "navbar should be collapsed");
is(CustomizableUI.inDefaultState, false, "Should no longer be in default state");
yield startCustomizing();
@ -40,8 +40,8 @@ add_task(function() {
yield endCustomizing();
is(bookmarksToolbar.collapsed, true, "Customization reset should restore collapsed-state to the bookmarks toolbar");
isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
is(bookmarksToolbar.getBoundingClientRect().height, 0, "The bookmarksToolbar should have height=0 after reset");
ok(!tabsToolbar.collapsed, "TabsToolbar should not be collapsed");
ok(bookmarksToolbar.collapsed, "The bookmarksToolbar should be collapsed after reset");
ok(CustomizableUI.inDefaultState, "Everything should be back to default state");
});
@ -74,25 +74,25 @@ add_task(function() {
// Customization reset should restore collapsed-state to default-collapsed toolbars.
add_task(function() {
ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
is(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should have height=0");
isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
ok(bookmarksToolbar.collapsed, "bookmarksToolbar should be collapsed");
ok(!tabsToolbar.collapsed, "TabsToolbar should not be collapsed");
setToolbarVisibility(bookmarksToolbar, true);
isnot(bookmarksToolbar.getBoundingClientRect().height, 0, "bookmarksToolbar should be visible now");
ok(!bookmarksToolbar.collapsed, "bookmarksToolbar should be visible now");
is(CustomizableUI.inDefaultState, false, "Should no longer be in default state");
yield startCustomizing();
isnot(bookmarksToolbar.getBoundingClientRect().height, 0, "The bookmarksToolbar should be visible before reset");
isnot(navbar.getBoundingClientRect().height, 0, "The navbar should be visible before reset");
isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
ok(!bookmarksToolbar.collapsed, "The bookmarksToolbar should be visible before reset");
ok(!navbar.collapsed, "The navbar should be visible before reset");
ok(!tabsToolbar.collapsed, "TabsToolbar should not be collapsed");
gCustomizeMode.reset();
yield waitForCondition(function() !gCustomizeMode.resetting);
is(bookmarksToolbar.getBoundingClientRect().height, 0, "The bookmarksToolbar should have height=0 after reset");
isnot(tabsToolbar.getBoundingClientRect().height, 0, "TabsToolbar should have non-zero height");
isnot(navbar.getBoundingClientRect().height, 0, "The navbar should still be visible after reset");
ok(bookmarksToolbar.collapsed, "The bookmarksToolbar should be collapsed after reset");
ok(!tabsToolbar.collapsed, "TabsToolbar should not be collapsed");
ok(!navbar.collapsed, "The navbar should still be visible after reset");
ok(CustomizableUI.inDefaultState, "Everything should be back to default state");
yield endCustomizing();
});

View File

@ -139,7 +139,6 @@ loop.shared.models = (function() {
throw new Error("Can't start session as it's not ready");
}
this.session = this.sdk.initSession(this.get("sessionId"));
this.listenTo(this.session, "sessionConnected", this._sessionConnected);
this.listenTo(this.session, "streamCreated", this._streamCreated);
this.listenTo(this.session, "connectionDestroyed",
this._connectionDestroyed);
@ -147,7 +146,8 @@ loop.shared.models = (function() {
this._sessionDisconnected);
this.listenTo(this.session, "networkDisconnected",
this._networkDisconnected);
this.session.connect(this.get("apiKey"), this.get("sessionToken"));
this.session.connect(this.get("apiKey"), this.get("sessionToken"),
this._onConnectCompletion.bind(this));
},
/**
@ -160,14 +160,22 @@ loop.shared.models = (function() {
},
/**
* Session is created.
* Manages connection status
* triggers apropriate event for connection error/success
* http://tokbox.com/opentok/tutorials/connect-session/js/
* http://tokbox.com/opentok/tutorials/hello-world/js/
* http://tokbox.com/opentok/libraries/client/js/reference/SessionConnectEvent.html
*
* @param {SessionConnectEvent} event
* @param {error|null} error
*/
_sessionConnected: function(event) {
this.trigger("session:connected", event);
this.set("ongoing", true);
_onConnectCompletion: function(error) {
if (error) {
this.trigger("session:connection-error", error);
this.endSession();
} else {
this.trigger("session:connected");
this.set("ongoing", true);
}
},
/**

View File

@ -103,10 +103,22 @@ loop.shared.router = (function(l10n) {
this._onPeerHungup);
this.listenTo(this._conversation, "session:network-disconnected",
this._onNetworkDisconnected);
this.listenTo(this._conversation, "session:connection-error",
this._notifyError);
BaseRouter.apply(this, arguments);
},
/**
* Notify the user that the connection was not possible
* @param {{code: number, message: string}} error
*/
_notifyError: function(error) {
console.log(error);
this._notifier.errorL10n("connection_error_see_console_notification");
this.endCall();
},
/**
* Starts the call. This method should be overriden.
*/

View File

@ -13,6 +13,7 @@ use_latest_firefox.innerHTML=To use Loop, please use the latest version of <a hr
incompatible_device=Incompatible device
sorry_device_unsupported=Sorry, Loop does not currently support your device.
use_firefox_windows_mac_linux=Please open this page using the latest Firefox on Windows, Android, Mac or Linux.
connection_error_see_console_notification=Call failed; see console for details.
[fr]
call_has_ended=L'appel est terminé.

View File

@ -26,7 +26,9 @@ describe("loop.shared.models", function() {
apiKey: "apiKey"
};
fakeSession = _.extend({
connect: sandbox.spy(),
connect: function () {},
endSession: sandbox.stub(),
set: sandbox.stub(),
disconnect: sandbox.spy(),
unpublish: sandbox.spy()
}, Backbone.Events);
@ -163,12 +165,72 @@ describe("loop.shared.models", function() {
sinon.assert.calledOnce(fakeSDK.initSession);
});
describe("Session events", function() {
it("should trigger a session:connected event on sessionConnected",
function(done) {
model.once("session:connected", function(){ done(); });
it("should call connect", function() {
fakeSession.connect = sandbox.stub();
fakeSession.trigger("sessionConnected");
model.startSession();
sinon.assert.calledOnce(fakeSession.connect);
sinon.assert.calledWithExactly(fakeSession.connect,
sinon.match.string, sinon.match.string,
sinon.match.func);
});
it("should set ongoing to true when no error is called back",
function() {
fakeSession.connect = function(key, token, cb) {
cb(null);
};
sinon.stub(model, "set");
model.startSession();
sinon.assert.calledWith(model.set, "ongoing", true);
});
it("should trigger session:connected when no error is called back",
function() {
fakeSession.connect = function(key, token, cb) {
cb(null);
};
sandbox.stub(model, "trigger");
model.startSession();
sinon.assert.calledWithExactly(model.trigger, "session:connected");
});
describe("Session events", function() {
it("should trigger a fail event when an error is called back",
function() {
fakeSession.connect = function(key, token, cb) {
cb({
error: true
});
};
sinon.stub(model, "endSession");
model.startSession();
sinon.assert.calledOnce(model.endSession);
sinon.assert.calledWithExactly(model.endSession);
});
it("should trigger session:connection-error event when an error is" +
" called back", function() {
fakeSession.connect = function(key, token, cb) {
cb({
error: true
});
};
sandbox.stub(model, "trigger");
model.startSession();
sinon.assert.calledOnce(model.trigger);
sinon.assert.calledWithExactly(model.trigger,
"session:connection-error", sinon.match.object);
});
it("should trigger a session:ended event on sessionDisconnected",

View File

@ -125,6 +125,24 @@ describe("loop.shared.router", function() {
});
});
describe("session:connection-error", function() {
it("should warn the user when .connect() call fails", function() {
conversation.trigger("session:connection-error");
sinon.assert.calledOnce(notifier.errorL10n);
sinon.assert.calledWithExactly(notifier.errorL10n, sinon.match.string);
});
it("should invoke endCall()", function() {
conversation.trigger("session:connection-error");
sinon.assert.calledOnce(router.endCall);
sinon.assert.calledWithExactly(router.endCall);
});
});
it("should call startCall() once the call session is ready", function() {
conversation.trigger("session:ready");

View File

@ -11,7 +11,7 @@ for platform in all_platforms:
whitelist['nightly'][platform] = [
'ac_add_options --enable-update-channel=nightly',
'ac_add_options --enable-profiling',
'mk_add_options CLIENT_PY_ARGS="--hg-options=\'--verbose --time\' --hgtool=../tools/buildfarm/utils/hgtool.py --skip-chatzilla --skip-comm --skip-inspector --skip-venkman --tinderbox-print"'
'mk_add_options CLIENT_PY_ARGS="--hg-options=\'--verbose --time\' --hgtool=../tools/buildfarm/utils/hgtool.py --skip-chatzilla --skip-comm --skip-inspector --tinderbox-print"'
]
for platform in ['linux32', 'linux64', 'macosx-universal']:

View File

@ -277,9 +277,10 @@ DevTools.prototype = {
});
// If we were asked for a specific tool then we need to wait for the
// tool to be ready, otherwise we can just wait for toolbox open
// tool to be ready and selected, otherwise we can just wait for the
// toolbox open promise.
if (toolId != null) {
toolbox.once(toolId + "-ready", (event, panel) => {
toolbox.once(toolId + "-selected", (event, panel) => {
this.emit("toolbox-ready", toolbox);
deferred.resolve(toolbox);
});

View File

@ -39,13 +39,7 @@ function runTests(aTab) {
let target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, toolId).then(function(toolbox) {
// Wait for the test tool to be visible and selected.
let { promise: testToolShown, resolve } = promise.defer();
toolbox.once("test-tool-selected", resolve);
return testToolShown.then(() => toolbox);
}).then(function (toolbox) {
gDevTools.showToolbox(target, toolId).then(function (toolbox) {
is(toolbox.target, target, "toolbox target is correct");
is(toolbox._host.hostTab, gBrowser.selectedTab, "toolbox host is correct");
continueTests(toolbox);

View File

@ -53,10 +53,8 @@ function testToggle() {
target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, "styleeditor").then(function(aToolbox) {
toolbox = aToolbox;
aToolbox.once("styleeditor-selected", () => {
is(toolbox.currentToolId, "styleeditor", "The style editor is selected");
finishUp();
});
is(toolbox.currentToolId, "styleeditor", "The style editor is selected");
finishUp();
});
});

View File

@ -24,7 +24,9 @@ function test() {
}
function testShortcuts(aToolbox, aIndex) {
if (aIndex == toolIDs.length) {
if (aIndex === undefined) {
aIndex = 1;
} else if (aIndex == toolIDs.length) {
aIndex = 0;
if (secondTime) {
secondTime = false;
@ -55,20 +57,14 @@ function testShortcuts(aToolbox, aIndex) {
toolbox.once("select", onSelect);
if (aIndex != null) {
// This if block is to allow the call of onSelect without shortcut press for
// the first time. That happens because on opening of toolbox, one tool gets
// selected atleast.
let key = (reverse ? prevKey: nextKey);
let modifiers = {
accelKey: true
};
idIndex = aIndex;
info("Testing shortcut to switch to tool " + aIndex + ":" + toolIDs[aIndex] +
" using key " + key);
EventUtils.synthesizeKey(key, modifiers, toolbox.doc.defaultView);
}
let key = (reverse ? prevKey: nextKey);
let modifiers = {
accelKey: true
};
idIndex = aIndex;
info("Testing shortcut to switch to tool " + aIndex + ":" + toolIDs[aIndex] +
" using key " + key);
EventUtils.synthesizeKey(key, modifiers, toolbox.doc.defaultView);
}
function onSelect(event, id) {

View File

@ -41,7 +41,9 @@ function test() {
}
function testShortcuts(aToolbox, aIndex) {
if (aIndex == toolIDs.length) {
if (aIndex === undefined) {
aIndex = 1;
} else if (aIndex == toolIDs.length) {
tidyUp();
return;
}
@ -51,23 +53,17 @@ function testShortcuts(aToolbox, aIndex) {
toolbox.once("select", selectCB);
if (aIndex != null) {
// This if block is to allow the call of selectCB without shortcut press for
// the first time. That happens because on opening of toolbox, one tool gets
// selected atleast.
let key = gDevTools._tools.get(toolIDs[aIndex]).key;
let toolModifiers = gDevTools._tools.get(toolIDs[aIndex]).modifiers;
let modifiers = {
accelKey: toolModifiers.contains("accel"),
altKey: toolModifiers.contains("alt"),
shiftKey: toolModifiers.contains("shift"),
};
idIndex = aIndex;
info("Testing shortcut for tool " + aIndex + ":" + toolIDs[aIndex] +
" using key " + key);
EventUtils.synthesizeKey(key, modifiers, toolbox.doc.defaultView.parent);
}
let key = gDevTools._tools.get(toolIDs[aIndex]).key;
let toolModifiers = gDevTools._tools.get(toolIDs[aIndex]).modifiers;
let modifiers = {
accelKey: toolModifiers.contains("accel"),
altKey: toolModifiers.contains("alt"),
shiftKey: toolModifiers.contains("shift"),
};
idIndex = aIndex;
info("Testing shortcut for tool " + aIndex + ":" + toolIDs[aIndex] +
" using key " + key);
EventUtils.synthesizeKey(key, modifiers, toolbox.doc.defaultView.parent);
}
function selectCB(event, id) {

View File

@ -187,6 +187,7 @@ InspectorPanel.prototype = {
this.selection.setNodeFront(null);
this._destroyMarkup();
this.isDirty = false;
this._pendingSelection = null;
},
_getPageStyle: function() {
@ -204,18 +205,35 @@ InspectorPanel.prototype = {
}
let walker = this.walker;
let rootNode = null;
let pendingSelection = this._pendingSelection;
// A helper to tell if the target has or is about to navigate.
// this._pendingSelection changes on "will-navigate" and "new-root" events.
let hasNavigated = () => pendingSelection !== this._pendingSelection;
// If available, set either the previously selected node or the body
// as default selected, else set documentElement
return walker.getRootNode().then(aRootNode => {
if (hasNavigated()) {
return promise.reject("navigated; resolution of _defaultNode aborted");
}
rootNode = aRootNode;
return walker.querySelector(rootNode, this.selectionCssSelector);
}).then(front => {
if (hasNavigated()) {
return promise.reject("navigated; resolution of _defaultNode aborted");
}
if (front) {
return front;
}
return walker.querySelector(rootNode, "body");
}).then(front => {
if (hasNavigated()) {
return promise.reject("navigated; resolution of _defaultNode aborted");
}
if (front) {
return front;
}
@ -339,7 +357,7 @@ InspectorPanel.prototype = {
});
};
this._pendingSelection = onNodeSelected;
this._getDefaultNodeForSelection().then(onNodeSelected);
this._getDefaultNodeForSelection().then(onNodeSelected, console.error);
},
_selectionCssSelector: null,

View File

@ -703,7 +703,9 @@ var ProjectEditor = Class({
*/
set menuEnabled(val) {
this._menuEnabled = val;
this._updateMenuItems();
if (this._loaded) {
this._updateMenuItems();
}
},
get menuEnabled() {

View File

@ -1953,8 +1953,10 @@ Widgets.JSObject.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
*/
_anchor: function(text, options = {})
{
if (!options.onClick && !options.href) {
options.onClick = this._onClick;
if (!options.onClick) {
// If the anchor has an URL, open it in a new tab. If not, show the
// current object actor.
options.onClick = options.href ? this._onClickAnchor : this._onClick;
}
let anchor = this.el("a", {
@ -1963,7 +1965,7 @@ Widgets.JSObject.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
href: options.href || "#",
}, text);
this.message._addLinkCallback(anchor, !options.href ? options.onClick : null);
this.message._addLinkCallback(anchor, options.onClick);
if (options.appendTo) {
options.appendTo.appendChild(anchor);

View File

@ -492,8 +492,8 @@ WebConsole.prototype = {
});
return;
}
toolbox.selectTool("webconsole");
this.viewSource(aSourceURL, aSourceLine);
toolbox.selectTool("webconsole")
.then(() => this.viewSource(aSourceURL, aSourceLine));
}
// If the Debugger was already open, switch to it and try to show the

View File

@ -258,6 +258,7 @@ run-if = os == "mac"
[browser_webconsole_netlogging.js]
[browser_webconsole_network_panel.js]
[browser_webconsole_notifications.js]
[browser_webconsole_open-links-without-callback.js]
[browser_webconsole_output_copy_newlines.js]
[browser_webconsole_output_order.js]
[browser_webconsole_property_provider.js]

View File

@ -0,0 +1,50 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that if a link without an onclick callback is clicked the link is
// opened in a new tab and no exception occurs (bug 999236).
function test() {
function* runner() {
const TEST_EVAL_STRING = "document";
const TEST_PAGE_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
const {tab} = yield loadTab(TEST_PAGE_URI);
const hud = yield openConsole(tab);
hud.jsterm.execute(TEST_EVAL_STRING);
const EXPECTED_OUTPUT = new RegExp("HTMLDocument \.+");
let messages = yield waitForMessages({
webconsole: hud,
messages: [{
name: "JS eval output",
text: EXPECTED_OUTPUT,
category: CATEGORY_OUTPUT,
}],
});
let messageNode = messages[0].matched.values().next().value;
// The correct anchor is second in the message node; the first anchor has
// class .cm-variable. Ignore the first one by not matching anchors that
// have the class .cm-variable.
let urlNode = messageNode.querySelector("a:not(.cm-variable)");
let linkOpened = false;
let oldOpenUILinkIn = window.openUILinkIn;
window.openUILinkIn = function(aLink) {
if (aLink == TEST_PAGE_URI) {
linkOpened = true;
}
}
EventUtils.synthesizeMouseAtCenter(urlNode, {}, hud.iframeWindow);
ok(linkOpened, "Clicking the URL opens the desired page");
window.openUILinkIn = oldOpenUILinkIn;
}
Task.spawn(runner).then(finishTest);
}

View File

@ -5,7 +5,7 @@
const Cu = Components.utils;
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
const {GetAvailableAddons} = require("devtools/webide/addons");
const {GetAvailableAddons, ForgetAddonsList} = require("devtools/webide/addons");
const Strings = Services.strings.createBundle("chrome://webide/content/webide.properties");
window.addEventListener("load", function onLoad() {
@ -20,6 +20,11 @@ window.addEventListener("load", function onLoad() {
});
}, true);
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
ForgetAddonsList();
}, true);
function CloseUI() {
window.parent.UI.openProject();
}

View File

@ -27,9 +27,8 @@ const Strings = Services.strings.createBundle("chrome://webide/content/webide.pr
const HTML = "http://www.w3.org/1999/xhtml";
const HELP_URL = "https://developer.mozilla.org/Firefox_OS/Using_the_App_Manager#Troubleshooting";
// download some JSON early.
// download template index early
GetTemplatesJSON(true);
GetAddonsJSON(true);
// See bug 989619
console.log = console.log.bind(console);

View File

@ -66,7 +66,7 @@ let GetAvailableAddons = exports.GetAvailableAddons = function() {
simulators: [],
adb: null
}
GetAddonsJSON().then(json => {
GetAddonsJSON(true).then(json => {
for (let stability in json) {
for (let version of json[stability]) {
addons.simulators.push(new SimulatorAddon(stability, version));
@ -82,6 +82,10 @@ let GetAvailableAddons = exports.GetAvailableAddons = function() {
return GetAvailableAddons_promise;
}
exports.ForgetAddonsList = function() {
GetAvailableAddons_promise = null;
}
function Addon() {}
Addon.prototype = {
_status: "unknown",

View File

@ -5,8 +5,7 @@
body {
margin: 0;
background-color: white;
font-family: Lucida Grande, Helvetica, Helvetica Neue, sans-serif;
font-size: 12px;
font: message-box;
}
.hidden {
@ -30,6 +29,7 @@ h1, h3, p {
border-style: solid;
margin: 0;
padding: 0 12px;
font-family: inherit;
font-weight: bold;
height: 24px;
}

View File

@ -34,7 +34,10 @@ window:not(.busy) #action-busy {
/* Panel buttons */
.panel-button {
-moz-appearance: none;
-moz-box-align: center;
border-width: 0;
background: none;
}
.panel-button-anchor {
@ -123,6 +126,7 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
padding: 3px 12px;
margin: 0;
-moz-appearance: none;
border-width: 0;
}
.panel-item-help {

View File

@ -84,10 +84,6 @@ ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET)))
DEFINES += -DMOZ_SHARED_MOZGLUE=1
endif
ifdef MOZ_JSDEBUGGER
DEFINES += -DMOZ_JSDEBUGGER
endif
ifdef NECKO_WIFI
DEFINES += -DNECKO_WIFI
endif

View File

@ -247,9 +247,6 @@
@BINPATH@/components/inspector.xpt
@BINPATH@/components/intl.xpt
@BINPATH@/components/jar.xpt
#ifdef MOZ_JSDEBUGGER
@BINPATH@/components/jsdservice.xpt
#endif
@BINPATH@/components/jsdebugger.xpt
@BINPATH@/components/jsdownloads.xpt
@BINPATH@/components/jsinspector.xpt

View File

@ -28,3 +28,5 @@ close_window=Close this window
cannot_start_call_session_not_ready=Can't start call, session is not ready.
network_disconnected=The network connection terminated abruptly.
connection_error_see_console_notification=Call failed; see console for details.

View File

@ -31,11 +31,6 @@ leak:GI___strdup
### Many leaks only affect some test suites. The suite annotations are not checked.
###
# Bug 800200 - JSD1 is leaking, but it is about to be removed, so ignore it. m4
leak:jsd_CreateLock
leak:jsdScript::GetExecutableLines
leak:jsdService::ActivateDebugger
# Bug 979928 - WebRTC is leaky. m2, m3
leak:/media/mtransport/
leak:/media/webrtc/signaling/

View File

@ -3849,7 +3849,6 @@ MOZ_BRANDING_DIRECTORY=
MOZ_OFFICIAL_BRANDING=
MOZ_FEEDS=1
MOZ_WEBAPP_RUNTIME=
MOZ_JSDEBUGGER=1
MOZ_AUTH_EXTENSION=1
MOZ_RAW=
MOZ_VORBIS=
@ -4944,15 +4943,6 @@ if test -n "$MOZ_ANDROID_BEAM"; then
AC_DEFINE(MOZ_ANDROID_BEAM)
fi
dnl ========================================================
dnl = JS Debugger XPCOM component (js/jsd)
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(jsd,
[ --disable-jsd Disable JavaScript debug library],
MOZ_JSDEBUGGER=,
MOZ_JSDEBUGGER=1)
dnl ========================================================
dnl = Enable IPDL's "expensive" unit tests
dnl ========================================================
@ -6182,11 +6172,6 @@ if test `echo "$MOZ_EXTENSIONS" | grep -c gio` -ne 0; then
fi
AC_SUBST(MOZ_GIO_COMPONENT)
if test -z "$MOZ_JSDEBUGGER" -a `echo "$MOZ_EXTENSIONS" | grep -c venkman` -ne 0; then
AC_MSG_WARN([Cannot build venkman without JavaScript debug library. Removing venkman from MOZ_EXTENSIONS.])
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|venkman||'`
fi
dnl Remove dupes
MOZ_EXTENSIONS=`${PERL} ${srcdir}/build/unix/uniq.pl ${MOZ_EXTENSIONS}`
@ -8195,7 +8180,7 @@ if test "$MOZ_XUL"; then
AC_DEFINE(MOZ_XUL)
else
dnl remove extensions that require XUL
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's/inspector//' -e 's/venkman//' -e 's/irc//' -e 's/tasks//'`
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's/inspector//' -e 's/irc//' -e 's/tasks//'`
fi
AC_SUBST(MOZ_XUL)
@ -8429,7 +8414,6 @@ AC_SUBST(MOZ_DEBUG_DISABLE_DEFS)
AC_SUBST(MOZ_DEBUG_LDFLAGS)
AC_SUBST(WARNINGS_AS_ERRORS)
AC_SUBST(MOZ_EXTENSIONS)
AC_SUBST(MOZ_JSDEBUGGER)
AC_SUBST(MOZ_ENABLE_PROFILER_SPS)
AC_SUBST(MOZ_JPROF)
AC_SUBST(MOZ_SHARK)

View File

@ -125,7 +125,7 @@ SVGEllipseElement::BuildPath()
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
ArcToBezier(pathBuilder.get(), Point(x, y), Size(rx, ry), 0, Float(2*M_PI), false);
EllipseToBezier(pathBuilder.get(), Point(x, y), Size(rx, ry));
return pathBuilder->Finish();
}

View File

@ -182,7 +182,7 @@ LOCAL_INCLUDES += [
'/js/xpconnect/wrappers',
]
for var in ('MOZ_JSDEBUGGER', 'MOZ_B2G_RIL', 'MOZ_B2G_FM'):
for var in ('MOZ_B2G_RIL', 'MOZ_B2G_FM'):
if CONFIG[var]:
DEFINES[var] = True

View File

@ -230,10 +230,6 @@
#include "mozilla/dom/SpeechSynthesis.h"
#endif
#ifdef MOZ_JSDEBUGGER
#include "jsdIDebuggerService.h"
#endif
#ifdef MOZ_B2G
#include "nsPISocketTransportService.h"
#endif
@ -10881,7 +10877,6 @@ nsGlobalWindow::ShowSlowScriptDialog()
// Prioritize the SlowScriptDebug interface over JSD1.
nsCOMPtr<nsISlowScriptDebugCallback> debugCallback;
bool oldDebugPossible = false;
if (hasFrame) {
const char *debugCID = "@mozilla.org/dom/slow-script-debug;1";
@ -10889,33 +10884,9 @@ nsGlobalWindow::ShowSlowScriptDialog()
if (NS_SUCCEEDED(rv)) {
debugService->GetActivationHandler(getter_AddRefs(debugCallback));
}
if (!debugCallback) {
oldDebugPossible = js::CanCallContextDebugHandler(cx);
#ifdef MOZ_JSDEBUGGER
// Get the debugger service if necessary.
if (oldDebugPossible) {
bool jsds_IsOn = false;
const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
nsCOMPtr<jsdIExecutionHook> jsdHook;
nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
// Check if there's a user for the debugger service that's 'on' for us
if (NS_SUCCEEDED(rv)) {
jsds->GetDebuggerHook(getter_AddRefs(jsdHook));
jsds->GetIsOn(&jsds_IsOn);
}
// If there is a debug handler registered for this runtime AND
// ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs)))
// then something useful will be done with our request to debug.
oldDebugPossible = ((jsds_IsOn && (jsdHook != nullptr)) || !jsds_IsOn);
}
#endif
}
}
bool showDebugButton = debugCallback || oldDebugPossible;
bool showDebugButton = !!debugCallback;
// Get localizable strings
nsXPIDLString title, msg, stopButton, waitButton, debugButton, neverShowDlg;
@ -11024,10 +10995,6 @@ nsGlobalWindow::ShowSlowScriptDialog()
rv = debugCallback->HandleSlowScriptDebug(this);
return NS_SUCCEEDED(rv) ? ContinueSlowScript : KillSlowScript;
}
if (oldDebugPossible) {
return js_CallContextDebugHandler(cx) ? ContinueSlowScript : KillSlowScript;
}
}
JS_ClearPendingException(cx);
return KillSlowScript;

View File

@ -70,9 +70,6 @@
#endif
#include "AccessCheck.h"
#ifdef MOZ_JSDEBUGGER
#include "jsdIDebuggerService.h"
#endif
#ifdef MOZ_LOGGING
// Force PR_LOGGING so we can get JS strict warnings even in release builds
#define FORCE_PR_LOG 1

View File

@ -129,13 +129,9 @@ CameraPreferences::PreferenceChanged(const char* aPref, void* aClosure)
return;
}
#ifdef DEBUG
if (NS_FAILED(rv)) {
nsCString msg;
msg.AppendPrintf("Failed to update pref '%s' (0x%x)\n", aPref, rv);
NS_WARNING(msg.get());
DOM_CAMERA_LOGE("Failed to get pref '%s' (0x%x)\n", aPref, rv);
}
#endif
}
/* static */

View File

@ -4,9 +4,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EventListenerService.h"
#ifdef MOZ_JSDEBUGGER
#include "jsdIDebuggerService.h"
#endif
#include "mozilla/BasicEvents.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
@ -131,35 +128,6 @@ EventListenerInfo::ToSource(nsAString& aResult)
return NS_OK;
}
NS_IMETHODIMP
EventListenerInfo::GetDebugObject(nsISupports** aRetVal)
{
*aRetVal = nullptr;
#ifdef MOZ_JSDEBUGGER
nsresult rv = NS_OK;
nsCOMPtr<jsdIDebuggerService> jsd =
do_GetService("@mozilla.org/js/jsd/debugger-service;1", &rv);
NS_ENSURE_SUCCESS(rv, NS_OK);
bool isOn = false;
jsd->GetIsOn(&isOn);
NS_ENSURE_TRUE(isOn, NS_OK);
AutoSafeJSContext cx;
Maybe<JSAutoCompartment> ac;
JS::Rooted<JS::Value> v(cx);
if (GetJSVal(cx, ac, &v)) {
nsCOMPtr<jsdIValue> jsdValue;
rv = jsd->WrapValue(v, getter_AddRefs(jsdValue));
NS_ENSURE_SUCCESS(rv, rv);
jsdValue.forget(aRetVal);
}
#endif
return NS_OK;
}
NS_IMETHODIMP
EventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget,
uint32_t* aCount,

View File

@ -144,6 +144,3 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
LOCAL_INCLUDES += [
'/dom/wifi',
]
if CONFIG['MOZ_JSDEBUGGER']:
DEFINES['MOZ_JSDEBUGGER'] = True

View File

@ -12,7 +12,7 @@ interface nsIDOMEventTarget;
* An instance of this interface describes how an event listener
* was added to an event target.
*/
[scriptable, uuid(c4776eb7-05bc-49ce-a0ca-6213a346d53a)]
[scriptable, uuid(11ba5fd7-8db2-4b1a-9f67-342cfa11afad)]
interface nsIEventListenerInfo : nsISupports
{
/**
@ -37,12 +37,6 @@ interface nsIEventListenerInfo : nsISupports
* (for example with C++ listeners).
*/
AString toSource();
/**
* If jsdIDebuggerService is active and the listener is implemented in JS,
* this returns the listener as a jsdIValue. Otherwise null.
*/
nsISupports getDebugObject();
};
[scriptable, uuid(f6964bfb-dabe-4cab-9733-be0ee2bf8171)]

View File

@ -22,12 +22,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=448602
var els, root, l2, l3;
function runTests() {
/*
Disabled due to lack of present support for JSD in JM
var jsdIDebuggerService = SpecialPowers.Ci.jsdIDebuggerService;
var jsd = SpecialPowers.Components.classes['@mozilla.org/js/jsd/debugger-service;1']
.getService(jsdIDebuggerService);
*/
els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"]
.getService(SpecialPowers.Ci.nsIEventListenerService);
@ -48,18 +42,6 @@ function runTests() {
is(SpecialPowers.unwrap(infos[0].listenerObject), root.onclick,
"Should have the right listener object (1)");
/*
var jsdOn = jsd.isOn;
if (!jsdOn) {
is(infos[0].getDebugObject(), null,
"If JSD isn't running, getDebugObject() should return null.")
jsd.on();
ok(jsd.isOn, "JSD should be running.");
}
var jsdvalue = infos[0].getDebugObject().QueryInterface(SpecialPowers.Ci.jsdIValue);
is(jsdvalue.jsType, 3, "Event listener should be a function! (1)");
*/
root.removeAttribute("onclick");
root.setAttribute("onclick", "...invalid script...");
SimpleTest.expectUncaughtException(true);
@ -84,12 +66,6 @@ function runTests() {
is(infos[0].allowsUntrusted, true, "Should allow untrusted events (2)");
is(SpecialPowers.unwrap(infos[0].listenerObject), l,
"Should have the right listener object (2)");
/*
jsdvalue = infos[0].getDebugObject().QueryInterface(SpecialPowers.Ci.jsdIValue);
is(jsdvalue.jsType, 3, "Event listener should be a function!(2)");
is(jsdvalue.getWrappedValue(), l, "Wrong JS value! (1)");
*/
is(infos[1].toSource(), "(function (e) { alert(e); })",
"Unexpected serialization (3)");
is(infos[1].type, "foo", "Wrong type (3)");
@ -98,11 +74,6 @@ function runTests() {
is(SpecialPowers.unwrap(infos[1].listenerObject), l,
"Should have the right listener object (3)");
/*
jsdvalue2 = infos[1].getDebugObject().QueryInterface(SpecialPowers.Ci.jsdIValue);
is(jsdvalue2.jsType, 3, "Event listener should be a function! (3)");
is(jsdvalue2.getWrappedValue(), l, "Wrong JS value! (2)");
*/
root.removeEventListener("foo", l, true);
root.removeEventListener("foo", l, false);
infos = els.getListenerInfoFor(root, {});
@ -142,12 +113,6 @@ function runTests() {
ok(hasDocumentInChain, "Should have document in event target chain!");
ok(hasWindowInChain, "Should have window in event target chain!");
/*
if (!jsdOn) {
jsd.off();
ok(!jsd.isOn, "JSD shouldn't be running anymore.");
}
*/
try {
els.getListenerInfoFor(null, {});

View File

@ -24,19 +24,31 @@
}
function periodicCheck(type, checkFunc, successMessage, done) {
var interval = setInterval(function periodic() {
var num = 0;
var timeout;
function periodic() {
if (checkFunc()) {
ok(true, type + ' is ' + successMessage);
clearInterval(interval);
interval = null;
done();
} else {
setupNext();
}
}, 200);
}
function setupNext() {
// exponential backoff on the timer
// on a very slow system (like the b2g emulator) a long timeout is
// necessary, but we want to run fast if we can
timeout = setTimeout(periodic, 200 << num);
num++;
}
setupNext();
return function cancel() {
if (interval) {
if (timeout) {
ok(false, type + ' (' + successMessage + ')' +
' failed after waiting full duration');
clearInterval(interval);
clearTimeout(timeout);
done();
}
};
@ -59,16 +71,22 @@
var silent = check(constraintApplied, isSilence(view), 'be silence for audio');
return sampleCount > 0 && silent;
}
function disconnect() {
source.disconnect();
analyser.disconnect();
done();
}
return periodicCheck('audio', testAudio,
(constraintApplied ? '' : 'not ') + 'silent', done);
(constraintApplied ? '' : 'not ') + 'silent', disconnect);
}
function mkElement(type) {
var display = document.getElementById('display');
// this makes an unattached element
// it's not rendered to save the cycles that costs on b2g emulator
// and it gets droped (and GC'd) when the test is done
var e = document.createElement(type);
e.width = 32;
e.height = 24;
display.appendChild(e);
return e;
}

View File

@ -187,6 +187,50 @@ var commandsPeerConnection = [
});
}
],
[
'PC_REMOTE_CHECK_FOR_DUPLICATED_PORTS_IN_SDP',
function (test) {
var re = /a=candidate.* (UDP|TCP) [\d]+ ([\d\.]+) ([\d]+) typ host/g;
function _sdpCandidatesIntoArray(sdp) {
var regexArray = [];
var resultArray = [];
while ((regexArray = re.exec(sdp)) !== null) {
info("regexArray: " + regexArray);
if ((regexArray[1] === "TCP") && (regexArray[3] === "9")) {
// As both sides can advertise TCP active connection on port 9 lets
// ignore them all together
info("Ignoring TCP candidate on port 9");
continue;
}
const triple = regexArray[1] + ":" + regexArray[2] + ":" + regexArray[3];
info("triple: " + triple);
if (resultArray.indexOf(triple) !== -1) {
dump("SDP: " + sdp.replace(/[\r]/g, '') + "\n");
ok(false, "This Transport:IP:Port " + triple + " appears twice in the SDP above!");
}
resultArray.push(triple);
}
return resultArray;
}
const offerTriples = _sdpCandidatesIntoArray(test._local_offer.sdp);
info("Offer ICE host candidates: " + JSON.stringify(offerTriples));
const answerTriples = _sdpCandidatesIntoArray(test.pcRemote._last_answer.sdp);
info("Answer ICE host candidates: " + JSON.stringify(answerTriples));
for (var i=0; i< offerTriples.length; i++) {
if (answerTriples.indexOf(offerTriples[i]) !== -1) {
dump("SDP offer: " + test._local_offer.sdp.replace(/[\r]/g, '') + "\n");
dump("SDP answer: " + test.pcRemote._last_answer.sdp.replace(/[\r]/g, '') + "\n");
ok(false, "This IP:Port " + offerTriples[i] + " appears in SDP offer and answer!");
}
}
test.next();
}
],
[
'PC_REMOTE_SET_LOCAL_DESCRIPTION',
function (test) {

View File

@ -36,8 +36,8 @@ function theTest() {
}
var cancelAudioCheck = audioIsSilence(withConstraint, stream, checkDone);
var cancelVideoCheck = videoIsBlack(withConstraint, stream, checkDone);
setTimeout(cancelAudioCheck, 20000);
setTimeout(cancelVideoCheck, 20000);
setTimeout(cancelAudioCheck, 3*60*1000);
setTimeout(cancelVideoCheck, 3*60*1000);
}, function(e) {
ok(false, 'gUM error: ' + e);
});

View File

@ -7,6 +7,7 @@
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsIDOMEvent.h"
#include "SharedWorker.h"
@ -17,6 +18,7 @@ using mozilla::dom::EventHandlerNonNull;
using mozilla::dom::MessagePortBase;
using mozilla::dom::Optional;
using mozilla::dom::Sequence;
using mozilla::dom::AutoNoJSAPI;
using namespace mozilla;
USING_WORKERS_NAMESPACE
@ -42,6 +44,28 @@ public:
mEvents.SwapElements(aEvents);
}
bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
if (mBehavior == WorkerThreadModifyBusyCount) {
return aWorkerPrivate->ModifyBusyCount(aCx, true);
}
return true;
}
void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult)
{
if (!aDispatchResult) {
if (mBehavior == WorkerThreadModifyBusyCount) {
aWorkerPrivate->ModifyBusyCount(aCx, false);
}
if (aCx) {
JS_ReportPendingException(aCx);
}
}
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
};
@ -281,6 +305,8 @@ DelayedEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
mMessagePort->AssertCorrectThread();
MOZ_ASSERT(mEvents.Length());
AutoNoJSAPI nojsapi;
bool ignored;
for (uint32_t i = 0; i < mEvents.Length(); i++) {
mMessagePort->DispatchEvent(mEvents[i], &ignored);

View File

@ -11,20 +11,242 @@
#include "mozilla/Preferences.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DOMError.h"
#include "nsContentUtils.h"
#include "nsCxPusher.h"
#include "nsNetUtil.h"
#include "nsProxyRelease.h"
#include "nsTArray.h"
#include "RuntimeService.h"
#include "ServiceWorker.h"
#include "WorkerInlines.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
using namespace mozilla;
using namespace mozilla::dom;
BEGIN_WORKERS_NAMESPACE
NS_IMPL_ISUPPORTS0(ServiceWorkerRegistration)
UpdatePromise::UpdatePromise()
: mState(Pending)
{
MOZ_COUNT_CTOR(UpdatePromise);
}
UpdatePromise::~UpdatePromise()
{
MOZ_COUNT_DTOR(UpdatePromise);
}
void
UpdatePromise::AddPromise(Promise* aPromise)
{
MOZ_ASSERT(mState == Pending);
mPromises.AppendElement(aPromise);
}
void
UpdatePromise::ResolveAllPromises(const nsACString& aScriptSpec, const nsACString& aScope)
{
AssertIsOnMainThread();
MOZ_ASSERT(mState == Pending);
mState = Resolved;
RuntimeService* rs = RuntimeService::GetOrCreateService();
MOZ_ASSERT(rs);
nsTArray<nsTWeakRef<Promise>> array;
array.SwapElements(mPromises);
for (uint32_t i = 0; i < array.Length(); ++i) {
nsTWeakRef<Promise>& pendingPromise = array.ElementAt(i);
if (pendingPromise) {
nsCOMPtr<nsIGlobalObject> go =
do_QueryInterface(pendingPromise->GetParentObject());
MOZ_ASSERT(go);
AutoSafeJSContext cx;
JS::Rooted<JSObject*> global(cx, go->GetGlobalJSObject());
JSAutoCompartment ac(cx, global);
GlobalObject domGlobal(cx, global);
nsRefPtr<ServiceWorker> serviceWorker;
nsresult rv = rs->CreateServiceWorker(domGlobal,
NS_ConvertUTF8toUTF16(aScriptSpec),
aScope,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
pendingPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
continue;
}
pendingPromise->MaybeResolve(serviceWorker);
}
}
}
void
UpdatePromise::RejectAllPromises(nsresult aRv)
{
AssertIsOnMainThread();
MOZ_ASSERT(mState == Pending);
mState = Rejected;
nsTArray<nsTWeakRef<Promise>> array;
array.SwapElements(mPromises);
for (uint32_t i = 0; i < array.Length(); ++i) {
nsTWeakRef<Promise>& pendingPromise = array.ElementAt(i);
if (pendingPromise) {
// Since ServiceWorkerContainer is only exposed to windows we can be
// certain about this cast.
nsCOMPtr<nsPIDOMWindow> window =
do_QueryInterface(pendingPromise->GetParentObject());
MOZ_ASSERT(window);
nsRefPtr<DOMError> domError = new DOMError(window, aRv);
pendingPromise->MaybeRejectBrokenly(domError);
}
}
}
class FinishFetchOnMainThreadRunnable : public nsRunnable
{
nsMainThreadPtrHandle<ServiceWorkerUpdateInstance> mUpdateInstance;
public:
FinishFetchOnMainThreadRunnable
(const nsMainThreadPtrHandle<ServiceWorkerUpdateInstance>& aUpdateInstance)
: mUpdateInstance(aUpdateInstance)
{ }
NS_IMETHOD
Run() MOZ_OVERRIDE;
};
class FinishSuccessfulFetchWorkerRunnable : public WorkerRunnable
{
nsMainThreadPtrHandle<ServiceWorkerUpdateInstance> mUpdateInstance;
public:
FinishSuccessfulFetchWorkerRunnable(WorkerPrivate* aWorkerPrivate,
const nsMainThreadPtrHandle<ServiceWorkerUpdateInstance>& aUpdateInstance)
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
mUpdateInstance(aUpdateInstance)
{
AssertIsOnMainThread();
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
aWorkerPrivate->AssertIsOnWorkerThread();
if (!aWorkerPrivate->WorkerScriptExecutedSuccessfully()) {
return true;
}
nsRefPtr<FinishFetchOnMainThreadRunnable> r =
new FinishFetchOnMainThreadRunnable(mUpdateInstance);
NS_DispatchToMainThread(r);
return true;
}
};
// Allows newer calls to Update() to 'abort' older calls.
// Each call to Update() creates the instance which handles creating the
// worker and queues up a runnable to resolve the update promise once the
// worker has successfully been parsed.
class ServiceWorkerUpdateInstance MOZ_FINAL : public nsISupports
{
// Owner of this instance.
ServiceWorkerRegistration* mRegistration;
nsCString mScriptSpec;
nsCOMPtr<nsPIDOMWindow> mWindow;
bool mAborted;
public:
NS_DECL_ISUPPORTS
ServiceWorkerUpdateInstance(ServiceWorkerRegistration *aRegistration,
nsPIDOMWindow* aWindow)
: mRegistration(aRegistration),
// Capture the current script spec in case register() gets called.
mScriptSpec(aRegistration->mScriptSpec),
mWindow(aWindow),
mAborted(false)
{
AssertIsOnMainThread();
}
void
Abort()
{
MOZ_ASSERT(!mAborted);
mAborted = true;
}
void
Update()
{
AssertIsOnMainThread();
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
nsRefPtr<ServiceWorker> serviceWorker;
nsresult rv = swm->CreateServiceWorkerForWindow(mWindow,
mScriptSpec,
mRegistration->mScope,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
swm->RejectUpdatePromiseObservers(mRegistration, rv);
return;
}
nsMainThreadPtrHandle<ServiceWorkerUpdateInstance> handle =
new nsMainThreadPtrHolder<ServiceWorkerUpdateInstance>(this);
// FIXME(nsm): Deal with error case (worker failed to download, redirect,
// parse) in error handler patch.
nsRefPtr<FinishSuccessfulFetchWorkerRunnable> r =
new FinishSuccessfulFetchWorkerRunnable(serviceWorker->GetWorkerPrivate(), handle);
AutoSafeJSContext cx;
if (!r->Dispatch(cx)) {
swm->RejectUpdatePromiseObservers(mRegistration, NS_ERROR_FAILURE);
}
}
void
FetchDone()
{
AssertIsOnMainThread();
if (mAborted) {
return;
}
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
swm->FinishFetch(mRegistration, mWindow);
}
};
NS_IMPL_ISUPPORTS0(ServiceWorkerUpdateInstance)
NS_IMETHODIMP
FinishFetchOnMainThreadRunnable::Run()
{
AssertIsOnMainThread();
mUpdateInstance->FetchDone();
return NS_OK;
}
ServiceWorkerRegistration::ServiceWorkerRegistration(const nsACString& aScope)
: mScope(aScope),
mPendingUninstall(false)
{ }
ServiceWorkerRegistration::~ServiceWorkerRegistration()
{ }
//////////////////////////
// ServiceWorkerManager //
//////////////////////////
@ -89,13 +311,15 @@ public:
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
ServiceWorkerManager::ServiceWorkerDomainInfo* domainInfo =
swm->mDomainMap.Get(domain);
// FIXME(nsm): Refactor this pattern.
// XXXnsm: This pattern can be refactored if we end up using it
// often enough.
if (!swm->mDomainMap.Get(domain, &domainInfo)) {
domainInfo = new ServiceWorkerManager::ServiceWorkerDomainInfo;
swm->mDomainMap.Put(domain, domainInfo);
}
nsRefPtr<ServiceWorkerRegistration> registration = domainInfo->GetRegistration(mScope);
nsRefPtr<ServiceWorkerRegistration> registration =
domainInfo->GetRegistration(mScope);
nsCString spec;
rv = mScriptURI->GetSpec(spec);
@ -107,9 +331,6 @@ public:
if (registration) {
registration->mPendingUninstall = false;
if (spec.Equals(registration->mScriptSpec)) {
// FIXME(nsm): Force update on Shift+Reload. Algorithm not specified for
// that yet.
// There is an existing update in progress. Resolve with whatever it
// results in.
if (registration->HasUpdatePromise()) {
@ -117,8 +338,8 @@ public:
return NS_OK;
}
// There is no update in progress and since SW updating is upto the UA, we
// will not update right now. Simply resolve with whatever worker we
// There is no update in progress and since SW updating is upto the UA,
// we will not update right now. Simply resolve with whatever worker we
// have.
ServiceWorkerInfo info = registration->Newest();
if (info.IsValid()) {
@ -143,10 +364,16 @@ public:
registration->mScriptSpec = spec;
// FIXME(nsm): Call Update. Same bug, different patch.
// For now if the registration reaches this spot, the promise remains
// unresolved.
return NS_OK;
rv = swm->Update(registration, mWindow);
MOZ_ASSERT(registration->HasUpdatePromise());
// We append this register() call's promise after calling Update() because
// we don't want this one to be aborted when the others (existing updates
// for the same registration) are aborted. Update() sets a new
// UpdatePromise on the registration.
registration->mUpdatePromise->AddPromise(mPromise);
return rv;
}
};
@ -154,7 +381,8 @@ public:
// automatically reject the Promise.
NS_IMETHODIMP
ServiceWorkerManager::Register(nsIDOMWindow* aWindow, const nsAString& aScope,
const nsAString& aScriptURL, nsISupports** aPromise)
const nsAString& aScriptURL,
nsISupports** aPromise)
{
AssertIsOnMainThread();
MOZ_ASSERT(aWindow);
@ -206,10 +434,9 @@ ServiceWorkerManager::Register(nsIDOMWindow* aWindow, const nsAString& aScope,
return rv;
}
// https://github.com/slightlyoff/ServiceWorker/issues/262
// allowIfInheritsPrincipal: allow data: URLs for now.
// Data URLs are not allowed.
rv = documentPrincipal->CheckMayLoad(scriptURI, true /* report */,
true /* allowIfInheritsPrincipal */);
false /* allowIfInheritsPrincipal */);
if (NS_FAILED(rv)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
@ -238,11 +465,51 @@ ServiceWorkerManager::Register(nsIDOMWindow* aWindow, const nsAString& aScope,
return NS_DispatchToCurrentThread(registerRunnable);
}
void
ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistration* aRegistration,
nsresult aRv)
{
AssertIsOnMainThread();
MOZ_ASSERT(aRegistration->HasUpdatePromise());
aRegistration->mUpdatePromise->RejectAllPromises(aRv);
aRegistration->mUpdatePromise = nullptr;
}
/*
* Update() does not return the Promise that the spec says it should. Callers
* may access the registration's (new) Promise after calling this method.
*/
NS_IMETHODIMP
ServiceWorkerManager::Update(ServiceWorkerRegistration* aRegistration,
nsPIDOMWindow* aWindow)
{
// FIXME(nsm): Same bug, different patch.
if (aRegistration->HasUpdatePromise()) {
NS_WARNING("Already had a UpdatePromise. Aborting that one!");
RejectUpdatePromiseObservers(aRegistration, NS_ERROR_DOM_ABORT_ERR);
MOZ_ASSERT(aRegistration->mUpdateInstance);
aRegistration->mUpdateInstance->Abort();
aRegistration->mUpdateInstance = nullptr;
}
if (aRegistration->mInstallingWorker.IsValid()) {
// FIXME(nsm): Terminate the worker. We still haven't figured out worker
// instance ownership when not associated with a window, so let's wait on
// this.
// FIXME(nsm): We should be setting the state on the actual worker
// instance.
// FIXME(nsm): Fire "statechange" on installing worker instance.
aRegistration->mInstallingWorker.Invalidate();
}
aRegistration->mUpdatePromise = new UpdatePromise();
// FIXME(nsm): Bug 931249. If we don't need to fetch & install, resolve
// promise and skip this.
// FIXME(nsm): Bug 931249. Force cache update if > 1 day.
aRegistration->mUpdateInstance =
new ServiceWorkerUpdateInstance(aRegistration, aWindow);
aRegistration->mUpdateInstance->Update();
return NS_OK;
}
@ -266,11 +533,69 @@ ServiceWorkerManager::Unregister(nsIDOMWindow* aWindow, const nsAString& aScope,
already_AddRefed<ServiceWorkerManager>
ServiceWorkerManager::GetInstance()
{
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
nsCOMPtr<nsIServiceWorkerManager> swm =
do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
nsRefPtr<ServiceWorkerManager> concrete = do_QueryObject(swm);
return concrete.forget();
}
void
ServiceWorkerManager::ResolveRegisterPromises(ServiceWorkerRegistration* aRegistration,
const nsACString& aWorkerScriptSpec)
{
AssertIsOnMainThread();
MOZ_ASSERT(aRegistration->HasUpdatePromise());
if (aRegistration->mUpdatePromise->IsRejected()) {
aRegistration->mUpdatePromise = nullptr;
return;
}
aRegistration->mUpdatePromise->ResolveAllPromises(aWorkerScriptSpec,
aRegistration->mScope);
aRegistration->mUpdatePromise = nullptr;
}
// Must NS_Free() aString
void
ServiceWorkerManager::FinishFetch(ServiceWorkerRegistration* aRegistration,
nsPIDOMWindow* aWindow)
{
AssertIsOnMainThread();
MOZ_ASSERT(aRegistration->HasUpdatePromise());
MOZ_ASSERT(aRegistration->mUpdateInstance);
aRegistration->mUpdateInstance = nullptr;
if (aRegistration->mUpdatePromise->IsRejected()) {
aRegistration->mUpdatePromise = nullptr;
return;
}
// We have skipped Steps 3-8.3 of the Update algorithm here!
nsRefPtr<ServiceWorker> worker;
nsresult rv = CreateServiceWorkerForWindow(aWindow,
aRegistration->mScriptSpec,
aRegistration->mScope,
getter_AddRefs(worker));
if (NS_WARN_IF(NS_FAILED(rv))) {
RejectUpdatePromiseObservers(aRegistration, rv);
return;
}
ResolveRegisterPromises(aRegistration, aRegistration->mScriptSpec);
ServiceWorkerInfo info(aRegistration->mScriptSpec);
Install(aRegistration, info);
}
void
ServiceWorkerManager::Install(ServiceWorkerRegistration* aRegistration,
ServiceWorkerInfo aServiceWorkerInfo)
{
// FIXME(nsm): Same bug, different patch.
}
NS_IMETHODIMP
ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
const nsACString& aScriptSpec,

View File

@ -23,6 +23,44 @@ namespace dom {
namespace workers {
class ServiceWorker;
class ServiceWorkerUpdateInstance;
/**
* UpdatePromise is a utility class that sort of imitates Promise, but not
* completely. Using DOM Promise from C++ is a pain when we know the precise types
* we're dealing with since it involves dealing with JSAPI. In this case we
* also don't (yet) need the 'thenables added after resolution should trigger
* immediately' support and other things like that. All we want is something
* that works reasonably Promise like and can resolve real DOM Promises added
* pre-emptively.
*/
class UpdatePromise MOZ_FINAL
{
public:
UpdatePromise();
~UpdatePromise();
void AddPromise(Promise* aPromise);
void ResolveAllPromises(const nsACString& aScriptSpec, const nsACString& aScope);
void RejectAllPromises(nsresult aRv);
bool
IsRejected() const
{
return mState == Rejected;
}
private:
enum {
Pending,
Resolved,
Rejected
} mState;
// XXXnsm: Right now we don't need to support AddPromise() after
// already being resolved (i.e. true Promise-like behaviour).
nsTArray<nsTWeakRef<Promise>> mPromises;
};
/*
* Wherever the spec treats a worker instance and a description of said worker
@ -32,7 +70,7 @@ class ServiceWorker;
*/
class ServiceWorkerInfo
{
const nsCString mScriptSpec;
nsCString mScriptSpec;
public:
bool
@ -41,6 +79,12 @@ public:
return !mScriptSpec.IsVoid();
}
void
Invalidate()
{
mScriptSpec.SetIsVoid(true);
}
const nsCString&
GetScriptSpec() const
{
@ -49,19 +93,23 @@ public:
}
ServiceWorkerInfo()
{ }
{
Invalidate();
}
explicit ServiceWorkerInfo(const nsACString& aScriptSpec)
: mScriptSpec(aScriptSpec)
{ }
};
class ServiceWorkerRegistration
// Needs to inherit from nsISupports because NS_ProxyRelease() does not support
// non-ISupports classes.
class ServiceWorkerRegistration MOZ_FINAL : public nsISupports
{
private:
~ServiceWorkerRegistration() {}
virtual ~ServiceWorkerRegistration();
public:
NS_INLINE_DECL_REFCOUNTING(ServiceWorkerRegistration)
NS_DECL_ISUPPORTS
nsCString mScope;
// The scriptURL for the registration. This may be completely different from
@ -72,18 +120,20 @@ public:
ServiceWorkerInfo mWaitingWorker;
ServiceWorkerInfo mInstallingWorker;
bool mHasUpdatePromise;
nsAutoPtr<UpdatePromise> mUpdatePromise;
nsRefPtr<ServiceWorkerUpdateInstance> mUpdateInstance;
void
AddUpdatePromiseObserver(Promise* aPromise)
{
// FIXME(nsm): Same bug, different patch.
MOZ_ASSERT(HasUpdatePromise());
mUpdatePromise->AddPromise(aPromise);
}
bool
HasUpdatePromise()
{
return mHasUpdatePromise;
return mUpdatePromise;
}
// When unregister() is called on a registration, it is not immediately
@ -91,11 +141,7 @@ public:
// pendingUninstall and when all controlling documents go away, removed.
bool mPendingUninstall;
explicit ServiceWorkerRegistration(const nsACString& aScope)
: mScope(aScope),
mHasUpdatePromise(false),
mPendingUninstall(false)
{ }
explicit ServiceWorkerRegistration(const nsACString& aScope);
ServiceWorkerInfo
Newest() const
@ -126,6 +172,8 @@ public:
class ServiceWorkerManager MOZ_FINAL : public nsIServiceWorkerManager
{
friend class RegisterRunnable;
friend class CallInstallRunnable;
friend class ServiceWorkerUpdateInstance;
public:
NS_DECL_ISUPPORTS
@ -174,12 +222,17 @@ public:
nsClassHashtable<nsCStringHashKey, ServiceWorkerDomainInfo> mDomainMap;
// FIXME(nsm): What do we do if a page calls for register("/foo_worker.js", { scope: "/*"
// }) and then another page calls register("/bar_worker.js", { scope: "/*" })
// while the install is in progress. The async install steps for register
// bar_worker.js could finish before foo_worker.js, but bar_worker still has
// to be the winning controller.
// FIXME(nsm): Move this into per domain?
void
ResolveRegisterPromises(ServiceWorkerRegistration* aRegistration,
const nsACString& aWorkerScriptSpec);
void
RejectUpdatePromiseObservers(ServiceWorkerRegistration* aRegistration,
nsresult aResult);
void
FinishFetch(ServiceWorkerRegistration* aRegistration,
nsPIDOMWindow* aWindow);
static already_AddRefed<ServiceWorkerManager>
GetInstance();
@ -191,6 +244,10 @@ private:
NS_IMETHOD
Update(ServiceWorkerRegistration* aRegistration, nsPIDOMWindow* aWindow);
void
Install(ServiceWorkerRegistration* aRegistration,
ServiceWorkerInfo aServiceWorkerInfo);
NS_IMETHODIMP
CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
const nsACString& aScriptSpec,

View File

@ -40,6 +40,7 @@ SharedWorker::SharedWorker(nsPIDOMWindow* aWindow,
SharedWorker::~SharedWorker()
{
AssertIsOnMainThread();
Close();
MOZ_ASSERT(!mWorkerPrivate);
}

View File

@ -0,0 +1,6 @@
self.addEventListener("connect", function(e) {
var port = e.ports[0];
port.onmessage = function(e) {
port.postMessage(eval(e.data));
};
});

View File

@ -7,6 +7,7 @@ support-files =
bug1014466_worker.js
bug1020226_worker.js
bug1020226_frame.html
bug998474_worker.js
clearTimeouts_worker.js
closeOnGC_server.sjs
closeOnGC_worker.js
@ -81,10 +82,12 @@ support-files =
[test_atob.html]
[test_blobConstructor.html]
[test_blobWorkers.html]
[test_bug1002702.html]
[test_bug949946.html]
[test_bug1010784.html]
[test_bug1014466.html]
[test_bug1020226.html]
[test_bug998474.html]
[test_chromeWorker.html]
[test_clearTimeouts.html]
[test_close.html]
@ -121,6 +124,7 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure
[test_onLine.html]
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
[test_promise.html]
[test_promise_resolved_with_string.html]
[test_recursion.html]
[test_recursiveOnerror.html]
[test_relativeLoad.html]

View File

@ -1,2 +1,8 @@
[DEFAULT]
support-files =
worker.js
worker2.js
worker3.js
[test_installation_simple.html]
[test_navigator.html]

View File

@ -16,7 +16,7 @@
<script class="testbody" type="text/javascript">
function simpleRegister() {
var p = navigator.serviceWorker.register("/fake_worker.js");
var p = navigator.serviceWorker.register("worker.js");
ok(p instanceof Promise, "register() should return a Promise");
return Promise.resolve();
}
@ -50,14 +50,60 @@
ok(false, "non-HTTPS pages cannot register ServiceWorkers");
}, function(e) {
ok(e.name === "SecurityError", "Should fail with a SecurityError");
}).then(function() {
return new Promise((resolve) => SpecialPowers.popPrefEnv(resolve));
});
}
function realWorker() {
var p = navigator.serviceWorker.register("worker.js");
return p.then(function(w) {
ok(w instanceof ServiceWorker, "Register a ServiceWorker");
info(w.scope);
ok(w.scope == (new URL("/*", document.baseURI)).href, "Scope should match");
ok(w.url == (new URL("worker.js", document.baseURI)).href, "URL should be of the worker");
}, function(e) {
info(e.name);
ok(false, "Registration should have succeeded!");
});
}
function abortPrevious() {
var p = navigator.serviceWorker.register("worker2.js", { scope: "foo/*" });
var q = navigator.serviceWorker.register("worker3.js", { scope: "foo/*" });
return Promise.all([
p.then(function(w) {
ok(false, "First registration should fail with AbortError");
}, function(e) {
ok(e.name === "AbortError", "First registration should fail with AbortError");
}),
q.then(function(w) {
ok(w instanceof ServiceWorker, "Second registration should succeed");
}, function(e) {
ok(false, "Second registration should succeed");
})
]);
}
function networkError404() {
return navigator.serviceWorker.register("404.js").then(function(w) {
todo(false, "Should fail with NetworkError");
}, function(e) {
todo(e.name === "NetworkError", "Should fail with NetworkError");
});
}
function runTest() {
simpleRegister()
.then(sameOriginWorker)
.then(sameOriginScope)
.then(httpsOnly)
.then(realWorker)
.then(abortPrevious)
// FIXME(nsm): Uncomment once we have the error trapping patch from Bug 984048.
// .then(networkError404)
// put more tests here.
.then(function() {
SimpleTest.finish();

View File

@ -0,0 +1 @@
// empty worker, always succeed!

View File

@ -0,0 +1 @@
// worker2.js

View File

@ -0,0 +1 @@
// worker3.js

View File

@ -0,0 +1,27 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test for bug 1002702</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
var port = new SharedWorker('data:application/javascript,1').port;
port.close();
SpecialPowers.forceGC();
ok(true, "No crash \\o/");
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,39 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test for bug 998474</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="boom();">
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
function boom()
{
var worker = new SharedWorker("bug998474_worker.js");
setTimeout(function() {
port = worker.port;
port.postMessage("");
setTimeout(function() {
port.start();
ok(true, "Still alive!");
SimpleTest.finish();
}, 150);
}, 150);
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1027221
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1027221</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 1027221 **/
// Set up a permanent atom
SimpleTest.waitForExplicitFinish();
var x = "x";
// Trigger some incremental gc
SpecialPowers.Cu.getJSTestingFunctions().gcslice(0);
// Kick off a worker that uses this same atom
var w = new Worker("data:text/plain,Promise.resolve('x').then(function() { postMessage(1); });");
// Maybe trigger some more incremental gc
SpecialPowers.Cu.getJSTestingFunctions().gcslice(0);
w.onmessage = function() {
ok(true, "Got here");
SimpleTest.finish();
};
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1027221">Mozilla Bug 1027221</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -620,6 +620,8 @@ public:
DrawTarget() : mTransformDirty(false), mPermitSubpixelAA(false) {}
virtual ~DrawTarget() {}
virtual DrawTargetType GetType() const = 0;
virtual BackendType GetBackendType() const = 0;
/**
* Returns a SourceSurface which is a snapshot of the current contents of the DrawTarget.

View File

@ -155,6 +155,13 @@ DrawTargetCG::~DrawTargetCG()
CGContextRelease(mCg);
}
DrawTargetType
DrawTargetCG::GetType() const
{
return GetBackendType() == BackendType::COREGRAPHICS_ACCELERATED ?
DrawTargetType::HARDWARE_RASTER : DrawTargetType::SOFTWARE_RASTER;
}
BackendType
DrawTargetCG::GetBackendType() const
{

View File

@ -100,6 +100,7 @@ public:
DrawTargetCG();
virtual ~DrawTargetCG();
virtual DrawTargetType GetType() const MOZ_OVERRIDE;
virtual BackendType GetBackendType() const;
virtual TemporaryRef<SourceSurface> Snapshot();

View File

@ -372,6 +372,56 @@ DrawTargetCairo::~DrawTargetCairo()
MOZ_ASSERT(!mLockedBits);
}
DrawTargetType
DrawTargetCairo::GetType() const
{
if (mContext) {
cairo_surface_type_t type = cairo_surface_get_type(mSurface);
if (type == CAIRO_SURFACE_TYPE_TEE) {
type = cairo_surface_get_type(cairo_tee_surface_index(mSurface, 0));
MOZ_ASSERT(type != CAIRO_SURFACE_TYPE_TEE, "C'mon!");
MOZ_ASSERT(type == cairo_surface_get_type(cairo_tee_surface_index(mSurface, 1)),
"What should we do here?");
}
switch (type) {
case CAIRO_SURFACE_TYPE_PDF:
case CAIRO_SURFACE_TYPE_PS:
case CAIRO_SURFACE_TYPE_SVG:
case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
case CAIRO_SURFACE_TYPE_XML:
return DrawTargetType::VECTOR;
case CAIRO_SURFACE_TYPE_VG:
case CAIRO_SURFACE_TYPE_GL:
case CAIRO_SURFACE_TYPE_GLITZ:
case CAIRO_SURFACE_TYPE_QUARTZ:
case CAIRO_SURFACE_TYPE_DIRECTFB:
return DrawTargetType::HARDWARE_RASTER;
case CAIRO_SURFACE_TYPE_SKIA:
case CAIRO_SURFACE_TYPE_QT:
MOZ_ASSERT(false, "Can't determine actual DrawTargetType for DrawTargetCairo - assuming SOFTWARE_RASTER");
// fallthrough
case CAIRO_SURFACE_TYPE_IMAGE:
case CAIRO_SURFACE_TYPE_XLIB:
case CAIRO_SURFACE_TYPE_XCB:
case CAIRO_SURFACE_TYPE_WIN32:
case CAIRO_SURFACE_TYPE_BEOS:
case CAIRO_SURFACE_TYPE_OS2:
case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE:
case CAIRO_SURFACE_TYPE_SCRIPT:
case CAIRO_SURFACE_TYPE_RECORDING:
case CAIRO_SURFACE_TYPE_DRM:
case CAIRO_SURFACE_TYPE_SUBSURFACE:
case CAIRO_SURFACE_TYPE_D2D:
case CAIRO_SURFACE_TYPE_TEE: // included to silence warning about unhandled enum value
return DrawTargetType::SOFTWARE_RASTER;
}
}
MOZ_ASSERT(false, "Could not determine DrawTargetType for DrawTargetCairo");
return DrawTargetType::SOFTWARE_RASTER;
}
IntSize
DrawTargetCairo::GetSize()
{

View File

@ -58,6 +58,7 @@ public:
DrawTargetCairo();
virtual ~DrawTargetCairo();
virtual DrawTargetType GetType() const MOZ_OVERRIDE;
virtual BackendType GetBackendType() const { return BackendType::CAIRO; }
virtual TemporaryRef<SourceSurface> Snapshot();
virtual IntSize GetSize();

View File

@ -47,6 +47,7 @@ public:
DrawTargetD2D();
virtual ~DrawTargetD2D();
virtual DrawTargetType GetType() const MOZ_OVERRIDE { return DrawTargetType::HARDWARE_RASTER; }
virtual BackendType GetBackendType() const { return BackendType::DIRECT2D; }
virtual TemporaryRef<SourceSurface> Snapshot();
virtual IntSize GetSize() { return mSize; }

View File

@ -39,6 +39,7 @@ public:
DrawTargetD2D1();
virtual ~DrawTargetD2D1();
virtual DrawTargetType GetType() const MOZ_OVERRIDE { return DrawTargetType::HARDWARE_RASTER; }
virtual BackendType GetBackendType() const { return BackendType::DIRECT2D1_1; }
virtual TemporaryRef<SourceSurface> Snapshot();
virtual IntSize GetSize() { return mSize; }

View File

@ -43,6 +43,7 @@ public:
mFormat = aA->GetFormat();
}
virtual DrawTargetType GetType() const MOZ_OVERRIDE { return mA->GetType(); }
virtual BackendType GetBackendType() const { return mA->GetBackendType(); }
virtual TemporaryRef<SourceSurface> Snapshot() { return new SourceSurfaceDual(mA, mB); }
virtual IntSize GetSize() { return mA->GetSize(); }

View File

@ -19,6 +19,7 @@ public:
DrawTargetRecording(DrawEventRecorder *aRecorder, DrawTarget *aDT, bool aHasData = false);
~DrawTargetRecording();
virtual DrawTargetType GetType() const MOZ_OVERRIDE { return mFinalDT->GetType(); }
virtual BackendType GetBackendType() const { return mFinalDT->GetBackendType(); }
virtual TemporaryRef<SourceSurface> Snapshot();

View File

@ -277,12 +277,12 @@ struct AutoPaintSetup {
mPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
SkPaint temp;
temp.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp));
temp.setAlpha(U8CPU(aOptions.mAlpha*255+0.5));
temp.setAlpha(ColorFloatToByte(aOptions.mAlpha));
//TODO: Get a rect here
mCanvas->saveLayer(nullptr, &temp);
mNeedsRestore = true;
} else {
mPaint.setAlpha(U8CPU(aOptions.mAlpha*255.0+0.5));
mPaint.setAlpha(ColorFloatToByte(aOptions.mAlpha));
mAlpha = aOptions.mAlpha;
}
mPaint.setFilterLevel(SkPaint::kLow_FilterLevel);
@ -339,6 +339,17 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface,
mCanvas->drawBitmapRectToRect(bitmap.mBitmap, &sourceRect, destRect, &paint.mPaint);
}
DrawTargetType
DrawTargetSkia::GetType() const
{
#ifdef USE_SKIA_GPU
if (mGrContext) {
return DrawTargetType::HARDWARE_RASTER;
}
#endif
return DrawTargetType::SOFTWARE_RASTER;
}
void
DrawTargetSkia::DrawFilter(FilterNode *aNode,
const Rect &aSourceRect,

View File

@ -31,6 +31,7 @@ public:
DrawTargetSkia();
virtual ~DrawTargetSkia();
virtual DrawTargetType GetType() const MOZ_OVERRIDE;
virtual BackendType GetBackendType() const { return BackendType::SKIA; }
virtual TemporaryRef<SourceSurface> Snapshot();
virtual IntSize GetSize() { return mSize; }

View File

@ -21,6 +21,7 @@ public:
bool Init(const TileSet& mTiles);
virtual DrawTargetType GetType() const MOZ_OVERRIDE { return mTiles[0].mDrawTarget->GetType(); }
virtual BackendType GetBackendType() const { return mTiles[0].mDrawTarget->GetBackendType(); }
virtual TemporaryRef<SourceSurface> Snapshot();
virtual IntSize GetSize() { return IntSize(mRect.XMost(), mRect.YMost()); }

View File

@ -235,11 +235,20 @@ GfxOpToSkiaOp(CompositionOp op)
}
}
static inline SkColor ColorToSkColor(const Color &color, Float aAlpha)
/* There's quite a bit of inconsistency about
* whether float colors should be rounded with .5f.
* We choose to do it to match cairo which also
* happens to match the Direct3D specs */
static inline U8CPU ColorFloatToByte(Float color)
{
//XXX: do a better job converting to int
return SkColorSetARGB(U8CPU(color.a*aAlpha*255.0), U8CPU(color.r*255.0),
U8CPU(color.g*255.0), U8CPU(color.b*255.0));
return U8CPU(color*255.f + .5f);
};
static inline SkColor ColorToSkColor(const Color &color, Float aAlpha)
{
return SkColorSetARGB(ColorFloatToByte(color.a*aAlpha), ColorFloatToByte(color.r),
ColorFloatToByte(color.g), ColorFloatToByte(color.b));
}
static inline SkRect

View File

@ -83,6 +83,51 @@ void ArcToBezier(T* aSink, const Point &aOrigin, const Size &aRadius,
}
}
/* This is basically the ArcToBezier with the parameters for drawing a circle
* inlined which vastly simplifies it and avoids a bunch of transcedental function
* calls which should make it faster. */
template <typename T>
void EllipseToBezier(T* aSink, const Point &aOrigin, const Size &aRadius)
{
Point startPoint(aOrigin.x + aRadius.width,
aOrigin.y);
aSink->LineTo(startPoint);
// Calculate kappa constant for partial curve. The sign of angle in the
// tangent will actually ensure this is negative for a counter clockwise
// sweep, so changing signs later isn't needed.
Float kappaFactor = (4.0f / 3.0f) * tan((M_PI/2.0f) / 4.0f);
Float kappaX = kappaFactor * aRadius.width;
Float kappaY = kappaFactor * aRadius.height;
Float cosStartAngle = 1;
Float sinStartAngle = 0;
for (int i = 0; i < 4; i++) {
// We guarantee here the current point is the start point of the next
// curve segment.
Point currentStartPoint(aOrigin.x + cosStartAngle * aRadius.width,
aOrigin.y + sinStartAngle * aRadius.height);
Point currentEndPoint(aOrigin.x + -sinStartAngle * aRadius.width,
aOrigin.y + cosStartAngle * aRadius.height);
Point tangentStart(-sinStartAngle, cosStartAngle);
Point cp1 = currentStartPoint;
cp1 += Point(tangentStart.x * kappaX, tangentStart.y * kappaY);
Point revTangentEnd(cosStartAngle, sinStartAngle);
Point cp2 = currentEndPoint;
cp2 += Point(revTangentEnd.x * kappaX, revTangentEnd.y * kappaY);
aSink->BezierTo(cp1, cp2, currentEndPoint);
// cos(x+pi/2) == -sin(x)
// sin(x+pi/2) == cos(x)
Float tmp = cosStartAngle;
cosStartAngle = -sinStartAngle;
sinStartAngle = tmp;
}
}
/**
* Appends a path represending a rounded rectangle to the path being built by
* aPathBuilder.

View File

@ -72,6 +72,12 @@ MOZ_BEGIN_ENUM_CLASS(FilterType, int8_t)
UNPREMULTIPLY
MOZ_END_ENUM_CLASS(FilterType)
MOZ_BEGIN_ENUM_CLASS(DrawTargetType, int8_t)
SOFTWARE_RASTER = 0,
HARDWARE_RASTER,
VECTOR
MOZ_END_ENUM_CLASS(DrawTargetType)
MOZ_BEGIN_ENUM_CLASS(BackendType, int8_t)
NONE = 0,
DIRECT2D,

View File

@ -14,7 +14,6 @@
#include "LayerSorter.h" // for SortLayersBy3DZOrder
#include "LayersLogging.h" // for AppendToString
#include "ReadbackLayer.h" // for ReadbackLayer
#include "gfxImageSurface.h"
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxUtils.h" // for gfxUtils, etc
#include "gfx2DGlue.h"
@ -1232,18 +1231,13 @@ void WriteSnapshotLinkToDumpFile(T* aObj, std::stringstream& aStream)
template <typename T>
void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf)
{
nsRefPtr<gfxImageSurface> deprecatedSurf =
new gfxImageSurface(aSurf->GetData(),
ThebesIntSize(aSurf->GetSize()),
aSurf->Stride(),
SurfaceFormatToImageFormat(aSurf->GetFormat()));
nsCString string(aObj->Name());
string.Append('-');
string.AppendInt((uint64_t)aObj);
if (gfxUtils::sDumpPaintFile) {
fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
}
deprecatedSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
gfxUtils::DumpAsDataURI(aSurf, gfxUtils::sDumpPaintFile);
if (gfxUtils::sDumpPaintFile) {
fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
}

View File

@ -55,6 +55,17 @@ public:
uint64_t mAsyncID;
};
void
RemoveTextureFromCompositableTracker::ReleaseTextureClient()
{
if (mTextureClient) {
TextureClientReleaseTask* task = new TextureClientReleaseTask(mTextureClient);
RefPtr<ISurfaceAllocator> allocator = mTextureClient->GetAllocator();
mTextureClient = nullptr;
allocator->GetMessageLoop()->PostTask(FROM_HERE, task);
}
}
/* static */ void
CompositableClient::TransactionCompleteted(PCompositableChild* aActor, uint64_t aTransactionId)
{

View File

@ -42,22 +42,22 @@ public:
~RemoveTextureFromCompositableTracker()
{
MOZ_COUNT_DTOR(RemoveTextureFromCompositableTracker);
ReleaseTextureClient();
}
virtual void Complete() MOZ_OVERRIDE
{
// The TextureClient's recycling is postponed until the transaction
// complete.
mTextureClient = nullptr;
ReleaseTextureClient();
}
virtual void Cancel() MOZ_OVERRIDE
{
mTextureClient = nullptr;
ReleaseTextureClient();
}
virtual void SetTextureClient(TextureClient* aTextureClient) MOZ_OVERRIDE
{
ReleaseTextureClient();
mTextureClient = aTextureClient;
}
@ -68,6 +68,9 @@ public:
}
}
protected:
void ReleaseTextureClient();
private:
RefPtr<TextureClient> mTextureClient;
};

View File

@ -203,6 +203,7 @@ TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
MOZ_ASSERT(mActor);
mActor->mForwarder = aForwarder;
mActor->mTextureClient = this;
mAllocator = aForwarder;
mShared = true;
return mActor->IPCOpen();
}

View File

@ -364,7 +364,13 @@ protected:
mFlags |= aFlags;
}
ISurfaceAllocator* GetAllocator()
{
return mAllocator;
}
RefPtr<TextureChild> mActor;
RefPtr<ISurfaceAllocator> mAllocator;
TextureFlags mFlags;
bool mShared;
bool mValid;
@ -372,10 +378,30 @@ protected:
FenceHandle mAcquireFenceHandle;
friend class TextureChild;
friend class RemoveTextureFromCompositableTracker;
friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*);
friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&);
};
/**
* Task that releases TextureClient pointer on a specified thread.
*/
class TextureClientReleaseTask : public Task
{
public:
TextureClientReleaseTask(TextureClient* aClient)
: mTextureClient(aClient) {
}
virtual void Run() MOZ_OVERRIDE
{
mTextureClient = nullptr;
}
private:
mozilla::RefPtr<TextureClient> mTextureClient;
};
/**
* TextureClient that wraps a random access buffer such as a Shmem or raw memory.
* This class must be inherited to implement the memory allocation and access bits.

View File

@ -8,6 +8,7 @@
#include <utility> // for pair
#include "ContentHost.h" // for ContentHostDoubleBuffered, etc
#include "Effects.h" // for EffectMask, Effect, etc
#include "gfxUtils.h"
#include "ImageHost.h" // for ImageHostBuffered, etc
#include "TiledContentHost.h" // for TiledContentHost
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
@ -227,12 +228,8 @@ CompositableHost::DumpTextureHost(std::stringstream& aStream, TextureHost* aText
dSurf->GetSize(),
dSurf->Stride(),
dSurf->GetFormat());
nsRefPtr<gfxASurface> surf = platform->GetThebesSurfaceForDrawTarget(dt);
if (!surf) {
return;
}
// TODO stream surface
surf->DumpAsDataURL(stderr);
gfxUtils::DumpAsDataURI(dt, stderr);
}
#endif

View File

@ -85,7 +85,9 @@ class ISurfaceAllocator : public AtomicRefCountedWithFinalize<ISurfaceAllocator>
{
public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator)
ISurfaceAllocator() {}
ISurfaceAllocator()
: mDefaultMessageLoop(MessageLoop::current())
{}
void Finalize();
@ -163,6 +165,11 @@ public:
virtual bool IPCOpen() const { return true; }
virtual bool IsSameProcess() const = 0;
virtual MessageLoop * GetMessageLoop() const
{
return mDefaultMessageLoop;
}
// Returns true if aSurface wraps a Shmem.
static bool IsShmem(SurfaceDescriptor* aSurface);
@ -177,6 +184,8 @@ protected:
// This is used to implement an extremely simple & naive heap allocator.
std::vector<mozilla::ipc::Shmem> mUsedShmems;
MessageLoop* mDefaultMessageLoop;
friend class AtomicRefCountedWithFinalize<ISurfaceAllocator>;
};

View File

@ -170,7 +170,7 @@ public:
*
* Can be called from any thread.
*/
MessageLoop * GetMessageLoop() const;
virtual MessageLoop * GetMessageLoop() const MOZ_OVERRIDE;
PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo, uint64_t* aID) MOZ_OVERRIDE;
bool DeallocPCompositableChild(PCompositableChild* aActor) MOZ_OVERRIDE;

View File

@ -261,7 +261,7 @@ ImageBridgeParent::RecvChildAsyncMessages(const InfallibleTArray<AsyncChildMessa
return true;
}
MessageLoop * ImageBridgeParent::GetMessageLoop() {
MessageLoop * ImageBridgeParent::GetMessageLoop() const {
return mMessageLoop;
}

View File

@ -88,7 +88,7 @@ public:
// Shutdown step 2
virtual bool RecvStop() MOZ_OVERRIDE;
MessageLoop * GetMessageLoop();
virtual MessageLoop* GetMessageLoop() const MOZ_OVERRIDE;
// ISurfaceAllocator

View File

@ -28,14 +28,14 @@ class nsIAtom;
class nsIWidget;
// IID for the nsITheme interface
// {b0f3efe9-0bd4-4f6b-8daa-0ec7f6006822}
// {7a3474d9-3bd6-407c-8657-c5c7633639f0}
#define NS_ITHEME_IID \
{ 0x4440b5c7, 0xd8bd, 0x4d9c, \
{ 0x9c, 0x3e, 0xa5, 0xe6, 0x26, 0x81, 0x10, 0xa0 } }
// {D930E29B-6909-44e5-AB4B-AF10D6923705}
{ 0x7a3474d9, 0x3bd6, 0x407c, \
{ 0x86, 0x57, 0xc5, 0xc7, 0x63, 0x36, 0x39, 0xf0 } }
// {0ae05515-cf7a-45a8-9e02-6556de7685b1}
#define NS_THEMERENDERER_CID \
{ 0x9020805b, 0x14a3, 0x4125, \
{ 0xa5, 0x63, 0x4a, 0x8c, 0x5d, 0xe0, 0xa9, 0xa3 } }
{ 0x0ae05515, 0xcf7a, 0x45a8, \
{ 0x9e, 0x02, 0x65, 0x56, 0xde, 0x76, 0x85, 0xb1 } }
/**
* nsITheme is a service that provides platform-specific native
@ -113,7 +113,7 @@ public:
* minimum size; if false, this size is the only valid size for the
* widget.
*/
NS_IMETHOD GetMinimumWidgetSize(nsRenderingContext* aContext,
NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
nsIntSize* aResult,

View File

@ -20,8 +20,6 @@
#include "nsRect.h" // for nsRect, nsIntRect
#include "nsRegion.h" // for nsIntRegionRectIterator, etc
class gfxASurface;
// XXXTodo: rename FORM_TWIPS to FROM_APPUNITS
#define FROM_TWIPS(_x) ((gfxFloat)((_x)/(mP2A)))
#define FROM_TWIPS_INT(_x) (NSToIntRound((gfxFloat)((_x)/(mP2A))))
@ -65,13 +63,6 @@ static int32_t FindSafeLength(const char *aString, uint32_t aLength,
//////////////////////////////////////////////////////////////////////
//// nsRenderingContext
void
nsRenderingContext::Init(nsDeviceContext* aContext,
gfxASurface *aThebesSurface)
{
Init(aContext, new gfxContext(aThebesSurface));
}
void
nsRenderingContext::Init(nsDeviceContext* aContext,
gfxContext *aThebesContext)

View File

@ -22,7 +22,6 @@
#include "nsString.h" // for nsString
#include "nscore.h" // for char16_t
class gfxASurface;
class nsIntRegion;
struct nsPoint;
struct nsRect;
@ -45,7 +44,6 @@ public:
NS_INLINE_DECL_REFCOUNTING(nsRenderingContext)
void Init(nsDeviceContext* aContext, gfxASurface* aThebesSurface);
void Init(nsDeviceContext* aContext, gfxContext* aThebesContext);
void Init(nsDeviceContext* aContext, DrawTarget* aDrawTarget);

View File

@ -683,179 +683,6 @@ gfxASurface::BytesPerPixel(gfxImageFormat aImageFormat)
}
}
void
gfxASurface::WriteAsPNG(const char* aFile)
{
FILE *file = fopen(aFile, "wb");
if (file) {
WriteAsPNG_internal(file, true);
fclose(file);
} else {
NS_WARNING("Failed to create file!\n");
}
}
void
gfxASurface::DumpAsDataURL(FILE* aOutput)
{
WriteAsPNG_internal(aOutput, false);
}
void
gfxASurface::CopyAsDataURL()
{
WriteAsPNG_internal(nullptr, false);
}
/**
* Write to a PNG file. If aBinary is true, then it is written
* as binary, otherwise as a data URL. If no file is specified then
* data is copied to the clipboard (must not be binary!).
*/
void
gfxASurface::WriteAsPNG_internal(FILE* aFile, bool aBinary)
{
nsRefPtr<gfxImageSurface> imgsurf = GetAsImageSurface();
nsIntSize size;
// FIXME/bug 831898: hack r5g6b5 for now.
if (!imgsurf || imgsurf->Format() == gfxImageFormat::RGB16_565) {
size = GetSize();
if (size.width == -1 && size.height == -1) {
printf("Could not determine surface size\n");
return;
}
imgsurf =
new gfxImageSurface(nsIntSize(size.width, size.height),
gfxImageFormat::ARGB32);
if (!imgsurf || imgsurf->CairoStatus()) {
printf("Could not allocate image surface\n");
return;
}
nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
if (!ctx || ctx->HasError()) {
printf("Could not allocate image context\n");
return;
}
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(this, gfxPoint(0, 0));
ctx->Paint();
}
size = imgsurf->GetSize();
nsCOMPtr<imgIEncoder> encoder =
do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png");
if (!encoder) {
int32_t w = std::min(size.width, 8);
int32_t h = std::min(size.height, 8);
printf("Could not create encoder. Printing %dx%d pixels.\n", w, h);
for (int32_t y = 0; y < h; ++y) {
for (int32_t x = 0; x < w; ++x) {
printf("%x ", reinterpret_cast<uint32_t*>(imgsurf->Data())[y*imgsurf->Stride()+ x]);
}
}
return;
}
nsresult rv = encoder->InitFromData(imgsurf->Data(),
size.width * size.height * 4,
size.width,
size.height,
imgsurf->Stride(),
imgIEncoder::INPUT_FORMAT_HOSTARGB,
NS_LITERAL_STRING(""));
if (NS_FAILED(rv))
return;
nsCOMPtr<nsIInputStream> imgStream;
CallQueryInterface(encoder.get(), getter_AddRefs(imgStream));
if (!imgStream)
return;
uint64_t bufSize64;
rv = imgStream->Available(&bufSize64);
if (NS_FAILED(rv))
return;
if (bufSize64 > UINT32_MAX - 16)
return;
uint32_t bufSize = (uint32_t)bufSize64;
// ...leave a little extra room so we can call read again and make sure we
// got everything. 16 bytes for better padding (maybe)
bufSize += 16;
uint32_t imgSize = 0;
char* imgData = (char*)moz_malloc(bufSize);
if (!imgData)
return;
uint32_t numReadThisTime = 0;
while ((rv = imgStream->Read(&imgData[imgSize],
bufSize - imgSize,
&numReadThisTime)) == NS_OK && numReadThisTime > 0)
{
imgSize += numReadThisTime;
if (imgSize == bufSize) {
// need a bigger buffer, just double
bufSize *= 2;
char* newImgData = (char*)moz_realloc(imgData, bufSize);
if (!newImgData) {
moz_free(imgData);
return;
}
imgData = newImgData;
}
}
if (aBinary) {
if (aFile) {
fwrite(imgData, 1, imgSize, aFile);
} else {
NS_WARNING("Can't write binary image data without a file!");
}
return;
}
// base 64, result will be null-terminated
nsCString encodedImg;
rv = Base64Encode(Substring(imgData, imgSize), encodedImg);
moz_free(imgData);
if (NS_FAILED(rv)) // not sure why this would fail
return;
nsCString string("data:image/png;base64,");
string.Append(encodedImg);
if (aFile) {
#ifdef ANDROID
if (aFile == stdout || aFile == stderr) {
// ADB logcat cuts off long strings so we will break it down
const char* cStr = string.BeginReading();
size_t len = strlen(cStr);
while (true) {
printf_stderr("IMG: %.140s\n", cStr);
if (len <= 140)
break;
len -= 140;
cStr += 140;
}
}
#endif
fprintf_stderr(aFile, "%s", string.BeginReading());
} else {
nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
if (clipboard) {
clipboard->CopyString(NS_ConvertASCIItoUTF16(string), nullptr);
}
}
return;
}
void
gfxASurface::SetOpaqueRect(const gfxRect& aRect)
{

View File

@ -175,27 +175,6 @@ public:
virtual const nsIntSize GetSize() const;
/**
* Debug functions to encode the current image as a PNG and export it.
*/
/**
* Writes a binary PNG file.
*/
void WriteAsPNG(const char* aFile);
/**
* Write as a PNG encoded Data URL to a file.
*/
void DumpAsDataURL(FILE* aOutput = stdout);
/**
* Copy a PNG encoded Data URL to the clipboard.
*/
void CopyAsDataURL();
void WriteAsPNG_internal(FILE* aFile, bool aBinary);
void SetOpaqueRect(const gfxRect& aRect);
const gfxRect& GetOpaqueRect() {

View File

@ -16,6 +16,7 @@
#include "gfxColor.h"
#include "gfxMatrix.h"
#include "gfxUtils.h"
#include "gfxASurface.h"
#include "gfxPattern.h"
#include "gfxPlatform.h"
@ -1957,34 +1958,31 @@ gfxContext::RoundedRectangle(const gfxRect& rect,
#ifdef MOZ_DUMP_PAINTING
void
gfxContext::WriteAsPNG(const char* aFile)
{
nsRefPtr<gfxASurface> surf = CurrentSurface();
if (surf) {
surf->WriteAsPNG(aFile);
{
if (mDT) {
gfxUtils::WriteAsPNG(mDT, aFile);
} else {
NS_WARNING("No surface found!");
NS_WARNING("No DrawTarget found!");
}
}
void
gfxContext::DumpAsDataURL()
{
nsRefPtr<gfxASurface> surf = CurrentSurface();
if (surf) {
surf->DumpAsDataURL();
gfxContext::DumpAsDataURI()
{
if (mDT) {
gfxUtils::DumpAsDataURI(mDT);
} else {
NS_WARNING("No surface found!");
NS_WARNING("No DrawTarget found!");
}
}
void
gfxContext::CopyAsDataURL()
{
nsRefPtr<gfxASurface> surf = CurrentSurface();
if (surf) {
surf->CopyAsDataURL();
gfxContext::CopyAsDataURI()
{
if (mDT) {
gfxUtils::CopyAsDataURI(mDT);
} else {
NS_WARNING("No surface found!");
NS_WARNING("No DrawTarget found!");
}
}
#endif

View File

@ -707,12 +707,12 @@ public:
/**
* Write as a PNG encoded Data URL to stdout.
*/
void DumpAsDataURL();
void DumpAsDataURI();
/**
* Copy a PNG encoded Data URL to the clipboard.
*/
void CopyAsDataURL();
void CopyAsDataURI();
#endif
static mozilla::gfx::UserDataKey sDontUseAsSourceKey;

View File

@ -9,6 +9,7 @@
#include "mozilla/dom/ContentChild.h"
#include "gfxAndroidPlatform.h"
#include "mozilla/Omnijar.h"
#include "nsAutoPtr.h"
#include "nsIInputStream.h"
#include "nsNetUtil.h"
#define gfxToolkitPlatform gfxAndroidPlatform
@ -1084,7 +1085,8 @@ gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
uint32_t bufSize = item->RealSize();
// We use fallible allocation here; if there's not enough RAM, we'll simply
// ignore the bundled fonts and fall back to the device's installed fonts.
nsAutoPtr<uint8_t> buf(static_cast<uint8_t*>(moz_malloc(bufSize)));
static const fallible_t fallible = fallible_t();
nsAutoArrayPtr<uint8_t> buf(new (fallible) uint8_t[bufSize]);
if (!buf) {
return;
}

View File

@ -876,16 +876,32 @@ gfxUserFontSet::UserFontCache::Flusher::Observe(nsISupports* aSubject,
return NS_OK;
}
static bool
IgnorePrincipal(nsIURI *aURI)
{
nsresult rv;
bool inherits = false;
rv = NS_URIChainHasFlags(aURI,
nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
&inherits);
return NS_SUCCEEDED(rv) && inherits;
}
bool
gfxUserFontSet::UserFontCache::Entry::KeyEquals(const KeyTypePointer aKey) const
{
bool equal;
if (NS_FAILED(mURI->Equals(aKey->mURI, &equal)) || !equal) {
bool result;
if (NS_FAILED(mURI->Equals(aKey->mURI, &result)) || !result) {
return false;
}
if (NS_FAILED(mPrincipal->Equals(aKey->mPrincipal, &equal)) || !equal) {
return false;
// For data: URIs, we don't care about the principal; otherwise, check it.
if (!IgnorePrincipal(mURI)) {
NS_ASSERTION(mPrincipal && aKey->mPrincipal,
"only data: URIs are allowed to omit the principal");
if (NS_FAILED(mPrincipal->Equals(aKey->mPrincipal, &result)) || !result) {
return false;
}
}
if (mPrivate != aKey->mPrivate) {
@ -925,7 +941,16 @@ gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry *aFontEntry)
}
gfxUserFontData *data = aFontEntry->mUserFontData;
sUserFonts->PutEntry(Key(data->mURI, data->mPrincipal, aFontEntry,
// For data: URIs, the principal is ignored; anyone who has the same
// data: URI is able to load it and get an equivalent font.
// Otherwise, the principal is used as part of the cache key.
nsIPrincipal *principal;
if (IgnorePrincipal(data->mURI)) {
principal = nullptr;
} else {
principal = data->mPrincipal;
}
sUserFonts->PutEntry(Key(data->mURI, principal, aFontEntry,
data->mPrivate));
#ifdef DEBUG_USERFONT_CACHE
@ -965,7 +990,15 @@ gfxUserFontSet::UserFontCache::GetFont(nsIURI *aSrcURI,
return nullptr;
}
Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, aPrincipal, aProxy,
// Ignore principal when looking up a data: URI.
nsIPrincipal *principal;
if (IgnorePrincipal(aSrcURI)) {
principal = nullptr;
} else {
principal = aPrincipal;
}
Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, principal, aProxy,
aPrivate));
if (entry) {
return entry->GetFontEntry();
@ -990,20 +1023,21 @@ gfxUserFontSet::UserFontCache::Entry::DumpEntry(Entry* aEntry, void* aUserData)
{
nsresult rv;
nsAutoCString principalURISpec;
nsCOMPtr<nsIURI> principalURI;
rv = aEntry->mPrincipal->GetURI(getter_AddRefs(principalURI));
if (NS_SUCCEEDED(rv)) {
principalURI->GetSpec(principalURISpec);
}
nsAutoCString principalURISpec("(null)");
bool setDomain = false;
nsCOMPtr<nsIURI> domainURI;
aEntry->mPrincipal->GetDomain(getter_AddRefs(domainURI));
if (domainURI) {
setDomain = true;
if (aEntry->mPrincipal) {
nsCOMPtr<nsIURI> principalURI;
rv = aEntry->mPrincipal->GetURI(getter_AddRefs(principalURI));
if (NS_SUCCEEDED(rv)) {
principalURI->GetSpec(principalURISpec);
}
nsCOMPtr<nsIURI> domainURI;
aEntry->mPrincipal->GetDomain(getter_AddRefs(domainURI));
if (domainURI) {
setDomain = true;
}
}
NS_ASSERTION(aEntry->mURI, "null URI in userfont cache entry");

View File

@ -294,7 +294,7 @@ public:
// entry and the corresponding "real" font entry.
struct Key {
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIPrincipal> mPrincipal; // use nullptr with data: URLs
gfxFontEntry *mFontEntry;
bool mPrivate;
@ -333,8 +333,10 @@ public:
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
static PLDHashNumber HashKey(const KeyTypePointer aKey) {
uint32_t principalHash;
aKey->mPrincipal->GetHashValue(&principalHash);
uint32_t principalHash = 0;
if (aKey->mPrincipal) {
aKey->mPrincipal->GetHashValue(&principalHash);
}
return mozilla::HashGeneric(principalHash + int(aKey->mPrivate),
nsURIHashKey::HashKey(aKey->mURI),
HashFeatures(aKey->mFontEntry->mFeatureSettings),
@ -365,7 +367,7 @@ public:
}
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIPrincipal> mPrincipal; // or nullptr for data: URLs
// The "real" font entry corresponding to this downloaded font.
// The font entry MUST notify the cache when it is destroyed

View File

@ -10,9 +10,19 @@
#include "gfxImageSurface.h"
#include "gfxPlatform.h"
#include "gfxDrawable.h"
#include "imgIEncoder.h"
#include "mozilla/Base64.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Vector.h"
#include "nsComponentManagerUtils.h"
#include "nsIClipboardHelper.h"
#include "nsIFile.h"
#include "nsIPresShell.h"
#include "nsPresContext.h"
#include "nsRegion.h"
#include "nsServiceManagerUtils.h"
#include "yuv_convert.h"
#include "ycbcr_to_rgb565.h"
#include "GeckoProfiler.h"
@ -1105,83 +1115,258 @@ gfxUtils::GetColorForFrameNumber(uint64_t aFrameNumber)
return colors[aFrameNumber % sNumFrameColors];
}
#ifdef MOZ_DUMP_PAINTING
/* static */ nsresult
gfxUtils::EncodeSourceSurface(SourceSurface* aSurface,
const nsACString& aMimeType,
const nsAString& aOutputOptions,
BinaryOrData aBinaryOrData,
FILE* aFile)
{
MOZ_ASSERT(aBinaryOrData == eDataURIEncode || aFile,
"Copying binary encoding to clipboard not currently supported");
const IntSize size = aSurface->GetSize();
if (size.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
const Size floatSize(size.width, size.height);
RefPtr<DataSourceSurface> dataSurface;
if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) {
// FIXME bug 995807 (B8G8R8X8), bug 831898 (R5G6B5)
dataSurface =
CopySurfaceToDataSourceSurfaceWithFormat(aSurface,
SurfaceFormat::B8G8R8A8);
} else {
dataSurface = aSurface->GetDataSurface();
}
if (!dataSurface) {
return NS_ERROR_FAILURE;
}
DataSourceSurface::MappedSurface map;
if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
return NS_ERROR_FAILURE;
}
nsAutoCString encoderCID(
NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
if (!encoder) {
#ifdef DEBUG
int32_t w = std::min(size.width, 8);
int32_t h = std::min(size.height, 8);
printf("Could not create encoder. Top-left %dx%d pixels contain:\n", w, h);
for (int32_t y = 0; y < h; ++y) {
for (int32_t x = 0; x < w; ++x) {
printf("%x ", reinterpret_cast<uint32_t*>(map.mData)[y*map.mStride+x]);
}
}
#endif
dataSurface->Unmap();
return NS_ERROR_FAILURE;
}
nsresult rv = encoder->InitFromData(map.mData,
BufferSizeFromStrideAndHeight(map.mStride, size.height),
size.width,
size.height,
map.mStride,
imgIEncoder::INPUT_FORMAT_HOSTARGB,
aOutputOptions);
dataSurface->Unmap();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIInputStream> imgStream;
CallQueryInterface(encoder.get(), getter_AddRefs(imgStream));
if (!imgStream) {
return NS_ERROR_FAILURE;
}
uint64_t bufSize64;
rv = imgStream->Available(&bufSize64);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(bufSize64 < UINT32_MAX - 16, NS_ERROR_FAILURE);
uint32_t bufSize = (uint32_t)bufSize64;
// ...leave a little extra room so we can call read again and make sure we
// got everything. 16 bytes for better padding (maybe)
bufSize += 16;
uint32_t imgSize = 0;
Vector<char> imgData;
if (!imgData.initCapacity(bufSize)) {
return NS_ERROR_OUT_OF_MEMORY;
}
uint32_t numReadThisTime = 0;
while ((rv = imgStream->Read(imgData.begin() + imgSize,
bufSize - imgSize,
&numReadThisTime)) == NS_OK && numReadThisTime > 0)
{
imgSize += numReadThisTime;
if (imgSize == bufSize) {
// need a bigger buffer, just double
bufSize *= 2;
if (!imgData.resizeUninitialized(bufSize)) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
}
if (aBinaryOrData == eBinaryEncode) {
if (aFile) {
fwrite(imgData.begin(), 1, imgSize, aFile);
}
return NS_OK;
}
// base 64, result will be null-terminated
nsCString encodedImg;
rv = Base64Encode(Substring(imgData.begin(), imgSize), encodedImg);
NS_ENSURE_SUCCESS(rv, rv);
nsCString string("data:");
string.Append(aMimeType);
string.Append(";base64,");
string.Append(encodedImg);
if (aFile) {
#ifdef ANDROID
if (aFile == stdout || aFile == stderr) {
// ADB logcat cuts off long strings so we will break it down
const char* cStr = string.BeginReading();
size_t len = strlen(cStr);
while (true) {
printf_stderr("IMG: %.140s\n", cStr);
if (len <= 140)
break;
len -= 140;
cStr += 140;
}
}
#endif
fprintf(aFile, "%s", string.BeginReading());
} else {
nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
if (clipboard) {
clipboard->CopyString(NS_ConvertASCIItoUTF16(string), nullptr);
}
}
return NS_OK;
}
/* static */ void
gfxUtils::WriteAsPNG(SourceSurface* aSurface, const nsAString& aFile)
{
WriteAsPNG(aSurface, NS_ConvertUTF16toUTF8(aFile).get());
}
/* static */ void
gfxUtils::WriteAsPNG(SourceSurface* aSurface, const char* aFile)
{
FILE* file = fopen(aFile, "wb");
if (!file) {
// Maybe the directory doesn't exist; try creating it, then fopen again.
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsIFile> comFile = do_CreateInstance("@mozilla.org/file/local;1");
if (comFile) {
NS_ConvertUTF8toUTF16 utf16path((nsDependentCString(aFile)));
rv = comFile->InitWithPath(utf16path);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIFile> dirPath;
comFile->GetParent(getter_AddRefs(dirPath));
if (dirPath) {
rv = dirPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_ALREADY_EXISTS) {
file = fopen(aFile, "wb");
}
}
}
}
if (!file) {
NS_WARNING("Failed to open file to create PNG!\n");
return;
}
}
EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"),
EmptyString(), eBinaryEncode, file);
fclose(file);
}
/* static */ void
gfxUtils::WriteAsPNG(DrawTarget* aDT, const nsAString& aFile)
{
WriteAsPNG(aDT, NS_ConvertUTF16toUTF8(aFile).get());
}
/* static */ void
gfxUtils::WriteAsPNG(DrawTarget* aDT, const char* aFile)
{
aDT->Flush();
nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aDT);
if (surf) {
surf->WriteAsPNG(aFile);
RefPtr<SourceSurface> surface = aDT->Snapshot();
if (surface) {
WriteAsPNG(surface, aFile);
} else {
NS_WARNING("Failed to get Thebes surface!");
NS_WARNING("Failed to get surface!");
}
}
/* static */ void
gfxUtils::DumpAsDataURL(DrawTarget* aDT)
gfxUtils::WriteAsPNG(nsIPresShell* aShell, const char* aFile)
{
aDT->Flush();
nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aDT);
if (surf) {
surf->DumpAsDataURL();
int32_t width = 1000, height = 1000;
nsRect r(0, 0, aShell->GetPresContext()->DevPixelsToAppUnits(width),
aShell->GetPresContext()->DevPixelsToAppUnits(height));
RefPtr<mozilla::gfx::DrawTarget> dt = gfxPlatform::GetPlatform()->
CreateOffscreenContentDrawTarget(IntSize(width, height),
SurfaceFormat::B8G8R8A8);
NS_ENSURE_TRUE(dt, /*void*/);
nsRefPtr<gfxContext> context = new gfxContext(dt);
aShell->RenderDocument(r, 0, NS_RGB(255, 255, 0), context);
WriteAsPNG(dt.get(), aFile);
}
/* static */ void
gfxUtils::DumpAsDataURI(SourceSurface* aSurface, FILE* aFile)
{
EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"),
EmptyString(), eDataURIEncode, aFile);
}
/* static */ void
gfxUtils::DumpAsDataURI(DrawTarget* aDT, FILE* aFile)
{
RefPtr<SourceSurface> surface = aDT->Snapshot();
if (surface) {
DumpAsDataURI(surface, aFile);
} else {
NS_WARNING("Failed to get Thebes surface!");
NS_WARNING("Failed to get surface!");
}
}
/* static */ void
gfxUtils::CopyAsDataURL(DrawTarget* aDT)
gfxUtils::CopyAsDataURI(SourceSurface* aSurface)
{
aDT->Flush();
nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aDT);
if (surf) {
surf->CopyAsDataURL();
EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"),
EmptyString(), eDataURIEncode, nullptr);
}
/* static */ void
gfxUtils::CopyAsDataURI(DrawTarget* aDT)
{
RefPtr<SourceSurface> surface = aDT->Snapshot();
if (surface) {
CopyAsDataURI(surface);
} else {
NS_WARNING("Failed to get Thebes surface!");
NS_WARNING("Failed to get surface!");
}
}
/* static */ void
gfxUtils::WriteAsPNG(gfx::SourceSurface* aSourceSurface, const char* aFile)
{
RefPtr<gfx::DataSourceSurface> dataSurface = aSourceSurface->GetDataSurface();
RefPtr<gfx::DrawTarget> dt
= gfxPlatform::GetPlatform()
->CreateDrawTargetForData(dataSurface->GetData(),
dataSurface->GetSize(),
dataSurface->Stride(),
aSourceSurface->GetFormat());
gfxUtils::WriteAsPNG(dt.get(), aFile);
}
/* static */ void
gfxUtils::DumpAsDataURL(gfx::SourceSurface* aSourceSurface)
{
RefPtr<gfx::DataSourceSurface> dataSurface = aSourceSurface->GetDataSurface();
RefPtr<gfx::DrawTarget> dt
= gfxPlatform::GetPlatform()
->CreateDrawTargetForData(dataSurface->GetData(),
dataSurface->GetSize(),
dataSurface->Stride(),
aSourceSurface->GetFormat());
gfxUtils::DumpAsDataURL(dt.get());
}
/* static */ void
gfxUtils::CopyAsDataURL(gfx::SourceSurface* aSourceSurface)
{
RefPtr<gfx::DataSourceSurface> dataSurface = aSourceSurface->GetDataSurface();
RefPtr<gfx::DrawTarget> dt
= gfxPlatform::GetPlatform()
->CreateDrawTargetForData(dataSurface->GetData(),
dataSurface->GetSize(),
dataSurface->Stride(),
aSourceSurface->GetFormat());
gfxUtils::CopyAsDataURL(dt.get());
}
#ifdef MOZ_DUMP_PAINTING
static bool sDumpPaintList = getenv("MOZ_DUMP_PAINT_LIST") != 0;
/* static */ bool

View File

@ -16,6 +16,8 @@
class gfxASurface;
class gfxDrawable;
class nsIntRegion;
class nsIPresShell;
struct nsIntRect;
namespace mozilla {
@ -27,6 +29,7 @@ struct PlanarYCbCrData;
class gfxUtils {
public:
typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::IntPoint IntPoint;
typedef mozilla::gfx::Matrix Matrix;
typedef mozilla::gfx::SourceSurface SourceSurface;
@ -228,45 +231,78 @@ public:
static const mozilla::gfx::Color& GetColorForFrameNumber(uint64_t aFrameNumber);
static const uint32_t sNumFrameColors;
enum BinaryOrData {
eBinaryEncode,
eDataURIEncode
};
/**
* Encodes the given surface to PNG/JPEG/BMP/etc. using imgIEncoder.
*
* @param aMimeType The MIME-type of the image type that the surface is to
* be encoded to. Used to create an appropriate imgIEncoder instance to
* do the encoding.
*
* @param aOutputOptions Passed directly to imgIEncoder::InitFromData as
* the value of the |outputOptions| parameter. Callers are responsible
* for making sure that this is a sane value for the passed MIME-type
* (i.e. for the type of encoder that will be created).
*
* @aBinaryOrData Flag used to determine if the surface is simply encoded
* to the requested binary image format, or if the binary image is
* further converted to base-64 and written out as a 'data:' URI.
*
* @aFile If specified, the encoded data is written out to aFile, otherwise
* it is copied to the clipboard.
*
* TODO: Copying to the clipboard as a binary file is not currently
* supported.
*/
static nsresult
EncodeSourceSurface(SourceSurface* aSurface,
const nsACString& aMimeType,
const nsAString& aOutputOptions,
BinaryOrData aBinaryOrData,
FILE* aFile);
/**
* Write as a PNG file to the path aFile.
*/
static void WriteAsPNG(SourceSurface* aSurface, const nsAString& aFile);
static void WriteAsPNG(SourceSurface* aSurface, const char* aFile);
static void WriteAsPNG(DrawTarget* aDT, const nsAString& aFile);
static void WriteAsPNG(DrawTarget* aDT, const char* aFile);
static void WriteAsPNG(nsIPresShell* aShell, const char* aFile);
/**
* Dump as a PNG encoded Data URL to a FILE stream (using stdout by
* default).
*
* Rather than giving aFile a default argument we have separate functions
* to make them easier to use from a debugger.
*/
static void DumpAsDataURI(SourceSurface* aSourceSurface, FILE* aFile);
static inline void DumpAsDataURI(SourceSurface* aSourceSurface) {
DumpAsDataURI(aSourceSurface, stdout);
}
static void DumpAsDataURI(DrawTarget* aDT, FILE* aFile);
static inline void DumpAsDataURI(DrawTarget* aDT) {
DumpAsDataURI(aDT, stdout);
}
/**
* Copy to the clipboard as a PNG encoded Data URL.
*/
static void CopyAsDataURI(SourceSurface* aSourceSurface);
static void CopyAsDataURI(DrawTarget* aDT);
#ifdef MOZ_DUMP_PAINTING
/**
* Writes a binary PNG file.
*/
static void WriteAsPNG(mozilla::gfx::DrawTarget* aDT, const char* aFile);
/**
* Write as a PNG encoded Data URL to stdout.
*/
static void DumpAsDataURL(mozilla::gfx::DrawTarget* aDT);
/**
* Copy a PNG encoded Data URL to the clipboard.
*/
static void CopyAsDataURL(mozilla::gfx::DrawTarget* aDT);
static bool DumpPaintList();
static bool sDumpPainting;
static bool sDumpPaintingToFile;
static FILE* sDumpPaintFile;
/**
* Writes a binary PNG file.
* Expensive. Creates a DataSourceSurface, then a DrawTarget, then passes to DrawTarget overloads
*/
static void WriteAsPNG(mozilla::gfx::SourceSurface* aSourceSurface, const char* aFile);
/**
* Write as a PNG encoded Data URL to stdout.
* Expensive. Creates a DataSourceSurface, then a DrawTarget, then passes to DrawTarget overloads
*/
static void DumpAsDataURL(mozilla::gfx::SourceSurface* aSourceSurface);
/**
* Copy a PNG encoded Data URL to the clipboard.
* Expensive. Creates a DataSourceSurface, then a DrawTarget, then passes to DrawTarget overloads
*/
static void CopyAsDataURL(mozilla::gfx::SourceSurface* aSourceSurface);
#endif
};

View File

@ -1,6 +0,0 @@
js/jsd contains code for debugging support for the C-based JavaScript engine
in js/src. jsd_xpc.cpp provides an XPCOM binding for the library.
js/jsd/jsdb is a console debugger using only native code (see README in that
directory.) This debugger is no longer being actively developed, though it
should work.

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
XPIDL_SOURCES += [
'jsdIDebuggerService.idl',
]
XPIDL_MODULE = 'jsdservice'

File diff suppressed because it is too large Load Diff

View File

@ -1,77 +0,0 @@
; -*- Mode: Fundamental; tab-width: 4; 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/.
LIBRARY JSD1640.DLL
EXETYPE WINDOWS
PROTMODE
DESCRIPTION 'Netscape 16-bit JavaScript Debugger Library'
CODE LOADONCALL MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE SINGLE
HEAPSIZE 8192
EXPORTS
WEP @1 RESIDENTNAME NONAME
_JSD_AppendSourceText
_JSD_ClearAllExecutionHooks
_JSD_ClearAllExecutionHooksForScript
_JSD_ClearDebugBreakHook
_JSD_ClearExecutionHook
_JSD_ClearInterruptHook
_JSD_ClearSourceText
_JSD_DebuggerOff
_JSD_DebuggerOn
_JSD_EvaluateScriptInStackFrame
_JSD_FindSourceForURL
_JSD_GetCallingStackFrame
_JSD_GetClosestLine
_JSD_GetClosestPC
_JSD_GetCountOfStackFrames
_JSD_GetMajorVersion
_JSD_GetMinorVersion
_JSD_GetPCForStackFrame
_JSD_GetScriptBaseLineNumber
_JSD_GetScriptFilename
_JSD_GetScriptForStackFrame
_JSD_GetScriptFunctionId
_JSD_GetScriptHook
_JSD_GetScriptLineExtent
_JSD_GetSourceAlterCount
_JSD_GetSourceStatus
_JSD_GetSourceText
_JSD_GetSourceURL
_JSD_GetStackFrame
_JSD_IncrementSourceAlterCount
_JSD_IsSourceDirty
_JSD_IterateScripts
_JSD_IterateSources
_JSD_LockScriptSubsystem
_JSD_LockSourceTextSubsystem
_JSD_NewSourceText
_JSD_SetDebugBreakHook
_JSD_SetErrorReporter
_JSD_SetExecutionHook
_JSD_SetInterruptHook
_JSD_SetScriptHook
_JSD_SetSourceDirty
_JSD_SetUserCallbacks
_JSD_UnlockScriptSubsystem
_JSD_UnlockSourceTextSubsystem
_Java_netscape_jsdebug_DebugController__0005fsetController_stub
_Java_netscape_jsdebug_DebugController_executeScriptInStackFrame_stub
_Java_netscape_jsdebug_DebugController_sendInterrupt_stub
_Java_netscape_jsdebug_DebugController_setInstructionHook0_stub
_Java_netscape_jsdebug_JSPC_getSourceLocation_stub
_Java_netscape_jsdebug_JSSourceTextProvider_loadSourceTextItem_stub
_Java_netscape_jsdebug_JSSourceTextProvider_refreshSourceTextVector_stub
_Java_netscape_jsdebug_JSStackFrameInfo_getCaller0_stub
_Java_netscape_jsdebug_JSStackFrameInfo_getPC_stub
_Java_netscape_jsdebug_JSThreadState_countStackFrames_stub
_Java_netscape_jsdebug_JSThreadState_getCurrentFrame_stub
_Java_netscape_jsdebug_Script_getClosestPC_stub

View File

@ -1,67 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/////////////////////////////////////////////////////////////////////////////
// Version stamp for this .DLL
#include <windows.h>
#include <ver.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4 // major, minor, release (alpha 1), build #
PRODUCTVERSION 4
FILEFLAGSMASK 0
FILEFLAGS 0 // final version
FILEOS VOS_DOS_WINDOWS16
FILETYPE VFT_DLL
FILESUBTYPE 0 // not used
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4" // Lang=US English, CharSet=Windows Multilingual
BEGIN
VALUE "CompanyName", "Netscape Communications Corporation\0"
VALUE "FileDescription", "Netscape 16-bit JavaScript Debugger Module\0"
VALUE "FileVersion", "4.0\0"
VALUE "InternalName", "JSD1640\0"
VALUE "LegalCopyright", "Copyright Netscape Communications. 1994-96\0"
VALUE "LegalTrademarks", "Netscape, Mozilla\0"
VALUE "OriginalFilename","JSD1640.DLL\0"
VALUE "ProductName", "NETSCAPE\0"
VALUE "ProductVersion", "4.0\0"
END
END
END

View File

@ -1,86 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winver.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,0,0,0
PRODUCTVERSION 4,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x10004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "Netscape Communications Corporation\0"
VALUE "FileDescription", "Netscape 32-bit JavaScript Debugger Module\0"
VALUE "FileVersion", "4.0\0"
VALUE "InternalName", "JSD3240\0"
VALUE "LegalCopyright", "Copyright Netscape Communications. 1994-96\0"
VALUE "LegalTrademarks", "Netscape, Mozilla\0"
VALUE "OriginalFilename", "jsd3240.dll\0"
VALUE "ProductName", "NETSCAPE\0"
VALUE "ProductVersion", "4.0\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""winver.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////

View File

@ -1,147 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
/*
* JavaScript Debugging support - Atom support
*/
#include "jsd.h"
/* #define TEST_ATOMS 1 */
#ifdef TEST_ATOMS
static void
_testAtoms(JSDContext*jsdc)
{
JSDAtom* atom0 = jsd_AddAtom(jsdc, "foo");
JSDAtom* atom1 = jsd_AddAtom(jsdc, "foo");
JSDAtom* atom2 = jsd_AddAtom(jsdc, "bar");
JSDAtom* atom3 = jsd_CloneAtom(jsdc, atom1);
JSDAtom* atom4 = jsd_CloneAtom(jsdc, atom2);
const char* c0 = JSD_ATOM_TO_STRING(atom0);
const char* c1 = JSD_ATOM_TO_STRING(atom1);
const char* c2 = JSD_ATOM_TO_STRING(atom2);
const char* c3 = JSD_ATOM_TO_STRING(atom3);
const char* c4 = JSD_ATOM_TO_STRING(atom4);
jsd_DropAtom(jsdc, atom0);
jsd_DropAtom(jsdc, atom1);
jsd_DropAtom(jsdc, atom2);
jsd_DropAtom(jsdc, atom3);
jsd_DropAtom(jsdc, atom4);
}
#endif
static int
_atom_smasher(JSHashEntry *he, int i, void *arg)
{
MOZ_ASSERT(he);
MOZ_ASSERT(he->value);
MOZ_ASSERT(((JSDAtom*)(he->value))->str);
free(((JSDAtom*)(he->value))->str);
free(he->value);
he->value = nullptr;
he->key = nullptr;
return HT_ENUMERATE_NEXT;
}
static int
_compareAtomKeys(const void *v1, const void *v2)
{
return 0 == strcmp((const char*)v1, (const char*)v2);
}
static int
_compareAtoms(const void *v1, const void *v2)
{
return 0 == strcmp(((JSDAtom*)v1)->str, ((JSDAtom*)v2)->str);
}
bool
jsd_CreateAtomTable(JSDContext* jsdc)
{
jsdc->atoms = JS_NewHashTable(256, JS_HashString,
_compareAtomKeys, _compareAtoms,
nullptr, nullptr);
#ifdef TEST_ATOMS
_testAtoms(jsdc);
#endif
return !!jsdc->atoms;
}
void
jsd_DestroyAtomTable(JSDContext* jsdc)
{
if( jsdc->atoms )
{
JS_HashTableEnumerateEntries(jsdc->atoms, _atom_smasher, nullptr);
JS_HashTableDestroy(jsdc->atoms);
jsdc->atoms = nullptr;
}
}
JSDAtom*
jsd_AddAtom(JSDContext* jsdc, const char* str)
{
JSDAtom* atom;
if(!str)
{
MOZ_ASSERT(0);
return nullptr;
}
JSD_LOCK_ATOMS(jsdc);
atom = (JSDAtom*) JS_HashTableLookup(jsdc->atoms, str);
if( atom )
atom->refcount++;
else
{
atom = (JSDAtom*) malloc(sizeof(JSDAtom));
if( atom )
{
atom->str = strdup(str);
atom->refcount = 1;
if(!JS_HashTableAdd(jsdc->atoms, atom->str, atom))
{
free(atom->str);
free(atom);
atom = nullptr;
}
}
}
JSD_UNLOCK_ATOMS(jsdc);
return atom;
}
JSDAtom*
jsd_CloneAtom(JSDContext* jsdc, JSDAtom* atom)
{
JSD_LOCK_ATOMS(jsdc);
atom->refcount++;
JSD_UNLOCK_ATOMS(jsdc);
return atom;
}
void
jsd_DropAtom(JSDContext* jsdc, JSDAtom* atom)
{
JSD_LOCK_ATOMS(jsdc);
if(! --atom->refcount)
{
JS_HashTableRemove(jsdc->atoms, atom->str);
free(atom->str);
free(atom);
}
JSD_UNLOCK_ATOMS(jsdc);
}

Some files were not shown because too many files have changed in this diff Show More