MozReview-Commit-ID: 9qR4QYHAi2x
This commit is contained in:
Wes Kocher 2017-09-28 17:08:09 -07:00
Родитель 29d5db60ba 1cdb198bd9
Коммит 253017b382
310 изменённых файлов: 4281 добавлений и 7529 удалений

Просмотреть файл

@ -240,6 +240,9 @@ window:not([chromehidden~="toolbar"]) #nav-bar[nonemptyoverflow] > .overflow-but
%ifdef CAN_DRAW_IN_TITLEBAR %ifdef CAN_DRAW_IN_TITLEBAR
%ifdef MENUBAR_CAN_AUTOHIDE
#toolbar-menubar:not([autohide=true]) ~ #TabsToolbar > .titlebar-placeholder,
%endif
#main-window:not([chromemargin]) > #titlebar, #main-window:not([chromemargin]) > #titlebar,
#main-window[inFullscreen] > #titlebar, #main-window[inFullscreen] > #titlebar,
#main-window[inFullscreen] .titlebar-placeholder, #main-window[inFullscreen] .titlebar-placeholder,
@ -308,12 +311,6 @@ toolbarpaletteitem {
#main-window[tabletmode] #titlebar-max { #main-window[tabletmode] #titlebar-max {
display: none !important; display: none !important;
} }
#main-window[tabsintitlebar] #TabsToolbar,
#main-window[tabsintitlebar] #toolbar-menubar,
#main-window[tabsintitlebar] #navigator-toolbox > toolbar:-moz-lwtheme {
-moz-window-dragging: drag;
}
%endif %endif
%endif %endif

Просмотреть файл

@ -5054,8 +5054,7 @@ var CombinedStopReload = {
}, },
switchToReload(aRequest, aWebProgress) { switchToReload(aRequest, aWebProgress) {
if (!this.ensureInitialized() || !this._shouldSwitch(aRequest, aWebProgress) || if (!this.ensureInitialized() || !this.reload.hasAttribute("displaystop")) {
!this.reload.hasAttribute("displaystop")) {
return; return;
} }
@ -6142,7 +6141,7 @@ function stripUnsafeProtocolOnPaste(pasteData) {
// LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL for those. // LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL for those.
let changed = false; let changed = false;
let pasteDataNoJS = pasteData.replace(/\r?\n/g, "") let pasteDataNoJS = pasteData.replace(/\r?\n/g, "")
.replace(/^(?:\s*javascript:)+/i, .replace(/^(?:\W*javascript:)+/i,
() => { () => {
changed = true; changed = true;
return ""; return "";

Просмотреть файл

@ -634,7 +634,7 @@
#ifdef CAN_DRAW_IN_TITLEBAR #ifdef CAN_DRAW_IN_TITLEBAR
<hbox class="titlebar-placeholder" type="pre-tabs" <hbox class="titlebar-placeholder" type="pre-tabs"
skipintoolbarset="true"/> skipintoolbarset="true"/>
#endif #endif
<tabs id="tabbrowser-tabs" <tabs id="tabbrowser-tabs"
@ -681,6 +681,12 @@
</menupopup> </menupopup>
</toolbarbutton> </toolbarbutton>
#ifdef CAN_DRAW_IN_TITLEBAR
<hbox class="titlebar-placeholder" type="post-tabs"
ordinal="1000"
skipintoolbarset="true"/>
#endif
<button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;" <button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;"
ordinal="1000" ordinal="1000"
aria-live="polite" skipintoolbarset="true"/> aria-live="polite" skipintoolbarset="true"/>

Просмотреть файл

@ -379,7 +379,7 @@ nsContextMenu.prototype = {
initLeaveDOMFullScreenItems: function CM_initLeaveFullScreenItem() { initLeaveDOMFullScreenItems: function CM_initLeaveFullScreenItem() {
// only show the option if the user is in DOM fullscreen // only show the option if the user is in DOM fullscreen
var shouldShow = (this.target.ownerDocument.fullscreenElement != null); var shouldShow = this.target.ownerDocument.fullscreen;
this.showItem("context-leave-dom-fullscreen", shouldShow); this.showItem("context-leave-dom-fullscreen", shouldShow);
// Explicitly show if in DOM fullscreen, but do not hide it has already been shown // Explicitly show if in DOM fullscreen, but do not hide it has already been shown
@ -643,7 +643,7 @@ nsContextMenu.prototype = {
this.showItem("context-media-loop", onMedia); this.showItem("context-media-loop", onMedia);
this.showItem("context-media-showcontrols", onMedia && !this.target.controls); this.showItem("context-media-showcontrols", onMedia && !this.target.controls);
this.showItem("context-media-hidecontrols", this.target.controls && (this.onVideo || (this.onAudio && !this.inSyntheticDoc))); this.showItem("context-media-hidecontrols", this.target.controls && (this.onVideo || (this.onAudio && !this.inSyntheticDoc)));
this.showItem("context-video-fullscreen", this.onVideo && this.target.ownerDocument.fullscreenElement == null); this.showItem("context-video-fullscreen", this.onVideo && !this.target.ownerDocument.fullscreen);
this.showItem("context-media-eme-learnmore", this.onDRMMedia); this.showItem("context-media-eme-learnmore", this.onDRMMedia);
this.showItem("context-media-eme-separator", this.onDRMMedia); this.showItem("context-media-eme-separator", this.onDRMMedia);

Просмотреть файл

@ -7,6 +7,7 @@ var pairs = [
["javascript:", ""], ["javascript:", ""],
["javascript:1+1", "1+1"], ["javascript:1+1", "1+1"],
["javascript:document.domain", "document.domain"], ["javascript:document.domain", "document.domain"],
[" \u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009javascript:document.domain", "document.domain"],
["java\nscript:foo", "foo"], ["java\nscript:foo", "foo"],
["http://\nexample.com", "http://example.com"], ["http://\nexample.com", "http://example.com"],
["http://\nexample.com\n", "http://example.com"], ["http://\nexample.com\n", "http://example.com"],

Просмотреть файл

@ -31,6 +31,7 @@ for (const type of [
"DELETE_HISTORY_URL_CONFIRM", "DELETE_HISTORY_URL_CONFIRM",
"DIALOG_CANCEL", "DIALOG_CANCEL",
"DIALOG_OPEN", "DIALOG_OPEN",
"DISABLE_ONBOARDING",
"INIT", "INIT",
"LOCALE_UPDATED", "LOCALE_UPDATED",
"MIGRATION_CANCEL", "MIGRATION_CANCEL",
@ -49,8 +50,8 @@ for (const type of [
"PLACES_BOOKMARK_CHANGED", "PLACES_BOOKMARK_CHANGED",
"PLACES_BOOKMARK_REMOVED", "PLACES_BOOKMARK_REMOVED",
"PLACES_HISTORY_CLEARED", "PLACES_HISTORY_CLEARED",
"PLACES_LINKS_DELETED",
"PLACES_LINK_BLOCKED", "PLACES_LINK_BLOCKED",
"PLACES_LINK_DELETED",
"PREFS_INITIAL_VALUES", "PREFS_INITIAL_VALUES",
"PREF_CHANGED", "PREF_CHANGED",
"SAVE_SESSION_PERF_DATA", "SAVE_SESSION_PERF_DATA",

Просмотреть файл

@ -74,8 +74,7 @@ this.PrerenderData = new _PrerenderData({
icon: "pocket", icon: "pocket",
id: "topstories", id: "topstories",
order: 1, order: 1,
title: {id: "header_recommended_by", values: {provider: "Pocket"}}, title: {id: "header_recommended_by", values: {provider: "Pocket"}}
topics: [{}]
}, },
{ {
enabled: true, enabled: true,

Просмотреть файл

@ -288,7 +288,9 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
return item; return item;
}) })
})); }));
case at.PLACES_LINK_DELETED: case at.PLACES_LINKS_DELETED:
return prevState.map(section => Object.assign({}, section,
{rows: section.rows.filter(site => !action.data.includes(site.url))}));
case at.PLACES_LINK_BLOCKED: case at.PLACES_LINK_BLOCKED:
return prevState.map(section => return prevState.map(section =>
Object.assign({}, section, {rows: section.rows.filter(site => site.url !== action.data.url)})); Object.assign({}, section, {rows: section.rows.filter(site => site.url !== action.data.url)}));

Просмотреть файл

@ -138,9 +138,6 @@
"enabled": true, "enabled": true,
"icon": "pocket", "icon": "pocket",
"id": "topstories", "id": "topstories",
"topics": [
{}
],
"initialized": false "initialized": false
}, },
{ {

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -94,7 +94,7 @@ const globalImportContext = typeof Window === "undefined" ? BACKGROUND_PROCESS :
// UNINIT: "UNINIT" // UNINIT: "UNINIT"
// } // }
const actionTypes = {}; const actionTypes = {};
for (const type of ["BLOCK_URL", "BOOKMARK_URL", "DELETE_BOOKMARK_BY_ID", "DELETE_HISTORY_URL", "DELETE_HISTORY_URL_CONFIRM", "DIALOG_CANCEL", "DIALOG_OPEN", "INIT", "LOCALE_UPDATED", "MIGRATION_CANCEL", "MIGRATION_COMPLETED", "MIGRATION_START", "NEW_TAB_INIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_REHYDRATED", "NEW_TAB_STATE_REQUEST", "NEW_TAB_UNLOAD", "OPEN_LINK", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_CHANGED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINK_BLOCKED", "PLACES_LINK_DELETED", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_OPTIONS_CHANGED", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SET_PREF", "SHOW_FIREFOX_ACCOUNTS", "SNIPPETS_DATA", "SNIPPETS_RESET", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_ADD", "TOP_SITES_CANCEL_EDIT", "TOP_SITES_EDIT", "TOP_SITES_PIN", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "UNINIT"]) { for (const type of ["BLOCK_URL", "BOOKMARK_URL", "DELETE_BOOKMARK_BY_ID", "DELETE_HISTORY_URL", "DELETE_HISTORY_URL_CONFIRM", "DIALOG_CANCEL", "DIALOG_OPEN", "DISABLE_ONBOARDING", "INIT", "LOCALE_UPDATED", "MIGRATION_CANCEL", "MIGRATION_COMPLETED", "MIGRATION_START", "NEW_TAB_INIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_REHYDRATED", "NEW_TAB_STATE_REQUEST", "NEW_TAB_UNLOAD", "OPEN_LINK", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_CHANGED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINKS_DELETED", "PLACES_LINK_BLOCKED", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_OPTIONS_CHANGED", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SET_PREF", "SHOW_FIREFOX_ACCOUNTS", "SNIPPETS_DATA", "SNIPPETS_RESET", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_ADD", "TOP_SITES_CANCEL_EDIT", "TOP_SITES_EDIT", "TOP_SITES_PIN", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "UNINIT"]) {
actionTypes[type] = type; actionTypes[type] = type;
} }
@ -638,7 +638,8 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
return item; return item;
}) })
})); }));
case at.PLACES_LINK_DELETED: case at.PLACES_LINKS_DELETED:
return prevState.map(section => Object.assign({}, section, { rows: section.rows.filter(site => !action.data.includes(site.url)) }));
case at.PLACES_LINK_BLOCKED: case at.PLACES_LINK_BLOCKED:
return prevState.map(section => Object.assign({}, section, { rows: section.rows.filter(site => site.url !== action.data.url) })); return prevState.map(section => Object.assign({}, section, { rows: section.rows.filter(site => site.url !== action.data.url) }));
default: default:
@ -1511,10 +1512,14 @@ class TopSitesEdit extends React.PureComponent {
"section", "section",
{ className: "edit-topsites-inner-wrapper" }, { className: "edit-topsites-inner-wrapper" },
React.createElement( React.createElement(
"h3", "div",
{ className: "section-title" }, { className: "section-top-bar" },
React.createElement("span", { className: `icon icon-small-spacer icon-topsites` }), React.createElement(
React.createElement(FormattedMessage, { id: "header_top_sites" }) "h3",
{ className: "section-title" },
React.createElement("span", { className: `icon icon-small-spacer icon-topsites` }),
React.createElement(FormattedMessage, { id: "header_top_sites" })
)
), ),
React.createElement( React.createElement(
"ul", "ul",
@ -2569,7 +2574,10 @@ class Section extends React.PureComponent {
contextMenuOptions, intl, initialized contextMenuOptions, intl, initialized
} = this.props; } = this.props;
const maxCards = CARDS_PER_ROW * maxRows; const maxCards = CARDS_PER_ROW * maxRows;
const shouldShowTopics = id === "topstories" && this.props.topics && this.props.topics.length > 0;
// Show topics only for top stories and if it's not initialized yet (so
// content doesn't shift when it is loaded) or has loaded with topics
const shouldShowTopics = id === "topstories" && (!this.props.topics || this.props.topics.length > 0);
const infoOptionIconA11yAttrs = { const infoOptionIconA11yAttrs = {
"aria-haspopup": "true", "aria-haspopup": "true",
@ -2694,6 +2702,9 @@ const { FormattedMessage } = __webpack_require__(2);
const cardContextTypes = __webpack_require__(26); const cardContextTypes = __webpack_require__(26);
const { actionCreators: ac, actionTypes: at } = __webpack_require__(0); const { actionCreators: ac, actionTypes: at } = __webpack_require__(0);
// Keep track of pending image loads to only request once
const gImageLoading = new Map();
/** /**
* Card component. * Card component.
* Cards are found within a Section component and contain information about a link such * Cards are found within a Section component and contain information about a link such
@ -2706,11 +2717,47 @@ const { actionCreators: ac, actionTypes: at } = __webpack_require__(0);
class Card extends React.PureComponent { class Card extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { showContextMenu: false, activeCard: null }; this.state = {
activeCard: null,
imageLoaded: false,
showContextMenu: false
};
this.onMenuButtonClick = this.onMenuButtonClick.bind(this); this.onMenuButtonClick = this.onMenuButtonClick.bind(this);
this.onMenuUpdate = this.onMenuUpdate.bind(this); this.onMenuUpdate = this.onMenuUpdate.bind(this);
this.onLinkClick = this.onLinkClick.bind(this); this.onLinkClick = this.onLinkClick.bind(this);
} }
/**
* Helper to conditionally load an image and update state when it loads.
*/
async maybeLoadImage() {
// No need to load if it's already loaded or no image
const { image } = this.props.link;
if (!this.state.imageLoaded && image) {
// Initialize a promise to share a load across multiple card updates
if (!gImageLoading.has(image)) {
const loaderPromise = new Promise((resolve, reject) => {
const loader = new Image();
loader.addEventListener("load", resolve);
loader.addEventListener("error", reject);
loader.src = image;
});
// Save and remove the promise only while it's pending
gImageLoading.set(image, loaderPromise);
loaderPromise.catch(ex => ex).then(() => gImageLoading.delete(image)).catch();
}
// Wait for the image whether just started loading or reused promise
await gImageLoading.get(image);
// Only update state if we're still waiting to load the original image
if (this.props.link.image === image && !this.state.imageLoaded) {
this.setState({ imageLoaded: true });
}
}
}
onMenuButtonClick(event) { onMenuButtonClick(event) {
event.preventDefault(); event.preventDefault();
this.setState({ this.setState({
@ -2742,6 +2789,18 @@ class Card extends React.PureComponent {
onMenuUpdate(showContextMenu) { onMenuUpdate(showContextMenu) {
this.setState({ showContextMenu }); this.setState({ showContextMenu });
} }
componentDidMount() {
this.maybeLoadImage();
}
componentDidUpdate() {
this.maybeLoadImage();
}
componentWillReceiveProps(nextProps) {
// Clear the image state if changing images
if (nextProps.link.image !== this.props.link.image) {
this.setState({ imageLoaded: false });
}
}
render() { render() {
const { index, link, dispatch, contextMenuOptions, eventSource, shouldSendImpressionStats } = this.props; const { index, link, dispatch, contextMenuOptions, eventSource, shouldSendImpressionStats } = this.props;
const { props } = this; const { props } = this;
@ -2763,7 +2822,7 @@ class Card extends React.PureComponent {
hasImage && React.createElement( hasImage && React.createElement(
"div", "div",
{ className: "card-preview-image-outer" }, { className: "card-preview-image-outer" },
React.createElement("div", { className: `card-preview-image${link.image ? " loaded" : ""}`, style: imageStyle }) React.createElement("div", { className: `card-preview-image${this.state.imageLoaded ? " loaded" : ""}`, style: imageStyle })
), ),
React.createElement( React.createElement(
"div", "div",
@ -2894,7 +2953,7 @@ class Topics extends React.PureComponent {
React.createElement( React.createElement(
"ul", "ul",
null, null,
topics.map(t => React.createElement(Topic, { key: t.name, url: t.url, name: t.name })) topics && topics.map(t => React.createElement(Topic, { key: t.name, url: t.url, name: t.name }))
), ),
read_more_endpoint && React.createElement( read_more_endpoint && React.createElement(
"a", "a",
@ -2985,8 +3044,7 @@ var PrerenderData = new _PrerenderData({
icon: "pocket", icon: "pocket",
id: "topstories", id: "topstories",
order: 1, order: 1,
title: { id: "header_recommended_by", values: { provider: "Pocket" } }, title: { id: "header_recommended_by", values: { provider: "Pocket" } }
topics: [{}]
}, { }, {
enabled: true, enabled: true,
id: "highlights", id: "highlights",
@ -3257,6 +3315,10 @@ class SnippetsMap extends Map {
await this.set("blockList", blockList); await this.set("blockList", blockList);
} }
disableOnboarding() {
this._dispatch(ac.SendToMain({ type: at.DISABLE_ONBOARDING }));
}
showFirefoxAccounts() { showFirefoxAccounts() {
this._dispatch(ac.SendToMain({ type: at.SHOW_FIREFOX_ACCOUNTS })); this._dispatch(ac.SendToMain({ type: at.SHOW_FIREFOX_ACCOUNTS }));
} }
@ -3395,7 +3457,6 @@ class SnippetsProvider {
if (needsUpdate && this.appData.snippetsURL) { if (needsUpdate && this.appData.snippetsURL) {
this.snippetsMap.set("snippets-last-update", Date.now()); this.snippetsMap.set("snippets-last-update", Date.now());
try { try {
// TODO: timeout?
const response = await fetch(this.appData.snippetsURL); const response = await fetch(this.appData.snippetsURL);
if (response.status === 200) { if (response.status === 200) {
const payload = await response.text(); const payload = await response.text();
@ -3409,10 +3470,18 @@ class SnippetsProvider {
} }
} }
_showDefaultSnippets() { _noSnippetFallback() {
// TODO // TODO
} }
_forceOnboardingVisibility(shouldBeVisible) {
const onboardingEl = document.getElementById("onboarding-notification-bar");
if (onboardingEl) {
onboardingEl.style.display = shouldBeVisible ? "" : "none";
}
}
_showRemoteSnippets() { _showRemoteSnippets() {
const snippetsEl = document.getElementById(this.elementId); const snippetsEl = document.getElementById(this.elementId);
const payload = this.snippetsMap.get("snippets"); const payload = this.snippetsMap.get("snippets");
@ -3480,15 +3549,18 @@ class SnippetsProvider {
try { try {
this._showRemoteSnippets(); this._showRemoteSnippets();
} catch (e) { } catch (e) {
this._showDefaultSnippets(e); this._noSnippetFallback(e);
} }
window.dispatchEvent(new Event(SNIPPETS_ENABLED_EVENT)); window.dispatchEvent(new Event(SNIPPETS_ENABLED_EVENT));
this._forceOnboardingVisibility(true);
this.initialized = true; this.initialized = true;
} }
uninit() { uninit() {
window.dispatchEvent(new Event(SNIPPETS_DISABLED_EVENT)); window.dispatchEvent(new Event(SNIPPETS_DISABLED_EVENT));
this._forceOnboardingVisibility(false);
this.initialized = false; this.initialized = false;
} }
} }
@ -3508,16 +3580,16 @@ function addSnippetsSubscriber(store) {
store.subscribe(async () => { store.subscribe(async () => {
const state = store.getState(); const state = store.getState();
// state.Snippets.initialized: Should snippets be initialised? // state.Prefs.values["feeds.snippets"]: Should snippets be shown?
// snippets.initialized: Is SnippetsProvider currently initialised? // state.Snippets.initialized Is the snippets data initialized?
if (state.Snippets.initialized && !snippets.initialized && state.Snippets.onboardingFinished) { // snippets.initialized: Is SnippetsProvider currently initialised?
// Don't call init multiple times if (state.Prefs.values["feeds.snippets"] && state.Snippets.initialized && !snippets.initialized &&
if (!initializing) { // Don't call init multiple times
initializing = true; !initializing) {
await snippets.init({ appData: state.Snippets }); initializing = true;
initializing = false; await snippets.init({ appData: state.Snippets });
} initializing = false;
} else if (state.Snippets.initialized === false && snippets.initialized) { } else if (state.Prefs.values["feeds.snippets"] === false && snippets.initialized) {
snippets.uninit(); snippets.uninit();
} }
}); });

Просмотреть файл

@ -92,7 +92,8 @@ body {
background: #F9F9FA; background: #F9F9FA;
color: #0C0C0D; color: #0C0C0D;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Ubuntu', 'Helvetica Neue', sans-serif; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Ubuntu', 'Helvetica Neue', sans-serif;
font-size: 16px; } font-size: 16px;
overflow-y: scroll; }
h1, h1,
h2 { h2 {
@ -457,26 +458,24 @@ main {
padding-inline-start: 3px; } padding-inline-start: 3px; }
.topsite-form .form-wrapper { .topsite-form .form-wrapper {
margin: auto;
max-width: 350px;
padding: 15px 0; } padding: 15px 0; }
.topsite-form .form-wrapper .field { .topsite-form .form-wrapper .field {
margin-inline-start: 205px;
position: relative; } position: relative; }
.topsite-form .form-wrapper .url input:not(:placeholder-shown):dir(rtl) { .topsite-form .form-wrapper .url input:not(:placeholder-shown):dir(rtl) {
direction: ltr; direction: ltr;
text-align: right; } text-align: right; }
.topsite-form .form-wrapper .section-title { .topsite-form .form-wrapper .section-title {
margin-bottom: 5px; margin-bottom: 5px; }
margin-inline-start: 205px; }
.topsite-form .form-wrapper input[type='text'] { .topsite-form .form-wrapper input[type='text'] {
border: solid 1px rgba(12, 12, 13, 0.2); border: solid 1px rgba(12, 12, 13, 0.2);
border-radius: 2px; border-radius: 2px;
margin: 5px 0; margin: 5px 0;
padding: 7px; padding: 7px;
width: 350px; } width: 100%; }
.topsite-form .form-wrapper input[type='text']:focus { .topsite-form .form-wrapper input[type='text']:focus {
border: solid 1px rgba(12, 12, 13, 0.4); } border: solid 1px rgba(12, 12, 13, 0.4); }
.topsite-form .form-wrapper input[type='text']::placeholder {
font-style: italic; }
.topsite-form .form-wrapper .invalid input[type='text'] { .topsite-form .form-wrapper .invalid input[type='text'] {
border: solid 1px #D70022; border: solid 1px #D70022;
box-shadow: 0 0 0 2px rgba(215, 0, 34, 0.35); } box-shadow: 0 0 0 2px rgba(215, 0, 34, 0.35); }
@ -676,28 +675,19 @@ main {
width: 100%; width: 100%;
height: 36px; } height: 36px; }
.search-wrapper input { .search-wrapper input {
border: 0;
box-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
border: 1px solid rgba(0, 0, 0, 0.15); border: 1px solid rgba(0, 0, 0, 0.15);
box-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
border-radius: 3px; border-radius: 3px;
border-radius: 4px; box-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
color: inherit; color: inherit;
padding: 0; padding: 0;
padding-inline-end: 36px; padding-inline-end: 36px;
padding-inline-start: 35px; padding-inline-start: 35px;
width: 100%; width: 100%;
font-size: 15px; } font-size: 15px; }
.search-wrapper input:focus { .search-wrapper:active input,
border-color: #0060DF; .search-wrapper input:focus {
box-shadow: 0 0 0 2px #0060DF; border-color: #0A84FF;
z-index: 1; } box-shadow: 0 0 0 2px #0A84FF; }
.search-wrapper input:focus + .search-button {
z-index: 1;
background-color: #0060DF;
background-image: url("chrome://browser/skin/forward.svg");
fill: #FFF;
-moz-context-properties: fill; }
.search-wrapper .search-label { .search-wrapper .search-label {
background: url("chrome://browser/skin/search-glass.svg") no-repeat 12px center/16px; background: url("chrome://browser/skin/search-glass.svg") no-repeat 12px center/16px;
fill: rgba(12, 12, 13, 0.4); fill: rgba(12, 12, 13, 0.4);
@ -705,8 +695,7 @@ main {
position: absolute; position: absolute;
offset-inline-start: 0; offset-inline-start: 0;
height: 100%; height: 100%;
width: 35px; width: 35px; }
z-index: 2; }
.search-wrapper .search-button { .search-wrapper .search-button {
background: url("chrome://browser/skin/forward.svg") no-repeat center center; background: url("chrome://browser/skin/forward.svg") no-repeat center center;
border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0;
@ -718,11 +707,11 @@ main {
height: 100%; height: 100%;
offset-inline-end: 0; offset-inline-end: 0;
position: absolute; } position: absolute; }
.search-wrapper .search-button:hover { .search-wrapper .search-button:focus, .search-wrapper .search-button:hover {
z-index: 1; background-color: rgba(12, 12, 13, 0.1);
background-color: #0060DF;
fill: #FFF;
cursor: pointer; } cursor: pointer; }
.search-wrapper .search-button:active {
background-color: rgba(12, 12, 13, 0.15); }
.search-wrapper .search-button:dir(rtl) { .search-wrapper .search-button:dir(rtl) {
transform: scaleX(-1); } transform: scaleX(-1); }
.search-wrapper .contentSearchSuggestionTable { .search-wrapper .contentSearchSuggestionTable {
@ -1009,13 +998,11 @@ main {
.card-outer:-moz-any(:hover, :focus, .active):not(.placeholder) .card-title { .card-outer:-moz-any(:hover, :focus, .active):not(.placeholder) .card-title {
color: #0060DF; } color: #0060DF; }
.card-outer .card-preview-image-outer { .card-outer .card-preview-image-outer {
background-color: #F9F9FA;
position: relative; position: relative;
background: linear-gradient(135deg, #B1B1B3, #D7D7DB);
height: 122px; height: 122px;
border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0;
overflow: hidden; } overflow: hidden; }
.card-outer .card-preview-image-outer:dir(rtl) {
background: linear-gradient(225deg, #B1B1B3, #D7D7DB); }
.card-outer .card-preview-image-outer::after { .card-outer .card-preview-image-outer::after {
border-bottom: 1px solid rgba(0, 0, 0, 0.05); border-bottom: 1px solid rgba(0, 0, 0, 0.05);
bottom: 0; bottom: 0;
@ -1028,8 +1015,8 @@ main {
background-size: cover; background-size: cover;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
transition: opacity 1s; opacity: 0;
opacity: 0; } transition: opacity 1s cubic-bezier(0.07, 0.95, 0, 1); }
.card-outer .card-preview-image-outer .card-preview-image.loaded { .card-outer .card-preview-image-outer .card-preview-image.loaded {
opacity: 1; } opacity: 1; }
.card-outer .card-details { .card-outer .card-details {

Просмотреть файл

@ -580,7 +580,51 @@
"time_label_hour": "{number}e", "time_label_hour": "{number}e",
"time_label_day": "{number}d", "time_label_day": "{number}d",
"settings_pane_button_label": "Personelait ho pajenn Ivinell Nevez", "settings_pane_button_label": "Personelait ho pajenn Ivinell Nevez",
"settings_pane_header": "Gwellvezioù an ivinell nevez" "settings_pane_header": "Gwellvezioù an ivinell nevez",
"settings_pane_body2": "Dibabit petra a welit war ar bajenn-mañ.",
"settings_pane_search_header": "Klask",
"settings_pane_search_body": "Klask er web adalek an ivinell nevez.",
"settings_pane_topsites_header": "Lec'hiennoù gwellañ",
"settings_pane_topsites_body": "Kit war al lec'hiennoù gweladennet ar muiañ ganeoc'h.",
"settings_pane_topsites_options_showmore": "Diskouez daou vann",
"settings_pane_bookmarks_header": "Sinedoù nevez",
"settings_pane_bookmarks_body": "Ho sinedoù nevez strollet en ul lec'h aes da dizhout.",
"settings_pane_visit_again_header": "Gweladenniñ en-dro",
"settings_pane_visit_again_body": "Firefox a ziskouezo deoc'h ul lodenn eus ho roll istor a c'hallfec'h kaout c'hoant da zerc'hel soñj pe da zistreiñ eno.",
"settings_pane_highlights_header": "Mareoù pouezus",
"settings_pane_highlights_body2": "Adkavit an traoù dedennus gweladennet pe lakaet er sinedoù nevez zo.",
"settings_pane_highlights_options_bookmarks": "Sinedoù",
"settings_pane_highlights_options_visited": "Lec'hiennoù gweladennet",
"settings_pane_snippets_header": "Notennigoù",
"settings_pane_snippets_body": "Lennit an hizivadurioù berr ha dous graet gant Mozilla evit Firefox, sevenadur ar genrouedad, hag ur mem dre-zegouezh ur wech an amzer.",
"settings_pane_done_button": "Graet",
"edit_topsites_button_text": "Embann",
"edit_topsites_button_label": "Personelaat ar gevrenn “lec'hiennoù gweladennet ar muiañ”",
"edit_topsites_showmore_button": "Diskouez muioc'h",
"edit_topsites_showless_button": "Diskouez nebeutoc'h",
"edit_topsites_done_button": "Graet",
"edit_topsites_pin_button": "Spilhennañ al lec'hienn-mañ",
"edit_topsites_unpin_button": "Dispilhennañ al lec'hienn-mañ",
"edit_topsites_edit_button": "Embann al lec'hienn-mañ",
"edit_topsites_dismiss_button": "Dilemel al lec'hienn-mañ",
"edit_topsites_add_button": "Ouzhpennañ",
"topsites_form_add_header": "Lec'hiennoù gwellañ nevez",
"topsites_form_edit_header": "Embann al Lec'hiennoù Gwellañ",
"topsites_form_title_placeholder": "Enankañ un titl",
"topsites_form_url_placeholder": "Skrivit pe pegit un URL",
"topsites_form_add_button": "Ouzhpennañ",
"topsites_form_save_button": "Enrollañ",
"topsites_form_cancel_button": "Nullañ",
"topsites_form_url_validation": "URL talvoudek azgoulennet",
"pocket_read_more": "Danvezioù brudet:",
"pocket_read_even_more": "Gwelet muioc'h a istorioù",
"pocket_feedback_header": "Ar gwellañ eus ar web, dibabet gant ouzhpenn 25 milion a dud.",
"pocket_description": "Dizoloit pennadoù eus an dibab ho pije gellout c'hwitout a-hent all warno, a-drugarez da bPocket, hag a zo bremañ ul lodenn deus Mozilla.",
"highlights_empty_state": "Krogit da verdeiñ hag e tiskouezimp deoch pennadoù, videoioù ha pajennoù all gweladennet pe lakaet er sinedoù nevez zo.",
"topstories_empty_state": "Aet oc'h betek penn. Distroit diwezhatoc'h evit muioch a istorioù digant {provider}. Noc'h ket evit gortoz? Dibabit un danvez brudet evit klask muioch a bennadoù dedennus eus pep lech er web.",
"manual_migration_explanation2": "Amprouit Firefox gant sinedoù, roll istor ha gerioù-tremen ur merdeer all.",
"manual_migration_cancel_button": "N'am bo ket",
"manual_migration_import_button": "Emporzhiañ bremañ"
}, },
"ca": { "ca": {
"newtab_page_title": "Pestanya nova", "newtab_page_title": "Pestanya nova",
@ -955,6 +999,7 @@
"default_label_loading": "Indlæser…", "default_label_loading": "Indlæser…",
"header_top_sites": "Mest besøgte websider", "header_top_sites": "Mest besøgte websider",
"header_stories": "Tophistorier", "header_stories": "Tophistorier",
"header_highlights": "Højdepunkter",
"header_visit_again": "Besøg igen", "header_visit_again": "Besøg igen",
"header_bookmarks": "Seneste bogmærker", "header_bookmarks": "Seneste bogmærker",
"header_recommended_by": "Anbefalet af {provider}", "header_recommended_by": "Anbefalet af {provider}",
@ -986,6 +1031,7 @@
"search_web_placeholder": "Søg på internettet", "search_web_placeholder": "Søg på internettet",
"search_settings": "Skift søgeindstillinger", "search_settings": "Skift søgeindstillinger",
"section_info_option": "Info", "section_info_option": "Info",
"section_info_send_feedback": "Send feedback",
"welcome_title": "Velkommen til nyt faneblad", "welcome_title": "Velkommen til nyt faneblad",
"welcome_body": "Firefox vil bruge denne plads til at vise dine mest relevante bogmærker, artikler, videoer og sider, du har besøgt for nylig - så kan du nemmere finde dem.", "welcome_body": "Firefox vil bruge denne plads til at vise dine mest relevante bogmærker, artikler, videoer og sider, du har besøgt for nylig - så kan du nemmere finde dem.",
"welcome_label": "Finder dine højdepunkter", "welcome_label": "Finder dine højdepunkter",
@ -995,7 +1041,6 @@
"time_label_day": "{number} d.", "time_label_day": "{number} d.",
"settings_pane_button_label": "Tilpas siden Nyt faneblad", "settings_pane_button_label": "Tilpas siden Nyt faneblad",
"settings_pane_header": "Indstillinger for Nyt faneblad", "settings_pane_header": "Indstillinger for Nyt faneblad",
"settings_pane_body": "Vælg, hvad der vises, når du åbner et nyt faneblad.",
"settings_pane_search_header": "Søgning", "settings_pane_search_header": "Søgning",
"settings_pane_search_body": "Søg på nettet fra Nyt faneblad.", "settings_pane_search_body": "Søg på nettet fra Nyt faneblad.",
"settings_pane_topsites_header": "Mest besøgte websider", "settings_pane_topsites_header": "Mest besøgte websider",
@ -1005,8 +1050,6 @@
"settings_pane_bookmarks_body": "Dine seneste bogmærker samlet ét sted.", "settings_pane_bookmarks_body": "Dine seneste bogmærker samlet ét sted.",
"settings_pane_visit_again_header": "Besøg igen", "settings_pane_visit_again_header": "Besøg igen",
"settings_pane_visit_again_body": "Firefox viser dig dele af din browserhistorik, som du måske vil huske på eller vende tilbage til.", "settings_pane_visit_again_body": "Firefox viser dig dele af din browserhistorik, som du måske vil huske på eller vende tilbage til.",
"settings_pane_pocketstories_header": "Tophistorier",
"settings_pane_pocketstories_body": "Pocket, en del af Mozilla-familien, hjælper dig med at opdage indhold af høj kvalitet, som du måske ellers ikke ville have fundet.",
"settings_pane_done_button": "Færdig", "settings_pane_done_button": "Færdig",
"edit_topsites_button_text": "Rediger", "edit_topsites_button_text": "Rediger",
"edit_topsites_button_label": "Tilpas afsnittet Mest besøgte websider", "edit_topsites_button_label": "Tilpas afsnittet Mest besøgte websider",
@ -1029,10 +1072,7 @@
"pocket_read_more": "Populære emner:", "pocket_read_more": "Populære emner:",
"pocket_read_even_more": "Se flere historier", "pocket_read_even_more": "Se flere historier",
"pocket_feedback_header": "Det bedste fra nettet, udvalgt af mere end 25 millioner mennesker.", "pocket_feedback_header": "Det bedste fra nettet, udvalgt af mere end 25 millioner mennesker.",
"pocket_feedback_body": "Pocket, en del af Mozilla-familien, hjælper dig med at opdage indhold af høj kvalitet, som du måske ellers ikke ville have fundet.",
"pocket_send_feedback": "Send feedback",
"topstories_empty_state": "Der er ikke flere nye historier. Kom tilbage senere for at se flere tophistorier fra {provider}. Kan du ikke vente? Vælg et populært emne og find flere spændende historier fra hele verden.", "topstories_empty_state": "Der er ikke flere nye historier. Kom tilbage senere for at se flere tophistorier fra {provider}. Kan du ikke vente? Vælg et populært emne og find flere spændende historier fra hele verden.",
"manual_migration_explanation": "Prøv Firefox med dine favorit-websteder og bogmærker fra en anden browser.",
"manual_migration_cancel_button": "Nej tak", "manual_migration_cancel_button": "Nej tak",
"manual_migration_import_button": "Importer nu" "manual_migration_import_button": "Importer nu"
}, },
@ -2586,6 +2626,7 @@
"default_label_loading": "Ga luchdadh…", "default_label_loading": "Ga luchdadh…",
"header_top_sites": "Brod nan làrach", "header_top_sites": "Brod nan làrach",
"header_stories": "Brod nan sgeul", "header_stories": "Brod nan sgeul",
"header_highlights": "Sàr-roghainn",
"header_visit_again": "Tadhail a-rithist", "header_visit_again": "Tadhail a-rithist",
"header_bookmarks": "Comharran-lìn o chionn goirid", "header_bookmarks": "Comharran-lìn o chionn goirid",
"header_recommended_by": "Ga mholadh le {provider}", "header_recommended_by": "Ga mholadh le {provider}",
@ -2617,6 +2658,8 @@
"search_web_placeholder": "Lorg air an lìon", "search_web_placeholder": "Lorg air an lìon",
"search_settings": "Atharraich roghainnean an luirg", "search_settings": "Atharraich roghainnean an luirg",
"section_info_option": "Fiosrachadh", "section_info_option": "Fiosrachadh",
"section_info_send_feedback": "Cuir thugainn do bheachdan",
"section_info_privacy_notice": "Sanas prìobhaideachd",
"welcome_title": "Fàilte gun taba ùr", "welcome_title": "Fàilte gun taba ùr",
"welcome_body": "Seallaidh Firefox na comharran-lìn, artaigealan, videothan is duilleagan as iomchaidhe dhut, an fheadhainn air an do thadhail thu o chionn goirid, ach an ruig thu iad gu luath.", "welcome_body": "Seallaidh Firefox na comharran-lìn, artaigealan, videothan is duilleagan as iomchaidhe dhut, an fheadhainn air an do thadhail thu o chionn goirid, ach an ruig thu iad gu luath.",
"welcome_label": "Ag aithneachadh nan highlights agad", "welcome_label": "Ag aithneachadh nan highlights agad",
@ -2626,7 +2669,7 @@
"time_label_day": "{number}l", "time_label_day": "{number}l",
"settings_pane_button_label": "Gnàthaich duilleag nan tabaichean ùra agad", "settings_pane_button_label": "Gnàthaich duilleag nan tabaichean ùra agad",
"settings_pane_header": "Roghainnean nan tabaichean ùra", "settings_pane_header": "Roghainnean nan tabaichean ùra",
"settings_pane_body": "Tagh na chì thu nuair a dhfhosglas tu taba ùr.", "settings_pane_body2": "Tagh na chì thu air an duilleag seo.",
"settings_pane_search_header": "Lorg", "settings_pane_search_header": "Lorg",
"settings_pane_search_body": "Lorg air an lìon on taba ùr agad.", "settings_pane_search_body": "Lorg air an lìon on taba ùr agad.",
"settings_pane_topsites_header": "Brod nan làrach", "settings_pane_topsites_header": "Brod nan làrach",
@ -2636,8 +2679,11 @@
"settings_pane_bookmarks_body": "Na comharran-lìn ùra agad san aon àite ghoireasach.", "settings_pane_bookmarks_body": "Na comharran-lìn ùra agad san aon àite ghoireasach.",
"settings_pane_visit_again_header": "Tadhail a-rithist", "settings_pane_visit_again_header": "Tadhail a-rithist",
"settings_pane_visit_again_body": "Seallaidh Firefox cuid dhen eachdraidh bhrabhsaidh agad dhut a bu toil leat cuimhneachadh no tadhal air a-rithist ma dhfhaoidte.", "settings_pane_visit_again_body": "Seallaidh Firefox cuid dhen eachdraidh bhrabhsaidh agad dhut a bu toil leat cuimhneachadh no tadhal air a-rithist ma dhfhaoidte.",
"settings_pane_pocketstories_header": "Brod nan sgeul", "settings_pane_highlights_header": "Sàr-roghainn",
"settings_pane_pocketstories_body": "Pocket, ball de theaghlach Mozilla, a cheanglas tu ri susbaint fhìor-mhath nach biodh tu air fhaicinn air dòigh eile.", "settings_pane_highlights_body2": "Faigh greim gu furasta air rudan inntinneach air an do thadhail thu roimhe no a rinn thu comharran-lìn dhiubh.",
"settings_pane_highlights_options_bookmarks": "Comharran-lìn",
"settings_pane_highlights_options_visited": "Làraichean a thadhladh orra",
"settings_pane_snippets_header": "Snippets",
"settings_pane_done_button": "Deiseil", "settings_pane_done_button": "Deiseil",
"edit_topsites_button_text": "Deasaich", "edit_topsites_button_text": "Deasaich",
"edit_topsites_button_label": "Gnàthaich earrann brod nan làrach agad", "edit_topsites_button_label": "Gnàthaich earrann brod nan làrach agad",
@ -2660,10 +2706,7 @@
"pocket_read_more": "Cuspairean fèillmhor:", "pocket_read_more": "Cuspairean fèillmhor:",
"pocket_read_even_more": "Seall barrachd sgeul", "pocket_read_even_more": "Seall barrachd sgeul",
"pocket_feedback_header": "Brod an eadar-lìn, air a dheasachadh le barrachd air 25 millean duine.", "pocket_feedback_header": "Brod an eadar-lìn, air a dheasachadh le barrachd air 25 millean duine.",
"pocket_feedback_body": "Pocket, ball de theaghlach Mozilla, a cheanglas tu ri susbaint fhìor-mhath nach biodh tu air fhaicinn air dòigh eile.",
"pocket_send_feedback": "Dè do bheachd air?",
"topstories_empty_state": "Sin na naidheachdan uile o {provider} an-dràsta ach bidh barrachd ann a dhaithghearr. No thoir sùil air cuspair air a bheil fèill mhòr is leugh na tha a dol mun cuairt air an lìon an-dràsta.", "topstories_empty_state": "Sin na naidheachdan uile o {provider} an-dràsta ach bidh barrachd ann a dhaithghearr. No thoir sùil air cuspair air a bheil fèill mhòr is leugh na tha a dol mun cuairt air an lìon an-dràsta.",
"manual_migration_explanation": "Feuch Firefox leis na làraichean is comharran-lìn as fhearr leat o bhrabhsair eile.",
"manual_migration_cancel_button": "Chan eil, tapadh leibh", "manual_migration_cancel_button": "Chan eil, tapadh leibh",
"manual_migration_import_button": "Ion-phortaich an-dràsta" "manual_migration_import_button": "Ion-phortaich an-dràsta"
}, },
@ -3788,8 +3831,8 @@
"kk": { "kk": {
"newtab_page_title": "Жаңа бет", "newtab_page_title": "Жаңа бет",
"default_label_loading": "Жүктелуде…", "default_label_loading": "Жүктелуде…",
"header_top_sites": "Топ сайттар", "header_top_sites": "Үздік сайттар",
"header_stories": "Топ хикаялар", "header_stories": "Үздік хикаялар",
"header_highlights": "Ерекше жаңалықтар", "header_highlights": "Ерекше жаңалықтар",
"header_visit_again": "Қайтадан шолу", "header_visit_again": "Қайтадан шолу",
"header_bookmarks": "Соңғы бетбелгілер", "header_bookmarks": "Соңғы бетбелгілер",
@ -3815,7 +3858,7 @@
"menu_action_unpin": "Бекітуді алып тастау", "menu_action_unpin": "Бекітуді алып тастау",
"confirm_history_delete_p1": "Бұл парақтың барлық кездесулерін шолу тарихыңыздан өшіруді қалайсыз ба?", "confirm_history_delete_p1": "Бұл парақтың барлық кездесулерін шолу тарихыңыздан өшіруді қалайсыз ба?",
"confirm_history_delete_notice_p2": "Бұл әрекетті болдырмау мүмкін болмайды.", "confirm_history_delete_notice_p2": "Бұл әрекетті болдырмау мүмкін болмайды.",
"menu_action_save_to_pocket": "Pocketе сақтау", "menu_action_save_to_pocket": "Pocket ішіне сақтау",
"search_for_something_with": "{search_term} ұғымын көмегімен іздеу:", "search_for_something_with": "{search_term} ұғымын көмегімен іздеу:",
"search_button": "Іздеу", "search_button": "Іздеу",
"search_header": "{search_engine_name} іздеуі", "search_header": "{search_engine_name} іздеуі",
@ -3833,10 +3876,10 @@
"time_label_day": "{number} күн", "time_label_day": "{number} күн",
"settings_pane_button_label": "Жаңа бетті баптаңыз", "settings_pane_button_label": "Жаңа бетті баптаңыз",
"settings_pane_header": "Жаңа бет баптаулары", "settings_pane_header": "Жаңа бет баптаулары",
"settings_pane_body2": "Бұл парақта не көргіңіз келетінді таңдаңыз.", "settings_pane_body2": "Бұл бетте не көргіңіз келетінді таңдаңыз.",
"settings_pane_search_header": "Іздеу", "settings_pane_search_header": "Іздеу",
"settings_pane_search_body": "Жаңа беттен интернеттен іздеңіз.", "settings_pane_search_body": "Жаңа беттен интернеттен іздеңіз.",
"settings_pane_topsites_header": "Топ сайттар", "settings_pane_topsites_header": "Үздік сайттар",
"settings_pane_topsites_body": "Көбірек қаралатын сайттарға қатынау.", "settings_pane_topsites_body": "Көбірек қаралатын сайттарға қатынау.",
"settings_pane_topsites_options_showmore": "Екі жолды көрсету", "settings_pane_topsites_options_showmore": "Екі жолды көрсету",
"settings_pane_bookmarks_header": "Соңғы бетбелгілер", "settings_pane_bookmarks_header": "Соңғы бетбелгілер",
@ -3848,7 +3891,7 @@
"settings_pane_highlights_options_bookmarks": "Бетбелгілер", "settings_pane_highlights_options_bookmarks": "Бетбелгілер",
"settings_pane_highlights_options_visited": "Ашылған сайттар", "settings_pane_highlights_options_visited": "Ашылған сайттар",
"settings_pane_snippets_header": "Үзінділер", "settings_pane_snippets_header": "Үзінділер",
"settings_pane_snippets_body": "Mozillaан Firefox және интернет мәдениеті туралы қысқа жаңалықтарды, және кездейсоқ мемдерді оқыңыз.", "settings_pane_snippets_body": "Mozilla ұсынған Firefox және интернет мәдениеті туралы қысқа жаңалықтарды, және кездейсоқ мемдерді оқыңыз.",
"settings_pane_done_button": "Дайын", "settings_pane_done_button": "Дайын",
"edit_topsites_button_text": "Түзету", "edit_topsites_button_text": "Түзету",
"edit_topsites_button_label": "Топ сайттар санатын баптау", "edit_topsites_button_label": "Топ сайттар санатын баптау",
@ -3874,7 +3917,7 @@
"pocket_description": "Ол болмаса, сіз жіберіп алатын мүмкіндігі бар жоғары сапалы құраманы Pocket көмегімен табыңыз, ол енді Mozilla-ның бөлігі болып табылады.", "pocket_description": "Ол болмаса, сіз жіберіп алатын мүмкіндігі бар жоғары сапалы құраманы Pocket көмегімен табыңыз, ол енді Mozilla-ның бөлігі болып табылады.",
"highlights_empty_state": "Шолуды бастаңыз, сіз жақында шолған немесе бетбелгілерге қосқан тамаша мақалалар, видеолар немесе басқа парақтардың кейбіреулері осында көрсетіледі.", "highlights_empty_state": "Шолуды бастаңыз, сіз жақында шолған немесе бетбелгілерге қосқан тамаша мақалалар, видеолар немесе басқа парақтардың кейбіреулері осында көрсетіледі.",
"topstories_empty_state": "Дайын. {provider} ұсынған көбірек мақалаларды алу үшін кейінірек тексеріңіз. Күте алмайсыз ба? Интернеттен көбірек тамаша мақалаларды алу үшін әйгілі теманы таңдаңыз.", "topstories_empty_state": "Дайын. {provider} ұсынған көбірек мақалаларды алу үшін кейінірек тексеріңіз. Күте алмайсыз ба? Интернеттен көбірек тамаша мақалаларды алу үшін әйгілі теманы таңдаңыз.",
"manual_migration_explanation2": "Firefox-ты басқа браузер бетбелгілері, тарихы және парольдерімен қолданып көріңіз.", "manual_migration_explanation2": "Firefox қолданбасын басқа браузер бетбелгілері, тарихы және парольдерімен қолданып көріңіз.",
"manual_migration_cancel_button": "Жоқ, рахмет", "manual_migration_cancel_button": "Жоқ, рахмет",
"manual_migration_import_button": "Қазір импорттау" "manual_migration_import_button": "Қазір импорттау"
}, },
@ -4203,13 +4246,15 @@
"manual_migration_import_button": "Importuoti dabar" "manual_migration_import_button": "Importuoti dabar"
}, },
"lv": { "lv": {
"newtab_page_title": "Jauna cilne" "newtab_page_title": "Jauna cilne",
"default_label_loading": "Notiek ielāde…"
}, },
"mk": { "mk": {
"newtab_page_title": "Ново јазиче", "newtab_page_title": "Ново јазиче",
"default_label_loading": "Се вчитува…", "default_label_loading": "Се вчитува…",
"header_top_sites": "Врвни мрежни места", "header_top_sites": "Популарни мрежни места",
"header_stories": "Врвни написи", "header_stories": "Популарни написи",
"header_highlights": "Интереси",
"header_visit_again": "Посети повторно", "header_visit_again": "Посети повторно",
"header_bookmarks": "Скорешни обележувачи", "header_bookmarks": "Скорешни обележувачи",
"header_recommended_by": "Препорачано од {provider}", "header_recommended_by": "Препорачано од {provider}",
@ -4232,7 +4277,7 @@
"menu_action_delete": "Избриши од историја", "menu_action_delete": "Избриши од историја",
"menu_action_pin": "Прикачи", "menu_action_pin": "Прикачи",
"menu_action_unpin": "Откачи", "menu_action_unpin": "Откачи",
"confirm_history_delete_p1": "Дали сте сигурни дека сакате да ја избришете оваа страница отсекаде во Вашата историја на прелистување?", "confirm_history_delete_p1": "Дали сте сигурни дека сакате да ја избришете оваа страница отсекаде во вашата историја на прелистување?",
"confirm_history_delete_notice_p2": "Ова дејство не може да се одврати.", "confirm_history_delete_notice_p2": "Ова дејство не може да се одврати.",
"menu_action_save_to_pocket": "Зачувај во Pocket", "menu_action_save_to_pocket": "Зачувај во Pocket",
"search_for_something_with": "Пребарај за {search_term} со:", "search_for_something_with": "Пребарај за {search_term} со:",
@ -4241,30 +4286,36 @@
"search_web_placeholder": "Пребарајте на Интернет", "search_web_placeholder": "Пребарајте на Интернет",
"search_settings": "Промени поставувања за пребарување", "search_settings": "Промени поставувања за пребарување",
"section_info_option": "Инфо", "section_info_option": "Инфо",
"section_info_send_feedback": "Испрати мислење",
"section_info_privacy_notice": "Белешка за приватност",
"welcome_title": "Добредојдовте во новото јазиче", "welcome_title": "Добредојдовте во новото јазиче",
"welcome_body": "Firefox ќе го искористи овој простор за да Ви ги прикаже најрелевантните обележувачи, написи, видеа и страници што сте ги посетиле, за да можете лесно да им се навратите.", "welcome_body": "Firefox ќе го искористи овој простор за да Ви ги прикаже најрелевантните обележувачи, написи, видеа и страници што сте ги посетиле, за да можете лесно да им се навратите.",
"welcome_label": "Ги откривам Вашите интереси", "welcome_label": "Ги откривам вашите Интереси",
"time_label_less_than_minute": "< 1 м", "time_label_less_than_minute": "< 1 м",
"time_label_minute": "{number} м", "time_label_minute": "{number} м",
"time_label_hour": "{number} ч", "time_label_hour": "{number} ч",
"time_label_day": "{number} д", "time_label_day": "{number} д",
"settings_pane_button_label": "Прилагодете ја страницата на Вашето Ново јазиче", "settings_pane_button_label": "Прилагодете ја страницата на вашето Ново јазиче",
"settings_pane_header": "Преференци за Ново јазиче", "settings_pane_header": "Преференци за Ново јазиче",
"settings_pane_body": "Изберете што ќе гледате кога ќе отворите ново јазиче.", "settings_pane_body2": "Изберете што ќе гледате на оваа страница.",
"settings_pane_search_header": "Пребарување", "settings_pane_search_header": "Пребарување",
"settings_pane_search_body": "Пребарајте низ Интернет од Вашето ново јазиче.", "settings_pane_search_body": "Пребарајте низ Интернет од вашето ново јазиче.",
"settings_pane_topsites_header": "Врвни мрежни места", "settings_pane_topsites_header": "Врвни мрежни места",
"settings_pane_topsites_body": "Пристапете до мрежните места што ги посетувате најмногу.", "settings_pane_topsites_body": "Пристапете до мрежните места што ги посетувате најмногу.",
"settings_pane_topsites_options_showmore": "Прикажи два реда", "settings_pane_topsites_options_showmore": "Прикажи два реда",
"settings_pane_bookmarks_header": "Скорешни обележувачи", "settings_pane_bookmarks_header": "Скорешни обележувачи",
"settings_pane_bookmarks_body": "Вашите нови обележувачи во едно згодно место.", "settings_pane_bookmarks_body": "Вашите нови обележувачи во едно згодно место.",
"settings_pane_visit_again_header": "Посети повторно", "settings_pane_visit_again_header": "Посети повторно",
"settings_pane_visit_again_body": "Firefox ќе прикаже делови од Вашата историја на прелистување кои можеби би сакале да ги запомните или пак да им се навратите.", "settings_pane_visit_again_body": "Firefox ќе прикаже делови од вашата историја на прелистување кои можеби би сакале да ги запомните или пак да им се навратите.",
"settings_pane_pocketstories_header": "Врвни написи", "settings_pane_highlights_header": "Интереси",
"settings_pane_pocketstories_body": "Pocket, дел од семејството на Mozilla, ќе Ви помогне да стигнете до високо-квалитетни содржини кои можеби не би ги откриле на друг начин.", "settings_pane_highlights_body2": "Навратете се на интересни места што неодамна сте ги посетиле или обележале.",
"settings_pane_highlights_options_bookmarks": "Обележувачи",
"settings_pane_highlights_options_visited": "Посетени мрежни места",
"settings_pane_snippets_header": "Исечоци",
"settings_pane_snippets_body": "Прочитајте кратки и слатки новости од Mozilla во врска со Firefox, Интернет-културата и повремените случајни меми.",
"settings_pane_done_button": "Готово", "settings_pane_done_button": "Готово",
"edit_topsites_button_text": "Уреди", "edit_topsites_button_text": "Уреди",
"edit_topsites_button_label": "Прилагодете ги Вашите Врвни мрежни места", "edit_topsites_button_label": "Прилагодете ги вашите Популарни мрежни места",
"edit_topsites_showmore_button": "Прикажи повеќе", "edit_topsites_showmore_button": "Прикажи повеќе",
"edit_topsites_showless_button": "Прикажи помалку", "edit_topsites_showless_button": "Прикажи помалку",
"edit_topsites_done_button": "Готово", "edit_topsites_done_button": "Готово",
@ -4284,10 +4335,10 @@
"pocket_read_more": "Популарни теми:", "pocket_read_more": "Популарни теми:",
"pocket_read_even_more": "Види повеќе написи", "pocket_read_even_more": "Види повеќе написи",
"pocket_feedback_header": "Најдоброто од Интернет, одбрано од повеќе од 25 милиони луѓе.", "pocket_feedback_header": "Најдоброто од Интернет, одбрано од повеќе од 25 милиони луѓе.",
"pocket_feedback_body": "Pocket, дел од семејството на Mozilla, ќе Ви помогне да стигнете до високо-квалитетни содржини кои можеби не би ги откриле на друг начин.", "pocket_description": "Откријте високо-квалитетни содржини, коишто инаку би можеле да ги пропуштите, со помош на Pocket, кој сега е дел од Mozilla.",
"pocket_send_feedback": "Остави коментар", "highlights_empty_state": "Започнете со прелистување и ние овде ќе ви прикажеме некои од одличните написи, видеа и други страници што неодамна сте ги поселите или обележале.",
"topstories_empty_state": "Имате видено сѐ! Навратете се подоцна за нови содржини од {provider}. Не можете да чекате? Изберете популарна тема и откријте уште одлични содржини ширум Интернет.", "topstories_empty_state": "Имате видено сѐ! Навратете се подоцна за нови содржини од {provider}. Не можете да чекате? Изберете популарна тема и откријте уште одлични содржини ширум Интернет.",
"manual_migration_explanation": "Пробајте го Firefox со Вашите омилени мрежни места и обележувачи од друг прелистувач.", "manual_migration_explanation2": "Пробајте го Firefox со обележувачите, историјата и лозинките на друг прелистувач.",
"manual_migration_cancel_button": "Не, благодарам", "manual_migration_cancel_button": "Не, благодарам",
"manual_migration_import_button": "Увези сега" "manual_migration_import_button": "Увези сега"
}, },
@ -6092,7 +6143,7 @@
"header_stories": "เรื่องราวเด่น", "header_stories": "เรื่องราวเด่น",
"header_highlights": "รายการเด่น", "header_highlights": "รายการเด่น",
"header_visit_again": "เยี่ยมชมอีกครั้ง", "header_visit_again": "เยี่ยมชมอีกครั้ง",
"header_bookmarks": "ที่คั่นหน้าเมื่อเร็ว ๆ นี้", "header_bookmarks": "ที่คั่นหน้าล่าสุด",
"header_recommended_by": "แนะนำโดย {provider}", "header_recommended_by": "แนะนำโดย {provider}",
"header_bookmarks_placeholder": "คุณยังไม่มีที่คั่นหน้าใด ๆ", "header_bookmarks_placeholder": "คุณยังไม่มีที่คั่นหน้าใด ๆ",
"header_stories_from": "จาก", "header_stories_from": "จาก",
@ -6139,7 +6190,7 @@
"settings_pane_topsites_header": "ไซต์เด่น", "settings_pane_topsites_header": "ไซต์เด่น",
"settings_pane_topsites_body": "เข้าถึงเว็บไซต์ที่คุณเยี่ยมชมมากที่สุด", "settings_pane_topsites_body": "เข้าถึงเว็บไซต์ที่คุณเยี่ยมชมมากที่สุด",
"settings_pane_topsites_options_showmore": "แสดงสองแถว", "settings_pane_topsites_options_showmore": "แสดงสองแถว",
"settings_pane_bookmarks_header": "ที่คั่นหน้าเมื่อเร็ว ๆ นี้", "settings_pane_bookmarks_header": "ที่คั่นหน้าล่าสุด",
"settings_pane_bookmarks_body": "ที่คั่นหน้าที่สร้างใหม่ของคุณในตำแหน่งที่ตั้งเดียวที่สะดวก", "settings_pane_bookmarks_body": "ที่คั่นหน้าที่สร้างใหม่ของคุณในตำแหน่งที่ตั้งเดียวที่สะดวก",
"settings_pane_visit_again_header": "เยี่ยมชมอีกครั้ง", "settings_pane_visit_again_header": "เยี่ยมชมอีกครั้ง",
"settings_pane_highlights_header": "รายการเด่น", "settings_pane_highlights_header": "รายการเด่น",
@ -6617,8 +6668,8 @@
"settings_pane_highlights_body2": "根据您最近访问的页面和添加的书签推荐您感兴趣的东西。", "settings_pane_highlights_body2": "根据您最近访问的页面和添加的书签推荐您感兴趣的东西。",
"settings_pane_highlights_options_bookmarks": "书签", "settings_pane_highlights_options_bookmarks": "书签",
"settings_pane_highlights_options_visited": "访问过的网站", "settings_pane_highlights_options_visited": "访问过的网站",
"settings_pane_snippets_header": "板报", "settings_pane_snippets_header": "只言片语",
"settings_pane_snippets_body": "阅读和了解 Mozilla 就 Firefox、互联网文化等提供的一些简短而有趣的更新。", "settings_pane_snippets_body": "阅读 Mozilla 就 Firefox、互联网文化、偶尔还有模因提供的一些简短而有趣的小文章。",
"settings_pane_done_button": "完成", "settings_pane_done_button": "完成",
"edit_topsites_button_text": "编辑", "edit_topsites_button_text": "编辑",
"edit_topsites_button_label": "定制您的“常用网站”区域", "edit_topsites_button_label": "定制您的“常用网站”区域",
@ -6641,7 +6692,7 @@
"pocket_read_more": "热门主题:", "pocket_read_more": "热门主题:",
"pocket_read_even_more": "查看更多文章", "pocket_read_even_more": "查看更多文章",
"pocket_feedback_header": "由超过 2500 万人挑选出来的网上精华内容。", "pocket_feedback_header": "由超过 2500 万人挑选出来的网上精华内容。",
"pocket_description": "借助 Pocket目前所属 Mozilla发现有趣的高品质内容。", "pocket_description": "借助 Pocket目前属 Mozilla 旗下)发现您不容错过的高品质内容。",
"highlights_empty_state": "开始浏览旅程吧,之后这里会显示您最近看过或加了书签的精彩文章、视频以及其他页面。", "highlights_empty_state": "开始浏览旅程吧,之后这里会显示您最近看过或加了书签的精彩文章、视频以及其他页面。",
"topstories_empty_state": "所有文章都读完啦!晚点再来,{provider} 将推荐更多热门文章。等不及了?选择一个热门话题,找到更多网上的好文章。", "topstories_empty_state": "所有文章都读完啦!晚点再来,{provider} 将推荐更多热门文章。等不及了?选择一个热门话题,找到更多网上的好文章。",
"manual_migration_explanation2": "把在其他浏览器中保存的书签、历史记录和密码带到 Firefox 吧。", "manual_migration_explanation2": "把在其他浏览器中保存的书签、历史记录和密码带到 Firefox 吧。",
@ -6733,8 +6784,8 @@
"topsites_form_url_validation": "請輸入有效的網址", "topsites_form_url_validation": "請輸入有效的網址",
"pocket_read_more": "熱門主題:", "pocket_read_more": "熱門主題:",
"pocket_read_even_more": "檢視更多文章", "pocket_read_even_more": "檢視更多文章",
"pocket_feedback_header": "由超過兩千五百萬人找出來的 Web 最佳內容。", "pocket_feedback_header": "超過兩千五百萬人共同探索出的 Web 最佳內容。",
"pocket_description": "透過現在也是 Mozilla 旗下一員的 Pocket 的幫助,發現您先前可能錯過的高品質內容。", "pocket_description": "透過 Mozilla 旗下的 Pocket 服務,發現您可能錯過的優質內容。",
"highlights_empty_state": "開始上網,我們就會把您在網路上發現的好文章、影片、剛加入書籤的頁面顯示於此。", "highlights_empty_state": "開始上網,我們就會把您在網路上發現的好文章、影片、剛加入書籤的頁面顯示於此。",
"topstories_empty_state": "所有文章都讀完啦!晚點再來,{provider} 將提供更多推薦故事。等不及了?選擇熱門主題,看看 Web 上各式精采資訊。", "topstories_empty_state": "所有文章都讀完啦!晚點再來,{provider} 將提供更多推薦故事。等不及了?選擇熱門主題,看看 Web 上各式精采資訊。",
"manual_migration_explanation2": "試試將其他瀏覽器的書籤、瀏覽記錄與密碼匯入 Firefox。", "manual_migration_explanation2": "試試將其他瀏覽器的書籤、瀏覽記錄與密碼匯入 Firefox。",

Просмотреть файл

@ -8,7 +8,7 @@
<em:type>2</em:type> <em:type>2</em:type>
<em:bootstrap>true</em:bootstrap> <em:bootstrap>true</em:bootstrap>
<em:unpack>false</em:unpack> <em:unpack>false</em:unpack>
<em:version>2017.09.22.1389-2ee94db4</em:version> <em:version>2017.09.28.0954-66ebf91c</em:version>
<em:name>Activity Stream</em:name> <em:name>Activity Stream</em:name>
<em:description>A rich visual history feed and a reimagined home page make it easier than ever to find exactly what you're looking for in Firefox.</em:description> <em:description>A rich visual history feed and a reimagined home page make it easier than ever to find exactly what you're looking for in Firefox.</em:description>
<em:multiprocessCompatible>true</em:multiprocessCompatible> <em:multiprocessCompatible>true</em:multiprocessCompatible>

Просмотреть файл

@ -160,7 +160,7 @@ this.HighlightsFeed = class HighlightsFeed {
break; break;
case at.MIGRATION_COMPLETED: case at.MIGRATION_COMPLETED:
case at.PLACES_HISTORY_CLEARED: case at.PLACES_HISTORY_CLEARED:
case at.PLACES_LINK_DELETED: case at.PLACES_LINKS_DELETED:
case at.PLACES_LINK_BLOCKED: case at.PLACES_LINK_BLOCKED:
this.fetchHighlights(true); this.fetchHighlights(true);
break; break;

Просмотреть файл

@ -42,11 +42,24 @@ class HistoryObserver extends Observer {
* @param {obj} uri A URI object representing the link's url * @param {obj} uri A URI object representing the link's url
* {str} uri.spec The URI as a string * {str} uri.spec The URI as a string
*/ */
onDeleteURI(uri) { async onDeleteURI(uri) {
this.dispatch({ // Add to an existing array of links if we haven't dispatched yet
type: at.PLACES_LINK_DELETED, const {spec} = uri;
data: {url: uri.spec} if (this._deletedLinks) {
}); this._deletedLinks.push(spec);
} else {
// Store an array of synchronously deleted links
this._deletedLinks = [spec];
// Only dispatch a single action when we've gotten all deleted urls
await Promise.resolve().then(() => {
this.dispatch({
type: at.PLACES_LINKS_DELETED,
data: this._deletedLinks
});
delete this._deletedLinks;
});
}
} }
/** /**

Просмотреть файл

@ -8,6 +8,9 @@ const {utils: Cu} = Components;
const {actionCreators: ac, actionTypes: at} = Cu.import("resource://activity-stream/common/Actions.jsm", {}); const {actionCreators: ac, actionTypes: at} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
const {Prefs} = Cu.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm", {}); const {Prefs} = Cu.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm", {});
const {PrerenderData} = Cu.import("resource://activity-stream/common/PrerenderData.jsm", {}); const {PrerenderData} = Cu.import("resource://activity-stream/common/PrerenderData.jsm", {});
Cu.import("resource://gre/modules/Services.jsm");
const ONBOARDING_FINISHED_PREF = "browser.onboarding.notification.finished";
this.PrefsFeed = class PrefsFeed { this.PrefsFeed = class PrefsFeed {
constructor(prefMap) { constructor(prefMap) {
@ -27,11 +30,30 @@ this.PrefsFeed = class PrefsFeed {
} }
} }
_initOnboardingPref() {
const snippetsEnabled = this._prefs.get("feeds.snippets");
if (!snippetsEnabled) {
this.setOnboardingDisabledDefault(true);
}
}
setOnboardingDisabledDefault(value) {
const branch = Services.prefs.getDefaultBranch("");
branch.setBoolPref(ONBOARDING_FINISHED_PREF, value);
}
onPrefChanged(name, value) { onPrefChanged(name, value) {
if (this._prefMap.has(name)) { if (this._prefMap.has(name)) {
this.store.dispatch(ac.BroadcastToContent({type: at.PREF_CHANGED, data: {name, value}})); this.store.dispatch(ac.BroadcastToContent({type: at.PREF_CHANGED, data: {name, value}}));
} }
this._checkPrerender(name); this._checkPrerender(name);
if (name === "feeds.snippets") {
// If snippets are disabled, onboarding notifications should also be
// disabled because they look like snippets.
this.setOnboardingDisabledDefault(!value);
}
} }
init() { init() {
@ -47,6 +69,7 @@ this.PrefsFeed = class PrefsFeed {
this.store.dispatch(ac.BroadcastToContent({type: at.PREFS_INITIAL_VALUES, data: values})); this.store.dispatch(ac.BroadcastToContent({type: at.PREFS_INITIAL_VALUES, data: values}));
this._setPrerenderPref(); this._setPrerenderPref();
this._initOnboardingPref();
} }
removeListeners() { removeListeners() {
this._prefs.ignoreBranch(this); this._prefs.ignoreBranch(this);
@ -58,10 +81,14 @@ this.PrefsFeed = class PrefsFeed {
break; break;
case at.UNINIT: case at.UNINIT:
this.removeListeners(); this.removeListeners();
this.setOnboardingDisabledDefault(false);
break; break;
case at.SET_PREF: case at.SET_PREF:
this._prefs.set(action.data.name, action.data.value); this._prefs.set(action.data.name, action.data.value);
break; break;
case at.DISABLE_ONBOARDING:
this.setOnboardingDisabledDefault(true);
break;
} }
} }
}; };

Просмотреть файл

@ -17,8 +17,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "ProfileAge",
// Url to fetch snippets, in the urlFormatter service format. // Url to fetch snippets, in the urlFormatter service format.
const SNIPPETS_URL_PREF = "browser.aboutHomeSnippets.updateUrl"; const SNIPPETS_URL_PREF = "browser.aboutHomeSnippets.updateUrl";
const TELEMETRY_PREF = "datareporting.healthreport.uploadEnabled"; const TELEMETRY_PREF = "datareporting.healthreport.uploadEnabled";
const ONBOARDING_FINISHED_PREF = "browser.onboarding.notification.finished";
const FXA_USERNAME_PREF = "services.sync.username"; const FXA_USERNAME_PREF = "services.sync.username";
const ONBOARDING_FINISHED_PREF = "browser.onboarding.notification.finished";
// Prefix for any target matching a search engine. // Prefix for any target matching a search engine.
const TARGET_SEARCHENGINE_PREFIX = "searchEngine-"; const TARGET_SEARCHENGINE_PREFIX = "searchEngine-";

Просмотреть файл

@ -21,6 +21,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
"@mozilla.org/uuid-generator;1", "@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator"); "nsIUUIDGenerator");
const ACTIVITY_STREAM_ID = "activity-stream";
const ACTIVITY_STREAM_ENDPOINT_PREF = "browser.newtabpage.activity-stream.telemetry.ping.endpoint"; const ACTIVITY_STREAM_ENDPOINT_PREF = "browser.newtabpage.activity-stream.telemetry.ping.endpoint";
// This is a mapping table between the user preferences and its encoding code // This is a mapping table between the user preferences and its encoding code
@ -160,12 +161,10 @@ this.TelemetryFeed = class TelemetryFeed {
* Lazily initialize PingCentre to send pings * Lazily initialize PingCentre to send pings
*/ */
get pingCentre() { get pingCentre() {
const ACTIVITY_STREAM_ID = "activity-stream";
Object.defineProperty(this, "pingCentre", Object.defineProperty(this, "pingCentre",
{ {
value: new PingCentre({ value: new PingCentre({
topic: ACTIVITY_STREAM_ID, topic: ACTIVITY_STREAM_ID,
filter: ACTIVITY_STREAM_ID,
overrideEndpointPref: ACTIVITY_STREAM_ENDPOINT_PREF overrideEndpointPref: ACTIVITY_STREAM_ENDPOINT_PREF
}) })
}); });
@ -363,7 +362,8 @@ this.TelemetryFeed = class TelemetryFeed {
async sendEvent(event_object) { async sendEvent(event_object) {
if (this.telemetryEnabled) { if (this.telemetryEnabled) {
this.pingCentre.sendPing(event_object); this.pingCentre.sendPing(event_object,
{filter: ACTIVITY_STREAM_ID});
} }
} }

Просмотреть файл

@ -264,8 +264,8 @@ this.TopSitesFeed = class TopSitesFeed {
// All these actions mean we need new top sites // All these actions mean we need new top sites
case at.MIGRATION_COMPLETED: case at.MIGRATION_COMPLETED:
case at.PLACES_HISTORY_CLEARED: case at.PLACES_HISTORY_CLEARED:
case at.PLACES_LINK_DELETED:
case at.PLACES_LINK_BLOCKED: case at.PLACES_LINK_BLOCKED:
case at.PLACES_LINKS_DELETED:
this.frecentCache.expire(); this.frecentCache.expire();
this.refresh(); this.refresh();
break; break;

Просмотреть файл

@ -358,13 +358,22 @@ describe("Reducers", () => {
}); });
it("should remove blocked and deleted urls from all rows in all sections", () => { it("should remove blocked and deleted urls from all rows in all sections", () => {
const blockAction = {type: at.PLACES_LINK_BLOCKED, data: {url: "www.foo.bar"}}; const blockAction = {type: at.PLACES_LINK_BLOCKED, data: {url: "www.foo.bar"}};
const deleteAction = {type: at.PLACES_LINK_DELETED, data: {url: "www.foo.bar"}}; const deleteAction = {type: at.PLACES_LINKS_DELETED, data: ["www.foo.bar"]};
const newBlockState = Sections(oldState, blockAction); const newBlockState = Sections(oldState, blockAction);
const newDeleteState = Sections(oldState, deleteAction); const newDeleteState = Sections(oldState, deleteAction);
newBlockState.concat(newDeleteState).forEach(section => { newBlockState.concat(newDeleteState).forEach(section => {
assert.deepEqual(section.rows, [{url: "www.other.url"}]); assert.deepEqual(section.rows, [{url: "www.other.url"}]);
}); });
}); });
it("should remove all deleted urls", () => {
const deleteAction = {type: at.PLACES_LINKS_DELETED, data: ["www.foo.bar", "www.other.url"]};
const newState = Sections(oldState, deleteAction);
newState.forEach(section => {
assert.lengthOf(section.rows, 0);
});
});
it("should not update state for empty action.data on PLACES_BOOKMARK_ADDED", () => { it("should not update state for empty action.data on PLACES_BOOKMARK_ADDED", () => {
const nextState = Sections(undefined, {type: at.PLACES_BOOKMARK_ADDED}); const nextState = Sections(undefined, {type: at.PLACES_BOOKMARK_ADDED});
assert.equal(nextState, INITIAL_STATE.Sections); assert.equal(nextState, INITIAL_STATE.Sections);

Просмотреть файл

@ -296,10 +296,10 @@ describe("Highlights Feed", () => {
assert.calledOnce(feed.fetchHighlights); assert.calledOnce(feed.fetchHighlights);
assert.calledWith(feed.fetchHighlights, true); assert.calledWith(feed.fetchHighlights, true);
}); });
it("should fetch highlights on PLACES_LINK_DELETED", async () => { it("should fetch highlights on PLACES_LINKS_DELETED", async () => {
await feed.fetchHighlights(); await feed.fetchHighlights();
feed.fetchHighlights = sinon.spy(); feed.fetchHighlights = sinon.spy();
feed.onAction({type: at.PLACES_LINK_DELETED}); feed.onAction({type: at.PLACES_LINKS_DELETED});
assert.calledOnce(feed.fetchHighlights); assert.calledOnce(feed.fetchHighlights);
assert.calledWith(feed.fetchHighlights, true); assert.calledWith(feed.fetchHighlights, true);
}); });

Просмотреть файл

@ -179,9 +179,20 @@ describe("PlacesFeed", () => {
assert.property(observer, "QueryInterface"); assert.property(observer, "QueryInterface");
}); });
describe("#onDeleteURI", () => { describe("#onDeleteURI", () => {
it("should dispatch a PLACES_LINK_DELETED action with the right url", () => { it("should dispatch a PLACES_LINKS_DELETED action with the right url", async() => {
await observer.onDeleteURI({spec: "foo.com"});
assert.calledWith(dispatch, {type: at.PLACES_LINKS_DELETED, data: ["foo.com"]});
});
it("should dispatch a PLACES_LINKS_DELETED action with multiple urls", async() => {
const promise = observer.onDeleteURI({spec: "bar.com"});
observer.onDeleteURI({spec: "foo.com"}); observer.onDeleteURI({spec: "foo.com"});
assert.calledWith(dispatch, {type: at.PLACES_LINK_DELETED, data: {url: "foo.com"}}); await promise;
const result = dispatch.firstCall.args[0].data;
assert.lengthOf(result, 2);
assert.equal(result[0], "bar.com");
assert.equal(result[1], "foo.com");
}); });
}); });
describe("#onClearHistory", () => { describe("#onClearHistory", () => {

Просмотреть файл

@ -4,6 +4,7 @@ const {PrerenderData} = require("common/PrerenderData.jsm");
const {initialPrefs} = PrerenderData; const {initialPrefs} = PrerenderData;
const PRERENDER_PREF_NAME = "prerender"; const PRERENDER_PREF_NAME = "prerender";
const ONBOARDING_FINISHED_PREF = "browser.onboarding.notification.finished";
describe("PrefsFeed", () => { describe("PrefsFeed", () => {
let feed; let feed;
@ -62,6 +63,44 @@ describe("PrefsFeed", () => {
assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME, false); assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME, false);
}); });
}); });
describe("Onboarding", () => {
let sandbox;
let defaultBranch;
beforeEach(() => {
sandbox = sinon.sandbox.create();
defaultBranch = {setBoolPref: sandbox.stub()};
sandbox.stub(global.Services.prefs, "getDefaultBranch").returns(defaultBranch);
});
afterEach(() => {
sandbox.restore();
});
it("should set ONBOARDING_FINISHED_PREF to true if prefs.feeds.snippets if false", () => {
FAKE_PREFS.set("feeds.snippets", false);
feed.onAction({type: at.INIT});
assert.calledWith(defaultBranch.setBoolPref, ONBOARDING_FINISHED_PREF, true);
});
it("should not set ONBOARDING_FINISHED_PREF if prefs.feeds.snippets is true", () => {
FAKE_PREFS.set("feeds.snippets", true);
feed.onAction({type: at.INIT});
assert.notCalled(defaultBranch.setBoolPref);
});
it("should set ONBOARDING_FINISHED_PREF to true if the feeds.snippets pref changes to false", () => {
feed.onPrefChanged("feeds.snippets", false);
assert.calledWith(defaultBranch.setBoolPref, ONBOARDING_FINISHED_PREF, true);
});
it("should set ONBOARDING_FINISHED_PREF to false if the feeds.snippets pref changes to true", () => {
feed.onPrefChanged("feeds.snippets", true);
assert.calledWith(defaultBranch.setBoolPref, ONBOARDING_FINISHED_PREF, false);
});
it("should not set ONBOARDING_FINISHED_PREF if an unrelated pref changes", () => {
feed.onPrefChanged("foo", true);
assert.notCalled(defaultBranch.setBoolPref);
});
it("should set ONBOARDING_FINISHED_PREF to true if a DISABLE_ONBOARDING action was received", () => {
feed.onAction({type: at.DISABLE_ONBOARDING});
assert.calledWith(defaultBranch.setBoolPref, ONBOARDING_FINISHED_PREF, true);
});
});
describe("onPrefChanged prerendering", () => { describe("onPrefChanged prerendering", () => {
it("should not change the prerender pref if the pref is not included in invalidatingPrefs", () => { it("should not change the prerender pref if the pref is not included in invalidatingPrefs", () => {
feed.onPrefChanged("foo123", true); feed.onPrefChanged("foo123", true);

Просмотреть файл

@ -507,9 +507,9 @@ describe("Top Sites Feed", () => {
assert.calledOnce(feed.refresh); assert.calledOnce(feed.refresh);
assert.equal(feed.refresh.firstCall.args[0], null); assert.equal(feed.refresh.firstCall.args[0], null);
}); });
it("should call refresh without a target on PLACES_LINK_DELETED action", async () => { it("should call refresh without a target on PLACES_LINKS_DELETED action", async () => {
sinon.stub(feed, "refresh"); sinon.stub(feed, "refresh");
await feed.onAction({type: at.PLACES_LINK_DELETED}); await feed.onAction({type: at.PLACES_LINKS_DELETED});
assert.calledOnce(feed.refresh); assert.calledOnce(feed.refresh);
assert.equal(feed.refresh.firstCall.args[0], null); assert.equal(feed.refresh.firstCall.args[0], null);
}); });

Просмотреть файл

@ -27,6 +27,8 @@ overrider.set({
ContentSearchUIController: function() {}, // NB: This is a function/constructor ContentSearchUIController: function() {}, // NB: This is a function/constructor
dump() {}, dump() {},
fetch() {}, fetch() {},
// eslint-disable-next-line object-shorthand
Image: function() {}, // NB: This is a function/constructor
Preferences: FakePrefs, Preferences: FakePrefs,
Services: { Services: {
locale: { locale: {

Просмотреть файл

@ -8,7 +8,7 @@
<em:type>2</em:type> <em:type>2</em:type>
<em:bootstrap>true</em:bootstrap> <em:bootstrap>true</em:bootstrap>
<em:unpack>false</em:unpack> <em:unpack>false</em:unpack>
<em:version>73</em:version> <em:version>76</em:version>
<em:name>Shield Recipe Client</em:name> <em:name>Shield Recipe Client</em:name>
<em:description>Client to download and run recipes for SHIELD, Heartbeat, etc.</em:description> <em:description>Client to download and run recipes for SHIELD, Heartbeat, etc.</em:description>
<em:multiprocessCompatible>true</em:multiprocessCompatible> <em:multiprocessCompatible>true</em:multiprocessCompatible>

Просмотреть файл

@ -12,6 +12,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ShellService", "resource:///modules/ShellService.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ShellService", "resource:///modules/ShellService.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryArchive", "resource://gre/modules/TelemetryArchive.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "TelemetryArchive", "resource://gre/modules/TelemetryArchive.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils", "resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NormandyApi", "resource://shield-recipe-client/lib/NormandyApi.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NormandyApi", "resource://shield-recipe-client/lib/NormandyApi.jsm");
XPCOMUtils.defineLazyModuleGetter( XPCOMUtils.defineLazyModuleGetter(
this, this,
@ -107,7 +108,7 @@ this.ClientEnvironment = {
const mostRecentPings = {}; const mostRecentPings = {};
for (const ping of pings) { for (const ping of pings) {
if (ping.type in mostRecentPings) { if (ping.type in mostRecentPings) {
if (mostRecentPings[ping.type].timeStampCreated < ping.timeStampCreated) { if (mostRecentPings[ping.type].timestampCreated < ping.timestampCreated) {
mostRecentPings[ping.type] = ping; mostRecentPings[ping.type] = ping;
} }
} else { } else {
@ -128,7 +129,7 @@ this.ClientEnvironment = {
}); });
XPCOMUtils.defineLazyGetter(environment, "channel", () => { XPCOMUtils.defineLazyGetter(environment, "channel", () => {
return Services.appinfo.defaultUpdateChannel; return UpdateUtils.getUpdateChannel(false);
}); });
XPCOMUtils.defineLazyGetter(environment, "isDefaultBrowser", () => { XPCOMUtils.defineLazyGetter(environment, "isDefaultBrowser", () => {

Просмотреть файл

@ -21,6 +21,7 @@ Cu.import("resource://shield-recipe-client/lib/ClientEnvironment.jsm");
Cu.import("resource://shield-recipe-client/lib/PreferenceExperiments.jsm"); Cu.import("resource://shield-recipe-client/lib/PreferenceExperiments.jsm");
Cu.import("resource://shield-recipe-client/lib/Sampling.jsm"); Cu.import("resource://shield-recipe-client/lib/Sampling.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils", "resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyModuleGetter( XPCOMUtils.defineLazyModuleGetter(
this, "AddonStudies", "resource://shield-recipe-client/lib/AddonStudies.jsm"); this, "AddonStudies", "resource://shield-recipe-client/lib/AddonStudies.jsm");
@ -82,7 +83,7 @@ this.NormandyDriver = function(sandboxManager) {
client() { client() {
const appinfo = { const appinfo = {
version: Services.appinfo.version, version: Services.appinfo.version,
channel: Services.appinfo.defaultUpdateChannel, channel: UpdateUtils.getUpdateChannel(false),
isDefaultBrowser: ShellService.isDefaultBrowser() || null, isDefaultBrowser: ShellService.isDefaultBrowser() || null,
searchEngine: null, searchEngine: null,
syncSetup: Preferences.isSet("services.sync.username"), syncSetup: Preferences.isSet("services.sync.username"),

Просмотреть файл

@ -12,6 +12,7 @@ add_task(async function testTelemetry() {
// setup // setup
await TelemetryController.submitExternalPing("testfoo", {foo: 1}); await TelemetryController.submitExternalPing("testfoo", {foo: 1});
await TelemetryController.submitExternalPing("testbar", {bar: 2}); await TelemetryController.submitExternalPing("testbar", {bar: 2});
await TelemetryController.submitExternalPing("testfoo", {foo: 3});
const environment = ClientEnvironment.getEnvironment(); const environment = ClientEnvironment.getEnvironment();
// Test it can access telemetry // Test it can access telemetry
@ -19,8 +20,8 @@ add_task(async function testTelemetry() {
is(typeof telemetry, "object", "Telemetry is accesible"); is(typeof telemetry, "object", "Telemetry is accesible");
// Test it reads different types of telemetry // Test it reads different types of telemetry
is(telemetry.testfoo.payload.foo, 1, "value 'foo' is in mock telemetry"); is(telemetry.testfoo.payload.foo, 3, "telemetry filters pull the latest ping from a type");
is(telemetry.testbar.payload.bar, 2, "value 'bar' is in mock telemetry"); is(telemetry.testbar.payload.bar, 2, "telemetry filters pull from submitted telemetry pings");
}); });
add_task(async function testUserId() { add_task(async function testUserId() {

Просмотреть файл

@ -1,35 +1,24 @@
fbjs@0.8.12 BSD-3-Clause fbjs@0.8.16 MIT
BSD License MIT License
For fbjs software
Copyright (c) 2013-present, Facebook, Inc. Copyright (c) 2013-present, Facebook, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Permission is hereby granted, free of charge, to any person obtaining a copy of
are permitted provided that the following conditions are met: this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
* Redistributions of source code must retain the above copyright notice, this The above copyright notice and this permission notice shall be included in all
list of conditions and the following disclaimer. copies or substantial portions of the Software.
* Redistributions in binary form must reproduce the above copyright notice, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
this list of conditions and the following disclaimer in the documentation IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
and/or other materials provided with the distribution. FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* Neither the name Facebook nor the names of its contributors may be used to IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
endorse or promote products derived from this software without specific CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
react-dom@15.6.1 BSD-3-Clause react-dom@15.6.1 BSD-3-Clause
@ -66,7 +55,7 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
object-assign@4.1.0 MIT object-assign@4.1.1 MIT
The MIT License (MIT) The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
@ -157,38 +146,28 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
create-react-class@15.6.0 BSD-3-Clause create-react-class@15.6.2 MIT
BSD License MIT License
For React software
Copyright (c) 2013-present, Facebook, Inc. Copyright (c) 2013-present, Facebook, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Permission is hereby granted, free of charge, to any person obtaining a copy
are permitted provided that the following conditions are met: of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice, this The above copyright notice and this permission notice shall be included in all
list of conditions and the following disclaimer. copies or substantial portions of the Software.
* Redistributions in binary form must reproduce the above copyright notice, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
this list of conditions and the following disclaimer in the documentation IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
and/or other materials provided with the distribution. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* Neither the name Facebook nor the names of its contributors may be used to LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
endorse or promote products derived from this software without specific OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
prior written permission. SOFTWARE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
mozjexl@1.1.5 MIT mozjexl@1.1.5 MIT

Просмотреть файл

@ -1 +1 @@
/* eslint-disable */this.PropTypes=function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={i:d,l:!1,exports:{}};return a[d].call(e.exports,e,e.exports,b),e.l=!0,e.exports}var c={};return b.m=a,b.c=c,b.d=function(a,c,d){b.o(a,c)||Object.defineProperty(a,c,{configurable:!1,enumerable:!0,get:d})},b.n=function(a){var c=a&&a.__esModule?function(){return a['default']}:function(){return a};return b.d(c,'a',c),c},b.o=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)},b.p='',b(b.s=101)}({0:function(a){'use strict';var g=function(){};!1,a.exports=function(h,i,j,a,b,c,d,e){if(g(i),!h){var f;if(void 0===i)f=new Error('Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.');else{var k=[j,a,b,c,d,e],l=0;f=new Error(i.replace(/%s/g,function(){return k[l++]})),f.name='Invariant Violation'}throw f.framesToPop=1,f}}},101:function(a,b,c){a.exports=c(102)()},102:function(a,b,c){'use strict';var d=c(5),e=c(0),f=c(19);a.exports=function(){function a(a,b,c,d,g,h){h===f||e(!1,'Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types')}function b(){return a}a.isRequired=a;var c={array:a,bool:a,func:a,number:a,object:a,string:a,symbol:a,any:a,arrayOf:b,element:a,instanceOf:b,node:a,objectOf:b,oneOf:b,oneOfType:b,shape:b};return c.checkPropTypes=d,c.PropTypes=c,c}},19:function(a){'use strict';a.exports='SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'},5:function(a){'use strict';function b(a){return function(){return a}}var c=function(){};c.thatReturns=b,c.thatReturnsFalse=b(!1),c.thatReturnsTrue=b(!0),c.thatReturnsNull=b(null),c.thatReturnsThis=function(){return this},c.thatReturnsArgument=function(a){return a},a.exports=c}});this.EXPORTED_SYMBOLS = ["PropTypes"]; /* eslint-disable */this.PropTypes=function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={i:d,l:!1,exports:{}};return a[d].call(e.exports,e,e.exports,b),e.l=!0,e.exports}var c={};return b.m=a,b.c=c,b.d=function(a,c,d){b.o(a,c)||Object.defineProperty(a,c,{configurable:!1,enumerable:!0,get:d})},b.n=function(a){var c=a&&a.__esModule?function(){return a['default']}:function(){return a};return b.d(c,'a',c),c},b.o=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)},b.p='',b(b.s=100)}({0:function(a){'use strict';var g=function(){};!1,a.exports=function(h,i,j,a,b,c,d,e){if(g(i),!h){var f;if(void 0===i)f=new Error('Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.');else{var k=[j,a,b,c,d,e],l=0;f=new Error(i.replace(/%s/g,function(){return k[l++]})),f.name='Invariant Violation'}throw f.framesToPop=1,f}}},100:function(a,b,c){a.exports=c(101)()},101:function(a,b,c){'use strict';var d=c(5),e=c(0),f=c(19);a.exports=function(){function a(a,b,c,d,g,h){h===f||e(!1,'Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types')}function b(){return a}a.isRequired=a;var c={array:a,bool:a,func:a,number:a,object:a,string:a,symbol:a,any:a,arrayOf:b,element:a,instanceOf:b,node:a,objectOf:b,oneOf:b,oneOfType:b,shape:b};return c.checkPropTypes=d,c.PropTypes=c,c}},19:function(a){'use strict';a.exports='SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'},5:function(a){'use strict';function b(a){return function(){return a}}var c=function(){};c.thatReturns=b,c.thatReturnsFalse=b(!1),c.thatReturnsTrue=b(!0),c.thatReturnsNull=b(null),c.thatReturnsThis=function(){return this},c.thatReturnsArgument=function(a){return a},a.exports=c}});this.EXPORTED_SYMBOLS = ["PropTypes"];

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1 +1 @@
/* eslint-disable */this.classnames=function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={i:d,l:!1,exports:{}};return a[d].call(e.exports,e,e.exports,b),e.l=!0,e.exports}var c={};return b.m=a,b.c=c,b.d=function(a,c,d){b.o(a,c)||Object.defineProperty(a,c,{configurable:!1,enumerable:!0,get:d})},b.n=function(a){var c=a&&a.__esModule?function(){return a['default']}:function(){return a};return b.d(c,'a',c),c},b.o=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)},b.p='',b(b.s=93)}({93:function(a,b){var c,d;(function(){'use strict';function e(){for(var a,b=[],c=0;c<arguments.length;c++)if(a=arguments[c],a){var d=typeof a;if('string'==d||'number'==d)b.push(a);else if(Array.isArray(a))b.push(e.apply(null,a));else if('object'==d)for(var g in a)f.call(a,g)&&a[g]&&b.push(g)}return b.join(' ')}var f={}.hasOwnProperty;'undefined'!=typeof a&&a.exports?a.exports=e:(c=[],d=function(){return e}.apply(b,c),!(d!==void 0&&(a.exports=d)))})()}});this.EXPORTED_SYMBOLS = ["classnames"]; /* eslint-disable */this.classnames=function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={i:d,l:!1,exports:{}};return a[d].call(e.exports,e,e.exports,b),e.l=!0,e.exports}var c={};return b.m=a,b.c=c,b.d=function(a,c,d){b.o(a,c)||Object.defineProperty(a,c,{configurable:!1,enumerable:!0,get:d})},b.n=function(a){var c=a&&a.__esModule?function(){return a['default']}:function(){return a};return b.d(c,'a',c),c},b.o=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)},b.p='',b(b.s=92)}({92:function(a,b){var c,d;(function(){'use strict';function e(){for(var a,b=[],c=0;c<arguments.length;c++)if(a=arguments[c],a){var d=typeof a;if('string'==d||'number'==d)b.push(a);else if(Array.isArray(a))b.push(e.apply(null,a));else if('object'==d)for(var g in a)f.call(a,g)&&a[g]&&b.push(g)}return b.join(' ')}var f={}.hasOwnProperty;'undefined'!=typeof a&&a.exports?a.exports=e:(c=[],d=function(){return e}.apply(b,c),!(d!==void 0&&(a.exports=d)))})()}});this.EXPORTED_SYMBOLS = ["classnames"];

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -648,7 +648,7 @@ class ContextMenu {
cleanTarget.ownerDocument = { cleanTarget.ownerDocument = {
// used for nsContextMenu.initLeaveDOMFullScreenItems and // used for nsContextMenu.initLeaveDOMFullScreenItems and
// nsContextMenu.initMediaPlayerItems // nsContextMenu.initMediaPlayerItems
fullscreenElement: context.target.ownerDocument.fullscreenElement, fullscreen: context.target.ownerDocument.fullscreen,
// used for nsContextMenu.initMiscItems // used for nsContextMenu.initMiscItems
contentType: context.target.ownerDocument.contentType, contentType: context.target.ownerDocument.contentType,

Просмотреть файл

@ -38,7 +38,6 @@ class PingCentre {
} }
this._topic = options.topic; this._topic = options.topic;
this._filter = options.filter;
this._prefs = Services.prefs.getBranch(""); this._prefs = Services.prefs.getBranch("");
this._setPingEndpoint(options.topic, options.overrideEndpointPref); this._setPingEndpoint(options.topic, options.overrideEndpointPref);
@ -92,12 +91,12 @@ class PingCentre {
this._fhrEnabled = this._prefs.getBoolPref(prefKey); this._fhrEnabled = this._prefs.getBoolPref(prefKey);
} }
_createExperimentsString(activeExperiments) { _createExperimentsString(activeExperiments, filter) {
let experimentsString = ""; let experimentsString = "";
for (let experimentID in activeExperiments) { for (let experimentID in activeExperiments) {
if (!activeExperiments[experimentID] || if (!activeExperiments[experimentID] ||
!activeExperiments[experimentID].branch || !activeExperiments[experimentID].branch ||
(this._filter && !experimentID.includes(this._filter))) { (filter && !experimentID.includes(filter))) {
continue; continue;
} }
let expString = `${experimentID}:${activeExperiments[experimentID].branch}`; let expString = `${experimentID}:${activeExperiments[experimentID].branch}`;
@ -106,9 +105,10 @@ class PingCentre {
return experimentsString; return experimentsString;
} }
async sendPing(data) { async sendPing(data, options) {
let filter = options && options.filter;
let experiments = TelemetryEnvironment.getActiveExperiments(); let experiments = TelemetryEnvironment.getActiveExperiments();
let experimentsString = this._createExperimentsString(experiments); let experimentsString = this._createExperimentsString(experiments, filter);
if (!this.enabled) { if (!this.enabled) {
return Promise.resolve(); return Promise.resolve();
} }

Просмотреть файл

@ -554,6 +554,7 @@ html|span.ac-emphasize-text-url {
color: -moz-menubartext; color: -moz-menubartext;
} }
#nav-bar,
#toolbar-menubar:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag), #toolbar-menubar:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
#TabsToolbar:not(:-moz-lwtheme):-moz-system-metric(menubar-drag) { #TabsToolbar:not(:-moz-lwtheme):-moz-system-metric(menubar-drag) {
-moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag"); -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");

Просмотреть файл

@ -92,14 +92,14 @@
to { transform: perspective(5000px) rotateY(360deg); } to { transform: perspective(5000px) rotateY(360deg); }
} }
:root:not([uidensity=compact]) #PanelUI-button { :root:not([uidensity=compact]):not([chromehidden~="toolbar"]) #PanelUI-button {
margin-inline-start: 3px; margin-inline-start: 3px;
border-inline-start: 1px solid; border-inline-start: 1px solid;
border-image: linear-gradient(transparent 4px, rgba(0,0,0,.1) 4px, rgba(0,0,0,.1) calc(100% - 4px), transparent calc(100% - 4px)); border-image: linear-gradient(transparent 4px, rgba(0,0,0,.1) 4px, rgba(0,0,0,.1) calc(100% - 4px), transparent calc(100% - 4px));
border-image-slice: 1; border-image-slice: 1;
} }
:root:not([uidensity=compact]) #nav-bar[brighttext] > #PanelUI-button { :root:not([uidensity=compact]):not([chromehidden~="toolbar"]) #nav-bar[brighttext] > #PanelUI-button {
border-image-source: linear-gradient(transparent 4px, rgba(100%,100%,100%,.2) 4px, rgba(100%,100%,100%,.2) calc(100% - 4px), transparent calc(100% - 4px)); border-image-source: linear-gradient(transparent 4px, rgba(100%,100%,100%,.2) 4px, rgba(100%,100%,100%,.2) calc(100% - 4px), transparent calc(100% - 4px));
} }

Просмотреть файл

@ -2,5 +2,5 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this - 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/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path fill="#0C0C0D" d="M9.24 16.03v2.73c0 .7-.56 1.24-1.25 1.24-.7 0-1.26-.55-1.26-1.24v-2.73h-.9c-.75 0-1.35-.59-1.35-1.33v-8h11.2v8c0 .74-.6 1.33-1.36 1.33h-.9v2.73c0 .7-.55 1.24-1.25 1.24s-1.26-.55-1.26-1.24v-2.73H9.24zM2.76 6.5c.7 0 1.25.55 1.25 1.24v5.15c0 .7-.56 1.24-1.25 1.24-.7 0-1.26-.55-1.26-1.24V7.73c0-.69.56-1.24 1.26-1.24zm14.64 0c.7 0 1.25.55 1.25 1.24v5.15c0 .7-.55 1.24-1.25 1.24s-1.26-.55-1.26-1.24V7.73c0-.69.56-1.24 1.26-1.24zM6.6 0c.06 0 .12.03.16.1l.9 1.58a6.04 6.04 0 0 1 4.84 0L13.4.1a.18.18 0 0 1 .24-.07c.09.05.12.15.07.24l-.89 1.58a5.04 5.04 0 0 1 2.86 4.43H4.48c0-1.9 1.15-3.56 2.85-4.43L6.45.26a.17.17 0 0 1 .07-.24A.18.18 0 0 1 6.6 0zm.9 3.33c-.26 0-.47.2-.47.46a.47.47 0 0 0 .93 0 .47.47 0 0 0-.47-.46zm5.16 0c-.25 0-.47.2-.47.46a.47.47 0 0 0 .94 0 .47.47 0 0 0-.47-.46z"/> <path fill="context-fill" d="M9.24 16.03v2.73c0 .7-.56 1.24-1.25 1.24-.7 0-1.26-.55-1.26-1.24v-2.73h-.9c-.75 0-1.35-.59-1.35-1.33v-8h11.2v8c0 .74-.6 1.33-1.36 1.33h-.9v2.73c0 .7-.55 1.24-1.25 1.24s-1.26-.55-1.26-1.24v-2.73H9.24zM2.76 6.5c.7 0 1.25.55 1.25 1.24v5.15c0 .7-.56 1.24-1.25 1.24-.7 0-1.26-.55-1.26-1.24V7.73c0-.69.56-1.24 1.26-1.24zm14.64 0c.7 0 1.25.55 1.25 1.24v5.15c0 .7-.55 1.24-1.25 1.24s-1.26-.55-1.26-1.24V7.73c0-.69.56-1.24 1.26-1.24zM6.6 0c.06 0 .12.03.16.1l.9 1.58a6.04 6.04 0 0 1 4.84 0L13.4.1a.18.18 0 0 1 .24-.07c.09.05.12.15.07.24l-.89 1.58a5.04 5.04 0 0 1 2.86 4.43H4.48c0-1.9 1.15-3.56 2.85-4.43L6.45.26a.17.17 0 0 1 .07-.24A.18.18 0 0 1 6.6 0zm.9 3.33c-.26 0-.47.2-.47.46a.47.47 0 0 0 .93 0 .47.47 0 0 0-.47-.46zm5.16 0c-.25 0-.47.2-.47.46a.47.47 0 0 0 .94 0 .47.47 0 0 0-.47-.46z"/>
</svg> </svg>

До

Ширина:  |  Высота:  |  Размер: 1.1 KiB

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -2,5 +2,5 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this - 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/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path fill="#0C0C0D" fill-rule="evenodd" d="M16.84 15.03c-.27.63-.59 1.2-.96 1.74-.51.72-.93 1.23-1.25 1.5-.5.46-1.03.7-1.6.71-.41 0-.9-.12-1.48-.35a4.25 4.25 0 0 0-1.6-.36c-.5 0-1.05.12-1.63.36A4.4 4.4 0 0 1 6.9 19c-.55.02-1.1-.22-1.64-.73-.35-.3-.78-.82-1.3-1.56-.56-.78-1.02-1.7-1.38-2.73A10.03 10.03 0 0 1 2 10.7c0-1.2.26-2.25.78-3.12a4.6 4.6 0 0 1 3.86-2.28c.43 0 1 .13 1.71.4.71.26 1.16.4 1.36.4.15 0 .66-.16 1.51-.47.8-.3 1.5-.41 2.05-.37 1.51.13 2.65.72 3.4 1.8a3.8 3.8 0 0 0-2 3.44 4.1 4.1 0 0 0 2.5 3.68c-.1.3-.21.57-.33.84zM13.37 1.36c0 .9-.33 1.74-.98 2.52-.8.92-1.75 1.46-2.79 1.37a3.95 3.95 0 0 1 1.02-2.89c.34-.38.76-.7 1.28-.95.51-.25 1-.39 1.45-.41.02.12.02.24.02.36z"/> <path fill="context-fill" d="M16.84 15.03c-.27.63-.59 1.2-.96 1.74-.51.72-.93 1.23-1.25 1.5-.5.46-1.03.7-1.6.71-.41 0-.9-.12-1.48-.35a4.25 4.25 0 0 0-1.6-.36c-.5 0-1.05.12-1.63.36A4.4 4.4 0 0 1 6.9 19c-.55.02-1.1-.22-1.64-.73-.35-.3-.78-.82-1.3-1.56-.56-.78-1.02-1.7-1.38-2.73A10.03 10.03 0 0 1 2 10.7c0-1.2.26-2.25.78-3.12a4.6 4.6 0 0 1 3.86-2.28c.43 0 1 .13 1.71.4.71.26 1.16.4 1.36.4.15 0 .66-.16 1.51-.47.8-.3 1.5-.41 2.05-.37 1.51.13 2.65.72 3.4 1.8a3.8 3.8 0 0 0-2 3.44 4.1 4.1 0 0 0 2.5 3.68c-.1.3-.21.57-.33.84zM13.37 1.36c0 .9-.33 1.74-.98 2.52-.8.92-1.75 1.46-2.79 1.37a3.95 3.95 0 0 1 1.02-2.89c.34-.38.76-.7 1.28-.95.51-.25 1-.39 1.45-.41.02.12.02.24.02.36z"/>
</svg> </svg>

До

Ширина:  |  Высота:  |  Размер: 970 B

После

Ширина:  |  Высота:  |  Размер: 955 B

Просмотреть файл

@ -582,6 +582,8 @@ button > hbox > label {
width: 20px; width: 20px;
height: 20px; height: 20px;
vertical-align: text-bottom; vertical-align: text-bottom;
-moz-context-properties: fill;
fill: currentColor;
} }
#updateDeck > hbox > label { #updateDeck > hbox > label {

Просмотреть файл

@ -528,21 +528,15 @@ tabbrowser {
/* Tab separators */ /* Tab separators */
%ifdef CAN_DRAW_IN_TITLEBAR .titlebar-placeholder[type="pre-tabs"],
/* Add space for dragging the window */ .titlebar-placeholder[type="post-tabs"] {
%ifdef MOZ_WIDGET_COCOA
:root[tabsintitlebar]:not([sizemode=fullscreen]) .titlebar-placeholder[type="pre-tabs"]
%elifdef MENUBAR_CAN_AUTOHIDE
:root[tabsintitlebar][sizemode=normal] #toolbar-menubar[autohide=true] ~ #TabsToolbar > .titlebar-placeholder[type="pre-tabs"]
%else
:root[tabsintitlebar][sizemode=normal] #TabsToolbar > .titlebar-placeholder[type="pre-tabs"]
%endif
{
width: 40px; width: 40px;
}
.titlebar-placeholder[type="pre-tabs"] {
border-inline-end: 1px solid; border-inline-end: 1px solid;
opacity: 0.2; opacity: 0.2;
} }
%endif
.tabbrowser-tab::after, .tabbrowser-tab::after,
.tabbrowser-tab::before { .tabbrowser-tab::before {

Просмотреть файл

@ -23,21 +23,17 @@
} }
@media (-moz-windows-compositor) { @media (-moz-windows-compositor) {
#main-window {
-moz-appearance: -moz-win-glass;
}
/* On win10, if we don't set this on the entire browser container including
* the sidebar, if the sidebar is open the accent color bleeds through in
* the titlebar */
#browser {
-moz-appearance: -moz-win-exclude-glass;
}
@media not all and (-moz-os-version: windows-win7) { @media not all and (-moz-os-version: windows-win7) {
@media not all and (-moz-os-version: windows-win8) { @media not all and (-moz-os-version: windows-win8) {
@media (-moz-windows-default-theme) { @media (-moz-windows-default-theme) {
:root[sizemode=normal][tabsintitlebar] {
border-top: 1px solid -moz-win-accentcolor;
}
:root[sizemode=normal][tabsintitlebar]:-moz-window-inactive {
border-top-color: rgba(0,0,0,.2);
}
:root:not(:-moz-lwtheme) { :root:not(:-moz-lwtheme) {
background-color: hsl(0, 0%, 78%); background-color: hsl(0, 0%, 78%);
} }
@ -66,6 +62,14 @@
@media (-moz-windows-default-theme: 0) { @media (-moz-windows-default-theme: 0) {
:root { :root {
background-color: transparent; background-color: transparent;
-moz-appearance: -moz-win-glass;
}
/* On win10, if we don't set this on the entire browser container including
* the sidebar, if the sidebar is open the accent color bleeds through in
* the titlebar */
#browser {
-moz-appearance: -moz-win-exclude-glass;
} }
} }
@ -230,15 +234,15 @@
@media (-moz-os-version: windows-win7), @media (-moz-os-version: windows-win7),
(-moz-os-version: windows-win8) { (-moz-os-version: windows-win8) {
#main-window[sizemode="maximized"] #titlebar-buttonbox { :root {
margin-inline-end: 3px;
}
#main-window {
background-color: transparent; background-color: transparent;
-moz-appearance: -moz-win-borderless-glass; -moz-appearance: -moz-win-borderless-glass;
} }
:root[sizemode="maximized"] #titlebar-buttonbox {
margin-inline-end: 3px;
}
/* These should be hidden w/ glass enabled. Windows draws its own buttons. */ /* These should be hidden w/ glass enabled. Windows draws its own buttons. */
.titlebar-button { .titlebar-button {
display: none; display: none;
@ -247,10 +251,6 @@
/* The borders on the glass frame are ours, and inside #browser, and on /* The borders on the glass frame are ours, and inside #browser, and on
* win7 we want to make sure they are "glassy", so we can't use #browser * win7 we want to make sure they are "glassy", so we can't use #browser
* as the exclude-glass container. We use #appcontent instead. */ * as the exclude-glass container. We use #appcontent instead. */
#browser {
-moz-appearance: none;
}
#appcontent { #appcontent {
-moz-appearance: -moz-win-exclude-glass; -moz-appearance: -moz-win-exclude-glass;
} }
@ -326,6 +326,11 @@
border-top-right-radius: 2.5px; border-top-right-radius: 2.5px;
} }
/* Set to full fill-opacity to improve visibility of toolbar buttons on aero glass. */
#TabsToolbar:not(:-moz-lwtheme) {
--toolbarbutton-icon-fill-opacity: 1;
}
#toolbar-menubar:not(:-moz-lwtheme) { #toolbar-menubar:not(:-moz-lwtheme) {
text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4); text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
} }

Просмотреть файл

@ -296,10 +296,6 @@
} }
} }
.titlebar-placeholder[type="caption-buttons"] {
margin-left: 22px; /* space needed for Aero Snap */
}
/* titlebar command buttons */ /* titlebar command buttons */
#titlebar-min { #titlebar-min {

Просмотреть файл

@ -20,12 +20,6 @@
} }
} }
@media (-moz-windows-compositor) {
#main-window {
background: transparent !important;
}
}
#toolbar-menubar { #toolbar-menubar {
text-shadow: none !important; text-shadow: none !important;
} }
@ -46,6 +40,11 @@
} }
@media (-moz-windows-glass) { @media (-moz-windows-glass) {
/* Set to full fill-opacity to improve visibility of toolbar buttons on aero glass. */
#TabsToolbar {
--toolbarbutton-icon-fill-opacity: 1;
}
/* Make the menubar text readable on aero glass (copied from browser-aero.css). */ /* Make the menubar text readable on aero glass (copied from browser-aero.css). */
#toolbar-menubar { #toolbar-menubar {
text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4); text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
@ -60,6 +59,12 @@
@media (-moz-os-version: windows-win7), @media (-moz-os-version: windows-win7),
(-moz-os-version: windows-win8) { (-moz-os-version: windows-win8) {
@media (-moz-windows-compositor) {
#main-window {
background: transparent !important;
}
}
/* Always show full-height tab separators on tabs with borders. */ /* Always show full-height tab separators on tabs with borders. */
.tabbrowser-tab::before { .tabbrowser-tab::before {
border-image: none !important; border-image: none !important;

Просмотреть файл

@ -96,7 +96,7 @@ add_old_configure_assignment('MACOSX_DEPLOYMENT_TARGET', macos_target)
# Xcode state # Xcode state
# =========== # ===========
option('--disable-xcode-checks', js_option('--disable-xcode-checks',
help='Do not check that Xcode is installed and properly configured') help='Do not check that Xcode is installed and properly configured')
@depends(host, '--disable-xcode-checks') @depends(host, '--disable-xcode-checks')

Просмотреть файл

@ -0,0 +1,18 @@
<script>
function fzfn(e){
let nc=window.frames[0].document.body.childElementCount;
let o=window.frames[0].document.body.childNodes[1%nc];
document.getElementById('b').appendChild(o.parentNode.removeChild(o));
}
window.onload=function(){
document.body.onerror=fzfn;
document.getElementById('c').addEventListener('DOMNodeRemoved', fzfn, true);
document.getElementById('c').attributes[0].name=='id';
window.frames[0].document.body.appendChild(document.getElementById('c'));
document.getElementById('a').innerHTML=document.createElement('multicol').outerHTML;
}
</script>
<iframe></iframe>
<script id='a'></script>
<script id='b'></script>
<script id='c'></script>

Просмотреть файл

@ -225,3 +225,4 @@ load 1383780.html
pref(clipboard.autocopy,true) load 1385272-1.html pref(clipboard.autocopy,true) load 1385272-1.html
load 1393806.html load 1393806.html
load 1400701.html load 1400701.html
load 1403377.html

Просмотреть файл

@ -7791,15 +7791,19 @@ nsDOMAttributeMap::BlastSubtreeToPieces(nsINode *aNode)
Element *element = aNode->AsElement(); Element *element = aNode->AsElement();
const nsDOMAttributeMap *map = element->GetAttributeMap(); const nsDOMAttributeMap *map = element->GetAttributeMap();
if (map) { if (map) {
// This non-standard style of iteration is presumably used because some
// of the code in the loop body can trigger element removal, which
// invalidates the iterator.
while (true) { while (true) {
auto iter = map->mAttributeCache.ConstIter(); nsCOMPtr<nsIAttribute> attr;
if (iter.Done()) { {
break; // Use an iterator to get an arbitrary attribute from the
// cache. The iterator must be destroyed before any other
// operations on mAttributeCache, to avoid hash table
// assertions.
auto iter = map->mAttributeCache.ConstIter();
if (iter.Done()) {
break;
}
attr = iter.UserData();
} }
nsCOMPtr<nsIAttribute> attr = iter.UserData();
NS_ASSERTION(attr.get(), NS_ASSERTION(attr.get(),
"non-nsIAttribute somehow made it into the hashmap?!"); "non-nsIAttribute somehow made it into the hashmap?!");
@ -13608,6 +13612,29 @@ nsIDocument::ReportHasScrollLinkedEffect()
"ScrollLinkedEffectFound2"); "ScrollLinkedEffectFound2");
} }
#ifdef MOZ_STYLO
// URL-based blacklist for stylo.
static bool
ShouldUseGeckoBackend(nsIURI* aDocumentURI)
{
if (!aDocumentURI) {
return false;
}
bool isScheme = false;
if (NS_SUCCEEDED(aDocumentURI->SchemeIs("about", &isScheme))) {
nsAutoCString path;
aDocumentURI->GetFilePath(path);
// about:reader requires support of :scope pseudo-class so we have
// to use Gecko backend for now. See bug 1402094.
// This should be fixed by bug 1204818.
if (path.EqualsLiteral("reader")) {
return true;
}
}
return false;
}
#endif // MOZ_STYLO
void void
nsIDocument::UpdateStyleBackendType() nsIDocument::UpdateStyleBackendType()
{ {
@ -13626,7 +13653,7 @@ nsIDocument::UpdateStyleBackendType()
// Note that, since tests can have XUL support, we still need to // Note that, since tests can have XUL support, we still need to
// explicitly exclude XUL documents here. // explicitly exclude XUL documents here.
if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()) && if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()) &&
!IsXULDocument()) { !IsXULDocument() && !ShouldUseGeckoBackend(mDocumentURI)) {
mStyleBackendType = StyleBackendType::Servo; mStyleBackendType = StyleBackendType::Servo;
} }
} }

Просмотреть файл

@ -3129,7 +3129,7 @@ MediaDecoderStateMachine::RequestAudioData()
mStateObj->HandleAudioDecoded(aAudio); mStateObj->HandleAudioDecoded(aAudio);
}, },
[this, self] (const MediaResult& aError) { [this, self] (const MediaResult& aError) {
LOGV("OnAudioNotDecoded aError=%" PRIu32, static_cast<uint32_t>(aError.Code())); LOGV("OnAudioNotDecoded aError=%s", aError.ErrorName().get());
mAudioDataRequest.Complete(); mAudioDataRequest.Complete();
switch (aError.Code()) { switch (aError.Code()) {
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA: case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
@ -3175,7 +3175,7 @@ MediaDecoderStateMachine::RequestVideoData(const media::TimeUnit& aCurrentTime)
mStateObj->HandleVideoDecoded(aVideo, videoDecodeStartTime); mStateObj->HandleVideoDecoded(aVideo, videoDecodeStartTime);
}, },
[this, self] (const MediaResult& aError) { [this, self] (const MediaResult& aError) {
LOGV("OnVideoNotDecoded aError=%" PRIu32 , static_cast<uint32_t>(aError.Code())); LOGV("OnVideoNotDecoded aError=%s" , aError.ErrorName().get());
mVideoDataRequest.Complete(); mVideoDataRequest.Complete();
switch (aError.Code()) { switch (aError.Code()) {
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA: case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:

Просмотреть файл

@ -1635,9 +1635,9 @@ void
MediaFormatReader::OnDemuxFailed(TrackType aTrack, const MediaResult& aError) MediaFormatReader::OnDemuxFailed(TrackType aTrack, const MediaResult& aError)
{ {
MOZ_ASSERT(OnTaskQueue()); MOZ_ASSERT(OnTaskQueue());
LOG("Failed to demux %s, failure:%" PRIu32, LOG("Failed to demux %s, failure:%s",
aTrack == TrackType::kVideoTrack ? "video" : "audio", aTrack == TrackType::kVideoTrack ? "video" : "audio",
static_cast<uint32_t>(aError.Code())); aError.ErrorName().get());
auto& decoder = GetDecoderData(aTrack); auto& decoder = GetDecoderData(aTrack);
decoder.mDemuxRequest.Complete(); decoder.mDemuxRequest.Complete();
switch (aError.Code()) { switch (aError.Code()) {
@ -2823,7 +2823,7 @@ void
MediaFormatReader::OnSeekFailed(TrackType aTrack, const MediaResult& aError) MediaFormatReader::OnSeekFailed(TrackType aTrack, const MediaResult& aError)
{ {
MOZ_ASSERT(OnTaskQueue()); MOZ_ASSERT(OnTaskQueue());
LOGV("%s failure:%s" PRIu32, TrackTypeToStr(aTrack), aError.ErrorName().get()); LOGV("%s failure:%s", TrackTypeToStr(aTrack), aError.ErrorName().get());
if (aTrack == TrackType::kVideoTrack) { if (aTrack == TrackType::kVideoTrack) {
mVideo.mSeekRequest.Complete(); mVideo.mSeekRequest.Complete();
} else { } else {

Просмотреть файл

@ -61,10 +61,8 @@ public:
if (NS_SUCCEEDED(mCode)) { if (NS_SUCCEEDED(mCode)) {
return nsCString(); return nsCString();
} }
nsCString name;
GetErrorName(mCode, name);
return nsPrintfCString("%s (0x%08" PRIx32 ")%s%s", return nsPrintfCString("%s (0x%08" PRIx32 ")%s%s",
name.get(), ErrorName().get(),
static_cast<uint32_t>(mCode), static_cast<uint32_t>(mCode),
mMessage.IsEmpty() ? "" : " - ", mMessage.IsEmpty() ? "" : " - ",
mMessage.get()); mMessage.get());

Просмотреть файл

@ -7,7 +7,6 @@
#ifndef CDMCaps_h_ #ifndef CDMCaps_h_
#define CDMCaps_h_ #define CDMCaps_h_
#include "gmp-decryption.h"
#include "nsIThread.h" #include "nsIThread.h"
#include "nsTArray.h" #include "nsTArray.h"
#include "nsString.h" #include "nsString.h"

Просмотреть файл

@ -68,6 +68,8 @@ public:
dom::Optional<dom::MediaKeyStatus> mStatus; dom::Optional<dom::MediaKeyStatus> mStatus;
}; };
// Time is defined as the number of milliseconds since the
// Epoch (00:00:00 UTC, January 1, 1970).
typedef int64_t UnixTime; typedef int64_t UnixTime;
// Proxies calls CDM, and proxies calls back. // Proxies calls CDM, and proxies calls back.

Просмотреть файл

@ -133,7 +133,7 @@ public:
private: private:
// Instantiate CDMProxy instance. // Instantiate CDMProxy instance.
// It could be MediaDrmCDMProxy (Widevine on Fennec) or GMPCDMProxy (the rest). // It could be MediaDrmCDMProxy (Widevine on Fennec) or ChromiumCDMProxy (the rest).
already_AddRefed<CDMProxy> CreateCDMProxy(nsIEventTarget* aMainThread); already_AddRefed<CDMProxy> CreateCDMProxy(nsIEventTarget* aMainThread);
// Removes promise from mPromises, and returns it. // Removes promise from mPromises, and returns it.

Просмотреть файл

@ -33,57 +33,36 @@
************************************************************************************* *************************************************************************************
*/ */
#include <stdint.h> #include "stddef.h"
#include <cstdio> #include "cdm-test-decryptor.h"
#include <cstring> #include "content_decryption_module.h"
#include <string> #include "content_decryption_module_ext.h"
#include <memory>
#include "gmp-platform.h"
#include "gmp-video-decode.h"
#if defined(GMP_FAKE_SUPPORT_DECRYPT)
#include "gmp-decryption.h"
#include "gmp-test-decryptor.h"
#include "gmp-test-storage.h"
#endif
#if defined(_MSC_VER)
#define PUBLIC_FUNC __declspec(dllexport)
#else
#define PUBLIC_FUNC
#endif
GMPPlatformAPI* g_platform_api = nullptr;
extern "C" { extern "C" {
PUBLIC_FUNC GMPErr CDM_API
GMPInit (GMPPlatformAPI* aPlatformAPI) { void INITIALIZE_CDM_MODULE() {
g_platform_api = aPlatformAPI;
return GMPNoErr;
}
PUBLIC_FUNC GMPErr }
GMPGetAPI (const char* aApiName, void* aHostAPI, void** aPluginApi) {
if (!strcmp (aApiName, GMP_API_VIDEO_DECODER)) {
// Note: Deliberately advertise in our .info file that we support
// video-decode, but we fail the "get" call here to simulate what
// happens when decoder init fails.
return GMPGenericErr;
#if defined(GMP_FAKE_SUPPORT_DECRYPT)
}
if (!strcmp (aApiName, GMP_API_DECRYPTOR)) {
*aPluginApi = new FakeDecryptor();
return GMPNoErr;
#endif
}
return GMPGenericErr;
}
PUBLIC_FUNC void CDM_API
GMPShutdown (void) { void* CreateCdmInstance(int cdm_interface_version,
g_platform_api = nullptr; const char* key_system,
} uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func,
void* user_data)
{
cdm::Host_8* host = static_cast<cdm::Host_8*>(
get_cdm_host_func(cdm_interface_version, user_data));
return new FakeDecryptor(host);
}
CDM_API
bool
VerifyCdmHost_0(const cdm::HostFile* aHostFiles, uint32_t aNumFiles)
{
return true;
}
} // extern "C" } // extern "C"

Просмотреть файл

@ -3,10 +3,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gmp-test-decryptor.h" #include "cdm-test-decryptor.h"
#include "gmp-test-storage.h" #include "cdm-test-storage.h"
#include "gmp-test-output-protection.h" #include "cdm-test-output-protection.h"
#include <mutex>
#include <string> #include <string>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
@ -14,6 +15,7 @@
#include <iterator> #include <iterator>
#include <sstream> #include <sstream>
#include <set> #include <set>
#include <thread>
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
@ -21,28 +23,14 @@
using namespace std; using namespace std;
FakeDecryptor* FakeDecryptor::sInstance = nullptr; FakeDecryptor* FakeDecryptor::sInstance = nullptr;
extern GMPPlatformAPI* g_platform_api; // Defined in gmp-fake.cpp
class GMPMutexAutoLock
{
public:
explicit GMPMutexAutoLock(GMPMutex* aMutex) : mMutex(aMutex) {
mMutex->Acquire();
}
~GMPMutexAutoLock() {
mMutex->Release();
}
private:
GMPMutex* const mMutex;
};
class TestManager { class TestManager {
public: public:
TestManager() : mMutex(CreateMutex()) {} TestManager() = default;
// Register a test with the test manager. // Register a test with the test manager.
void BeginTest(const string& aTestID) { void BeginTest(const string& aTestID) {
GMPMutexAutoLock lock(mMutex); std::lock_guard<std::mutex> lock(mMutex);
auto found = mTestIDs.find(aTestID); auto found = mTestIDs.find(aTestID);
if (found == mTestIDs.end()) { if (found == mTestIDs.end()) {
mTestIDs.insert(aTestID); mTestIDs.insert(aTestID);
@ -57,7 +45,7 @@ public:
void EndTest(const string& aTestID) { void EndTest(const string& aTestID) {
bool isEmpty = false; bool isEmpty = false;
{ {
GMPMutexAutoLock lock(mMutex); std::lock_guard<std::mutex> lock(mMutex);
auto found = mTestIDs.find(aTestID); auto found = mTestIDs.find(aTestID);
if (found != mTestIDs.end()) { if (found != mTestIDs.end()) {
mTestIDs.erase(aTestID); mTestIDs.erase(aTestID);
@ -74,9 +62,7 @@ public:
} }
private: private:
~TestManager() { ~TestManager() = default;
mMutex->Destroy();
}
static void Error(const string& msg) { static void Error(const string& msg) {
FakeDecryptor::Message(msg); FakeDecryptor::Message(msg);
@ -86,37 +72,29 @@ private:
FakeDecryptor::Message("test-storage complete"); FakeDecryptor::Message("test-storage complete");
} }
static GMPMutex* CreateMutex() { std::mutex mMutex;
GMPMutex* mutex = nullptr;
g_platform_api->createmutex(&mutex);
return mutex;
}
GMPMutex* const mMutex;
set<string> mTestIDs; set<string> mTestIDs;
}; };
FakeDecryptor::FakeDecryptor() FakeDecryptor::FakeDecryptor(cdm::Host_8* aHost)
: mCallback(nullptr) : mHost(aHost)
{ {
MOZ_ASSERT(!sInstance); MOZ_ASSERT(!sInstance);
sInstance = this; sInstance = this;
} }
void FakeDecryptor::DecryptingComplete()
{
sInstance = nullptr;
delete this;
}
void void
FakeDecryptor::Message(const std::string& aMessage) FakeDecryptor::Message(const std::string& aMessage)
{ {
MOZ_ASSERT(sInstance); MOZ_ASSERT(sInstance);
const static std::string sid("fake-session-id"); const static std::string sid("fake-session-id");
sInstance->mCallback->SessionMessage(sid.c_str(), sid.size(), sInstance->mHost->OnSessionMessage(sid.c_str(),
kGMPLicenseRequest, sid.size(),
(const uint8_t*)aMessage.c_str(), aMessage.size()); cdm::MessageType::kLicenseRequest,
aMessage.c_str(),
aMessage.size(),
nullptr,
0);
} }
std::vector<std::string> std::vector<std::string>
@ -130,40 +108,38 @@ Tokenize(const std::string& aString)
static const string TruncateRecordId = "truncate-record-id"; static const string TruncateRecordId = "truncate-record-id";
static const string TruncateRecordData = "I will soon be truncated"; static const string TruncateRecordData = "I will soon be truncated";
class ReadThenTask : public GMPTask { template<class Continuation>
class WriteRecordSuccessTask {
public: public:
ReadThenTask(string aId, ReadContinuation* aThen) WriteRecordSuccessTask(string aId, Continuation aThen)
: mId(aId) : mId(aId)
, mThen(aThen) , mThen(move(aThen))
{} {}
void Run() override {
ReadRecord(mId, mThen); void operator()()
} {
void Destroy() override { ReadRecord(FakeDecryptor::sInstance->mHost, mId, mThen);
delete this;
} }
string mId; string mId;
ReadContinuation* mThen; Continuation mThen;
}; };
class SendMessageTask : public GMPTask { class WriteRecordFailureTask {
public: public:
explicit SendMessageTask(const string& aMessage, explicit WriteRecordFailureTask(const string& aMessage,
TestManager* aTestManager = nullptr, TestManager* aTestManager = nullptr,
const string& aTestID = "") const string& aTestID = "")
: mMessage(aMessage), mTestmanager(aTestManager), mTestID(aTestID) {} : mMessage(aMessage), mTestmanager(aTestManager), mTestID(aTestID) {}
void Run() override { void operator()()
{
FakeDecryptor::Message(mMessage); FakeDecryptor::Message(mMessage);
if (mTestmanager) { if (mTestmanager) {
mTestmanager->EndTest(mTestID); mTestmanager->EndTest(mTestID);
} }
} }
void Destroy() override {
delete this;
}
private: private:
string mMessage; string mMessage;
TestManager* const mTestmanager; TestManager* const mTestmanager;
@ -175,12 +151,14 @@ public:
TestEmptyContinuation(TestManager* aTestManager, const string& aTestID) TestEmptyContinuation(TestManager* aTestManager, const string& aTestID)
: mTestmanager(aTestManager), mTestID(aTestID) {} : mTestmanager(aTestManager), mTestID(aTestID) {}
void ReadComplete(GMPErr aErr, const std::string& aData) override { virtual void operator()(bool aSuccess,
if (!aData.empty()) { const uint8_t* aData,
uint32_t aDataSize) override
{
if (aDataSize) {
FakeDecryptor::Message("FAIL TestEmptyContinuation record was not truncated"); FakeDecryptor::Message("FAIL TestEmptyContinuation record was not truncated");
} }
mTestmanager->EndTest(mTestID); mTestmanager->EndTest(mTestID);
delete this;
} }
private: private:
@ -195,15 +173,18 @@ public:
const string& aTestID) const string& aTestID)
: mID(aID), mTestmanager(aTestManager), mTestID(aTestID) {} : mID(aID), mTestmanager(aTestManager), mTestID(aTestID) {}
void ReadComplete(GMPErr aErr, const std::string& aData) override { virtual void operator()(bool aSuccess,
if (aData != TruncateRecordData) { const uint8_t* aData,
uint32_t aDataSize) override
{
if (string(reinterpret_cast<const char*>(aData), aDataSize) != TruncateRecordData) {
FakeDecryptor::Message("FAIL TruncateContinuation read data doesn't match written data"); FakeDecryptor::Message("FAIL TruncateContinuation read data doesn't match written data");
} }
auto cont = new TestEmptyContinuation(mTestmanager, mTestID); auto cont = TestEmptyContinuation(mTestmanager, mTestID);
auto msg = "FAIL in TruncateContinuation write."; auto msg = "FAIL in TruncateContinuation write.";
auto failTask = new SendMessageTask(msg, mTestmanager, mTestID); WriteRecord(FakeDecryptor::sInstance->mHost, mID, nullptr, 0,
WriteRecord(mID, nullptr, 0, new ReadThenTask(mID, cont), failTask); WriteRecordSuccessTask<TestEmptyContinuation>(mID, cont),
delete this; WriteRecordFailureTask(msg, mTestmanager, mTestID));
} }
private: private:
@ -219,12 +200,14 @@ public:
const string& aTestID) const string& aTestID)
: mValue(aValue), mTestmanager(aTestManager), mTestID(aTestID) {} : mValue(aValue), mTestmanager(aTestManager), mTestID(aTestID) {}
void ReadComplete(GMPErr aErr, const std::string& aData) override { virtual void operator()(bool aSuccess,
if (aData != mValue) { const uint8_t* aData,
uint32_t aDataSize) override
{
if (string(reinterpret_cast<const char*>(aData), aDataSize) != mValue) {
FakeDecryptor::Message("FAIL VerifyAndFinishContinuation read data doesn't match expected data"); FakeDecryptor::Message("FAIL VerifyAndFinishContinuation read data doesn't match expected data");
} }
mTestmanager->EndTest(mTestID); mTestmanager->EndTest(mTestID);
delete this;
} }
private: private:
@ -244,15 +227,18 @@ public:
, mTestID(aTestID) , mTestID(aTestID)
{} {}
void ReadComplete(GMPErr aErr, const std::string& aData) override { virtual void operator()(bool aSuccess,
if (aData != mValue) { const uint8_t* aData,
uint32_t aDataSize) override
{
if (string(reinterpret_cast<const char*>(aData), aDataSize) != mValue) {
FakeDecryptor::Message("FAIL VerifyAndOverwriteContinuation read data doesn't match expected data"); FakeDecryptor::Message("FAIL VerifyAndOverwriteContinuation read data doesn't match expected data");
} }
auto cont = new VerifyAndFinishContinuation(mOverwrite, mTestmanager, mTestID); auto cont = VerifyAndFinishContinuation(mOverwrite, mTestmanager, mTestID);
auto msg = "FAIL in VerifyAndOverwriteContinuation write."; auto msg = "FAIL in VerifyAndOverwriteContinuation write.";
auto failTask = new SendMessageTask(msg, mTestmanager, mTestID); WriteRecord(FakeDecryptor::sInstance->mHost, mId, mOverwrite,
WriteRecord(mId, mOverwrite, new ReadThenTask(mId, cont), failTask); WriteRecordSuccessTask<VerifyAndFinishContinuation>(mId, cont),
delete this; WriteRecordFailureTask(msg, mTestmanager, mTestID));
} }
private: private:
@ -267,27 +253,21 @@ static const string OpenAgainRecordId = "open-again-record-id";
class OpenedSecondTimeContinuation : public OpenContinuation { class OpenedSecondTimeContinuation : public OpenContinuation {
public: public:
explicit OpenedSecondTimeContinuation(GMPRecord* aRecord, explicit OpenedSecondTimeContinuation(TestManager* aTestManager,
TestManager* aTestManager,
const string& aTestID) const string& aTestID)
: mRecord(aRecord), mTestmanager(aTestManager), mTestID(aTestID) { : mTestmanager(aTestManager), mTestID(aTestID)
MOZ_ASSERT(aRecord); {
} }
void OpenComplete(GMPErr aStatus, GMPRecord* aRecord) override { void operator()(bool aSuccess) override {
if (GMP_SUCCEEDED(aStatus)) { if (!aSuccess) {
FakeDecryptor::Message("FAIL OpenSecondTimeContinuation should not be able to re-open record."); FakeDecryptor::Message("FAIL OpenSecondTimeContinuation should not be able to re-open record.");
} }
if (aRecord) {
aRecord->Close();
}
// Succeeded, open should have failed. // Succeeded, open should have failed.
mTestmanager->EndTest(mTestID); mTestmanager->EndTest(mTestID);
mRecord->Close();
} }
private: private:
GMPRecord* mRecord;
TestManager* const mTestmanager; TestManager* const mTestmanager;
const string mTestID; const string mTestID;
}; };
@ -299,18 +279,15 @@ public:
const string& aTestID) const string& aTestID)
: mID(aID), mTestmanager(aTestManager), mTestID(aTestID) {} : mID(aID), mTestmanager(aTestManager), mTestID(aTestID) {}
void OpenComplete(GMPErr aStatus, GMPRecord* aRecord) override { void operator()(bool aSuccess) override {
if (GMP_FAILED(aStatus)) { if (!aSuccess) {
FakeDecryptor::Message("FAIL OpenAgainContinuation to open record initially."); FakeDecryptor::Message("FAIL OpenAgainContinuation to open record initially.");
mTestmanager->EndTest(mTestID); mTestmanager->EndTest(mTestID);
if (aRecord) {
aRecord->Close();
}
return; return;
} }
auto cont = new OpenedSecondTimeContinuation(aRecord, mTestmanager, mTestID); auto cont = OpenedSecondTimeContinuation(mTestmanager, mTestID);
GMPOpenRecord(mID, cont); OpenRecord(FakeDecryptor::sInstance->mHost, mID, cont);
} }
private: private:
@ -322,8 +299,9 @@ private:
static void static void
DoTestStorage(const string& aPrefix, TestManager* aTestManager) DoTestStorage(const string& aPrefix, TestManager* aTestManager)
{ {
MOZ_ASSERT(FakeDecryptor::sInstance->mHost, "FakeDecryptor::sInstance->mHost should not be null");
// Basic I/O tests. We run three cases concurrently. The tests, like // Basic I/O tests. We run three cases concurrently. The tests, like
// GMPStorage run asynchronously. When they've all passed, we send // CDMStorage run asynchronously. When they've all passed, we send
// a message back to the parent process, or a failure message if not. // a message back to the parent process, or a failure message if not.
// Test 1: Basic I/O test, and test that writing 0 bytes in a record // Test 1: Basic I/O test, and test that writing 0 bytes in a record
@ -336,11 +314,11 @@ DoTestStorage(const string& aPrefix, TestManager* aTestManager)
const string id1 = aPrefix + TruncateRecordId; const string id1 = aPrefix + TruncateRecordId;
const string testID1 = aPrefix + "write-test-1"; const string testID1 = aPrefix + "write-test-1";
aTestManager->BeginTest(testID1); aTestManager->BeginTest(testID1);
auto cont1 = new TruncateContinuation(id1, aTestManager, testID1); auto cont1 = TruncateContinuation(id1, aTestManager, testID1);
auto msg1 = "FAIL in TestStorage writing TruncateRecord."; auto msg1 = "FAIL in TestStorage writing TruncateRecord.";
auto failTask1 = new SendMessageTask(msg1, aTestManager, testID1); WriteRecord(FakeDecryptor::sInstance->mHost, id1, TruncateRecordData,
WriteRecord(id1, TruncateRecordData, WriteRecordSuccessTask<TruncateContinuation>(id1, cont1),
new ReadThenTask(id1, cont1), failTask1); WriteRecordFailureTask(msg1, aTestManager, testID1));
// Test 2: Test that overwriting a record with a shorter record truncates // Test 2: Test that overwriting a record with a shorter record truncates
// the record to the shorter record. // the record to the shorter record.
@ -354,11 +332,12 @@ DoTestStorage(const string& aPrefix, TestManager* aTestManager)
string overwrite = "A shorter record"; string overwrite = "A shorter record";
const string testID2 = aPrefix + "write-test-2"; const string testID2 = aPrefix + "write-test-2";
aTestManager->BeginTest(testID2); aTestManager->BeginTest(testID2);
auto task2 = new VerifyAndOverwriteContinuation(id2, record1, overwrite, auto task2 = VerifyAndOverwriteContinuation(id2, record1, overwrite,
aTestManager, testID2); aTestManager, testID2);
auto msg2 = "FAIL in TestStorage writing record1."; auto msg2 = "FAIL in TestStorage writing record1.";
auto failTask2 = new SendMessageTask(msg2, aTestManager, testID2); WriteRecord(FakeDecryptor::sInstance->mHost, id2, record1,
WriteRecord(id2, record1, new ReadThenTask(id2, task2), failTask2); WriteRecordSuccessTask<VerifyAndOverwriteContinuation>(id2, task2),
WriteRecordFailureTask(msg2, aTestManager, testID2));
// Test 3: Test that opening a record while it's already open fails. // Test 3: Test that opening a record while it's already open fails.
// //
@ -368,71 +347,33 @@ DoTestStorage(const string& aPrefix, TestManager* aTestManager)
const string id3 = aPrefix + OpenAgainRecordId; const string id3 = aPrefix + OpenAgainRecordId;
const string testID3 = aPrefix + "open-test-1"; const string testID3 = aPrefix + "open-test-1";
aTestManager->BeginTest(testID3); aTestManager->BeginTest(testID3);
auto task3 = new OpenedFirstTimeContinuation(id3, aTestManager, testID3); auto task3 = OpenedFirstTimeContinuation(id3, aTestManager, testID3);
GMPOpenRecord(id3, task3); OpenRecord(FakeDecryptor::sInstance->mHost, id3, task3);
} }
class TestStorageTask : public GMPTask {
public:
TestStorageTask(const string& aPrefix, TestManager* aTestManager)
: mPrefix(aPrefix), mTestManager(aTestManager) {}
void Destroy() override { delete this; }
void Run() override {
DoTestStorage(mPrefix, mTestManager);
}
private:
const string mPrefix;
TestManager* const mTestManager;
};
void void
FakeDecryptor::TestStorage() FakeDecryptor::TestStorage()
{ {
auto* testManager = new TestManager(); auto* testManager = new TestManager();
GMPThread* thread1 = nullptr;
GMPThread* thread2 = nullptr;
// Main thread tests. // Main thread tests.
DoTestStorage("mt1-", testManager); DoTestStorage("mt1-", testManager);
DoTestStorage("mt2-", testManager); DoTestStorage("mt2-", testManager);
// Off-main-thread tests.
if (GMP_SUCCEEDED(g_platform_api->createthread(&thread1))) {
thread1->Post(new TestStorageTask("thread1-", testManager));
} else {
FakeDecryptor::Message("FAIL to create thread1 for storage tests");
}
if (GMP_SUCCEEDED(g_platform_api->createthread(&thread2))) {
thread2->Post(new TestStorageTask("thread2-", testManager));
} else {
FakeDecryptor::Message("FAIL to create thread2 for storage tests");
}
if (thread1) {
thread1->Join();
}
if (thread2) {
thread2->Join();
}
// Note: Once all tests finish, TestManager will dispatch "test-pass" message, // Note: Once all tests finish, TestManager will dispatch "test-pass" message,
// which ends the test for the parent. // which ends the test for the parent.
} }
class ReportWritten : public GMPTask { class ReportWritten
{
public: public:
ReportWritten(const string& aRecordId, const string& aValue) ReportWritten(const string& aRecordId, const string& aValue)
: mRecordId(aRecordId) : mRecordId(aRecordId)
, mValue(aValue) , mValue(aValue)
{} {}
void Run() override { void operator()() {
FakeDecryptor::Message("stored " + mRecordId + " " + mValue); FakeDecryptor::Message("stored " + mRecordId + " " + mValue);
} }
void Destroy() override {
delete this;
}
const string mRecordId; const string mRecordId;
const string mValue; const string mValue;
}; };
@ -442,18 +383,20 @@ public:
explicit ReportReadStatusContinuation(const string& aRecordId) explicit ReportReadStatusContinuation(const string& aRecordId)
: mRecordId(aRecordId) : mRecordId(aRecordId)
{} {}
void ReadComplete(GMPErr aErr, const std::string& aData) override { void operator()(bool aSuccess,
if (GMP_FAILED(aErr)) { const uint8_t* aData,
uint32_t aDataSize) override
{
if (!aSuccess) {
FakeDecryptor::Message("retrieve " + mRecordId + " failed"); FakeDecryptor::Message("retrieve " + mRecordId + " failed");
} else { } else {
stringstream ss; stringstream ss;
ss << aData.size(); ss << aDataSize;
string len; string len;
ss >> len; ss >> len;
FakeDecryptor::Message("retrieve " + mRecordId + " succeeded (length " + FakeDecryptor::Message("retrieve " + mRecordId + " succeeded (length " +
len + " bytes)"); len + " bytes)");
} }
delete this;
} }
string mRecordId; string mRecordId;
}; };
@ -463,13 +406,17 @@ public:
explicit ReportReadRecordContinuation(const string& aRecordId) explicit ReportReadRecordContinuation(const string& aRecordId)
: mRecordId(aRecordId) : mRecordId(aRecordId)
{} {}
void ReadComplete(GMPErr aErr, const std::string& aData) override { void operator()(bool aSuccess,
if (GMP_FAILED(aErr)) { const uint8_t* aData,
uint32_t aDataSize) override
{
if (!aSuccess) {
FakeDecryptor::Message("retrieved " + mRecordId + " failed"); FakeDecryptor::Message("retrieved " + mRecordId + " failed");
} else { } else {
FakeDecryptor::Message("retrieved " + mRecordId + " " + aData); FakeDecryptor::Message("retrieved " + mRecordId + " " +
string(reinterpret_cast<const char*>(aData),
aDataSize));
} }
delete this;
} }
string mRecordId; string mRecordId;
}; };
@ -490,6 +437,7 @@ FakeDecryptor::UpdateSession(uint32_t aPromiseId,
const uint8_t* aResponse, const uint8_t* aResponse,
uint32_t aResponseSize) uint32_t aResponseSize)
{ {
MOZ_ASSERT(FakeDecryptor::sInstance->mHost, "FakeDecryptor::sInstance->mHost should not be null");
std::string response((const char*)aResponse, (const char*)(aResponse)+aResponseSize); std::string response((const char*)aResponse, (const char*)(aResponse)+aResponseSize);
std::vector<std::string> tokens = Tokenize(response); std::vector<std::string> tokens = Tokenize(response);
const string& task = tokens[0]; const string& task = tokens[0];
@ -499,13 +447,14 @@ FakeDecryptor::UpdateSession(uint32_t aPromiseId,
// send "stored record" message on complete. // send "stored record" message on complete.
const string& id = tokens[1]; const string& id = tokens[1];
const string& value = tokens[2]; const string& value = tokens[2];
WriteRecord(id, WriteRecord(FakeDecryptor::sInstance->mHost,
id,
value, value,
new ReportWritten(id, value), ReportWritten(id, value),
new SendMessageTask("FAIL in writing record.")); WriteRecordFailureTask("FAIL in writing record."));
} else if (task == "retrieve") { } else if (task == "retrieve") {
const string& id = tokens[1]; const string& id = tokens[1];
ReadRecord(id, new ReportReadStatusContinuation(id)); ReadRecord(FakeDecryptor::sInstance->mHost, id, ReportReadStatusContinuation(id));
} else if (task == "shutdown-mode") { } else if (task == "shutdown-mode") {
const string& mode = tokens[1]; const string& mode = tokens[1];
if (mode == "timeout") { if (mode == "timeout") {
@ -516,8 +465,10 @@ FakeDecryptor::UpdateSession(uint32_t aPromiseId,
Message("shutdown-token received " + sShutdownToken); Message("shutdown-token received " + sShutdownToken);
} }
} else if (task == "retrieve-shutdown-token") { } else if (task == "retrieve-shutdown-token") {
ReadRecord("shutdown-token", new ReportReadRecordContinuation("shutdown-token")); ReadRecord(FakeDecryptor::sInstance->mHost,
"shutdown-token",
ReportReadRecordContinuation("shutdown-token"));
} else if (task == "test-op-apis") { } else if (task == "test-op-apis") {
mozilla::gmptest::TestOuputProtectionAPIs(); mozilla::cdmtest::TestOuputProtectionAPIs();
} }
} }

Просмотреть файл

@ -0,0 +1,138 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef FAKE_DECRYPTOR_H__
#define FAKE_DECRYPTOR_H__
#include "content_decryption_module.h"
#include <string>
#include "mozilla/Attributes.h"
class FakeDecryptor : public cdm::ContentDecryptionModule_8 {
public:
explicit FakeDecryptor(cdm::Host_8* aHost);
void Initialize(bool aAllowDistinctiveIdentifier,
bool aAllowPersistentState) override
{
}
void SetServerCertificate(uint32_t aPromiseId,
const uint8_t* aServerCertificateData,
uint32_t aServerCertificateDataSize)
override
{
}
void CreateSessionAndGenerateRequest(uint32_t aPromiseId,
cdm::SessionType aSessionType,
cdm::InitDataType aInitDataType,
const uint8_t* aInitData,
uint32_t aInitDataSize)
override
{
}
void LoadSession(uint32_t aPromiseId,
cdm::SessionType aSessionType,
const char* aSessionId,
uint32_t aSessionIdSize) override
{
}
void UpdateSession(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdSize,
const uint8_t* aResponse,
uint32_t aResponseSize) override;
void CloseSession(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdSize) override
{
}
void RemoveSession(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdSize) override
{
}
void TimerExpired(void* aContext) override
{
}
cdm::Status Decrypt(const cdm::InputBuffer& aEncryptedBuffer,
cdm::DecryptedBlock* aDecryptedBuffer) override
{
return cdm::Status::kDecodeError;
}
cdm::Status InitializeAudioDecoder(
const cdm::AudioDecoderConfig& aAudioDecoderConfig) override
{
return cdm::Status::kDecodeError;
}
cdm::Status InitializeVideoDecoder(
const cdm::VideoDecoderConfig& aVideoDecoderConfig) override
{
return cdm::Status::kDecodeError;
}
void DeinitializeDecoder(cdm::StreamType aDecoderType) override
{
}
void ResetDecoder(cdm::StreamType aDecoderType) override
{
}
cdm::Status DecryptAndDecodeFrame(
const cdm::InputBuffer& aEncryptedBuffer,
cdm::VideoFrame* aVideoFrame) override
{
return cdm::Status::kDecodeError;
}
cdm::Status DecryptAndDecodeSamples(
const cdm::InputBuffer& aEncryptedBuffer,
cdm::AudioFrames* aAudioFrame) override
{
return cdm::Status::kDecodeError;
}
void OnPlatformChallengeResponse(
const cdm::PlatformChallengeResponse& aResponse) override
{
}
void OnQueryOutputProtectionStatus(cdm::QueryResult aResult,
uint32_t aLinkMask,
uint32_t aOutputProtectionMask) override
{
}
void Destroy() override
{
delete this;
sInstance = nullptr;
}
static void Message(const std::string& aMessage);
cdm::Host_8* mHost;
static FakeDecryptor* sInstance;
private:
virtual ~FakeDecryptor() {}
void TestStorage();
};
#endif

Просмотреть файл

@ -15,7 +15,7 @@
#endif #endif
namespace mozilla { namespace mozilla {
namespace gmptest { namespace cdmtest {
#if defined(XP_WIN) #if defined(XP_WIN)
typedef HRESULT(STDAPICALLTYPE * OPMGetVideoOutputsFromHMONITORProc) typedef HRESULT(STDAPICALLTYPE * OPMGetVideoOutputsFromHMONITORProc)
@ -125,5 +125,5 @@ TestOuputProtectionAPIs()
FakeDecryptor::Message("OP tests completed"); FakeDecryptor::Message("OP tests completed");
} }
} // namespace gmptest } // namespace cdmtest
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -0,0 +1,252 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "cdm-test-storage.h"
#include <vector>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
using namespace cdm;
using namespace std;
class WriteRecordClient : public FileIOClient
{
public:
WriteRecordClient(function<void()>&& aOnSuccess,
function<void()>&& aOnFailure,
const uint8_t* aData,
uint32_t aDataSize)
: mOnSuccess(move(aOnSuccess))
, mOnFailure(move(aOnFailure))
{
mData.insert(mData.end(), aData, aData + aDataSize);
}
void OnOpenComplete(Status aStatus) override
{
// If we hit an error, fail.
if (aStatus != Status::kSuccess) {
Done(aStatus);
} else if (mFileIO) { // Otherwise, write our data to the file.
mFileIO->Write(mData.empty() ? nullptr : &mData.front(), mData.size());
}
}
void OnReadComplete(Status aStatus,
const uint8_t* aData,
uint32_t aDataSize) override
{
}
void OnWriteComplete(Status aStatus) override
{
Done(aStatus);
}
void Do(const string& aName, Host_8* aHost)
{
// Initialize the FileIO.
mFileIO = aHost->CreateFileIO(this);
mFileIO->Open(aName.c_str(), aName.size());
}
private:
void Done(cdm::FileIOClient::Status aStatus)
{
// Note: Call Close() before running continuation, in case the
// continuation tries to open the same record; if we call Close()
// after running the continuation, the Close() call will arrive
// just after the Open() call succeeds, immediately closing the
// record we just opened.
if (mFileIO) {
// will delete mFileIO inside Close.
mFileIO->Close();
}
if (IO_SUCCEEDED(aStatus)) {
mOnSuccess();
} else {
mOnFailure();
}
delete this;
}
FileIO* mFileIO = nullptr;
function<void()> mOnSuccess;
function<void()> mOnFailure;
std::vector<uint8_t> mData;
};
void
WriteRecord(Host_8* aHost,
const std::string& aRecordName,
const uint8_t* aData,
uint32_t aNumBytes,
function<void()>&& aOnSuccess,
function<void()>&& aOnFailure)
{
// client will be delete in WriteRecordClient::Done
WriteRecordClient* client = new WriteRecordClient(move(aOnSuccess),
move(aOnFailure),
aData,
aNumBytes);
client->Do(aRecordName, aHost);
}
void
WriteRecord(Host_8* aHost,
const std::string& aRecordName,
const std::string& aData,
function<void()> &&aOnSuccess,
function<void()>&& aOnFailure)
{
return WriteRecord(aHost,
aRecordName,
(const uint8_t*)aData.c_str(),
aData.size(),
move(aOnSuccess),
move(aOnFailure));
}
class ReadRecordClient : public FileIOClient
{
public:
explicit ReadRecordClient(function<void(bool, const uint8_t*, uint32_t)>&& aOnReadComplete)
: mOnReadComplete(move(aOnReadComplete))
{
}
void OnOpenComplete(Status aStatus) override
{
auto err = aStatus;
if (aStatus != Status::kSuccess) {
Done(err, reinterpret_cast<const uint8_t*>(""), 0);
} else {
mFileIO->Read();
}
}
void OnReadComplete(Status aStatus,
const uint8_t* aData,
uint32_t aDataSize) override
{
Done(aStatus, aData, aDataSize);
}
void OnWriteComplete(Status aStatus) override
{
}
void Do(const string& aName, Host_8* aHost)
{
mFileIO = aHost->CreateFileIO(this);
mFileIO->Open(aName.c_str(), aName.size());
}
private:
void Done(cdm::FileIOClient::Status aStatus,
const uint8_t* aData,
uint32_t aDataSize)
{
// Note: Call Close() before running continuation, in case the
// continuation tries to open the same record; if we call Close()
// after running the continuation, the Close() call will arrive
// just after the Open() call succeeds, immediately closing the
// record we just opened.
if (mFileIO) {
// will delete mFileIO inside Close.
mFileIO->Close();
}
if (IO_SUCCEEDED(aStatus)) {
mOnReadComplete(true, aData, aDataSize);
} else {
mOnReadComplete(false, reinterpret_cast<const uint8_t*>(""), 0);
}
delete this;
}
FileIO* mFileIO = nullptr;
function<void(bool, const uint8_t*, uint32_t)> mOnReadComplete;
};
void
ReadRecord(Host_8* aHost,
const std::string& aRecordName,
function<void(bool, const uint8_t*, uint32_t)>&& aOnReadComplete)
{
// client will be delete in ReadRecordClient::Done
ReadRecordClient* client = new ReadRecordClient(move(aOnReadComplete));
client->Do(aRecordName, aHost);
}
class OpenRecordClient : public FileIOClient
{
public:
explicit OpenRecordClient(function<void(bool)>&& aOpenComplete)
: mOpenComplete(move(aOpenComplete))
{
}
void OnOpenComplete(Status aStatus) override
{
Done(aStatus);
}
void OnReadComplete(Status aStatus,
const uint8_t* aData,
uint32_t aDataSize) override
{
}
void OnWriteComplete(Status aStatus) override
{
}
void Do(const string& aName, Host_8* aHost)
{
// Initialize the FileIO.
mFileIO = aHost->CreateFileIO(this);
mFileIO->Open(aName.c_str(), aName.size());
}
private:
void Done(cdm::FileIOClient::Status aStatus)
{
// Note: Call Close() before running continuation, in case the
// continuation tries to open the same record; if we call Close()
// after running the continuation, the Close() call will arrive
// just after the Open() call succeeds, immediately closing the
// record we just opened.
if (mFileIO) {
// will delete mFileIO inside Close.
mFileIO->Close();
}
if (IO_SUCCEEDED(aStatus)) {
mOpenComplete(true);
} else {
mOpenComplete(false);
}
delete this;
}
FileIO* mFileIO = nullptr;
function<void(bool)> mOpenComplete;;
};
void
OpenRecord(Host_8* aHost,
const std::string& aRecordName,
function<void(bool)>&& aOpenComplete)
{
// client will be delete in OpenRecordClient::Done
OpenRecordClient* client = new OpenRecordClient(move(aOpenComplete));
client->Do(aRecordName, aHost);
}

Просмотреть файл

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef TEST_CDM_STORAGE_H__
#define TEST_CDM_STORAGE_H__
#include <functional>
#include <string>
#include <vector>
// This include is required in order for content_decryption_module to work
// on Unix systems.
#include "stddef.h"
#include "content_decryption_module.h"
#define IO_SUCCEEDED(x) ((x) == cdm::FileIOClient::Status::kSuccess)
#define IO_FAILED(x) ((x) != cdm::FileIOClient::Status::kSuccess)
class ReadContinuation {
public:
virtual ~ReadContinuation() {}
virtual void operator()(bool aSuccess,
const uint8_t* aData,
uint32_t aDataSize) = 0;
};
void WriteRecord(cdm::Host_8* aHost,
const std::string& aRecordName,
const std::string& aData,
std::function<void()>&& aOnSuccess,
std::function<void()>&& aOnFailure);
void WriteRecord(cdm::Host_8* aHost,
const std::string& aRecordName,
const uint8_t* aData,
uint32_t aNumBytes,
std::function<void()>&& aOnSuccess,
std::function<void()>&& aOnFailure);
void ReadRecord(cdm::Host_8* aHost,
const std::string& aRecordName,
std::function<void(bool, const uint8_t*, uint32_t)>&& aOnReadComplete);
class OpenContinuation {
public:
virtual ~OpenContinuation() {}
virtual void operator()(bool aSuccess) = 0;
};
void OpenRecord(cdm::Host_8* aHost,
const std::string& aRecordName,
std::function<void(bool)>&& aOpenComplete);
#endif // TEST_CDM_STORAGE_H__

Просмотреть файл

@ -0,0 +1,9 @@
{
"name": "fake",
"description": "Fake CDM Plugin",
"version": "1",
"x-cdm-module-versions": "4",
"x-cdm-interface-versions": "8",
"x-cdm-host-versions": "8",
"x-cdm-codecs": ""
}

Просмотреть файл

@ -7,17 +7,16 @@
FINAL_TARGET = 'dist/bin/gmp-fake/1.0' FINAL_TARGET = 'dist/bin/gmp-fake/1.0'
FINAL_TARGET_FILES += [ FINAL_TARGET_FILES += [
'fake.info', 'manifest.json',
'fake.voucher',
] ]
SOURCES += [ SOURCES += [
'gmp-fake.cpp', 'cdm-fake.cpp',
'gmp-test-decryptor.cpp', 'cdm-test-decryptor.cpp',
'gmp-test-storage.cpp', 'cdm-test-storage.cpp',
] ]
DEFINES['GMP_FAKE_SUPPORT_DECRYPT'] = True DEFINES['CDM_IMPLEMENTATION'] = True
SharedLibrary("fake") SharedLibrary("fake")

Просмотреть файл

@ -1 +0,0 @@
gmp-fakeopenh264 placeholder voucher

Просмотреть файл

@ -50,12 +50,6 @@
#include "gmp-video-frame-i420.h" #include "gmp-video-frame-i420.h"
#include "gmp-video-frame-encoded.h" #include "gmp-video-frame-encoded.h"
#if defined(GMP_FAKE_SUPPORT_DECRYPT)
#include "gmp-decryption.h"
#include "gmp-test-decryptor.h"
#include "gmp-test-storage.h"
#endif
#include "mozilla/PodOperations.h" #include "mozilla/PodOperations.h"
#if defined(_MSC_VER) #if defined(_MSC_VER)
@ -476,12 +470,6 @@ extern "C" {
if (!strcmp (aApiName, GMP_API_VIDEO_ENCODER)) { if (!strcmp (aApiName, GMP_API_VIDEO_ENCODER)) {
*aPluginApi = new FakeVideoEncoder (static_cast<GMPVideoHost*> (aHostAPI)); *aPluginApi = new FakeVideoEncoder (static_cast<GMPVideoHost*> (aHostAPI));
return GMPNoErr; return GMPNoErr;
#if defined(GMP_FAKE_SUPPORT_DECRYPT)
}
if (!strcmp (aApiName, GMP_API_DECRYPTOR)) {
*aPluginApi = new FakeDecryptor();
return GMPNoErr;
#endif
} }
return GMPGenericErr; return GMPGenericErr;
} }

Просмотреть файл

@ -10,7 +10,6 @@ FINAL_TARGET = 'dist/bin/gmp-fakeopenh264/1.0'
FINAL_TARGET_FILES += [ FINAL_TARGET_FILES += [
'fakeopenh264.info', 'fakeopenh264.info',
'fakeopenh264.voucher',
] ]
SOURCES += [ SOURCES += [

Просмотреть файл

@ -1,5 +0,0 @@
Name: fake
Description: Fake GMP Plugin.
Version: 1.0
APIs: decode-video[h264:broken], eme-decrypt-v9[fake]
Libraries: dxva2.dll

Просмотреть файл

@ -1 +0,0 @@
gmp-fake placeholder voucher

Просмотреть файл

@ -1,84 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef FAKE_DECRYPTOR_H__
#define FAKE_DECRYPTOR_H__
#include "gmp-decryption.h"
#include <string>
#include "mozilla/Attributes.h"
class FakeDecryptor : public GMPDecryptor {
public:
explicit FakeDecryptor();
void Init(GMPDecryptorCallback* aCallback,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired) override
{
mCallback = aCallback;
}
void CreateSession(uint32_t aCreateSessionToken,
uint32_t aPromiseId,
const char* aInitDataType,
uint32_t aInitDataTypeSize,
const uint8_t* aInitData,
uint32_t aInitDataSize,
GMPSessionType aSessionType) override
{
}
void LoadSession(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdLength) override
{
}
void UpdateSession(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aResponse,
uint32_t aResponseSize) override;
void CloseSession(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdLength) override
{
}
void RemoveSession(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdLength) override
{
}
void SetServerCertificate(uint32_t aPromiseId,
const uint8_t* aServerCert,
uint32_t aServerCertSize) override
{
}
void Decrypt(GMPBuffer* aBuffer,
GMPEncryptedBufferMetadata* aMetadata) override
{
}
void DecryptingComplete() override;
static void Message(const std::string& aMessage);
private:
virtual ~FakeDecryptor() {}
static FakeDecryptor* sInstance;
void TestStorage();
GMPDecryptorCallback* mCallback;
};
#endif

Просмотреть файл

@ -1,226 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gmp-test-storage.h"
#include <vector>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
class WriteRecordClient : public GMPRecordClient {
public:
GMPErr Init(GMPRecord* aRecord,
GMPTask* aOnSuccess,
GMPTask* aOnFailure,
const uint8_t* aData,
uint32_t aDataSize) {
mRecord = aRecord;
mOnSuccess = aOnSuccess;
mOnFailure = aOnFailure;
mData.insert(mData.end(), aData, aData + aDataSize);
return mRecord->Open();
}
void OpenComplete(GMPErr aStatus) override {
if (GMP_SUCCEEDED(aStatus)) {
mRecord->Write(mData.empty() ? nullptr : &mData.front(), mData.size());
} else {
GMPRunOnMainThread(mOnFailure);
mOnSuccess->Destroy();
}
}
void ReadComplete(GMPErr aStatus,
const uint8_t* aData,
uint32_t aDataSize) override {}
void WriteComplete(GMPErr aStatus) override {
// Note: Call Close() before running continuation, in case the
// continuation tries to open the same record; if we call Close()
// after running the continuation, the Close() call will arrive
// just after the Open() call succeeds, immediately closing the
// record we just opened.
mRecord->Close();
if (GMP_SUCCEEDED(aStatus)) {
GMPRunOnMainThread(mOnSuccess);
mOnFailure->Destroy();
} else {
GMPRunOnMainThread(mOnFailure);
mOnSuccess->Destroy();
}
delete this;
}
private:
GMPRecord* mRecord;
GMPTask* mOnSuccess;
GMPTask* mOnFailure;
std::vector<uint8_t> mData;
};
GMPErr
WriteRecord(const std::string& aRecordName,
const uint8_t* aData,
uint32_t aNumBytes,
GMPTask* aOnSuccess,
GMPTask* aOnFailure)
{
GMPRecord* record;
auto* client = new WriteRecordClient();
auto err = GMPOpenRecord(aRecordName.c_str(),
aRecordName.size(),
&record,
client);
if (GMP_FAILED(err)) {
GMPRunOnMainThread(aOnFailure);
aOnSuccess->Destroy();
return err;
}
return client->Init(record, aOnSuccess, aOnFailure, aData, aNumBytes);
}
GMPErr
WriteRecord(const std::string& aRecordName,
const std::string& aData,
GMPTask* aOnSuccess,
GMPTask* aOnFailure)
{
return WriteRecord(aRecordName,
(const uint8_t*)aData.c_str(),
aData.size(),
aOnSuccess,
aOnFailure);
}
class ReadRecordClient : public GMPRecordClient {
public:
GMPErr Init(GMPRecord* aRecord,
ReadContinuation* aContinuation) {
mRecord = aRecord;
mContinuation = aContinuation;
return mRecord->Open();
}
void OpenComplete(GMPErr aStatus) override {
auto err = mRecord->Read();
if (GMP_FAILED(err)) {
mContinuation->ReadComplete(err, "");
delete this;
}
}
void ReadComplete(GMPErr aStatus,
const uint8_t* aData,
uint32_t aDataSize) override {
// Note: Call Close() before running continuation, in case the
// continuation tries to open the same record; if we call Close()
// after running the continuation, the Close() call will arrive
// just after the Open() call succeeds, immediately closing the
// record we just opened.
mRecord->Close();
std::string data((const char*)aData, aDataSize);
mContinuation->ReadComplete(GMPNoErr, data);
delete this;
}
void WriteComplete(GMPErr aStatus) override {
}
private:
GMPRecord* mRecord;
ReadContinuation* mContinuation;
};
GMPErr
ReadRecord(const std::string& aRecordName,
ReadContinuation* aContinuation)
{
MOZ_ASSERT(aContinuation);
GMPRecord* record;
auto* client = new ReadRecordClient();
auto err = GMPOpenRecord(aRecordName.c_str(),
aRecordName.size(),
&record,
client);
if (GMP_FAILED(err)) {
return err;
}
return client->Init(record, aContinuation);
}
extern GMPPlatformAPI* g_platform_api; // Defined in gmp-fake.cpp
GMPErr
GMPOpenRecord(const char* aName,
uint32_t aNameLength,
GMPRecord** aOutRecord,
GMPRecordClient* aClient)
{
MOZ_ASSERT(g_platform_api);
return g_platform_api->createrecord(aName, aNameLength, aOutRecord, aClient);
}
GMPErr
GMPRunOnMainThread(GMPTask* aTask)
{
MOZ_ASSERT(g_platform_api);
return g_platform_api->runonmainthread(aTask);
}
class OpenRecordClient : public GMPRecordClient {
public:
/*
* This function will take the memory ownership of the parameters and
* delete them when done.
*/
static void Open(const std::string& aRecordName,
OpenContinuation* aContinuation) {
MOZ_ASSERT(aContinuation);
(new OpenRecordClient(aContinuation))->Do(aRecordName);
}
void OpenComplete(GMPErr aStatus) override {
Done(aStatus);
}
void ReadComplete(GMPErr aStatus,
const uint8_t* aData,
uint32_t aDataSize) override {
MOZ_CRASH("Should not reach here.");
}
void WriteComplete(GMPErr aStatus) override {
MOZ_CRASH("Should not reach here.");
}
private:
explicit OpenRecordClient(OpenContinuation* aContinuation)
: mRecord(nullptr), mContinuation(aContinuation) {}
void Do(const std::string& aName) {
auto err = GMPOpenRecord(aName.c_str(), aName.size(), &mRecord, this);
if (GMP_FAILED(err) ||
GMP_FAILED(err = mRecord->Open())) {
Done(err);
}
}
void Done(GMPErr err) {
// mContinuation is responsible for closing mRecord.
mContinuation->OpenComplete(err, mRecord);
delete mContinuation;
delete this;
}
GMPRecord* mRecord;
OpenContinuation* mContinuation;
};
void
GMPOpenRecord(const std::string& aRecordName,
OpenContinuation* aContinuation)
{
OpenRecordClient::Open(aRecordName, aContinuation);
}

Просмотреть файл

@ -1,59 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef TEST_GMP_STORAGE_H__
#define TEST_GMP_STORAGE_H__
#include "gmp-errors.h"
#include "gmp-platform.h"
#include <string>
class ReadContinuation {
public:
virtual ~ReadContinuation() {}
virtual void ReadComplete(GMPErr aErr, const std::string& aData) = 0;
};
// Reads a record to storage using GMPRecord.
// Calls ReadContinuation with read data.
GMPErr
ReadRecord(const std::string& aRecordName,
ReadContinuation* aContinuation);
// Writes a record to storage using GMPRecord.
// Runs continuation when data is written.
GMPErr
WriteRecord(const std::string& aRecordName,
const std::string& aData,
GMPTask* aOnSuccess,
GMPTask* aOnFailure);
GMPErr
WriteRecord(const std::string& aRecordName,
const uint8_t* aData,
uint32_t aNumBytes,
GMPTask* aOnSuccess,
GMPTask* aOnFailure);
GMPErr
GMPOpenRecord(const char* aName,
uint32_t aNameLength,
GMPRecord** aOutRecord,
GMPRecordClient* aClient);
GMPErr
GMPRunOnMainThread(GMPTask* aTask);
class OpenContinuation {
public:
virtual ~OpenContinuation() {}
virtual void OpenComplete(GMPErr aStatus, GMPRecord* aRecord) = 0;
};
void
GMPOpenRecord(const std::string& aRecordName,
OpenContinuation* aContinuation);
#endif // TEST_GMP_STORAGE_H__

Просмотреть файл

@ -8,9 +8,7 @@
#include "content_decryption_module_ext.h" #include "content_decryption_module_ext.h"
#include "VideoUtils.h" #include "VideoUtils.h"
#include "gmp-api/gmp-entrypoints.h" #include "gmp-api/gmp-entrypoints.h"
#include "gmp-api/gmp-decryption.h"
#include "gmp-api/gmp-video-codec.h" #include "gmp-api/gmp-video-codec.h"
#include "gmp-api/gmp-platform.h"
#include "WidevineUtils.h" #include "WidevineUtils.h"
#include "GMPLog.h" #include "GMPLog.h"
#include "mozilla/Move.h" #include "mozilla/Move.h"

Просмотреть файл

@ -494,7 +494,7 @@ ChromiumCDMProxy::OnKeyStatusesChange(const nsAString& aSessionId)
void void
ChromiumCDMProxy::OnExpirationChange(const nsAString& aSessionId, ChromiumCDMProxy::OnExpirationChange(const nsAString& aSessionId,
GMPTimestamp aExpiryTime) UnixTime aExpiryTime)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mKeys.IsNull()) { if (mKeys.IsNull()) {

Просмотреть файл

@ -71,7 +71,7 @@ public:
const nsTArray<uint8_t>& aMessage) override; const nsTArray<uint8_t>& aMessage) override;
void OnExpirationChange(const nsAString& aSessionId, void OnExpirationChange(const nsAString& aSessionId,
GMPTimestamp aExpiryTime) override; UnixTime aExpiryTime) override;
void OnSessionClosed(const nsAString& aSessionId) override; void OnSessionClosed(const nsAString& aSessionId) override;
@ -130,4 +130,4 @@ private:
} // namespace mozilla } // namespace mozilla
#endif // GMPCDMProxy_h_ #endif // ChromiumCDMProxy_h_

Просмотреть файл

@ -1,231 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "GMPCDMCallbackProxy.h"
#include "mozilla/CDMProxy.h"
#include "nsString.h"
#include "mozilla/dom/MediaKeys.h"
#include "mozilla/dom/MediaKeySession.h"
#include "mozIGeckoMediaPluginService.h"
#include "nsContentCID.h"
#include "nsServiceManagerUtils.h"
#include "MainThreadUtils.h"
#include "mozilla/EMEUtils.h"
namespace mozilla {
GMPCDMCallbackProxy::GMPCDMCallbackProxy(CDMProxy* aProxy,
nsIEventTarget* aMainThread)
: mProxy(aProxy)
, mMainThread(aMainThread)
{}
void
GMPCDMCallbackProxy::SetDecryptorId(uint32_t aId)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
mMainThread->Dispatch(
NS_NewRunnableFunction("GMPCDMCallbackProxy::SetDecryptorId",
[proxy, aId]() { proxy->OnSetDecryptorId(aId); }),
NS_DISPATCH_NORMAL);
}
void
GMPCDMCallbackProxy::SetSessionId(uint32_t aToken,
const nsCString& aSessionId)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
mMainThread->Dispatch(
NS_NewRunnableFunction(
"GMPCDMCallbackProxy::SetSessionId",
[proxy, aToken, sid]() { proxy->OnSetSessionId(aToken, sid); }),
NS_DISPATCH_NORMAL);
}
void
GMPCDMCallbackProxy::ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccess)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
mMainThread->Dispatch(
NS_NewRunnableFunction("GMPCDMCallbackProxy::ResolveLoadSessionPromise",
[proxy, aPromiseId, aSuccess]() {
proxy->OnResolveLoadSessionPromise(aPromiseId,
aSuccess);
}),
NS_DISPATCH_NORMAL);
}
void
GMPCDMCallbackProxy::ResolvePromise(uint32_t aPromiseId)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
// Note: CDMProxy proxies this from non-main threads to main thread.
mProxy->ResolvePromise(aPromiseId);
}
void
GMPCDMCallbackProxy::RejectPromise(uint32_t aPromiseId,
nsresult aException,
const nsCString& aMessage)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
mMainThread->Dispatch(
NS_NewRunnableFunction("GMPCDMCallbackProxy::RejectPromise",
[proxy, aPromiseId, aException, aMessage]() {
proxy->OnRejectPromise(
aPromiseId, aException, aMessage);
}),
NS_DISPATCH_NORMAL);
}
void
GMPCDMCallbackProxy::SessionMessage(const nsCString& aSessionId,
dom::MediaKeyMessageType aMessageType,
const nsTArray<uint8_t>& aMessage)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
nsTArray<uint8_t> msg(aMessage);
mMainThread->Dispatch(
NS_NewRunnableFunction("GMPCDMCallbackProxy::SessionMessage",
[proxy, sid, aMessageType, msg]() mutable {
proxy->OnSessionMessage(sid, aMessageType, msg);
}),
NS_DISPATCH_NORMAL);
}
void
GMPCDMCallbackProxy::ExpirationChange(const nsCString& aSessionId,
GMPTimestamp aExpiryTime)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
mMainThread->Dispatch(
NS_NewRunnableFunction("GMPCDMCallbackProxy::ExpirationChange",
[proxy, sid, aExpiryTime]() {
proxy->OnExpirationChange(sid, aExpiryTime);
}),
NS_DISPATCH_NORMAL);
}
void
GMPCDMCallbackProxy::SessionClosed(const nsCString& aSessionId)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
bool keyStatusesChange = false;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
{
CDMCaps::AutoLock caps(mProxy->Capabilites());
keyStatusesChange = caps.RemoveKeysForSession(NS_ConvertUTF8toUTF16(aSessionId));
}
if (keyStatusesChange) {
RefPtr<CDMProxy> proxy = mProxy;
mMainThread->Dispatch(
NS_NewRunnableFunction(
"GMPCDMCallbackProxy::SessionClosed",
[proxy, sid]() { proxy->OnKeyStatusesChange(sid); }),
NS_DISPATCH_NORMAL);
}
RefPtr<CDMProxy> proxy = mProxy;
mMainThread->Dispatch(
NS_NewRunnableFunction("GMPCDMCallbackProxy::SessionClosed",
[proxy, sid]() { proxy->OnSessionClosed(sid); }),
NS_DISPATCH_NORMAL);
}
void
GMPCDMCallbackProxy::SessionError(const nsCString& aSessionId,
nsresult aException,
uint32_t aSystemCode,
const nsCString& aMessage)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
auto msg = NS_ConvertUTF8toUTF16(aMessage);
mMainThread->Dispatch(
NS_NewRunnableFunction("GMPCDMCallbackProxy::SessionError",
[proxy, sid, aException, aSystemCode, msg]() {
proxy->OnSessionError(
sid, aException, aSystemCode, msg);
}),
NS_DISPATCH_NORMAL);
}
void
GMPCDMCallbackProxy::BatchedKeyStatusChanged(const nsCString& aSessionId,
const nsTArray<CDMKeyInfo>& aKeyInfos)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
BatchedKeyStatusChangedInternal(aSessionId, aKeyInfos);
}
void
GMPCDMCallbackProxy::BatchedKeyStatusChangedInternal(const nsCString& aSessionId,
const nsTArray<CDMKeyInfo>& aKeyInfos)
{
bool keyStatusesChange = false;
{
CDMCaps::AutoLock caps(mProxy->Capabilites());
for (size_t i = 0; i < aKeyInfos.Length(); i++) {
keyStatusesChange |=
caps.SetKeyStatus(aKeyInfos[i].mKeyId,
NS_ConvertUTF8toUTF16(aSessionId),
aKeyInfos[i].mStatus);
}
}
if (keyStatusesChange) {
RefPtr<CDMProxy> proxy = mProxy;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
mMainThread->Dispatch(
NS_NewRunnableFunction(
"GMPCDMCallbackProxy::BatchedKeyStatusChangedInternal",
[proxy, sid]() { proxy->OnKeyStatusesChange(sid); }),
NS_DISPATCH_NORMAL);
}
}
void
GMPCDMCallbackProxy::Decrypted(uint32_t aId,
DecryptStatus aResult,
const nsTArray<uint8_t>& aDecryptedData)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
mProxy->OnDecrypted(aId, aResult, aDecryptedData);
}
void
GMPCDMCallbackProxy::Terminated()
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
mMainThread->Dispatch(
NS_NewRunnableFunction("GMPCDMCallbackProxy::Terminated",
[proxy]() { proxy->Terminated(); }),
NS_DISPATCH_NORMAL);
}
} // namespace mozilla

Просмотреть файл

@ -1,74 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 GMPCDMCallbackProxy_h_
#define GMPCDMCallbackProxy_h_
#include "mozilla/CDMProxy.h"
#include "gmp-decryption.h"
#include "GMPDecryptorProxy.h"
namespace mozilla {
// Proxies call backs from the CDM on the GMP thread back to the MediaKeys
// object on the main thread.
class GMPCDMCallbackProxy : public GMPDecryptorProxyCallback {
public:
void SetDecryptorId(uint32_t aId) override;
void SetSessionId(uint32_t aCreateSessionToken,
const nsCString& aSessionId) override;
void ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccess) override;
void ResolvePromise(uint32_t aPromiseId) override;
void RejectPromise(uint32_t aPromiseId,
nsresult aException,
const nsCString& aSessionId) override;
void SessionMessage(const nsCString& aSessionId,
dom::MediaKeyMessageType aMessageType,
const nsTArray<uint8_t>& aMessage) override;
void ExpirationChange(const nsCString& aSessionId,
UnixTime aExpiryTime) override;
void SessionClosed(const nsCString& aSessionId) override;
void SessionError(const nsCString& aSessionId,
nsresult aException,
uint32_t aSystemCode,
const nsCString& aMessage) override;
void Decrypted(uint32_t aId,
DecryptStatus aResult,
const nsTArray<uint8_t>& aDecryptedData) override;
void BatchedKeyStatusChanged(const nsCString& aSessionId,
const nsTArray<CDMKeyInfo>& aKeyInfos) override;
void Terminated() override;
~GMPCDMCallbackProxy() {}
private:
friend class GMPCDMProxy;
GMPCDMCallbackProxy(CDMProxy* aProxy, nsIEventTarget* aMainThread);
void BatchedKeyStatusChangedInternal(const nsCString& aSessionId,
const nsTArray<CDMKeyInfo>& aKeyInfos);
// Warning: Weak ref.
CDMProxy* mProxy;
const nsCOMPtr<nsIEventTarget> mMainThread;
};
} // namespace mozilla
#endif // GMPCDMCallbackProxy_h_

Просмотреть файл

@ -9,7 +9,6 @@
#include "GMPLoader.h" #include "GMPLoader.h"
#include "GMPVideoDecoderChild.h" #include "GMPVideoDecoderChild.h"
#include "GMPVideoEncoderChild.h" #include "GMPVideoEncoderChild.h"
#include "GMPDecryptorChild.h"
#include "GMPVideoHost.h" #include "GMPVideoHost.h"
#include "nsDebugImpl.h" #include "nsDebugImpl.h"
#include "nsIFile.h" #include "nsIFile.h"

Просмотреть файл

@ -5,7 +5,6 @@
#include "GMPContentChild.h" #include "GMPContentChild.h"
#include "GMPChild.h" #include "GMPChild.h"
#include "GMPDecryptorChild.h"
#include "GMPVideoDecoderChild.h" #include "GMPVideoDecoderChild.h"
#include "GMPVideoEncoderChild.h" #include "GMPVideoEncoderChild.h"
#include "ChromiumCDMChild.h" #include "ChromiumCDMChild.h"
@ -50,21 +49,6 @@ GMPContentChild::ProcessingError(Result aCode, const char* aReason)
mGMPChild->ProcessingError(aCode, aReason); mGMPChild->ProcessingError(aCode, aReason);
} }
PGMPDecryptorChild*
GMPContentChild::AllocPGMPDecryptorChild()
{
GMPDecryptorChild* actor = new GMPDecryptorChild(this);
actor->AddRef();
return actor;
}
bool
GMPContentChild::DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor)
{
static_cast<GMPDecryptorChild*>(aActor)->Release();
return true;
}
PGMPVideoDecoderChild* PGMPVideoDecoderChild*
GMPContentChild::AllocPGMPVideoDecoderChild(const uint32_t& aDecryptorId) GMPContentChild::AllocPGMPVideoDecoderChild(const uint32_t& aDecryptorId)
{ {
@ -110,22 +94,6 @@ GMPContentChild::DeallocPChromiumCDMChild(PChromiumCDMChild* aActor)
return true; return true;
} }
mozilla::ipc::IPCResult
GMPContentChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
{
GMPDecryptorChild* child = static_cast<GMPDecryptorChild*>(aActor);
void* ptr = nullptr;
GMPErr err = mGMPChild->GetAPI(GMP_API_DECRYPTOR, nullptr, &ptr, child->DecryptorId());
if (err != GMPNoErr || !ptr) {
NS_WARNING("GMPGetAPI call failed trying to construct decryptor.");
return IPC_FAIL_NO_REASON(this);
}
child->Init(static_cast<GMPDecryptor*>(ptr));
return IPC_OK();
}
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
GMPContentChild::RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor, GMPContentChild::RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor,
const uint32_t& aDecryptorId) const uint32_t& aDecryptorId)
@ -183,12 +151,6 @@ void
GMPContentChild::CloseActive() GMPContentChild::CloseActive()
{ {
// Invalidate and remove any remaining API objects. // Invalidate and remove any remaining API objects.
const ManagedContainer<PGMPDecryptorChild>& decryptors =
ManagedPGMPDecryptorChild();
for (auto iter = decryptors.ConstIter(); !iter.Done(); iter.Next()) {
iter.Get()->GetKey()->SendShutdown();
}
const ManagedContainer<PGMPVideoDecoderChild>& videoDecoders = const ManagedContainer<PGMPVideoDecoderChild>& videoDecoders =
ManagedPGMPVideoDecoderChild(); ManagedPGMPVideoDecoderChild();
for (auto iter = videoDecoders.ConstIter(); !iter.Done(); iter.Next()) { for (auto iter = videoDecoders.ConstIter(); !iter.Done(); iter.Next()) {
@ -210,8 +172,7 @@ GMPContentChild::CloseActive()
bool bool
GMPContentChild::IsUsed() GMPContentChild::IsUsed()
{ {
return !ManagedPGMPDecryptorChild().IsEmpty() || return !ManagedPGMPVideoDecoderChild().IsEmpty() ||
!ManagedPGMPVideoDecoderChild().IsEmpty() ||
!ManagedPGMPVideoEncoderChild().IsEmpty() || !ManagedPGMPVideoEncoderChild().IsEmpty() ||
!ManagedPChromiumCDMChild().IsEmpty(); !ManagedPChromiumCDMChild().IsEmpty();
} }

Просмотреть файл

@ -23,15 +23,11 @@ public:
MessageLoop* GMPMessageLoop(); MessageLoop* GMPMessageLoop();
mozilla::ipc::IPCResult RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor) override;
mozilla::ipc::IPCResult RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor, const uint32_t& aDecryptorId) override; mozilla::ipc::IPCResult RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor, const uint32_t& aDecryptorId) override;
mozilla::ipc::IPCResult RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor) override; mozilla::ipc::IPCResult RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor) override;
mozilla::ipc::IPCResult RecvPChromiumCDMConstructor( mozilla::ipc::IPCResult RecvPChromiumCDMConstructor(
PChromiumCDMChild* aActor) override; PChromiumCDMChild* aActor) override;
PGMPDecryptorChild* AllocPGMPDecryptorChild() override;
bool DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor) override;
PGMPVideoDecoderChild* AllocPGMPVideoDecoderChild(const uint32_t& aDecryptorId) override; PGMPVideoDecoderChild* AllocPGMPVideoDecoderChild(const uint32_t& aDecryptorId) override;
bool DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor) override; bool DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor) override;

Просмотреть файл

@ -4,7 +4,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPContentParent.h" #include "GMPContentParent.h"
#include "GMPDecryptorParent.h"
#include "GMPParent.h" #include "GMPParent.h"
#include "GMPServiceChild.h" #include "GMPServiceChild.h"
#include "GMPVideoDecoderParent.h" #include "GMPVideoDecoderParent.h"
@ -67,8 +66,9 @@ private:
void void
GMPContentParent::ActorDestroy(ActorDestroyReason aWhy) GMPContentParent::ActorDestroy(ActorDestroyReason aWhy)
{ {
MOZ_ASSERT(mDecryptors.IsEmpty() && mVideoDecoders.IsEmpty() && MOZ_ASSERT(mVideoDecoders.IsEmpty() &&
mVideoEncoders.IsEmpty() && mChromiumCDMs.IsEmpty()); mVideoEncoders.IsEmpty() &&
mChromiumCDMs.IsEmpty());
NS_DispatchToCurrentThread(new ReleaseGMPContentParent(this)); NS_DispatchToCurrentThread(new ReleaseGMPContentParent(this));
} }
@ -107,15 +107,6 @@ GMPContentParent::VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder)
CloseIfUnused(); CloseIfUnused();
} }
void
GMPContentParent::DecryptorDestroyed(GMPDecryptorParent* aSession)
{
MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
MOZ_ALWAYS_TRUE(mDecryptors.RemoveElement(aSession));
CloseIfUnused();
}
void void
GMPContentParent::AddCloseBlocker() GMPContentParent::AddCloseBlocker()
{ {
@ -134,8 +125,9 @@ GMPContentParent::RemoveCloseBlocker()
void void
GMPContentParent::CloseIfUnused() GMPContentParent::CloseIfUnused()
{ {
if (mDecryptors.IsEmpty() && mVideoDecoders.IsEmpty() && if (mVideoDecoders.IsEmpty() &&
mVideoEncoders.IsEmpty() && mChromiumCDMs.IsEmpty() && mVideoEncoders.IsEmpty() &&
mChromiumCDMs.IsEmpty() &&
mCloseBlockerCount == 0) { mCloseBlockerCount == 0) {
RefPtr<GMPContentParent> toClose; RefPtr<GMPContentParent> toClose;
if (mParent) { if (mParent) {
@ -151,23 +143,6 @@ GMPContentParent::CloseIfUnused()
} }
} }
nsresult
GMPContentParent::GetGMPDecryptor(GMPDecryptorParent** aGMPDP)
{
PGMPDecryptorParent* pdp = SendPGMPDecryptorConstructor();
if (!pdp) {
return NS_ERROR_FAILURE;
}
GMPDecryptorParent* dp = static_cast<GMPDecryptorParent*>(pdp);
// This addref corresponds to the Proxy pointer the consumer is returned.
// It's dropped by calling Close() on the interface.
NS_ADDREF(dp);
mDecryptors.AppendElement(dp);
*aGMPDP = dp;
return NS_OK;
}
nsCOMPtr<nsISerialEventTarget> nsCOMPtr<nsISerialEventTarget>
GMPContentParent::GMPEventTarget() GMPContentParent::GMPEventTarget()
{ {
@ -292,21 +267,5 @@ GMPContentParent::DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor)
return true; return true;
} }
PGMPDecryptorParent*
GMPContentParent::AllocPGMPDecryptorParent()
{
GMPDecryptorParent* ksp = new GMPDecryptorParent(this);
NS_ADDREF(ksp);
return ksp;
}
bool
GMPContentParent::DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor)
{
GMPDecryptorParent* ksp = static_cast<GMPDecryptorParent*>(aActor);
NS_RELEASE(ksp);
return true;
}
} // namespace gmp } // namespace gmp
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -13,7 +13,6 @@
namespace mozilla { namespace mozilla {
namespace gmp { namespace gmp {
class GMPDecryptorParent;
class GMPParent; class GMPParent;
class GMPVideoDecoderParent; class GMPVideoDecoderParent;
class GMPVideoEncoderParent; class GMPVideoEncoderParent;
@ -34,9 +33,6 @@ public:
nsresult GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE); nsresult GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE);
void VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder); void VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder);
nsresult GetGMPDecryptor(GMPDecryptorParent** aGMPKS);
void DecryptorDestroyed(GMPDecryptorParent* aSession);
already_AddRefed<ChromiumCDMParent> GetChromiumCDM(); already_AddRefed<ChromiumCDMParent> GetChromiumCDM();
void ChromiumCDMDestroyed(ChromiumCDMParent* aCDM); void ChromiumCDMDestroyed(ChromiumCDMParent* aCDM);
@ -93,9 +89,6 @@ private:
PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() override; PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() override;
bool DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor) override; bool DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor) override;
PGMPDecryptorParent* AllocPGMPDecryptorParent() override;
bool DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor) override;
PChromiumCDMParent* AllocPChromiumCDMParent() override; PChromiumCDMParent* AllocPChromiumCDMParent() override;
bool DeallocPChromiumCDMParent(PChromiumCDMParent* aActor) override; bool DeallocPChromiumCDMParent(PChromiumCDMParent* aActor) override;
@ -109,7 +102,6 @@ private:
nsTArray<RefPtr<GMPVideoDecoderParent>> mVideoDecoders; nsTArray<RefPtr<GMPVideoDecoderParent>> mVideoDecoders;
nsTArray<RefPtr<GMPVideoEncoderParent>> mVideoEncoders; nsTArray<RefPtr<GMPVideoEncoderParent>> mVideoEncoders;
nsTArray<RefPtr<GMPDecryptorParent>> mDecryptors;
nsTArray<RefPtr<ChromiumCDMParent>> mChromiumCDMs; nsTArray<RefPtr<ChromiumCDMParent>> mChromiumCDMs;
nsCOMPtr<nsISerialEventTarget> mGMPEventTarget; nsCOMPtr<nsISerialEventTarget> mGMPEventTarget;
RefPtr<GMPParent> mParent; RefPtr<GMPParent> mParent;

Просмотреть файл

@ -1,382 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPDecryptorChild.h"
#include "GMPContentChild.h"
#include "GMPChild.h"
#include "base/task.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Unused.h"
#include "runnable_utils.h"
#include <ctime>
#define ON_GMP_THREAD() (mPlugin->GMPMessageLoop() == MessageLoop::current())
#define CALL_ON_GMP_THREAD(_func, ...) \
CallOnGMPThread(&GMPDecryptorChild::_func, __VA_ARGS__)
namespace mozilla {
namespace gmp {
static uint32_t sDecryptorCount = 1;
GMPDecryptorChild::GMPDecryptorChild(GMPContentChild* aPlugin)
: mSession(nullptr)
, mPlugin(aPlugin)
, mDecryptorId(sDecryptorCount++)
{
MOZ_ASSERT(mPlugin);
}
GMPDecryptorChild::~GMPDecryptorChild()
{
}
template <typename MethodType, typename... ParamType>
void
GMPDecryptorChild::CallMethod(MethodType aMethod, ParamType&&... aParams)
{
MOZ_ASSERT(ON_GMP_THREAD());
// Don't send IPC messages after tear-down.
if (mSession) {
(this->*aMethod)(Forward<ParamType>(aParams)...);
}
}
template<typename T>
struct AddConstReference {
typedef const typename RemoveReference<T>::Type& Type;
};
template<typename MethodType, typename... ParamType>
void
GMPDecryptorChild::CallOnGMPThread(MethodType aMethod, ParamType&&... aParams)
{
if (ON_GMP_THREAD()) {
// Use forwarding reference when we can.
CallMethod(aMethod, Forward<ParamType>(aParams)...);
} else {
// Use const reference when we have to.
auto m = &GMPDecryptorChild::CallMethod<
decltype(aMethod), typename AddConstReference<ParamType>::Type...>;
RefPtr<mozilla::Runnable> t =
dont_add_new_uses_of_this::NewRunnableMethod(this, m, aMethod, Forward<ParamType>(aParams)...);
mPlugin->GMPMessageLoop()->PostTask(t.forget());
}
}
void
GMPDecryptorChild::Init(GMPDecryptor* aSession)
{
MOZ_ASSERT(aSession);
mSession = aSession;
// The ID of this decryptor is the IPDL actor ID. Note it's unique inside
// the child process, but not necessarily across all gecko processes. However,
// since GMPDecryptors are segregated by node ID/origin, we shouldn't end up
// with clashes in the content process.
SendSetDecryptorId(DecryptorId());
}
void
GMPDecryptorChild::SetSessionId(uint32_t aCreateSessionToken,
const char* aSessionId,
uint32_t aSessionIdLength)
{
CALL_ON_GMP_THREAD(SendSetSessionId,
aCreateSessionToken, nsCString(aSessionId, aSessionIdLength));
}
void
GMPDecryptorChild::ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccess)
{
CALL_ON_GMP_THREAD(SendResolveLoadSessionPromise, aPromiseId, aSuccess);
}
void
GMPDecryptorChild::ResolvePromise(uint32_t aPromiseId)
{
CALL_ON_GMP_THREAD(SendResolvePromise, aPromiseId);
}
void
GMPDecryptorChild::RejectPromise(uint32_t aPromiseId,
GMPDOMException aException,
const char* aMessage,
uint32_t aMessageLength)
{
CALL_ON_GMP_THREAD(SendRejectPromise,
aPromiseId, aException, nsCString(aMessage, aMessageLength));
}
void
GMPDecryptorChild::SessionMessage(const char* aSessionId,
uint32_t aSessionIdLength,
GMPSessionMessageType aMessageType,
const uint8_t* aMessage,
uint32_t aMessageLength)
{
nsTArray<uint8_t> msg;
msg.AppendElements(aMessage, aMessageLength);
CALL_ON_GMP_THREAD(SendSessionMessage,
nsCString(aSessionId, aSessionIdLength),
aMessageType, Move(msg));
}
void
GMPDecryptorChild::ExpirationChange(const char* aSessionId,
uint32_t aSessionIdLength,
GMPTimestamp aExpiryTime)
{
CALL_ON_GMP_THREAD(SendExpirationChange,
nsCString(aSessionId, aSessionIdLength), aExpiryTime);
}
void
GMPDecryptorChild::SessionClosed(const char* aSessionId,
uint32_t aSessionIdLength)
{
CALL_ON_GMP_THREAD(SendSessionClosed,
nsCString(aSessionId, aSessionIdLength));
}
void
GMPDecryptorChild::SessionError(const char* aSessionId,
uint32_t aSessionIdLength,
GMPDOMException aException,
uint32_t aSystemCode,
const char* aMessage,
uint32_t aMessageLength)
{
CALL_ON_GMP_THREAD(SendSessionError,
nsCString(aSessionId, aSessionIdLength),
aException, aSystemCode,
nsCString(aMessage, aMessageLength));
}
void
GMPDecryptorChild::KeyStatusChanged(const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aKeyId,
uint32_t aKeyIdLength,
GMPMediaKeyStatus aStatus)
{
AutoTArray<uint8_t, 16> kid;
kid.AppendElements(aKeyId, aKeyIdLength);
nsTArray<GMPKeyInformation> keyInfos;
keyInfos.AppendElement(GMPKeyInformation(kid, aStatus));
CALL_ON_GMP_THREAD(SendBatchedKeyStatusChanged,
nsCString(aSessionId, aSessionIdLength),
keyInfos);
}
void
GMPDecryptorChild::BatchedKeyStatusChanged(const char* aSessionId,
uint32_t aSessionIdLength,
const GMPMediaKeyInfo* aKeyInfos,
uint32_t aKeyInfosLength)
{
nsTArray<GMPKeyInformation> keyInfos;
for (uint32_t i = 0; i < aKeyInfosLength; i++) {
nsTArray<uint8_t> keyId;
keyId.AppendElements(aKeyInfos[i].keyid, aKeyInfos[i].keyid_size);
keyInfos.AppendElement(GMPKeyInformation(keyId, aKeyInfos[i].status));
}
CALL_ON_GMP_THREAD(SendBatchedKeyStatusChanged,
nsCString(aSessionId, aSessionIdLength),
keyInfos);
}
void
GMPDecryptorChild::Decrypted(GMPBuffer* aBuffer, GMPErr aResult)
{
if (!ON_GMP_THREAD()) {
// We should run this whole method on the GMP thread since the buffer needs
// to be deleted after the SendDecrypted call.
mPlugin->GMPMessageLoop()->PostTask(
NewRunnableMethod<GMPBuffer*, GMPErr>("gmp::GMPDecryptorChild::Decrypted",
this,
&GMPDecryptorChild::Decrypted,
aBuffer,
aResult));
return;
}
if (!aBuffer) {
NS_WARNING("GMPDecryptorCallback passed bull GMPBuffer");
return;
}
auto buffer = static_cast<GMPBufferImpl*>(aBuffer);
if (mSession) {
SendDecrypted(buffer->mId, aResult, buffer->mData);
}
delete buffer;
}
void
GMPDecryptorChild::SetCapabilities(uint64_t aCaps)
{
// Deprecated.
}
mozilla::ipc::IPCResult
GMPDecryptorChild::RecvInit(const bool& aDistinctiveIdentifierRequired,
const bool& aPersistentStateRequired)
{
if (!mSession) {
return IPC_FAIL_NO_REASON(this);
}
mSession->Init(this, aDistinctiveIdentifierRequired, aPersistentStateRequired);
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorChild::RecvCreateSession(const uint32_t& aCreateSessionToken,
const uint32_t& aPromiseId,
const nsCString& aInitDataType,
InfallibleTArray<uint8_t>&& aInitData,
const GMPSessionType& aSessionType)
{
if (!mSession) {
return IPC_FAIL_NO_REASON(this);
}
mSession->CreateSession(aCreateSessionToken,
aPromiseId,
aInitDataType.get(),
aInitDataType.Length(),
aInitData.Elements(),
aInitData.Length(),
aSessionType);
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorChild::RecvLoadSession(const uint32_t& aPromiseId,
const nsCString& aSessionId)
{
if (!mSession) {
return IPC_FAIL_NO_REASON(this);
}
mSession->LoadSession(aPromiseId,
aSessionId.get(),
aSessionId.Length());
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorChild::RecvUpdateSession(const uint32_t& aPromiseId,
const nsCString& aSessionId,
InfallibleTArray<uint8_t>&& aResponse)
{
if (!mSession) {
return IPC_FAIL_NO_REASON(this);
}
mSession->UpdateSession(aPromiseId,
aSessionId.get(),
aSessionId.Length(),
aResponse.Elements(),
aResponse.Length());
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorChild::RecvCloseSession(const uint32_t& aPromiseId,
const nsCString& aSessionId)
{
if (!mSession) {
return IPC_FAIL_NO_REASON(this);
}
mSession->CloseSession(aPromiseId,
aSessionId.get(),
aSessionId.Length());
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorChild::RecvRemoveSession(const uint32_t& aPromiseId,
const nsCString& aSessionId)
{
if (!mSession) {
return IPC_FAIL_NO_REASON(this);
}
mSession->RemoveSession(aPromiseId,
aSessionId.get(),
aSessionId.Length());
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorChild::RecvSetServerCertificate(const uint32_t& aPromiseId,
InfallibleTArray<uint8_t>&& aServerCert)
{
if (!mSession) {
return IPC_FAIL_NO_REASON(this);
}
mSession->SetServerCertificate(aPromiseId,
aServerCert.Elements(),
aServerCert.Length());
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorChild::RecvDecrypt(const uint32_t& aId,
InfallibleTArray<uint8_t>&& aBuffer,
const GMPDecryptionData& aMetadata)
{
if (!mSession) {
return IPC_FAIL_NO_REASON(this);
}
// Note: the GMPBufferImpl created here is deleted when the GMP passes
// it back in the Decrypted() callback above.
GMPBufferImpl* buffer = new GMPBufferImpl(aId, aBuffer);
// |metadata| lifetime is managed by |buffer|.
GMPEncryptedBufferDataImpl* metadata = new GMPEncryptedBufferDataImpl(aMetadata);
buffer->SetMetadata(metadata);
mSession->Decrypt(buffer, metadata);
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorChild::RecvDecryptingComplete()
{
// Reset |mSession| before calling DecryptingComplete(). We should not send
// any IPC messages during tear-down.
auto session = mSession;
mSession = nullptr;
if (!session) {
return IPC_FAIL_NO_REASON(this);
}
session->DecryptingComplete();
Unused << Send__delete__(this);
return IPC_OK();
}
} // namespace gmp
} // namespace mozilla
// avoid redefined macro in unified build
#undef ON_GMP_THREAD
#undef CALL_ON_GMP_THREAD

Просмотреть файл

@ -1,132 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPDecryptorChild_h_
#define GMPDecryptorChild_h_
#include "mozilla/gmp/PGMPDecryptorChild.h"
#include "gmp-decryption.h"
#include "mozilla/gmp/GMPTypes.h"
#include "GMPEncryptedBufferDataImpl.h"
#include <string>
namespace mozilla {
namespace gmp {
class GMPContentChild;
class GMPDecryptorChild : public GMPDecryptorCallback
, public PGMPDecryptorChild
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPDecryptorChild);
explicit GMPDecryptorChild(GMPContentChild* aPlugin);
void Init(GMPDecryptor* aSession);
// GMPDecryptorCallback
void SetSessionId(uint32_t aCreateSessionToken,
const char* aSessionId,
uint32_t aSessionIdLength) override;
void ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccess) override;
void ResolvePromise(uint32_t aPromiseId) override;
void RejectPromise(uint32_t aPromiseId,
GMPDOMException aException,
const char* aMessage,
uint32_t aMessageLength) override;
void SessionMessage(const char* aSessionId,
uint32_t aSessionIdLength,
GMPSessionMessageType aMessageType,
const uint8_t* aMessage,
uint32_t aMessageLength) override;
void ExpirationChange(const char* aSessionId,
uint32_t aSessionIdLength,
GMPTimestamp aExpiryTime) override;
void SessionClosed(const char* aSessionId,
uint32_t aSessionIdLength) override;
void SessionError(const char* aSessionId,
uint32_t aSessionIdLength,
GMPDOMException aException,
uint32_t aSystemCode,
const char* aMessage,
uint32_t aMessageLength) override;
void KeyStatusChanged(const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aKeyId,
uint32_t aKeyIdLength,
GMPMediaKeyStatus aStatus) override;
void SetCapabilities(uint64_t aCaps) override;
void Decrypted(GMPBuffer* aBuffer, GMPErr aResult) override;
void BatchedKeyStatusChanged(const char* aSessionId,
uint32_t aSessionIdLength,
const GMPMediaKeyInfo* aKeyInfos,
uint32_t aKeyInfosLength) override;
uint32_t DecryptorId() const { return mDecryptorId; }
private:
~GMPDecryptorChild();
// GMPDecryptorChild
mozilla::ipc::IPCResult RecvInit(const bool& aDistinctiveIdentifierRequired,
const bool& aPersistentStateRequired) override;
mozilla::ipc::IPCResult RecvCreateSession(const uint32_t& aCreateSessionToken,
const uint32_t& aPromiseId,
const nsCString& aInitDataType,
InfallibleTArray<uint8_t>&& aInitData,
const GMPSessionType& aSessionType) override;
mozilla::ipc::IPCResult RecvLoadSession(const uint32_t& aPromiseId,
const nsCString& aSessionId) override;
mozilla::ipc::IPCResult RecvUpdateSession(const uint32_t& aPromiseId,
const nsCString& aSessionId,
InfallibleTArray<uint8_t>&& aResponse) override;
mozilla::ipc::IPCResult RecvCloseSession(const uint32_t& aPromiseId,
const nsCString& aSessionId) override;
mozilla::ipc::IPCResult RecvRemoveSession(const uint32_t& aPromiseId,
const nsCString& aSessionId) override;
mozilla::ipc::IPCResult RecvDecrypt(const uint32_t& aId,
InfallibleTArray<uint8_t>&& aBuffer,
const GMPDecryptionData& aMetadata) override;
// Resolve/reject promise on completion.
mozilla::ipc::IPCResult RecvSetServerCertificate(const uint32_t& aPromiseId,
InfallibleTArray<uint8_t>&& aServerCert) override;
mozilla::ipc::IPCResult RecvDecryptingComplete() override;
template <typename MethodType, typename... ParamType>
void CallMethod(MethodType, ParamType&&...);
template<typename MethodType, typename... ParamType>
void CallOnGMPThread(MethodType, ParamType&&...);
// GMP's GMPDecryptor implementation.
// Only call into this on the (GMP process) main thread.
GMPDecryptor* mSession;
GMPContentChild* mPlugin;
const uint32_t mDecryptorId;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPDecryptorChild_h_

Просмотреть файл

@ -1,509 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPDecryptorParent.h"
#include "GMPContentParent.h"
#include "GMPUtils.h"
#include "MediaData.h"
#include "mozilla/Unused.h"
namespace mozilla {
#ifdef LOG
#undef LOG
#endif
extern LogModule* GetGMPLog();
#define LOGV(msg) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Verbose, msg)
#define LOGD(msg) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Debug, msg)
#define LOG(level, msg) MOZ_LOG(GetGMPLog(), (level), msg)
namespace gmp {
GMPDecryptorParent::GMPDecryptorParent(GMPContentParent* aPlugin)
: mIsOpen(false)
, mShuttingDown(false)
, mActorDestroyed(false)
, mPlugin(aPlugin)
, mPluginId(aPlugin->GetPluginId())
, mCallback(nullptr)
#ifdef DEBUG
, mGMPEventTarget(aPlugin->GMPEventTarget())
#endif
{
MOZ_ASSERT(mPlugin && mGMPEventTarget);
}
GMPDecryptorParent::~GMPDecryptorParent()
{
}
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvSetDecryptorId(const uint32_t& aId)
{
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return IPC_FAIL_NO_REASON(this);
}
mCallback->SetDecryptorId(aId);
return IPC_OK();
}
nsresult
GMPDecryptorParent::Init(GMPDecryptorProxyCallback* aCallback,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired)
{
LOGD(("GMPDecryptorParent[%p]::Init()", this));
if (mIsOpen) {
NS_WARNING("Trying to re-use an in-use GMP decrypter!");
return NS_ERROR_FAILURE;
}
mCallback = aCallback;
if (!SendInit(aDistinctiveIdentifierRequired, aPersistentStateRequired)) {
return NS_ERROR_FAILURE;
}
mIsOpen = true;
return NS_OK;
}
void
GMPDecryptorParent::CreateSession(uint32_t aCreateSessionToken,
uint32_t aPromiseId,
const nsCString& aInitDataType,
const nsTArray<uint8_t>& aInitData,
GMPSessionType aSessionType)
{
LOGD(("GMPDecryptorParent[%p]::CreateSession(token=%u, promiseId=%u, aInitData='%s')",
this, aCreateSessionToken, aPromiseId, ToHexString(aInitData).get()));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return;
}
// Caller should ensure parameters passed in from JS are valid.
MOZ_ASSERT(!aInitDataType.IsEmpty() && !aInitData.IsEmpty());
Unused << SendCreateSession(aCreateSessionToken, aPromiseId, aInitDataType, aInitData, aSessionType);
}
void
GMPDecryptorParent::LoadSession(uint32_t aPromiseId,
const nsCString& aSessionId)
{
LOGD(("GMPDecryptorParent[%p]::LoadSession(sessionId='%s', promiseId=%u)",
this, aSessionId.get(), aPromiseId));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return;
}
// Caller should ensure parameters passed in from JS are valid.
MOZ_ASSERT(!aSessionId.IsEmpty());
Unused << SendLoadSession(aPromiseId, aSessionId);
}
void
GMPDecryptorParent::UpdateSession(uint32_t aPromiseId,
const nsCString& aSessionId,
const nsTArray<uint8_t>& aResponse)
{
LOGD(("GMPDecryptorParent[%p]::UpdateSession(sessionId='%s', promiseId=%u response='%s')",
this, aSessionId.get(), aPromiseId, ToHexString(aResponse).get()));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return;
}
// Caller should ensure parameters passed in from JS are valid.
MOZ_ASSERT(!aSessionId.IsEmpty() && !aResponse.IsEmpty());
Unused << SendUpdateSession(aPromiseId, aSessionId, aResponse);
}
void
GMPDecryptorParent::CloseSession(uint32_t aPromiseId,
const nsCString& aSessionId)
{
LOGD(("GMPDecryptorParent[%p]::CloseSession(sessionId='%s', promiseId=%u)",
this, aSessionId.get(), aPromiseId));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return;
}
// Caller should ensure parameters passed in from JS are valid.
MOZ_ASSERT(!aSessionId.IsEmpty());
Unused << SendCloseSession(aPromiseId, aSessionId);
}
void
GMPDecryptorParent::RemoveSession(uint32_t aPromiseId,
const nsCString& aSessionId)
{
LOGD(("GMPDecryptorParent[%p]::RemoveSession(sessionId='%s', promiseId=%u)",
this, aSessionId.get(), aPromiseId));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return;
}
// Caller should ensure parameters passed in from JS are valid.
MOZ_ASSERT(!aSessionId.IsEmpty());
Unused << SendRemoveSession(aPromiseId, aSessionId);
}
void
GMPDecryptorParent::SetServerCertificate(uint32_t aPromiseId,
const nsTArray<uint8_t>& aServerCert)
{
LOGD(("GMPDecryptorParent[%p]::SetServerCertificate(promiseId=%u)",
this, aPromiseId));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return;
}
// Caller should ensure parameters passed in from JS are valid.
MOZ_ASSERT(!aServerCert.IsEmpty());
Unused << SendSetServerCertificate(aPromiseId, aServerCert);
}
void
GMPDecryptorParent::Decrypt(uint32_t aId,
const CryptoSample& aCrypto,
const nsTArray<uint8_t>& aBuffer)
{
LOGV(("GMPDecryptorParent[%p]::Decrypt(id=%d)", this, aId));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return;
}
// Caller should ensure parameters passed in are valid.
MOZ_ASSERT(!aBuffer.IsEmpty());
if (aCrypto.mValid) {
GMPDecryptionData data(aCrypto.mKeyId,
aCrypto.mIV,
aCrypto.mPlainSizes,
aCrypto.mEncryptedSizes,
aCrypto.mSessionIds);
Unused << SendDecrypt(aId, aBuffer, data);
} else {
GMPDecryptionData data;
Unused << SendDecrypt(aId, aBuffer, data);
}
}
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvSetSessionId(const uint32_t& aCreateSessionId,
const nsCString& aSessionId)
{
LOGD(("GMPDecryptorParent[%p]::RecvSetSessionId(token=%u, sessionId='%s')",
this, aCreateSessionId, aSessionId.get()));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return IPC_FAIL_NO_REASON(this);
}
mCallback->SetSessionId(aCreateSessionId, aSessionId);
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvResolveLoadSessionPromise(const uint32_t& aPromiseId,
const bool& aSuccess)
{
LOGD(("GMPDecryptorParent[%p]::RecvResolveLoadSessionPromise(promiseId=%u)",
this, aPromiseId));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return IPC_FAIL_NO_REASON(this);
}
mCallback->ResolveLoadSessionPromise(aPromiseId, aSuccess);
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvResolvePromise(const uint32_t& aPromiseId)
{
LOGD(("GMPDecryptorParent[%p]::RecvResolvePromise(promiseId=%u)",
this, aPromiseId));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return IPC_FAIL_NO_REASON(this);
}
mCallback->ResolvePromise(aPromiseId);
return IPC_OK();
}
nsresult
GMPExToNsresult(GMPDOMException aDomException) {
switch (aDomException) {
case kGMPNoModificationAllowedError: return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
case kGMPNotFoundError: return NS_ERROR_DOM_NOT_FOUND_ERR;
case kGMPNotSupportedError: return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
case kGMPInvalidStateError: return NS_ERROR_DOM_INVALID_STATE_ERR;
case kGMPSyntaxError: return NS_ERROR_DOM_SYNTAX_ERR;
case kGMPInvalidModificationError: return NS_ERROR_DOM_INVALID_MODIFICATION_ERR;
case kGMPInvalidAccessError: return NS_ERROR_DOM_INVALID_ACCESS_ERR;
case kGMPSecurityError: return NS_ERROR_DOM_SECURITY_ERR;
case kGMPAbortError: return NS_ERROR_DOM_ABORT_ERR;
case kGMPQuotaExceededError: return NS_ERROR_DOM_QUOTA_EXCEEDED_ERR;
case kGMPTimeoutError: return NS_ERROR_DOM_TIMEOUT_ERR;
case kGMPTypeError: return NS_ERROR_DOM_TYPE_ERR;
default: return NS_ERROR_DOM_UNKNOWN_ERR;
}
}
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvRejectPromise(const uint32_t& aPromiseId,
const GMPDOMException& aException,
const nsCString& aMessage)
{
LOGD(("GMPDecryptorParent[%p]::RecvRejectPromise(promiseId=%u, exception=%d, msg='%s')",
this, aPromiseId, aException, aMessage.get()));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return IPC_FAIL_NO_REASON(this);
}
mCallback->RejectPromise(aPromiseId, GMPExToNsresult(aException), aMessage);
return IPC_OK();
}
static dom::MediaKeyMessageType
ToMediaKeyMessageType(GMPSessionMessageType aMessageType) {
switch (aMessageType) {
case kGMPLicenseRequest: return dom::MediaKeyMessageType::License_request;
case kGMPLicenseRenewal: return dom::MediaKeyMessageType::License_renewal;
case kGMPLicenseRelease: return dom::MediaKeyMessageType::License_release;
case kGMPIndividualizationRequest: return dom::MediaKeyMessageType::Individualization_request;
default: return dom::MediaKeyMessageType::License_request;
};
};
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvSessionMessage(const nsCString& aSessionId,
const GMPSessionMessageType& aMessageType,
nsTArray<uint8_t>&& aMessage)
{
LOGD(("GMPDecryptorParent[%p]::RecvSessionMessage(sessionId='%s', type=%d, msg='%s')",
this, aSessionId.get(), aMessageType, ToHexString(aMessage).get()));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return IPC_FAIL_NO_REASON(this);
}
mCallback->SessionMessage(aSessionId, ToMediaKeyMessageType(aMessageType), aMessage);
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvExpirationChange(const nsCString& aSessionId,
const double& aExpiryTime)
{
LOGD(("GMPDecryptorParent[%p]::RecvExpirationChange(sessionId='%s', expiry=%lf)",
this, aSessionId.get(), aExpiryTime));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return IPC_FAIL_NO_REASON(this);
}
mCallback->ExpirationChange(aSessionId, aExpiryTime);
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvSessionClosed(const nsCString& aSessionId)
{
LOGD(("GMPDecryptorParent[%p]::RecvSessionClosed(sessionId='%s')",
this, aSessionId.get()));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return IPC_FAIL_NO_REASON(this);
}
mCallback->SessionClosed(aSessionId);
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvSessionError(const nsCString& aSessionId,
const GMPDOMException& aException,
const uint32_t& aSystemCode,
const nsCString& aMessage)
{
LOGD(("GMPDecryptorParent[%p]::RecvSessionError(sessionId='%s', exception=%d, sysCode=%d, msg='%s')",
this, aSessionId.get(),
aException, aSystemCode, aMessage.get()));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return IPC_FAIL_NO_REASON(this);
}
mCallback->SessionError(aSessionId,
GMPExToNsresult(aException),
aSystemCode,
aMessage);
return IPC_OK();
}
static dom::MediaKeyStatus
ToMediaKeyStatus(GMPMediaKeyStatus aStatus) {
switch (aStatus) {
case kGMPUsable: return dom::MediaKeyStatus::Usable;
case kGMPExpired: return dom::MediaKeyStatus::Expired;
case kGMPOutputDownscaled: return dom::MediaKeyStatus::Output_downscaled;
case kGMPOutputRestricted: return dom::MediaKeyStatus::Output_restricted;
case kGMPInternalError: return dom::MediaKeyStatus::Internal_error;
case kGMPReleased: return dom::MediaKeyStatus::Released;
case kGMPStatusPending: return dom::MediaKeyStatus::Status_pending;
default: return dom::MediaKeyStatus::Internal_error;
}
}
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvBatchedKeyStatusChanged(const nsCString& aSessionId,
InfallibleTArray<GMPKeyInformation>&& aKeyInfos)
{
LOGD(("GMPDecryptorParent[%p]::RecvBatchedKeyStatusChanged(sessionId='%s', KeyInfos len='%zu')",
this, aSessionId.get(), aKeyInfos.Length()));
if (mIsOpen) {
nsTArray<CDMKeyInfo> cdmKeyInfos(aKeyInfos.Length());
for (uint32_t i = 0; i < aKeyInfos.Length(); i++) {
LOGD(("GMPDecryptorParent[%p]::RecvBatchedKeyStatusChanged(keyId=%s, gmp-status=%d)",
this, ToHexString(aKeyInfos[i].keyId()).get(), aKeyInfos[i].status()));
// If the status is kGMPUnknown, we're going to forget(remove) that key info.
if (aKeyInfos[i].status() != kGMPUnknown) {
auto status = ToMediaKeyStatus(aKeyInfos[i].status());
cdmKeyInfos.AppendElement(CDMKeyInfo(aKeyInfos[i].keyId(),
dom::Optional<dom::MediaKeyStatus>(status)));
} else {
cdmKeyInfos.AppendElement(CDMKeyInfo(aKeyInfos[i].keyId()));
}
}
mCallback->BatchedKeyStatusChanged(aSessionId, cdmKeyInfos);
}
return IPC_OK();
}
DecryptStatus
ToDecryptStatus(GMPErr aError)
{
switch (aError) {
case GMPNoErr: return eme::Ok;
case GMPNoKeyErr: return eme::NoKeyErr;
case GMPAbortedErr: return eme::AbortedErr;
default: return eme::GenericErr;
}
}
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvDecrypted(const uint32_t& aId,
const GMPErr& aErr,
InfallibleTArray<uint8_t>&& aBuffer)
{
LOGV(("GMPDecryptorParent[%p]::RecvDecrypted(id=%d, err=%d)",
this, aId, aErr));
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return IPC_FAIL_NO_REASON(this);
}
mCallback->Decrypted(aId, ToDecryptStatus(aErr), aBuffer);
return IPC_OK();
}
mozilla::ipc::IPCResult
GMPDecryptorParent::RecvShutdown()
{
LOGD(("GMPDecryptorParent[%p]::RecvShutdown()", this));
Shutdown();
return IPC_OK();
}
// Note: may be called via Terminated()
void
GMPDecryptorParent::Close()
{
LOGD(("GMPDecryptorParent[%p]::Close()", this));
MOZ_ASSERT(mGMPEventTarget->IsOnCurrentThread());
// Consumer is done with us; we can shut down. No more callbacks should
// be made to mCallback. Note: do this before Shutdown()!
mCallback = nullptr;
// Let Shutdown mark us as dead so it knows if we had been alive
// In case this is the last reference
RefPtr<GMPDecryptorParent> kungfudeathgrip(this);
this->Release();
Shutdown();
}
void
GMPDecryptorParent::Shutdown()
{
LOGD(("GMPDecryptorParent[%p]::Shutdown()", this));
MOZ_ASSERT(mGMPEventTarget->IsOnCurrentThread());
if (mShuttingDown) {
return;
}
mShuttingDown = true;
// Notify client we're gone! Won't occur after Close()
if (mCallback) {
mCallback->Terminated();
mCallback = nullptr;
}
mIsOpen = false;
if (!mActorDestroyed) {
Unused << SendDecryptingComplete();
}
}
// Note: Keep this sync'd up with Shutdown
void
GMPDecryptorParent::ActorDestroy(ActorDestroyReason aWhy)
{
LOGD(("GMPDecryptorParent[%p]::ActorDestroy(reason=%d)", this, aWhy));
mIsOpen = false;
mActorDestroyed = true;
if (mCallback) {
// May call Close() (and Shutdown()) immediately or with a delay
mCallback->Terminated();
mCallback = nullptr;
}
if (mPlugin) {
mPlugin->DecryptorDestroyed(this);
mPlugin = nullptr;
}
MaybeDisconnect(aWhy == AbnormalShutdown);
}
mozilla::ipc::IPCResult
GMPDecryptorParent::Recv__delete__()
{
LOGD(("GMPDecryptorParent[%p]::Recv__delete__()", this));
if (mPlugin) {
mPlugin->DecryptorDestroyed(this);
mPlugin = nullptr;
}
return IPC_OK();
}
} // namespace gmp
} // namespace mozilla

Просмотреть файл

@ -1,129 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPDecryptorParent_h_
#define GMPDecryptorParent_h_
#include "mozilla/gmp/PGMPDecryptorParent.h"
#include "mozilla/RefPtr.h"
#include "gmp-decryption.h"
#include "GMPDecryptorProxy.h"
#include "GMPCrashHelperHolder.h"
namespace mozilla {
class CryptoSample;
namespace gmp {
class GMPContentParent;
class GMPDecryptorParent final : public GMPDecryptorProxy
, public PGMPDecryptorParent
, public GMPCrashHelperHolder
{
public:
NS_INLINE_DECL_REFCOUNTING(GMPDecryptorParent)
explicit GMPDecryptorParent(GMPContentParent *aPlugin);
// GMPDecryptorProxy
uint32_t GetPluginId() const override { return mPluginId; }
nsresult Init(GMPDecryptorProxyCallback* aCallback,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired) override;
void CreateSession(uint32_t aCreateSessionToken,
uint32_t aPromiseId,
const nsCString& aInitDataType,
const nsTArray<uint8_t>& aInitData,
GMPSessionType aSessionType) override;
void LoadSession(uint32_t aPromiseId,
const nsCString& aSessionId) override;
void UpdateSession(uint32_t aPromiseId,
const nsCString& aSessionId,
const nsTArray<uint8_t>& aResponse) override;
void CloseSession(uint32_t aPromiseId,
const nsCString& aSessionId) override;
void RemoveSession(uint32_t aPromiseId,
const nsCString& aSessionId) override;
void SetServerCertificate(uint32_t aPromiseId,
const nsTArray<uint8_t>& aServerCert) override;
void Decrypt(uint32_t aId,
const CryptoSample& aCrypto,
const nsTArray<uint8_t>& aBuffer) override;
void Close() override;
void Shutdown();
private:
~GMPDecryptorParent();
// PGMPDecryptorParent
mozilla::ipc::IPCResult RecvSetDecryptorId(const uint32_t& aId) override;
mozilla::ipc::IPCResult RecvSetSessionId(const uint32_t& aCreateSessionToken,
const nsCString& aSessionId) override;
mozilla::ipc::IPCResult RecvResolveLoadSessionPromise(const uint32_t& aPromiseId,
const bool& aSuccess) override;
mozilla::ipc::IPCResult RecvResolvePromise(const uint32_t& aPromiseId) override;
mozilla::ipc::IPCResult RecvRejectPromise(const uint32_t& aPromiseId,
const GMPDOMException& aException,
const nsCString& aMessage) override;
mozilla::ipc::IPCResult RecvSessionMessage(const nsCString& aSessionId,
const GMPSessionMessageType& aMessageType,
nsTArray<uint8_t>&& aMessage) override;
mozilla::ipc::IPCResult RecvExpirationChange(const nsCString& aSessionId,
const double& aExpiryTime) override;
mozilla::ipc::IPCResult RecvSessionClosed(const nsCString& aSessionId) override;
mozilla::ipc::IPCResult RecvSessionError(const nsCString& aSessionId,
const GMPDOMException& aException,
const uint32_t& aSystemCode,
const nsCString& aMessage) override;
mozilla::ipc::IPCResult RecvDecrypted(const uint32_t& aId,
const GMPErr& aErr,
InfallibleTArray<uint8_t>&& aBuffer) override;
mozilla::ipc::IPCResult RecvBatchedKeyStatusChanged(const nsCString& aSessionId,
InfallibleTArray<GMPKeyInformation>&& aKeyInfos) override;
mozilla::ipc::IPCResult RecvShutdown() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult Recv__delete__() override;
bool mIsOpen;
bool mShuttingDown;
bool mActorDestroyed;
RefPtr<GMPContentParent> mPlugin;
uint32_t mPluginId;
GMPDecryptorProxyCallback* mCallback;
#ifdef DEBUG
nsCOMPtr<nsISerialEventTarget> const mGMPEventTarget;
#endif
};
} // namespace gmp
} // namespace mozilla
#endif // GMPDecryptorChild_h_

Просмотреть файл

@ -1,63 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPDecryptorProxy_h_
#define GMPDecryptorProxy_h_
#include "mozilla/DecryptorProxyCallback.h"
#include "GMPCallbackBase.h"
#include "gmp-decryption.h"
#include "nsString.h"
namespace mozilla {
class CryptoSample;
} // namespace mozilla
class GMPDecryptorProxyCallback : public DecryptorProxyCallback,
public GMPCallbackBase {
public:
virtual ~GMPDecryptorProxyCallback() {}
};
class GMPDecryptorProxy {
public:
~GMPDecryptorProxy() {}
virtual uint32_t GetPluginId() const = 0;
virtual nsresult Init(GMPDecryptorProxyCallback* aCallback,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired) = 0;
virtual void CreateSession(uint32_t aCreateSessionToken,
uint32_t aPromiseId,
const nsCString& aInitDataType,
const nsTArray<uint8_t>& aInitData,
GMPSessionType aSessionType) = 0;
virtual void LoadSession(uint32_t aPromiseId,
const nsCString& aSessionId) = 0;
virtual void UpdateSession(uint32_t aPromiseId,
const nsCString& aSessionId,
const nsTArray<uint8_t>& aResponse) = 0;
virtual void CloseSession(uint32_t aPromiseId,
const nsCString& aSessionId) = 0;
virtual void RemoveSession(uint32_t aPromiseId,
const nsCString& aSessionId) = 0;
virtual void SetServerCertificate(uint32_t aPromiseId,
const nsTArray<uint8_t>& aServerCert) = 0;
virtual void Decrypt(uint32_t aId,
const mozilla::CryptoSample& aCrypto,
const nsTArray<uint8_t>& aBuffer) = 0;
virtual void Close() = 0;
};
#endif // GMPDecryptorProxy_h_

Просмотреть файл

@ -1,132 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPEncryptedBufferDataImpl.h"
#include "mozilla/gmp/GMPTypes.h"
#include "MediaData.h"
namespace mozilla {
namespace gmp {
GMPEncryptedBufferDataImpl::GMPEncryptedBufferDataImpl(const CryptoSample& aCrypto)
: mKeyId(aCrypto.mKeyId)
, mIV(aCrypto.mIV)
, mClearBytes(aCrypto.mPlainSizes)
, mCipherBytes(aCrypto.mEncryptedSizes)
, mSessionIdList(aCrypto.mSessionIds)
{
}
GMPEncryptedBufferDataImpl::GMPEncryptedBufferDataImpl(const GMPDecryptionData& aData)
: mKeyId(aData.mKeyId())
, mIV(aData.mIV())
, mClearBytes(aData.mClearBytes())
, mCipherBytes(aData.mCipherBytes())
, mSessionIdList(aData.mSessionIds())
{
MOZ_ASSERT(mClearBytes.Length() == mCipherBytes.Length());
}
GMPEncryptedBufferDataImpl::~GMPEncryptedBufferDataImpl()
{
}
void
GMPEncryptedBufferDataImpl::RelinquishData(GMPDecryptionData& aData)
{
aData.mKeyId() = Move(mKeyId);
aData.mIV() = Move(mIV);
aData.mClearBytes() = Move(mClearBytes);
aData.mCipherBytes() = Move(mCipherBytes);
mSessionIdList.RelinquishData(aData.mSessionIds());
}
const uint8_t*
GMPEncryptedBufferDataImpl::KeyId() const
{
return mKeyId.Elements();
}
uint32_t
GMPEncryptedBufferDataImpl::KeyIdSize() const
{
return mKeyId.Length();
}
const uint8_t*
GMPEncryptedBufferDataImpl::IV() const
{
return mIV.Elements();
}
uint32_t
GMPEncryptedBufferDataImpl::IVSize() const
{
return mIV.Length();
}
const uint16_t*
GMPEncryptedBufferDataImpl::ClearBytes() const
{
return mClearBytes.Elements();
}
const uint32_t*
GMPEncryptedBufferDataImpl::CipherBytes() const
{
return mCipherBytes.Elements();
}
const GMPStringList*
GMPEncryptedBufferDataImpl::SessionIds() const
{
return &mSessionIdList;
}
uint32_t
GMPEncryptedBufferDataImpl::NumSubsamples() const
{
MOZ_ASSERT(mClearBytes.Length() == mCipherBytes.Length());
// Return the min of the two, to ensure there's not chance of array index
// out-of-bounds shenanigans.
return std::min<uint32_t>(mClearBytes.Length(), mCipherBytes.Length());
}
GMPStringListImpl::GMPStringListImpl(const nsTArray<nsCString>& aStrings)
: mStrings(aStrings)
{
}
uint32_t
GMPStringListImpl::Size() const
{
return mStrings.Length();
}
void
GMPStringListImpl::StringAt(uint32_t aIndex,
const char** aOutString,
uint32_t *aOutLength) const
{
if (NS_WARN_IF(aIndex >= Size())) {
return;
}
*aOutString = mStrings[aIndex].BeginReading();
*aOutLength = mStrings[aIndex].Length();
}
void
GMPStringListImpl::RelinquishData(nsTArray<nsCString>& aStrings)
{
aStrings = Move(mStrings);
}
GMPStringListImpl::~GMPStringListImpl()
{
}
} // namespace gmp
} // namespace mozilla

Просмотреть файл

@ -1,92 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPEncryptedBufferDataImpl_h_
#define GMPEncryptedBufferDataImpl_h_
#include "gmp-decryption.h"
#include "nsAutoPtr.h"
#include "nsTArray.h"
#include "mozilla/gmp/GMPTypes.h"
namespace mozilla {
class CryptoSample;
namespace gmp {
class GMPStringListImpl : public GMPStringList
{
public:
explicit GMPStringListImpl(const nsTArray<nsCString>& aStrings);
uint32_t Size() const override;
void StringAt(uint32_t aIndex,
const char** aOutString, uint32_t *aOutLength) const override;
virtual ~GMPStringListImpl() override;
void RelinquishData(nsTArray<nsCString>& aStrings);
private:
nsTArray<nsCString> mStrings;
};
class GMPEncryptedBufferDataImpl : public GMPEncryptedBufferMetadata {
public:
explicit GMPEncryptedBufferDataImpl(const CryptoSample& aCrypto);
explicit GMPEncryptedBufferDataImpl(const GMPDecryptionData& aData);
virtual ~GMPEncryptedBufferDataImpl();
void RelinquishData(GMPDecryptionData& aData);
const uint8_t* KeyId() const override;
uint32_t KeyIdSize() const override;
const uint8_t* IV() const override;
uint32_t IVSize() const override;
uint32_t NumSubsamples() const override;
const uint16_t* ClearBytes() const override;
const uint32_t* CipherBytes() const override;
const GMPStringList* SessionIds() const override;
private:
nsTArray<uint8_t> mKeyId;
nsTArray<uint8_t> mIV;
nsTArray<uint16_t> mClearBytes;
nsTArray<uint32_t> mCipherBytes;
GMPStringListImpl mSessionIdList;
};
class GMPBufferImpl : public GMPBuffer {
public:
GMPBufferImpl(uint32_t aId, const nsTArray<uint8_t>& aData)
: mId(aId)
, mData(aData)
{
}
uint32_t Id() const override {
return mId;
}
uint8_t* Data() override {
return mData.Elements();
}
uint32_t Size() const override {
return mData.Length();
}
void Resize(uint32_t aSize) override {
mData.SetLength(aSize);
}
// Set metadata object to be freed when this buffer is destroyed.
void SetMetadata(GMPEncryptedBufferDataImpl* aMetadata) {
mMetadata = aMetadata;
}
uint32_t mId;
nsTArray<uint8_t> mData;
nsAutoPtr<GMPEncryptedBufferDataImpl> mMetadata;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPEncryptedBufferDataImpl_h_

Просмотреть файл

@ -8,7 +8,6 @@
#include "gmp-video-codec.h" #include "gmp-video-codec.h"
#include "gmp-video-frame-encoded.h" #include "gmp-video-frame-encoded.h"
#include "gmp-decryption.h"
#include "IPCMessageUtils.h" #include "IPCMessageUtils.h"
namespace IPC { namespace IPC {
@ -20,28 +19,6 @@ struct ParamTraits<GMPErr>
GMPLastErr> GMPLastErr>
{}; {};
struct GMPDomExceptionValidator {
static bool IsLegalValue(GMPDOMException aValue) {
switch (aValue) {
case kGMPNoModificationAllowedError:
case kGMPNotFoundError:
case kGMPNotSupportedError:
case kGMPInvalidStateError:
case kGMPSyntaxError:
case kGMPInvalidModificationError:
case kGMPInvalidAccessError:
case kGMPSecurityError:
case kGMPAbortError:
case kGMPQuotaExceededError:
case kGMPTimeoutError:
case kGMPTypeError:
return true;
default:
return false;
}
}
};
template <> template <>
struct ParamTraits<GMPVideoFrameType> struct ParamTraits<GMPVideoFrameType>
: public ContiguousEnumSerializer<GMPVideoFrameType, : public ContiguousEnumSerializer<GMPVideoFrameType,
@ -49,32 +26,6 @@ struct ParamTraits<GMPVideoFrameType>
kGMPVideoFrameInvalid> kGMPVideoFrameInvalid>
{}; {};
template<>
struct ParamTraits<GMPDOMException>
: public EnumSerializer<GMPDOMException, GMPDomExceptionValidator>
{};
template <>
struct ParamTraits<GMPSessionMessageType>
: public ContiguousEnumSerializer<GMPSessionMessageType,
kGMPLicenseRequest,
kGMPMessageInvalid>
{};
template <>
struct ParamTraits<GMPMediaKeyStatus>
: public ContiguousEnumSerializer<GMPMediaKeyStatus,
kGMPUsable,
kGMPMediaKeyStatusInvalid>
{};
template <>
struct ParamTraits<GMPSessionType>
: public ContiguousEnumSerializer<GMPSessionType,
kGMPTemporySession,
kGMPSessionInvalid>
{};
template <> template <>
struct ParamTraits<GMPVideoCodecComplexity> struct ParamTraits<GMPVideoCodecComplexity>
: public ContiguousEnumSerializer<GMPVideoCodecComplexity, : public ContiguousEnumSerializer<GMPVideoCodecComplexity,

Просмотреть файл

@ -691,22 +691,6 @@ GMPParent::ReadGMPInfoFile(nsIFile* aFile)
} }
} }
if (cap.mAPIName.EqualsLiteral(GMP_API_DECRYPTOR)) {
mCanDecrypt = true;
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
if (!mozilla::SandboxInfo::Get().CanSandboxMedia()) {
nsPrintfCString msg(
"GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM"
" but this system can't sandbox it; not loading.",
mDisplayName.get());
printf_stderr("%s\n", msg.get());
LOGD("%s", msg.get());
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
#endif
}
mCapabilities.AppendElement(Move(cap)); mCapabilities.AppendElement(Move(cap));
} }
@ -789,6 +773,11 @@ GMPParent::ParseChromiumManifest(const nsAString& aJSON)
// psapi.dll added for GetMappedFileNameW, which could possibly be avoided // psapi.dll added for GetMappedFileNameW, which could possibly be avoided
// in future versions, see bug 1383611 for details. // in future versions, see bug 1383611 for details.
mLibs = NS_LITERAL_CSTRING("dxva2.dll, psapi.dll"); mLibs = NS_LITERAL_CSTRING("dxva2.dll, psapi.dll");
#endif
} else if (mDisplayName.EqualsASCII("fake")) {
kEMEKeySystem = NS_LITERAL_CSTRING("fake");
#if XP_WIN
mLibs = NS_LITERAL_CSTRING("dxva2.dll");
#endif #endif
} else { } else {
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);

Просмотреть файл

@ -8,7 +8,6 @@
#include "GMPProcessParent.h" #include "GMPProcessParent.h"
#include "GMPServiceParent.h" #include "GMPServiceParent.h"
#include "GMPDecryptorParent.h"
#include "GMPVideoDecoderParent.h" #include "GMPVideoDecoderParent.h"
#include "GMPVideoEncoderParent.h" #include "GMPVideoEncoderParent.h"
#include "GMPTimerParent.h" #include "GMPTimerParent.h"

Просмотреть файл

@ -21,7 +21,6 @@
#include "nsIXULAppInfo.h" #include "nsIXULAppInfo.h"
#include "nsIConsoleService.h" #include "nsIConsoleService.h"
#include "mozilla/Unused.h" #include "mozilla/Unused.h"
#include "GMPDecryptorParent.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
#include "runnable_utils.h" #include "runnable_utils.h"
#include "VideoUtils.h" #include "VideoUtils.h"
@ -425,50 +424,6 @@ GeckoMediaPluginService::GetGMPVideoEncoder(GMPCrashHelper* aHelper,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
GeckoMediaPluginService::GetGMPDecryptor(GMPCrashHelper* aHelper,
nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPDecryptorCallback>&& aCallback)
{
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
if (!SandboxInfo::Get().CanSandboxMedia()) {
NS_WARNING("GeckoMediaPluginService::GetGMPDecryptor: "
"EME decryption not available without sandboxing support.");
return NS_ERROR_NOT_AVAILABLE;
}
#endif
MOZ_ASSERT(mGMPThread->EventTarget()->IsOnCurrentThread());
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
NS_ENSURE_ARG(aCallback);
if (mShuttingDownOnGMPThread) {
return NS_ERROR_FAILURE;
}
GetGMPDecryptorCallback* rawCallback = aCallback.release();
RefPtr<AbstractThread> thread(GetAbstractGMPThread());
RefPtr<GMPCrashHelper> helper(aHelper);
GetContentParent(aHelper, aNodeId, NS_LITERAL_CSTRING(GMP_API_DECRYPTOR), *aTags)
->Then(thread, __func__,
[rawCallback, helper](RefPtr<GMPContentParent::CloseBlocker> wrapper) {
RefPtr<GMPContentParent> parent = wrapper->mParent;
UniquePtr<GetGMPDecryptorCallback> callback(rawCallback);
GMPDecryptorParent* actor = nullptr;
if (parent && NS_SUCCEEDED(parent->GetGMPDecryptor(&actor))) {
actor->SetCrashHelper(helper);
}
callback->Done(actor);
},
[rawCallback] {
UniquePtr<GetGMPDecryptorCallback> callback(rawCallback);
callback->Done(nullptr);
});
return NS_OK;
}
void void
GeckoMediaPluginService::ConnectCrashHelper(uint32_t aPluginId, GMPCrashHelper* aHelper) GeckoMediaPluginService::ConnectCrashHelper(uint32_t aPluginId, GMPCrashHelper* aHelper)
{ {

Просмотреть файл

@ -87,11 +87,6 @@ public:
const nsACString& aNodeId, const nsACString& aNodeId,
UniquePtr<GetGMPVideoEncoderCallback>&& aCallback) UniquePtr<GetGMPVideoEncoderCallback>&& aCallback)
override; override;
NS_IMETHOD GetGMPDecryptor(GMPCrashHelper* aHelper,
nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPDecryptorCallback>&& aCallback)
override;
// Helper for backwards compatibility with WebRTC/tests. // Helper for backwards compatibility with WebRTC/tests.
NS_IMETHOD NS_IMETHOD

Просмотреть файл

@ -23,7 +23,6 @@
#include "nsNativeCharsetUtils.h" #include "nsNativeCharsetUtils.h"
#include "nsIConsoleService.h" #include "nsIConsoleService.h"
#include "mozilla/Unused.h" #include "mozilla/Unused.h"
#include "GMPDecryptorParent.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
#include "runnable_utils.h" #include "runnable_utils.h"
#include "VideoUtils.h" #include "VideoUtils.h"
@ -1955,4 +1954,4 @@ GMPServiceParent::Create(Endpoint<PGMPServiceParent>&& aGMPService)
} // namespace gmp } // namespace gmp
} // namespace mozilla } // namespace mozilla
#undef NS_DispatchToMainThread #undef NS_DispatchToMainThread

Просмотреть файл

@ -4,7 +4,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using GMPBufferType from "gmp-video-codec.h"; using GMPBufferType from "gmp-video-codec.h";
using GMPMediaKeyStatus from "gmp-decryption.h";
namespace mozilla { namespace mozilla {
namespace gmp { namespace gmp {
@ -15,14 +14,6 @@ struct NodeIdData {
nsString mGMPName; nsString mGMPName;
}; };
struct GMPDecryptionData {
uint8_t[] mKeyId;
uint8_t[] mIV;
uint16_t[] mClearBytes;
uint32_t[] mCipherBytes;
nsCString[] mSessionIds;
};
struct GMPVideoEncodedFrameData struct GMPVideoEncodedFrameData
{ {
uint32_t mEncodedWidth; uint32_t mEncodedWidth;
@ -34,7 +25,6 @@ struct GMPVideoEncodedFrameData
GMPBufferType mBufferType; GMPBufferType mBufferType;
Shmem mBuffer; Shmem mBuffer;
bool mCompleteFrame; bool mCompleteFrame;
GMPDecryptionData mDecryptionData;
}; };
struct GMPPlaneData struct GMPPlaneData
@ -55,11 +45,6 @@ struct GMPVideoi420FrameData
uint64_t mDuration; // microseconds uint64_t mDuration; // microseconds
}; };
struct GMPKeyInformation {
uint8_t[] keyId;
GMPMediaKeyStatus status;
};
struct CDMInputBuffer { struct CDMInputBuffer {
Shmem mData; Shmem mData;
uint8_t[] mKeyId; uint8_t[] mKeyId;

Просмотреть файл

@ -123,27 +123,15 @@ GMPVideoDecoderParent::InitDecode(const GMPVideoCodec& aCodecSettings,
return NS_OK; return NS_OK;
} }
static nsCString
CryptoInfo(const GMPUniquePtr<GMPVideoEncodedFrame>& aInputFrame)
{
const GMPEncryptedBufferMetadata* crypto = aInputFrame->GetDecryptionData();
if (!crypto) {
return EmptyCString();
}
return nsPrintfCString(" kid=%s",
ToHexString(crypto->KeyId(), crypto->KeyIdSize()).get());
}
nsresult nsresult
GMPVideoDecoderParent::Decode(GMPUniquePtr<GMPVideoEncodedFrame> aInputFrame, GMPVideoDecoderParent::Decode(GMPUniquePtr<GMPVideoEncodedFrame> aInputFrame,
bool aMissingFrames, bool aMissingFrames,
const nsTArray<uint8_t>& aCodecSpecificInfo, const nsTArray<uint8_t>& aCodecSpecificInfo,
int64_t aRenderTimeMs) int64_t aRenderTimeMs)
{ {
LOGV(("GMPVideoDecoderParent[%p]::Decode() timestamp=%" PRId64 " keyframe=%d%s", LOGV(("GMPVideoDecoderParent[%p]::Decode() timestamp=%" PRId64 " keyframe=%d",
this, aInputFrame->TimeStamp(), this, aInputFrame->TimeStamp(),
aInputFrame->FrameType() == kGMPKeyFrame, aInputFrame->FrameType() == kGMPKeyFrame));
CryptoInfo(aInputFrame).get()));
if (!mIsOpen) { if (!mIsOpen) {
LOGE(("GMPVideoDecoderParent[%p]::Decode() ERROR; dead GMPVideoDecoder", this)); LOGE(("GMPVideoDecoderParent[%p]::Decode() ERROR; dead GMPVideoDecoder", this));

Просмотреть файл

@ -7,7 +7,6 @@
#include "GMPVideoHost.h" #include "GMPVideoHost.h"
#include "mozilla/gmp/GMPTypes.h" #include "mozilla/gmp/GMPTypes.h"
#include "GMPSharedMemManager.h" #include "GMPSharedMemManager.h"
#include "GMPEncryptedBufferDataImpl.h"
namespace mozilla { namespace mozilla {
namespace gmp { namespace gmp {
@ -41,9 +40,6 @@ GMPVideoEncodedFrameImpl::GMPVideoEncodedFrameImpl(const GMPVideoEncodedFrameDat
mBufferType(aFrameData.mBufferType()) mBufferType(aFrameData.mBufferType())
{ {
MOZ_ASSERT(aHost); MOZ_ASSERT(aHost);
if (aFrameData.mDecryptionData().mKeyId().Length() > 0) {
mCrypto = new GMPEncryptedBufferDataImpl(aFrameData.mDecryptionData());
}
aHost->EncodedFrameCreated(this); aHost->EncodedFrameCreated(this);
} }
@ -55,18 +51,6 @@ GMPVideoEncodedFrameImpl::~GMPVideoEncodedFrameImpl()
} }
} }
void
GMPVideoEncodedFrameImpl::InitCrypto(const CryptoSample& aCrypto)
{
mCrypto = new GMPEncryptedBufferDataImpl(aCrypto);
}
const GMPEncryptedBufferMetadata*
GMPVideoEncodedFrameImpl::GetDecryptionData() const
{
return mCrypto;
}
GMPVideoFrameFormat GMPVideoFrameFormat
GMPVideoEncodedFrameImpl::GetFrameFormat() GMPVideoEncodedFrameImpl::GetFrameFormat()
{ {
@ -105,9 +89,6 @@ GMPVideoEncodedFrameImpl::RelinquishFrameData(GMPVideoEncodedFrameData& aFrameDa
aFrameData.mCompleteFrame() = mCompleteFrame; aFrameData.mCompleteFrame() = mCompleteFrame;
aFrameData.mBuffer() = mBuffer; aFrameData.mBuffer() = mBuffer;
aFrameData.mBufferType() = mBufferType; aFrameData.mBufferType() = mBufferType;
if (mCrypto) {
mCrypto->RelinquishData(aFrameData.mDecryptionData());
}
// This method is called right before Shmem is sent to another process. // This method is called right before Shmem is sent to another process.
// We need to effectively zero out our member copy so that we don't // We need to effectively zero out our member copy so that we don't
@ -164,7 +145,6 @@ GMPVideoEncodedFrameImpl::CopyFrame(const GMPVideoEncodedFrame& aFrame)
mSize = f.mSize; // already set... mSize = f.mSize; // already set...
mCompleteFrame = f.mCompleteFrame; mCompleteFrame = f.mCompleteFrame;
mBufferType = f.mBufferType; mBufferType = f.mBufferType;
mCrypto = new GMPEncryptedBufferDataImpl(*(f.mCrypto));
// Don't copy host, that should have been set properly on object creation via host. // Don't copy host, that should have been set properly on object creation via host.
return GMPNoErr; return GMPNoErr;

Просмотреть файл

@ -34,7 +34,6 @@
#include "gmp-errors.h" #include "gmp-errors.h"
#include "gmp-video-frame.h" #include "gmp-video-frame.h"
#include "gmp-video-frame-encoded.h" #include "gmp-video-frame-encoded.h"
#include "gmp-decryption.h"
#include "mozilla/ipc/Shmem.h" #include "mozilla/ipc/Shmem.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
@ -45,7 +44,6 @@ namespace gmp {
class GMPVideoHostImpl; class GMPVideoHostImpl;
class GMPVideoEncodedFrameData; class GMPVideoEncodedFrameData;
class GMPEncryptedBufferDataImpl;
class GMPVideoEncodedFrameImpl: public GMPVideoEncodedFrame class GMPVideoEncodedFrameImpl: public GMPVideoEncodedFrame
{ {
@ -55,8 +53,6 @@ public:
GMPVideoEncodedFrameImpl(const GMPVideoEncodedFrameData& aFrameData, GMPVideoHostImpl* aHost); GMPVideoEncodedFrameImpl(const GMPVideoEncodedFrameData& aFrameData, GMPVideoHostImpl* aHost);
virtual ~GMPVideoEncodedFrameImpl(); virtual ~GMPVideoEncodedFrameImpl();
void InitCrypto(const CryptoSample& aCrypto);
// This is called during a normal destroy sequence, which is // This is called during a normal destroy sequence, which is
// when a consumer is finished or during XPCOM shutdown. // when a consumer is finished or during XPCOM shutdown.
void DoneWithAPI(); void DoneWithAPI();
@ -97,7 +93,6 @@ public:
uint8_t* Buffer() override; uint8_t* Buffer() override;
GMPBufferType BufferType() const override; GMPBufferType BufferType() const override;
void SetBufferType(GMPBufferType aBufferType) override; void SetBufferType(GMPBufferType aBufferType) override;
const GMPEncryptedBufferMetadata* GetDecryptionData() const override;
private: private:
void DestroyBuffer(); void DestroyBuffer();
@ -112,7 +107,6 @@ private:
GMPVideoHostImpl* mHost; GMPVideoHostImpl* mHost;
ipc::Shmem mBuffer; ipc::Shmem mBuffer;
GMPBufferType mBufferType; GMPBufferType mBufferType;
nsAutoPtr<GMPEncryptedBufferDataImpl> mCrypto;
}; };
} // namespace gmp } // namespace gmp

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше