зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2ginbound, a=merge
This commit is contained in:
Коммит
dda81554e2
|
@ -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);
|
||||
|
|
|
@ -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@);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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 -->
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
},
|
||||
|
||||
|
|
|
@ -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();
|
||||
},
|
||||
|
||||
|
|
|
@ -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});
|
||||
},
|
||||
|
|
|
@ -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});
|
||||
},
|
||||
|
|
|
@ -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));
|
||||
},
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
}),
|
||||
|
|
|
@ -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));
|
||||
},
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
})
|
||||
];
|
|
@ -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);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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).
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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();
|
|
@ -7,4 +7,4 @@
|
|||
<!ENTITY aboutAccountsConfig.description "Sign in to sync your tabs, bookmarks, passwords & 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">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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@
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"],
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -455,6 +455,9 @@ void
|
|||
EventStateManager::OnStartToObserveContent(
|
||||
IMEContentObserver* aIMEContentObserver)
|
||||
{
|
||||
if (mIMEContentObserver == aIMEContentObserver) {
|
||||
return;
|
||||
}
|
||||
ReleaseCurrentIMEContentObserver();
|
||||
mIMEContentObserver = aIMEContentObserver;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "AudioContext.h"
|
||||
#include "AudioNodeEngine.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "gfxD2DSurface.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include <d3d10_1.h>
|
||||
#include "D3D9SurfaceImage.h"
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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 */
|
|
@ -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) {
|
||||
|
|
|
@ -82,7 +82,6 @@ enum class gfxSurfaceType {
|
|||
XML,
|
||||
Skia,
|
||||
Subsurface,
|
||||
D2D,
|
||||
Max
|
||||
};
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
]
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче