Merge m-c to b2ginbound, a=merge

This commit is contained in:
Wes Kocher 2015-07-06 17:21:12 -07:00
commit 9cc26b9bcb
148 changed files with 2322 additions and 1119 deletions

View File

@ -457,10 +457,12 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
if (IPCAccessibilityActive()) {
DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
docAcc->SetIPCDoc(ipcDoc);
nsCOMPtr<nsITabChild> tabChild =
do_GetInterface(aDocument->GetDocShell());
static_cast<TabChild*>(tabChild.get())->
SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
nsIDocShell* docShell = aDocument->GetDocShell();
if (docShell) {
nsCOMPtr<nsITabChild> tabChild = do_GetInterface(docShell);
static_cast<TabChild*>(tabChild.get())->
SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
}
}
} else {
parentDocAcc->BindChildDocument(docAcc);

View File

@ -928,6 +928,8 @@ pref("general.useragent.device_id", "");
// Make <audio> and <video> talk to the AudioChannelService.
pref("media.useAudioChannelService", true);
// Add Mozilla AudioChannel APIs.
pref("media.useAudioChannelAPI", true);
pref("b2g.version", @MOZ_B2G_VERSION@);
pref("b2g.osName", @MOZ_B2G_OS_NAME@);

View File

@ -561,6 +561,8 @@ let settingsToObserve = {
},
'dom.mozApps.use_reviewer_certs': false,
'dom.mozApps.signed_apps_installable_from': 'https://marketplace.firefox.com',
'dom.serviceWorkers.interception.enabled': true,
'dom.serviceWorkers.testing.enabled': false,
'gfx.layerscope.enabled': false,
'layers.draw-borders': false,
'layers.draw-tile-borders': false,
@ -568,12 +570,12 @@ let settingsToObserve = {
'layers.enable-tiles': true,
'layers.effect.invert': false,
'layers.effect.grayscale': false,
'layers.effect.contrast': "0.0",
'layers.effect.contrast': '0.0',
'mms.debugging.enabled': false,
'network.debugging.enabled': false,
'privacy.donottrackheader.enabled': false,
'ril.debugging.enabled': false,
'ril.radio.disabled': false,
'mms.debugging.enabled': false,
'ril.mms.requestReadReport.enabled': {
prefName: 'dom.mms.requestReadReport',
defaultValue: true

View File

@ -43,7 +43,7 @@
<div class="graphic graphic-sync-intro"> </div>
<div class="button-row">
<button id="buttonOpenPrefs" class="button" href="#" tabindex="0">&aboutAccountsConfig.manage.label;</button>
<button id="buttonOpenPrefs" class="button" href="#" tabindex="0">&aboutAccountsConfig.syncPreferences.label;</button>
</div>
</section>
</div>

View File

@ -266,6 +266,11 @@ let gFxAccounts = {
let signedInTooltiptext = this.panelUIStatus.getAttribute("signedinTooltiptext");
let updateWithUserData = (userData) => {
// Window might have been closed while fetching data.
if (window.closed) {
return;
}
// Reset the button to its original state.
this.panelUILabel.setAttribute("label", defaultLabel);
this.panelUIStatus.removeAttribute("tooltiptext");

View File

@ -6683,9 +6683,20 @@ var gIdentityHandler = {
this._identityPopup.hidePopup();
},
showSubView(name, anchor) {
toggleSubView(name, anchor) {
let view = document.getElementById("identity-popup-multiView");
view.showSubView(`identity-popup-${name}View`, anchor);
if (view.showingSubView) {
view.showMainView();
} else {
view.showSubView(`identity-popup-${name}View`, anchor);
}
// If an element is focused that's not the anchor, clear the focus.
// Elements of hidden views have -moz-user-focus:ignore but setting that
// per CSS selector doesn't blur a focused element in those hidden views.
if (Services.focus.focusedElement != anchor) {
Services.focus.clearFocus(window);
}
},
/**
@ -7054,11 +7065,6 @@ var gIdentityHandler = {
this._identityPopup.openPopup(this._identityIcon, "bottomcenter topleft");
},
onPopupShown : function(event) {
this._identityPopup.addEventListener("blur", this, true);
this._identityPopup.addEventListener("popuphidden", this);
},
onDragStart: function (event) {
if (gURLBar.getAttribute("pageproxystate") != "valid")
return;
@ -7075,26 +7081,6 @@ var gIdentityHandler = {
dt.setDragImage(gProxyFavIcon, 16, 16);
},
handleEvent: function (event) {
switch (event.type) {
case "blur":
// Focus hasn't moved yet, need to wait until after the blur event.
setTimeout(() => {
if (document.activeElement &&
document.activeElement.compareDocumentPosition(this._identityPopup) &
Node.DOCUMENT_POSITION_CONTAINS)
return;
this._identityPopup.hidePopup();
}, 0);
break;
case "popuphidden":
this._identityPopup.removeEventListener("blur", this, true);
this._identityPopup.removeEventListener("popuphidden", this);
break;
}
},
updateSitePermissions: function () {
while (this._permissionList.hasChildNodes())
this._permissionList.removeChild(this._permissionList.lastChild);

View File

@ -220,7 +220,6 @@ skip-if = toolkit != "cocoa"
[browser_bug580956.js]
[browser_bug581242.js]
[browser_bug581253.js]
skip-if = e10s # Bug 1093756 - can't bookmark the data: url in e10s somehow
[browser_bug581947.js]
[browser_bug585558.js]
[browser_bug585785.js]
@ -234,7 +233,6 @@ skip-if = e10s # Bug 653065 - Make the lightweight theme web installer ready for
[browser_bug597218.js]
[browser_bug609700.js]
[browser_bug623155.js]
skip-if = e10s && debug
[browser_bug623893.js]
[browser_bug624734.js]
[browser_bug633691.js]
@ -245,7 +243,6 @@ skip-if = buildapp == 'mulet'
[browser_bug676619.js]
skip-if = buildapp == 'mulet' || os == "mac" # mac: Intermittent failures, bug 925225
[browser_bug678392.js]
skip-if = e10s # bug 1102331 - does focus things on the content window which break in e10s mode
[browser_bug710878.js]
[browser_bug719271.js]
[browser_bug724239.js]
@ -260,7 +257,6 @@ skip-if = e10s # bug 1102331 - does focus things on the content window which bre
[browser_bug832435.js]
[browser_bug839103.js]
[browser_bug880101.js]
skip-if = e10s # Bug 1126316 - New e10s windows erroneously fire initial about:blank location through nsIWebProgressListener
[browser_bug882977.js]
[browser_bug902156.js]
[browser_bug906190.js]
@ -295,7 +291,6 @@ skip-if = e10s
skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
[browser_favicon_change.js]
[browser_favicon_change_not_in_document.js]
skip-if = e10s
[browser_findbarClose.js]
[browser_fullscreen-window-open.js]
skip-if = buildapp == 'mulet' || e10s || os == "linux" # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly. Linux: Intermittent failures - bug 941575.
@ -309,11 +304,10 @@ skip-if = e10s # Bug 863514 - no gesture support.
[browser_homeDrop.js]
skip-if = buildapp == 'mulet'
[browser_identity_UI.js]
skip-if = e10s && debug # Seeing lots of timeouts (bug 1095517)
skip-if = debug # Seeing lots of timeouts (bug 1095517)
[browser_keywordBookmarklets.js]
skip-if = e10s # Bug 1102025 - different principals for the bookmarklet only in e10s mode (unclear if test or 'real' issue)
[browser_keywordSearch.js]
skip-if = e10s # Bug 921957 - remote webprogress doesn't supply cancel method on the request object
[browser_keywordSearch_postData.js]
[browser_lastAccessedTab.js]
skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bug 969405)
@ -334,12 +328,9 @@ skip-if = buildapp == 'mulet' || e10s # Bug 1093603 - test breaks with PopupNoti
[browser_pageInfo.js]
skip-if = buildapp == 'mulet'
[browser_page_style_menu.js]
[browser_parsable_css.js]
skip-if = e10s
[browser_parsable_script.js]
skip-if = asan || (os == 'linux' && !debug && (bits == 32)) # disabled on asan because of timeouts, and bug 1172468 for the linux 32-bit pgo issue.
[browser_pinnedTabs.js]
[browser_plainTextLinks.js]
[browser_popupUI.js]
@ -377,7 +368,6 @@ skip-if = buildapp == 'mulet'
[browser_save_video_frame.js]
[browser_scope.js]
[browser_searchSuggestionUI.js]
skip-if = e10s
support-files =
searchSuggestionUI.html
searchSuggestionUI.js
@ -388,7 +378,6 @@ run-if = e10s
[browser_star_hsts.js]
[browser_subframe_favicons_not_used.js]
[browser_syncui.js]
skip-if = e10s # Bug 1137087 - browser_tabopen_reflows.js fails if this was previously run with e10s
[browser_tabDrop.js]
skip-if = buildapp == 'mulet' || e10s
[browser_tabReorder.js]
@ -407,7 +396,6 @@ skip-if = buildapp == 'mulet'
skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
# Disabled on OS X because of bug 967917
[browser_tabfocus.js]
skip-if = e10s && debug # Bug 907326
[browser_tabkeynavigation.js]
skip-if = e10s
[browser_tabopen_reflows.js]
@ -455,7 +443,7 @@ skip-if = true # Bug 1005420 - fails intermittently. also with e10s enabled: biz
[browser_visibleTabs_bookmarkAllTabs.js]
[browser_visibleTabs_contextMenu.js]
[browser_visibleTabs_tabPreview.js]
skip-if = (os == "win" && !debug) || e10s # Bug 1007418
skip-if = (os == "win" && !debug)
[browser_web_channel.js]
[browser_windowopen_reflows.js]
skip-if = buildapp == 'mulet'

View File

@ -5,9 +5,6 @@
<panel id="identity-popup"
type="arrow"
hidden="true"
noautofocus="true"
onpopupshown="if (event.target == this)
gIdentityHandler.onPopupShown(event);"
orient="vertical"
level="top">
@ -33,7 +30,7 @@
value="&identity.connectionInternal;"/>
</vbox>
<button class="identity-popup-expander"
oncommand="gIdentityHandler.showSubView('security', this)"/>
oncommand="gIdentityHandler.toggleSubView('security', this)"/>
</hbox>
<!-- Tracking Protection Section -->

View File

@ -15,7 +15,7 @@
<content>
<xul:box anonid="viewContainer" class="panel-viewcontainer" xbl:inherits="panelopen,viewtype,transitioning">
<xul:stack anonid="viewStack" xbl:inherits="viewtype,transitioning" viewtype="main" class="panel-viewstack">
<xul:vbox anonid="mainViewContainer" class="panel-mainview"/>
<xul:vbox anonid="mainViewContainer" class="panel-mainview" xbl:inherits="viewtype"/>
<!-- Used to capture click events over the PanelUI-mainView if we're in
subview mode. That way, any click on the PanelUI-mainView causes us

View File

@ -459,7 +459,7 @@ loop.conversationViews = (function(mozL10n) {
_onEmailLinkReceived: function() {
var emailLink = this.getStoreState().emailLink;
var contactEmail = _getPreferredEmail(this.props.contact).value;
sharedUtils.composeCallUrlEmail(emailLink, contactEmail);
sharedUtils.composeCallUrlEmail(emailLink, contactEmail, null, "callfailed");
this.closeWindow();
},

View File

@ -459,7 +459,7 @@ loop.conversationViews = (function(mozL10n) {
_onEmailLinkReceived: function() {
var emailLink = this.getStoreState().emailLink;
var contactEmail = _getPreferredEmail(this.props.contact).value;
sharedUtils.composeCallUrlEmail(emailLink, contactEmail);
sharedUtils.composeCallUrlEmail(emailLink, contactEmail, null, "callfailed");
this.closeWindow();
},

View File

@ -546,7 +546,8 @@ loop.panel = (function(_, mozL10n) {
event.stopPropagation();
event.preventDefault();
this.props.dispatcher.dispatch(new sharedActions.CopyRoomUrl({
roomUrl: this.props.room.roomUrl
roomUrl: this.props.room.roomUrl,
from: "panel"
}));
this.setState({urlCopied: true});
},

View File

@ -546,7 +546,8 @@ loop.panel = (function(_, mozL10n) {
event.stopPropagation();
event.preventDefault();
this.props.dispatcher.dispatch(new sharedActions.CopyRoomUrl({
roomUrl: this.props.room.roomUrl
roomUrl: this.props.room.roomUrl,
from: "panel"
}));
this.setState({urlCopied: true});
},

View File

@ -275,7 +275,9 @@ loop.store = loop.store || {};
this._notifications.remove("create-room-error");
this._mozLoop.rooms.create(roomCreationData, function(err, createdRoom) {
var buckets = this._mozLoop.ROOM_CREATE;
if (err) {
this._mozLoop.telemetryAddValue("LOOP_ROOM_CREATE", buckets.CREATE_FAIL);
this.dispatchAction(new sharedActions.CreateRoomError({error: err}));
return;
}
@ -283,6 +285,16 @@ loop.store = loop.store || {};
this.dispatchAction(new sharedActions.CreatedRoom({
roomToken: createdRoom.roomToken
}));
this._mozLoop.telemetryAddValue("LOOP_ROOM_CREATE", buckets.CREATE_SUCCESS);
// Since creating a room with context is only possible from the panel,
// we can record that as the action here.
var URLs = roomCreationData.decryptedContext.urls;
if (URLs && URLs.length) {
buckets = this._mozLoop.ROOM_CONTEXT_ADD;
this._mozLoop.telemetryAddValue("LOOP_ROOM_CONTEXT_ADD",
buckets.ADD_FROM_PANEL);
}
}.bind(this));
},
@ -325,6 +337,14 @@ loop.store = loop.store || {};
copyRoomUrl: function(actionData) {
this._mozLoop.copyString(actionData.roomUrl);
this._mozLoop.notifyUITour("Loop:RoomURLCopied");
var from = actionData.from;
var bucket = this._mozLoop.SHARING_ROOM_URL["COPY_FROM_" + from.toUpperCase()];
if (typeof bucket === "undefined") {
console.error("No URL sharing type bucket found for '" + from + "'");
return;
}
this._mozLoop.telemetryAddValue("LOOP_SHARING_ROOM_URL", bucket);
},
/**
@ -334,7 +354,7 @@ loop.store = loop.store || {};
*/
emailRoomUrl: function(actionData) {
loop.shared.utils.composeCallUrlEmail(actionData.roomUrl, null,
actionData.roomDescription);
actionData.roomDescription, actionData.from);
this._mozLoop.notifyUITour("Loop:RoomURLEmailed");
},
@ -390,9 +410,12 @@ loop.store = loop.store || {};
*/
deleteRoom: function(actionData) {
this._mozLoop.rooms.delete(actionData.roomToken, function(err) {
var buckets = this._mozLoop.ROOM_DELETE;
if (err) {
this.dispatchAction(new sharedActions.DeleteRoomError({error: err}));
this.dispatchAction(new sharedActions.DeleteRoomError({error: err}));
}
this._mozLoop.telemetryAddValue("LOOP_ROOM_DELETE", buckets[err ?
"DELETE_FAIL" : "DELETE_SUCCESS"]);
}.bind(this));
},
@ -521,6 +544,8 @@ loop.store = loop.store || {};
return;
}
var hadContextBefore = !!oldRoomURL;
this.setStoreState({error: null});
this._mozLoop.rooms.update(actionData.roomToken, roomData,
function(error, data) {
@ -528,6 +553,15 @@ loop.store = loop.store || {};
new sharedActions.UpdateRoomContextError({ error: error }) :
new sharedActions.UpdateRoomContextDone();
this.dispatchAction(action);
if (!err && !hadContextBefore) {
// Since updating the room context data is only possible from the
// conversation window, we can assume that any newly added URL was
// done from there.
var buckets = this._mozLoop.ROOM_CONTEXT_ADD;
this._mozLoop.telemetryAddValue("LOOP_ROOM_CONTEXT_ADD",
buckets.ADD_FROM_CONVERSATION);
}
}.bind(this));
}.bind(this));
},

View File

@ -178,15 +178,18 @@ loop.roomViews = (function(mozL10n) {
this.props.dispatcher.dispatch(
new sharedActions.EmailRoomUrl({
roomUrl: roomData.roomUrl,
roomDescription: contextURL && contextURL.description
roomDescription: contextURL && contextURL.description,
from: "conversation"
}));
},
handleCopyButtonClick: function(event) {
event.preventDefault();
this.props.dispatcher.dispatch(
new sharedActions.CopyRoomUrl({roomUrl: this.props.roomData.roomUrl}));
this.props.dispatcher.dispatch(new sharedActions.CopyRoomUrl({
roomUrl: this.props.roomData.roomUrl,
from: "conversation"
}));
this.setState({copiedUrl: true});
},
@ -395,7 +398,10 @@ loop.roomViews = (function(mozL10n) {
return;
}
this.props.mozLoop.openURL(url.location);
var mozLoop = this.props.mozLoop;
mozLoop.openURL(url.location);
mozLoop.telemetryAddValue("LOOP_ROOM_CONTEXT_CLICK", 1);
},
handleCheckboxChange: function(state) {

View File

@ -178,15 +178,18 @@ loop.roomViews = (function(mozL10n) {
this.props.dispatcher.dispatch(
new sharedActions.EmailRoomUrl({
roomUrl: roomData.roomUrl,
roomDescription: contextURL && contextURL.description
roomDescription: contextURL && contextURL.description,
from: "conversation"
}));
},
handleCopyButtonClick: function(event) {
event.preventDefault();
this.props.dispatcher.dispatch(
new sharedActions.CopyRoomUrl({roomUrl: this.props.roomData.roomUrl}));
this.props.dispatcher.dispatch(new sharedActions.CopyRoomUrl({
roomUrl: this.props.roomData.roomUrl,
from: "conversation"
}));
this.setState({copiedUrl: true});
},
@ -395,7 +398,10 @@ loop.roomViews = (function(mozL10n) {
return;
}
this.props.mozLoop.openURL(url.location);
var mozLoop = this.props.mozLoop;
mozLoop.openURL(url.location);
mozLoop.telemetryAddValue("LOOP_ROOM_CONTEXT_CLICK", 1);
},
handleCheckboxChange: function(state) {

View File

@ -415,6 +415,7 @@ loop.shared.actions = (function() {
* XXX: should move to some roomActions module - refs bug 1079284
*/
CopyRoomUrl: Action.define("copyRoomUrl", {
from: String,
roomUrl: String
}),
@ -423,6 +424,7 @@ loop.shared.actions = (function() {
* XXX: should move to some roomActions module - refs bug 1079284
*/
EmailRoomUrl: Action.define("emailRoomUrl", {
from: String,
roomUrl: String
// roomDescription: String, Optional.
}),

View File

@ -439,11 +439,14 @@ loop.store = loop.store || {};
maxSize: loop.store.MAX_ROOM_CREATION_SIZE,
expiresIn: loop.store.DEFAULT_EXPIRES_IN
}, function(err, createdRoomData) {
var buckets = this.mozLoop.ROOM_CREATE;
if (err) {
this.trigger("error:emailLink");
this.mozLoop.telemetryAddValue("LOOP_ROOM_CREATE", buckets.CREATE_FAIL);
return;
}
this.setStoreState({"emailLink": createdRoomData.roomUrl});
this.mozLoop.telemetryAddValue("LOOP_ROOM_CREATE", buckets.CREATE_SUCCESS);
}.bind(this));
},

View File

@ -388,9 +388,11 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
* @param {String} callUrl The call URL.
* @param {String} [recipient] The recipient email address (optional).
* @param {String} [contextDescription] The context description (optional).
* @param {String} [from] The area from which this function is called.
*/
function composeCallUrlEmail(callUrl, recipient, contextDescription) {
if (typeof navigator.mozLoop === "undefined") {
function composeCallUrlEmail(callUrl, recipient, contextDescription, from) {
var mozLoop = navigator.mozLoop;
if (typeof mozLoop === "undefined") {
console.warn("composeCallUrlEmail isn't available for Loop standalone.");
return;
}
@ -399,7 +401,7 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
var brandShortname = mozL10n.get("brandShortname");
var clientShortname2 = mozL10n.get("clientShortname2");
var clientSuperShortname = mozL10n.get("clientSuperShortname");
var learnMoreUrl = navigator.mozLoop.getLoopPref("learnMoreUrl");
var learnMoreUrl = mozLoop.getLoopPref("learnMoreUrl");
if (contextDescription) {
subject = mozL10n.get("share_email_subject_context", {
@ -427,11 +429,18 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
});
}
navigator.mozLoop.composeEmail(
mozLoop.composeEmail(
subject,
body.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n"),
recipient
);
var bucket = mozLoop.SHARING_ROOM_URL["EMAIL_FROM_" + (from || "").toUpperCase()];
if (typeof bucket === "undefined") {
console.error("No URL sharing type bucket found for '" + from + "'");
return;
}
mozLoop.telemetryAddValue("LOOP_SHARING_ROOM_URL", bucket);
}
// We can alias `subarray` to `slice` when the latter is not available, because

View File

@ -674,6 +674,34 @@ function injectLoopAPI(targetWindow) {
}
},
SHARING_ROOM_URL: {
enumerable: true,
get: function() {
return Cu.cloneInto(SHARING_ROOM_URL, targetWindow);
}
},
ROOM_CREATE: {
enumerable: true,
get: function() {
return Cu.cloneInto(ROOM_CREATE, targetWindow);
}
},
ROOM_DELETE: {
enumerable: true,
get: function() {
return Cu.cloneInto(ROOM_DELETE, targetWindow);
}
},
ROOM_CONTEXT_ADD: {
enumerable: true,
get: function() {
return Cu.cloneInto(ROOM_CONTEXT_ADD, targetWindow);
}
},
fxAEnabled: {
enumerable: true,
get: function() {

View File

@ -42,6 +42,49 @@ const SHARING_STATE_CHANGE = {
BROWSER_DISABLED: 3
};
/**
* Values that we segment sharing a room URL action telemetry probes into.
*
* @type {{COPY_FROM_PANEL: Number, COPY_FROM_CONVERSATION: Number,
* EMAIL_FROM_CALLFAILED: Number, EMAIL_FROM_CONVERSATION: Number}}
*/
const SHARING_ROOM_URL = {
COPY_FROM_PANEL: 0,
COPY_FROM_CONVERSATION: 1,
EMAIL_FROM_CALLFAILED: 2,
EMAIL_FROM_CONVERSATION: 3
};
/**
* Values that we segment room create action telemetry probes into.
*
* @type {{CREATE_SUCCESS: Number, CREATE_FAIL: Number}}
*/
const ROOM_CREATE = {
CREATE_SUCCESS: 0,
CREATE_FAIL: 1
};
/**
* Values that we segment room delete action telemetry probes into.
*
* @type {{DELETE_SUCCESS: Number, DELETE_FAIL: Number}}
*/
const ROOM_DELETE = {
DELETE_SUCCESS: 0,
DELETE_FAIL: 1
};
/**
* Values that we segment room context action telemetry probes into.
*
* @type {{ADD_FROM_PANEL: Number, ADD_FROM_CONVERSATION: Number}}
*/
const ROOM_CONTEXT_ADD = {
ADD_FROM_PANEL: 0,
ADD_FROM_CONVERSATION: 1
};
// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
const PREF_LOG_LEVEL = "loop.debug.loglevel";
@ -56,7 +99,8 @@ Cu.import("resource://gre/modules/FxAccountsOAuthClient.jsm");
Cu.importGlobalProperties(["URL"]);
this.EXPORTED_SYMBOLS = ["MozLoopService", "LOOP_SESSION_TYPE",
"TWO_WAY_MEDIA_CONN_LENGTH", "SHARING_STATE_CHANGE"];
"TWO_WAY_MEDIA_CONN_LENGTH", "SHARING_STATE_CHANGE", "SHARING_ROOM_URL",
"ROOM_CREATE", "ROOM_DELETE", "ROOM_CONTEXT_ADD"];
XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI",
"resource:///modules/loop/MozLoopAPI.jsm");

View File

@ -52,6 +52,10 @@ describe("loop.conversationViews", function () {
};
fakeMozLoop = navigator.mozLoop = {
SHARING_ROOM_URL: {
EMAIL_FROM_CALLFAILED: 2,
EMAIL_FROM_CONVERSATION: 3
},
// Dummy function, stubbed below.
getLoopPref: function() {},
calls: {
@ -255,7 +259,7 @@ describe("loop.conversationViews", function () {
});
describe("CallFailedView", function() {
var fakeAudio;
var fakeAudio, composeCallUrlEmail;
var fakeContact = {email: [{value: "test@test.tld"}]};
@ -275,6 +279,7 @@ describe("loop.conversationViews", function () {
removeAttribute: sinon.spy()
};
sandbox.stub(window, "Audio").returns(fakeAudio);
composeCallUrlEmail = sandbox.stub(sharedUtils, "composeCallUrlEmail");
});
it("should dispatch a retryCall action when the retry button is pressed",
@ -346,13 +351,12 @@ describe("loop.conversationViews", function () {
});
it("should compose an email once the email link is received", function() {
var composeCallUrlEmail = sandbox.stub(sharedUtils, "composeCallUrlEmail");
view = mountTestComponent({contact: fakeContact});
conversationStore.setStoreState({emailLink: "http://fake.invalid/"});
sinon.assert.calledOnce(composeCallUrlEmail);
sinon.assert.calledWithExactly(composeCallUrlEmail,
"http://fake.invalid/", "test@test.tld");
"http://fake.invalid/", "test@test.tld", null, "callfailed");
});
it("should close the conversation window once the email link is received",

View File

@ -526,8 +526,10 @@ describe("loop.panel", function() {
TestUtils.Simulate.click(copyButton);
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.CopyRoomUrl({roomUrl: roomData.roomUrl}));
sinon.assert.calledWithExactly(dispatcher.dispatch, new sharedActions.CopyRoomUrl({
roomUrl: roomData.roomUrl,
from: "panel"
}));
});
it("should set state.urlCopied when the click event fires", function() {

View File

@ -76,6 +76,24 @@ describe("loop.store.RoomStore", function () {
beforeEach(function() {
fakeMozLoop = {
SHARING_ROOM_URL: {
COPY_FROM_PANEL: 0,
COPY_FROM_CONVERSATION: 1,
EMAIL_FROM_PANEL: 2,
EMAIL_FROM_CONVERSATION: 3
},
ROOM_CREATE: {
CREATE_SUCCESS: 0,
CREATE_FAIL: 1
},
ROOM_DELETE: {
DELETE_SUCCESS: 0,
DELETE_FAIL: 1
},
ROOM_CONTEXT_ADD: {
ADD_FROM_PANEL: 0,
ADD_FROM_CONVERSATION: 1
},
copyString: function() {},
getLoopPref: function(pref) {
return pref;
@ -83,11 +101,13 @@ describe("loop.store.RoomStore", function () {
notifyUITour: function() {},
rooms: {
create: function() {},
delete: function() {},
getAll: function() {},
open: function() {},
rename: function() {},
on: sandbox.stub()
}
},
telemetryAddValue: sinon.stub()
};
fakeNotifications = {
set: sinon.stub(),
@ -217,14 +237,15 @@ describe("loop.store.RoomStore", function () {
var fakeNameTemplate = "Conversation {{conversationLabel}}";
var fakeLocalRoomId = "777";
var fakeOwner = "fake@invalid";
var fakeRoomCreationData = {
nameTemplate: fakeNameTemplate,
roomOwner: fakeOwner
};
var fakeRoomCreationData;
beforeEach(function() {
sandbox.stub(dispatcher, "dispatch");
store.setStoreState({pendingCreation: false, rooms: []});
fakeRoomCreationData = {
nameTemplate: fakeNameTemplate,
roomOwner: fakeOwner
};
});
it("should clear any existing room errors", function() {
@ -237,6 +258,24 @@ describe("loop.store.RoomStore", function () {
"create-room-error");
});
it("should log a telemetry event when the operation with context is successful", function() {
sandbox.stub(fakeMozLoop.rooms, "create", function(data, cb) {
cb(null, {roomToken: "fakeToken"});
});
fakeRoomCreationData.urls = [{
location: "http://invalid.com",
description: "fakeSite",
thumbnail: "fakeimage.png"
}];
store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
sinon.assert.calledTwice(fakeMozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(fakeMozLoop.telemetryAddValue,
"LOOP_ROOM_CONTEXT_ADD", 0);
});
it("should request creation of a new room", function() {
sandbox.stub(fakeMozLoop.rooms, "create");
@ -314,6 +353,31 @@ describe("loop.store.RoomStore", function () {
error: err
}));
});
it("should log a telemetry event when the operation is successful", function() {
sandbox.stub(fakeMozLoop.rooms, "create", function(data, cb) {
cb(null, {roomToken: "fakeToken"});
});
store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
sinon.assert.calledOnce(fakeMozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(fakeMozLoop.telemetryAddValue,
"LOOP_ROOM_CREATE", 0);
});
it("should log a telemetry event when the operation fails", function() {
var err = new Error("fake");
sandbox.stub(fakeMozLoop.rooms, "create", function(data, cb) {
cb(err);
});
store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
sinon.assert.calledOnce(fakeMozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(fakeMozLoop.telemetryAddValue,
"LOOP_ROOM_CREATE", 1);
});
});
describe("#createdRoom", function() {
@ -369,17 +433,104 @@ describe("loop.store.RoomStore", function () {
});
});
describe("#deleteRoom", function() {
var fakeRoomToken = "42abc";
beforeEach(function() {
sandbox.stub(dispatcher, "dispatch");
});
it("should request deletion of a room", function() {
sandbox.stub(fakeMozLoop.rooms, "delete");
store.deleteRoom(new sharedActions.DeleteRoom({
roomToken: fakeRoomToken
}));
sinon.assert.calledWith(fakeMozLoop.rooms.delete, fakeRoomToken);
});
it("should dispatch a DeleteRoomError action if the operation fails", function() {
var err = new Error("fake");
sandbox.stub(fakeMozLoop.rooms, "delete", function(roomToken, cb) {
cb(err);
});
store.deleteRoom(new sharedActions.DeleteRoom({
roomToken: fakeRoomToken
}));
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.DeleteRoomError({
error: err
}));
});
it("should log a telemetry event when the operation is successful", function() {
sandbox.stub(fakeMozLoop.rooms, "delete", function(roomToken, cb) {
cb();
});
store.deleteRoom(new sharedActions.DeleteRoom({
roomToken: fakeRoomToken
}));
sinon.assert.calledOnce(fakeMozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(fakeMozLoop.telemetryAddValue,
"LOOP_ROOM_DELETE", 0);
});
it("should log a telemetry event when the operation fails", function() {
var err = new Error("fake");
sandbox.stub(fakeMozLoop.rooms, "delete", function(roomToken, cb) {
cb(err);
});
store.deleteRoom(new sharedActions.DeleteRoom({
roomToken: fakeRoomToken
}));
sinon.assert.calledOnce(fakeMozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(fakeMozLoop.telemetryAddValue,
"LOOP_ROOM_DELETE", 1);
});
});
describe("#copyRoomUrl", function() {
it("should copy the room URL", function() {
var copyString = sandbox.stub(fakeMozLoop, "copyString");
store.copyRoomUrl(new sharedActions.CopyRoomUrl({
roomUrl: "http://invalid"
roomUrl: "http://invalid",
from: "conversation"
}));
sinon.assert.calledOnce(copyString);
sinon.assert.calledWithExactly(copyString, "http://invalid");
});
it("should send a telemetry event for copy from panel", function() {
store.copyRoomUrl(new sharedActions.CopyRoomUrl({
roomUrl: "http://invalid",
from: "panel"
}));
sinon.assert.calledOnce(fakeMozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(fakeMozLoop.telemetryAddValue,
"LOOP_SHARING_ROOM_URL", 0);
});
it("should send a telemetry event for copy from conversation", function() {
store.copyRoomUrl(new sharedActions.CopyRoomUrl({
roomUrl: "http://invalid",
from: "conversation"
}));
sinon.assert.calledOnce(fakeMozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(fakeMozLoop.telemetryAddValue,
"LOOP_SHARING_ROOM_URL", 1);
});
});
describe("#emailRoomUrl", function() {
@ -387,12 +538,13 @@ describe("loop.store.RoomStore", function () {
sandbox.stub(sharedUtils, "composeCallUrlEmail");
store.emailRoomUrl(new sharedActions.EmailRoomUrl({
roomUrl: "http://invalid"
roomUrl: "http://invalid",
from: "conversation"
}));
sinon.assert.calledOnce(sharedUtils.composeCallUrlEmail);
sinon.assert.calledWith(sharedUtils.composeCallUrlEmail,
"http://invalid");
"http://invalid", null, undefined, "conversation");
});
it("should call composeUrlEmail differently with context", function() {
@ -402,12 +554,13 @@ describe("loop.store.RoomStore", function () {
var description = "Hello, is it me you're looking for?";
store.emailRoomUrl(new sharedActions.EmailRoomUrl({
roomUrl: url,
roomDescription: description
roomDescription: description,
from: "conversation"
}));
sinon.assert.calledOnce(sharedUtils.composeCallUrlEmail);
sinon.assert.calledWithExactly(sharedUtils.composeCallUrlEmail,
url, null, description);
url, null, description, "conversation");
});
});

View File

@ -29,6 +29,7 @@ describe("loop.roomViews", function () {
previews: [],
title: ""
}),
openURL: sinon.stub(),
rooms: {
get: sinon.stub().callsArgWith(1, null, {
roomToken: "fakeToken",
@ -39,7 +40,8 @@ describe("loop.roomViews", function () {
}
}),
update: sinon.stub().callsArgWith(2, null)
}
},
telemetryAddValue: sinon.stub()
};
fakeWindow = {
@ -163,7 +165,8 @@ describe("loop.roomViews", function () {
sinon.assert.calledWith(dispatcher.dispatch,
new sharedActions.EmailRoomUrl({
roomUrl: "http://invalid",
roomDescription: undefined
roomDescription: undefined,
from: "conversation"
}));
});
@ -186,7 +189,8 @@ describe("loop.roomViews", function () {
sinon.assert.calledWith(dispatcher.dispatch,
new sharedActions.EmailRoomUrl({
roomUrl: url,
roomDescription: description
roomDescription: description,
from: "conversation"
}));
});
@ -204,8 +208,10 @@ describe("loop.roomViews", function () {
React.addons.TestUtils.Simulate.click(copyBtn);
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWith(dispatcher.dispatch,
new sharedActions.CopyRoomUrl({roomUrl: "http://invalid"}));
sinon.assert.calledWith(dispatcher.dispatch, new sharedActions.CopyRoomUrl({
roomUrl: "http://invalid",
from: "conversation"
}));
});
it("should change the text when the url has been copied", function() {
@ -932,5 +938,54 @@ describe("loop.roomViews", function () {
expect(node.querySelector(".room-context-comments").value).to.eql("");
});
});
describe("#handleContextClick", function() {
var fakeEvent;
beforeEach(function() {
fakeEvent = {
preventDefault: sinon.stub(),
stopPropagation: sinon.stub()
};
});
it("should not attempt to open a URL when none is attached", function() {
view = mountTestComponent({
roomData: {
roomToken: "fakeToken",
roomName: "fakeName"
}
});
view.handleContextClick(fakeEvent);
sinon.assert.calledOnce(fakeEvent.preventDefault);
sinon.assert.calledOnce(fakeEvent.stopPropagation);
sinon.assert.notCalled(fakeMozLoop.openURL);
sinon.assert.notCalled(fakeMozLoop.telemetryAddValue);
});
it("should open a URL", function() {
view = mountTestComponent({
roomData: {
roomToken: "fakeToken",
roomName: "fakeName",
roomContextUrls: [fakeContextURL]
}
});
view.handleContextClick(fakeEvent);
sinon.assert.calledOnce(fakeEvent.preventDefault);
sinon.assert.calledOnce(fakeEvent.stopPropagation);
sinon.assert.calledOnce(fakeMozLoop.openURL);
sinon.assert.calledWithExactly(fakeMozLoop.openURL, fakeContextURL.location);
sinon.assert.calledOnce(fakeMozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(fakeMozLoop.telemetryAddValue,
"LOOP_ROOM_CONTEXT_CLICK", 1);
});
});
});
});

View File

@ -76,3 +76,104 @@ add_task(function* test_mozLoop_telemetryAdd_sharing_buckets() {
Assert.strictEqual(snapshot.counts[SHARING_STATES.BROWSER_ENABLED], 3, "SHARING_STATE_CHANGE.BROWSER_ENABLED");
Assert.strictEqual(snapshot.counts[SHARING_STATES.BROWSER_DISABLED], 4, "SHARING_STATE_CHANGE.BROWSER_DISABLED");
});
add_task(function* test_mozLoop_telemetryAdd_sharingURL_buckets() {
let histogramId = "LOOP_SHARING_ROOM_URL";
let histogram = Services.telemetry.getHistogramById(histogramId);
const SHARING_TYPES = gMozLoopAPI.SHARING_ROOM_URL;
histogram.clear();
for (let value of [SHARING_TYPES.COPY_FROM_PANEL,
SHARING_TYPES.COPY_FROM_CONVERSATION,
SHARING_TYPES.COPY_FROM_CONVERSATION,
SHARING_TYPES.EMAIL_FROM_CALLFAILED,
SHARING_TYPES.EMAIL_FROM_CALLFAILED,
SHARING_TYPES.EMAIL_FROM_CALLFAILED,
SHARING_TYPES.EMAIL_FROM_CONVERSATION,
SHARING_TYPES.EMAIL_FROM_CONVERSATION,
SHARING_TYPES.EMAIL_FROM_CONVERSATION,
SHARING_TYPES.EMAIL_FROM_CONVERSATION]) {
gMozLoopAPI.telemetryAddValue(histogramId, value);
}
let snapshot = histogram.snapshot();
Assert.strictEqual(snapshot.counts[SHARING_TYPES.COPY_FROM_PANEL], 1,
"SHARING_ROOM_URL.COPY_FROM_PANEL");
Assert.strictEqual(snapshot.counts[SHARING_TYPES.COPY_FROM_CONVERSATION], 2,
"SHARING_ROOM_URL.COPY_FROM_CONVERSATION");
Assert.strictEqual(snapshot.counts[SHARING_TYPES.EMAIL_FROM_CALLFAILED], 3,
"SHARING_ROOM_URL.EMAIL_FROM_CALLFAILED");
Assert.strictEqual(snapshot.counts[SHARING_TYPES.EMAIL_FROM_CONVERSATION], 4,
"SHARING_ROOM_URL.EMAIL_FROM_CONVERSATION");
});
add_task(function* test_mozLoop_telemetryAdd_roomCreate_buckets() {
let histogramId = "LOOP_ROOM_CREATE";
let histogram = Services.telemetry.getHistogramById(histogramId);
const ACTION_TYPES = gMozLoopAPI.ROOM_CREATE;
histogram.clear();
for (let value of [ACTION_TYPES.CREATE_SUCCESS,
ACTION_TYPES.CREATE_FAIL,
ACTION_TYPES.CREATE_FAIL]) {
gMozLoopAPI.telemetryAddValue(histogramId, value);
}
let snapshot = histogram.snapshot();
Assert.strictEqual(snapshot.counts[ACTION_TYPES.CREATE_SUCCESS], 1,
"SHARING_ROOM_URL.CREATE_SUCCESS");
Assert.strictEqual(snapshot.counts[ACTION_TYPES.CREATE_FAIL], 2,
"SHARING_ROOM_URL.CREATE_FAIL");
});
add_task(function* test_mozLoop_telemetryAdd_roomDelete_buckets() {
let histogramId = "LOOP_ROOM_DELETE";
let histogram = Services.telemetry.getHistogramById(histogramId);
const ACTION_TYPES = gMozLoopAPI.ROOM_DELETE;
histogram.clear();
for (let value of [ACTION_TYPES.DELETE_SUCCESS,
ACTION_TYPES.DELETE_FAIL,
ACTION_TYPES.DELETE_FAIL]) {
gMozLoopAPI.telemetryAddValue(histogramId, value);
}
let snapshot = histogram.snapshot();
Assert.strictEqual(snapshot.counts[ACTION_TYPES.DELETE_SUCCESS], 1,
"SHARING_ROOM_URL.DELETE_SUCCESS");
Assert.strictEqual(snapshot.counts[ACTION_TYPES.DELETE_FAIL], 2,
"SHARING_ROOM_URL.DELETE_FAIL");
});
add_task(function* test_mozLoop_telemetryAdd_roomContextAdd_buckets() {
let histogramId = "LOOP_ROOM_CONTEXT_ADD";
let histogram = Services.telemetry.getHistogramById(histogramId);
const ACTION_TYPES = gMozLoopAPI.ROOM_CONTEXT_ADD;
histogram.clear();
for (let value of [ACTION_TYPES.ADD_FROM_PANEL,
ACTION_TYPES.ADD_FROM_CONVERSATION,
ACTION_TYPES.ADD_FROM_CONVERSATION]) {
gMozLoopAPI.telemetryAddValue(histogramId, value);
}
let snapshot = histogram.snapshot();
Assert.strictEqual(snapshot.counts[ACTION_TYPES.ADD_FROM_PANEL], 1,
"SHARING_ROOM_URL.CREATE_SUCCESS");
Assert.strictEqual(snapshot.counts[ACTION_TYPES.ADD_FROM_CONVERSATION], 2,
"SHARING_ROOM_URL.ADD_FROM_CONVERSATION");
});
add_task(function* test_mozLoop_telemetryAdd_roomContextClick() {
let histogramId = "LOOP_ROOM_CONTEXT_CLICK";
let histogram = Services.telemetry.getHistogramById(histogramId);
histogram.clear();
let snapshot;
for (let i = 1; i < 4; ++i) {
gMozLoopAPI.telemetryAddValue("LOOP_ROOM_CONTEXT_CLICK", 1);
snapshot = histogram.snapshot();
Assert.strictEqual(snapshot.counts[0], i);
}
});

View File

@ -39,6 +39,10 @@ describe("loop.store.ConversationStore", function () {
};
fakeMozLoop = {
ROOM_CREATE: {
CREATE_SUCCESS: 0,
CREATE_FAIL: 1
},
getLoopPref: sandbox.stub(),
addConversationContext: sandbox.stub(),
calls: {
@ -48,7 +52,8 @@ describe("loop.store.ConversationStore", function () {
},
rooms: {
create: sandbox.stub()
}
},
telemetryAddValue: sandbox.stub()
};
dispatcher = new loop.Dispatcher();
@ -1036,6 +1041,8 @@ describe("loop.store.ConversationStore", function () {
}));
expect(store.getStoreState("emailLink")).eql("http://fake.invalid/");
sinon.assert.calledOnce(fakeMozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(fakeMozLoop.telemetryAddValue, "LOOP_ROOM_CREATE", 0);
});
it("should trigger an error:emailLink event in case of failure",
@ -1051,6 +1058,8 @@ describe("loop.store.ConversationStore", function () {
sinon.assert.calledOnce(trigger);
sinon.assert.calledWithExactly(trigger, "error:emailLink");
sinon.assert.calledOnce(fakeMozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(fakeMozLoop.telemetryAddValue, "LOOP_ROOM_CREATE", 1);
});
});

View File

@ -338,7 +338,7 @@ describe("loop.shared.utils", function() {
});
describe("#composeCallUrlEmail", function() {
var composeEmail;
var composeEmail, telemetryAddValue;
beforeEach(function() {
// fake mozL10n
@ -355,9 +355,15 @@ describe("loop.shared.utils", function() {
}
});
composeEmail = sandbox.spy();
telemetryAddValue = sandbox.spy();
navigator.mozLoop = {
SHARING_ROOM_URL: {
EMAIL_FROM_CALLFAILED: 2,
EMAIL_FROM_CONVERSATION: 3
},
getLoopPref: sandbox.spy(),
composeEmail: composeEmail
composeEmail: composeEmail,
telemetryAddValue: telemetryAddValue
};
});
@ -375,6 +381,13 @@ describe("loop.shared.utils", function() {
sinon.assert.calledOnce(composeEmail);
sinon.assert.calledWith(composeEmail, "subject_context", "body_context");
});
it("should record a telemetry event when an email is composed", function() {
sharedUtils.composeCallUrlEmail("http://invalid", null,
"Hello, is me you're looking for?", "callfailed");
sinon.assert.calledOnce(telemetryAddValue, "LOOP_SHARING_ROOM_URL", 2);
});
});
describe("#btoa", function() {

View File

@ -289,6 +289,15 @@ if (typeof Mozilla == 'undefined') {
_sendEvent('toggleReaderMode');
};
Mozilla.UITour.setDefaultBrowser = function() {
_sendEvent('setDefaultBrowser');
}
Mozilla.UITour.isDefaultBrowser = function(callback) {
_sendEvent('isDefaultBrowser', {
callbackID: _waitForCallback(callback),
});
}
})();
// Make this library Require-able.

View File

@ -716,6 +716,22 @@ this.UITour = {
targetPromise.then(target => {
ReaderParent.toggleReaderMode({target: target.node});
});
break;
}
case "setDefaultBrowser": {
let shell = Components.classes["@mozilla.org/browser/shell-service;1"]
.getService(Components.interfaces.nsIShellService);
shell.setDefaultBrowser(true, false);
break;
}
case "isDefaultBrowser": {
let shell = Components.classes["@mozilla.org/browser/shell-service;1"]
.getService(Components.interfaces.nsIShellService);
let isDefault = shell.isDefaultBrowser(false);
this.sendPageCallback(messageManager, data.callbackID, { value: isDefault });
break;
}
}

View File

@ -42,3 +42,5 @@ skip-if = e10s # Bug 1073247 - UITour.jsm not e10s friendly
skip-if = e10s # Bug 1073247 - UITour.jsm not e10s friendly
[browser_UITour_resetProfile.js]
skip-if = e10s # Bug 1073247 - UITour.jsm not e10s friendly
[browser_UITour_defaultBrowser.js]
skip-if = e10s # Bug 1073427 - UITour.jsm not e10s friendly

View File

@ -0,0 +1,68 @@
"use strict";
let gTestTab;
let gContentAPI;
let gContentWindow;
let setDefaultBrowserCalled = false;
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://mochikit/content/tests/SimpleTest/MockObjects.js", this);
function MockShellService() {};
MockShellService.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIShellService]),
isDefaultBrowser: function(aStartupCheck, aForAllTypes) { return false; },
setDefaultBrowser: function(aClaimAllTypes, aForAllUsers) {
setDefaultBrowserCalled = true;
},
shouldCheckDefaultBrowser: false,
canSetDesktopBackground: false,
BACKGROUND_TILE : 1,
BACKGROUND_STRETCH : 2,
BACKGROUND_CENTER : 3,
BACKGROUND_FILL : 4,
BACKGROUND_FIT : 5,
setDesktopBackground: function(aElement, aPosition) {},
APPLICATION_MAIL : 0,
APPLICATION_NEWS : 1,
openApplication: function(aApplication) {},
desktopBackgroundColor: 0,
openApplicationWithURI: function(aApplication, aURI) {},
defaultFeedReader: 0,
};
let mockShellService = new MockObjectRegisterer("@mozilla.org/browser/shell-service;1",
MockShellService);
// Temporarily disabled, see note at test_setDefaultBrowser.
// mockShellService.register();
function test() {
UITourTest();
}
let tests = [
/* This test is disabled (bug 1180714) since the MockObjectRegisterer
is not actually replacing the original ShellService.
taskify(function* test_setDefaultBrowser() {
try {
gContentAPI.setDefaultBrowser();
ok(setDefaultBrowserCalled, "setDefaultBrowser called");
} finally {
mockShellService.unregister();
}
}),
*/
taskify(function* test_isDefaultBrowser(done) {
let shell = Components.classes["@mozilla.org/browser/shell-service;1"]
.getService(Components.interfaces.nsIShellService);
let isDefault = shell.isDefaultBrowser(false);
gContentAPI.isDefaultBrowser(function(data) {
is(data.value, isDefault, "gContentAPI.isDefaultBrowser should match shellService.isDefaultBrowser");
done();
});
})
];

View File

@ -1047,7 +1047,7 @@ InspectorPanel.prototype = {
if (!this.selection.isNode()) {
return;
}
this._copyLongStr(this.walker.innerHTML(this.selection.nodeFront));
this._copyLongString(this.walker.innerHTML(this.selection.nodeFront));
},
/**
@ -1057,8 +1057,21 @@ InspectorPanel.prototype = {
if (!this.selection.isNode()) {
return;
}
let node = this.selection.nodeFront;
this._copyLongStr(this.walker.outerHTML(this.selection.nodeFront));
switch (node.nodeType) {
case Ci.nsIDOMNode.ELEMENT_NODE :
this._copyLongString(this.walker.outerHTML(node));
break;
case Ci.nsIDOMNode.COMMENT_NODE :
this._getLongString(node.getNodeValue()).then(comment => {
clipboardHelper.copyString("<!--" + comment + "-->");
});
break;
case Ci.nsIDOMNode.DOCUMENT_TYPE_NODE :
clipboardHelper.copyString(node.doctypeString);
break;
}
},
/**
@ -1071,13 +1084,29 @@ InspectorPanel.prototype = {
}
},
_copyLongStr: function(promise) {
return promise.then(longstr => {
return longstr.string().then(toCopy => {
longstr.release().then(null, console.error);
clipboardHelper.copyString(toCopy);
/**
* Copy the content of a longString (via a promise resolving a LongStringActor) to the clipboard
* @param {Promise} longStringActorPromise promise expected to resolve a LongStringActor instance
* @return {Promise} promise resolving (with no argument) when the string is sent to the clipboard
*/
_copyLongString: function(longStringActorPromise) {
return this._getLongString(longStringActorPromise).then(string => {
clipboardHelper.copyString(string);
}).catch(Cu.reportError);
},
/**
* Retrieve the content of a longString (via a promise resolving a LongStringActor)
* @param {Promise} longStringActorPromise promise expected to resolve a LongStringActor instance
* @return {Promise} promise resolving with the retrieved string as argument
*/
_getLongString: function(longStringActorPromise) {
return longStringActorPromise.then(longStringActor => {
return longStringActor.string().then(string => {
longStringActor.release().catch(Cu.reportError);
return string;
});
}).then(null, console.error);
}).catch(Cu.reportError);
},
/**

View File

@ -21,6 +21,7 @@ support-files =
doc_inspector_infobar_01.html
doc_inspector_infobar_02.html
doc_inspector_menu.html
doc_inspector_outerhtml.html
doc_inspector_remove-iframe-during-load.html
doc_inspector_search.html
doc_inspector_search-reserved.html
@ -76,6 +77,7 @@ skip-if = e10s # GCLI isn't e10s compatible. See bug 1128988.
[browser_inspector_initialization.js]
[browser_inspector_inspect-object-element.js]
[browser_inspector_invalidate.js]
[browser_inspector_keyboard-shortcuts-copy-outerhtml.js]
[browser_inspector_keyboard-shortcuts.js]
[browser_inspector_menu-01-sensitivity.js]
[browser_inspector_menu-02-copy-items.js]

View File

@ -0,0 +1,58 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test copy outer HTML from the keyboard/copy event
const TEST_URL = TEST_URL_ROOT + "doc_inspector_outerhtml.html";
add_task(function *() {
let { inspector } = yield openInspectorForURL(TEST_URL);
let root = inspector.markup._elt;
info("Test copy outerHTML for COMMENT node");
let comment = getElementByType(inspector, Ci.nsIDOMNode.COMMENT_NODE);
yield setSelectionNodeFront(comment, inspector);
yield checkClipboard("<!-- Comment -->", root);
info("Test copy outerHTML for DOCTYPE node");
let doctype = getElementByType(inspector, Ci.nsIDOMNode.DOCUMENT_TYPE_NODE);
yield setSelectionNodeFront(doctype, inspector);
yield checkClipboard("<!DOCTYPE html>", root);
info("Test copy outerHTML for ELEMENT node");
yield selectAndHighlightNode("div", inspector);
yield checkClipboard("<div><p>Test copy OuterHTML</p></div>", root);
});
function* setSelectionNodeFront(node, inspector) {
let updated = inspector.once("inspector-updated");
inspector.selection.setNodeFront(node);
yield updated;
}
function* checkClipboard(expectedText, node) {
let deferred = promise.defer();
waitForClipboard(
expectedText,
() => fireCopyEvent(node),
deferred.resolve,
deferred.reject
);
try {
yield deferred.promise;
ok(true, "Clipboard successfully filled with : " + expectedText);
} catch (e) {
ok(false, "Clipboard could not be filled with the expected text : " + expectedText);
}
}
function getElementByType(inspector, type) {
for (let [node] of inspector.markup._containers) {
if (node.nodeType === type) {
return node;
}
}
}

View File

@ -0,0 +1,11 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Inspector Copy OuterHTML Test</title>
</head>
<body>
<!-- Comment -->
<div><p>Test copy OuterHTML</p></div>
</body>
</html>

View File

@ -723,6 +723,15 @@ function wait(ms) {
return def.promise;
}
/**
* Dispatch the copy event on the given element
*/
function fireCopyEvent(element) {
let evt = element.ownerDocument.createEvent("Event");
evt.initEvent("copy", true, true);
element.dispatchEvent(evt);
}
/**
* Send an async message to the frame script (chrome -> content) and wait for a
* response message with the same name (content -> chrome).

View File

@ -6,6 +6,10 @@
-moz-control-character-visibility: visible;
}
body {
-moz-user-select: none;
}
/* Force height and width (possibly overflowing) from inline elements.
* This allows long overflows of text or input fields to still be styled with
* the container, rather than the background disappearing when scrolling */
@ -16,7 +20,6 @@
body.dragging .tag-line {
cursor: grabbing;
-moz-user-select: none;
}
#root-wrapper:after {

View File

@ -111,6 +111,9 @@ function MarkupView(aInspector, aFrame, aControllerWindow) {
this._boundKeyDown = this._onKeyDown.bind(this);
this._frame.contentWindow.addEventListener("keydown", this._boundKeyDown, false);
this._onCopy = this._onCopy.bind(this);
this._frame.contentWindow.addEventListener("copy", this._onCopy);
this._boundFocus = this._onFocus.bind(this);
this._frame.addEventListener("focus", this._boundFocus, false);
@ -507,6 +510,20 @@ MarkupView.prototype = {
return walker;
},
_onCopy: function (evt) {
// Ignore copy events from editors
if (this._isInputOrTextarea(evt.target)) {
return;
}
let selection = this._inspector.selection;
if (selection.isNode()) {
this._inspector.copyOuterHTML();
}
evt.stopPropagation();
evt.preventDefault();
},
/**
* Key handling.
*/
@ -514,8 +531,7 @@ MarkupView.prototype = {
let handled = true;
// Ignore keystrokes that originated in editors.
if (aEvent.target.tagName.toLowerCase() === "input" ||
aEvent.target.tagName.toLowerCase() === "textarea") {
if (this._isInputOrTextarea(aEvent.target)) {
return;
}
@ -614,6 +630,14 @@ MarkupView.prototype = {
}
},
/**
* Check if a node is an input or textarea
*/
_isInputOrTextarea : function (element) {
let name = element.tagName.toLowerCase();
return name === "input" || name === "textarea";
},
/**
* Delete a node from the DOM.
* This is an undoable action.
@ -1485,6 +1509,9 @@ MarkupView.prototype = {
this._boundKeyDown, false);
this._boundKeyDown = null;
this._frame.contentWindow.removeEventListener("copy", this._onCopy);
this._onCopy = null;
this._inspector.selection.off("new-node-front", this._boundOnNewSelection);
this._boundOnNewSelection = null;
@ -2314,10 +2341,7 @@ function GenericEditor(aContainer, aNode) {
this.tag.textContent = aNode.isBeforePseudoElement ? "::before" : "::after";
} else if (aNode.nodeType == Ci.nsIDOMNode.DOCUMENT_TYPE_NODE) {
this.elt.classList.add("comment");
this.tag.textContent = '<!DOCTYPE ' + aNode.name +
(aNode.publicId ? ' PUBLIC "' + aNode.publicId + '"': '') +
(aNode.systemId ? ' "' + aNode.systemId + '"' : '') +
'>';
this.tag.textContent = aNode.doctypeString;
} else {
this.tag.textContent = aNode.nodeName;
}

View File

@ -151,6 +151,7 @@ function CssHtmlTree(aStyleInspector, aPageStyle)
this._onClick = this._onClick.bind(this);
this._onCopy = this._onCopy.bind(this);
this._onCopyColor = this._onCopyColor.bind(this);
this._onCopyUrl = this._onCopyUrl.bind(this);
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
this._onFilterStyles = this._onFilterStyles.bind(this);
this._onFilterKeyPress = this._onFilterKeyPress.bind(this);
@ -716,6 +717,13 @@ CssHtmlTree.prototype = {
command: this._onCopyColor
});
// Copy URL
this.menuitemCopyUrl = createMenuItem(this._contextmenu, {
label: "styleinspector.contextmenu.copyUrl",
accesskey: "styleinspector.contextmenu.copyUrl.accessKey",
command: this._onCopyUrl
});
// Copy data URI
this.menuitemCopyImageDataUrl = createMenuItem(this._contextmenu, {
label: "styleinspector.contextmenu.copyImageDataUrl",
@ -753,6 +761,7 @@ CssHtmlTree.prototype = {
this.menuitemSources.setAttribute("checked", showOrig);
this.menuitemCopyColor.hidden = !this._isColorPopup();
this.menuitemCopyUrl.hidden = !this._isImageUrlPopup();
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrlPopup();
},
@ -874,6 +883,13 @@ CssHtmlTree.prototype = {
clipboardHelper.copyString(this._colorToCopy);
},
/**
* Retrieve the url for the selected image and copy it to the clipboard
*/
_onCopyUrl: function() {
clipboardHelper.copyString(this._imageUrlToCopy);
},
/**
* Retrieve the image data for the selected image url and copy it to the clipboard
*/
@ -979,6 +995,10 @@ CssHtmlTree.prototype = {
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
this.menuitemCopyColor = null;
// Destroy Copy URL menuitem
this.menuitemCopyUrl.removeEventListener("command", this._onCopyUrl);
this.menuitemCopyUrl = null;
// Destroy Copy Data URI menuitem.
this.menuitemCopyImageDataUrl.removeEventListener("command", this._onCopyImageDataUrl);
this.menuitemCopyImageDataUrl = null;
@ -1047,7 +1067,9 @@ function createMenuItem(aMenu, aAttributes)
let item = aMenu.ownerDocument.createElementNS(XUL_NS, "menuitem");
item.setAttribute("label", CssHtmlTree.l10n(aAttributes.label));
item.setAttribute("accesskey", CssHtmlTree.l10n(aAttributes.accesskey));
if (aAttributes.accesskey) {
item.setAttribute("accesskey", CssHtmlTree.l10n(aAttributes.accesskey));
}
item.addEventListener("command", aAttributes.command);
if (aAttributes.type) {

View File

@ -1158,6 +1158,7 @@ function CssRuleView(aInspector, aDoc, aStore, aPageStyle) {
this._onSelectAll = this._onSelectAll.bind(this);
this._onCopy = this._onCopy.bind(this);
this._onCopyColor = this._onCopyColor.bind(this);
this._onCopyUrl = this._onCopyUrl.bind(this);
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
this._onCopyLocation = this._onCopyLocation.bind(this);
this._onCopyPropertyDeclaration = this._onCopyPropertyDeclaration.bind(this);
@ -1274,6 +1275,12 @@ CssRuleView.prototype = {
command: this._onCopyColor
});
this.menuitemCopyUrl = createMenuItem(this._contextmenu, {
label: "styleinspector.contextmenu.copyUrl",
accesskey: "styleinspector.contextmenu.copyUrl.accessKey",
command: this._onCopyUrl
});
this.menuitemCopyImageDataUrl = createMenuItem(this._contextmenu, {
label: "styleinspector.contextmenu.copyImageDataUrl",
accesskey: "styleinspector.contextmenu.copyImageDataUrl.accessKey",
@ -1469,6 +1476,7 @@ CssRuleView.prototype = {
this.menuitemCopy.hidden = !copy;
this.menuitemCopyColor.hidden = !this._isColorPopup();
this.menuitemCopyUrl.hidden = !this._isImageUrlPopup();
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrlPopup();
this.menuitemCopyLocation.hidden = true;
@ -1713,9 +1721,16 @@ CssRuleView.prototype = {
clipboardHelper.copyString(this._colorToCopy);
},
/**
* Retrieve the url for the selected image and copy it to the clipboard
*/
_onCopyUrl: function() {
clipboardHelper.copyString(this._imageUrlToCopy);
},
/**
* Retrieve the image data for the selected image url and copy it to
* the clipboard
* the clipboard
*/
_onCopyImageDataUrl: Task.async(function*() {
let message;
@ -2012,6 +2027,11 @@ CssRuleView.prototype = {
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
this.menuitemCopyColor = null;
// Destroy Copy URL menuitem.
this.menuitemCopyUrl.removeEventListener("command",
this._onCopyUrl);
this.menuitemCopyUrl = null;
// Destroy Copy Data URI menuitem.
this.menuitemCopyImageDataUrl.removeEventListener("command",
this._onCopyImageDataUrl);

View File

@ -161,7 +161,7 @@ skip-if = e10s # bug 1040670 Cannot open inline styles in viewSourceUtils
[browser_ruleview_user-property-reset.js]
[browser_styleinspector_context-menu-copy-color_01.js]
[browser_styleinspector_context-menu-copy-color_02.js]
[browser_styleinspector_context-menu-copy-data-uri.js]
[browser_styleinspector_context-menu-copy-urls.js]
[browser_styleinspector_csslogic-content-stylesheets.js]
[browser_styleinspector_output-parser.js]
[browser_styleinspector_refresh_when_active.js]

View File

@ -1,6 +1,10 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/* Tests both Copy URL and Copy Data URL context menu items */
const PROPERTIES_URL = "chrome://global/locale/devtools/styleinspector.properties";
const TEST_DATA_URI = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=";
@ -36,20 +40,24 @@ function* startTest() {
let ruleViewData = yield openRuleView();
info("Test valid background image URL in rule view");
yield testCopyImageDataUrlToClipboard(ruleViewData, ".valid-background", TEST_DATA_URI);
yield testCopyUrlToClipboard(ruleViewData, "data-uri", ".valid-background", TEST_DATA_URI);
yield testCopyUrlToClipboard(ruleViewData, "url", ".valid-background", TEST_DATA_URI);
info("Test invalid background image URL in rue view");
yield testCopyImageDataUrlToClipboard(ruleViewData, ".invalid-background", ERROR_MESSAGE);
yield testCopyUrlToClipboard(ruleViewData, "data-uri", ".invalid-background", ERROR_MESSAGE);
yield testCopyUrlToClipboard(ruleViewData, "url", ".invalid-background", PROPERTIES_URL);
info("Opening computed view");
let computedViewData = yield openComputedView();
info("Test valid background image URL in computed view");
yield testCopyImageDataUrlToClipboard(computedViewData, ".valid-background", TEST_DATA_URI);
yield testCopyUrlToClipboard(computedViewData, "data-uri", ".valid-background", TEST_DATA_URI);
yield testCopyUrlToClipboard(computedViewData, "url", ".valid-background", TEST_DATA_URI);
info("Test invalid background image URL in computed view");
yield testCopyImageDataUrlToClipboard(computedViewData, ".invalid-background", ERROR_MESSAGE);
yield testCopyUrlToClipboard(computedViewData, "data-uri", ".invalid-background", ERROR_MESSAGE);
yield testCopyUrlToClipboard(computedViewData, "url", ".invalid-background", PROPERTIES_URL);
}
function* testCopyImageDataUrlToClipboard({view, inspector}, selector, expected) {
function* testCopyUrlToClipboard({view, inspector}, type, selector, expected) {
info("Select node in inspector panel");
yield selectNode(selector, inspector);
@ -74,8 +82,13 @@ function* testCopyImageDataUrlToClipboard({view, inspector}, selector, expected)
info("Context menu is displayed");
ok(!view.menuitemCopyImageDataUrl.hidden, "\"Copy Image Data-URL\" menu entry is displayed");
info("Click Copy Data URI and wait for clipboard");
yield waitForClipboard(() => view.menuitemCopyImageDataUrl.click(), expected);
if (type == "data-uri") {
info("Click Copy Data URI and wait for clipboard");
yield waitForClipboard(() => view.menuitemCopyImageDataUrl.click(), expected);
} else {
info("Click Copy URL and wait for clipboard");
yield waitForClipboard(() => view.menuitemCopyUrl.click(), expected);
}
info("Hide context menu");
view._contextmenu.hidePopup();

View File

@ -7,4 +7,4 @@
<!ENTITY aboutAccountsConfig.description "Sign in to sync your tabs, bookmarks, passwords &amp; more.">
<!ENTITY aboutAccountsConfig.startButton.label "Get started">
<!ENTITY aboutAccountsConfig.useOldSync.label "Using an older version of Sync?">
<!ENTITY aboutAccountsConfig.manage.label "Manage">
<!ENTITY aboutAccountsConfig.syncPreferences.label "Sync preferences">

View File

@ -6,6 +6,7 @@ profileName_format=%S %S
# Browser Specific
sourceNameIE=Internet Explorer
sourceNameEdge=Microsoft Edge
sourceNameSafari=Safari
sourceNameChrome=Google Chrome
sourceNameFirefox=Mozilla Firefox
@ -19,40 +20,47 @@ importedSafariReadingList=Reading List (From Safari)
# Note: When adding an import source for profile reset, add the string name to
# resetProfile.js if it should be listed in the reset dialog.
1_ie=Internet Options
1_edge=Settings
1_safari=Preferences
1_chrome=Preferences
1_360se=Preferences
2_ie=Cookies
2_edge=Cookies
2_safari=Cookies
2_chrome=Cookies
2_firefox=Cookies
2_360se=Cookies
4_ie=Browsing History
4_edge=Browsing History
4_safari=Browsing History
4_chrome=Browsing History
4_firefox_history_and_bookmarks=Browsing History and Bookmarks
4_360se=Browsing History
8_ie=Saved Form History
8_edge=Saved Form History
8_safari=Saved Form History
8_chrome=Saved Form History
8_firefox=Saved Form History
8_360se=Saved Form History
16_ie=Saved Passwords
16_edge=Saved Passwords
16_safari=Saved Passwords
16_chrome=Saved Passwords
16_firefox=Saved Passwords
16_360se=Saved Passwords
32_ie=Favorites
32_edge=Favorites
32_safari=Bookmarks
32_chrome=Bookmarks
32_360se=Bookmarks
64_ie=Other Data
64_edge=Other Data
64_safari=Other Data
64_chrome=Other Data
64_firefox_other=Other Data

View File

@ -3,3 +3,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../../shared/controlcenter/panel.inc.css
.identity-popup-expander:-moz-focusring,
#identity-popup-more-info-button {
padding: 1px;
}
.identity-popup-expander:-moz-focusring > .button-box,
#identity-popup-more-info-button:-moz-focusring > .button-box {
outline: 1px -moz-dialogtext dotted;
}

View File

@ -2,8 +2,19 @@
* 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/. */
%include ../shared.inc
%include ../../shared/controlcenter/panel.inc.css
#identity-popup {
margin-top: 1px;
}
.identity-popup-expander:-moz-focusring,
#identity-popup-more-info-button {
padding: 2px;
}
.identity-popup-expander:-moz-focusring > .button-box,
#identity-popup-more-info-button:-moz-focusring > .button-box {
@hudButtonFocused@
}

View File

@ -21,6 +21,11 @@
max-height: 0;
}
.panel-mainview[panelid=identity-popup][viewtype=subview] > #identity-popup-mainView menulist,
.panel-mainview[panelid=identity-popup][viewtype=subview] > #identity-popup-mainView button:not([panel-multiview-anchor]) {
-moz-user-focus: ignore;
}
#identity-popup > .panel-arrowcontainer > .panel-arrowcontent {
padding: 0;
}
@ -133,16 +138,15 @@
}
}
.identity-popup-expander > .button-box,
.identity-popup-expander > .button-box:focus {
.identity-popup-expander > .button-box {
padding: 0;
-moz-appearance: none;
border: solid #e5e5e5;
border-width: 0 0 0 1px;
}
.identity-popup-expander[panel-multiview-anchor] > .button-box,
.identity-popup-expander[panel-multiview-anchor] > .button-box:focus {
.identity-popup-expander:-moz-focusring > .button-box,
.identity-popup-expander[panel-multiview-anchor] > .button-box {
border: 0 none;
}
@ -283,10 +287,14 @@
background: transparent;
-moz-appearance: none;
margin-top: 5px;
padding: 1.1em;
margin: 0;
}
#identity-popup-more-info-button > .button-box {
-moz-appearance: none;
padding: 1em;
}
#identity-popup-more-info-button:hover {
background-color: hsla(210,4%,10%,.07);
}
@ -296,3 +304,7 @@
background-color: hsla(210,4%,10%,.12);
box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
}
#identity-popup-more-info-button:-moz-focusring {
border-color: transparent;
}

View File

@ -18,6 +18,9 @@
%define conditionalForwardWithUrlbarWidth 30
:root {
--toolbarbutton-vertical-inner-padding: 2px;
--toolbarbutton-vertical-outer-padding: 8px;
--toolbarbutton-hover-background: hsla(210,4%,10%,.08);
--toolbarbutton-hover-bordercolor: hsla(210,4%,10%,.1);
--toolbarbutton-hover-boxshadow: none;
@ -633,7 +636,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
#nav-bar .toolbarbutton-1:not([type=menu-button]),
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button,
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
padding: 8px 2px;
padding: var(--toolbarbutton-vertical-outer-padding) 2px;
-moz-box-pack: center;
}
@ -672,7 +675,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
@conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
padding: 2px 6px;
padding: var(--toolbarbutton-vertical-inner-padding) 6px;
border: 1px solid;
border-color: transparent;
transition-property: background-color, border-color;
@ -740,7 +743,7 @@ toolbarbutton[cui-areatype="toolbar"] > :-moz-any(@nestedButtons@) > .toolbarbut
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container,
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
padding: 3px 7px;
padding: calc(var(--toolbarbutton-vertical-inner-padding) + 1px) 7px;
}
/* Help SDK icons fit: */
@ -1246,6 +1249,12 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
font-size: 1.15em;
min-height: 28px;
}
:root {
/* let toolbar buttons match the location and search bar's minimum height */
--toolbarbutton-vertical-inner-padding: 4px;
--toolbarbutton-vertical-outer-padding: 5px;
}
}
#urlbar:-moz-lwtheme,
@ -1873,8 +1882,8 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
}
#bookmarks-menu-button[cui-areatype="toolbar"]:not(.bookmark-item):not([overflowedItem=true]) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
padding-top: 2px;
padding-bottom: 2px;
padding-top: var(--toolbarbutton-vertical-inner-padding);
padding-bottom: var(--toolbarbutton-vertical-inner-padding);
}
#BMB_bookmarksPopup[side="top"],

View File

@ -3,3 +3,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../../shared/controlcenter/panel.inc.css
.identity-popup-expander:-moz-focusring,
#identity-popup-more-info-button {
padding: 1px;
}
.identity-popup-expander:-moz-focusring > .button-box,
#identity-popup-more-info-button:-moz-focusring > .button-box {
outline: 1px -moz-dialogtext dotted;
}

View File

@ -52,6 +52,7 @@ var tests = [
// Preferences
function() {
SpecialPowers.pushPrefEnv({"set": [["dom.ipc.browser_frames.oop_by_default", true],
["media.useAudioChannelAPI", true],
["media.useAudioChannelService", true],
["media.defaultAudioChannel", "telephony"],
["dom.mozBrowserFramesEnabled", true],

View File

@ -13,7 +13,6 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Likely.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/SegmentedVector.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/FragmentOrElement.h"
@ -1227,12 +1226,24 @@ FragmentOrElement::FireNodeInserted(nsIDocument* aDoc,
//----------------------------------------------------------------------
class ContentUnbinder
{
static const size_t kSegmentSize = sizeof(void*) * 512;
typedef SegmentedVector<nsCOMPtr<nsIContent>, kSegmentSize, InfallibleAllocPolicy> ContentArray;
// nsISupports implementation
static void UnbindSubtree(nsIContent* aNode)
#define SUBTREE_UNBINDINGS_PER_RUNNABLE 500
class ContentUnbinder : public nsRunnable
{
public:
ContentUnbinder()
{
mLast = this;
}
~ContentUnbinder()
{
Run();
}
void UnbindSubtree(nsIContent* aNode)
{
if (aNode->NodeType() != nsIDOMNode::ELEMENT_NODE &&
aNode->NodeType() != nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
@ -1258,56 +1269,73 @@ class ContentUnbinder
}
}
// These two methods are based on DeferredFinalizerImpl.
static void*
AppendContentUnbinderPointer(void* aData, void* aObject)
NS_IMETHOD Run()
{
ContentArray* contentArray = static_cast<ContentArray*>(aData);
if (!contentArray) {
contentArray = new ContentArray();
}
contentArray->InfallibleAppend(dont_AddRef(static_cast<nsIContent*>(aObject)));
return contentArray;
}
static bool
DeferredFinalize(uint32_t aSliceBudget, void* aData)
{
MOZ_ASSERT(aSliceBudget > 0, "nonsensical/useless call with aSliceBudget == 0");
nsAutoScriptBlocker scriptBlocker;
ContentArray* contentArray = static_cast<ContentArray*>(aData);
size_t numToRemove = contentArray->Length();
if (aSliceBudget < numToRemove) {
numToRemove = aSliceBudget;
uint32_t len = mSubtreeRoots.Length();
if (len) {
for (uint32_t i = 0; i < len; ++i) {
UnbindSubtree(mSubtreeRoots[i]);
}
mSubtreeRoots.Clear();
}
for (size_t i = 0; i < numToRemove; ++i) {
nsCOMPtr<nsIContent> element = contentArray->GetLast().forget();
contentArray->PopLast();
UnbindSubtree(element);
}
nsCycleCollector_dispatchDeferredDeletion();
if (contentArray->Length() == 0) {
delete contentArray;
return true;
if (this == sContentUnbinder) {
sContentUnbinder = nullptr;
if (mNext) {
nsRefPtr<ContentUnbinder> next;
next.swap(mNext);
sContentUnbinder = next;
next->mLast = mLast;
mLast = nullptr;
NS_DispatchToMainThread(next);
}
}
return false;
return NS_OK;
}
public:
static void
Append(nsIContent* aSubtreeRoot)
static void UnbindAll()
{
nsCOMPtr<nsIContent> root = aSubtreeRoot;
mozilla::DeferredFinalize(AppendContentUnbinderPointer, DeferredFinalize, root.forget().take());
nsRefPtr<ContentUnbinder> ub = sContentUnbinder;
sContentUnbinder = nullptr;
while (ub) {
ub->Run();
ub = ub->mNext;
}
}
static void Append(nsIContent* aSubtreeRoot)
{
if (!sContentUnbinder) {
sContentUnbinder = new ContentUnbinder();
nsCOMPtr<nsIRunnable> e = sContentUnbinder;
NS_DispatchToMainThread(e);
}
if (sContentUnbinder->mLast->mSubtreeRoots.Length() >=
SUBTREE_UNBINDINGS_PER_RUNNABLE) {
sContentUnbinder->mLast->mNext = new ContentUnbinder();
sContentUnbinder->mLast = sContentUnbinder->mLast->mNext;
}
sContentUnbinder->mLast->mSubtreeRoots.AppendElement(aSubtreeRoot);
}
private:
nsAutoTArray<nsCOMPtr<nsIContent>,
SUBTREE_UNBINDINGS_PER_RUNNABLE> mSubtreeRoots;
nsRefPtr<ContentUnbinder> mNext;
ContentUnbinder* mLast;
static ContentUnbinder* sContentUnbinder;
};
ContentUnbinder* ContentUnbinder::sContentUnbinder = nullptr;
void
FragmentOrElement::ClearContentUnbinder()
{
ContentUnbinder::UnbindAll();
}
NS_IMPL_CYCLE_COLLECTION_CLASS(FragmentOrElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)

View File

@ -65,7 +65,7 @@ public:
private:
~nsNodeWeakReference();
nsINode* mNode;
nsINode* MOZ_NON_OWNING_REF mNode;
};
/**
@ -215,6 +215,7 @@ public:
mRefCnt.RemovePurple();
}
static void ClearContentUnbinder();
static bool CanSkip(nsINode* aNode, bool aRemovingAllowed);
static bool CanSkipInCC(nsINode* aNode);
static bool CanSkipThis(nsINode* aNode);

View File

@ -318,6 +318,8 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
if (!strcmp(aTopic, "xpcom-shutdown")) {
Element::ClearContentUnbinder();
nsCOMPtr<nsIObserverService> obs =
mozilla::services::GetObserverService();
if (!obs)
@ -342,6 +344,9 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
!strcmp(aTopic, "cycle-collector-forget-skippable");
bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
if (prepareForCC) {
Element::ClearContentUnbinder();
}
// Increase generation to effectively unmark all current objects
if (!++sGeneration) {

View File

@ -62,7 +62,7 @@ struct CharacterDataChangeInfo
* mChangeStart + mReplaceLength.
*/
struct Details {
struct MOZ_STACK_CLASS Details {
enum {
eMerge, // two text nodes are merged as a result of normalize()
eSplit // a text node is split as a result of splitText()
@ -71,7 +71,7 @@ struct CharacterDataChangeInfo
* For eMerge it's the text node that will be removed, for eSplit it's the
* new text node.
*/
nsIContent* mNextSibling;
nsIContent* MOZ_NON_OWNING_REF mNextSibling;
};
/**

View File

@ -778,7 +778,10 @@ protected:
// These members are only used on outer windows.
nsCOMPtr<mozilla::dom::Element> mFrameElement;
nsIDocShell *mDocShell; // Weak Reference
// This reference is used by the subclass nsGlobalWindow, and cleared in it's
// DetachFromDocShell() method. This method is called by nsDocShell::Destroy(),
// which is called before the nsDocShell is destroyed.
nsIDocShell* MOZ_NON_OWNING_REF mDocShell; // Weak Reference
// mPerformance is only used on inner windows.
nsRefPtr<nsPerformance> mPerformance;

View File

@ -46,15 +46,6 @@ namespace mozilla {
namespace dom {
template<typename DataType> class MozMap;
struct SelfRef
{
SelfRef() : ptr(nullptr) {}
explicit SelfRef(nsISupports *p) : ptr(p) {}
~SelfRef() { NS_IF_RELEASE(ptr); }
nsISupports* ptr;
};
nsresult
UnwrapArgImpl(JS::Handle<JSObject*> src, const nsIID& iid, void** ppArg);

View File

@ -455,6 +455,9 @@ void
EventStateManager::OnStartToObserveContent(
IMEContentObserver* aIMEContentObserver)
{
if (mIMEContentObserver == aIMEContentObserver) {
return;
}
ReleaseCurrentIMEContentObserver();
mIMEContentObserver = aIMEContentObserver;
}

View File

@ -1076,6 +1076,11 @@ static bool UseAudioChannelService()
return Preferences::GetBool("media.useAudioChannelService");
}
static bool UseAudioChannelAPI()
{
return Preferences::GetBool("media.useAudioChannelAPI");
}
void HTMLMediaElement::UpdatePreloadAction()
{
PreloadAction nextAction = PRELOAD_UNDEFINED;
@ -4445,11 +4450,15 @@ nsresult HTMLMediaElement::UpdateChannelMuteState(AudioChannelState aCanPlay)
// We have to mute this channel.
if (aCanPlay == AUDIO_CHANNEL_STATE_MUTED && !(mMuted & MUTED_BY_AUDIO_CHANNEL)) {
SetMutedInternal(mMuted | MUTED_BY_AUDIO_CHANNEL);
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptbegin"));
if (UseAudioChannelAPI()) {
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptbegin"));
}
} else if (aCanPlay != AUDIO_CHANNEL_STATE_MUTED &&
(mMuted & MUTED_BY_AUDIO_CHANNEL)) {
SetMutedInternal(mMuted & ~MUTED_BY_AUDIO_CHANNEL);
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptend"));
if (UseAudioChannelAPI()) {
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptend"));
}
}
SuspendOrResumeElement(mMuted & MUTED_BY_AUDIO_CHANNEL, false);

View File

@ -263,7 +263,7 @@ this.Keyboard = {
break;
case 'Keyboard:Register':
this._keyboardMM = mm;
if (kbID !== null) {
if (kbID) {
// keyboard identifies itself, use its kbID
// this msg would be async, so no need to return
this._keyboardID = kbID;

View File

@ -19,12 +19,34 @@ XPCOMUtils.defineLazyServiceGetter(this, "tm",
"@mozilla.org/thread-manager;1", "nsIThreadManager");
/*
* A WeakMap to map input method iframe window to its active status and kbID.
* A WeakMap to map input method iframe window to
* it's active status, kbID, and ipcHelper.
*/
let WindowMap = {
// WeakMap of <window, object> pairs.
_map: null,
/*
* Set the object associated to the window and return it.
*/
_getObjForWin: function(win) {
if (!this._map) {
this._map = new WeakMap();
}
if (this._map.has(win)) {
return this._map.get(win);
} else {
let obj = {
active: false,
kbID: undefined,
ipcHelper: null
};
this._map.set(win, obj);
return obj;
}
},
/*
* Check if the given window is active.
*/
@ -33,12 +55,7 @@ let WindowMap = {
return false;
}
let obj = this._map.get(win);
if (obj && 'active' in obj) {
return obj.active;
}else{
return false;
}
return this._getObjForWin(win).active;
},
/*
@ -48,45 +65,59 @@ let WindowMap = {
if (!win) {
return;
}
if (!this._map) {
this._map = new WeakMap();
}
if (!this._map.has(win)) {
this._map.set(win, {});
}
this._map.get(win).active = isActive;
let obj = this._getObjForWin(win);
obj.active = isActive;
},
/*
* Get the keyboard ID (assigned by Keyboard.ksm) of the given window.
* Get the keyboard ID (assigned by Keyboard.jsm) of the given window.
*/
getKbID: function(win) {
if (!this._map || !win) {
return null;
return undefined;
}
let obj = this._map.get(win);
if (obj && 'kbID' in obj) {
return obj.kbID;
}else{
return null;
}
let obj = this._getObjForWin(win);
return obj.kbID;
},
/*
* Set the keyboard ID (assigned by Keyboard.ksm) of the given window.
* Set the keyboard ID (assigned by Keyboard.jsm) of the given window.
*/
setKbID: function(win, kbID) {
if (!win) {
return;
}
if (!this._map) {
this._map = new WeakMap();
let obj = this._getObjForWin(win);
obj.kbID = kbID;
},
/*
* Get InputContextDOMRequestIpcHelper instance attached to this window.
*/
getInputContextIpcHelper: function(win) {
if (!win) {
return;
}
if (!this._map.has(win)) {
this._map.set(win, {});
let obj = this._getObjForWin(win);
if (!obj.ipcHelper) {
obj.ipcHelper = new InputContextDOMRequestIpcHelper(win);
}
this._map.get(win).kbID = kbID;
return obj.ipcHelper;
},
/*
* Unset InputContextDOMRequestIpcHelper instance.
*/
unsetInputContextIpcHelper: function(win) {
if (!win) {
return;
}
let obj = this._getObjForWin(win);
if (!obj.ipcHelper) {
return;
}
obj.ipcHelper = null;
}
};
@ -332,9 +363,9 @@ MozInputMethod.prototype = {
// Note: if we need to get it from Keyboard.jsm,
// we have to use a synchronous message
var kbID = WindowMap.getKbID(this._window);
if (kbID !== null) {
if (kbID) {
cpmmSendAsyncMessageWithKbID(this, 'Keyboard:Register', {});
}else{
} else {
let res = cpmm.sendSyncMessage('Keyboard:Register', {});
WindowMap.setKbID(this._window, res[0]);
}
@ -415,6 +446,61 @@ MozInputMethod.prototype = {
}
};
/**
* ==============================================
* InputContextDOMRequestIpcHelper
* ==============================================
*/
function InputContextDOMRequestIpcHelper(win) {
this.initDOMRequestHelper(win,
["Keyboard:GetText:Result:OK",
"Keyboard:GetText:Result:Error",
"Keyboard:SetSelectionRange:Result:OK",
"Keyboard:ReplaceSurroundingText:Result:OK",
"Keyboard:SendKey:Result:OK",
"Keyboard:SendKey:Result:Error",
"Keyboard:SetComposition:Result:OK",
"Keyboard:EndComposition:Result:OK",
"Keyboard:SequenceError"]);
}
InputContextDOMRequestIpcHelper.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
_inputContext: null,
attachInputContext: function(inputCtx) {
if (this._inputContext) {
throw new Error("InputContextDOMRequestIpcHelper: detach the context first.");
}
this._inputContext = inputCtx;
},
// Unset ourselves when the window is destroyed.
uninit: function() {
WindowMap.unsetInputContextIpcHelper(this._window);
},
detachInputContext: function() {
// All requests that are still pending need to be invalidated
// because the context is no longer valid.
this.forEachPromiseResolver(k => {
this.takePromiseResolver(k).reject("InputContext got destroyed");
});
this._inputContext = null;
},
receiveMessage: function(msg) {
if (!this._inputContext) {
dump('InputContextDOMRequestIpcHelper received message without context attached.\n');
return;
}
this._inputContext.receiveMessage(msg);
}
};
/**
* ==============================================
* InputContext
@ -438,11 +524,10 @@ function MozInputContext(ctx) {
}
MozInputContext.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
_window: null,
_context: null,
_contextId: -1,
_ipcHelper: null,
classID: Components.ID("{1e38633d-d08b-4867-9944-afa5c648adb6}"),
@ -453,30 +538,12 @@ MozInputContext.prototype = {
init: function ic_init(win) {
this._window = win;
this._utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
this.initDOMRequestHelper(win,
["Keyboard:GetText:Result:OK",
"Keyboard:GetText:Result:Error",
"Keyboard:SetSelectionRange:Result:OK",
"Keyboard:ReplaceSurroundingText:Result:OK",
"Keyboard:SendKey:Result:OK",
"Keyboard:SendKey:Result:Error",
"Keyboard:SetComposition:Result:OK",
"Keyboard:EndComposition:Result:OK",
"Keyboard:SequenceError"]);
this._ipcHelper = WindowMap.getInputContextIpcHelper(win);
this._ipcHelper.attachInputContext(this);
},
destroy: function ic_destroy() {
let self = this;
// All requests that are still pending need to be invalidated
// because the context is no longer valid.
this.forEachPromiseResolver(function(k) {
self.takePromiseResolver(k).reject("InputContext got destroyed");
});
this.destroyDOMRequestHelper();
// A consuming application might still hold a cached version of
// this object. After destroying all methods will throw because we
// cannot create new promises anymore, but we still hold
@ -487,6 +554,9 @@ MozInputContext.prototype = {
}
}
this._ipcHelper.detachInputContext();
this._ipcHelper = null;
this._window = null;
},
@ -497,9 +567,10 @@ MozInputContext.prototype = {
}
let json = msg.json;
let resolver = this.takePromiseResolver(json.requestId);
let resolver = this._ipcHelper.takePromiseResolver(json.requestId);
if (!resolver) {
dump('InputContext received invalid requestId.\n');
return;
}
@ -715,10 +786,10 @@ MozInputContext.prototype = {
_sendPromise: function(callback) {
let self = this;
return this.createPromise(function(resolve, reject) {
let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
return this._ipcHelper.createPromise(function(resolve, reject) {
let resolverId = self._ipcHelper.getPromiseResolverId({ resolve: resolve, reject: reject });
if (!WindowMap.isActive(self._window)) {
self.removePromiseResolver(resolverId);
self._ipcHelper.removePromiseResolver(resolverId);
reject('Input method is not active.');
return;
}

View File

@ -671,7 +671,8 @@ let FormAssistant = {
target = target.parentNode;
this.setFocusedElement(target);
this.isHandlingFocus = this.sendInputState(target);
this.sendInputState(target);
this.isHandlingFocus = true;
},
unhandleFocus: function fa_unhandleFocus() {
@ -690,7 +691,8 @@ let FormAssistant = {
return true;
return (element instanceof HTMLInputElement &&
!this.ignoredInputTypes.has(element.type));
!this.ignoredInputTypes.has(element.type) &&
!element.readOnly);
},
getTopLevelEditable: function fa_getTopLevelEditable(element) {
@ -705,15 +707,7 @@ let FormAssistant = {
},
sendInputState: function(element) {
// FIXME/bug 729623: work around apparent bug in the IME manager
// in gecko.
let readonly = element.getAttribute("readonly");
if (readonly) {
return false;
}
sendAsyncMessage("Forms:Input", getJSON(element, this._focusCounter));
return true;
},
getSelectionInfo: function fa_getSelectionInfo() {

View File

@ -20,6 +20,7 @@ support-files =
[test_bug1043828.html]
[test_bug1059163.html]
[test_bug1066515.html]
[test_bug1175399.html]
[test_sendkey_cancel.html]
[test_sync_edit.html]
[test_two_inputs.html]

View File

@ -32,7 +32,7 @@ function kbFrameScript() {
}, function(e){
sendAsyncMessage('test:InputMethod:getText:Reject');
});
}else{
} else {
dump("Could not get inputcontext") ;
}
}
@ -103,7 +103,7 @@ function runTest() {
mmKeyboardB.loadFrameScript('data:,(' + kbFrameScript.toString() + ')();', false);
mmKeyboardB.addMessageListener('test:InputMethod:getText:Resolve', function() {
ok(true, 'getText() was resolved');
info('getText() was resolved');
inputmethod_cleanup();
});
@ -124,6 +124,7 @@ function runTest() {
// STEP 2: Set keyboard A active
function step2() {
info('step2');
let req = keyboardA.setInputMethodActive(true);
req.onsuccess = function(){
@ -140,6 +141,7 @@ function runTest() {
// STEP 3: Set keyboard B active
function step3() {
info('step3');
let req = keyboardB.setInputMethodActive(true);
req.onsuccess = function(){
@ -156,6 +158,7 @@ function runTest() {
// STEP 4: Set keyboard A inactive
function step4() {
info('step4');
let req = keyboardA.setInputMethodActive(false);
req.onsuccess = function(){
@ -172,6 +175,7 @@ function runTest() {
// STEP 5: getText
function step5() {
info('step5');
mmKeyboardB.sendAsyncMessage('test:InputMethod:getText:Do');
}

View File

@ -0,0 +1,62 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1175399
-->
<head>
<title>Test focus when page unloads</title>
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1175399">Mozilla Bug 1175399</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
inputmethod_setup(function() {
runTest();
});
let appFrameScript = function appFrameScript() {
let input = content.document.body.firstElementChild;
input.focus();
content.setTimeout(function() {
sendAsyncMessage('test:step');
});
};
function runTest() {
let im = navigator.mozInputMethod;
// Set current page as an input method.
SpecialPowers.wrap(im).setActive(true);
let iframe = document.createElement('iframe');
iframe.src = 'data:text/html,<html><body><input value="First" readonly></body></html>';
iframe.setAttribute('mozbrowser', true);
document.body.appendChild(iframe);
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
im.oninputcontextchange = function() {
is(false, 'should not receive inputcontextchange event');
};
iframe.addEventListener('mozbrowserloadend', function() {
mm.addMessageListener('test:step', function() {
let inputcontext = navigator.mozInputMethod.inputcontext;
is(inputcontext, null, 'inputcontext is null');
inputmethod_cleanup();
});
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
});
}
</script>
</pre>
</body>
</html>

View File

@ -161,17 +161,6 @@ EnsureMinCDMVersion(mozIGeckoMediaPluginService* aGMPService,
return MediaKeySystemStatus::Cdm_not_installed;
}
if (aMinCdmVersion == NO_CDM_VERSION) {
return MediaKeySystemStatus::Available;
}
nsresult rv;
int32_t version = versionStr.ToInteger(&rv);
if (NS_FAILED(rv) || version < 0 || aMinCdmVersion > version) {
aOutMessage = NS_LITERAL_CSTRING("Installed CDM version insufficient");
return MediaKeySystemStatus::Cdm_insufficient_version;
}
#ifdef XP_WIN
if (aKeySystem.EqualsLiteral("com.adobe.access") ||
aKeySystem.EqualsLiteral("com.adobe.primetime")) {
@ -197,6 +186,14 @@ EnsureMinCDMVersion(mozIGeckoMediaPluginService* aGMPService,
}
#endif
nsresult rv;
int32_t version = versionStr.ToInteger(&rv);
if (aMinCdmVersion != NO_CDM_VERSION &&
(NS_FAILED(rv) || version < 0 || aMinCdmVersion > version)) {
aOutMessage = NS_LITERAL_CSTRING("Installed CDM version insufficient");
return MediaKeySystemStatus::Cdm_insufficient_version;
}
return MediaKeySystemStatus::Available;
}

View File

@ -183,7 +183,7 @@ GMPParent::LoadProcess()
mState = GMPStateLoaded;
// Hold a self ref while the child process is alive. This ensures that
// during shutdown the GMPParent stays we stay alive long enough to
// during shutdown the GMPParent stays alive long enough to
// terminate the child process.
MOZ_ASSERT(!mHoldingSelfRef);
mHoldingSelfRef = true;
@ -212,6 +212,7 @@ AbortWaitingForGMPAsyncShutdown(nsITimer* aTimer, void* aClosure)
nsresult
GMPParent::EnsureAsyncShutdownTimeoutSet()
{
MOZ_ASSERT(mAsyncShutdownRequired);
if (mAsyncShutdownTimeout) {
return NS_OK;
}
@ -235,9 +236,11 @@ GMPParent::EnsureAsyncShutdownTimeoutSet()
if (service) {
timeout = service->AsyncShutdownTimeoutMs();
}
return mAsyncShutdownTimeout->InitWithFuncCallback(
rv = mAsyncShutdownTimeout->InitWithFuncCallback(
&AbortWaitingForGMPAsyncShutdown, this, timeout,
nsITimer::TYPE_ONE_SHOT);
unused << NS_WARN_IF(NS_FAILED(rv));
return rv;
}
bool
@ -286,17 +289,25 @@ GMPParent::CloseIfUnused()
NS_LITERAL_CSTRING("Sent BeginAsyncShutdown"));
#endif
mAsyncShutdownInProgress = true;
if (!SendBeginAsyncShutdown() ||
NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
if (!SendBeginAsyncShutdown()) {
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AnnotateCrashReport(
nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
NS_LITERAL_CSTRING("Could not send BeginAsyncShutdown - Aborting"));
NS_LITERAL_CSTRING("Could not send BeginAsyncShutdown - Aborting async shutdown"));
#endif
AbortAsyncShutdown();
} else if (NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AnnotateCrashReport(
nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
NS_LITERAL_CSTRING("Could not start timer after sending BeginAsyncShutdown - Aborting async shutdown"));
#endif
AbortAsyncShutdown();
}
}
} else {
// No async-shutdown, kill async-shutdown timer started in CloseActive().
AbortAsyncShutdown();
// Any async shutdown must be complete. Shutdown GMPStorage.
for (size_t i = mStorage.Length(); i > 0; i--) {
mStorage[i - 1]->Shutdown();
@ -346,7 +357,38 @@ GMPParent::CloseActive(bool aDieWhenUnloaded)
nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
nsPrintfCString("Sent CloseActive, content children to close: %u", mGMPContentChildCount));
#endif
unused << SendCloseActive();
if (!SendCloseActive()) {
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AnnotateCrashReport(
nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
NS_LITERAL_CSTRING("Could not send CloseActive - Aborting async shutdown"));
#endif
AbortAsyncShutdown();
} else if (IsUsed()) {
// We're expecting RecvPGMPContentChildDestroyed's -> Start async-shutdown timer now if needed.
if (mAsyncShutdownRequired && NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AnnotateCrashReport(
nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
NS_LITERAL_CSTRING("Could not start timer after sending CloseActive - Aborting async shutdown"));
#endif
AbortAsyncShutdown();
}
} else {
// We're not expecting any RecvPGMPContentChildDestroyed
// -> Call CloseIfUnused() now, to run async shutdown if necessary.
// Note that CloseIfUnused() may have already been called from a prior
// RecvPGMPContentChildDestroyed(), however depending on the state at
// that time, it might not have proceeded with shutdown; And calling it
// again after shutdown is fine because after the first one we'll be in
// GMPStateNotLoaded.
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AnnotateCrashReport(
nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
NS_LITERAL_CSTRING("Content children already destroyed"));
#endif
CloseIfUnused();
}
}
}

View File

@ -35,6 +35,7 @@
#include "PeriodicWave.h"
#include "ConvolverNode.h"
#include "OscillatorNode.h"
#include "blink/PeriodicWave.h"
#include "nsNetUtil.h"
#include "AudioStream.h"
#include "mozilla/dom/Promise.h"
@ -1050,5 +1051,48 @@ AudioContext::ExtraCurrentTime() const
return mDestination->ExtraCurrentTime();
}
BasicWaveFormCache*
AudioContext::GetBasicWaveFormCache()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mBasicWaveFormCache) {
mBasicWaveFormCache = new BasicWaveFormCache(SampleRate());
}
return mBasicWaveFormCache;
}
BasicWaveFormCache::BasicWaveFormCache(uint32_t aSampleRate)
: mSampleRate(aSampleRate)
{
MOZ_ASSERT(NS_IsMainThread());
}
BasicWaveFormCache::~BasicWaveFormCache()
{ }
WebCore::PeriodicWave*
BasicWaveFormCache::GetBasicWaveForm(OscillatorType aType)
{
MOZ_ASSERT(!NS_IsMainThread());
if (aType == OscillatorType::Sawtooth) {
if (!mSawtooth) {
mSawtooth = WebCore::PeriodicWave::createSawtooth(mSampleRate);
}
return mSawtooth;
} else if (aType == OscillatorType::Square) {
if (!mSquare) {
mSquare = WebCore::PeriodicWave::createSquare(mSampleRate);
}
return mSquare;
} else if (aType == OscillatorType::Triangle) {
if (!mTriangle) {
mTriangle = WebCore::PeriodicWave::createTriangle(mSampleRate);
}
return mTriangle;
} else {
MOZ_ASSERT(false, "Not reached");
return nullptr;
}
}
}
}

View File

@ -27,6 +27,10 @@
#undef CurrentTime
#endif
namespace WebCore {
class PeriodicWave;
};
class nsPIDOMWindow;
namespace mozilla {
@ -65,6 +69,25 @@ class StereoPannerNode;
class WaveShaperNode;
class PeriodicWave;
class Promise;
enum class OscillatorType : uint32_t;
// This is addrefed by the OscillatorNodeEngine on the main thread
// and then used from the MSG thread.
// It can be released either from the graph thread or the main thread.
class BasicWaveFormCache
{
public:
explicit BasicWaveFormCache(uint32_t aSampleRate);
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BasicWaveFormCache)
WebCore::PeriodicWave* GetBasicWaveForm(OscillatorType aType);
private:
~BasicWaveFormCache();
nsRefPtr<WebCore::PeriodicWave> mSawtooth;
nsRefPtr<WebCore::PeriodicWave> mSquare;
nsRefPtr<WebCore::PeriodicWave> mTriangle;
uint32_t mSampleRate;
};
/* This runnable allows the MSG to notify the main thread when audio is actually
* flowing */
@ -294,6 +317,8 @@ public:
void OnStateChanged(void* aPromise, AudioContextState aNewState);
BasicWaveFormCache* GetBasicWaveFormCache();
IMPL_EVENT_HANDLER(mozinterruptbegin)
IMPL_EVENT_HANDLER(mozinterruptend)
@ -339,6 +364,8 @@ private:
// Hashsets containing all the PannerNodes, to compute the doppler shift.
// These are weak pointers.
nsTHashtable<nsPtrHashKey<PannerNode> > mPannerNodes;
// Cache to avoid recomputing basic waveforms all the time.
nsRefPtr<BasicWaveFormCache> mBasicWaveFormCache;
// Number of channels passed in the OfflineAudioContext ctor.
uint32_t mNumberOfChannels;
// Number of nodes that currently exist for this AudioContext

View File

@ -293,6 +293,11 @@ static bool UseAudioChannelService()
return Preferences::GetBool("media.useAudioChannelService");
}
static bool UseAudioChannelAPI()
{
return Preferences::GetBool("media.useAudioChannelAPI");
}
class EventProxyHandler final : public nsIDOMEventListener
{
public:
@ -543,9 +548,11 @@ AudioDestinationNode::CanPlayChanged(int32_t aCanPlay)
mAudioChannelAgentPlaying = playing;
SetCanPlay(playing);
Context()->DispatchTrustedEvent(
playing ? NS_LITERAL_STRING("mozinterruptend")
: NS_LITERAL_STRING("mozinterruptbegin"));
if (UseAudioChannelAPI()) {
Context()->DispatchTrustedEvent(
playing ? NS_LITERAL_STRING("mozinterruptend")
: NS_LITERAL_STRING("mozinterruptbegin"));
}
return NS_OK;
}

View File

@ -40,6 +40,8 @@ public:
, mRecomputeParameters(true)
, mCustomLength(0)
{
MOZ_ASSERT(NS_IsMainThread());
mBasicWaveFormCache = aDestination->Context()->GetBasicWaveFormCache();
}
void SetSourceStream(AudioNodeStream* aSource)
@ -104,13 +106,9 @@ public:
mPhase = 0.0;
break;
case OscillatorType::Square:
mPeriodicWave = WebCore::PeriodicWave::createSquare(mSource->SampleRate());
break;
case OscillatorType::Triangle:
mPeriodicWave = WebCore::PeriodicWave::createTriangle(mSource->SampleRate());
break;
case OscillatorType::Sawtooth:
mPeriodicWave = WebCore::PeriodicWave::createSawtooth(mSource->SampleRate());
mPeriodicWave = mBasicWaveFormCache->GetBasicWaveForm(mType);
break;
case OscillatorType::Custom:
break;
@ -371,8 +369,9 @@ public:
float mPhaseIncrement;
bool mRecomputeParameters;
nsRefPtr<ThreadSharedFloatArrayBufferList> mCustom;
nsRefPtr<BasicWaveFormCache> mBasicWaveFormCache;
uint32_t mCustomLength;
nsAutoPtr<WebCore::PeriodicWave> mPeriodicWave;
nsRefPtr<WebCore::PeriodicWave> mPeriodicWave;
};
OscillatorNode::OscillatorNode(AudioContext* aContext)

View File

@ -12,7 +12,6 @@
#include "mozilla/Attributes.h"
#include "AudioContext.h"
#include "AudioNodeEngine.h"
#include "nsAutoPtr.h"
namespace mozilla {

View File

@ -40,48 +40,58 @@ using mozilla::dom::OscillatorType;
namespace WebCore {
PeriodicWave* PeriodicWave::create(float sampleRate,
const float* real,
const float* imag,
size_t numberOfComponents)
already_AddRefed<PeriodicWave>
PeriodicWave::create(float sampleRate,
const float* real,
const float* imag,
size_t numberOfComponents)
{
bool isGood = real && imag && numberOfComponents > 0 &&
numberOfComponents <= PeriodicWaveSize;
MOZ_ASSERT(isGood);
if (isGood) {
PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
nsRefPtr<PeriodicWave> periodicWave =
new PeriodicWave(sampleRate);
periodicWave->createBandLimitedTables(real, imag, numberOfComponents);
return periodicWave;
return periodicWave.forget();
}
return 0;
return nullptr;
}
PeriodicWave* PeriodicWave::createSine(float sampleRate)
already_AddRefed<PeriodicWave>
PeriodicWave::createSine(float sampleRate)
{
PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Sine);
return periodicWave;
nsRefPtr<PeriodicWave> periodicWave =
new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Sine);
return periodicWave.forget();
}
PeriodicWave* PeriodicWave::createSquare(float sampleRate)
already_AddRefed<PeriodicWave>
PeriodicWave::createSquare(float sampleRate)
{
PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Square);
return periodicWave;
nsRefPtr<PeriodicWave> periodicWave =
new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Square);
return periodicWave.forget();
}
PeriodicWave* PeriodicWave::createSawtooth(float sampleRate)
already_AddRefed<PeriodicWave>
PeriodicWave::createSawtooth(float sampleRate)
{
PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Sawtooth);
return periodicWave;
nsRefPtr<PeriodicWave> periodicWave =
new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Sawtooth);
return periodicWave.forget();
}
PeriodicWave* PeriodicWave::createTriangle(float sampleRate)
already_AddRefed<PeriodicWave>
PeriodicWave::createTriangle(float sampleRate)
{
PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Triangle);
return periodicWave;
nsRefPtr<PeriodicWave> periodicWave =
new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Triangle);
return periodicWave.forget();
}
PeriodicWave::PeriodicWave(float sampleRate)

View File

@ -42,17 +42,19 @@ typedef nsTArray<float> AudioFloatArray;
class PeriodicWave {
public:
static PeriodicWave* createSine(float sampleRate);
static PeriodicWave* createSquare(float sampleRate);
static PeriodicWave* createSawtooth(float sampleRate);
static PeriodicWave* createTriangle(float sampleRate);
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebCore::PeriodicWave);
static already_AddRefed<PeriodicWave> createSine(float sampleRate);
static already_AddRefed<PeriodicWave> createSquare(float sampleRate);
static already_AddRefed<PeriodicWave> createSawtooth(float sampleRate);
static already_AddRefed<PeriodicWave> createTriangle(float sampleRate);
// Creates an arbitrary periodic wave given the frequency components
// (Fourier coefficients).
static PeriodicWave* create(float sampleRate,
const float* real,
const float* imag,
size_t numberOfComponents);
static already_AddRefed<PeriodicWave> create(float sampleRate,
const float* real,
const float* imag,
size_t numberOfComponents);
// Returns pointers to the lower and higher wave data for the pitch range
// containing the given fundamental frequency. These two tables are in
@ -75,6 +77,7 @@ public:
private:
explicit PeriodicWave(float sampleRate);
~PeriodicWave() {}
void generateBasicWaveform(mozilla::dom::OscillatorType);

View File

@ -35,6 +35,7 @@ function test() {
"dom/media/webaudio/test/browser_mozAudioChannel.html";
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", "content" ],
["media.useAudioChannelAPI", true ],
["media.useAudioChannelService", true ]]},
function() {
let tab1 = gBrowser.addTab(testURL);

View File

@ -35,6 +35,7 @@ function test() {
"dom/media/webaudio/test/browser_mozAudioChannel_muted.html";
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", "content" ],
["media.useAudioChannelAPI", true ],
["media.useAudioChannelService", true ]]},
function() {
let tab1 = gBrowser.addTab(testURL);

View File

@ -141,7 +141,8 @@ function runTest() {
test();
}
SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelService", true ]]}, runTest);
SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelAPI", true ],
["media.useAudioChannelService", true ]]}, runTest);
SimpleTest.waitForExplicitFinish();
SimpleTest.requestLongerTimeout(5);

View File

@ -2853,8 +2853,7 @@ PluginInstanceChild::CreateOptSurface(void)
#endif
#ifdef XP_WIN
if (mSurfaceType == gfxSurfaceType::Win32 ||
mSurfaceType == gfxSurfaceType::D2D) {
if (mSurfaceType == gfxSurfaceType::Win32) {
bool willHaveTransparentPixels = mIsTransparent && !mBackground;
SharedDIBSurface* s = new SharedDIBSurface();

View File

@ -50,8 +50,9 @@ class Promise;
#if defined(DOM_PROMISE_DEPRECATED_REPORTING)
class PromiseReportRejectFeature : public workers::WorkerFeature
{
// The Promise that owns this feature.
Promise* mPromise;
// PromiseReportRejectFeature is held by an nsAutoPtr on the Promise which
// means that this object will be destroyed before the Promise is destroyed.
Promise* MOZ_NON_OWNING_REF mPromise;
public:
explicit PromiseReportRejectFeature(Promise* aPromise)

View File

@ -95,16 +95,16 @@ interface AudioContext : EventTarget {
// Mozilla extensions
partial interface AudioContext {
// Read AudioChannel.webidl for more information about this attribute.
[Pref="media.useAudioChannelService"]
[Pref="media.useAudioChannelAPI"]
readonly attribute AudioChannel mozAudioChannelType;
// These 2 events are dispatched when the AudioContext object is muted by
// the AudioChannelService. It's call 'interrupt' because when this event is
// dispatched on a HTMLMediaElement, the audio stream is paused.
[Pref="media.useAudioChannelService"]
[Pref="media.useAudioChannelAPI"]
attribute EventHandler onmozinterruptbegin;
[Pref="media.useAudioChannelService"]
[Pref="media.useAudioChannelAPI"]
attribute EventHandler onmozinterruptend;
// This method is for test only.

View File

@ -3544,12 +3544,38 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
AssertIsOnMainThread();
JSAutoStructuredCloneBuffer buffer(Move(aBuffer));
const JSStructuredCloneCallbacks* callbacks =
WorkerStructuredCloneCallbacks(true);
class MOZ_STACK_CLASS AutoCloneBufferCleaner final
{
public:
AutoCloneBufferCleaner(JSAutoStructuredCloneBuffer& aBuffer,
const JSStructuredCloneCallbacks* aCallbacks,
WorkerStructuredCloneClosure& aClosure)
: mBuffer(aBuffer)
, mCallbacks(aCallbacks)
, mClosure(aClosure)
{}
~AutoCloneBufferCleaner()
{
mBuffer.clear(mCallbacks, &mClosure);
}
private:
JSAutoStructuredCloneBuffer& mBuffer;
const JSStructuredCloneCallbacks* mCallbacks;
WorkerStructuredCloneClosure& mClosure;
};
WorkerStructuredCloneClosure closure;
closure.mClonedObjects.SwapElements(aClosure.mClonedObjects);
MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty());
closure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers);
AutoCloneBufferCleaner bufferCleaner(buffer, callbacks, closure);
SharedWorker* sharedWorker;
if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) {
// SharedWorker has already been unregistered?
@ -3577,8 +3603,6 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
return false;
}
buffer.clear();
nsRefPtr<MessageEvent> event = new MessageEvent(port, nullptr, nullptr);
nsresult rv =
event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false, data,

View File

@ -659,9 +659,6 @@ DrawTargetCairo::GetType() const
case CAIRO_SURFACE_TYPE_RECORDING:
case CAIRO_SURFACE_TYPE_DRM:
case CAIRO_SURFACE_TYPE_SUBSURFACE:
#ifdef CAIRO_HAS_D2D_SURFACE
case CAIRO_SURFACE_TYPE_D2D:
#endif
case CAIRO_SURFACE_TYPE_TEE: // included to silence warning about unhandled enum value
return DrawTargetType::SOFTWARE_RASTER;
default:

View File

@ -50,7 +50,12 @@ DrawTargetD2D1::~DrawTargetD2D1()
// mSnapshot will be cleared now.
}
mDC->EndDraw();
if (mDC) {
// The only way mDC can be null is if Init failed, but it can happen and the
// destructor is the only place where we need to check for it since the
// DrawTarget will destroyed right after Init fails.
mDC->EndDraw();
}
// Targets depending on us can break that dependency, since we're obviously not going to
// be modified in the future.

View File

@ -32,7 +32,6 @@
#endif
#ifdef XP_WIN
#include "gfxD2DSurface.h"
#include "gfxWindowsPlatform.h"
#include <d3d10_1.h>
#include "D3D9SurfaceImage.h"

View File

@ -45,7 +45,9 @@ window.onload = function() {
// The B2G emulator is hella slow, and needs more than 300ms to run the
// main-thread code that deals with layerizing subframes and running
// touch listeners. In my local runs this needs to be at least 1000.
["apz.content_response_timeout", "5000"]
// On try this sometimes needs to be as long as 8 seconds (bug 1176798)
// so we make it 15 seconds just to be extra safe.
["apz.content_response_timeout", "15000"]
]
}, testDone);
};

View File

@ -74,7 +74,7 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
#ifdef XP_WIN
if (backend == LayersBackend::LAYERS_D3D11) {
useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
} else
#endif
#ifdef MOZ_WIDGET_GTK

View File

@ -344,7 +344,7 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
if (parentBackend == LayersBackend::LAYERS_D3D11 &&
(aMoz2DBackend == gfx::BackendType::DIRECT2D ||
aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
gfxWindowsPlatform::GetPlatform()->GetD3D10Device() &&
aSize.width <= maxTextureSize &&
aSize.height <= maxTextureSize) {
texture = new TextureClientD3D11(aAllocator, aFormat, aTextureFlags);
@ -355,7 +355,7 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
aSize.width <= maxTextureSize &&
aSize.height <= maxTextureSize) {
if (gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
texture = new CairoTextureClientD3D9(aAllocator, aFormat, aTextureFlags);
texture = new TextureClientD3D9(aAllocator, aFormat, aTextureFlags);
}
}

View File

@ -502,7 +502,7 @@ protected:
* deserialized.
* Calling ToSurfaceDescriptor again after it has already returned true,
* or never constructing a TextureHost with aDescriptor may result in a memory
* leak (see CairoTextureClientD3D9 for example).
* leak (see TextureClientD3D9 for example).
*/
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) = 0;

View File

@ -9,7 +9,6 @@
#include "Effects.h"
#include "mozilla/layers/YCbCrImageDataSerializer.h"
#include "gfxWindowsPlatform.h"
#include "gfxD2DSurface.h"
#include "gfx2DGlue.h"
#include "gfxPrefs.h"
#include "ReadbackManagerD3D11.h"

View File

@ -161,7 +161,7 @@ CompositingRenderTargetD3D9::GetSize() const
}
/**
* Helper method for DataToTexture and SurfaceToTexture.
* Helper method for DataToTexture.
* The last three params are out params.
* Returns the created texture, or null if we fail.
*/
@ -203,7 +203,7 @@ TextureSourceD3D9::InitTextures(DeviceManagerD3D9* aDeviceManager,
}
/**
* Helper method for DataToTexture and SurfaceToTexture.
* Helper method for DataToTexture.
*/
static void
FinishTextures(DeviceManagerD3D9* aDeviceManager,
@ -274,47 +274,6 @@ TextureSourceD3D9::TextureToTexture(DeviceManagerD3D9* aDeviceManager,
return texture.forget();
}
already_AddRefed<IDirect3DTexture9>
TextureSourceD3D9::SurfaceToTexture(DeviceManagerD3D9* aDeviceManager,
gfxWindowsSurface* aSurface,
const IntSize& aSize,
_D3DFORMAT aFormat)
{
RefPtr<IDirect3DSurface9> surface;
D3DLOCKED_RECT lockedRect;
RefPtr<IDirect3DTexture9> texture = InitTextures(aDeviceManager, aSize, aFormat,
surface, lockedRect);
if (!texture) {
return nullptr;
}
{
RefPtr<DrawTarget> dt =
Factory::CreateDrawTargetForData(BackendType::CAIRO,
reinterpret_cast<unsigned char*>(lockedRect.pBits),
aSize, lockedRect.Pitch,
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aSurface->GetContentType()));
if (dt) {
NativeSurface nativeSurf;
nativeSurf.mSize = aSize;
nativeSurf.mType = NativeSurfaceType::CAIRO_SURFACE;
// We don't know that this is actually the right format, but it's the best
// we can get for the content type. In practice this probably always works.
nativeSurf.mFormat = dt->GetFormat();
nativeSurf.mSurface = aSurface->CairoSurface();
RefPtr<SourceSurface> surf = dt->CreateSourceSurfaceFromNativeSurface(nativeSurf);
dt->CopySurface(surf, IntRect(IntPoint(), aSize), IntPoint());
}
}
FinishTextures(aDeviceManager, texture, surface);
return texture.forget();
}
DataTextureSourceD3D9::DataTextureSourceD3D9(gfx::SurfaceFormat aFormat,
CompositorD3D9* aCompositor,
TextureFlags aFlags,
@ -440,81 +399,6 @@ DataTextureSourceD3D9::Update(gfx::DataSourceSurface* aSurface,
return true;
}
bool
DataTextureSourceD3D9::Update(gfxWindowsSurface* aSurface)
{
MOZ_ASSERT(aSurface);
if (!mCompositor || !mCompositor->device()) {
NS_WARNING("No D3D device to update the texture.");
return false;
}
mSize = aSurface->GetSize();
uint32_t bpp = 0;
_D3DFORMAT format = D3DFMT_A8R8G8B8;
mFormat = ImageFormatToSurfaceFormat(
gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType()));
switch (mFormat) {
case SurfaceFormat::B8G8R8X8:
format = D3DFMT_X8R8G8B8;
bpp = 4;
break;
case SurfaceFormat::B8G8R8A8:
format = D3DFMT_A8R8G8B8;
bpp = 4;
break;
case SurfaceFormat::A8:
format = D3DFMT_A8;
bpp = 1;
break;
default:
NS_WARNING("Bad image format");
return false;
}
int32_t maxSize = mCompositor->GetMaxTextureSize();
DeviceManagerD3D9* deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
if ((mSize.width <= maxSize && mSize.height <= maxSize) ||
(mFlags & TextureFlags::DISALLOW_BIGIMAGE)) {
mTexture = SurfaceToTexture(deviceManager, aSurface, mSize, format);
if (!mTexture) {
NS_WARNING("Could not upload texture");
Reset();
return false;
}
mIsTiled = false;
} else {
mIsTiled = true;
uint32_t tileCount = GetRequiredTilesD3D9(mSize.width, maxSize) *
GetRequiredTilesD3D9(mSize.height, maxSize);
mTileTextures.resize(tileCount);
mTexture = nullptr;
nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
for (uint32_t i = 0; i < tileCount; i++) {
IntRect tileRect = GetTileRect(i);
unsigned char* data = imgSurface->Data() +
tileRect.y * imgSurface->Stride() +
tileRect.x * bpp;
mTileTextures[i] = DataToTexture(deviceManager,
data,
imgSurface->Stride(),
IntSize(tileRect.width, tileRect.height),
format,
bpp);
if (!mTileTextures[i]) {
NS_WARNING("Could not upload texture");
Reset();
return false;
}
}
}
return true;
}
void
DataTextureSourceD3D9::SetCompositor(Compositor* aCompositor)
{
@ -558,9 +442,9 @@ DataTextureSourceD3D9::GetTileRect()
return GetTileRect(mCurrentTile);
}
CairoTextureClientD3D9::CairoTextureClientD3D9(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags)
TextureClientD3D9::TextureClientD3D9(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags)
: TextureClient(aAllocator, aFlags)
, mFormat(aFormat)
, mIsLocked(false)
@ -568,19 +452,19 @@ CairoTextureClientD3D9::CairoTextureClientD3D9(ISurfaceAllocator* aAllocator,
, mNeedsClearWhite(false)
, mLockRect(false)
{
MOZ_COUNT_CTOR(CairoTextureClientD3D9);
MOZ_COUNT_CTOR(TextureClientD3D9);
}
CairoTextureClientD3D9::~CairoTextureClientD3D9()
TextureClientD3D9::~TextureClientD3D9()
{
MOZ_COUNT_DTOR(CairoTextureClientD3D9);
MOZ_COUNT_DTOR(TextureClientD3D9);
}
already_AddRefed<TextureClient>
CairoTextureClientD3D9::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const
TextureClientD3D9::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const
{
RefPtr<TextureClient> tex = new CairoTextureClientD3D9(mAllocator, mFormat,
mFlags | aFlags);
RefPtr<TextureClient> tex = new TextureClientD3D9(mAllocator, mFormat,
mFlags | aFlags);
if (!tex->AllocateForSurface(mSize, aAllocFlags)) {
return nullptr;
@ -590,7 +474,7 @@ CairoTextureClientD3D9::CreateSimilar(TextureFlags aFlags, TextureAllocationFlag
}
bool
CairoTextureClientD3D9::Lock(OpenMode aMode)
TextureClientD3D9::Lock(OpenMode aMode)
{
MOZ_ASSERT(!mIsLocked);
if (!IsValid() || !IsAllocated()) {
@ -647,7 +531,7 @@ CairoTextureClientD3D9::Lock(OpenMode aMode)
}
void
CairoTextureClientD3D9::Unlock()
TextureClientD3D9::Unlock()
{
MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!");
if (!mIsLocked) {
@ -664,14 +548,11 @@ CairoTextureClientD3D9::Unlock()
mLockRect = false;
}
if (mSurface) {
mSurface = nullptr;
}
mIsLocked = false;
}
bool
CairoTextureClientD3D9::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
TextureClientD3D9::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
{
MOZ_ASSERT(IsValid());
if (!IsAllocated()) {
@ -684,7 +565,7 @@ CairoTextureClientD3D9::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
}
gfx::DrawTarget*
CairoTextureClientD3D9::BorrowDrawTarget()
TextureClientD3D9::BorrowDrawTarget()
{
MOZ_ASSERT(mIsLocked && mD3D9Surface);
if (!mIsLocked || !mD3D9Surface) {
@ -697,12 +578,13 @@ CairoTextureClientD3D9::BorrowDrawTarget()
}
if (ContentForFormat(mFormat) == gfxContentType::COLOR) {
mSurface = new gfxWindowsSurface(mD3D9Surface);
if (!mSurface || mSurface->CairoStatus()) {
nsRefPtr<gfxASurface> surface = new gfxWindowsSurface(mD3D9Surface);
if (!surface || surface->CairoStatus()) {
NS_WARNING("Could not create surface for d3d9 surface");
mSurface = nullptr;
return nullptr;
}
mDrawTarget =
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surface, mSize);
} else {
// gfxWindowsSurface don't support transparency so we can't use the d3d9
// windows surface optimization.
@ -713,19 +595,17 @@ CairoTextureClientD3D9::BorrowDrawTarget()
gfxCriticalError() << "Failed to lock rect borrowing the target in D3D9 " << hexa(hr);
return nullptr;
}
mSurface = new gfxImageSurface((uint8_t*)rect.pBits, mSize,
rect.Pitch, SurfaceFormatToImageFormat(mFormat));
mDrawTarget =
gfxPlatform::GetPlatform()->CreateDrawTargetForData((uint8_t*)rect.pBits, mSize,
rect.Pitch, mFormat);
mLockRect = true;
}
mDrawTarget =
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mSurface, mSize);
return mDrawTarget;
}
bool
CairoTextureClientD3D9::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
TextureClientD3D9::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
{
MOZ_ASSERT(!IsAllocated());
mSize = aSize;
@ -827,7 +707,7 @@ TextureHostD3D9::TextureHostD3D9(TextureFlags aFlags,
{
mTexture = reinterpret_cast<IDirect3DTexture9*>(aDescriptor.texture());
MOZ_ASSERT(mTexture);
mTexture->Release(); // see AddRef in CairoTextureClientD3D9::ToSurfaceDescriptor
mTexture->Release(); // see AddRef in TextureClientD3D9::ToSurfaceDescriptor
MOZ_ASSERT(mTexture);
D3DSURFACE_DESC desc;
HRESULT hr = mTexture->GetLevelDesc(0, &desc);

View File

@ -76,12 +76,6 @@ protected:
const gfx::IntSize& aSize,
_D3DFORMAT aFormat);
already_AddRefed<IDirect3DTexture9> SurfaceToTexture(
DeviceManagerD3D9* aDeviceManager,
gfxWindowsSurface* aSurface,
const gfx::IntSize& aSize,
_D3DFORMAT aFormat);
gfx::IntSize mSize;
// Linked list of all objects holding d3d9 textures.
@ -162,10 +156,6 @@ public:
*/
bool UpdateFromTexture(IDirect3DTexture9* aTexture, const nsIntRegion* aRegion);
// To use with DIBTextureHostD3D9
bool Update(gfxWindowsSurface* aSurface);
protected:
gfx::IntRect GetTileRect(uint32_t aTileIndex) const;
@ -181,16 +171,16 @@ protected:
};
/**
* Can only be drawn into through Cairo and need a D3D9 context on the client side.
* Needs a D3D9 context on the client side.
* The corresponding TextureHost is TextureHostD3D9.
*/
class CairoTextureClientD3D9 : public TextureClient
class TextureClientD3D9 : public TextureClient
{
public:
CairoTextureClientD3D9(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
TextureClientD3D9(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
TextureFlags aFlags);
virtual ~CairoTextureClientD3D9();
virtual ~TextureClientD3D9();
// TextureClient
@ -225,7 +215,6 @@ private:
RefPtr<IDirect3DTexture9> mTexture;
nsRefPtr<IDirect3DSurface9> mD3D9Surface;
RefPtr<gfx::DrawTarget> mDrawTarget;
nsRefPtr<gfxASurface> mSurface;
gfx::IntSize mSize;
gfx::SurfaceFormat mFormat;
bool mIsLocked;

View File

@ -27,9 +27,6 @@
#ifdef CAIRO_HAS_WIN32_SURFACE
#include "gfxWindowsSurface.h"
#endif
#ifdef CAIRO_HAS_D2D_SURFACE
#include "gfxD2DSurface.h"
#endif
#ifdef MOZ_X11
#include "gfxXlibSurface.h"
@ -179,11 +176,6 @@ gfxASurface::Wrap (cairo_surface_t *csurf, const IntSize& aSize)
result = new gfxWindowsSurface(csurf);
}
#endif
#ifdef CAIRO_HAS_D2D_SURFACE
else if (stype == CAIRO_SURFACE_TYPE_D2D) {
result = new gfxD2DSurface(csurf);
}
#endif
#ifdef MOZ_X11
else if (stype == CAIRO_SURFACE_TYPE_XLIB) {
result = new gfxXlibSurface(csurf);
@ -568,15 +560,10 @@ static const SurfaceMemoryReporterAttrs sSurfaceMemoryReporterAttrs[] = {
{"gfx-surface-xml", nullptr},
{"gfx-surface-skia", nullptr},
{"gfx-surface-subsurface", nullptr},
{"gfx-surface-d2d", nullptr},
};
PR_STATIC_ASSERT(MOZ_ARRAY_LENGTH(sSurfaceMemoryReporterAttrs) ==
size_t(gfxSurfaceType::Max));
#ifdef CAIRO_HAS_D2D_SURFACE
PR_STATIC_ASSERT(uint32_t(CAIRO_SURFACE_TYPE_D2D) ==
uint32_t(gfxSurfaceType::D2D));
#endif
PR_STATIC_ASSERT(uint32_t(CAIRO_SURFACE_TYPE_SKIA) ==
uint32_t(gfxSurfaceType::Skia));

View File

@ -434,6 +434,11 @@ CreateBoxShadow(DrawTarget& aDT, SourceSurface* aBlurMask, const gfxRGBA& aShado
gfxPlatform* platform = gfxPlatform::GetPlatform();
RefPtr<DrawTarget> boxShadowDT =
platform->CreateOffscreenContentDrawTarget(blurredSize, SurfaceFormat::B8G8R8A8);
if (!boxShadowDT) {
return nullptr;
}
MOZ_ASSERT(boxShadowDT->GetType() == aDT.GetType());
ColorPattern shadowColor(ToDeviceColor(aShadowColor));
@ -475,6 +480,10 @@ GetBlur(DrawTarget& aDT,
}
RefPtr<SourceSurface> boxShadow = CreateBoxShadow(aDT, blurMask, aShadowColor);
if (!boxShadow) {
return nullptr;
}
CacheBlur(aDT, minSize, aBlurRadius, aCornerRadii, aShadowColor, aExtendDestBy, boxShadow);
return boxShadow;
}

View File

@ -1,101 +0,0 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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/. */
#include "gfxD2DSurface.h"
#include "cairo.h"
#include "cairo-win32.h"
#include "gfxWindowsPlatform.h"
gfxD2DSurface::gfxD2DSurface(HWND aWnd, gfxContentType aContent)
{
Init(cairo_d2d_surface_create_for_hwnd(
gfxWindowsPlatform::GetPlatform()->GetD2DDevice(),
aWnd,
(cairo_content_t)(int)aContent));
}
gfxD2DSurface::gfxD2DSurface(HANDLE handle, gfxContentType aContent)
{
Init(cairo_d2d_surface_create_for_handle(
gfxWindowsPlatform::GetPlatform()->GetD2DDevice(),
handle,
(cairo_content_t)(int)aContent));
}
gfxD2DSurface::gfxD2DSurface(ID3D10Texture2D *texture, gfxContentType aContent)
{
Init(cairo_d2d_surface_create_for_texture(
gfxWindowsPlatform::GetPlatform()->GetD2DDevice(),
texture,
(cairo_content_t)(int)aContent));
}
gfxD2DSurface::gfxD2DSurface(cairo_surface_t *csurf)
{
Init(csurf, true);
}
gfxD2DSurface::gfxD2DSurface(const mozilla::gfx::IntSize& size,
gfxImageFormat imageFormat)
{
Init(cairo_d2d_surface_create(
gfxWindowsPlatform::GetPlatform()->GetD2DDevice(),
(cairo_format_t)(int)imageFormat,
size.width, size.height));
}
gfxD2DSurface::~gfxD2DSurface()
{
}
void
gfxD2DSurface::Present()
{
cairo_d2d_present_backbuffer(CairoSurface());
}
void
gfxD2DSurface::Scroll(const nsIntPoint &aDelta, const mozilla::gfx::IntRect &aClip)
{
cairo_rectangle_t rect;
rect.x = aClip.x;
rect.y = aClip.y;
rect.width = aClip.width;
rect.height = aClip.height;
cairo_d2d_scroll(CairoSurface(), aDelta.x, aDelta.y, &rect);
}
ID3D10Texture2D*
gfxD2DSurface::GetTexture()
{
return cairo_d2d_surface_get_texture(CairoSurface());
}
HDC
gfxD2DSurface::GetDC(bool aRetainContents)
{
return cairo_d2d_get_dc(CairoSurface(), aRetainContents);
}
void
gfxD2DSurface::ReleaseDC(const mozilla::gfx::IntRect *aUpdatedRect)
{
if (!aUpdatedRect) {
return cairo_d2d_release_dc(CairoSurface(), nullptr);
}
cairo_rectangle_int_t rect;
rect.x = aUpdatedRect->x;
rect.y = aUpdatedRect->y;
rect.width = aUpdatedRect->width;
rect.height = aUpdatedRect->height;
cairo_d2d_release_dc(CairoSurface(), &rect);
}
const mozilla::gfx::IntSize gfxD2DSurface::GetSize() const
{
return mozilla::gfx::IntSize(cairo_d2d_surface_get_width(mSurface),
cairo_d2d_surface_get_height(mSurface));
}

View File

@ -1,44 +0,0 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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/. */
#ifndef GFX_D2DSURFACE_H
#define GFX_D2DSURFACE_H
#include "gfxASurface.h"
#include "nsPoint.h"
#include <windows.h>
struct ID3D10Texture2D;
class gfxD2DSurface : public gfxASurface {
public:
gfxD2DSurface(HWND wnd,
gfxContentType aContent);
gfxD2DSurface(const mozilla::gfx::IntSize& size,
gfxImageFormat imageFormat = gfxImageFormat::RGB24);
gfxD2DSurface(HANDLE handle, gfxContentType aContent);
gfxD2DSurface(ID3D10Texture2D *texture, gfxContentType aContent);
gfxD2DSurface(cairo_surface_t *csurf);
virtual ~gfxD2DSurface();
void Present();
void Scroll(const nsIntPoint &aDelta, const mozilla::gfx::IntRect &aClip);
virtual const mozilla::gfx::IntSize GetSize() const;
ID3D10Texture2D *GetTexture();
HDC GetDC(bool aRetainContents);
void ReleaseDC(const mozilla::gfx::IntRect *aUpdatedRect);
};
#endif /* GFX_D2DSURFACE_H */

View File

@ -31,7 +31,6 @@
#if defined(XP_WIN)
#include "gfxWindowsPlatform.h"
#include "gfxD2DSurface.h"
#elif defined(XP_MACOSX)
#include "gfxPlatformMac.h"
#include "gfxQuartzSurface.h"
@ -912,21 +911,6 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
RefPtr<SourceSurface> srcBuffer;
#ifdef XP_WIN
if (aSurface->GetType() == gfxSurfaceType::D2D &&
format != SurfaceFormat::A8) {
NativeSurface surf;
surf.mFormat = format;
surf.mType = NativeSurfaceType::D3D10_TEXTURE;
surf.mSurface = static_cast<gfxD2DSurface*>(aSurface)->GetTexture();
surf.mSize = aSurface->GetSize();
mozilla::gfx::DrawTarget *dt = static_cast<mozilla::gfx::DrawTarget*>(aSurface->GetData(&kDrawTarget));
if (dt) {
dt->Flush();
}
srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
}
#endif
// Currently no other DrawTarget types implement CreateSourceSurfaceFromNativeSurface
if (!srcBuffer) {

View File

@ -82,7 +82,6 @@ enum class gfxSurfaceType {
XML,
Skia,
Subsurface,
D2D,
Max
};

View File

@ -55,8 +55,6 @@
#include <string>
#ifdef CAIRO_HAS_D2D_SURFACE
#include "gfxD2DSurface.h"
#include <d3d10_1.h>
#include "mozilla/gfx/2D.h"
@ -116,38 +114,6 @@ static const char *kFeatureLevelPref =
static const int kSupportedFeatureLevels[] =
{ D3D10_FEATURE_LEVEL_10_1, D3D10_FEATURE_LEVEL_10_0 };
class GfxD2DSurfaceReporter final : public nsIMemoryReporter
{
~GfxD2DSurfaceReporter() {}
public:
NS_DECL_ISUPPORTS
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize)
{
nsresult rv;
int64_t amount = cairo_d2d_get_image_surface_cache_usage();
rv = MOZ_COLLECT_REPORT(
"gfx-d2d-surface-cache", KIND_OTHER, UNITS_BYTES, amount,
"Memory used by the Direct2D internal surface cache.");
NS_ENSURE_SUCCESS(rv, rv);
cairo_device_t *device =
gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
amount = device ? cairo_d2d_get_surface_vram_usage(device) : 0;
rv = MOZ_COLLECT_REPORT(
"gfx-d2d-surface-vram", KIND_OTHER, UNITS_BYTES, amount,
"Video memory used by D2D surfaces.");
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
};
NS_IMPL_ISUPPORTS(GfxD2DSurfaceReporter, nsIMemoryReporter)
#endif
class GfxD2DVramReporter final : public nsIMemoryReporter
@ -421,10 +387,6 @@ gfxWindowsPlatform::gfxWindowsPlatform()
*/
CoInitialize(nullptr);
#ifdef CAIRO_HAS_D2D_SURFACE
RegisterStrongMemoryReporter(new GfxD2DSurfaceReporter());
mD2DDevice = nullptr;
#endif
RegisterStrongMemoryReporter(new GfxD2DVramReporter());
if (gfxPrefs::Direct2DUse1_1()) {
@ -443,18 +405,11 @@ gfxWindowsPlatform::gfxWindowsPlatform()
gfxWindowsPlatform::~gfxWindowsPlatform()
{
mDeviceManager = nullptr;
mD3D10Device = nullptr;
mD3D11Device = nullptr;
mD3D11ContentDevice = nullptr;
mD3D11ImageBridgeDevice = nullptr;
// not calling FT_Done_FreeType because cairo may still hold references to
// these FT_Faces. See bug 458169.
#ifdef CAIRO_HAS_D2D_SURFACE
if (mD2DDevice) {
cairo_release_device(mD2DDevice);
}
#endif
mozilla::gfx::Factory::D2DCleanup();
mAdapter = nullptr;
@ -548,12 +503,12 @@ gfxWindowsPlatform::UpdateRenderMode()
mDoesD3D11TextureSharingWork) {
VerifyD2DDevice(d2dForceEnabled);
if (mD2DDevice && GetD3D11Device()) {
if (mD3D10Device && GetD3D11Device()) {
mRenderMode = RENDER_DIRECT2D;
mUseDirectWrite = true;
}
} else {
mD2DDevice = nullptr;
mD3D10Device = nullptr;
}
#endif
@ -631,7 +586,7 @@ gfxWindowsPlatform::CreateDevice(nsRefPtr<IDXGIAdapter1> &adapter1,
if (!createD3DDevice)
return E_FAIL;
nsRefPtr<ID3D10Device1> device;
ID3D10Device1* device = nullptr;
HRESULT hr =
createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
#ifdef DEBUG
@ -641,14 +596,17 @@ gfxWindowsPlatform::CreateDevice(nsRefPtr<IDXGIAdapter1> &adapter1,
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
static_cast<D3D10_FEATURE_LEVEL1>(kSupportedFeatureLevels[featureLevelIndex]),
D3D10_1_SDK_VERSION, getter_AddRefs(device));
D3D10_1_SDK_VERSION, &device);
// If we fail here, the DirectX version or video card probably
// changed. We previously could use 10.1 but now we can't
// anymore. Revert back to doing a 10.0 check first before
// the 10.1 check.
if (device) {
mD2DDevice = cairo_d2d_create_device_from_d3d10device(device);
mD3D10Device = device;
// Leak the module while the D3D 10 device is being used.
d3d10module.disown();
// Setup a pref for future launch optimizaitons when in main process.
if (XRE_IsParentProcess()) {
@ -669,13 +627,11 @@ gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
return;
}
if (mD2DDevice) {
ID3D10Device1 *device = cairo_d2d_device_get_device(mD2DDevice);
if (SUCCEEDED(device->GetDeviceRemovedReason())) {
if (mD3D10Device) {
if (SUCCEEDED(mD3D10Device->GetDeviceRemovedReason())) {
return;
}
mD2DDevice = nullptr;
mD3D10Device = nullptr;
// Surface cache needs to be invalidated since it may contain vector
// images rendered with our old, broken D2D device.
@ -684,8 +640,6 @@ gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce);
nsRefPtr<ID3D10Device1> device;
int supportedFeatureLevelsCount = ArrayLength(kSupportedFeatureLevels);
nsRefPtr<IDXGIAdapter1> adapter1 = GetDXGIAdapter();
@ -724,13 +678,9 @@ gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
}
}
if (!mD2DDevice && aAttemptForce) {
mD2DDevice = cairo_d2d_create_device();
}
if (mD2DDevice) {
if (mD3D10Device) {
reporter.SetSuccessful();
mozilla::gfx::Factory::SetDirect3D10Device(cairo_d2d_device_get_device(mD2DDevice));
mozilla::gfx::Factory::SetDirect3D10Device(mD3D10Device);
}
ScopedGfxFeatureReporter reporter1_1("D2D1.1");
@ -779,17 +729,11 @@ gfxWindowsPlatform::CreateOffscreenSurface(const IntSize& size,
nsRefPtr<gfxASurface> surf = nullptr;
#ifdef CAIRO_HAS_WIN32_SURFACE
if (mRenderMode == RENDER_GDI)
if (mRenderMode == RENDER_GDI || mRenderMode == RENDER_DIRECT2D)
surf = new gfxWindowsSurface(size,
OptimalFormatForContent(contentType));
#endif
#ifdef CAIRO_HAS_D2D_SURFACE
if (mRenderMode == RENDER_DIRECT2D)
surf = new gfxD2DSurface(size,
OptimalFormatForContent(contentType));
#endif
if (!surf || surf->CairoStatus()) {
surf = new gfxImageSurface(size,
OptimalFormatForContent(contentType));

View File

@ -240,10 +240,7 @@ public:
void OnDeviceManagerDestroy(mozilla::layers::DeviceManagerD3D9* aDeviceManager);
mozilla::layers::DeviceManagerD3D9* GetD3D9DeviceManager();
IDirect3DDevice9* GetD3D9Device();
#ifdef CAIRO_HAS_D2D_SURFACE
cairo_device_t *GetD2DDevice() { return mD2DDevice; }
ID3D10Device1 *GetD3D10Device() { return mD2DDevice ? cairo_d2d_device_get_device(mD2DDevice) : nullptr; }
#endif
ID3D10Device1 *GetD3D10Device() { return mD3D10Device; }
ID3D11Device *GetD3D11Device();
ID3D11Device *GetD3D11ContentDevice();
// Device to be used on the ImageBridge thread
@ -290,12 +287,10 @@ private:
nsRefPtr<IDWriteTextAnalyzer> mDWriteAnalyzer;
nsRefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
DWRITE_MEASURING_MODE mMeasuringMode;
#endif
#ifdef CAIRO_HAS_D2D_SURFACE
cairo_device_t *mD2DDevice;
#endif
mozilla::RefPtr<IDXGIAdapter1> mAdapter;
nsRefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager;
mozilla::RefPtr<ID3D10Device1> mD3D10Device;
mozilla::RefPtr<ID3D11Device> mD3D11Device;
mozilla::RefPtr<ID3D11Device> mD3D11ContentDevice;
mozilla::RefPtr<ID3D11Device> mD3D11ImageBridgeDevice;

View File

@ -162,7 +162,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
EXPORTS += [
'gfxD2DSurface.h',
'gfxDWriteFonts.h',
'gfxGDIFont.h',
'gfxGDIFontList.h',
@ -185,7 +184,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
'gfxDWriteFontList.cpp',
]
SOURCES += [
'gfxD2DSurface.cpp',
'gfxDWriteCommon.cpp',
'gfxDWriteFonts.cpp',
]

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