merge mozilla-central to mozilla-inbound. r=merge a=merge

This commit is contained in:
Sebastian Hengst 2017-09-12 11:37:58 +02:00
Родитель 737aea1a0f ecf716b8bb
Коммит 6af41593df
405 изменённых файлов: 5017 добавлений и 4224 удалений

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

@ -67,5 +67,5 @@ USE_STATIC_LIBS = True
LIBRARY_DEFINES['UNICODE'] = True
LIBRARY_DEFINES['_UNICODE'] = True
LIBRARY_DEFINES['MOZ_NO_MOZALLOC'] = True
DISABLE_STL_WRAPPING = True
DisableStlWrapping()

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

@ -62,16 +62,6 @@ function PlainTextConsole(print, innerID) {
}
});
// We defined the `__exposedProps__` in our console chrome object.
//
// Meanwhile we're investigating with the platform team if `__exposedProps__`
// are needed, or are just a left-over.
console.__exposedProps__ = Object.keys(ConsoleAPI.prototype).reduce(function(exposed, prop) {
exposed[prop] = "r";
return exposed;
}, {});
Object.freeze(console);
return console;
};

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

@ -53,11 +53,6 @@ function HookedPlainTextConsole(hook, print, innerID) {
this.exception = hook.bind(null, "exception", innerID);
this.time = hook.bind(null, "time", innerID);
this.timeEnd = hook.bind(null, "timeEnd", innerID);
this.__exposedProps__ = {
log: "rw", info: "rw", warn: "rw", error: "rw", debug: "rw",
exception: "rw", time: "rw", timeEnd: "rw"
};
}
// Creates a custom loader instance whose console module is hooked in order

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

@ -444,7 +444,7 @@ exports["test Highlight toString Behavior"] = createProxyTest("", function (help
let strToString = helper.rawWindow.Object.prototype.toString.call("");
assert.ok(/\[object String.*\]/.test(strToString), "strings are strings");
let o = {__exposedProps__:{}};
let o = {};
let objToString = helper.rawWindow.Object.prototype.toString.call(o);
assert.ok(/\[object Object.*\]/.test(objToString), "objects are objects");
@ -622,10 +622,6 @@ exports["test Functions"] = createProxyTest("", function (helper) {
helper.rawWindow.isEqual = function isEqual(a, b) {
return a == b;
};
// bug 784116: workaround in order to allow proxy code to cache proxies on
// these functions:
helper.rawWindow.callFunction.__exposedProps__ = {__proxy: 'rw'};
helper.rawWindow.isEqual.__exposedProps__ = {__proxy: 'rw'};
helper.createWorker(
'new ' + function ContentScriptScope() {

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

@ -444,7 +444,7 @@ exports["test Highlight toString Behavior"] = createProxyTest("", function (help
let strToString = helper.rawWindow.Object.prototype.toString.call("");
assert.ok(/\[object String.*\]/.test(strToString), "strings are strings");
let o = {__exposedProps__:{}};
let o = {};
let objToString = helper.rawWindow.Object.prototype.toString.call(o);
assert.ok(/\[object Object.*\]/.test(objToString), "objects are objects");
@ -622,10 +622,6 @@ exports["test Functions"] = createProxyTest("", function (helper) {
helper.rawWindow.isEqual = function isEqual(a, b) {
return a == b;
};
// bug 784116: workaround in order to allow proxy code to cache proxies on
// these functions:
helper.rawWindow.callFunction.__exposedProps__ = {__proxy: 'rw'};
helper.rawWindow.isEqual.__exposedProps__ = {__proxy: 'rw'};
helper.createWorker(
'new ' + function ContentScriptScope() {

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

@ -101,7 +101,7 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
LDFLAGS += ['/HEAP:0x40000']
DISABLE_STL_WRAPPING = True
DisableStlWrapping()
if CONFIG['MOZ_LINKER']:
OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']

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

@ -5179,7 +5179,9 @@
<parameter name="aTab"/>
<body>
<![CDATA[
this._getSwitcher().warmupTab(aTab);
if (gMultiProcessBrowser) {
this._getSwitcher().warmupTab(aTab);
}
]]>
</body>
</method>

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

@ -87,6 +87,10 @@ var whitelist = [
{file: "resource://app/modules/NewTabSearchProvider.jsm"},
{file: "resource://app/modules/NewTabWebChannel.jsm"},
// browser/extensions/activity-stream/data/content/activity-stream-prerendered.html
// This will used when Bug 1397875 lands
{file: "resource://activity-stream/data/content/activity-stream-prerendered.html"},
// layout/mathml/nsMathMLChar.cpp
{file: "resource://gre/res/fonts/mathfontSTIXGeneral.properties"},
{file: "resource://gre/res/fonts/mathfontUnicode.properties"},

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

@ -2694,17 +2694,15 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
<binding id="click-to-play-plugins-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
<content align="start" style="width: &pluginNotification.width;;">
<xul:vbox flex="1" align="stretch" class="popup-notification-main-box"
<xul:vbox flex="1" align="stretch" class="click-to-play-plugins-notification-main-box"
xbl:inherits="popupid">
<xul:hbox class="click-to-play-plugins-notification-description-box" flex="1" align="start">
<xul:description class="click-to-play-plugins-outer-description" flex="1">
<html:span anonid="click-to-play-plugins-notification-description" />
<xul:label class="text-link click-to-play-plugins-notification-link" anonid="click-to-play-plugins-notification-link" />
<html:br/>
<xul:label class="text-link click-to-play-plugins-notification-link popup-notification-learnmore-link"
anonid="click-to-play-plugins-notification-link" />
</xul:description>
<xul:toolbarbutton anonid="closebutton"
class="messageCloseButton popup-notification-closebutton tabbable close-icon"
xbl:inherits="oncommand=closebuttoncommand"
tooltiptext="&closeNotification.tooltip;"/>
</xul:hbox>
<xul:grid anonid="click-to-play-plugins-notification-center-box"
class="click-to-play-plugins-notification-center-box">
@ -2726,11 +2724,12 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
class="click-to-play-plugins-notification-button-container"
pack="center" align="center">
<xul:button anonid="primarybutton"
class="click-to-play-popup-button"
class="click-to-play-popup-button popup-notification-button"
oncommand="document.getBindingParent(this)._onButton(this)"
flex="1"/>
<xul:button anonid="secondarybutton"
class="click-to-play-popup-button"
default="true"
class="click-to-play-popup-button popup-notification-button"
oncommand="document.getBindingParent(this)._onButton(this);"
flex="1"/>
</xul:hbox>

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

@ -10,11 +10,21 @@
"optional": true
}
}
},
{
"$extend": "Permission",
"choices": [{
"type": "string",
"enum": [
"devtools"
]
}]
}
]
},
{
"namespace": "devtools",
"permissions": ["devtools"],
"allowedContexts": ["devtools", "devtools_only"],
"defaultContexts": ["devtools", "devtools_only"]
}

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

@ -56,6 +56,13 @@ function promiseStateChangeURI() {
function promiseContentSearchReady(browser) {
return ContentTask.spawn(browser, {}, async function(args) {
return new Promise(resolve => {
if (content.wrappedJSObject.gContentSearchController) {
let searchController = content.wrappedJSObject.gContentSearchController;
if (searchController.defaultEngine) {
resolve();
}
}
content.addEventListener("ContentSearchService", function listener(aEvent) {
if (aEvent.detail.type == "State") {
content.removeEventListener("ContentSearchService", listener);

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

@ -95,14 +95,9 @@ function promiseStateChangeURI() {
function promiseContentSearchReady(browser) {
return ContentTask.spawn(browser, {}, async function(args) {
return new Promise(resolve => {
content.addEventListener("ContentSearchService", function listener(aEvent) {
if (aEvent.detail.type == "State") {
content.removeEventListener("ContentSearchService", listener);
resolve();
}
});
});
await ContentTaskUtils.waitForCondition(() => content.wrappedJSObject.gContentSearchController &&
content.wrappedJSObject.gContentSearchController.defaultEngine
);
});
}

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

@ -39,6 +39,7 @@ for (const type of [
"NEW_TAB_INIT",
"NEW_TAB_INITIAL_STATE",
"NEW_TAB_LOAD",
"NEW_TAB_STATE_REQUEST",
"NEW_TAB_UNLOAD",
"OPEN_LINK",
"OPEN_NEW_WINDOW",

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

@ -1,26 +1,28 @@
/* globals Services */
"use strict";
let usablePerfObj;
let Cu;
const isRunningInChrome = typeof Window === "undefined";
/* istanbul ignore if */
if (isRunningInChrome) {
Cu = Components.utils;
} else {
Cu = {import() {}};
if (typeof Components !== "undefined" && Components.utils) {
Components.utils.import("resource://gre/modules/Services.jsm");
}
Cu.import("resource://gre/modules/Services.jsm");
let usablePerfObj;
/* istanbul ignore if */
if (isRunningInChrome) {
/* istanbul ignore else */
if (typeof Services !== "undefined") {
// Borrow the high-resolution timer from the hidden window....
usablePerfObj = Services.appShell.hiddenDOMWindow.performance;
} else { // we must be running in content space
} else if (typeof performance !== "undefined") {
// we must be running in content space
usablePerfObj = performance;
} else {
// This is a dummy object so this file doesn't crash in the node prerendering
// task.
usablePerfObj = {
now() {},
mark() {}
};
}
this._PerfService = function _PerfService(options) {

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

@ -0,0 +1,42 @@
const prefConfig = {
// Prefs listed with "invalidates: true" will prevent the prerendered version
// of AS from being used if their value is something other than what is listed
// here. This is required because some preferences cause the page layout to be
// too different for the prerendered version to be used. Unfortunately, this
// will result in users who have modified some of their preferences not being
// able to get the benefits of prerendering.
"migrationExpired": {value: true},
"showTopSites": {
value: true,
invalidates: true
},
"showSearch": {
value: true,
invalidates: true
},
"topSitesCount": {value: 6},
"feeds.section.topstories": {
value: true,
invalidates: true
}
};
this.PrerenderData = {
invalidatingPrefs: Object.keys(prefConfig).filter(key => prefConfig[key].invalidates),
initialPrefs: Object.keys(prefConfig).reduce((obj, key) => {
obj[key] = prefConfig[key].value;
return obj;
}, {}), // This creates an object of the form {prefName: value}
initialSections: [
{
enabled: true,
icon: "pocket",
id: "topstories",
order: 1,
title: {id: "header_recommended_by", values: {provider: "Pocket"}},
topics: [{}]
}
]
};
this.EXPORTED_SYMBOLS = ["PrerenderData"];

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

@ -5,6 +5,9 @@
const {actionTypes: at} = Components.utils.import("resource://activity-stream/common/Actions.jsm", {});
// Locales that should be displayed RTL
const RTL_LIST = ["ar", "he", "fa", "ur"];
const TOP_SITES_DEFAULT_LENGTH = 6;
const TOP_SITES_SHOWMORE_LENGTH = 12;
@ -16,6 +19,8 @@ const INITIAL_STATE = {
locale: "",
// Localized strings with defaults
strings: null,
// The text direction for the locale
textDirection: "",
// The version of the system-addon
version: null
},
@ -48,7 +53,8 @@ function App(prevState = INITIAL_STATE.App, action) {
let {locale, strings} = action.data;
return Object.assign({}, prevState, {
locale,
strings
strings,
textDirection: RTL_LIST.indexOf(locale.split("-")[0]) >= 0 ? "rtl" : "ltr"
});
}
default:

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

@ -0,0 +1,142 @@
// Note - this is a generated file.
window.gActivityStreamPrerenderedState = {
"TopSites": {
"initialized": false,
"rows": []
},
"App": {
"initialized": false,
"locale": "en-PRERENDER",
"strings": {
"newtab_page_title": " ",
"default_label_loading": " ",
"header_top_sites": " ",
"header_stories": " ",
"header_highlights": " ",
"header_visit_again": " ",
"header_bookmarks": " ",
"header_recommended_by": " ",
"header_bookmarks_placeholder": " ",
"header_stories_from": " ",
"type_label_visited": " ",
"type_label_bookmarked": " ",
"type_label_synced": " ",
"type_label_recommended": " ",
"type_label_open": " ",
"type_label_topic": " ",
"type_label_now": " ",
"menu_action_bookmark": " ",
"menu_action_remove_bookmark": " ",
"menu_action_copy_address": " ",
"menu_action_email_link": " ",
"menu_action_open_new_window": " ",
"menu_action_open_private_window": " ",
"menu_action_dismiss": " ",
"menu_action_delete": " ",
"menu_action_pin": " ",
"menu_action_unpin": " ",
"confirm_history_delete_p1": " ",
"confirm_history_delete_notice_p2": " ",
"menu_action_save_to_pocket": " ",
"search_for_something_with": " ",
"search_button": " ",
"search_header": " ",
"search_web_placeholder": "Search the Web",
"search_settings": " ",
"section_info_option": " ",
"section_info_send_feedback": " ",
"section_info_privacy_notice": " ",
"welcome_title": " ",
"welcome_body": " ",
"welcome_label": " ",
"time_label_less_than_minute": " ",
"time_label_minute": " ",
"time_label_hour": " ",
"time_label_day": " ",
"settings_pane_button_label": " ",
"settings_pane_header": " ",
"settings_pane_body2": " ",
"settings_pane_search_header": " ",
"settings_pane_search_body": " ",
"settings_pane_topsites_header": " ",
"settings_pane_topsites_body": " ",
"settings_pane_topsites_options_showmore": " ",
"settings_pane_bookmarks_header": " ",
"settings_pane_bookmarks_body": " ",
"settings_pane_visit_again_header": " ",
"settings_pane_visit_again_body": " ",
"settings_pane_highlights_header": " ",
"settings_pane_highlights_body2": " ",
"settings_pane_highlights_options_bookmarks": " ",
"settings_pane_highlights_options_visited": " ",
"settings_pane_snippets_header": " ",
"settings_pane_snippets_body": " ",
"settings_pane_done_button": " ",
"edit_topsites_button_text": " ",
"edit_topsites_button_label": " ",
"edit_topsites_showmore_button": " ",
"edit_topsites_showless_button": " ",
"edit_topsites_done_button": " ",
"edit_topsites_pin_button": " ",
"edit_topsites_unpin_button": " ",
"edit_topsites_edit_button": " ",
"edit_topsites_dismiss_button": " ",
"edit_topsites_add_button": " ",
"topsites_form_add_header": " ",
"topsites_form_edit_header": " ",
"topsites_form_title_placeholder": " ",
"topsites_form_url_placeholder": " ",
"topsites_form_add_button": " ",
"topsites_form_save_button": " ",
"topsites_form_cancel_button": " ",
"topsites_form_url_validation": " ",
"pocket_read_more": " ",
"pocket_read_even_more": " ",
"pocket_feedback_header": " ",
"pocket_description": " ",
"highlights_empty_state": " ",
"topstories_empty_state": " ",
"manual_migration_explanation2": " ",
"manual_migration_cancel_button": " ",
"manual_migration_import_button": " "
},
"textDirection": "ltr",
"version": null
},
"Snippets": {
"initialized": false
},
"Prefs": {
"initialized": true,
"values": {
"migrationExpired": true,
"showTopSites": true,
"showSearch": true,
"topSitesCount": 6,
"feeds.section.topstories": true
}
},
"Dialog": {
"visible": false,
"data": {}
},
"Sections": [
{
"title": {
"id": "header_recommended_by",
"values": {
"provider": "Pocket"
}
},
"rows": [],
"order": 1,
"enabled": true,
"icon": "pocket",
"id": "topstories",
"topics": [
{}
],
"initialized": false
}
]
};

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

@ -0,0 +1,25 @@
<!doctype html>
<html lang="" dir="ltr">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy-Report-Only" content="script-src 'unsafe-inline'; img-src http: https: data: blob:; style-src 'unsafe-inline'; child-src 'none'; object-src 'none'; report-uri https://tiles.services.mozilla.com/v4/links/activity-stream/csp">
<title></title>
<link rel="icon" type="image/png" id="favicon" href="chrome://branding/content/icon32.png"/>
<link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
<link rel="stylesheet" href="resource://activity-stream/data/content/activity-stream.css" />
</head>
<body class="activity-stream">
<div id="root"><div class="outer-wrapper" data-reactroot="" data-reactid="1" data-react-checksum="57168132"><main data-reactid="2"><div class="search-wrapper" data-reactid="3"><label for="newtab-search-text" class="search-label" data-reactid="4"><span class="sr-only" data-reactid="5"><span data-reactid="6">Search the Web</span></span></label><input type="search" id="newtab-search-text" maxlength="256" placeholder="Search the Web" title="Search the Web" data-reactid="7"/><button id="searchSubmit" class="search-button" title=" " data-reactid="8"><span class="sr-only" data-reactid="9"><span data-reactid="10"> </span></span></button></div><section class="top-sites" data-reactid="11"><h3 class="section-title" data-reactid="12"><span class="icon icon-small-spacer icon-topsites" data-reactid="13"></span><span data-reactid="14"> </span></h3><ul class="top-sites-list" data-reactid="15"><li class="top-site-outer placeholder" data-reactid="16"><a data-reactid="17"><div class="tile" aria-hidden="true" data-reactid="18"><span class="letter-fallback" data-reactid="19"></span><div class="screenshot" style="background-image:none;" data-reactid="20"></div></div><div class="title " data-reactid="21"><span dir="auto" data-reactid="22"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="23"><a data-reactid="24"><div class="tile" aria-hidden="true" data-reactid="25"><span class="letter-fallback" data-reactid="26"></span><div class="screenshot" style="background-image:none;" data-reactid="27"></div></div><div class="title " data-reactid="28"><span dir="auto" data-reactid="29"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="30"><a data-reactid="31"><div class="tile" aria-hidden="true" data-reactid="32"><span class="letter-fallback" data-reactid="33"></span><div class="screenshot" style="background-image:none;" data-reactid="34"></div></div><div class="title " data-reactid="35"><span dir="auto" data-reactid="36"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="37"><a data-reactid="38"><div class="tile" aria-hidden="true" data-reactid="39"><span class="letter-fallback" data-reactid="40"></span><div class="screenshot" style="background-image:none;" data-reactid="41"></div></div><div class="title " data-reactid="42"><span dir="auto" data-reactid="43"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="44"><a data-reactid="45"><div class="tile" aria-hidden="true" data-reactid="46"><span class="letter-fallback" data-reactid="47"></span><div class="screenshot" style="background-image:none;" data-reactid="48"></div></div><div class="title " data-reactid="49"><span dir="auto" data-reactid="50"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="51"><a data-reactid="52"><div class="tile" aria-hidden="true" data-reactid="53"><span class="letter-fallback" data-reactid="54"></span><div class="screenshot" style="background-image:none;" data-reactid="55"></div></div><div class="title " data-reactid="56"><span dir="auto" data-reactid="57"></span></div></a></li></ul></section><div class="sections-list" data-reactid="58"><section data-reactid="59"><div class="section-top-bar" data-reactid="60"><h3 class="section-title" data-reactid="61"><span class="icon icon-small-spacer icon-pocket" data-reactid="62"></span><span data-reactid="63"> </span></h3></div><ul class="section-list" style="padding:0;" data-reactid="64"><li class="card-outer placeholder" data-reactid="65"><a data-reactid="66"><div class="card" data-reactid="67"><div class="card-details no-image" data-reactid="68"><div class="card-text no-image no-host-name no-context" data-reactid="69"><h4 class="card-title" dir="auto" data-reactid="70"></h4><p class="card-description" dir="auto" data-reactid="71"></p></div></div></div></a></li><li class="card-outer placeholder" data-reactid="72"><a data-reactid="73"><div class="card" data-reactid="74"><div class="card-details no-image" data-reactid="75"><div class="card-text no-image no-host-name no-context" data-reactid="76"><h4 class="card-title" dir="auto" data-reactid="77"></h4><p class="card-description" dir="auto" data-reactid="78"></p></div></div></div></a></li><li class="card-outer placeholder" data-reactid="79"><a data-reactid="80"><div class="card" data-reactid="81"><div class="card-details no-image" data-reactid="82"><div class="card-text no-image no-host-name no-context" data-reactid="83"><h4 class="card-title" dir="auto" data-reactid="84"></h4><p class="card-description" dir="auto" data-reactid="85"></p></div></div></div></a></li></ul><div class="topic" data-reactid="86"><span data-reactid="87"><span data-reactid="88"> </span></span><ul data-reactid="89"><li data-reactid="90"><a class="topic-link" data-reactid="91"></a></li></ul></div></section></div><!-- react-empty: 92 --></main></div></div>
<div id="snippets-container">
<div id="snippets"></div>
</div>
<script src="resource://activity-stream/data/content/activity-stream-initial-state.js"></script>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="resource://activity-stream/vendor/react.js"></script>
<script src="resource://activity-stream/vendor/react-dom.js"></script>
<script src="resource://activity-stream/vendor/react-intl.js"></script>
<script src="resource://activity-stream/vendor/redux.js"></script>
<script src="resource://activity-stream/vendor/react-redux.js"></script>
<script src="resource://activity-stream/data/content/activity-stream.bundle.js"></script>
</body>
</html>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -64,7 +64,9 @@ input {
.icon.icon-historyItem {
background-image: url("assets/glyph-historyItem-16.svg"); }
.icon.icon-trending {
background-image: url("assets/glyph-trending-16.svg"); }
background-image: url("assets/glyph-trending-16.svg");
transform: translateY(2px);
/* trending bolt is visually top heavy */ }
.icon.icon-now {
background-image: url("chrome://browser/skin/history.svg"); }
.icon.icon-topsites {
@ -317,17 +319,26 @@ main {
opacity: 0; }
.top-sites-list .top-site-outer .screenshot.active {
opacity: 1; }
.top-sites-list .top-site-outer .tippy-top-icon {
.top-sites-list .top-site-outer .top-site-icon {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
border-radius: 6px;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
background-position: center center;
background-size: 96px;
background-repeat: no-repeat; }
background-repeat: no-repeat;
background-color: #F9F9FA; }
.top-sites-list .top-site-outer .rich-icon {
top: 0;
offset-inline-start: 0;
height: 100%;
width: 100%;
background-size: 96px; }
.top-sites-list .top-site-outer .default-icon {
z-index: 1;
top: -6px;
offset-inline-start: -6px;
height: 42px;
width: 42px;
background-size: 32px; }
.top-sites-list .top-site-outer .title {
font: message-box;
height: 30px;
@ -1017,11 +1028,10 @@ main {
display: flex; }
.card-outer .card-context-icon {
fill: rgba(12, 12, 13, 0.6);
font-size: 13px;
margin-inline-end: 6px;
display: block; }
margin-inline-end: 6px; }
.card-outer .card-context-label {
flex-grow: 1;
line-height: 16px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; }

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

@ -1,5 +1,5 @@
<!doctype html>
<html lang="en-us" dir="ltr">
<html lang="" dir="ltr">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy-Report-Only" content="script-src 'unsafe-inline'; img-src http: https: data: blob:; style-src 'unsafe-inline'; child-src 'none'; object-src 'none'; report-uri https://tiles.services.mozilla.com/v4/links/activity-stream/csp">

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

@ -232,9 +232,11 @@
"settings_pane_visit_again_header": "Təkrar ziyarət et",
"settings_pane_visit_again_body": "Firefox tarixçənizdən yadda saxlamaq və ya geri qayıtmaq istəyə biləcəyiniz hissələri göstərəcək.",
"settings_pane_highlights_header": "Seçilmişlər",
"settings_pane_highlights_body2": "Son ziyarət etdiyiniz və ya əlfəcinlədiyiniz maraqlı məzmunlara rahat qayıdın.",
"settings_pane_highlights_options_bookmarks": "Əlfəcinlər",
"settings_pane_highlights_options_visited": "Baxılmış Saytlar",
"settings_pane_snippets_header": "Hissələr",
"settings_pane_snippets_body": "Mozilladan Firefox, internet mədəniyyəti və digər yeniliklər haqqında qısa bildirişlər oxuyun.",
"settings_pane_done_button": "Oldu",
"edit_topsites_button_text": "Redaktə et",
"edit_topsites_button_label": "Qabaqcıl Saytlar bölümünüzü fərdiləşdirin",
@ -257,6 +259,8 @@
"pocket_read_more": "Məşhur Mövzular:",
"pocket_read_even_more": "Daha çox hekayə gör",
"pocket_feedback_header": "25 milyon nəfərin dəstəyi ilə internetin ən yaxşıları.",
"pocket_description": "Mozilla ailəsinin yeni üzvü olan Pocket ilə yüksək keyfiyyətli məzmunları kəşf edin.",
"highlights_empty_state": "İnternetdə gəzməyə başlayın, burada ziyarət edəcəyiniz və ya əlfəcinləyəcəyiniz məqalə, video və digər səhifələri göstərəcəyik.",
"topstories_empty_state": "Hamısını oxudunuz. Yeni {provider} məqalələri üçün daha sonra təkrar yoxlayın. Gözləyə bilmirsiz? Məşhur mövzu seçərək internetdən daha çox gözəl məqalələr tapın.",
"manual_migration_explanation2": "Firefox səyyahını digər səyyahlardan olan əlfəcin, tarixçə və parollar ilə yoxlayın.",
"manual_migration_cancel_button": "Xeyr, Təşəkkürlər",
@ -414,9 +418,11 @@
"settings_pane_visit_again_header": "Посещаване",
"settings_pane_visit_again_body": "Firefox ще ви показва части от вашата история на разглеждане, към която бихте желали да се върнете или запомните.",
"settings_pane_highlights_header": "Акценти",
"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": "Готово",
"edit_topsites_button_text": "Редактиране",
"edit_topsites_button_label": "Настройки на най-посещаваните",
@ -440,6 +446,7 @@
"pocket_read_even_more": "Повече статии",
"pocket_feedback_header": "Най-доброто от интернет, подбрано от над 25 милиона души.",
"pocket_description": "Открийте висококачествено съдържание, което иначе може да пропуснете, с помощта на Pocket, вече част от Mozilla.",
"highlights_empty_state": "Разглеждайте и тук ще ви покажем някои от най-добрите статии, видео и други страници, които сте посетили или отметнали наскоро.",
"topstories_empty_state": "Разгледахте всичко. Проверете по-късно за повече истории от {provider}. Нямате търпение? Изберете популярна тема, за да откриете повече истории из цялата Мрежа.",
"manual_migration_explanation2": "Опитайте Firefox с отметките, историята и паролите от друг четец.",
"manual_migration_cancel_button": "Не, благодаря",
@ -1055,10 +1062,10 @@
"menu_action_email_link": "Link per E-Mail versenden…",
"menu_action_open_new_window": "In neuem Fenster öffnen",
"menu_action_open_private_window": "In neuem privaten Fenster öffnen",
"menu_action_dismiss": "Schließen",
"menu_action_dismiss": "Entfernen",
"menu_action_delete": "Aus Chronik löschen",
"menu_action_pin": "Anheften",
"menu_action_unpin": "Lösen",
"menu_action_unpin": "Ablösen",
"confirm_history_delete_p1": "Soll wirklich jede Instanz dieser Seite aus Ihrer Chronik gelöscht werden?",
"confirm_history_delete_notice_p2": "Diese Aktion kann nicht rückgängig gemacht werden.",
"menu_action_save_to_pocket": "Bei Pocket speichern",
@ -1077,8 +1084,8 @@
"time_label_minute": "{number} m",
"time_label_hour": "{number} h",
"time_label_day": "{number} t",
"settings_pane_button_label": "Neuer-Tab-Seite anpassen",
"settings_pane_header": "Einstellungen zum neuen Tab",
"settings_pane_button_label": "Einstellungen für neue Tabs anpassen",
"settings_pane_header": "Einstellungen für neue Tabs",
"settings_pane_body2": "Wählen Sie aus, was auf dieser Seite angezeigt wird.",
"settings_pane_search_header": "Suche",
"settings_pane_search_body": "Suchen Sie aus einem neuen Tab im Internet.",
@ -1108,8 +1115,8 @@
"edit_topsites_add_button": "Hinzufügen",
"topsites_form_add_header": "Neue meistbesuchte Seite",
"topsites_form_edit_header": "Meistbesuchte Seite bearbeiten",
"topsites_form_title_placeholder": "Titel eingeben",
"topsites_form_url_placeholder": "Eine URL eingeben oder einfügen",
"topsites_form_title_placeholder": "Name eingeben",
"topsites_form_url_placeholder": "Eine Adresse eingeben oder einfügen",
"topsites_form_add_button": "Hinzufügen",
"topsites_form_save_button": "Speichern",
"topsites_form_cancel_button": "Abbrechen",
@ -1119,7 +1126,7 @@
"pocket_feedback_header": "Das Beste aus dem Web, zusammengetragen von 25 Millionen Menschen.",
"pocket_description": "Entdecken Sie qualitativ hochwertige Inhalte mithilfe von Pocket (jetzt Teil von von Mozilla), die Sie ansonsten verpassen würden.",
"highlights_empty_state": "Surfen Sie los und wir zeigen Ihnen hier tolle Artikel, Videos und andere Seiten, die Sie kürzlich besucht oder als Lesezeichen gespeichert haben.",
"topstories_empty_state": "Jetzt kennen Sie die Neuigkeiten. Schauen Sie später wieder vorbei, um neue Informationen von {provider} zu erhalten. Können sie nicht warten? Wählen Sie ein beliebtes Thema und lesen Sie weitere interessante Geschichten aus dem Internet.",
"topstories_empty_state": "Jetzt kennen Sie die Neuigkeiten. Schauen Sie später wieder vorbei, um neue Informationen von {provider} zu erhalten. Können Sie nicht warten? Wählen Sie ein beliebtes Thema und lesen Sie weitere interessante Geschichten aus dem Internet.",
"manual_migration_explanation2": "Probieren Sie Firefox aus und importieren Sie die Lesezeichen, Chronik und Passwörter eines anderen Browsers.",
"manual_migration_cancel_button": "Nein, danke",
"manual_migration_import_button": "Jetzt importieren"
@ -1763,6 +1770,7 @@
"default_label_loading": "Cargando…",
"header_top_sites": "Sitios favoritos",
"header_stories": "Historias populares",
"header_highlights": "Destacados",
"header_visit_again": "Visitar de nuevo",
"header_bookmarks": "Marcadores recientes",
"header_recommended_by": "Recomendado por {provider}",
@ -1794,6 +1802,8 @@
"search_web_placeholder": "Buscar en la Web",
"search_settings": "Cambiar ajustes de búsqueda",
"section_info_option": "Info",
"section_info_send_feedback": "Enviar comentario",
"section_info_privacy_notice": "Aviso de privacidad",
"welcome_title": "Bienvenido a la nueva pestaña",
"welcome_body": "Firefox utilizará este espacio para mostrarte los marcadores, artículos y vídeos más relevantes y las páginas que has visitado recientemente, para que puedas acceder más rápido.",
"welcome_label": "Identificar lo más destacado para ti",
@ -1803,7 +1813,7 @@
"time_label_day": "{number}d",
"settings_pane_button_label": "Personalizar la página Nueva pestaña",
"settings_pane_header": "Preferencias de nueva pestaña",
"settings_pane_body": "Elige qué quieres ver al abrir una nueva pestaña",
"settings_pane_body2": "Elige lo quieras ver en esta página.",
"settings_pane_search_header": "Buscar",
"settings_pane_search_body": "Busca en la Web desde tu nueva pestaña.",
"settings_pane_topsites_header": "Sitios populares",
@ -1813,8 +1823,12 @@
"settings_pane_bookmarks_body": "Tus marcadores recién creados, fácilmente accesibles.",
"settings_pane_visit_again_header": "Visitar de nuevo",
"settings_pane_visit_again_body": "Firefox te mostrará partes de tu historial de navegación que te gustaría recordar o volver a visitar.",
"settings_pane_pocketstories_header": "Historias populares",
"settings_pane_pocketstories_body": "Pocket, que forma parte de la familia de Mozilla, te ayudará a encontrar contenido de alta calidad que puede que no encuentres de otra forma.",
"settings_pane_highlights_header": "Destacados",
"settings_pane_highlights_body2": "Vuelve a encontrar todas las cosas interesantes que hayas visitado o marcado recientemente.",
"settings_pane_highlights_options_bookmarks": "Marcadores",
"settings_pane_highlights_options_visited": "Sitios visitados",
"settings_pane_snippets_header": "Fragmentos de código",
"settings_pane_snippets_body": "Lee actualizaciones breves de Mozilla sobre Firefox, la cultura de internet y el típico meme aleatorio.",
"settings_pane_done_button": "Hecho",
"edit_topsites_button_text": "Editar",
"edit_topsites_button_label": "Personalizar la sección de Sitios populares",
@ -1837,10 +1851,10 @@
"pocket_read_more": "Temas populares:",
"pocket_read_even_more": "Ver más historias",
"pocket_feedback_header": "Lo mejor de la web, confirmado por más de 25 millones de personas.",
"pocket_feedback_body": "Pocket, que forma parte de la familia de Mozilla, te ayudará a encontrar contenido de alta calidad que puede que no encuentres de otra forma.",
"pocket_send_feedback": "Enviar comentario",
"pocket_description": "Gracias a Pocket, que ahora forma parte de Mozilla, podrás descubrir contenido de alta calidad que de otra forma te perderías.",
"highlights_empty_state": "Empieza a navegar y nosotros te mostraremos aquí algunos de los mejores artículos, videos y otras páginas que hayas visitado recientemente o agregado a marcadores.",
"topstories_empty_state": "Ya estás al día. Vuelve luego y busca más historias de {provider}. ¿No puedes esperar? Selecciona un tema popular y encontrás más historias alucinantes por toda la web.",
"manual_migration_explanation": "Prueba Firefox con tusmarcadores y sitios favoritos importados desde otro navegador.",
"manual_migration_explanation2": "Prueba Firefox con los marcadores, historial y contraseñas de otro navegador.",
"manual_migration_cancel_button": "No, gracias",
"manual_migration_import_button": "Importar ahora"
},
@ -2363,7 +2377,7 @@
"settings_pane_visit_again_header": "Visiter à nouveau",
"settings_pane_visit_again_body": "Firefox affichera des extraits de votre historique de navigation dont vous pourriez vouloir vous souvenir ou que vous pourriez vouloir revisiter.",
"settings_pane_highlights_header": "Éléments-clés",
"settings_pane_highlights_body2": "Retrouvez des pages inintéressantes que vous avez déjà visitées récemment ou ajoutées aux marque-pages.",
"settings_pane_highlights_body2": "Retrouvez des pages intéressantes que vous avez visitées récemment ou ajoutées aux marque-pages.",
"settings_pane_highlights_options_bookmarks": "Marque-pages",
"settings_pane_highlights_options_visited": "Sites visités",
"settings_pane_snippets_header": "Brèves",
@ -3007,6 +3021,7 @@
"default_label_loading": "Betöltés…",
"header_top_sites": "Népszerű oldalak",
"header_stories": "Népszerű történetek",
"header_highlights": "Kiemelések",
"header_visit_again": "Látogasson el ismét",
"header_bookmarks": "Friss könyvjelzők",
"header_recommended_by": "A(z) {provider} ajánlásával",
@ -3038,6 +3053,8 @@
"search_web_placeholder": "Keresés a weben",
"search_settings": "Keresési beállítások módosítása",
"section_info_option": "Információ",
"section_info_send_feedback": "Visszajelzés küldése",
"section_info_privacy_notice": "Adatvédelmi nyilatkozat",
"welcome_title": "Üdvözöljük az új lapon",
"welcome_body": "A Firefox ezt a területet a leginkább releváns könyvjelzők, cikkek, videók és nemrég látogatott oldalak megjelenítésére fogja használni, így könnyedén visszatalálhat hozzájuk.",
"welcome_label": "A kiemeléseinek azonosítása",
@ -3047,7 +3064,7 @@
"time_label_day": "{number} n",
"settings_pane_button_label": "Az Új lap oldal személyre szabása",
"settings_pane_header": "Új lap beállításai",
"settings_pane_body": "Válassza ki, hogy mit lát, amikor megnyit egy új lapot.",
"settings_pane_body2": "Válassza ki, hogy mit akar látni ezen az oldalon.",
"settings_pane_search_header": "Keresés",
"settings_pane_search_body": "Keresés a weben az új lapon.",
"settings_pane_topsites_header": "Népszerű oldalak",
@ -3057,8 +3074,12 @@
"settings_pane_bookmarks_body": "A frissen létrehozott könyvjelzői egy praktikus helyen.",
"settings_pane_visit_again_header": "Látogasson el ismét",
"settings_pane_visit_again_body": "A Firefox megjeleníti a böngészési előzményeinek azt a részét, amelyet lehet hogy meg szeretne jegyezni, vagy ahová vissza akar térni.",
"settings_pane_pocketstories_header": "Népszerű történetek",
"settings_pane_pocketstories_body": "A Pocket a Mozilla család tagja, segít az olyan jó minőségű tartalmak fellelésében, melyekkel egyébként nem is találkozott volna.",
"settings_pane_highlights_header": "Kiemelések",
"settings_pane_highlights_body2": "Találjon vissza azokhoz az érdekes dolgokhoz, amelyeket meglátogatott vagy könyvjelzőzött.",
"settings_pane_highlights_options_bookmarks": "Könyvjelzők",
"settings_pane_highlights_options_visited": "Látogatott helyek",
"settings_pane_snippets_header": "Töredékek",
"settings_pane_snippets_body": "Olvasson rövid és érdekes híreket a Mozillától, a Firefoxról, az internetes kultúráról, és időnként kapjon mémeket.",
"settings_pane_done_button": "Kész",
"edit_topsites_button_text": "Szerkesztés",
"edit_topsites_button_label": "A Népszerű oldalak rész testreszabása",
@ -3081,10 +3102,10 @@
"pocket_read_more": "Népszerű témák:",
"pocket_read_even_more": "További történetek",
"pocket_feedback_header": "A web legjava, több mint 25 millió ember válogatásában.",
"pocket_feedback_body": "A Pocket a Mozilla család tagja, segít az olyan jó minőségű tartalmak fellelésében, melyekkel egyébként nem is találkozott volna.",
"pocket_send_feedback": "Visszajelzés küldése",
"pocket_description": "Fedezzen fel olyan, magas minőségű tartalmakat, amelyek egyébként elkerülnék a figyelmét, a Pocket segítségével, amely most már a Mozilla része.",
"highlights_empty_state": "Kezdjen el böngészni, és itt fognak megjelenni azok a nagyszerű cikkek, videók és más lapok, amelyeket nemrég meglátogatott vagy könyvjelzőzött.",
"topstories_empty_state": "Már felzárkózott. Nézzen vissza később a legújabb {provider} hírekért. Nem tud várni? Válasszon egy népszerű témát, hogy még több sztorit találjon a weben.",
"manual_migration_explanation": "Próbálja ki a Firefoxot egy másik böngészőben lévő kedvenc oldalaival és könyvjelzőivel.",
"manual_migration_explanation2": "Próbálja ki a Firefoxot másik böngészőből származó könyvjelzőkkel, előzményekkel és jelszavakkal.",
"manual_migration_cancel_button": "Köszönöm, nem",
"manual_migration_import_button": "Importálás most"
},
@ -3123,6 +3144,7 @@
"default_label_loading": "Memuat…",
"header_top_sites": "Situs Teratas",
"header_stories": "Cerita Utama",
"header_highlights": "Sorotan",
"header_visit_again": "Kunjungi Lagi",
"header_bookmarks": "Markah Terbaru",
"header_recommended_by": "Disarankan oleh {provider}",
@ -3154,6 +3176,8 @@
"search_web_placeholder": "Cari di Web",
"search_settings": "Ubah Pengaturan Pencarian",
"section_info_option": "Info",
"section_info_send_feedback": "Kirim Umpan Balik",
"section_info_privacy_notice": "Kebijakan Privasi",
"welcome_title": "Selamat datang di tab baru",
"welcome_body": "Firefox akan menggunakan ruang ini untuk menampilkan markah, artikel, video, dan laman yang baru-baru ini dikunjungi, yang paling relevan agar Anda bisa kembali mengunjunginya dengan mudah.",
"welcome_label": "Mengidentifikasi Sorotan Anda",
@ -3163,7 +3187,7 @@
"time_label_day": "{number} hr",
"settings_pane_button_label": "Ubahsuai laman Tab Baru Anda",
"settings_pane_header": "Preferensi Tab Baru",
"settings_pane_body": "Pilih apa yang Anda lihat ketika Anda membuka tab baru.",
"settings_pane_body2": "Pilih apa yang Anda lihat di halaman ini.",
"settings_pane_search_header": "Pencarian",
"settings_pane_search_body": "Cari Web dari tab baru Anda.",
"settings_pane_topsites_header": "Situs Teratas",
@ -3173,8 +3197,12 @@
"settings_pane_bookmarks_body": "Markah Anda dibuat di lokasi yang praktis.",
"settings_pane_visit_again_header": "Kunjungi Lagi",
"settings_pane_visit_again_body": "Firefox akan menunjukkan bagian dari riwayat penjelajahan yang mungkin ingin Anda ingat atau kunjungi lagi.",
"settings_pane_pocketstories_header": "Cerita Utama",
"settings_pane_pocketstories_body": "Pocket, bagian dari keluarga Mozilla, akan membantu hubungkan Anda dengan konten berkualitas tinggi yang tak dapat Anda temukan di tempat lain.",
"settings_pane_highlights_header": "Sorotan",
"settings_pane_highlights_body2": "Temukan jalan kembali ke hal menarik yang baru saja Anda kunjungi atau dimarkah.",
"settings_pane_highlights_options_bookmarks": "Markah",
"settings_pane_highlights_options_visited": "Situs Terkunjungi",
"settings_pane_snippets_header": "Catatan Kecil",
"settings_pane_snippets_body": "Baca info pendek terbaru dari Mozilla tentang Firefox, budaya internet dan beberapa meme acak.",
"settings_pane_done_button": "Selesai",
"edit_topsites_button_text": "Sunting",
"edit_topsites_button_label": "Ubahsuai bagian Situs Teratas Anda",
@ -3197,10 +3225,10 @@
"pocket_read_more": "Topik Populer:",
"pocket_read_even_more": "Lihat Cerita Lainnya",
"pocket_feedback_header": "Yang terbaik dari Web, dikurasi lebih dari 25 juta orang.",
"pocket_feedback_body": "Pocket, bagian dari keluarga Mozilla, akan membantu hubungkan Anda dengan konten berkualitas tinggi yang tak dapat Anda temukan di tempat lain.",
"pocket_send_feedback": "Kirim Umpanbalik",
"pocket_description": "Temukan konten berkualitas tinggi yang mungkin Anda lewatkan dengan bantuan Pocket, yang sekarang menjadi bagian dari Mozilla.",
"highlights_empty_state": "Mulai menjelajah, dan kami akan menampilkan beberapa artikel bagus, video, dan halaman lain yang baru saja Anda kunjungi atau termarkah di sini.",
"topstories_empty_state": "Maaf Anda tercegat. Periksa lagi nanti untuk lebih banyak cerita terbaik dari {provider}. Tidak mau menunggu? Pilih topik populer untuk menemukan lebih banyak cerita hebat dari seluruh web.",
"manual_migration_explanation": "Cobalah Firefox dengan situs dan markah kesukaan Anda dari peramban yang lain.",
"manual_migration_explanation2": "Coba Firefox dengan markah, riwayat, dan sandi dari peramban lain.",
"manual_migration_cancel_button": "Tidak, Terima kasih",
"manual_migration_import_button": "Impor Sekarang"
},
@ -3488,6 +3516,7 @@
"default_label_loading": "Asali…",
"header_top_sites": "Ismal ifazen",
"header_stories": "Tiqsiɣin ifazen",
"header_highlights": "Asebrureq",
"header_visit_again": "Rzu tikelt-nniḍen",
"header_bookmarks": "Ticraḍ n melmi kan",
"header_recommended_by": "Iwelleh-it-id {provider}",
@ -3519,6 +3548,8 @@
"search_web_placeholder": "Nadi di Web",
"search_settings": "Snifel iγewwaṛen n unadi",
"section_info_option": "Talɣut",
"section_info_send_feedback": "Azen tikti",
"section_info_privacy_notice": "Tasertit n tbaḍnit",
"welcome_title": "Ansuf ar yiccer amaynut",
"welcome_body": "Firefox ad iseqdec tallunt akken ad d-yesken akk ticraḍ n isebtar iwulmen, imagraden, tividyutin, akked isebtar aniɣer terziḍ melmi kan, ihi tzemreḍ ad d-uɣaleḍ ɣer-sen s wudem fessusen.",
"welcome_label": "Asulu n iferdisen tisura",
@ -3528,7 +3559,7 @@
"time_label_day": "{number}n wussan",
"settings_pane_button_label": "Sagen asebter n yiccer-ik amaynut",
"settings_pane_header": "Ismenyifen n yiccer amaynut",
"settings_pane_body": "Fren ayen ara twaliḍ ticki teldiḍ iccer imaynut.",
"settings_pane_body2": "Fren ayen ad twaliḍ deg usebter-agi.",
"settings_pane_search_header": "Nadi",
"settings_pane_search_body": "Nadi di Web seg iccer-ik amaynut.",
"settings_pane_topsites_header": "Ismal ifazen",
@ -3538,8 +3569,12 @@
"settings_pane_bookmarks_body": "Ticraḍ yettwarnan melmi kan deg iwen n umdiq ɣef afus.",
"settings_pane_visit_again_header": "Rzu tikelt-nniḍen",
"settings_pane_visit_again_body": "Firefox ad d-yesken tukkist n umazray-ik n tunigin i tzemreḍ ad twalid tikelt-nniḍen.",
"settings_pane_pocketstories_header": "Tiqsiɣin ifazen",
"settings_pane_pocketstories_body": "Pocket, aɛeggal n twaxult n Mozilla, ak-d-yefk afus ad twaliḍ agbur n tɣara meqqren i tzemred ad tzegleḍ.",
"settings_pane_highlights_header": "Asebrureq",
"settings_pane_highlights_body2": "Aff abrid-ik γer wayen i tḥemmleḍ i γef terziḍ yakan neγ tcerḍeḍ-t.",
"settings_pane_highlights_options_bookmarks": "Ticraḍ n isebtar",
"settings_pane_highlights_options_visited": "Ismal yettwarzan",
"settings_pane_snippets_header": "Tiwzillin",
"settings_pane_snippets_body": "Wali issalen n Mozilla γef Firefox, adlis internet, akked issalen nniṣen sya γer da.",
"settings_pane_done_button": "Immed",
"edit_topsites_button_text": "Ẓreg",
"edit_topsites_button_label": "Sagen tigezmi n ismal ifazen",
@ -3562,10 +3597,10 @@
"pocket_read_more": "Isental ittwasnen aṭas:",
"pocket_read_even_more": "Wali ugar n teqsiḍin",
"pocket_feedback_header": "D amezwaru n Web, ittwafren sγur ugar 25 imelyan n imdanen.",
"pocket_feedback_body": "Pocket, aɛeggal n twaxult n Mozilla, ak-d-yefk afus ad twaliḍ agbur n tɣara meqqren i tzemred ad tzegleḍ.",
"pocket_send_feedback": "Azen tikti",
"pocket_description": "S lmendad n Pocket n Mozillan wali aqbur ifazen aṭas, s ttawil-a werǧin ad tzegleḍ taγawsa.",
"highlights_empty_state": "Bdu tuniginn sakin nekkni ad k-n-sken imagraden, tividyutin, akked isebtar nniḍen i γef terziḍ yakan neγ i tceṛḍeḍ dagi.",
"topstories_empty_state": "Ulac wiyaḍ. Uɣal-d ticki s wugar n imagraden seg {provider}. Ur tebɣiḍ ara ad terǧuḍ? Fren asentel seg wid yettwasnen akken ad twaliḍ imagraden yelhan di Web.",
"manual_migration_explanation": "Ɛreḍ Firefox s ismal-ik inurifen akked ticraḍ seg iminig-nniḍen.",
"manual_migration_explanation2": "Σreḍ Firefox s ticṛaḍ n isebtar, amazray akked awalen uffiren sγur ilinigen nniḍen.",
"manual_migration_cancel_button": "Ala, tanemmirt",
"manual_migration_import_button": "Kter tura"
},
@ -3628,9 +3663,11 @@
"settings_pane_visit_again_header": "Қайтадан шолу",
"settings_pane_visit_again_body": "Firefox сізге есте сақтауды немесе қайта шолуды қалауыңыз мүмкін тарихыңыздың бөліктерін көрсетеді.",
"settings_pane_highlights_header": "Ерекше жаңалықтар",
"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": "Дайын",
"edit_topsites_button_text": "Түзету",
"edit_topsites_button_label": "Топ сайттар санатын баптау",
@ -3653,7 +3690,10 @@
"pocket_read_more": "Әйгілі тақырыптар:",
"pocket_read_even_more": "Көбірек хикаяларды қарау",
"pocket_feedback_header": "Интернеттің ең жақсысы, 25 миллион адаммен танылған.",
"pocket_description": "Ол болмаса, сіз жіберіп алатын мүмкіндігі бар жоғары сапалы құраманы Pocket көмегімен табыңыз, ол енді Mozilla-ның бөлігі болып табылады.",
"highlights_empty_state": "Шолуды бастаңыз, сіз жақында шолған немесе бетбелгілерге қосқан тамаша мақалалар, видеолар немесе басқа парақтардың кейбіреулері осында көрсетіледі.",
"topstories_empty_state": "Дайын. {provider} ұсынған көбірек мақалаларды алу үшін кейінірек тексеріңіз. Күте алмайсыз ба? Интернеттен көбірек тамаша мақалаларды алу үшін әйгілі теманы таңдаңыз.",
"manual_migration_explanation2": "Firefox-ты басқа браузер бетбелгілері, тарихы және парольдерімен қолданып көріңіз.",
"manual_migration_cancel_button": "Жоқ, рахмет",
"manual_migration_import_button": "Қазір импорттау"
},
@ -4376,6 +4416,7 @@
"pocket_read_more": "Populære emner:",
"pocket_read_even_more": "Vis flere saker",
"pocket_feedback_header": "Det beste av nettet, kurert av over 25 millioner mennesker.",
"pocket_description": "Oppdag høykvalitetsinnhold som du ellers ville gå glipp av, ved hjelp av Pocket, som nå er en del av Mozilla.",
"highlights_empty_state": "Begynn å surfe, og vi viser noen av de beste artiklene, videoer og andre sider du nylig har besøkt eller bokmerket her.",
"topstories_empty_state": "Du har tatt igjen. Kom tilbake senere for flere topphistorier fra {provider}. Kan du ikke vente? Velg et populært emne for å finne flere gode artikler fra hele Internett.",
"manual_migration_explanation2": "Prøv Firefox med bokmerkene, historikk og passord fra en annen nettleser.",
@ -4991,7 +5032,7 @@
"menu_action_email_link": "Trametter la colliaziun per e-mail…",
"menu_action_open_new_window": "Avrir en ina nova fanestra",
"menu_action_open_private_window": "Avrir en ina nova fanestra privata",
"menu_action_dismiss": "Serrar",
"menu_action_dismiss": "Sbittar",
"menu_action_delete": "Stizzar da la cronologia",
"menu_action_pin": "Fixar",
"menu_action_unpin": "Betg pli fixar",
@ -5371,6 +5412,8 @@
"settings_pane_highlights_body2": "Najdite pot nazaj do zanimivih strani, ki ste jih nedavno obiskali ali dodali med zaznamke.",
"settings_pane_highlights_options_bookmarks": "Zaznamki",
"settings_pane_highlights_options_visited": "Obiskane strani",
"settings_pane_snippets_header": "Izrezki",
"settings_pane_snippets_body": "Spremljajte kratke novice o Mozilli in Firefoxu, kulturi interneta in si občasno oglejte kak meme.",
"settings_pane_done_button": "Končano",
"edit_topsites_button_text": "Uredi",
"edit_topsites_button_label": "Prilagodite odsek Glavne strani",
@ -5384,8 +5427,8 @@
"edit_topsites_add_button": "Dodaj",
"topsites_form_add_header": "Nova glavna stran",
"topsites_form_edit_header": "Uredi glavno stran",
"topsites_form_title_placeholder": "Vnesite naslov",
"topsites_form_url_placeholder": "Vnesite ali prilepite URL",
"topsites_form_title_placeholder": "Vnesite ime",
"topsites_form_url_placeholder": "Vnesite ali prilepite spletni naslov",
"topsites_form_add_button": "Dodaj",
"topsites_form_save_button": "Shrani",
"topsites_form_cancel_button": "Prekliči",
@ -5725,6 +5768,7 @@
"default_label_loading": "వస్తోంది…",
"header_top_sites": "మేటి సైట్లు",
"header_stories": "ముఖ్య కథనాలు",
"header_highlights": "విశేషాలు",
"header_visit_again": "మళ్లీ సందర్శించండి",
"header_bookmarks": "ఇటీవలి ఇష్టాంశములు",
"header_recommended_by": "{provider}చే సిఫార్సు చేయబడినది",
@ -5756,6 +5800,8 @@
"search_web_placeholder": "జాలంలో వెతకండి",
"search_settings": "శోధన అమరికలు మార్చు",
"section_info_option": "సమాచారం",
"section_info_send_feedback": "అభిప్రాయాన్ని పంపండి",
"section_info_privacy_notice": "గోప్యతా విధానం",
"welcome_title": "కొత్త ట్యాబుకు స్వాగతం",
"welcome_body": "సముచితమైన మీ ఇష్టాంశాలను, వ్యాసాలను, వీడియోలను, ఇంకా మీరు ఇటీవలే చూసిన పేజీలను మీకు తేలిగ్గా అందుబాటులో ఉంచేందుకు Firefox ఈ జాగాని వాడుకుంటుంది.",
"welcome_label": "మీ ముఖ్యాంశాలను గుర్తిస్తున్నది",
@ -5765,7 +5811,7 @@
"time_label_day": "{number}రో",
"settings_pane_button_label": "మీ కొత్త ట్యాబు పేజీని మలచుకోండి",
"settings_pane_header": "కొత్త ట్యాబు అభిరుచులు",
"settings_pane_body": "మీరు కొత్త ట్యాబు తెరిచినప్పుడు ఏం చూడాలో ఎంచుకోండి.",
"settings_pane_body2": "మీరు ఈ పేజీలో చూసేదాన్ని ఎంచుకోండి.",
"settings_pane_search_header": "వెతకడం",
"settings_pane_search_body": "కొత్త ట్యాబు నుండే జాలంలో వెతకండి.",
"settings_pane_topsites_header": "మేటి సైట్లు",
@ -5775,8 +5821,9 @@
"settings_pane_bookmarks_body": "ఒక సులభ స్థానంలో మీ క్రొత్తగా సృష్టించిన బుక్మార్క్లు.",
"settings_pane_visit_again_header": "మళ్లీ సందర్శించండి",
"settings_pane_visit_again_body": "మీరు బ్రౌజింగ్ చరిత్రలో గుర్తుంచుకోవాల్సిన లేదా తిరిగి పొందవలసిన భాగాలను చూపిస్తుంది.",
"settings_pane_pocketstories_header": "ముఖ్య కథనాలు",
"settings_pane_pocketstories_body": "Mozilla కుటుంబం యొక్క Pocket, మీరు కనుగొనలేకపోయే అధిక-నాణ్యత విషయముకి మిమ్మల్ని అనుసంధానించడానికి సహాయపడుతుంది.",
"settings_pane_highlights_header": "విశేషాలు",
"settings_pane_highlights_options_bookmarks": "ఇష్టాంశాలు",
"settings_pane_highlights_options_visited": "చూసిన సైటులు",
"settings_pane_done_button": "పూర్తయింది",
"edit_topsites_button_text": "మార్చు",
"edit_topsites_button_label": "మీ మేటి సైట్ల విభాగాన్ని మలచుకోండి",
@ -5799,10 +5846,7 @@
"pocket_read_more": "ప్రముఖ అంశాలు:",
"pocket_read_even_more": "మరిన్ని కథలను వీక్షించండి",
"pocket_feedback_header": "వెబ్లో అత్యుత్తమమైనది, 25 మిలియన్లకు పైగా ప్రజలు పర్యవేక్షించినవి.",
"pocket_feedback_body": "Mozilla కుటుంబం యొక్క Pocket, మీరు కనుగొనలేకపోయే అధిక-నాణ్యత విషయముకి మిమ్మల్ని అనుసంధానించడానికి సహాయపడుతుంది.",
"pocket_send_feedback": "అభిప్రాయాన్ని పంపండి",
"topstories_empty_state": "మీరు పట్టుబడ్డారు. {provider} నుండి మరింత అగ్ర కథనాల కోసం తరువాత తనిఖీ చేయండి. వేచి ఉండలేరా? జాలములోని అంతటి నుండి మరింత గొప్ప కథనాలను కనుగొనడానికి ప్రసిద్ధ అంశం ఎంచుకోండి.",
"manual_migration_explanation": "మరొక విహరణి నుండి మీకు ఇష్టమైన సైట్లు మరియు ఇష్టంశాలతో Firefox ను ప్రయత్నించండి.",
"manual_migration_cancel_button": "అడిగినందుకు ధన్యవాదాలు, వద్దు",
"manual_migration_import_button": "ఇప్పుడే దిగుమతి చేయండి"
},
@ -5865,6 +5909,7 @@
"settings_pane_visit_again_header": "เยี่ยมชมอีกครั้ง",
"settings_pane_highlights_header": "รายการเด่น",
"settings_pane_highlights_options_bookmarks": "ที่คั่นหน้า",
"settings_pane_highlights_options_visited": "ไซต์ที่เยี่ยมชมแล้ว",
"settings_pane_done_button": "เสร็จสิ้น",
"edit_topsites_button_text": "แก้ไข",
"edit_topsites_button_label": "ปรับแต่งส่วนไซต์เด่นของคุณ",
@ -5887,6 +5932,7 @@
"pocket_read_more": "หัวข้อยอดนิยม:",
"pocket_read_even_more": "ดูเรื่องราวเพิ่มเติม",
"pocket_feedback_header": "ที่สุดของเว็บ จัดรายการโดยผู้คนกว่า 25 ล้านคน",
"manual_migration_explanation2": "ลอง Firefox ด้วยที่คั่นหน้า, ประวัติ และรหัสผ่านจากเบราว์เซอร์อื่น",
"manual_migration_cancel_button": "ไม่ ขอบคุณ",
"manual_migration_import_button": "นำเข้าตอนนี้"
},
@ -6294,8 +6340,8 @@
"menu_action_remove_bookmark": "移除书签",
"menu_action_copy_address": "复制地址",
"menu_action_email_link": "用邮件发送链接…",
"menu_action_open_new_window": "新窗口打开",
"menu_action_open_private_window": "在新的隐私窗口中打开",
"menu_action_open_new_window": "窗口打开",
"menu_action_open_private_window": "新建隐私浏览窗口打开",
"menu_action_dismiss": "隐藏",
"menu_action_delete": "从历史记录中删除",
"menu_action_pin": "固定",

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

@ -8,7 +8,7 @@
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:unpack>false</em:unpack>
<em:version>2017.09.08.0882-3dbf720c</em:version>
<em:version>2017.09.11.1306-373d9fc</em:version>
<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:multiprocessCompatible>true</em:multiprocessCompatible>

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

@ -77,6 +77,10 @@ const PREFS_CONFIG = new Map([
title: "Number of days to show the manual migration message",
value: 4
}],
["prerender", {
title: "Use the prerendered version of activity-stream.html. This is set automatically by PrefsFeed.jsm.",
value: true
}],
["showSearch", {
title: "Show the Search bar on the New Tab page",
value: true

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

@ -10,6 +10,7 @@ const {actionTypes: at} = Cu.import("resource://activity-stream/common/Actions.j
const {shortURL} = Cu.import("resource://activity-stream/lib/ShortURL.jsm", {});
const {SectionsManager} = Cu.import("resource://activity-stream/lib/SectionsManager.jsm", {});
const {TOP_SITES_SHOWMORE_LENGTH} = Cu.import("resource://activity-stream/common/Reducers.jsm", {});
const {Dedupe} = Cu.import("resource://activity-stream/common/Dedupe.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
@ -17,6 +18,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
const HIGHLIGHTS_MAX_LENGTH = 9;
const HIGHLIGHTS_UPDATE_TIME = 15 * 60 * 1000; // 15 minutes
const MANY_EXTRA_LENGTH = HIGHLIGHTS_MAX_LENGTH * 5 + TOP_SITES_SHOWMORE_LENGTH;
const SECTION_ID = "highlights";
this.HighlightsFeed = class HighlightsFeed {
@ -43,18 +45,39 @@ this.HighlightsFeed = class HighlightsFeed {
}
async fetchHighlights(broadcast = false) {
this.highlights = await NewTabUtils.activityStreamLinks.getHighlights();
for (let highlight of this.highlights) {
highlight.hostname = shortURL(Object.assign({}, highlight, {url: highlight.url}));
highlight.image = highlight.preview_image_url;
if (highlight.bookmarkGuid) {
highlight.type = "bookmark";
}
}
// Request more than the expected length to allow for items being removed by
// deduping against Top Sites or multiple history from the same domain, etc.
const manyPages = await NewTabUtils.activityStreamLinks.getHighlights({numItems: MANY_EXTRA_LENGTH});
// Remove any Highlights that are in Top Sites already
const deduped = this.dedupe.group(this.store.getState().TopSites.rows, this.highlights);
this.highlights = deduped[1];
const deduped = this.dedupe.group(this.store.getState().TopSites.rows, manyPages)[1];
// Keep all "bookmark"s and at most one (most recent) "history" per host
this.highlights = [];
const hosts = new Set();
for (const page of deduped) {
const hostname = shortURL(page);
// Skip this history page if we already something from the same host
if (page.type === "history" && hosts.has(hostname)) {
continue;
}
// We want the page, so update various fields for UI
Object.assign(page, {
hostname,
image: page.preview_image_url,
type: page.bookmarkGuid ? "bookmark" : page.type
});
// Add the "bookmark" or not-skipped "history"
this.highlights.push(page);
hosts.add(hostname);
// Skip the rest if we have enough items
if (this.highlights.length === HIGHLIGHTS_MAX_LENGTH) {
break;
}
}
SectionsManager.updateSection(SECTION_ID, {rows: this.highlights}, this.highlightsLastUpdated === 0 || broadcast);
this.highlightsLastUpdated = Date.now();

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

@ -12,12 +12,30 @@ const {actionCreators: ac, actionTypes: at} = Cu.import("resource://activity-str
* newly opened tabs.
*/
this.NewTabInit = class NewTabInit {
constructor() {
this._queue = new Set();
}
reply(target) {
const action = {type: at.NEW_TAB_INITIAL_STATE, data: this.store.getState()};
this.store.dispatch(ac.SendToContent(action, target));
}
onAction(action) {
let newAction;
switch (action.type) {
case at.NEW_TAB_LOAD:
newAction = {type: at.NEW_TAB_INITIAL_STATE, data: this.store.getState()};
this.store.dispatch(ac.SendToContent(newAction, action.meta.fromTarget));
case at.NEW_TAB_STATE_REQUEST:
// If localization hasn't been loaded yet, we should wait for it.
if (!this.store.getState().App.strings) {
this._queue.add(action.meta.fromTarget);
return;
}
this.reply(action.meta.fromTarget);
break;
case at.LOCALE_UPDATED:
// If the queue is full because we were waiting for strings,
// dispatch them now.
if (this._queue.size > 0 && this.store.getState().App.strings) {
this._queue.forEach(target => this.reply(target));
this._queue.clear();
}
break;
}
}

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

@ -7,17 +7,39 @@ const {utils: Cu} = Components;
const {actionCreators: ac, actionTypes: at} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
const {Prefs} = Cu.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm", {});
const {PrerenderData} = Cu.import("resource://activity-stream/common/PrerenderData.jsm", {});
this.PrefsFeed = class PrefsFeed {
constructor(prefMap) {
this._prefMap = prefMap;
this._prefs = new Prefs();
}
// If the any prefs are set to something other than what the prerendered version
// of AS expects, we can't use it.
_setPrerenderPref() {
for (const prefName of PrerenderData.invalidatingPrefs) {
if (this._prefs.get(prefName) !== PrerenderData.initialPrefs[prefName]) {
this._prefs.set("prerender", false);
return;
}
}
this._prefs.set("prerender", true);
}
_checkPrerender(name) {
if (PrerenderData.invalidatingPrefs.includes(name)) {
this._setPrerenderPref();
}
}
onPrefChanged(name, value) {
if (this._prefMap.has(name)) {
this.store.dispatch(ac.BroadcastToContent({type: at.PREF_CHANGED, data: {name, value}}));
}
this._checkPrerender(name, value);
}
init() {
this._prefs.observeBranch(this);
@ -29,6 +51,8 @@ this.PrefsFeed = class PrefsFeed {
// Set the initial state of all prefs in redux
this.store.dispatch(ac.BroadcastToContent({type: at.PREFS_INITIAL_VALUES, data: values}));
this._setPrerenderPref();
}
removeListeners() {
this._prefs.ignoreBranch(this);

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

@ -48,7 +48,7 @@ const BUILT_IN_SECTIONS = {
icon: "highlights",
title: {id: "header_highlights"},
maxRows: 3,
availableContextMenuOptions: ["CheckBookmark", "SaveToPocket", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl"],
availableContextMenuOptions: ["CheckBookmark", "SaveToPocket", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl", "DeleteUrl"],
emptyState: {
message: {id: "highlights_empty_state"},
icon: "highlights"

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

@ -121,7 +121,7 @@ this.SnippetsFeed = class SnippetsFeed {
Services.prefs.removeObserver(TELEMETRY_PREF, this._refresh);
Services.prefs.removeObserver(FXA_USERNAME_PREF, this._refresh);
Services.obs.removeObserver(this, SEARCH_ENGINE_OBSERVER_TOPIC);
this.store.dispatch({type: at.SNIPPETS_RESET});
this.store.dispatch(ac.BroadcastToContent({type: at.SNIPPETS_RESET}));
}
showFirefoxAccounts(browser) {

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

@ -21,6 +21,7 @@ const UPDATE_TIME = 15 * 60 * 1000; // 15 minutes
const DEFAULT_SITES_PREF = "default.sites";
const DEFAULT_TOP_SITES = [];
const FRECENCY_THRESHOLD = 100; // 1 visit (skip first-run/one-time pages)
const MIN_FAVICON_SIZE = 96;
this.TopSitesFeed = class TopSitesFeed {
constructor() {
@ -95,13 +96,13 @@ this.TopSitesFeed = class TopSitesFeed {
}
}
// Now, get a tippy top icon or screenshot for every item
// Now, get a tippy top icon, a rich icon, or screenshot for every item
for (let link of links) {
if (!link) { continue; }
// Check for tippy top icon.
// Check for tippy top icon or a rich icon.
link = this._tippyTopProvider.processSite(link);
if (link.tippyTopIcon) { continue; }
if (link.tippyTopIcon || link.faviconSize >= MIN_FAVICON_SIZE) { continue; }
// If no tippy top, then we get a screenshot.
if (currentScreenshots[link.url]) {

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

@ -0,0 +1,70 @@
const prerender = require("content-src/activity-stream-prerender");
const {prerenderStore} = prerender;
const {PrerenderData} = require("common/PrerenderData.jsm");
describe("prerenderStore", () => {
it("should create a store", () => {
const store = prerenderStore();
assert.isFunction(store.getState);
});
it("should start uninitialized", () => {
const store = prerenderStore();
const state = store.getState();
assert.equal(state.App.initialized, false);
});
it("should set the right locale, strings, and text direction", () => {
const strings = {foo: "foo"};
const store = prerenderStore("en-FOO", strings);
const state = store.getState();
assert.equal(state.App.locale, "en-FOO");
assert.equal(state.App.strings, strings);
assert.equal(state.App.textDirection, "ltr");
});
it("should add the right initial prefs", () => {
const store = prerenderStore();
const state = store.getState();
assert.equal(state.Prefs.values, PrerenderData.initialPrefs);
});
it("should add TopStories as the first section", () => {
const store = prerenderStore();
const state = store.getState();
// TopStories
const firstSection = state.Sections[0];
assert.equal(firstSection.id, "topstories");
// it should start uninitialized
assert.equal(firstSection.initialized, false);
});
});
describe("prerender", () => {
it("should set the locale and get the right strings of whatever is passed in", () => {
const {store} = prerender("en-US");
const state = store.getState();
assert.equal(state.App.locale, "en-US");
assert.equal(state.App.strings.newtab_page_title, "New Tab");
});
it("should throw if an unknown locale is passed in", () => {
assert.throws(() => prerender("en-FOO"));
});
it("should set the locale to en-PRERENDER and have empty strings if no locale is passed in", () => {
const {store} = prerender();
const state = store.getState();
assert.equal(state.App.locale, "en-PRERENDER");
assert.equal(state.App.strings.newtab_page_title, " ");
});
// # TODO: Remove when #3370 is resolved.
it("should render a real English string for search_web_placeholder", () => {
const {store} = prerender();
const state = store.getState();
assert.equal(state.App.strings.search_web_placeholder, "Search the Web");
});
});

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

@ -26,12 +26,20 @@ describe("Reducers", () => {
const nextState = App(undefined, {type: at.LOCALE_UPDATED});
assert.equal(nextState, INITIAL_STATE.App);
});
it("should set locale, strings on LOCALE_UPDATE", () => {
it("should set locale, strings and text direction on LOCALE_UPDATE", () => {
const strings = {};
const action = {type: "LOCALE_UPDATED", data: {locale: "zh-CN", strings}};
const nextState = App(undefined, action);
assert.propertyVal(nextState, "locale", "zh-CN");
assert.propertyVal(nextState, "strings", strings);
assert.propertyVal(nextState, "textDirection", "ltr");
});
it("should set rtl text direction for RTL locales", () => {
const action = {type: "LOCALE_UPDATED", data: {locale: "ar"}};
const nextState = App(undefined, action);
assert.propertyVal(nextState, "textDirection", "rtl");
});
});
describe("TopSites", () => {

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

@ -30,7 +30,7 @@ describe("Top Sites Feed", () => {
updateSection: sinon.spy(),
sections: new Map([["highlights", {}]])
};
shortURLStub = sinon.stub().callsFake(site => site.url);
shortURLStub = sinon.stub().callsFake(site => site.url.match(/\/([^/]+)/)[1]);
globals.set("NewTabUtils", fakeNewTabUtils);
({HighlightsFeed, HIGHLIGHTS_UPDATE_TIME, SECTION_ID} = injector({
"lib/ShortURL.jsm": {shortURL: shortURLStub},
@ -72,7 +72,7 @@ describe("Top Sites Feed", () => {
it("should add hostname and image to each link", async () => {
links = [{url: "https://mozilla.org", preview_image_url: "https://mozilla.org/preview.jog"}];
await feed.fetchHighlights();
assert.equal(feed.highlights[0].hostname, links[0].url);
assert.equal(feed.highlights[0].hostname, "mozilla.org");
assert.equal(feed.highlights[0].image, links[0].preview_image_url);
});
it("should not include any links already in Top Sites", async () => {
@ -86,6 +86,30 @@ describe("Top Sites Feed", () => {
assert.equal(feed.highlights.length, 1);
assert.deepEqual(feed.highlights[0], links[0]);
});
it("should not include history of same hostname as a bookmark", async () => {
links = [
{url: "https://site.com/bookmark", type: "bookmark"},
{url: "https://site.com/history", type: "history"}
];
await feed.fetchHighlights();
assert.equal(feed.highlights.length, 1);
assert.deepEqual(feed.highlights[0], links[0]);
});
it("should take the first history of a hostname", async () => {
links = [
{url: "https://site.com/first", type: "history"},
{url: "https://site.com/second", type: "history"},
{url: "https://other", type: "history"}
];
await feed.fetchHighlights();
assert.equal(feed.highlights.length, 2);
assert.deepEqual(feed.highlights[0], links[0]);
assert.deepEqual(feed.highlights[1], links[2]);
});
it("should set type to bookmark if there is a bookmarkGuid", async () => {
links = [{url: "https://mozilla.org", type: "history", bookmarkGuid: "1234567890"}];
await feed.fetchHighlights();

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

@ -0,0 +1,62 @@
const {NewTabInit} = require("lib/NewTabInit.jsm");
const {actionTypes: at, actionCreators: ac} = require("common/Actions.jsm");
describe("NewTabInit", () => {
let instance;
let store;
let STATE;
beforeEach(() => {
STATE = {};
store = {getState: sinon.stub().returns(STATE), dispatch: sinon.stub()};
instance = new NewTabInit();
instance.store = store;
});
it("should reply with a copy of the state immediately if localization is ready", () => {
STATE.App = {strings: {}};
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, 123));
const resp = ac.SendToContent({type: at.NEW_TAB_INITIAL_STATE, data: STATE}, 123);
assert.calledWith(store.dispatch, resp);
});
it("should not reply immediately if localization is not ready", () => {
STATE.App = {strings: null};
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, 123));
assert.notCalled(store.dispatch);
});
it("should dispatch responses for queued targets when LOCALE_UPDATED is received", () => {
STATE.App = {strings: null};
// Send requests before strings are ready
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "foo"));
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "bar"));
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "baz"));
assert.notCalled(store.dispatch);
// Update strings
STATE.App = {strings: {}};
instance.onAction({type: at.LOCALE_UPDATED});
assert.calledThrice(store.dispatch);
const action = {type: at.NEW_TAB_INITIAL_STATE, data: STATE};
assert.calledWith(store.dispatch, ac.SendToContent(action, "foo"));
assert.calledWith(store.dispatch, ac.SendToContent(action, "bar"));
assert.calledWith(store.dispatch, ac.SendToContent(action, "baz"));
});
it("should clear targets from the queue once they have been sent", () => {
STATE.App = {strings: null};
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "foo"));
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "bar"));
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "baz"));
STATE.App = {strings: {}};
instance.onAction({type: at.LOCALE_UPDATED});
assert.calledThrice(store.dispatch);
store.dispatch.reset();
instance.onAction({type: at.LOCALE_UPDATED});
assert.notCalled(store.dispatch);
});
});

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

@ -1,16 +1,20 @@
const {PrefsFeed} = require("lib/PrefsFeed.jsm");
const {actionTypes: at, actionCreators: ac} = require("common/Actions.jsm");
const {PrerenderData} = require("common/PrerenderData.jsm");
const {initialPrefs} = PrerenderData;
const FAKE_PREFS = new Map([["foo", {value: 1}], ["bar", {value: 2}]]);
const PRERENDER_PREF_NAME = "prerender";
describe("PrefsFeed", () => {
let feed;
let FAKE_PREFS;
beforeEach(() => {
FAKE_PREFS = new Map([["foo", 1], ["bar", 2]]);
feed = new PrefsFeed(FAKE_PREFS);
feed.store = {dispatch: sinon.spy()};
feed._prefs = {
get: sinon.spy(item => FAKE_PREFS.get(item).value),
set: sinon.spy(),
get: sinon.spy(item => FAKE_PREFS.get(item)),
set: sinon.spy((name, value) => FAKE_PREFS.set(name, value)),
observe: sinon.spy(),
observeBranch: sinon.spy(),
ignore: sinon.spy(),
@ -41,4 +45,42 @@ describe("PrefsFeed", () => {
feed.onPrefChanged("foo", 2);
assert.calledWith(feed.store.dispatch, ac.BroadcastToContent({type: at.PREF_CHANGED, data: {name: "foo", value: 2}}));
});
describe("INIT prerendering", () => {
it("should set a prerender pref on init", () => {
feed.onAction({type: at.INIT});
assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME);
});
it("should set prerender pref to true if prefs match initial values", () => {
Object.keys(initialPrefs).forEach(name => FAKE_PREFS.set(name, initialPrefs[name]));
feed.onAction({type: at.INIT});
assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME, true);
});
it("should set prerender pref to false if a pref does not match its initial value", () => {
Object.keys(initialPrefs).forEach(name => FAKE_PREFS.set(name, initialPrefs[name]));
FAKE_PREFS.set("feeds.section.topstories", false);
feed.onAction({type: at.INIT});
assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME, false);
});
});
describe("onPrefChanged prerendering", () => {
it("should not change the prerender pref if the pref is not included in invalidatingPrefs", () => {
feed.onPrefChanged("foo123", true);
assert.notCalled(feed._prefs.set);
});
it("should set the prerender pref to false if a pref in invalidatingPrefs is changed from its original value", () => {
Object.keys(initialPrefs).forEach(name => FAKE_PREFS.set(name, initialPrefs[name]));
feed._prefs.set("feeds.section.topstories", false);
feed.onPrefChanged("feeds.section.topstories", false);
assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME, false);
});
it("should set the prerender pref back to true if the invalidatingPrefs are changed back to their original values", () => {
Object.keys(initialPrefs).forEach(name => FAKE_PREFS.set(name, initialPrefs[name]));
FAKE_PREFS.set("feeds.section.topstories", false);
feed._prefs.set("feeds.section.topstories", true);
feed.onPrefChanged("feeds.section.topstories", true);
assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME, true);
});
});
});

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

@ -1,5 +1,5 @@
const {SnippetsFeed} = require("lib/SnippetsFeed.jsm");
const {actionTypes: at} = require("common/Actions.jsm");
const {actionCreators: ac, actionTypes: at} = require("common/Actions.jsm");
const {GlobalOverrider} = require("test/unit/utils");
const WEEK_IN_MS = 7 * 24 * 60 * 60 * 1000;
@ -78,13 +78,13 @@ describe("SnippetsFeed", () => {
feed.onAction({type: at.UNINIT});
assert.calledOnce(feed.uninit);
});
it("should dispatch a SNIPPETS_RESET on uninit", () => {
it("should broadcast a SNIPPETS_RESET on uninit", () => {
const feed = new SnippetsFeed();
feed.store = {dispatch: sandbox.stub()};
feed.uninit();
assert.calledWith(feed.store.dispatch, {type: at.SNIPPETS_RESET});
assert.calledWith(feed.store.dispatch, ac.BroadcastToContent({type: at.SNIPPETS_RESET}));
});
it("should dispatch an update event when the Search observer is called", async () => {
const feed = new SnippetsFeed();

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

@ -295,6 +295,22 @@ describe("Top Sites Feed", () => {
assert.calledOnce(feed.store.dispatch);
assert.notCalled(feed.getScreenshot);
});
it("should skip getting screenshot if there is an icon of size greater than 96x96 and no tippy top", async () => {
sandbox.stub(feed, "getScreenshot");
feed.getLinksWithDefaults = () => [{
url: "foo.com",
favicon: "data:foo",
faviconSize: 196
}];
feed._tippyTopProvider.processSite = site => {
site.tippyTopIcon = null;
site.backgroundColor = null;
return site;
};
await feed.refresh(action);
assert.calledOnce(feed.store.dispatch);
assert.notCalled(feed.getScreenshot);
});
});
describe("getScreenshot", () => {
it("should call Screenshots.getScreenshotForURL with the right url", async () => {

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

@ -1,6 +1,7 @@
const initStore = require("content-src/lib/init-store");
const {MERGE_STORE_ACTION, rehydrationMiddleware} = initStore;
const {GlobalOverrider, addNumberReducer} = require("test/unit/utils");
const {actionCreators: ac} = require("common/Actions.jsm");
const {actionCreators: ac, actionTypes: at} = require("common/Actions.jsm");
describe("initStore", () => {
let globals;
@ -16,20 +17,33 @@ describe("initStore", () => {
assert.ok(store);
assert.property(store.getState(), "number");
});
it("should add a listener for incoming actions", () => {
it("should add a listener that dispatches actions", () => {
assert.calledWith(global.addMessageListener, initStore.INCOMING_MESSAGE_NAME);
const callback = global.addMessageListener.firstCall.args[1];
const listener = global.addMessageListener.firstCall.args[1];
globals.sandbox.spy(store, "dispatch");
const message = {name: initStore.INCOMING_MESSAGE_NAME, data: {type: "FOO"}};
callback(message);
listener(message);
assert.calledWith(store.dispatch, message.data);
});
it("should not throw if addMessageListener is not defined", () => {
// Note: this is being set/restored by GlobalOverrider
delete global.addMessageListener;
assert.doesNotThrow(() => initStore({number: addNumberReducer}));
});
it("should initialize with an initial state if provided as the second argument", () => {
store = initStore({number: addNumberReducer}, {number: 42});
assert.equal(store.getState().number, 42);
});
it("should log errors from failed messages", () => {
const callback = global.addMessageListener.firstCall.args[1];
globals.sandbox.stub(global.console, "error");
globals.sandbox.stub(store, "dispatch").throws(Error("failed"));
const message = {name: initStore.INCOMING_MESSAGE_NAME, data: {type: "FOO"}};
const message = {name: initStore.INCOMING_MESSAGE_NAME, data: {type: MERGE_STORE_ACTION}};
callback(message);
assert.calledOnce(global.console.error);
@ -38,13 +52,60 @@ describe("initStore", () => {
store.dispatch({type: initStore.MERGE_STORE_ACTION, data: {number: 42}});
assert.deepEqual(store.getState(), {number: 42});
});
it("should send out SendToMain ations", () => {
it("should send out SendToMain actions", () => {
const action = ac.SendToMain({type: "FOO"});
store.dispatch(action);
assert.calledWith(global.sendAsyncMessage, initStore.OUTGOING_MESSAGE_NAME, action);
});
it("should not send out other types of ations", () => {
it("should not send out other types of actions", () => {
store.dispatch({type: "FOO"});
assert.notCalled(global.sendAsyncMessage);
});
describe("rehydrationMiddleware", () => {
it("should allow NEW_TAB_STATE_REQUEST to go through", () => {
const action = ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST});
const next = sinon.spy();
rehydrationMiddleware(store)(next)(action);
assert.calledWith(next, action);
});
it("should dispatch an additional NEW_TAB_STATE_REQUEST if INIT was received after a request", () => {
const requestAction = ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST});
const next = sinon.spy();
rehydrationMiddleware(store)(next)(requestAction);
next.reset();
rehydrationMiddleware(store)(next)({type: at.INIT});
assert.calledWith(next, requestAction);
});
it("should allow MERGE_STORE_ACTION to go through", () => {
const action = {type: MERGE_STORE_ACTION};
const next = sinon.spy();
rehydrationMiddleware(store)(next)(action);
assert.calledWith(next, action);
});
it("should not allow actions from main to go through before MERGE_STORE_ACTION was received", () => {
const next = sinon.spy();
rehydrationMiddleware(store)(next)(ac.BroadcastToContent({type: "FOO"}));
rehydrationMiddleware(store)(next)(ac.SendToContent({type: "FOO"}, 123));
assert.notCalled(next);
});
it("should allow all local actions to go through", () => {
const action = {type: "FOO"};
const next = sinon.spy();
rehydrationMiddleware(store)(next)(action);
assert.calledWith(next, action);
});
it("should allow actions from main to go through after MERGE_STORE_ACTION has been received", () => {
const next = sinon.spy();
rehydrationMiddleware(store)(next)({type: MERGE_STORE_ACTION});
next.reset();
const action = ac.SendToContent({type: "FOO"}, 123);
rehydrationMiddleware(store)(next)(action);
assert.calledWith(next, action);
});
});
});

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

@ -17,7 +17,7 @@
</fieldset>
<div id="controls-container">
<button id="remove" disabled="disabled" data-localization="remove"/>
<button id="show-credit-cards" data-localization="showCreditCards"/>
<button id="show-hide-credit-cards" data-localization="showCreditCards"/>
<button id="add" data-localization="add"/>
<button id="edit" disabled="disabled" data-localization="edit"/>
</div>
@ -28,7 +28,7 @@
records: document.getElementById("credit-cards"),
controlsContainer: document.getElementById("controls-container"),
remove: document.getElementById("remove"),
showCreditCards: document.getElementById("show-credit-cards"),
showHideCreditCards: document.getElementById("show-hide-credit-cards"),
add: document.getElementById("add"),
edit: document.getElementById("edit"),
});

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

@ -28,7 +28,6 @@ class ManageRecords {
this._storageInitPromise = profileStorage.initialize();
this._subStorageName = subStorageName;
this._elements = elements;
this._records = [];
this._newRequest = false;
this._isLoadingRecords = false;
this.prefWin = window.opener;
@ -152,6 +151,7 @@ class ManageRecords {
storage.remove(option.value);
option.remove();
}
this.updateButtonsStates(this._selectedOptions);
// Resume listening to storage change event
Services.obs.addObserver(this, "formautofill-storage-changed");
@ -327,9 +327,10 @@ class ManageAddresses extends ManageRecords {
class ManageCreditCards extends ManageRecords {
constructor(elements) {
super("creditCards", elements);
this.hasMasterPassword = MasterPassword.isEnabled;
if (this.hasMasterPassword) {
elements.showCreditCards.setAttribute("hidden", true);
this._hasMasterPassword = MasterPassword.isEnabled;
this._isDecrypted = false;
if (this._hasMasterPassword) {
elements.showHideCreditCards.setAttribute("hidden", true);
}
}
@ -341,7 +342,7 @@ class ManageCreditCards extends ManageRecords {
async openEditDialog(creditCard) {
// If master password is set, ask for password if user is trying to edit an
// existing credit card.
if (!this.hasMasterPassword || !creditCard || await MasterPassword.prompt()) {
if (!this._hasMasterPassword || !creditCard || await MasterPassword.prompt()) {
this.prefWin.gSubDialog.open(EDIT_CREDIT_CARD_URL, null, creditCard);
}
}
@ -373,17 +374,45 @@ class ManageCreditCards extends ManageRecords {
return parts.join(", ");
}
async decryptOptions(options) {
async toggleShowHideCards(options) {
this._isDecrypted = !this._isDecrypted;
this.updateShowHideButtonState();
await this.updateLabels(options, this._isDecrypted);
}
async updateLabels(options, isDecrypted) {
for (let option of options) {
option.text = await this.getLabel(option.record, true);
option.text = await this.getLabel(option.record, isDecrypted);
}
// For testing only: Notify when credit cards have been decrypted
this._elements.records.dispatchEvent(new CustomEvent("OptionsDecrypted"));
// For testing only: Notify when credit cards labels have been updated
this._elements.records.dispatchEvent(new CustomEvent("LabelsUpdated"));
}
async renderRecordElements(records) {
// Revert back to encrypted form when re-rendering happens
this._isDecrypted = false;
await super.renderRecordElements(records);
}
updateButtonsStates(selectedCount) {
this.updateShowHideButtonState();
super.updateButtonsStates(selectedCount);
}
updateShowHideButtonState() {
if (this._elements.records.length) {
this._elements.showHideCreditCards.removeAttribute("disabled");
} else {
this._elements.showHideCreditCards.setAttribute("disabled", true);
}
this._elements.showHideCreditCards.textContent =
this._isDecrypted ? FormAutofillUtils.stringBundle.GetStringFromName("hideCreditCards") :
FormAutofillUtils.stringBundle.GetStringFromName("showCreditCards");
}
handleClick(event) {
if (event.target == this._elements.showCreditCards) {
this.decryptOptions(this._elements.records.options);
if (event.target == this._elements.showHideCreditCards) {
this.toggleShowHideCards(this._elements.records.options);
}
super.handleClick(event);
}

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

@ -46,6 +46,7 @@ manageCreditCardsTitle = Saved Credit Cards
addressesListHeader = Addresses
creditCardsListHeader = Credit Cards
showCreditCards = Show Credit Cards
hideCreditCards = Hide Credit Cards
remove = Remove
add = Add…
edit = Edit…

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

@ -5,7 +5,7 @@ Cu.import("resource://testing-common/LoginTestUtils.jsm", this);
const TEST_SELECTORS = {
selRecords: "#credit-cards",
btnRemove: "#remove",
btnShowCreditCards: "#show-credit-cards",
btnShowHideCreditCards: "#show-hide-credit-cards",
btnAdd: "#add",
btnEdit: "#edit",
};
@ -17,13 +17,13 @@ add_task(async function test_manageCreditCardsInitialState() {
await ContentTask.spawn(browser, TEST_SELECTORS, (args) => {
let selRecords = content.document.querySelector(args.selRecords);
let btnRemove = content.document.querySelector(args.btnRemove);
let btnShowCreditCards = content.document.querySelector(args.btnShowCreditCards);
let btnShowHideCreditCards = content.document.querySelector(args.btnShowHideCreditCards);
let btnAdd = content.document.querySelector(args.btnAdd);
let btnEdit = content.document.querySelector(args.btnEdit);
is(selRecords.length, 0, "No credit card");
is(btnRemove.disabled, true, "Remove button disabled");
is(btnShowCreditCards.disabled, false, "Show Credit Cards button disabled");
is(btnShowHideCreditCards.disabled, true, "Show Credit Cards button disabled");
is(btnAdd.disabled, false, "Add button enabled");
is(btnEdit.disabled, true, "Edit button disabled");
});
@ -104,18 +104,44 @@ add_task(async function test_showCreditCards() {
await BrowserTestUtils.waitForEvent(win, "FormReady");
let selRecords = win.document.querySelector(TEST_SELECTORS.selRecords);
let btnShowCreditCards = win.document.querySelector(TEST_SELECTORS.btnShowCreditCards);
let btnShowHideCreditCards = win.document.querySelector(TEST_SELECTORS.btnShowHideCreditCards);
EventUtils.synthesizeMouseAtCenter(btnShowCreditCards, {}, win);
await BrowserTestUtils.waitForEvent(selRecords, "OptionsDecrypted");
is(btnShowHideCreditCards.disabled, false, "Show credit cards button enabled");
is(btnShowHideCreditCards.textContent, "Show Credit Cards", "Label should be 'Show Credit Cards'");
// Show credit card numbers
EventUtils.synthesizeMouseAtCenter(btnShowHideCreditCards, {}, win);
await BrowserTestUtils.waitForEvent(selRecords, "LabelsUpdated");
is(selRecords[0].text, "9999888877776666", "Decrypted credit card 3");
is(selRecords[1].text, "1111222233334444, Timothy Berners-Lee", "Decrypted credit card 2");
is(selRecords[2].text, "1234567812345678, John Doe", "Decrypted credit card 1");
is(btnShowHideCreditCards.textContent, "Hide Credit Cards", "Label should be 'Hide Credit Cards'");
// Hide credit card numbers
EventUtils.synthesizeMouseAtCenter(btnShowHideCreditCards, {}, win);
await BrowserTestUtils.waitForEvent(selRecords, "LabelsUpdated");
is(selRecords[0].text, "**** 6666", "Masked credit card 3");
is(selRecords[1].text, "**** 4444, Timothy Berners-Lee", "Masked credit card 2");
is(selRecords[2].text, "**** 5678, John Doe", "Masked credit card 1");
is(btnShowHideCreditCards.textContent, "Show Credit Cards", "Label should be 'Show Credit Cards'");
// Show credit card numbers again to test if they revert back to masked form when reloaded
EventUtils.synthesizeMouseAtCenter(btnShowHideCreditCards, {}, win);
await BrowserTestUtils.waitForEvent(selRecords, "LabelsUpdated");
// Ensure credit card numbers are shown again
is(selRecords[0].text, "9999888877776666", "Decrypted credit card 3");
// Remove a card to trigger reloading
await removeCreditCards([selRecords.options[2].value]);
await BrowserTestUtils.waitForEvent(selRecords, "RecordsLoaded");
is(selRecords[0].text, "**** 6666", "Masked credit card 3");
is(selRecords[1].text, "**** 4444, Timothy Berners-Lee", "Masked credit card 2");
// Remove the rest of the cards
await removeCreditCards([selRecords.options[1].value]);
await removeCreditCards([selRecords.options[0].value]);
await BrowserTestUtils.waitForEvent(selRecords, "RecordsLoaded");
is(btnShowHideCreditCards.disabled, true, "Show credit cards button is disabled when there is no card");
win.close();
});
@ -128,12 +154,12 @@ add_task(async function test_hasMasterPassword() {
let selRecords = win.document.querySelector(TEST_SELECTORS.selRecords);
let btnRemove = win.document.querySelector(TEST_SELECTORS.btnRemove);
let btnShowCreditCards = win.document.querySelector(TEST_SELECTORS.btnShowCreditCards);
let btnShowHideCreditCards = win.document.querySelector(TEST_SELECTORS.btnShowHideCreditCards);
let btnAdd = win.document.querySelector(TEST_SELECTORS.btnAdd);
let btnEdit = win.document.querySelector(TEST_SELECTORS.btnEdit);
let masterPasswordDialogShown = waitForMasterPasswordDialog();
is(btnShowCreditCards.hidden, true, "Show credit cards button is hidden");
is(btnShowHideCreditCards.hidden, true, "Show credit cards button is hidden");
// Master password dialog should show when trying to edit a credit card record.
EventUtils.synthesizeMouseAtCenter(selRecords.children[0], {}, win);

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

@ -100,6 +100,7 @@ webextPerms.description.browserSettings=Read and modify browser settings
webextPerms.description.browsingData=Clear recent browsing history, cookies, and related data
webextPerms.description.clipboardRead=Get data from the clipboard
webextPerms.description.clipboardWrite=Input data to the clipboard
webextPerms.description.devtools=Extend developer tools to access your data in open tabs
webextPerms.description.downloads=Download files and read and modify the browsers download history
webextPerms.description.downloads.open=Open files downloaded to your computer
webextPerms.description.find=Read the text of all open tabs

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

@ -57,7 +57,14 @@
display: none;
}
/* NB: these would be margin-inline-start/end if it wasn't for the fact that OS X
/* Making the toolbox position:relative (browser.inc.css) occludes titlebar indicators
* if the toolbox has a background. Fix this by positioning the relevant elements, too: */
#titlebar-secondary-buttonbox {
position: relative;
z-index: 1;
}
/* These would be margin-inline-start/end if it wasn't for the fact that OS X
* doesn't reverse the order of the items in the titlebar in RTL mode. */
.titlebar-placeholder[type="caption-buttons"],
#titlebar-buttonbox {

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

@ -27,9 +27,8 @@
.click-to-play-plugins-notification-button-container {
background-color: var(--arrowpanel-dimmed);
border-top: 1px solid var(--panel-separator-color);
padding: 10px;
margin-top: 5px;
display: flex;
}
.click-to-play-popup-button {
@ -49,6 +48,10 @@
margin: 0;
}
.click-to-play-plugins-notification-main-box {
width: 100%;
}
.messageImage[value="plugin-hidden"] {
list-style-image: url(chrome://browser/skin/notification-icons/plugin.svg);
}

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

@ -1099,6 +1099,9 @@ notification[value="translation"] {
#private-browsing-indicator-titlebar {
display: block;
position: absolute;
/* Need to ensure this gets positioned on top of the position:relative #navigator-toolbox
* in case the dark/light themes give that item a background. */
z-index: 1;
}
#main-window[privatebrowsingmode=temporary][tabsintitlebar] #private-browsing-indicator-titlebar > .private-browsing-indicator {

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

@ -48,8 +48,8 @@ third_party_paths.inputs = [
'/tools/rewriting/ThirdPartyPaths.txt',
]
DISABLE_STL_WRAPPING = True
NO_VISIBILITY_FLAGS = True
DisableStlWrapping()
NoVisibilityFlags()
# libc++ is required to build plugins against clang on OS X.
if CONFIG['HOST_OS_ARCH'] == 'Darwin':

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

@ -45,5 +45,5 @@ SOURCES += [
'TestTrivialCtorDtor.cpp',
]
DISABLE_STL_WRAPPING = True
NO_VISIBILITY_FLAGS = True
DisableStlWrapping()
NoVisibilityFlags()

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

@ -146,6 +146,14 @@ def HostRustLibrary(name, features=None):
if features:
HOST_RUST_LIBRARY_FEATURES = features
@template
def DisableStlWrapping():
COMPILE_FLAGS['STL'] = []
@template
def NoVisibilityFlags():
COMPILE_FLAGS['VISIBILITY'] = []
include('gecko_templates.mozbuild')
include('test_templates.mozbuild')

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

@ -23,4 +23,4 @@ SOURCES += [
NO_PGO = True
NO_VISIBILITY_FLAGS = True
NoVisibilityFlags()

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

@ -18,7 +18,7 @@ FORCE_STATIC_LIB = True
NO_PGO = True
DISABLE_STL_WRAPPING = True
DisableStlWrapping()
DEFINES['MOZ_LIBSTDCXX_VERSION'] = CONFIG['MOZ_LIBSTDCXX_TARGET_VERSION']
HOST_DEFINES['MOZ_LIBSTDCXX_VERSION'] = CONFIG['MOZ_LIBSTDCXX_HOST_VERSION']

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

@ -166,24 +166,20 @@ ifndef MOZ_DEBUG
# Used for generating an optimized build with debugging symbols.
# Used in the Windows nightlies to generate symbols for crash reporting.
ifdef MOZ_DEBUG_SYMBOLS
ifdef HAVE_64BIT_BUILD
OS_LDFLAGS += -DEBUG -OPT:REF,ICF
else
OS_LDFLAGS += -DEBUG -OPT:REF
endif
OS_LDFLAGS += -DEBUG
endif
#
# Handle DMD in optimized builds.
#
ifdef MOZ_DMD
ifdef HAVE_64BIT_BUILD
OS_LDFLAGS = -DEBUG -OPT:REF,ICF
else
OS_LDFLAGS = -DEBUG -OPT:REF
endif
OS_LDFLAGS = -DEBUG
endif # MOZ_DMD
ifdef MOZ_OPTIMIZE
OS_LDFLAGS += -OPT:REF,ICF
endif # MOZ_OPTIMIZE
endif # MOZ_DEBUG
endif # WINNT && !GNU_CC
@ -328,8 +324,8 @@ CXXFLAGS += $(WARNINGS_AS_ERRORS)
CFLAGS += $(WARNINGS_AS_ERRORS)
endif # ALLOW_COMPILER_WARNINGS
COMPILE_CFLAGS = $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CFLAGS) $(_DEPEND_CFLAGS) $(CFLAGS) $(MOZBUILD_CFLAGS) $(MK_COMPILE_DEFINES)
COMPILE_CXXFLAGS = $(if $(DISABLE_STL_WRAPPING),,$(STL_FLAGS)) $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CXXFLAGS) $(_DEPEND_CFLAGS) $(CXXFLAGS) $(MOZBUILD_CXXFLAGS) $(MK_COMPILE_DEFINES)
COMPILE_CFLAGS = $(COMPUTED_CFLAGS) $(DEFINES) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CFLAGS) $(_DEPEND_CFLAGS) $(CFLAGS) $(MOZBUILD_CFLAGS) $(MK_COMPILE_DEFINES)
COMPILE_CXXFLAGS = $(COMPUTED_CXXFLAGS) $(DEFINES) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CXXFLAGS) $(_DEPEND_CFLAGS) $(CXXFLAGS) $(MOZBUILD_CXXFLAGS) $(MK_COMPILE_DEFINES)
COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) $(MOZBUILD_CMFLAGS)
COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) $(MOZBUILD_CMMFLAGS)
ASFLAGS += $(MOZBUILD_ASFLAGS)

2
config/external/ffi/moz.build поставляемый
Просмотреть файл

@ -10,7 +10,7 @@ if CONFIG['MOZ_SYSTEM_FFI']:
OS_LIBS += CONFIG['MOZ_FFI_LIBS']
else:
ALLOW_COMPILER_WARNINGS = True
NO_VISIBILITY_FLAGS = True
NoVisibilityFlags()
CONFIGURE_DEFINE_FILES += [
'../../../js/src/ctypes/libffi/fficonfig.h',

2
config/external/icu/defs.mozbuild поставляемый
Просмотреть файл

@ -33,7 +33,7 @@ if CONFIG['GNU_CXX']:
elif CONFIG['OS_TARGET'] == 'WINNT':
CXXFLAGS += ['-GR']
DISABLE_STL_WRAPPING = True
DisableStlWrapping()
ALLOW_COMPILER_WARNINGS = True
# We allow compiler warnings, but we can at least cut down on spammy

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

@ -10,7 +10,7 @@ with Files('**'):
DIST_INSTALL = False
# For sanity's sake, we compile nsinstall without the wrapped system
# headers, so that we can use it to set up the wrapped system headers.
NO_VISIBILITY_FLAGS = True
NoVisibilityFlags()
CONFIGURE_SUBST_FILES += [
'doxygen.cfg',

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

@ -3,7 +3,7 @@
# 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/.
NO_VISIBILITY_FLAGS = True
NoVisibilityFlags()
EXPORTS += [
'sqlite3.h',

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

@ -11,6 +11,7 @@ const { interfaces: Ci, utils: Cu, results: Cr } = Components;
const DBG_XUL = "chrome://devtools/content/framework/toolbox-process-window.xul";
const CHROME_DEBUGGER_PROFILE_NAME = "chrome_debugger_profile";
const { console } = Cu.import("resource://gre/modules/Console.jsm", {});
const { require, DevToolsLoader } = Cu.import("resource://devtools/shared/Loader.jsm", {});
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
@ -276,6 +277,7 @@ BrowserToolboxProcess.prototype = {
command,
arguments: args,
environmentAppend: true,
stderr: "stdout",
environment: {
// Disable safe mode for the new process in case this was opened via the
// keyboard shortcut.
@ -302,6 +304,8 @@ BrowserToolboxProcess.prototype = {
proc.wait().then(() => this.close());
return proc;
}, err => {
console.log(`Error loading Browser Toolbox: ${command} ${args.join(" ")}`, err);
});
},

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

@ -12,6 +12,7 @@ const SPLITCONSOLE_HEIGHT_PREF = "devtools.toolbox.splitconsoleHeight";
const DISABLE_AUTOHIDE_PREF = "ui.popup.disable_autohide";
const HOST_HISTOGRAM = "DEVTOOLS_TOOLBOX_HOST";
const SCREENSIZE_HISTOGRAM = "DEVTOOLS_SCREEN_RESOLUTION_ENUMERATED_PER_USER";
const CURRENT_THEME_SCALAR = "devtools.current_theme";
const HTML_NS = "http://www.w3.org/1999/xhtml";
var {Ci, Cu, Cc} = require("chrome");
@ -650,6 +651,11 @@ Toolbox.prototype = {
this._telemetry.logOncePerBrowserVersion(SCREENSIZE_HISTOGRAM,
system.getScreenDimensions());
this._telemetry.log(HOST_HISTOGRAM, this._getTelemetryHostId());
// Log current theme. The question we want to answer is:
// "What proportion of users use which themes?"
let currentTheme = Services.prefs.getCharPref("devtools.theme");
this._telemetry.logKeyedScalar(CURRENT_THEME_SCALAR, currentTheme, 1);
},
/**

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

@ -17,6 +17,8 @@ function Telemetry() {
this.toolOpened = this.toolOpened.bind(this);
this.toolClosed = this.toolClosed.bind(this);
this.log = this.log.bind(this);
this.logScalar = this.logScalar.bind(this);
this.logKeyedScalar = this.logKeyedScalar.bind(this);
this.logOncePerBrowserVersion = this.logOncePerBrowserVersion.bind(this);
this.destroy = this.destroy.bind(this);
@ -309,6 +311,36 @@ Telemetry.prototype = {
}
},
/**
* Log a value to a keyed count scalar.
*
* @param {String} scalarId
* Scalar in which the data is to be stored.
* @param {String} key
* The key within the scalar.
* @param value
* Value to store.
*/
logKeyedScalar: function (scalarId, key, value) {
if (!scalarId) {
return;
}
try {
if (isNaN(value)) {
dump(`Warning: An attempt was made to write a non-numeric value ` +
`${value} to the ${scalarId} scalar. Only numeric values are ` +
`allowed.`);
return;
}
Services.telemetry.keyedScalarAdd(scalarId, key, value);
} catch (e) {
dump(`Warning: An attempt was made to write to the ${scalarId} ` +
`scalar, which is not defined in Scalars.yaml\n`);
}
},
/**
* Log a value to a keyed histogram.
*

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

@ -106,10 +106,6 @@ function testPrincipal(principal, wantXrays = true) {
var trapDidRun = false;
var proxy = new Proxy({}, new Proxy({}, {get: (_, trap) => {
return function(_, arg) {
if (trap === "has" && arg === "__exposedProps__") {
// Tolerate this case until bug 1392026 is fixed.
return false;
}
trapDidRun = true;
throw new Error("proxy trap '" + trap + "' was called.");
}

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

@ -186,8 +186,9 @@ AnimationEffectReadOnly::GetComputedTimingAt(
// Determine the 0-based index of the current iteration.
// https://w3c.github.io/web-animations/#current-iteration
result.mCurrentIteration =
IsInfinite(result.mIterations) &&
result.mPhase == ComputedTiming::AnimationPhase::After
(result.mIterations >= UINT64_MAX
&& result.mPhase == ComputedTiming::AnimationPhase::After)
|| overallProgress >= UINT64_MAX
? UINT64_MAX // In GetComputedTimingDictionary(),
// we will convert this into Infinity
: static_cast<uint64_t>(overallProgress);

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

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>
window.onload = function(){
let a = document.documentElement.animate([], {"iterations": 1.7976931348623157e+308, "fill": "both"});
};
</script>
</head>
</html>

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

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>
window.onload = function(){
let a = document.documentElement.animate([], {"iterationStart": 1.7976931348623157e+308, "fill": "both"});
};
</script>
</head>
</html>

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

@ -23,6 +23,8 @@ pref(dom.animations-api.core.enabled,true) load 1330190-2.html
pref(dom.animations-api.core.enabled,true) load 1330513-1.html
pref(dom.animations-api.core.enabled,true) load 1333539-1.html
pref(dom.animations-api.core.enabled,true) load 1333539-2.html
pref(dom.animations-api.core.enabled,true) load 1334582-1.html
pref(dom.animations-api.core.enabled,true) load 1334582-2.html
pref(dom.animations-api.core.enabled,true) load 1334583-1.html
pref(dom.animations-api.core.enabled,true) load 1335998-1.html
pref(dom.animations-api.core.enabled,true) load 1343589-1.html

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

@ -463,7 +463,7 @@ DOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult)
// Try to inherit a style backend.
auto styleBackend = StyleBackendType::None;
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mScriptHandlingObject);
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(scriptHandlingObject);
if (window && window->GetExtantDoc()) {
styleBackend = window->GetExtantDoc()->GetStyleBackendType();
}

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

@ -21,7 +21,6 @@ DEPRECATED_OPERATION(NodeValue)
DEPRECATED_OPERATION(TextContent)
DEPRECATED_OPERATION(EnablePrivilege)
DEPRECATED_OPERATION(DOMExceptionCode)
DEPRECATED_OPERATION(NoExposedProps)
DEPRECATED_OPERATION(MutationEvent)
DEPRECATED_OPERATION(Components)
DEPRECATED_OPERATION(PrefixedVisibilityAPI)

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

@ -105,7 +105,13 @@ function parent_test(finish)
addMessageListener("cpows:from_parent", (msg) => {
let obj = msg.objects.obj;
ok(obj.a == 1, "correct value from parent");
if (is_remote) {
ok(obj.a == undefined, "__exposedProps__ should not work");
} else {
// The same process test is not run as content, so the field can
// be accessed even though __exposedProps__ has been removed.
ok(obj.a == 1, "correct value from parent");
}
// Test that a CPOW reference to a function in the chrome process
// is callable from unprivileged content. Greasemonkey uses this
@ -260,11 +266,11 @@ function lifetime_test(finish)
var obj = {"will_die": {"f": 1}};
let [result] = sendRpcMessage("cpows:lifetime_test_1", {}, {obj: obj});
ok(result == 10, "got sync result");
ok(obj.wont_die.f == 2, "got reverse CPOW");
ok(obj.wont_die.f == undefined, "got reverse CPOW");
obj.will_die = null;
Components.utils.schedulePreciseGC(function() {
addMessageListener("cpows:lifetime_test_3", (msg) => {
ok(obj.wont_die.f == 2, "reverse CPOW still works");
ok(obj.wont_die.f == undefined, "reverse CPOW still works");
finish();
});
sendRpcMessage("cpows:lifetime_test_2");

2
dom/cache/DBSchema.cpp поставляемый
Просмотреть файл

@ -3184,7 +3184,7 @@ nsresult MigrateFrom25To26(mozIStorageConnection* aConn, bool& aRewriteSchema)
));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"UPDATE entries SET response_padding_size = 0 "
"WHERE response_type = 4" // opaque response
));

6
dom/cache/FileUtils.cpp поставляемый
Просмотреть файл

@ -786,8 +786,10 @@ LockedUpdateDirectoryPaddingFile(nsIFile* aBaseDir,
MOZ_DIAGNOSTIC_ASSERT(aDecreaseSize >= 0);
int64_t currentPaddingSize = 0;
nsresult rv = LockedDirectoryPaddingGet(aBaseDir, &currentPaddingSize);
if (NS_WARN_IF(NS_FAILED(rv)) || aTemporaryFileExist) {
nsresult rv = NS_OK;
if (aTemporaryFileExist ||
NS_WARN_IF(NS_FAILED(rv =
LockedDirectoryPaddingGet(aBaseDir, &currentPaddingSize)))) {
// Fail to read padding size from the dir padding file, so try to restore.
if (rv != NS_ERROR_FILE_NOT_FOUND &&
rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {

18
dom/cache/test/xpcshell/head.js поставляемый
Просмотреть файл

@ -19,7 +19,7 @@ var hash = Cc['@mozilla.org/security/hash;1']
.createInstance(Ci.nsICryptoHash);
// Expose Cache and Fetch symbols on the global
Cu.importGlobalProperties(['caches', 'fetch']);
Cu.importGlobalProperties(['caches', 'File', 'fetch']);
// Extract a zip file into the profile
function create_test_profile(zipFileName) {
@ -75,3 +75,19 @@ function create_test_profile(zipFileName) {
zipReader.close();
}
function getCacheDir()
{
let dirService = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties);
let profileDir = dirService.get("ProfD", Ci.nsIFile);
let cacheDir = profileDir.clone();
cacheDir.append("storage");
cacheDir.append("default");
cacheDir.append("chrome");
cacheDir.append("cache");
return cacheDir;
}

65
dom/cache/test/xpcshell/test_padding_error_handle.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,65 @@
/**
* This test is mainly to verify cache actions work as usual even there exists
* an unexpected padding file.
*/
function getTempPaddingFilePath() {
let cacheDir = getCacheDir();
let temporaryPaddingFile = cacheDir.clone();
temporaryPaddingFile.append(".padding-tmp");
return temporaryPaddingFile;
}
function createTempPaddingFile () {
let temporaryPaddingFile = getTempPaddingFilePath();
temporaryPaddingFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0644", 8));
ok(temporaryPaddingFile.exists(),
"Temporary padding file does be created by test");
}
async function run_test() {
do_test_pending();
create_test_profile('schema_25_profile.zip');
let cache = await caches.open("test");
// Step 1: Verify cache.match won't fail when there is a temporary padding
// file
createTempPaddingFile();
let response = await cache.match("https://www.mozilla.org");
ok(!!response, "Upgrade from 25 to 26 do succeed");
// Note: Only cache write actions(e.g. cache.put/add/addAll/delete) will
// remove unexpected temporary padding file when writting an opaque response
// into the file-system. Cache read actions(e.g. cache.keys/match) won't.
let temporaryPaddingFile = getTempPaddingFilePath();
ok(temporaryPaddingFile.exists(),
"Temporary padding file doesn't be removed by cache.match");
// Step 2: Verify cache.put won't fail when there is a temporary padding
// file
await cache.put("https://foo.com", response);
ok(!temporaryPaddingFile.exists(),
"Temporary padding file does be removed by cache.put");
// Step 3: Verify cache.keys won't fail when there is a temporary padding
// file
createTempPaddingFile();
let cacheEntries = await cache.keys("https://foo.com");
ok(cacheEntries.length === 1, "Cache.put does succeed");
ok(temporaryPaddingFile.exists(),
"Temporary padding file doesn't be removed by cache.keys");
// Step 4: Verify cache.delete won't fail when there is a temporary padding
// file
await cache.delete("https://foo.com");
ok(!temporaryPaddingFile.exists(),
"Temporary padding file does be removed by cache.delete");
await caches.delete("test");
do_test_finished();
}

1
dom/cache/test/xpcshell/xpcshell.ini поставляемый
Просмотреть файл

@ -13,4 +13,5 @@ support-files =
skip-if = true
[test_migration.js]
[test_padding_error_handle.js]
[test_schema_26_upgrade.js]

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

@ -1152,7 +1152,7 @@ HTMLInputElement::HTMLInputElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
, mHasPatternAttribute(false)
{
// If size is above 512, mozjemalloc allocates 1kB, see
// memory/mozjemalloc/jemalloc.c
// memory/build/mozjemalloc.cpp
static_assert(sizeof(HTMLInputElement) <= 512,
"Keep the size of HTMLInputElement under 512 to avoid "
"performance regression!");

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

@ -154,8 +154,6 @@ MediaEMENoCapabilitiesDeprecatedWarning=Calling navigator.requestMediaKeySystemA
MediaEMENoCodecsDeprecatedWarning=Calling navigator.requestMediaKeySystemAccess() (at %S) passing a candidate MediaKeySystemConfiguration containing audioCapabilities or videoCapabilities without a contentType with a “codecs” string is deprecated and will soon become unsupported.
# LOCALIZATION NOTE: Do not translate "DOMException", "code" and "name"
DOMExceptionCodeWarning=Use of DOMExceptions code attribute is deprecated. Use name instead.
# LOCALIZATION NOTE: Do not translate "__exposedProps__"
NoExposedPropsWarning=Exposing chrome JS objects to content without __exposedProps__ is insecure and deprecated. See https://developer.mozilla.org/en/XPConnect_wrappers for more information.
# LOCALIZATION NOTE: Do not translate "Mutation Event" and "MutationObserver"
MutationEventWarning=Use of Mutation Events is deprecated. Use MutationObserver instead.
# LOCALIZATION NOTE: Do not translate "Components"

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

@ -175,7 +175,7 @@ public:
// Main thread only.
virtual void OnSessionMessage(const nsAString& aSessionId,
dom::MediaKeyMessageType aMessageType,
nsTArray<uint8_t>& aMessage) = 0;
const nsTArray<uint8_t>& aMessage) = 0;
// Main thread only.
virtual void OnExpirationChange(const nsAString& aSessionId,

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

@ -72,15 +72,4 @@ KeySystemToGMPName(const nsAString& aKeySystem)
return EmptyString();
}
CDMType
ToCDMTypeTelemetryEnum(const nsString& aKeySystem)
{
if (IsWidevineKeySystem(aKeySystem)) {
return CDMType::eWidevine;
} else if (IsClearkeyKeySystem(aKeySystem)) {
return CDMType::eClearKey;
}
return CDMType::eUnknown;
}
} // namespace mozilla

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

@ -452,8 +452,6 @@ MediaKeys::OnCDMCreated(PromiseId aId, const uint32_t aPluginId)
MediaKeySystemAccess::NotifyObservers(mParent,
mKeySystem,
MediaKeySystemStatus::Cdm_created);
Telemetry::Accumulate(Telemetry::VIDEO_CDM_CREATED, ToCDMTypeTelemetryEnum(mKeySystem));
}
static bool

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

@ -226,7 +226,7 @@ MediaDrmCDMProxy::OnResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccess
void
MediaDrmCDMProxy::OnSessionMessage(const nsAString& aSessionId,
dom::MediaKeyMessageType aMessageType,
nsTArray<uint8_t>& aMessage)
const nsTArray<uint8_t>& aMessage)
{
MOZ_ASSERT(NS_IsMainThread());
if (mKeys.IsNull()) {

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

@ -77,7 +77,7 @@ public:
void OnSessionMessage(const nsAString& aSessionId,
dom::MediaKeyMessageType aMessageType,
nsTArray<uint8_t>& aMessage) override;
const nsTArray<uint8_t>& aMessage) override;
void OnExpirationChange(const nsAString& aSessionId,
UnixTime aExpiryTime) override;

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

@ -25,7 +25,7 @@ if CONFIG['OS_ARCH'] == 'WINNT':
]
USE_STATIC_LIBS = True
NO_VISIBILITY_FLAGS = True
NoVisibilityFlags()
# Don't use STL wrappers; this isn't Gecko code
DISABLE_STL_WRAPPING = True
DisableStlWrapping()
NO_PGO = True

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

@ -27,7 +27,7 @@ if CONFIG['OS_ARCH'] == 'WINNT':
]
USE_STATIC_LIBS = True
NO_VISIBILITY_FLAGS = True
NoVisibilityFlags()
# Don't use STL wrappers; this isn't Gecko code
DISABLE_STL_WRAPPING = True
DisableStlWrapping()
NO_PGO = True

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

@ -0,0 +1,52 @@
/* -*- 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 ChromiumCDMCallback_h_
#define ChromiumCDMCallback_h_
#include "mozilla/CDMProxy.h"
#include "mozilla/dom/MediaKeyStatusMapBinding.h" // For MediaKeyStatus
#include "mozilla/dom/MediaKeyMessageEventBinding.h" // For MediaKeyMessageType
#include "mozilla/gmp/GMPTypes.h" // For CDMKeyInformation
class ChromiumCDMCallback {
public:
virtual ~ChromiumCDMCallback() {}
virtual void SetSessionId(uint32_t aPromiseId,
const nsCString& aSessionId) = 0;
virtual void ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccessful) = 0;
virtual void ResolvePromise(uint32_t aPromiseId) = 0;
virtual void RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage) = 0;
virtual void SessionMessage(const nsACString& aSessionId,
uint32_t aMessageType,
nsTArray<uint8_t>&& aMessage) = 0;
virtual void SessionKeysChange(const nsCString& aSessionId,
nsTArray<mozilla::gmp::CDMKeyInformation>&& aKeysInfo) = 0;
virtual void ExpirationChange(const nsCString& aSessionId,
double aSecondsSinceEpoch) = 0;
virtual void SessionClosed(const nsCString& aSessionId) = 0;
virtual void LegacySessionError(const nsCString& aSessionId,
nsresult aError,
uint32_t aSystemCode,
const nsCString& aMessage) = 0;
virtual void Terminated() = 0;
virtual void Shutdown() = 0;
};
#endif

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

@ -0,0 +1,188 @@
/* -*- 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 "ChromiumCDMCallbackProxy.h"
#include "ChromiumCDMProxy.h"
#include "content_decryption_module.h"
namespace mozilla {
template<class Func, class... Args>
void ChromiumCDMCallbackProxy::DispatchToMainThread(const char* const aLabel,
Func aFunc,
Args&&... aArgs)
{
mMainThread->Dispatch(
// Use Decay to ensure all the types are passed by value not by reference.
NewRunnableMethod<typename Decay<Args>::Type...>(
aLabel,
mProxy,
aFunc,
Forward<Args>(aArgs)...),
NS_DISPATCH_NORMAL);
}
void
ChromiumCDMCallbackProxy::SetSessionId(uint32_t aPromiseId,
const nsCString& aSessionId)
{
DispatchToMainThread("ChromiumCDMProxy::OnSetSessionId",
&ChromiumCDMProxy::OnSetSessionId,
aPromiseId,
NS_ConvertUTF8toUTF16(aSessionId));
}
void
ChromiumCDMCallbackProxy::ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccessful)
{
DispatchToMainThread("ChromiumCDMProxy::OnResolveLoadSessionPromise",
&ChromiumCDMProxy::OnResolveLoadSessionPromise,
aPromiseId,
aSuccessful);
}
void
ChromiumCDMCallbackProxy::ResolvePromise(uint32_t aPromiseId)
{
DispatchToMainThread("ChromiumCDMProxy::ResolvePromise",
&ChromiumCDMProxy::ResolvePromise,
aPromiseId);
}
void
ChromiumCDMCallbackProxy::RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage)
{
DispatchToMainThread("ChromiumCDMProxy::RejectPromise",
&ChromiumCDMProxy::RejectPromise,
aPromiseId,
aError,
aErrorMessage);
}
static dom::MediaKeyMessageType
ToDOMMessageType(uint32_t aMessageType)
{
switch (static_cast<cdm::MessageType>(aMessageType)) {
case cdm::kLicenseRequest:
return dom::MediaKeyMessageType::License_request;
case cdm::kLicenseRenewal:
return dom::MediaKeyMessageType::License_renewal;
case cdm::kLicenseRelease:
return dom::MediaKeyMessageType::License_release;
}
MOZ_ASSERT_UNREACHABLE("Invalid cdm::MessageType enum value.");
return dom::MediaKeyMessageType::License_request;
}
void
ChromiumCDMCallbackProxy::SessionMessage(const nsACString& aSessionId,
uint32_t aMessageType,
nsTArray<uint8_t>&& aMessage)
{
DispatchToMainThread("ChromiumCDMProxy::OnSessionMessage",
&ChromiumCDMProxy::OnSessionMessage,
NS_ConvertUTF8toUTF16(aSessionId),
ToDOMMessageType(aMessageType),
Move(aMessage));
}
static dom::MediaKeyStatus
ToDOMMediaKeyStatus(uint32_t aStatus)
{
switch (static_cast<cdm::KeyStatus>(aStatus)) {
case cdm::kUsable:
return dom::MediaKeyStatus::Usable;
case cdm::kInternalError:
return dom::MediaKeyStatus::Internal_error;
case cdm::kExpired:
return dom::MediaKeyStatus::Expired;
case cdm::kOutputRestricted:
return dom::MediaKeyStatus::Output_restricted;
case cdm::kOutputDownscaled:
return dom::MediaKeyStatus::Output_downscaled;
case cdm::kStatusPending:
return dom::MediaKeyStatus::Status_pending;
case cdm::kReleased:
return dom::MediaKeyStatus::Released;
}
MOZ_ASSERT_UNREACHABLE("Invalid cdm::KeyStatus enum value.");
return dom::MediaKeyStatus::Internal_error;
}
void
ChromiumCDMCallbackProxy::SessionKeysChange(const nsCString& aSessionId,
nsTArray<mozilla::gmp::CDMKeyInformation> && aKeysInfo)
{
bool keyStatusesChange = false;
{
CDMCaps::AutoLock caps(mProxy->Capabilites());
for (const auto& keyInfo : aKeysInfo) {
keyStatusesChange |=
caps.SetKeyStatus(keyInfo.mKeyId(),
NS_ConvertUTF8toUTF16(aSessionId),
dom::Optional<dom::MediaKeyStatus>(
ToDOMMediaKeyStatus(keyInfo.mStatus())));
}
}
if (keyStatusesChange) {
DispatchToMainThread("ChromiumCDMProxy::OnKeyStatusesChange",
&ChromiumCDMProxy::OnKeyStatusesChange,
NS_ConvertUTF8toUTF16(aSessionId));
}
}
void
ChromiumCDMCallbackProxy::ExpirationChange(const nsCString& aSessionId,
double aSecondsSinceEpoch)
{
DispatchToMainThread("ChromiumCDMProxy::OnExpirationChange",
&ChromiumCDMProxy::OnExpirationChange,
NS_ConvertUTF8toUTF16(aSessionId),
UnixTime(aSecondsSinceEpoch * 1000));
}
void
ChromiumCDMCallbackProxy::SessionClosed(const nsCString& aSessionId)
{
DispatchToMainThread("ChromiumCDMProxy::OnSessionClosed",
&ChromiumCDMProxy::OnSessionClosed ,
NS_ConvertUTF8toUTF16(aSessionId));
}
void
ChromiumCDMCallbackProxy::LegacySessionError(const nsCString& aSessionId,
nsresult aError,
uint32_t aSystemCode,
const nsCString& aMessage)
{
DispatchToMainThread("ChromiumCDMProxy::OnSessionError",
&ChromiumCDMProxy::OnSessionError ,
NS_ConvertUTF8toUTF16(aSessionId),
aError,
aSystemCode,
NS_ConvertUTF8toUTF16(aMessage));
}
void
ChromiumCDMCallbackProxy::Terminated()
{
DispatchToMainThread("ChromiumCDMProxy::Terminated",
&ChromiumCDMProxy::Terminated);
}
void
ChromiumCDMCallbackProxy::Shutdown()
{
DispatchToMainThread("ChromiumCDMProxy::Shutdown",
&ChromiumCDMProxy::Shutdown);
}
} //namespace mozilla

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

@ -0,0 +1,68 @@
/* -*- 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 ChromiumCDMCallbackProxy_h_
#define ChromiumCDMCallbackProxy_h_
#include "ChromiumCDMCallback.h"
#include "ChromiumCDMProxy.h"
#include "nsThreadUtils.h"
namespace mozilla {
class ChromiumCDMCallbackProxy : public ChromiumCDMCallback {
public:
ChromiumCDMCallbackProxy(ChromiumCDMProxy* aProxy,
nsIEventTarget* aMainThread)
: mProxy(aProxy), mMainThread(aMainThread)
{
}
void SetSessionId(uint32_t aPromiseId,
const nsCString& aSessionId) override;
void ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccessful) override;
void ResolvePromise(uint32_t aPromiseId) override;
void RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage) override;
void SessionMessage(const nsACString& aSessionId,
uint32_t aMessageType,
nsTArray<uint8_t>&& aMessage) override;
void SessionKeysChange(const nsCString& aSessionId,
nsTArray<mozilla::gmp::CDMKeyInformation>&& aKeysInfo) override;
void ExpirationChange(const nsCString& aSessionId,
double aSecondsSinceEpoch) override;
void SessionClosed(const nsCString& aSessionId) override;
void LegacySessionError(const nsCString& aSessionId,
nsresult aError,
uint32_t aSystemCode,
const nsCString& aMessage) override;
void Terminated() override;
void Shutdown() override;
private:
template<class Func, class... Args>
void DispatchToMainThread(const char* const aLabel,
Func aFunc,
Args&&... aArgs);
// Warning: Weak ref.
ChromiumCDMProxy* mProxy;
const nsCOMPtr<nsIEventTarget> mMainThread;
};
} //namespace mozilla
#endif

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

@ -5,6 +5,8 @@
#include "ChromiumCDMParent.h"
#include "ChromiumCDMCallback.h"
#include "ChromiumCDMCallbackProxy.h"
#include "ChromiumCDMProxy.h"
#include "content_decryption_module.h"
#include "GMPContentChild.h"
@ -40,16 +42,16 @@ ChromiumCDMParent::ChromiumCDMParent(GMPContentParent* aContentParent,
}
bool
ChromiumCDMParent::Init(ChromiumCDMProxy* aProxy,
ChromiumCDMParent::Init(ChromiumCDMCallback* aCDMCallback,
bool aAllowDistinctiveIdentifier,
bool aAllowPersistentState,
nsIEventTarget* aMainThread)
{
GMP_LOG("ChromiumCDMParent::Init(this=%p)", this);
if (!aProxy || !aMainThread) {
if (!aCDMCallback || !aMainThread) {
return false;
}
mProxy = aProxy;
mCDMCallback = aCDMCallback;
mMainThread = aMainThread;
return SendInit(aAllowDistinctiveIdentifier, aAllowPersistentState);
}
@ -279,7 +281,7 @@ ChromiumCDMParent::RecvOnResolveNewSessionPromise(const uint32_t& aPromiseId,
this,
aPromiseId,
aSessionId.get());
if (!mProxy || mIsShutdown) {
if (!mCDMCallback || mIsShutdown) {
return IPC_OK();
}
@ -291,13 +293,7 @@ ChromiumCDMParent::RecvOnResolveNewSessionPromise(const uint32_t& aPromiseId,
return IPC_OK();
}
mMainThread->Dispatch(
NewRunnableMethod<uint32_t, nsString>("ChromiumCDMProxy::OnSetSessionId",
mProxy,
&ChromiumCDMProxy::OnSetSessionId,
token.value(),
NS_ConvertUTF8toUTF16(aSessionId)),
NS_DISPATCH_NORMAL);
mCDMCallback->SetSessionId(token.value(), aSessionId);
ResolvePromise(aPromiseId);
@ -313,21 +309,15 @@ ChromiumCDMParent::RecvResolveLoadSessionPromise(const uint32_t& aPromiseId,
this,
aPromiseId,
aSuccessful);
if (!mProxy || mIsShutdown) {
if (!mCDMCallback || mIsShutdown) {
return IPC_OK();
}
mMainThread->Dispatch(
NewRunnableMethod<uint32_t, bool>(
"ChromiumCDMProxy::OnResolveLoadSessionPromise",
mProxy,
&ChromiumCDMProxy::OnResolveLoadSessionPromise,
aPromiseId,
aSuccessful),
NS_DISPATCH_NORMAL);
mCDMCallback->ResolveLoadSessionPromise(aPromiseId, aSuccessful);
return IPC_OK();
}
void
ChromiumCDMParent::ResolvePromise(uint32_t aPromiseId)
{
@ -336,16 +326,11 @@ ChromiumCDMParent::ResolvePromise(uint32_t aPromiseId)
// Note: The MediaKeys rejects all pending DOM promises when it
// initiates shutdown.
if (!mProxy || mIsShutdown) {
if (!mCDMCallback || mIsShutdown) {
return;
}
mMainThread->Dispatch(
NewRunnableMethod<uint32_t>("ChromiumCDMProxy::ResolvePromise",
mProxy,
&ChromiumCDMProxy::ResolvePromise,
aPromiseId),
NS_DISPATCH_NORMAL);
mCDMCallback->ResolvePromise(aPromiseId);
}
ipc::IPCResult
@ -355,6 +340,22 @@ ChromiumCDMParent::RecvOnResolvePromise(const uint32_t& aPromiseId)
return IPC_OK();
}
void
ChromiumCDMParent::RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage)
{
GMP_LOG(
"ChromiumCDMParent::RejectPromise(this=%p, pid=%u)", this, aPromiseId);
// Note: The MediaKeys rejects all pending DOM promises when it
// initiates shutdown.
if (!mCDMCallback || mIsShutdown) {
return;
}
mCDMCallback->RejectPromise(aPromiseId, aError, aErrorMessage);
}
static nsresult
ToNsresult(uint32_t aError)
{
@ -382,30 +383,6 @@ ToNsresult(uint32_t aError)
return NS_ERROR_DOM_TIMEOUT_ERR; // Note: Unique placeholder.
}
void
ChromiumCDMParent::RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage)
{
GMP_LOG(
"ChromiumCDMParent::RejectPromise(this=%p, pid=%u)", this, aPromiseId);
// Note: The MediaKeys rejects all pending DOM promises when it
// initiates shutdown.
if (!mProxy || mIsShutdown) {
return;
}
mMainThread->Dispatch(
NewRunnableMethod<uint32_t, nsresult, nsCString>(
"ChromiumCDMProxy::RejectPromise",
mProxy,
&ChromiumCDMProxy::RejectPromise,
aPromiseId,
aError,
aErrorMessage),
NS_DISPATCH_NORMAL);
}
ipc::IPCResult
ChromiumCDMParent::RecvOnRejectPromise(const uint32_t& aPromiseId,
const uint32_t& aError,
@ -416,21 +393,6 @@ ChromiumCDMParent::RecvOnRejectPromise(const uint32_t& aPromiseId,
return IPC_OK();
}
static dom::MediaKeyMessageType
ToDOMMessageType(uint32_t aMessageType)
{
switch (static_cast<cdm::MessageType>(aMessageType)) {
case cdm::kLicenseRequest:
return dom::MediaKeyMessageType::License_request;
case cdm::kLicenseRenewal:
return dom::MediaKeyMessageType::License_renewal;
case cdm::kLicenseRelease:
return dom::MediaKeyMessageType::License_release;
}
MOZ_ASSERT_UNREACHABLE("Invalid cdm::MessageType enum value.");
return dom::MediaKeyMessageType::License_request;
}
ipc::IPCResult
ChromiumCDMParent::RecvOnSessionMessage(const nsCString& aSessionId,
const uint32_t& aMessageType,
@ -439,74 +401,25 @@ ChromiumCDMParent::RecvOnSessionMessage(const nsCString& aSessionId,
GMP_LOG("ChromiumCDMParent::RecvOnSessionMessage(this=%p, sid=%s)",
this,
aSessionId.get());
if (!mProxy || mIsShutdown) {
if (!mCDMCallback || mIsShutdown) {
return IPC_OK();
}
RefPtr<CDMProxy> proxy = mProxy;
nsString sid = NS_ConvertUTF8toUTF16(aSessionId);
dom::MediaKeyMessageType messageType = ToDOMMessageType(aMessageType);
nsTArray<uint8_t> msg(Move(aMessage));
mMainThread->Dispatch(
NS_NewRunnableFunction("gmp::ChromiumCDMParent::RecvOnSessionMessage",
[proxy, sid, messageType, msg]() mutable {
proxy->OnSessionMessage(sid, messageType, msg);
}),
NS_DISPATCH_NORMAL);
mCDMCallback->SessionMessage(aSessionId, aMessageType, Move(aMessage));
return IPC_OK();
}
static dom::MediaKeyStatus
ToDOMMediaKeyStatus(uint32_t aStatus)
{
switch (static_cast<cdm::KeyStatus>(aStatus)) {
case cdm::kUsable:
return dom::MediaKeyStatus::Usable;
case cdm::kInternalError:
return dom::MediaKeyStatus::Internal_error;
case cdm::kExpired:
return dom::MediaKeyStatus::Expired;
case cdm::kOutputRestricted:
return dom::MediaKeyStatus::Output_restricted;
case cdm::kOutputDownscaled:
return dom::MediaKeyStatus::Output_downscaled;
case cdm::kStatusPending:
return dom::MediaKeyStatus::Status_pending;
case cdm::kReleased:
return dom::MediaKeyStatus::Released;
}
MOZ_ASSERT_UNREACHABLE("Invalid cdm::KeyStatus enum value.");
return dom::MediaKeyStatus::Internal_error;
}
ipc::IPCResult
ChromiumCDMParent::RecvOnSessionKeysChange(
const nsCString& aSessionId,
nsTArray<CDMKeyInformation>&& aKeysInfo)
{
GMP_LOG("ChromiumCDMParent::RecvOnSessionKeysChange(this=%p)", this);
if (!mProxy || mIsShutdown) {
if (!mCDMCallback || mIsShutdown) {
return IPC_OK();
}
bool keyStatusesChange = false;
{
CDMCaps::AutoLock caps(mProxy->Capabilites());
for (size_t i = 0; i < aKeysInfo.Length(); i++) {
keyStatusesChange |=
caps.SetKeyStatus(aKeysInfo[i].mKeyId(),
NS_ConvertUTF8toUTF16(aSessionId),
dom::Optional<dom::MediaKeyStatus>(
ToDOMMediaKeyStatus(aKeysInfo[i].mStatus())));
}
}
if (keyStatusesChange) {
mMainThread->Dispatch(
NewRunnableMethod<nsString>("ChromiumCDMProxy::OnKeyStatusesChange",
mProxy,
&ChromiumCDMProxy::OnKeyStatusesChange,
NS_ConvertUTF8toUTF16(aSessionId)),
NS_DISPATCH_NORMAL);
}
mCDMCallback->SessionKeysChange(aSessionId, Move(aKeysInfo));
return IPC_OK();
}
@ -517,18 +430,11 @@ ChromiumCDMParent::RecvOnExpirationChange(const nsCString& aSessionId,
GMP_LOG("ChromiumCDMParent::RecvOnExpirationChange(this=%p) time=%lf",
this,
aSecondsSinceEpoch);
if (!mProxy || mIsShutdown) {
if (!mCDMCallback || mIsShutdown) {
return IPC_OK();
}
mMainThread->Dispatch(
NewRunnableMethod<nsString, UnixTime>(
"ChromiumCDMProxy::OnExpirationChange",
mProxy,
&ChromiumCDMProxy::OnExpirationChange,
NS_ConvertUTF8toUTF16(aSessionId),
GMPTimestamp(aSecondsSinceEpoch * 1000)),
NS_DISPATCH_NORMAL);
mCDMCallback->ExpirationChange(aSessionId, aSecondsSinceEpoch);
return IPC_OK();
}
@ -536,16 +442,11 @@ ipc::IPCResult
ChromiumCDMParent::RecvOnSessionClosed(const nsCString& aSessionId)
{
GMP_LOG("ChromiumCDMParent::RecvOnSessionClosed(this=%p)", this);
if (!mProxy || mIsShutdown) {
if (!mCDMCallback || mIsShutdown) {
return IPC_OK();
}
mMainThread->Dispatch(
NewRunnableMethod<nsString>("ChromiumCDMProxy::OnSessionClosed",
mProxy,
&ChromiumCDMProxy::OnSessionClosed,
NS_ConvertUTF8toUTF16(aSessionId)),
NS_DISPATCH_NORMAL);
mCDMCallback->SessionClosed(aSessionId);
return IPC_OK();
}
@ -556,20 +457,12 @@ ChromiumCDMParent::RecvOnLegacySessionError(const nsCString& aSessionId,
const nsCString& aMessage)
{
GMP_LOG("ChromiumCDMParent::RecvOnLegacySessionError(this=%p)", this);
if (!mProxy || mIsShutdown) {
if (!mCDMCallback || mIsShutdown) {
return IPC_OK();
}
mMainThread->Dispatch(
NewRunnableMethod<nsString, nsresult, uint32_t, nsString>(
"ChromiumCDMProxy::OnSessionError",
mProxy,
&ChromiumCDMProxy::OnSessionError,
NS_ConvertUTF8toUTF16(aSessionId),
ToNsresult(aError),
aSystemCode,
NS_ConvertUTF8toUTF16(aMessage)),
NS_DISPATCH_NORMAL);
mCDMCallback->LegacySessionError(
aSessionId, ToNsresult(aError), aSystemCode, aMessage);
return IPC_OK();
}
@ -934,8 +827,8 @@ ChromiumCDMParent::ActorDestroy(ActorDestroyReason aWhy)
GMP_LOG("ChromiumCDMParent::ActorDestroy(this=%p, reason=%d)", this, aWhy);
MOZ_ASSERT(!mActorDestroyed);
mActorDestroyed = true;
// Shutdown() will clear mProxy, so let's keep a reference for later use.
RefPtr<ChromiumCDMProxy> proxy = mProxy;
// Shutdown() will clear mCDMCallback, so let's keep a reference for later use.
auto callback = mCDMCallback;
if (!mIsShutdown) {
// Plugin crash.
MOZ_ASSERT(aWhy == AbnormalShutdown);
@ -948,13 +841,8 @@ ChromiumCDMParent::ActorDestroy(ActorDestroyReason aWhy)
mContentParent = nullptr;
}
bool abnormalShutdown = (aWhy == AbnormalShutdown);
if (abnormalShutdown && proxy) {
mMainThread->Dispatch(
NewRunnableMethod(
"ChromiumCDMProxy::Terminated",
proxy,
&ChromiumCDMProxy::Terminated),
NS_DISPATCH_NORMAL);
if (abnormalShutdown && callback) {
callback->Terminated();
}
MaybeDisconnect(abnormalShutdown);
}
@ -1190,19 +1078,14 @@ ChromiumCDMParent::Shutdown()
// proxy will shutdown when the owning MediaKeys is destroyed during cycle
// collection, and that will not shut down cleanly as the GMP thread will be
// shutdown by then.
if (mProxy) {
mMainThread->Dispatch(
NewRunnableMethod(
"ChromiumCDMProxy::Shutdown",
mProxy,
&ChromiumCDMProxy::Shutdown),
NS_DISPATCH_NORMAL);
if (mCDMCallback) {
mCDMCallback->Shutdown();
}
// We may be called from a task holding the last reference to the proxy, so
// We may be called from a task holding the last reference to the CDM callback, so
// let's clear our local weak pointer to ensure it will not be used afterward
// (including from an already-queued task, e.g.: ActorDestroy).
mProxy = nullptr;
mCDMCallback = nullptr;
mReorderQueue.Clear();

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

@ -18,6 +18,8 @@
#include "mozilla/Span.h"
#include "ReorderQueue.h"
class ChromiumCDMCallback;
namespace mozilla {
class MediaRawData;
@ -38,7 +40,7 @@ public:
uint32_t PluginId() const { return mPluginId; }
bool Init(ChromiumCDMProxy* aProxy,
bool Init(ChromiumCDMCallback* aCDMCallback,
bool aAllowDistinctiveIdentifier,
bool aAllowPersistentState,
nsIEventTarget* aMainThread);
@ -148,10 +150,9 @@ protected:
const uint32_t mPluginId;
GMPContentParent* mContentParent;
// Note: this pointer is a weak reference because otherwise it would cause
// a cycle, as ChromiumCDMProxy has a strong reference to the
// ChromiumCDMParent.
ChromiumCDMProxy* mProxy = nullptr;
// Note: this pointer is a weak reference as ChromiumCDMProxy has a strong reference to the
// ChromiumCDMCallback.
ChromiumCDMCallback* mCDMCallback = nullptr;
nsDataHashtable<nsUint32HashKey, uint32_t> mPromiseToCreateSessionToken;
nsTArray<RefPtr<DecryptJob>> mDecrypts;
@ -188,7 +189,7 @@ protected:
ReorderQueue mReorderQueue;
// The main thread associated with the root document. Must be set in Init().
nsCOMPtr<nsIEventTarget> mMainThread;
nsCOMPtr<nsIEventTarget> mMainThread;
};
} // namespace gmp

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

@ -5,6 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ChromiumCDMProxy.h"
#include "ChromiumCDMCallbackProxy.h"
#include "mozilla/dom/MediaKeySession.h"
#include "GMPUtils.h"
#include "nsPrintfCString.h"
@ -97,7 +98,9 @@ ChromiumCDMProxy::Init(PromiseId aPromiseId,
thread,
__func__,
[self, aPromiseId](RefPtr<gmp::ChromiumCDMParent> cdm) {
if (!cdm->Init(self,
self->mCallback =
MakeUnique<ChromiumCDMCallbackProxy>(self, self->mMainThread);
if (!cdm->Init(self->mCallback.get(),
self->mDistinctiveIdentifierRequired,
self->mPersistentStateRequired,
self->mMainThread)) {
@ -464,7 +467,7 @@ ChromiumCDMProxy::OnResolveLoadSessionPromise(uint32_t aPromiseId,
void
ChromiumCDMProxy::OnSessionMessage(const nsAString& aSessionId,
dom::MediaKeyMessageType aMessageType,
nsTArray<uint8_t>& aMessage)
const nsTArray<uint8_t>& aMessage)
{
MOZ_ASSERT(NS_IsMainThread());
if (mKeys.IsNull()) {

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

@ -15,7 +15,7 @@ namespace mozilla {
class MediaRawData;
class DecryptJob;
class ChromiumCDMCallbackProxy;
class ChromiumCDMProxy : public CDMProxy
{
public:
@ -68,7 +68,7 @@ public:
void OnSessionMessage(const nsAString& aSessionId,
dom::MediaKeyMessageType aMessageType,
nsTArray<uint8_t>& aMessage) override;
const nsTArray<uint8_t>& aMessage) override;
void OnExpirationChange(const nsAString& aSessionId,
GMPTimestamp aExpiryTime) override;
@ -125,6 +125,7 @@ private:
Mutex mCDMMutex;
RefPtr<gmp::ChromiumCDMParent> mCDM;
RefPtr<AbstractThread> mGMPThread;
UniquePtr<ChromiumCDMCallbackProxy> mCallback;
};
} // namespace mozilla

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

@ -12,6 +12,7 @@ XPIDL_SOURCES += [
]
EXPORTS += [
'ChromiumCDMCallback.h',
'ChromiumCDMParent.h',
'ChromiumCDMProxy.h',
'DecryptJob.h',
@ -72,6 +73,7 @@ EXPORTS += [
UNIFIED_SOURCES += [
'ChromiumCDMAdapter.cpp',
'ChromiumCDMCallbackProxy.cpp',
'ChromiumCDMChild.cpp',
'ChromiumCDMParent.cpp',
'ChromiumCDMProxy.cpp',

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

@ -15,7 +15,7 @@ include('/ipc/chromium/chromium-config.mozbuild')
DEFINES['NS_NO_XPCOM'] = True
DEFINES['_HAS_EXCEPTIONS'] = 0
DISABLE_STL_WRAPPING = True
DisableStlWrapping()
if CONFIG['GNU_CC']:
WIN32_EXE_LDFLAGS += ['-municode']

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

@ -35,7 +35,7 @@ elif toolkit == 'windows':
USE_STATIC_LIBS = True
# Don't use STL wrappers; nptest isn't Gecko code
DISABLE_STL_WRAPPING = True
DisableStlWrapping()
NO_PGO = True

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

@ -7,7 +7,6 @@
#include "hasht.h"
#include "nsICryptoHash.h"
#include "nsNetCID.h"
#include "nsNetUtil.h" // Used by WD-05 compat support (Remove in Bug 1381126)
#include "nsThreadUtils.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/AuthenticatorAttestationResponse.h"
@ -191,25 +190,7 @@ RelaxSameOrigin(nsPIDOMWindowInner* aParent,
return NS_ERROR_FAILURE;
}
// WD-05 origin compatibility support - aInputRpId might be a URI/origin,
// so catch that (Bug 1380421). Remove in Bug 1381126.
nsAutoString inputRpId(aInputRpId);
nsCOMPtr<nsIURI> inputUri;
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(inputUri), aInputRpId))) {
// If we parsed the input as a URI, then pull out the host and use it as the
// input
nsAutoCString uriHost;
if (NS_FAILED(inputUri->GetHost(uriHost))) {
return NS_ERROR_FAILURE;
}
CopyUTF8toUTF16(uriHost, inputRpId);
MOZ_LOG(gWebAuthnManagerLog, LogLevel::Debug,
("WD-05 Fallback: Parsed input %s URI into host %s",
NS_ConvertUTF16toUTF8(aInputRpId).get(), uriHost.get()));
}
// End WD-05 origin compatibility support (Bug 1380421)
if (!html->IsRegistrableDomainSuffixOfOrEqualTo(inputRpId, originHost)) {
if (!html->IsRegistrableDomainSuffixOfOrEqualTo(aInputRpId, originHost)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
@ -491,10 +472,8 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent,
return promise.forget();
}
// WD-05 vs. WD-06: In WD-06, the first parameter should be "origin". Fix
// this in Bug 1384776
nsAutoCString clientDataJSON;
srv = AssembleClientData(NS_ConvertUTF8toUTF16(rpId), challenge, clientDataJSON);
srv = AssembleClientData(origin, challenge, clientDataJSON);
if (NS_WARN_IF(NS_FAILED(srv))) {
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
return promise.forget();
@ -655,9 +634,7 @@ WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent,
}
nsAutoCString clientDataJSON;
// WD-05 vs. WD-06: In WD-06, the first parameter should be "origin". Fix
// this in Bug 1384776
srv = AssembleClientData(NS_ConvertUTF8toUTF16(rpId), challenge, clientDataJSON);
srv = AssembleClientData(origin, challenge, clientDataJSON);
if (NS_WARN_IF(NS_FAILED(srv))) {
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
return promise.forget();

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

@ -63,14 +63,22 @@ function() {
let clientData = JSON.parse(buffer2string(aCredInfo.response.clientDataJSON));
is(clientData.challenge, bytesToBase64UrlSafe(gCredentialChallenge), "Challenge is correct");
// WD-05 vs. WD-06: In WD-06, the second parameter should be "window.location.origin". Fix
// this in Bug 1384776
is(clientData.origin, document.domain, "Origin is correct");
is(clientData.origin, window.location.origin, "Origin is correct");
is(clientData.hashAlg, "SHA-256", "Hash algorithm is correct");
return webAuthnDecodeCBORAttestation(aCredInfo.response.attestationObject.buffer)
.then(function(decodedResult) {
ok(decodedResult.flags == (flag_TUP | flag_AT), "User presence and Attestation Object must both be set");
// Make sure the RP ID hash matches what we calculate.
return crypto.subtle.digest("SHA-256", string2buffer(document.domain))
.then(function(calculatedHash) {
is(bytesToBase64(new Uint8Array(calculatedHash)), bytesToBase64(decodedResult.rpIdHash),
"Calculated RP ID hash must match what the browser derived.");
return Promise.resolve(decodedResult);
});
})
.then(function(decodedResult) {
ok(decodedResult.flags == (flag_TUP | flag_AT),
"User presence and Attestation Object must both be set");
aCredInfo.clientDataObj = clientData;
aCredInfo.publicKeyHandle = decodedResult.publicKeyHandle;
@ -101,9 +109,7 @@ function() {
ok(aAssertion.response.authenticatorData.length > 0, "Authenticator data exists");
let clientData = JSON.parse(buffer2string(aAssertion.response.clientDataJSON));
is(clientData.challenge, bytesToBase64UrlSafe(gAssertionChallenge), "Challenge is correct");
// WD-05 vs. WD-06: In WD-06, the second parameter should be "window.location.origin". Fix
// this in Bug 1384776
is(clientData.origin, document.domain, "Origin is correct");
is(clientData.origin, window.location.origin, "Origin is correct");
is(clientData.hashAlg, "SHA-256", "Hash algorithm is correct");
return webAuthnDecodeAttestation(aAssertion.response.authenticatorData)

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

@ -231,7 +231,6 @@
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
// These next two tests should be removed in Bug 1381126.
function () {
// Test basic good Create call but using an origin (Bug 1380421)
let rp = {id: window.origin};
@ -239,22 +238,20 @@
rp: rp, user: user, challenge: chall, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(keepThisPublicKeyCredential("origin"))
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test basic good Get call but using an origin (Bug 1380421)
let publicKeyCredentialRequestOptions = {
challenge: chall,
rpId: window.origin,
allowList: [gTrackedCredential["origin"]]
allowList: [gTrackedCredential["basic"]]
};
return credm.get({publicKey: publicKeyCredentialRequestOptions})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
.then(arrivingHereIsBad)
.catch(expectSecurityError);
}
// End remove in Bug 1381126.
];
var i = 0;
var runNextTest = () => {

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

@ -412,7 +412,11 @@ fetch('interrupt.sjs')
['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'].forEach(function(method) {
fetchXHRWithMethod('xhr-method-test.txt', method, function(xhr) {
my_ok(xhr.status == 200, method + " load should be successful");
my_ok(xhr.responseText == ("intercepted " + method), method + " load should have synthesized response");
if (method === "HEAD") {
my_ok(xhr.responseText == "", method + "load should not have synthesized response");
} else {
my_ok(xhr.responseText == ("intercepted " + method), method + " load should have synthesized response");
}
finish();
});
});

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

@ -624,6 +624,12 @@ XMLHttpRequestMainThread::GetResponseText(XMLHttpRequestStringSnapshot& aSnapsho
return;
}
// Main Fetch step 18 requires to ignore body for head/connect methods.
if (mRequestMethod.EqualsLiteral("HEAD") ||
mRequestMethod.EqualsLiteral("CONNECT")) {
return;
}
// We only decode text lazily if we're also parsing to a doc.
// Also, if we've decoded all current data already, then no need to decode
// more.
@ -2081,15 +2087,11 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
}
// Set up responseXML
bool parseBody = mResponseType == XMLHttpRequestResponseType::_empty ||
mResponseType == XMLHttpRequestResponseType::Document;
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
if (parseBody && httpChannel) {
nsAutoCString method;
rv = httpChannel->GetRequestMethod(method);
MOZ_ASSERT(NS_SUCCEEDED(rv));
parseBody = !method.EqualsLiteral("HEAD");
}
// Note: Main Fetch step 18 requires to ignore body for head/connect methods.
bool parseBody = (mResponseType == XMLHttpRequestResponseType::_empty ||
mResponseType == XMLHttpRequestResponseType::Document) &&
!(mRequestMethod.EqualsLiteral("HEAD") ||
mRequestMethod.EqualsLiteral("CONNECT"));
mIsHtml = false;
mWarnAboutSyncHtml = false;

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

@ -205,16 +205,8 @@ APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
}
LayoutDevicePoint ldPoint = aPoint * aScale;
if (!mActiveElementManager->ActiveElementUsesStyle()) {
// If the active element isn't visually affected by the :active style, we
// have no need to wait the extra sActiveDurationMs to make the activation
// visually obvious to the user.
widget::nsAutoRollup rollup(touchRollup.get());
APZCCallbackHelper::FireSingleTapEvent(ldPoint, aModifiers, aClickCount, widget);
return;
}
APZES_LOG("Active element uses style, scheduling timer for click event\n");
APZES_LOG("Scheduling timer for click event\n");
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
dom::TabChild* tabChild = widget->GetOwningTabChild();

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

@ -27,8 +27,7 @@ static bool sActivationDelayMsSet = false;
ActiveElementManager::ActiveElementManager()
: mCanBePan(false),
mCanBePanSet(false),
mSetActiveTask(nullptr),
mActiveElementUsesStyle(false)
mSetActiveTask(nullptr)
{
if (!sActivationDelayMsSet) {
Preferences::AddIntVarCache(&sActivationDelayMs,
@ -142,12 +141,6 @@ ActiveElementManager::HandleTouchEnd()
mCanBePanSet = false;
}
bool
ActiveElementManager::ActiveElementUsesStyle() const
{
return mActiveElementUsesStyle;
}
static nsPresContext*
GetPresContextFor(nsIContent* aContent)
{
@ -161,30 +154,6 @@ GetPresContextFor(nsIContent* aContent)
return shell->GetPresContext();
}
static bool
ElementHasActiveStyle(dom::Element* aElement)
{
nsPresContext* pc = GetPresContextFor(aElement);
if (!pc) {
return false;
}
nsStyleSet* styleSet = pc->StyleSet()->GetAsGecko();
if (!styleSet) {
// Bug 1397434 tracks making this optimization work for stylo.
AEM_LOG("Element %p uses Servo style backend, assuming dependence on active state\n", aElement);
return true;
}
for (dom::Element* e = aElement; e; e = e->GetParentElement()) {
if (styleSet->HasStateDependentStyle(e, NS_EVENT_STATE_ACTIVE)) {
AEM_LOG("Element %p's style is dependent on the active state\n", e);
return true;
}
}
AEM_LOG("Element %p doesn't use active styles\n", aElement);
return false;
}
void
ActiveElementManager::SetActive(dom::Element* aTarget)
{
@ -192,7 +161,6 @@ ActiveElementManager::SetActive(dom::Element* aTarget)
if (nsPresContext* pc = GetPresContextFor(aTarget)) {
pc->EventStateManager()->SetContentState(aTarget, NS_EVENT_STATE_ACTIVE);
mActiveElementUsesStyle = ElementHasActiveStyle(aTarget);
}
}

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

@ -59,12 +59,6 @@ public:
* delayed until after touch listeners have responded to the APZ.
*/
void HandleTouchEnd();
/**
* @return true iff the currently active element (or one of its ancestors)
* actually had a style for the :active pseudo-class. The currently active
* element is the root element if no other elements are active.
*/
bool ActiveElementUsesStyle() const;
private:
/**
* The target of the first touch point in the current touch block.
@ -84,10 +78,6 @@ private:
* A task for calling SetActive() after a timeout.
*/
RefPtr<CancelableRunnable> mSetActiveTask;
/**
* See ActiveElementUsesStyle() documentation.
*/
bool mActiveElementUsesStyle;
// Helpers
void TriggerElementActivation();

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

@ -230,9 +230,6 @@ size_t Histogram::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
{
size_t n = 0;
n += aMallocSizeOf(this);
// We're not allowed to do deep dives into STL data structures. This
// is as close as we can get to measuring this array.
n += aMallocSizeOf(&ranges_[0]);
n += sample_.SizeOfExcludingThis(aMallocSizeOf);
return n;
}
@ -251,7 +248,6 @@ Histogram::Histogram(Sample minimum, Sample maximum, size_t bucket_count)
declared_max_(maximum),
bucket_count_(bucket_count),
flags_(kNoFlags),
ranges_(bucket_count + 1, 0),
range_checksum_(0) {
Initialize();
}
@ -262,7 +258,6 @@ Histogram::Histogram(TimeDelta minimum, TimeDelta maximum, size_t bucket_count)
declared_max_(static_cast<int> (maximum.InMilliseconds())),
bucket_count_(bucket_count),
flags_(kNoFlags),
ranges_(bucket_count + 1, 0),
range_checksum_(0) {
Initialize();
}
@ -273,8 +268,7 @@ Histogram::~Histogram() {
}
void Histogram::InitializeBucketRangeFromData(const int* buckets) {
DCHECK_EQ(bucket_count_ + 1, ranges_.size());
std::copy_n(buckets, bucket_count_, ranges_.data());
ranges_ = buckets;
ResetRangeChecksum();
DCHECK(ValidateBucketRanges());
}
@ -340,14 +334,9 @@ void Histogram::Accumulate(Sample value, Count count, size_t index) {
sample_.Accumulate(value, count, index);
}
void Histogram::SetBucketRange(size_t i, Sample value) {
DCHECK_GT(bucket_count_, i);
ranges_[i] = value;
}
bool Histogram::ValidateBucketRanges() const {
// Standard assertions that all bucket ranges should satisfy.
DCHECK_EQ(bucket_count_ + 1, ranges_.size());
DCHECK_EQ(0, ranges_[bucket_count_ + 1]);
DCHECK_EQ(0, ranges_[0]);
DCHECK_EQ(declared_min(), ranges_[1]);
DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]);
@ -356,8 +345,8 @@ bool Histogram::ValidateBucketRanges() const {
}
uint32_t Histogram::CalculateRangeChecksum() const {
DCHECK_EQ(ranges_.size(), bucket_count() + 1);
uint32_t checksum = static_cast<uint32_t>(ranges_.size()); // Seed checksum.
DCHECK_EQ(0, ranges_[bucket_count_ + 1]);
uint32_t checksum = static_cast<uint32_t>(bucket_count_ + 1); // Seed checksum.
for (size_t index = 0; index < bucket_count(); ++index)
checksum = Crc32(checksum, ranges(index));
return checksum;
@ -374,8 +363,6 @@ void Histogram::Initialize() {
CHECK_LT(bucket_count_, kBucketCount_MAX);
size_t maximal_bucket_count = declared_max_ - declared_min_ + 2;
DCHECK_LE(bucket_count_, maximal_bucket_count);
DCHECK_EQ(0, ranges_[0]);
ranges_[bucket_count_] = kSampleType_MAX;
}
// We generate the CRC-32 using the low order bits to select whether to XOR in
@ -485,7 +472,8 @@ LinearHistogram::~LinearHistogram() {
Histogram* LinearHistogram::FactoryGet(Sample minimum,
Sample maximum,
size_t bucket_count,
Flags flags) {
Flags flags,
const int* buckets) {
Histogram* histogram(NULL);
if (minimum < 1)
@ -495,7 +483,7 @@ Histogram* LinearHistogram::FactoryGet(Sample minimum,
LinearHistogram* linear_histogram =
new LinearHistogram(minimum, maximum, bucket_count);
linear_histogram->InitializeBucketRange();
linear_histogram->InitializeBucketRangeFromData(buckets);
linear_histogram->SetFlags(flags);
histogram = linear_histogram;
@ -504,14 +492,6 @@ Histogram* LinearHistogram::FactoryGet(Sample minimum,
return histogram;
}
Histogram* LinearHistogram::FactoryTimeGet(TimeDelta minimum,
TimeDelta maximum,
size_t bucket_count,
Flags flags) {
return FactoryGet(minimum.InMilliseconds(), maximum.InMilliseconds(),
bucket_count, flags);
}
Histogram::ClassType LinearHistogram::histogram_type() const {
return LINEAR_HISTOGRAM;
}
@ -541,19 +521,6 @@ LinearHistogram::LinearHistogram(TimeDelta minimum,
maximum, bucket_count) {
}
void LinearHistogram::InitializeBucketRange() {
DCHECK_GT(declared_min(), 0); // 0 is the underflow bucket here.
double min = declared_min();
double max = declared_max();
size_t i;
for (i = 1; i < bucket_count(); ++i) {
double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) /
(bucket_count() - 2);
SetBucketRange(i, static_cast<int> (linear_range + 0.5));
}
ResetRangeChecksum();
}
double LinearHistogram::GetBucketSize(Count current, size_t i) const {
DCHECK_GT(ranges(i + 1), ranges(i));
// Adjacent buckets with different widths would have "surprisingly" many (few)
@ -579,11 +546,11 @@ bool LinearHistogram::PrintEmptyBucket(size_t index) const {
// This section provides implementation for BooleanHistogram.
//------------------------------------------------------------------------------
Histogram* BooleanHistogram::FactoryGet(Flags flags) {
Histogram* BooleanHistogram::FactoryGet(Flags flags, const int* buckets) {
Histogram* histogram(NULL);
BooleanHistogram* tentative_histogram = new BooleanHistogram();
tentative_histogram->InitializeBucketRange();
tentative_histogram->InitializeBucketRangeFromData(buckets);
tentative_histogram->SetFlags(flags);
histogram = tentative_histogram;
@ -616,12 +583,12 @@ BooleanHistogram::Accumulate(Sample value, Count count, size_t index)
//------------------------------------------------------------------------------
Histogram *
FlagHistogram::FactoryGet(Flags flags)
FlagHistogram::FactoryGet(Flags flags, const int* buckets)
{
Histogram *h(nullptr);
FlagHistogram *fh = new FlagHistogram();
fh->InitializeBucketRange();
fh->InitializeBucketRangeFromData(buckets);
fh->SetFlags(flags);
size_t zero_index = fh->BucketIndex(0);
fh->LinearHistogram::Accumulate(0, 1, zero_index);
@ -694,12 +661,12 @@ FlagHistogram::Clear() {
//------------------------------------------------------------------------------
Histogram *
CountHistogram::FactoryGet(Flags flags)
CountHistogram::FactoryGet(Flags flags, const int* buckets)
{
Histogram *h(nullptr);
CountHistogram *fh = new CountHistogram();
fh->InitializeBucketRange();
fh->InitializeBucketRangeFromData(buckets);
fh->SetFlags(flags);
h = fh;
@ -740,62 +707,4 @@ CountHistogram::AddSampleSet(const SampleSet& sample) {
}
}
//------------------------------------------------------------------------------
// CustomHistogram:
//------------------------------------------------------------------------------
Histogram* CustomHistogram::FactoryGet(const std::vector<Sample>& custom_ranges,
Flags flags) {
Histogram* histogram(NULL);
// Remove the duplicates in the custom ranges array.
std::vector<int> ranges = custom_ranges;
ranges.push_back(0); // Ensure we have a zero value.
std::sort(ranges.begin(), ranges.end());
ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
if (ranges.size() <= 1) {
DCHECK(false);
// Note that we pushed a 0 in above, so for defensive code....
ranges.push_back(1); // Put in some data so we can index to [1].
}
DCHECK_LT(ranges.back(), kSampleType_MAX);
CustomHistogram* custom_histogram = new CustomHistogram(ranges);
custom_histogram->InitializedCustomBucketRange(ranges);
custom_histogram->SetFlags(flags);
histogram = custom_histogram;
DCHECK_EQ(histogram->histogram_type(), CUSTOM_HISTOGRAM);
DCHECK(histogram->HasConstructorArguments(ranges[1], ranges.back(),
ranges.size()));
return histogram;
}
Histogram::ClassType CustomHistogram::histogram_type() const {
return CUSTOM_HISTOGRAM;
}
CustomHistogram::CustomHistogram(const std::vector<Sample>& custom_ranges)
: Histogram(custom_ranges[1], custom_ranges.back(),
custom_ranges.size()) {
DCHECK_GT(custom_ranges.size(), 1u);
DCHECK_EQ(custom_ranges[0], 0);
}
void CustomHistogram::InitializedCustomBucketRange(
const std::vector<Sample>& custom_ranges) {
DCHECK_GT(custom_ranges.size(), 1u);
DCHECK_EQ(custom_ranges[0], 0);
DCHECK_LE(custom_ranges.size(), bucket_count());
for (size_t index = 0; index < custom_ranges.size(); ++index)
SetBucketRange(index, custom_ranges[index]);
ResetRangeChecksum();
}
double CustomHistogram::GetBucketSize(Count current, size_t i) const {
return 1;
}
} // namespace base

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