зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound, a=merge
This commit is contained in:
Коммит
b851c06cc9
|
@ -73,7 +73,9 @@ EMBED_MANIFEST_AT = 2
|
|||
INSTALL_TARGETS += midl
|
||||
midl_FILES := $(filter %.h %_i.c,$(MIDL_GENERATED_FILES))
|
||||
midl_DEST = $(DIST)/include
|
||||
midl_TARGET := export
|
||||
midl_TARGET := midl
|
||||
|
||||
export:: midl
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -47,4 +47,6 @@ midl_exports := \
|
|||
INSTALL_TARGETS += midl_exports
|
||||
midl_exports_FILES := $(midl_exports)
|
||||
midl_exports_DEST = $(DIST)/include
|
||||
midl_exports_TARGET := export
|
||||
midl_exports_TARGET := midl
|
||||
|
||||
export:: midl
|
||||
|
|
|
@ -223,6 +223,6 @@ def gen_files(fd, conf_file, xpidllex, xpidlyacc):
|
|||
deps = set()
|
||||
conf, inc_dir = get_conf(conf_file)
|
||||
deps.update(print_header_file(fd, conf, inc_dir))
|
||||
with open('xpcAccEvents.cpp', 'w') as cpp_fd:
|
||||
with open(os.path.join(os.path.dirname(fd.name), 'xpcAccEvents.cpp'), 'w') as cpp_fd:
|
||||
deps.update(print_cpp_file(cpp_fd, conf, inc_dir))
|
||||
return deps
|
||||
|
|
|
@ -90,5 +90,5 @@ if CONFIG['MOZ_LINUX_32_SSE2_STARTUP_ERROR']:
|
|||
DEFINES['MOZ_LINUX_32_SSE2_STARTUP_ERROR'] = True
|
||||
|
||||
for icon in ('firefox', 'document', 'newwindow', 'newtab', 'pbmode'):
|
||||
DEFINES[icon.upper() + '_ICO'] = '"%s/dist/branding/%s.ico"' % (
|
||||
TOPOBJDIR, icon)
|
||||
DEFINES[icon.upper() + '_ICO'] = '"%s/%s/%s.ico"' % (
|
||||
TOPSRCDIR, CONFIG['MOZ_BRANDING_DIRECTORY'], icon)
|
||||
|
|
|
@ -924,9 +924,6 @@ extensions.on("shutdown", (type, extension) => {
|
|||
|
||||
// Manages mapping between XUL windows and extension window IDs.
|
||||
global.WindowManager = {
|
||||
_windows: new WeakMap(),
|
||||
_nextId: 0,
|
||||
|
||||
// Note: These must match the values in windows.json.
|
||||
WINDOW_ID_NONE: -1,
|
||||
WINDOW_ID_CURRENT: -2,
|
||||
|
@ -965,12 +962,11 @@ global.WindowManager = {
|
|||
},
|
||||
|
||||
getId(window) {
|
||||
if (this._windows.has(window)) {
|
||||
return this._windows.get(window);
|
||||
if (!window.QueryInterface) {
|
||||
return null;
|
||||
}
|
||||
let id = this._nextId++;
|
||||
this._windows.set(window, id);
|
||||
return id;
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
|
||||
},
|
||||
|
||||
getWindow(id, context) {
|
||||
|
|
|
@ -261,7 +261,7 @@ this.MigratorPrototype = {
|
|||
for (let resourceType of Object.keys(MigrationUtils._importQuantities)) {
|
||||
let histogramId =
|
||||
"FX_MIGRATION_" + resourceType.toUpperCase() + "_QUANTITY";
|
||||
let histogram = Services.telemetry.getKeyedHistogram(histogramId);
|
||||
let histogram = Services.telemetry.getKeyedHistogramById(histogramId);
|
||||
histogram.add(this.getKey(), MigrationUtils._importQuantities[resourceType]);
|
||||
}
|
||||
} catch (ex) { /* Telemetry is exception-happy */ }
|
||||
|
|
|
@ -18,24 +18,7 @@ else:
|
|||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
DIRS += ['annotationProcessors']
|
||||
|
||||
for var in ('GRE_MILESTONE', 'MOZ_APP_VERSION', 'MOZ_APP_BASENAME',
|
||||
'MOZ_APP_VENDOR', 'MOZ_APP_ID', 'MAR_CHANNEL_ID',
|
||||
'ACCEPTED_MAR_CHANNEL_IDS', 'MOZ_APP_REMOTINGNAME'):
|
||||
DEFINES[var] = CONFIG[var]
|
||||
|
||||
if CONFIG['MOZ_APP_DISPLAYNAME'] != CONFIG['MOZ_APP_BASENAME']:
|
||||
DEFINES['MOZ_APP_DISPLAYNAME'] = CONFIG['MOZ_APP_DISPLAYNAME']
|
||||
|
||||
if CONFIG['MOZ_BUILD_APP'] == 'browser':
|
||||
DEFINES['MOZ_BUILD_APP_IS_BROWSER'] = True
|
||||
|
||||
if CONFIG['MOZ_APP_PROFILE']:
|
||||
DEFINES['MOZ_APP_PROFILE'] = CONFIG['MOZ_APP_PROFILE']
|
||||
|
||||
for var in ('MOZ_CRASHREPORTER', 'MOZ_PROFILE_MIGRATOR',
|
||||
'MOZ_APP_STATIC_INI'):
|
||||
if CONFIG[var]:
|
||||
DEFINES[var] = True
|
||||
DEFINES['ACCEPTED_MAR_CHANNEL_IDS'] = CONFIG['ACCEPTED_MAR_CHANNEL_IDS']
|
||||
|
||||
if CONFIG['MOZ_BUILD_APP'] == 'browser':
|
||||
PYTHON_UNITTEST_MANIFESTS += [
|
||||
|
@ -63,7 +46,37 @@ if CONFIG['MOZ_ASAN'] and CONFIG['CLANG_CL']:
|
|||
FINAL_TARGET_FILES += ['%' + CONFIG['MOZ_CLANG_RT_ASAN_LIB_PATH']]
|
||||
|
||||
if CONFIG['MOZ_APP_BASENAME']:
|
||||
FINAL_TARGET_PP_FILES += ['application.ini']
|
||||
appini_defines = {
|
||||
'TOPOBJDIR': TOPOBJDIR,
|
||||
}
|
||||
|
||||
for var in ('GRE_MILESTONE', 'MOZ_APP_VERSION', 'MOZ_APP_BASENAME',
|
||||
'MOZ_APP_VENDOR', 'MOZ_APP_ID', 'MAR_CHANNEL_ID',
|
||||
'MOZ_APP_REMOTINGNAME'):
|
||||
appini_defines[var] = CONFIG[var]
|
||||
|
||||
if CONFIG['MOZ_APP_DISPLAYNAME'] != CONFIG['MOZ_APP_BASENAME']:
|
||||
appini_defines['MOZ_APP_DISPLAYNAME'] = CONFIG['MOZ_APP_DISPLAYNAME']
|
||||
|
||||
if CONFIG['MOZ_BUILD_APP'] == 'browser':
|
||||
appini_defines['MOZ_BUILD_APP_IS_BROWSER'] = True
|
||||
|
||||
if CONFIG['MOZ_APP_PROFILE']:
|
||||
appini_defines['MOZ_APP_PROFILE'] = CONFIG['MOZ_APP_PROFILE']
|
||||
|
||||
for var in ('MOZ_CRASHREPORTER', 'MOZ_PROFILE_MIGRATOR',
|
||||
'MOZ_APP_STATIC_INI'):
|
||||
if CONFIG[var]:
|
||||
appini_defines[var] = True
|
||||
|
||||
GENERATED_FILES += ['application.ini']
|
||||
|
||||
appini = GENERATED_FILES['application.ini']
|
||||
appini.script = '../python/mozbuild/mozbuild/action/preprocessor.py:generate'
|
||||
appini.inputs = ['application.ini.in']
|
||||
appini.flags = ['-D%s=%s' % (k, '1' if v is True else v)
|
||||
for k, v in appini_defines.iteritems()]
|
||||
FINAL_TARGET_FILES += ['!application.ini']
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android' and CONFIG['MOZ_UPDATER']:
|
||||
FINAL_TARGET_PP_FILES += ['update-settings.ini']
|
||||
|
||||
|
@ -71,9 +84,7 @@ if CONFIG['MOZ_APP_BASENAME']:
|
|||
GENERATED_FILES += ['application.ini.h']
|
||||
appini = GENERATED_FILES['application.ini.h']
|
||||
appini.script = 'appini_header.py'
|
||||
appini.inputs = ['!/dist/bin/application.ini']
|
||||
|
||||
DEFINES['TOPOBJDIR'] = TOPOBJDIR
|
||||
appini.inputs = ['!application.ini']
|
||||
|
||||
# NOTE: Keep .gdbinit in the topsrcdir for people who run gdb from the topsrcdir.
|
||||
OBJDIR_FILES += ['/.gdbinit']
|
||||
|
|
|
@ -108,3 +108,5 @@ endif
|
|||
# It also requires all the install manifests for dist/bin to have been processed
|
||||
# because it adds interfaces.manifest references with buildlist.py.
|
||||
$(TOPOBJDIR)/config/makefiles/xpidl/xpidl: $(addprefix install-,$(filter dist/bin%,$(INSTALL_MANIFESTS)))
|
||||
|
||||
$(TOPOBJDIR)/build/application.ini: $(TOPOBJDIR)/buildid.h $(TOPOBJDIR)/source-repo.h
|
||||
|
|
|
@ -35,6 +35,7 @@ tree.labels.Cache=Cache Storage
|
|||
# LOCALIZATION NOTE (table.headers.*.*):
|
||||
# These strings are the header names of the columns in the Storage Table for
|
||||
# each type of storage available through the Storage Tree to the side.
|
||||
table.headers.cookies.uniqueKey=Unique key
|
||||
table.headers.cookies.name=Name
|
||||
table.headers.cookies.path=Path
|
||||
table.headers.cookies.host=Domain
|
||||
|
|
|
@ -140,7 +140,6 @@ skip-if = true # Bug 1258809
|
|||
skip-if = true # Bug 1258809
|
||||
[browser_net_simple-request.js]
|
||||
[browser_net_sort-01.js]
|
||||
skip-if = (e10s && debug && os == 'mac') # Bug 1253037
|
||||
[browser_net_sort-02.js]
|
||||
[browser_net_sort-03.js]
|
||||
[browser_net_statistics-01.js]
|
||||
|
|
|
@ -615,8 +615,13 @@ TableWidget.prototype = {
|
|||
/**
|
||||
* Populates the header context menu with the names of the columns along with
|
||||
* displaying which columns are hidden or visible.
|
||||
*
|
||||
* @param {Array} privateColumns=[]
|
||||
* An array of column names that should never appear in the table. This
|
||||
* allows us to e.g. have an invisible compound primary key for a
|
||||
* table's rows.
|
||||
*/
|
||||
populateMenuPopup: function () {
|
||||
populateMenuPopup: function (privateColumns = []) {
|
||||
if (!this.menupopup) {
|
||||
return;
|
||||
}
|
||||
|
@ -626,6 +631,10 @@ TableWidget.prototype = {
|
|||
}
|
||||
|
||||
for (let column of this.columns.values()) {
|
||||
if (privateColumns.includes(column.id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let menuitem = this.document.createElementNS(XUL_NS, "menuitem");
|
||||
menuitem.setAttribute("label", column.header.getAttribute("value"));
|
||||
menuitem.setAttribute("data-id", column.id);
|
||||
|
@ -663,16 +672,21 @@ TableWidget.prototype = {
|
|||
* Creates the columns in the table. Without calling this method, data cannot
|
||||
* be inserted into the table unless `initialColumns` was supplied.
|
||||
*
|
||||
* @param {object} columns
|
||||
* @param {Object} columns
|
||||
* A key value pair representing the columns of the table. Where the
|
||||
* key represents the id of the column and the value is the displayed
|
||||
* label in the header of the column.
|
||||
* @param {string} sortOn
|
||||
* @param {String} sortOn
|
||||
* The id of the column on which the table will be initially sorted on.
|
||||
* @param {array} hiddenColumns
|
||||
* @param {Array} hiddenColumns
|
||||
* Ids of all the columns that are hidden by default.
|
||||
* @param {Array} privateColumns=[]
|
||||
* An array of column names that should never appear in the table. This
|
||||
* allows us to e.g. have an invisible compound primary key for a
|
||||
* table's rows.
|
||||
*/
|
||||
setColumns: function (columns, sortOn = this.sortedOn, hiddenColumns = []) {
|
||||
setColumns: function (columns, sortOn = this.sortedOn, hiddenColumns = [],
|
||||
privateColumns = []) {
|
||||
for (let column of this.columns.values()) {
|
||||
column.destroy();
|
||||
}
|
||||
|
@ -702,13 +716,14 @@ TableWidget.prototype = {
|
|||
}
|
||||
|
||||
this.columns.set(id, new Column(this, id, columns[id]));
|
||||
if (hiddenColumns.indexOf(id) > -1) {
|
||||
if (hiddenColumns.includes(id) || privateColumns.includes(id)) {
|
||||
// Hide the column.
|
||||
this.columns.get(id).toggleColumn();
|
||||
}
|
||||
}
|
||||
this.sortedOn = sortOn;
|
||||
this.sortBy(this.sortedOn);
|
||||
this.populateMenuPopup();
|
||||
this.populateMenuPopup(privateColumns);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -778,6 +793,11 @@ TableWidget.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.editBookmark && !this.items.has(this.editBookmark)) {
|
||||
// Key has been updated... update bookmark.
|
||||
this.editBookmark = item[this.uniqueId];
|
||||
}
|
||||
|
||||
let index = this.columns.get(this.sortedOn).push(item);
|
||||
for (let [key, column] of this.columns) {
|
||||
if (key != this.sortedOn) {
|
||||
|
|
|
@ -29,7 +29,9 @@ support-files =
|
|||
[browser_storage_delete.js]
|
||||
[browser_storage_delete_all.js]
|
||||
[browser_storage_delete_tree.js]
|
||||
[browser_storage_dynamic_updates.js]
|
||||
[browser_storage_dynamic_updates_cookies.js]
|
||||
[browser_storage_dynamic_updates_localStorage.js]
|
||||
[browser_storage_dynamic_updates_sessionStorage.js]
|
||||
[browser_storage_empty_objectstores.js]
|
||||
[browser_storage_indexeddb_delete.js]
|
||||
[browser_storage_indexeddb_delete_blocked.js]
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
/* import-globals-from head.js */
|
||||
|
||||
// Basic test to assert that the storage tree and table corresponding to each
|
||||
// item in the storage tree is correctly displayed
|
||||
|
||||
|
@ -21,10 +23,23 @@
|
|||
"use strict";
|
||||
|
||||
const testCases = [
|
||||
[["cookies", "test1.example.org"],
|
||||
["c1", "cs2", "c3", "uc1"]],
|
||||
[["cookies", "sectest1.example.org"],
|
||||
["uc1", "cs2", "sc1"]],
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
[
|
||||
getCookieId("c1", "test1.example.org", "/browser"),
|
||||
getCookieId("cs2", ".example.org", "/"),
|
||||
getCookieId("c3", "test1.example.org", "/"),
|
||||
getCookieId("uc1", ".example.org", "/")
|
||||
]
|
||||
],
|
||||
[
|
||||
["cookies", "sectest1.example.org"],
|
||||
[
|
||||
getCookieId("uc1", ".example.org", "/"),
|
||||
getCookieId("cs2", ".example.org", "/"),
|
||||
getCookieId("sc1", "sectest1.example.org", "/browser/devtools/client/storage/test/")
|
||||
]
|
||||
],
|
||||
[["localStorage", "http://test1.example.org"],
|
||||
["ls1", "ls2"]],
|
||||
[["localStorage", "http://sectest1.example.org"],
|
||||
|
|
|
@ -21,8 +21,8 @@ function* performDelete(store, rowName, deleteAll) {
|
|||
yield selectTreeItem(store);
|
||||
|
||||
let eventWait = gUI.once("store-objects-updated");
|
||||
let cells = getRowCells(rowName, true);
|
||||
|
||||
let cells = getRowCells(rowName);
|
||||
yield waitForContextMenu(contextMenu, cells.name, () => {
|
||||
info(`Opened context menu in ${storeName}, row '${rowName}'`);
|
||||
if (deleteAll) {
|
||||
|
@ -43,24 +43,54 @@ add_task(function* () {
|
|||
|
||||
info("test state before delete");
|
||||
yield checkState([
|
||||
[["cookies", "test1.example.org"], ["c1", "c3", "cs2", "uc1"]],
|
||||
[["cookies", "sectest1.example.org"], ["cs2", "sc1", "uc1"]],
|
||||
[
|
||||
["cookies", "test1.example.org"], [
|
||||
getCookieId("c1", "test1.example.org", "/browser"),
|
||||
getCookieId("c3", "test1.example.org", "/"),
|
||||
getCookieId("cs2", ".example.org", "/"),
|
||||
getCookieId("uc1", ".example.org", "/")
|
||||
]
|
||||
],
|
||||
[
|
||||
["cookies", "sectest1.example.org"], [
|
||||
getCookieId("cs2", ".example.org", "/"),
|
||||
getCookieId("sc1", "sectest1.example.org",
|
||||
"/browser/devtools/client/storage/test/"),
|
||||
getCookieId("uc1", ".example.org", "/")
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
info("delete all from domain");
|
||||
// delete only cookies that match the host exactly
|
||||
yield performDelete(["cookies", "test1.example.org"], "c1", false);
|
||||
let id = getCookieId("c1", "test1.example.org", "/browser");
|
||||
yield performDelete(["cookies", "test1.example.org"], id, false);
|
||||
|
||||
info("test state after delete all from domain");
|
||||
yield checkState([
|
||||
// Domain cookies (.example.org) must not be deleted.
|
||||
[["cookies", "test1.example.org"], ["cs2", "uc1"]],
|
||||
[["cookies", "sectest1.example.org"], ["cs2", "sc1", "uc1"]],
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
[
|
||||
getCookieId("cs2", ".example.org", "/"),
|
||||
getCookieId("uc1", ".example.org", "/")
|
||||
]
|
||||
],
|
||||
[
|
||||
["cookies", "sectest1.example.org"],
|
||||
[
|
||||
getCookieId("cs2", ".example.org", "/"),
|
||||
getCookieId("uc1", ".example.org", "/"),
|
||||
getCookieId("sc1", "sectest1.example.org",
|
||||
"/browser/devtools/client/storage/test/"),
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
info("delete all");
|
||||
// delete all cookies for host, including domain cookies
|
||||
yield performDelete(["cookies", "sectest1.example.org"], "uc1", true);
|
||||
id = getCookieId("uc1", ".example.org", "/");
|
||||
yield performDelete(["cookies", "sectest1.example.org"], id, true);
|
||||
|
||||
info("test state after delete all");
|
||||
yield checkState([
|
||||
|
|
|
@ -13,8 +13,16 @@ add_task(function* () {
|
|||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
|
||||
|
||||
yield checkState([
|
||||
[["cookies", "test1.example.org"],
|
||||
["test1", "test2", "test3", "test4", "test5"]],
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
[
|
||||
getCookieId("test1", ".test1.example.org", "/browser"),
|
||||
getCookieId("test2", "test1.example.org", "/browser"),
|
||||
getCookieId("test3", ".test1.example.org", "/browser"),
|
||||
getCookieId("test4", "test1.example.org", "/browser"),
|
||||
getCookieId("test5", ".test1.example.org", "/browser")
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
yield finishTests();
|
||||
|
|
|
@ -10,13 +10,20 @@ add_task(function* () {
|
|||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
|
||||
showAllColumns(true);
|
||||
|
||||
yield editCell("test3", "name", "newTest3");
|
||||
yield editCell("newTest3", "path", "/");
|
||||
yield editCell("newTest3", "host", "test1.example.org");
|
||||
yield editCell("newTest3", "expires", "Tue, 14 Feb 2040 17:41:14 GMT");
|
||||
yield editCell("newTest3", "value", "newValue3");
|
||||
yield editCell("newTest3", "isSecure", "true");
|
||||
yield editCell("newTest3", "isHttpOnly", "true");
|
||||
let id = getCookieId("test3", ".test1.example.org", "/browser");
|
||||
yield editCell(id, "name", "newTest3");
|
||||
|
||||
id = getCookieId("newTest3", ".test1.example.org", "/browser");
|
||||
yield editCell(id, "host", "test1.example.org");
|
||||
|
||||
id = getCookieId("newTest3", "test1.example.org", "/browser");
|
||||
yield editCell(id, "path", "/");
|
||||
|
||||
id = getCookieId("newTest3", "test1.example.org", "/");
|
||||
yield editCell(id, "expires", "Tue, 14 Feb 2040 17:41:14 GMT");
|
||||
yield editCell(id, "value", "newValue3");
|
||||
yield editCell(id, "isSecure", "true");
|
||||
yield editCell(id, "isHttpOnly", "true");
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
|
@ -10,10 +10,11 @@ add_task(function* () {
|
|||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
|
||||
showAllColumns(true);
|
||||
|
||||
yield startCellEdit("test4", "name");
|
||||
let id = getCookieId("test4", "test1.example.org", "/browser");
|
||||
yield startCellEdit(id, "name");
|
||||
yield typeWithTerminator("test6", "VK_TAB");
|
||||
yield typeWithTerminator("/", "VK_TAB");
|
||||
yield typeWithTerminator(".example.org", "VK_TAB");
|
||||
yield typeWithTerminator("/", "VK_TAB");
|
||||
yield typeWithTerminator("Tue, 25 Dec 2040 12:00:00 GMT", "VK_TAB");
|
||||
yield typeWithTerminator("test6value", "VK_TAB");
|
||||
yield typeWithTerminator("false", "VK_TAB");
|
||||
|
|
|
@ -10,7 +10,8 @@ add_task(function* () {
|
|||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
|
||||
showAllColumns(true);
|
||||
|
||||
yield startCellEdit("test1", "name");
|
||||
let id = getCookieId("test1", ".test1.example.org", "/browser");
|
||||
yield startCellEdit(id, "name");
|
||||
|
||||
PressKeyXTimes("VK_TAB", 18);
|
||||
is(getCurrentEditorValue(), "value3",
|
||||
|
|
|
@ -13,8 +13,10 @@ const TEST_CASES = [
|
|||
"ls1", "name"],
|
||||
[["sessionStorage", "http://test1.example.org"],
|
||||
"ss1", "name"],
|
||||
[["cookies", "test1.example.org"],
|
||||
"c1", "name"],
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
getCookieId("c1", "test1.example.org", "/browser"), "name"
|
||||
],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
1, "name"],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
|
@ -41,7 +43,7 @@ add_task(function* () {
|
|||
yield waitForContextMenu(contextMenu, row[cellToClick], () => {
|
||||
info(`Opened context menu in ${treeItemName}, row '${rowName}'`);
|
||||
menuDeleteItem.click();
|
||||
let truncatedRowName = String(rowName).substr(0, 16);
|
||||
let truncatedRowName = String(rowName).replace(SEPARATOR_GUID, "-").substr(0, 16);
|
||||
ok(menuDeleteItem.getAttribute("label").includes(truncatedRowName),
|
||||
`Context menu item label contains '${rowName}' (maybe truncated)`);
|
||||
});
|
||||
|
|
|
@ -17,7 +17,15 @@ add_task(function* () {
|
|||
|
||||
info("test state before delete");
|
||||
yield checkState([
|
||||
[["cookies", "test1.example.org"], ["c1", "c3", "cs2", "uc1"]],
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
[
|
||||
getCookieId("c1", "test1.example.org", "/browser"),
|
||||
getCookieId("cs2", ".example.org", "/"),
|
||||
getCookieId("c3", "test1.example.org", "/"),
|
||||
getCookieId("uc1", ".example.org", "/")
|
||||
]
|
||||
],
|
||||
[["localStorage", "http://test1.example.org"], ["ls1", "ls2"]],
|
||||
[["sessionStorage", "http://test1.example.org"], ["ss1"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"], [1, 2, 3]],
|
||||
|
|
|
@ -1,213 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-updates.html");
|
||||
|
||||
let $ = id => gPanelWindow.document.querySelector(id);
|
||||
let $$ = sel => gPanelWindow.document.querySelectorAll(sel);
|
||||
|
||||
gUI.tree.expandAll();
|
||||
|
||||
ok(gUI.sidebar.hidden, "Sidebar is initially hidden");
|
||||
yield selectTableItem("c1");
|
||||
|
||||
// test that value is something initially
|
||||
let initialValue = [[
|
||||
{name: "c1", value: "1.2.3.4.5.6.7"},
|
||||
{name: "c1.Path", value: "/browser"}
|
||||
], [
|
||||
{name: "c1", value: "Array"},
|
||||
{name: "c1.0", value: "1"},
|
||||
{name: "c1.6", value: "7"}
|
||||
]];
|
||||
|
||||
// test that value is something initially
|
||||
let finalValue = [[
|
||||
{name: "c1", value: '{"foo": 4,"bar":6}'},
|
||||
{name: "c1.Path", value: "/browser"}
|
||||
], [
|
||||
{name: "c1", value: "Object"},
|
||||
{name: "c1.foo", value: "4"},
|
||||
{name: "c1.bar", value: "6"}
|
||||
]];
|
||||
// Check that sidebar shows correct initial value
|
||||
yield findVariableViewProperties(initialValue[0], false);
|
||||
yield findVariableViewProperties(initialValue[1], true);
|
||||
// Check if table shows correct initial value
|
||||
ok($("#value [data-id='c1'].table-widget-cell"), "cell is present");
|
||||
is($("#value [data-id='c1'].table-widget-cell").value, "1.2.3.4.5.6.7",
|
||||
"correct initial value in table");
|
||||
gWindow.addCookie("c1", '{"foo": 4,"bar":6}', "/browser");
|
||||
yield gUI.once("sidebar-updated");
|
||||
|
||||
yield findVariableViewProperties(finalValue[0], false);
|
||||
yield findVariableViewProperties(finalValue[1], true);
|
||||
ok($("#value [data-id='c1'].table-widget-cell"),
|
||||
"cell is present after update");
|
||||
is($("#value [data-id='c1'].table-widget-cell").value, '{"foo": 4,"bar":6}',
|
||||
"correct final value in table");
|
||||
|
||||
// Add a new entry
|
||||
is($$("#value .table-widget-cell").length, 2,
|
||||
"Correct number of rows before update 0");
|
||||
|
||||
gWindow.addCookie("c3", "booyeah");
|
||||
|
||||
// Wait once for update and another time for value fetching
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 3,
|
||||
"Correct number of rows after update 1");
|
||||
|
||||
// Add another
|
||||
gWindow.addCookie("c4", "booyeah");
|
||||
|
||||
// Wait once for update and another time for value fetching
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 4,
|
||||
"Correct number of rows after update 2");
|
||||
|
||||
// Removing cookies
|
||||
gWindow.removeCookie("c1", "/browser");
|
||||
|
||||
yield gUI.once("sidebar-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 3,
|
||||
"Correct number of rows after delete update 3");
|
||||
|
||||
ok(!$("#c1"), "Correct row got deleted");
|
||||
|
||||
ok(!gUI.sidebar.hidden, "Sidebar still visible for next row");
|
||||
|
||||
// Check if next element's value is visible in sidebar
|
||||
yield findVariableViewProperties([{name: "c2", value: "foobar"}]);
|
||||
|
||||
// Keep deleting till no rows
|
||||
|
||||
gWindow.removeCookie("c3");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 2,
|
||||
"Correct number of rows after delete update 4");
|
||||
|
||||
// Check if next element's value is visible in sidebar
|
||||
yield findVariableViewProperties([{name: "c2", value: "foobar"}]);
|
||||
|
||||
gWindow.removeCookie("c2", "/browser");
|
||||
|
||||
yield gUI.once("sidebar-updated");
|
||||
|
||||
yield findVariableViewProperties([{name: "c4", value: "booyeah"}]);
|
||||
|
||||
is($$("#value .table-widget-cell").length, 1,
|
||||
"Correct number of rows after delete update 5");
|
||||
|
||||
gWindow.removeCookie("c4");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 0,
|
||||
"Correct number of rows after delete update 6");
|
||||
ok(gUI.sidebar.hidden, "Sidebar is hidden when no rows");
|
||||
|
||||
// Testing in local storage
|
||||
yield selectTreeItem(["localStorage", "http://test1.example.org"]);
|
||||
|
||||
is($$("#value .table-widget-cell").length, 7,
|
||||
"Correct number of rows after delete update 7");
|
||||
|
||||
ok($(".table-widget-cell[data-id='ls4']"), "ls4 exists before deleting");
|
||||
|
||||
gWindow.localStorage.removeItem("ls4");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 6,
|
||||
"Correct number of rows after delete update 8");
|
||||
ok(!$(".table-widget-cell[data-id='ls4']"),
|
||||
"ls4 does not exists after deleting");
|
||||
|
||||
gWindow.localStorage.setItem("ls4", "again");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 7,
|
||||
"Correct number of rows after delete update 9");
|
||||
ok($(".table-widget-cell[data-id='ls4']"),
|
||||
"ls4 came back after adding it again");
|
||||
|
||||
// Updating a row
|
||||
gWindow.localStorage.setItem("ls2", "ls2-changed");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($("#value [data-id='ls2']").value, "ls2-changed",
|
||||
"Value got updated for local storage");
|
||||
|
||||
// Testing in session storage
|
||||
yield selectTreeItem(["sessionStorage", "http://test1.example.org"]);
|
||||
|
||||
is($$("#value .table-widget-cell").length, 3,
|
||||
"Correct number of rows for session storage");
|
||||
|
||||
gWindow.sessionStorage.setItem("ss4", "new-item");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 4,
|
||||
"Correct number of rows after session storage update");
|
||||
|
||||
// deleting item
|
||||
|
||||
gWindow.sessionStorage.removeItem("ss3");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
gWindow.sessionStorage.removeItem("ss1");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 2,
|
||||
"Correct number of rows after removing items from session storage");
|
||||
|
||||
yield selectTableItem("ss2");
|
||||
|
||||
ok(!gUI.sidebar.hidden, "sidebar is visible");
|
||||
|
||||
// Checking for correct value in sidebar before update
|
||||
yield findVariableViewProperties([{name: "ss2", value: "foobar"}]);
|
||||
|
||||
gWindow.sessionStorage.setItem("ss2", "changed=ss2");
|
||||
|
||||
yield gUI.once("sidebar-updated");
|
||||
|
||||
is($("#value [data-id='ss2']").value, "changed=ss2",
|
||||
"Value got updated for session storage in the table");
|
||||
|
||||
yield findVariableViewProperties([{name: "ss2", value: "changed=ss2"}]);
|
||||
|
||||
// Clearing items. Bug 1233497 makes it so that we can no longer yield
|
||||
// CPOWs from Tasks. We work around this by calling clear via a ContentTask
|
||||
// instead.
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
|
||||
return Task.spawn(content.wrappedJSObject.clear);
|
||||
});
|
||||
|
||||
yield gUI.once("store-objects-cleared");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 0,
|
||||
"Table should be cleared");
|
||||
|
||||
yield finishTests();
|
||||
});
|
|
@ -0,0 +1,188 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test dynamic updates in the storage inspector for cookies.
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-updates.html");
|
||||
|
||||
gUI.tree.expandAll();
|
||||
|
||||
ok(gUI.sidebar.hidden, "Sidebar is initially hidden");
|
||||
let c1id = getCookieId("c1", "test1.example.org", "/browser");
|
||||
yield selectTableItem(c1id);
|
||||
|
||||
// test that value is something initially
|
||||
let initialValue = [[
|
||||
{name: "c1", value: "1.2.3.4.5.6.7"},
|
||||
{name: "c1.Path", value: "/browser"}
|
||||
], [
|
||||
{name: "c1", value: "Array"},
|
||||
{name: "c1.0", value: "1"},
|
||||
{name: "c1.6", value: "7"}
|
||||
]];
|
||||
|
||||
// test that value is something initially
|
||||
let finalValue = [[
|
||||
{name: "c1", value: '{"foo": 4,"bar":6}'},
|
||||
{name: "c1.Path", value: "/browser"}
|
||||
], [
|
||||
{name: "c1", value: "Object"},
|
||||
{name: "c1.foo", value: "4"},
|
||||
{name: "c1.bar", value: "6"}
|
||||
]];
|
||||
|
||||
// Check that sidebar shows correct initial value
|
||||
yield findVariableViewProperties(initialValue[0], false);
|
||||
|
||||
yield findVariableViewProperties(initialValue[1], true);
|
||||
// Check if table shows correct initial value
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
[
|
||||
getCookieId("c1", "test1.example.org", "/browser"),
|
||||
getCookieId("c2", "test1.example.org", "/browser")
|
||||
]
|
||||
],
|
||||
]);
|
||||
checkCell(c1id, "value", "1.2.3.4.5.6.7");
|
||||
|
||||
gWindow.addCookie("c1", '{"foo": 4,"bar":6}', "/browser");
|
||||
yield gUI.once("sidebar-updated");
|
||||
|
||||
yield findVariableViewProperties(finalValue[0], false);
|
||||
yield findVariableViewProperties(finalValue[1], true);
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
[
|
||||
getCookieId("c1", "test1.example.org", "/browser"),
|
||||
getCookieId("c2", "test1.example.org", "/browser")
|
||||
]
|
||||
],
|
||||
]);
|
||||
checkCell(c1id, "value", '{"foo": 4,"bar":6}');
|
||||
|
||||
// Add a new entry
|
||||
gWindow.addCookie("c3", "booyeah");
|
||||
|
||||
// Wait once for update and another time for value fetching
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
[
|
||||
getCookieId("c1", "test1.example.org", "/browser"),
|
||||
getCookieId("c2", "test1.example.org", "/browser"),
|
||||
getCookieId("c3", "test1.example.org",
|
||||
"/browser/devtools/client/storage/test/")
|
||||
]
|
||||
],
|
||||
]);
|
||||
let c3id = getCookieId("c3", "test1.example.org",
|
||||
"/browser/devtools/client/storage/test/");
|
||||
checkCell(c3id, "value", "booyeah");
|
||||
|
||||
// Add another
|
||||
gWindow.addCookie("c4", "booyeah");
|
||||
|
||||
// Wait once for update and another time for value fetching
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
[
|
||||
getCookieId("c1", "test1.example.org", "/browser"),
|
||||
getCookieId("c2", "test1.example.org", "/browser"),
|
||||
getCookieId("c3", "test1.example.org",
|
||||
"/browser/devtools/client/storage/test/"),
|
||||
getCookieId("c4", "test1.example.org",
|
||||
"/browser/devtools/client/storage/test/")
|
||||
]
|
||||
],
|
||||
]);
|
||||
let c4id = getCookieId("c4", "test1.example.org",
|
||||
"/browser/devtools/client/storage/test/");
|
||||
checkCell(c4id, "value", "booyeah");
|
||||
|
||||
// Removing cookies
|
||||
gWindow.removeCookie("c1", "/browser");
|
||||
|
||||
yield gUI.once("sidebar-updated");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
[
|
||||
getCookieId("c2", "test1.example.org", "/browser"),
|
||||
getCookieId("c3", "test1.example.org",
|
||||
"/browser/devtools/client/storage/test/"),
|
||||
getCookieId("c4", "test1.example.org",
|
||||
"/browser/devtools/client/storage/test/")
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
ok(!gUI.sidebar.hidden, "Sidebar still visible for next row");
|
||||
|
||||
// Check if next element's value is visible in sidebar
|
||||
yield findVariableViewProperties([{name: "c2", value: "foobar"}]);
|
||||
|
||||
// Keep deleting till no rows
|
||||
gWindow.removeCookie("c3");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
[
|
||||
getCookieId("c2", "test1.example.org", "/browser"),
|
||||
getCookieId("c4", "test1.example.org",
|
||||
"/browser/devtools/client/storage/test/")
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
// Check if next element's value is visible in sidebar
|
||||
yield findVariableViewProperties([{name: "c2", value: "foobar"}]);
|
||||
|
||||
gWindow.removeCookie("c2", "/browser");
|
||||
|
||||
yield gUI.once("sidebar-updated");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["cookies", "test1.example.org"],
|
||||
[
|
||||
getCookieId("c4", "test1.example.org",
|
||||
"/browser/devtools/client/storage/test/")
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
// Check if next element's value is visible in sidebar
|
||||
yield findVariableViewProperties([{name: "c4", value: "booyeah"}]);
|
||||
|
||||
gWindow.removeCookie("c4");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
yield checkState([
|
||||
[["cookies", "test1.example.org"], [ ]],
|
||||
]);
|
||||
|
||||
ok(gUI.sidebar.hidden, "Sidebar is hidden when no rows");
|
||||
|
||||
yield finishTests();
|
||||
});
|
|
@ -0,0 +1,70 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test dynamic updates in the storage inspector for localStorage.
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-updates.html");
|
||||
|
||||
gUI.tree.expandAll();
|
||||
|
||||
ok(gUI.sidebar.hidden, "Sidebar is initially hidden");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["localStorage", "http://test1.example.org"],
|
||||
["ls1", "ls2", "ls3", "ls4", "ls5", "ls6", "ls7"]
|
||||
],
|
||||
]);
|
||||
|
||||
gWindow.localStorage.removeItem("ls4");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["localStorage", "http://test1.example.org"],
|
||||
["ls1", "ls2", "ls3", "ls5", "ls6", "ls7"]
|
||||
],
|
||||
]);
|
||||
|
||||
gWindow.localStorage.setItem("ls4", "again");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["localStorage", "http://test1.example.org"],
|
||||
["ls1", "ls2", "ls3", "ls4", "ls5", "ls6", "ls7"]
|
||||
],
|
||||
]);
|
||||
// Updating a row
|
||||
gWindow.localStorage.setItem("ls2", "ls2-changed");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
checkCell("ls2", "value", "ls2-changed");
|
||||
|
||||
// Clearing items. Bug 1233497 makes it so that we can no longer yield
|
||||
// CPOWs from Tasks. We work around this by calling clear via a ContentTask
|
||||
// instead.
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
|
||||
return Task.spawn(content.wrappedJSObject.clear);
|
||||
});
|
||||
|
||||
yield gUI.once("store-objects-cleared");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["localStorage", "http://test1.example.org"],
|
||||
[ ]
|
||||
],
|
||||
]);
|
||||
|
||||
yield finishTests();
|
||||
});
|
|
@ -0,0 +1,84 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test dynamic updates in the storage inspector for sessionStorage.
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-updates.html");
|
||||
|
||||
gUI.tree.expandAll();
|
||||
|
||||
ok(gUI.sidebar.hidden, "Sidebar is initially hidden");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["sessionStorage", "http://test1.example.org"],
|
||||
["ss1", "ss2", "ss3"]
|
||||
],
|
||||
]);
|
||||
|
||||
gWindow.sessionStorage.setItem("ss4", "new-item");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["sessionStorage", "http://test1.example.org"],
|
||||
["ss1", "ss2", "ss3", "ss4"]
|
||||
],
|
||||
]);
|
||||
|
||||
// deleting item
|
||||
|
||||
gWindow.sessionStorage.removeItem("ss3");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
gWindow.sessionStorage.removeItem("ss1");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["sessionStorage", "http://test1.example.org"],
|
||||
["ss2", "ss4"]
|
||||
],
|
||||
]);
|
||||
|
||||
yield selectTableItem("ss2");
|
||||
|
||||
ok(!gUI.sidebar.hidden, "sidebar is visible");
|
||||
|
||||
// Checking for correct value in sidebar before update
|
||||
yield findVariableViewProperties([{name: "ss2", value: "foobar"}]);
|
||||
|
||||
gWindow.sessionStorage.setItem("ss2", "changed=ss2");
|
||||
|
||||
yield gUI.once("sidebar-updated");
|
||||
|
||||
checkCell("ss2", "value", "changed=ss2");
|
||||
|
||||
yield findVariableViewProperties([{name: "ss2", value: "changed=ss2"}]);
|
||||
|
||||
// Clearing items. Bug 1233497 makes it so that we can no longer yield
|
||||
// CPOWs from Tasks. We work around this by calling clear via a ContentTask
|
||||
// instead.
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
|
||||
return Task.spawn(content.wrappedJSObject.clear);
|
||||
});
|
||||
|
||||
yield gUI.once("store-objects-cleared");
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["sessionStorage", "http://test1.example.org"],
|
||||
[ ]
|
||||
],
|
||||
]);
|
||||
|
||||
yield finishTests();
|
||||
});
|
|
@ -20,22 +20,22 @@ const testCases = [
|
|||
sidebarHidden: true
|
||||
},
|
||||
{
|
||||
location: "cs2",
|
||||
location: getCookieId("cs2", ".example.org", "/"),
|
||||
sidebarHidden: false
|
||||
},
|
||||
{
|
||||
sendEscape: true
|
||||
},
|
||||
{
|
||||
location: "cs2",
|
||||
location: getCookieId("cs2", ".example.org", "/"),
|
||||
sidebarHidden: false
|
||||
},
|
||||
{
|
||||
location: "uc1",
|
||||
location: getCookieId("uc1", ".example.org", "/"),
|
||||
sidebarHidden: false
|
||||
},
|
||||
{
|
||||
location: "uc1",
|
||||
location: getCookieId("uc1", ".example.org", "/"),
|
||||
sidebarHidden: false
|
||||
},
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
const LONG_WORD = "a".repeat(1000);
|
||||
|
||||
const testCases = [
|
||||
["cs2", [
|
||||
[getCookieId("cs2", ".example.org", "/"), [
|
||||
{name: "cs2", value: "sessionCookie"},
|
||||
{name: "cs2.Path", value: "/"},
|
||||
{name: "cs2.HostOnly", value: "false"},
|
||||
|
@ -26,7 +26,7 @@ const testCases = [
|
|||
{name: "cs2.Expires", value: "Session"},
|
||||
{name: "cs2.Secure", value: "false"},
|
||||
]],
|
||||
["c1", [
|
||||
[getCookieId("c1", "test1.example.org", "/browser"), [
|
||||
{name: "c1", value: JSON.stringify(["foo", "Bar", {foo: "Bar"}])},
|
||||
{name: "c1.Path", value: "/browser"},
|
||||
{name: "c1.HostOnly", value: "true"},
|
||||
|
@ -42,9 +42,13 @@ const testCases = [
|
|||
{name: "c1.2", value: "Object"},
|
||||
{name: "c1.2.foo", value: "Bar"},
|
||||
], true],
|
||||
["c_encoded", [
|
||||
{name: "c_encoded", value: encodeURIComponent(JSON.stringify({foo: {foo1: "bar"}}))}
|
||||
]],
|
||||
[
|
||||
getCookieId("c_encoded", "test1.example.org",
|
||||
"/browser/devtools/client/storage/test/"),
|
||||
[
|
||||
{name: "c_encoded", value: encodeURIComponent(JSON.stringify({foo: {foo1: "bar"}}))}
|
||||
]
|
||||
],
|
||||
[null, [
|
||||
{name: "c_encoded", value: "Object"},
|
||||
{name: "c_encoded.foo", value: "Object"},
|
||||
|
|
|
@ -24,6 +24,11 @@ const MAIN_DOMAIN = "http://test1.example.org/" + PATH;
|
|||
const ALT_DOMAIN = "http://sectest1.example.org/" + PATH;
|
||||
const ALT_DOMAIN_SECURED = "https://sectest1.example.org:443/" + PATH;
|
||||
|
||||
// GUID to be used as a separator in compound keys. This must match the same
|
||||
// constant in devtools/server/actors/storage.js,
|
||||
// devtools/client/storage/ui.js and devtools/server/tests/browser/head.js
|
||||
const SEPARATOR_GUID = "{9d414cc5-8319-0a04-0586-c0a6ae01670a}";
|
||||
|
||||
var gToolbox, gPanelWindow, gWindow, gUI;
|
||||
|
||||
// Services.prefs.setBoolPref(DUMPEMIT_PREF, true);
|
||||
|
@ -505,10 +510,17 @@ function* selectTreeItem(ids) {
|
|||
* The id of the row in the table widget
|
||||
*/
|
||||
function* selectTableItem(id) {
|
||||
let selector = ".table-widget-cell[data-id='" + id + "']";
|
||||
let table = gUI.table;
|
||||
let selector = ".table-widget-column#" + table.uniqueId +
|
||||
" .table-widget-cell[value='" + id + "']";
|
||||
let target = gPanelWindow.document.querySelector(selector);
|
||||
|
||||
ok(target, "table item found with ids " + id);
|
||||
|
||||
if (!target) {
|
||||
showAvailableIds();
|
||||
}
|
||||
|
||||
yield click(target);
|
||||
yield gUI.once("sidebar-updated");
|
||||
}
|
||||
|
@ -586,21 +598,38 @@ function getRowCells(id, includeHidden = false) {
|
|||
|
||||
if (!item) {
|
||||
ok(false, "Row id '" + id + "' exists");
|
||||
|
||||
showAvailableIds();
|
||||
}
|
||||
|
||||
let index = table.columns.get(table.uniqueId).visibleCellNodes.indexOf(item);
|
||||
let index = table.columns.get(table.uniqueId).cellNodes.indexOf(item);
|
||||
let cells = {};
|
||||
|
||||
for (let [name, column] of [...table.columns]) {
|
||||
if (!includeHidden && column.column.parentNode.hidden) {
|
||||
continue;
|
||||
}
|
||||
cells[name] = column.visibleCellNodes[index];
|
||||
cells[name] = column.cellNodes[index];
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show available ids.
|
||||
*/
|
||||
function showAvailableIds() {
|
||||
let doc = gPanelWindow.document;
|
||||
let table = gUI.table;
|
||||
|
||||
info("Available ids:");
|
||||
let cells = doc.querySelectorAll(".table-widget-column#" + table.uniqueId +
|
||||
" .table-widget-cell");
|
||||
for (let cell of cells) {
|
||||
info(" - " + cell.getAttribute("value"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a cell value.
|
||||
*
|
||||
|
@ -798,9 +827,18 @@ function* checkState(state) {
|
|||
|
||||
is(items.size, names.length,
|
||||
`There is correct number of rows in ${storeName}`);
|
||||
|
||||
if (names.length === 0) {
|
||||
showAvailableIds();
|
||||
}
|
||||
|
||||
for (let name of names) {
|
||||
ok(items.has(name),
|
||||
`There is item with name '${name}' in ${storeName}`);
|
||||
|
||||
if (!items.has(name)) {
|
||||
showAvailableIds();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -838,3 +876,7 @@ var focusSearchBoxUsingShortcut = Task.async(function* (panelWin, callback) {
|
|||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
function getCookieId(name, domain, path) {
|
||||
return `${name}${SEPARATOR_GUID}${domain}${SEPARATOR_GUID}${path}`;
|
||||
}
|
||||
|
|
|
@ -38,8 +38,10 @@ window.removeCookie = function(name, path) {
|
|||
* can be tested.
|
||||
*/
|
||||
window.clear = function*() {
|
||||
sessionStorage.clear();
|
||||
localStorage.clear();
|
||||
dump("removed localStorage from " + document.location + "\n");
|
||||
|
||||
sessionStorage.clear();
|
||||
dump("removed sessionStorage from " + document.location + "\n");
|
||||
};
|
||||
|
||||
|
|
|
@ -12,6 +12,12 @@ const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
|
|||
const JSOL = require("devtools/client/shared/vendor/jsol");
|
||||
const {KeyCodes} = require("devtools/client/shared/keycodes");
|
||||
|
||||
// GUID to be used as a separator in compound keys. This must match the same
|
||||
// constant in devtools/server/actors/storage.js,
|
||||
// devtools/client/storage/test/head.js and
|
||||
// devtools/server/tests/browser/head.js
|
||||
const SEPARATOR_GUID = "{9d414cc5-8319-0a04-0586-c0a6ae01670a}";
|
||||
|
||||
loader.lazyRequireGetter(this, "TreeWidget",
|
||||
"devtools/client/shared/widgets/TreeWidget", true);
|
||||
loader.lazyRequireGetter(this, "TableWidget",
|
||||
|
@ -36,13 +42,6 @@ const GENERIC_VARIABLES_VIEW_SETTINGS = {
|
|||
preventDescriptorModifiers: true
|
||||
};
|
||||
|
||||
// Columns which are hidden by default in the storage table
|
||||
const HIDDEN_COLUMNS = [
|
||||
"creationTime",
|
||||
"isDomain",
|
||||
"isSecure"
|
||||
];
|
||||
|
||||
const REASON = {
|
||||
NEW_ROW: "new-row",
|
||||
NEXT_50_ITEMS: "next-50-items",
|
||||
|
@ -786,6 +785,8 @@ StorageUI.prototype = {
|
|||
let uniqueKey = null;
|
||||
let columns = {};
|
||||
let editableFields = [];
|
||||
let hiddenFields = [];
|
||||
let privateFields = [];
|
||||
let fields = yield this.getCurrentActor().getFields(subtype);
|
||||
|
||||
fields.forEach(f => {
|
||||
|
@ -797,6 +798,14 @@ StorageUI.prototype = {
|
|||
editableFields.push(f.name);
|
||||
}
|
||||
|
||||
if (f.hidden) {
|
||||
hiddenFields.push(f.name);
|
||||
}
|
||||
|
||||
if (f.private) {
|
||||
privateFields.push(f.name);
|
||||
}
|
||||
|
||||
columns[f.name] = f.name;
|
||||
let columnName;
|
||||
try {
|
||||
|
@ -812,7 +821,7 @@ StorageUI.prototype = {
|
|||
}
|
||||
});
|
||||
|
||||
this.table.setColumns(columns, null, HIDDEN_COLUMNS);
|
||||
this.table.setColumns(columns, null, hiddenFields, privateFields);
|
||||
this.hideSidebar();
|
||||
|
||||
yield this.makeFieldsEditable(editableFields);
|
||||
|
@ -927,10 +936,13 @@ StorageUI.prototype = {
|
|||
|
||||
let rowId = this.table.contextMenuRowId;
|
||||
let data = this.table.items.get(rowId);
|
||||
let name = addEllipsis(data[this.table.uniqueId]);
|
||||
let name = data[this.table.uniqueId];
|
||||
|
||||
let separatorRegex = new RegExp(SEPARATOR_GUID, "g");
|
||||
let label = addEllipsis((name + "").replace(separatorRegex, "-"));
|
||||
|
||||
this._tablePopupDelete.setAttribute("label",
|
||||
L10N.getFormatStr("storage.popupMenu.deleteLabel", name));
|
||||
L10N.getFormatStr("storage.popupMenu.deleteLabel", label));
|
||||
|
||||
if (type === "cookies") {
|
||||
let host = addEllipsis(data.host);
|
||||
|
|
|
@ -15,6 +15,12 @@ const {isWindowIncluded} = require("devtools/shared/layout/utils");
|
|||
const specs = require("devtools/shared/specs/storage");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
|
||||
// GUID to be used as a separator in compound keys. This must match the same
|
||||
// constant in devtools/client/storage/ui.js,
|
||||
// devtools/client/storage/test/head.js and
|
||||
// devtools/server/tests/browser/head.js
|
||||
const SEPARATOR_GUID = "{9d414cc5-8319-0a04-0586-c0a6ae01670a}";
|
||||
|
||||
loader.lazyImporter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
loader.lazyImporter(this, "Sqlite", "resource://gre/modules/Sqlite.jsm");
|
||||
|
||||
|
@ -467,14 +473,16 @@ StorageActors.createActor({
|
|||
}
|
||||
|
||||
return {
|
||||
uniqueKey: `${cookie.name}${SEPARATOR_GUID}${cookie.host}` +
|
||||
`${SEPARATOR_GUID}${cookie.path}`,
|
||||
name: cookie.name,
|
||||
path: cookie.path || "",
|
||||
host: cookie.host || "",
|
||||
path: cookie.path || "",
|
||||
|
||||
// because expires is in seconds
|
||||
expires: (cookie.expires || 0) * 1000,
|
||||
|
||||
// because it is in micro seconds
|
||||
// because creationTime is in micro seconds
|
||||
creationTime: cookie.creationTime / 1000,
|
||||
|
||||
// - do -
|
||||
|
@ -495,7 +503,10 @@ StorageActors.createActor({
|
|||
|
||||
for (let cookie of cookies) {
|
||||
if (this.isCookieAtHost(cookie, host)) {
|
||||
this.hostVsStores.get(host).set(cookie.name, cookie);
|
||||
let uniqueKey = `${cookie.name}${SEPARATOR_GUID}${cookie.host}` +
|
||||
`${SEPARATOR_GUID}${cookie.path}`;
|
||||
|
||||
this.hostVsStores.get(host).set(uniqueKey, cookie);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -528,8 +539,11 @@ StorageActors.createActor({
|
|||
case "changed":
|
||||
if (hosts.length) {
|
||||
for (let host of hosts) {
|
||||
this.hostVsStores.get(host).set(subject.name, subject);
|
||||
data[host] = [subject.name];
|
||||
let uniqueKey = `${subject.name}${SEPARATOR_GUID}${subject.host}` +
|
||||
`${SEPARATOR_GUID}${subject.path}`;
|
||||
|
||||
this.hostVsStores.get(host).set(uniqueKey, subject);
|
||||
data[host] = [uniqueKey];
|
||||
}
|
||||
this.storageActor.update(action, "cookies", data);
|
||||
}
|
||||
|
@ -538,8 +552,11 @@ StorageActors.createActor({
|
|||
case "deleted":
|
||||
if (hosts.length) {
|
||||
for (let host of hosts) {
|
||||
this.hostVsStores.get(host).delete(subject.name);
|
||||
data[host] = [subject.name];
|
||||
let uniqueKey = `${subject.name}${SEPARATOR_GUID}${subject.host}` +
|
||||
`${SEPARATOR_GUID}${subject.path}`;
|
||||
|
||||
this.hostVsStores.get(host).delete(uniqueKey);
|
||||
data[host] = [uniqueKey];
|
||||
}
|
||||
this.storageActor.update("deleted", "cookies", data);
|
||||
}
|
||||
|
@ -550,8 +567,11 @@ StorageActors.createActor({
|
|||
for (let host of hosts) {
|
||||
let stores = [];
|
||||
for (let cookie of subject) {
|
||||
this.hostVsStores.get(host).delete(cookie.name);
|
||||
stores.push(cookie.name);
|
||||
let uniqueKey = `${cookie.name}${SEPARATOR_GUID}${cookie.host}` +
|
||||
`${SEPARATOR_GUID}${cookie.path}`;
|
||||
|
||||
this.hostVsStores.get(host).delete(uniqueKey);
|
||||
stores.push(uniqueKey);
|
||||
}
|
||||
data[host] = stores;
|
||||
}
|
||||
|
@ -573,15 +593,17 @@ StorageActors.createActor({
|
|||
|
||||
getFields: Task.async(function* () {
|
||||
return [
|
||||
{ name: "name", editable: 1},
|
||||
{ name: "path", editable: 1},
|
||||
{ name: "host", editable: 1},
|
||||
{ name: "expires", editable: 1},
|
||||
{ name: "lastAccessed", editable: 0},
|
||||
{ name: "value", editable: 1},
|
||||
{ name: "isDomain", editable: 0},
|
||||
{ name: "isSecure", editable: 1},
|
||||
{ name: "isHttpOnly", editable: 1}
|
||||
{ name: "uniqueKey", editable: false, private: true },
|
||||
{ name: "name", editable: true, hidden: false },
|
||||
{ name: "host", editable: true, hidden: false },
|
||||
{ name: "path", editable: true, hidden: false },
|
||||
{ name: "expires", editable: true, hidden: false },
|
||||
{ name: "lastAccessed", editable: false, hidden: false },
|
||||
{ name: "creationTime", editable: false, hidden: true },
|
||||
{ name: "value", editable: true, hidden: false },
|
||||
{ name: "isDomain", editable: false, hidden: true },
|
||||
{ name: "isSecure", editable: true, hidden: true },
|
||||
{ name: "isHttpOnly", editable: true, hidden: false }
|
||||
];
|
||||
}),
|
||||
|
||||
|
@ -703,7 +725,7 @@ var cookieHelpers = {
|
|||
* {
|
||||
* host: "http://www.mozilla.org",
|
||||
* field: "value",
|
||||
* key: "name",
|
||||
* editCookie: "name",
|
||||
* oldValue: "%7BHello%7D",
|
||||
* newValue: "%7BHelloo%7D",
|
||||
* items: {
|
||||
|
@ -727,10 +749,13 @@ var cookieHelpers = {
|
|||
let origPath = field === "path" ? oldValue : data.items.path;
|
||||
let cookie = null;
|
||||
|
||||
let enumerator = Services.cookies.getCookiesFromHost(origHost, data.originAttributes || {});
|
||||
let enumerator =
|
||||
Services.cookies.getCookiesFromHost(origHost, data.originAttributes || {});
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let nsiCookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
|
||||
if (nsiCookie.name === origName && nsiCookie.host === origHost) {
|
||||
if (nsiCookie.name === origName &&
|
||||
nsiCookie.host === origHost &&
|
||||
nsiCookie.path === origPath) {
|
||||
cookie = {
|
||||
host: nsiCookie.host,
|
||||
path: nsiCookie.path,
|
||||
|
@ -750,7 +775,7 @@ var cookieHelpers = {
|
|||
return;
|
||||
}
|
||||
|
||||
// If the date is expired set it for 1 minute in the future.
|
||||
// If the date is expired set it for 10 seconds in the future.
|
||||
let now = new Date();
|
||||
if (!cookie.isSession && (cookie.expires * 1000) <= now) {
|
||||
let tenSecondsFromNow = (now.getTime() + 10 * 1000) / 1000;
|
||||
|
@ -804,6 +829,15 @@ var cookieHelpers = {
|
|||
},
|
||||
|
||||
_removeCookies(host, opts = {}) {
|
||||
// We use a uniqueId to emulate compound keys for cookies. We need to
|
||||
// extract the cookie name to remove the correct cookie.
|
||||
if (opts.name) {
|
||||
let split = opts.name.split(SEPARATOR_GUID);
|
||||
|
||||
opts.name = split[0];
|
||||
opts.path = split[2];
|
||||
}
|
||||
|
||||
function hostMatches(cookieHost, matchHost) {
|
||||
if (cookieHost == null) {
|
||||
return matchHost == null;
|
||||
|
@ -814,12 +848,15 @@ var cookieHelpers = {
|
|||
return cookieHost == host;
|
||||
}
|
||||
|
||||
let enumerator = Services.cookies.getCookiesFromHost(host, opts.originAttributes || {});
|
||||
let enumerator =
|
||||
Services.cookies.getCookiesFromHost(host, opts.originAttributes || {});
|
||||
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
|
||||
if (hostMatches(cookie.host, host) &&
|
||||
(!opts.name || cookie.name === opts.name) &&
|
||||
(!opts.domain || cookie.host === opts.domain)) {
|
||||
(!opts.domain || cookie.host === opts.domain) &&
|
||||
(!opts.path || cookie.path === opts.path)) {
|
||||
Services.cookies.remove(
|
||||
cookie.host,
|
||||
cookie.name,
|
||||
|
@ -1031,8 +1068,8 @@ function getObjectForLocalOrSessionStorage(type) {
|
|||
|
||||
getFields: Task.async(function* () {
|
||||
return [
|
||||
{ name: "name", editable: 1},
|
||||
{ name: "value", editable: 1}
|
||||
{ name: "name", editable: true },
|
||||
{ name: "value", editable: true }
|
||||
];
|
||||
}),
|
||||
|
||||
|
@ -1212,8 +1249,8 @@ StorageActors.createActor({
|
|||
|
||||
getFields: Task.async(function* () {
|
||||
return [
|
||||
{ name: "url", editable: 0 },
|
||||
{ name: "status", editable: 0 }
|
||||
{ name: "url", editable: false },
|
||||
{ name: "status", editable: false }
|
||||
];
|
||||
}),
|
||||
|
||||
|
@ -1736,26 +1773,26 @@ StorageActors.createActor({
|
|||
// Detail of database
|
||||
case "database":
|
||||
return [
|
||||
{ name: "objectStore", editable: 0 },
|
||||
{ name: "keyPath", editable: 0 },
|
||||
{ name: "autoIncrement", editable: 0 },
|
||||
{ name: "indexes", editable: 0 },
|
||||
{ name: "objectStore", editable: false },
|
||||
{ name: "keyPath", editable: false },
|
||||
{ name: "autoIncrement", editable: false },
|
||||
{ name: "indexes", editable: false },
|
||||
];
|
||||
|
||||
// Detail of object store
|
||||
case "object store":
|
||||
return [
|
||||
{ name: "name", editable: 0 },
|
||||
{ name: "value", editable: 0 }
|
||||
{ name: "name", editable: false },
|
||||
{ name: "value", editable: false }
|
||||
];
|
||||
|
||||
// Detail of indexedDB for one origin
|
||||
default:
|
||||
return [
|
||||
{ name: "db", editable: 0 },
|
||||
{ name: "origin", editable: 0 },
|
||||
{ name: "version", editable: 0 },
|
||||
{ name: "objectStores", editable: 0 },
|
||||
{ name: "db", editable: false },
|
||||
{ name: "origin", editable: false },
|
||||
{ name: "version", editable: false },
|
||||
{ name: "objectStores", editable: false },
|
||||
];
|
||||
}
|
||||
})
|
||||
|
@ -2494,6 +2531,7 @@ let StorageActor = protocol.ActorClassWithSpec(specs.storageSpec, {
|
|||
// added or changed update
|
||||
this.removeNamesFromUpdateList("added", storeType, data);
|
||||
this.removeNamesFromUpdateList("changed", storeType, data);
|
||||
|
||||
for (let host in data) {
|
||||
if (data[host].length == 0 && this.boundUpdate.added &&
|
||||
this.boundUpdate.added[storeType] &&
|
||||
|
|
|
@ -11,6 +11,7 @@ support-files =
|
|||
doc_perf.html
|
||||
navigate-first.html
|
||||
navigate-second.html
|
||||
storage-cookies-same-name.html
|
||||
storage-dynamic-windows.html
|
||||
storage-listings.html
|
||||
storage-unsecured-iframe.html
|
||||
|
@ -80,6 +81,7 @@ skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still di
|
|||
#[browser_perf-front-profiler-01.js] bug 1077464
|
||||
#[browser_perf-front-profiler-05.js] bug 1077464
|
||||
#[browser_perf-front-profiler-06.js]
|
||||
[browser_storage_cookies-duplicate-names.js]
|
||||
[browser_storage_dynamic_windows.js]
|
||||
[browser_storage_listings.js]
|
||||
[browser_storage_updates.js]
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the storage panel is able to display multiple cookies with the same
|
||||
// name (and different paths).
|
||||
|
||||
const {StorageFront} = require("devtools/shared/fronts/storage");
|
||||
Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/server/tests/browser/storage-helpers.js", this);
|
||||
|
||||
const TESTDATA = {
|
||||
"test1.example.org": [
|
||||
{
|
||||
name: "name",
|
||||
value: "value1",
|
||||
expires: 0,
|
||||
path: "/",
|
||||
host: "test1.example.org",
|
||||
isDomain: false,
|
||||
isSecure: false,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
value: "value2",
|
||||
expires: 0,
|
||||
path: "/path2/",
|
||||
host: "test1.example.org",
|
||||
isDomain: false,
|
||||
isSecure: false,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
value: "value3",
|
||||
expires: 0,
|
||||
path: "/path3/",
|
||||
host: "test1.example.org",
|
||||
isDomain: false,
|
||||
isSecure: false,
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies-same-name.html");
|
||||
|
||||
initDebuggerServer();
|
||||
let client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
let form = yield connectDebuggerClient(client);
|
||||
let front = StorageFront(client, form);
|
||||
let data = yield front.listStores();
|
||||
|
||||
ok(data.cookies, "Cookies storage actor is present");
|
||||
|
||||
yield testCookies(data.cookies);
|
||||
yield clearStorage();
|
||||
|
||||
// Forcing GC/CC to get rid of docshells and windows created by this test.
|
||||
forceCollections();
|
||||
yield client.close();
|
||||
forceCollections();
|
||||
DebuggerServer.destroy();
|
||||
forceCollections();
|
||||
});
|
||||
|
||||
function testCookies(cookiesActor) {
|
||||
let numHosts = Object.keys(cookiesActor.hosts).length;
|
||||
is(numHosts, 1, "Correct number of host entries for cookies");
|
||||
return testCookiesObjects(0, cookiesActor.hosts, cookiesActor);
|
||||
}
|
||||
|
||||
var testCookiesObjects = Task.async(function* (index, hosts, cookiesActor) {
|
||||
let host = Object.keys(hosts)[index];
|
||||
let matchItems = data => {
|
||||
is(data.total, TESTDATA[host].length,
|
||||
"Number of cookies in host " + host + " matches");
|
||||
for (let item of data.data) {
|
||||
let found = false;
|
||||
for (let toMatch of TESTDATA[host]) {
|
||||
if (item.name === toMatch.name &&
|
||||
item.host === toMatch.host &&
|
||||
item.path === toMatch.path) {
|
||||
found = true;
|
||||
ok(true, "Found cookie " + item.name + " in response");
|
||||
is(item.value.str, toMatch.value, "The value matches.");
|
||||
is(item.expires, toMatch.expires, "The expiry time matches.");
|
||||
is(item.path, toMatch.path, "The path matches.");
|
||||
is(item.host, toMatch.host, "The host matches.");
|
||||
is(item.isSecure, toMatch.isSecure, "The isSecure value matches.");
|
||||
is(item.isDomain, toMatch.isDomain, "The isDomain value matches.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(found, "cookie " + item.name + " should exist in response");
|
||||
}
|
||||
};
|
||||
|
||||
ok(!!TESTDATA[host], "Host is present in the list : " + host);
|
||||
matchItems(yield cookiesActor.getStoreObjects(host));
|
||||
if (index == Object.keys(hosts).length - 1) {
|
||||
return;
|
||||
}
|
||||
yield testCookiesObjects(++index, hosts, cookiesActor);
|
||||
});
|
|
@ -66,6 +66,7 @@ function markOutMatched(toBeEmptied, data, deleted) {
|
|||
info("Testing for " + storageType);
|
||||
for (let host in data[storageType]) {
|
||||
ok(toBeEmptied[storageType][host], "Host " + host + " found");
|
||||
|
||||
if (!deleted) {
|
||||
for (let item of data[storageType][host]) {
|
||||
let index = toBeEmptied[storageType][host].indexOf(item);
|
||||
|
@ -87,50 +88,6 @@ function markOutMatched(toBeEmptied, data, deleted) {
|
|||
}
|
||||
}
|
||||
|
||||
// function testReload(front) {
|
||||
// info("Testing if reload works properly");
|
||||
|
||||
// let shouldBeEmptyFirst = Cu.cloneInto(beforeReload, {});
|
||||
// let shouldBeEmptyLast = Cu.cloneInto(beforeReload, {});
|
||||
// return new Promise(resolve => {
|
||||
|
||||
// let onStoresUpdate = data => {
|
||||
// info("in stores update of testReload");
|
||||
// // This might be second time stores update is happening, in which case,
|
||||
// // data.deleted will be null.
|
||||
// // OR.. This might be the first time on a super slow machine where both
|
||||
// // data.deleted and data.added is missing in the first update.
|
||||
// if (data.deleted) {
|
||||
// markOutMatched(shouldBeEmptyFirst, data.deleted, true);
|
||||
// }
|
||||
|
||||
// if (!Object.keys(shouldBeEmptyFirst).length) {
|
||||
// info("shouldBeEmptyFirst is empty now");
|
||||
// }
|
||||
|
||||
// // stores-update call might not have data.added for the first time on
|
||||
// // slow machines, in which case, data.added will be null
|
||||
// if (data.added) {
|
||||
// markOutMatched(shouldBeEmptyLast, data.added);
|
||||
// }
|
||||
|
||||
// if (!Object.keys(shouldBeEmptyLast).length) {
|
||||
// info("Everything to be received is received.");
|
||||
// endTestReloaded();
|
||||
// }
|
||||
// };
|
||||
|
||||
// let endTestReloaded = () => {
|
||||
// front.off("stores-update", onStoresUpdate);
|
||||
// resolve();
|
||||
// };
|
||||
|
||||
// front.on("stores-update", onStoresUpdate);
|
||||
|
||||
// content.location.reload();
|
||||
// });
|
||||
// }
|
||||
|
||||
function testAddIframe(front) {
|
||||
info("Testing if new iframe addition works properly");
|
||||
return new Promise(resolve => {
|
||||
|
@ -142,7 +99,10 @@ function testAddIframe(front) {
|
|||
"https://sectest1.example.org": ["iframe-s-ss1"]
|
||||
},
|
||||
cookies: {
|
||||
"sectest1.example.org": ["sc1"]
|
||||
"sectest1.example.org": [
|
||||
getCookieId("sc1", "sectest1.example.org",
|
||||
"/browser/devtools/server/tests/browser/")
|
||||
]
|
||||
},
|
||||
indexedDB: {
|
||||
// empty because indexed db creation happens after the page load, so at
|
||||
|
@ -150,7 +110,7 @@ function testAddIframe(front) {
|
|||
"https://sectest1.example.org": []
|
||||
},
|
||||
Cache: {
|
||||
"https://sectest1.example.org":[]
|
||||
"https://sectest1.example.org": []
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -35,15 +35,6 @@ const storeMap = {
|
|||
path: "/",
|
||||
host: "test1.example.org",
|
||||
isDomain: false,
|
||||
isSecure: false,
|
||||
},
|
||||
{
|
||||
name: "uc1",
|
||||
value: "foobar",
|
||||
host: ".example.org",
|
||||
path: "/",
|
||||
expires: 0,
|
||||
isDomain: true,
|
||||
isSecure: true,
|
||||
}
|
||||
],
|
||||
|
@ -337,7 +328,8 @@ function* testStores(data) {
|
|||
}
|
||||
|
||||
function testCookies(cookiesActor) {
|
||||
is(Object.keys(cookiesActor.hosts).length, 2, "Correct number of host entries for cookies");
|
||||
is(Object.keys(cookiesActor.hosts).length, 2,
|
||||
"Correct number of host entries for cookies");
|
||||
return testCookiesObjects(0, cookiesActor.hosts, cookiesActor);
|
||||
}
|
||||
|
||||
|
@ -346,9 +338,9 @@ var testCookiesObjects = Task.async(function* (index, hosts, cookiesActor) {
|
|||
let matchItems = data => {
|
||||
let cookiesLength = 0;
|
||||
for (let secureCookie of storeMap.cookies[host]) {
|
||||
if (secureCookie.isSecure) {
|
||||
++cookiesLength;
|
||||
}
|
||||
if (secureCookie.isSecure) {
|
||||
++cookiesLength;
|
||||
}
|
||||
}
|
||||
// Any secure cookies did not get stored in the database.
|
||||
is(data.total, storeMap.cookies[host].length - cookiesLength,
|
||||
|
|
|
@ -27,7 +27,12 @@ const TESTS = [
|
|||
expected: {
|
||||
added: {
|
||||
cookies: {
|
||||
"test1.example.org": ["c1", "c2"]
|
||||
"test1.example.org": [
|
||||
getCookieId("c1", "test1.example.org",
|
||||
"/browser/devtools/server/tests/browser/"),
|
||||
getCookieId("c2", "test1.example.org",
|
||||
"/browser/devtools/server/tests/browser/")
|
||||
]
|
||||
},
|
||||
localStorage: {
|
||||
"http://test1.example.org": ["l1"]
|
||||
|
@ -48,7 +53,10 @@ const TESTS = [
|
|||
expected: {
|
||||
changed: {
|
||||
cookies: {
|
||||
"test1.example.org": ["c1"]
|
||||
"test1.example.org": [
|
||||
getCookieId("c1", "test1.example.org",
|
||||
"/browser/devtools/server/tests/browser/"),
|
||||
]
|
||||
}
|
||||
},
|
||||
added: {
|
||||
|
@ -74,7 +82,10 @@ const TESTS = [
|
|||
expected: {
|
||||
deleted: {
|
||||
cookies: {
|
||||
"test1.example.org": ["c2"]
|
||||
"test1.example.org": [
|
||||
getCookieId("c2", "test1.example.org",
|
||||
"/browser/devtools/server/tests/browser/"),
|
||||
]
|
||||
},
|
||||
localStorage: {
|
||||
"http://test1.example.org": ["l1"]
|
||||
|
@ -112,7 +123,10 @@ const TESTS = [
|
|||
expected: {
|
||||
added: {
|
||||
cookies: {
|
||||
"test1.example.org": ["c3"]
|
||||
"test1.example.org": [
|
||||
getCookieId("c3", "test1.example.org",
|
||||
"/browser/devtools/server/tests/browser/"),
|
||||
]
|
||||
},
|
||||
sessionStorage: {
|
||||
"http://test1.example.org": ["s1", "s2"]
|
||||
|
@ -125,7 +139,10 @@ const TESTS = [
|
|||
},
|
||||
deleted: {
|
||||
cookies: {
|
||||
"test1.example.org": ["c1"]
|
||||
"test1.example.org": [
|
||||
getCookieId("c1", "test1.example.org",
|
||||
"/browser/devtools/server/tests/browser/"),
|
||||
]
|
||||
},
|
||||
localStorage: {
|
||||
"http://test1.example.org": ["l2"]
|
||||
|
@ -158,7 +175,10 @@ const TESTS = [
|
|||
expected: {
|
||||
deleted: {
|
||||
cookies: {
|
||||
"test1.example.org": ["c3"]
|
||||
"test1.example.org": [
|
||||
getCookieId("c3", "test1.example.org",
|
||||
"/browser/devtools/server/tests/browser/"),
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* eslint no-unused-vars: [2, {"vars": "local"}] */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
|
@ -19,6 +23,11 @@ const MAIN_DOMAIN = "http://test1.example.org/" + PATH;
|
|||
const ALT_DOMAIN = "http://sectest1.example.org/" + PATH;
|
||||
const ALT_DOMAIN_SECURED = "https://sectest1.example.org:443/" + PATH;
|
||||
|
||||
// GUID to be used as a separator in compound keys. This must match the same
|
||||
// constant in devtools/server/actors/storage.js,
|
||||
// devtools/client/storage/ui.js and devtools/client/storage/test/head.js
|
||||
const SEPARATOR_GUID = "{9d414cc5-8319-0a04-0586-c0a6ae01670a}";
|
||||
|
||||
// All tests are asynchronous.
|
||||
waitForExplicitFinish();
|
||||
|
||||
|
@ -94,7 +103,6 @@ function once(target, eventName, useCapture = false) {
|
|||
info("Waiting for event: '" + eventName + "' on " + target + ".");
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
||||
for (let [add, remove] of [
|
||||
["addEventListener", "removeEventListener"],
|
||||
["addListener", "removeListener"],
|
||||
|
@ -137,6 +145,8 @@ function getMockTabActor(win) {
|
|||
}
|
||||
|
||||
registerCleanupFunction(function tearDown() {
|
||||
Services.cookies.removeAll();
|
||||
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
|
@ -148,8 +158,11 @@ function idleWait(time) {
|
|||
|
||||
function busyWait(time) {
|
||||
let start = Date.now();
|
||||
// eslint-disable-next-line
|
||||
let stack;
|
||||
while (Date.now() - start < time) { stack = Components.stack; }
|
||||
while (Date.now() - start < time) {
|
||||
stack = Components.stack;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -172,11 +185,12 @@ function waitUntil(predicate, interval = 10) {
|
|||
}
|
||||
|
||||
function waitForMarkerType(front, types, predicate,
|
||||
unpackFun = (name, data) => data.markers,
|
||||
eventName = "timeline-data")
|
||||
{
|
||||
unpackFun = (name, data) => data.markers,
|
||||
eventName = "timeline-data") {
|
||||
types = [].concat(types);
|
||||
predicate = predicate || function () { return true; };
|
||||
predicate = predicate || function () {
|
||||
return true;
|
||||
};
|
||||
let filteredMarkers = [];
|
||||
let { promise, resolve } = defer();
|
||||
|
||||
|
@ -190,9 +204,11 @@ function waitForMarkerType(front, types, predicate,
|
|||
let markers = unpackFun(name, data);
|
||||
info("Got markers: " + JSON.stringify(markers, null, 2));
|
||||
|
||||
filteredMarkers = filteredMarkers.concat(markers.filter(m => types.indexOf(m.name) !== -1));
|
||||
filteredMarkers = filteredMarkers.concat(
|
||||
markers.filter(m => types.indexOf(m.name) !== -1));
|
||||
|
||||
if (types.every(t => filteredMarkers.some(m => m.name === t)) && predicate(filteredMarkers)) {
|
||||
if (types.every(t => filteredMarkers.some(m => m.name === t)) &&
|
||||
predicate(filteredMarkers)) {
|
||||
front.off(eventName, handler);
|
||||
resolve(filteredMarkers);
|
||||
}
|
||||
|
@ -201,3 +217,7 @@ function waitForMarkerType(front, types, predicate,
|
|||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function getCookieId(name, domain, path) {
|
||||
return `${name}${SEPARATOR_GUID}${domain}${SEPARATOR_GUID}${path}`;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Storage inspector cookies with duplicate names</title>
|
||||
</head>
|
||||
<body onload="createCookies()">
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
function createCookies() {
|
||||
document.cookie = "name=value1;path=/;";
|
||||
document.cookie = "name=value2;path=/path2/;";
|
||||
document.cookie = "name=value3;path=/path3/;";
|
||||
}
|
||||
|
||||
window.removeCookie = function (name) {
|
||||
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
|
||||
};
|
||||
|
||||
window.clearCookies = function () {
|
||||
let cookies = document.cookie;
|
||||
for (let cookie of cookies.split(";")) {
|
||||
removeCookie(cookie.split("=")[0]);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1525,6 +1525,7 @@ function NetworkMonitorChild(outerWindowID, messageManager, conn, owner) {
|
|||
this._onNewEvent = this._onNewEvent.bind(this);
|
||||
this._onUpdateEvent = this._onUpdateEvent.bind(this);
|
||||
this._netEvents = new Map();
|
||||
this._msgName = `debug:${this.conn.prefix}netmonitor`;
|
||||
}
|
||||
|
||||
exports.NetworkMonitorChild = NetworkMonitorChild;
|
||||
|
@ -1542,7 +1543,7 @@ NetworkMonitorChild.prototype = {
|
|||
set saveRequestAndResponseBodies(val) {
|
||||
this._saveRequestAndResponseBodies = val;
|
||||
|
||||
this._messageManager.sendAsyncMessage("debug:netmonitor", {
|
||||
this._messageManager.sendAsyncMessage(this._msgName, {
|
||||
action: "setPreferences",
|
||||
preferences: {
|
||||
saveRequestAndResponseBodies: this._saveRequestAndResponseBodies,
|
||||
|
@ -1557,7 +1558,7 @@ NetworkMonitorChild.prototype = {
|
|||
set throttleData(val) {
|
||||
this._throttleData = val;
|
||||
|
||||
this._messageManager.sendAsyncMessage("debug:netmonitor", {
|
||||
this._messageManager.sendAsyncMessage(this._msgName, {
|
||||
action: "setPreferences",
|
||||
preferences: {
|
||||
throttleData: this._throttleData,
|
||||
|
@ -1572,11 +1573,9 @@ NetworkMonitorChild.prototype = {
|
|||
});
|
||||
|
||||
let mm = this._messageManager;
|
||||
mm.addMessageListener("debug:netmonitor:newEvent",
|
||||
this._onNewEvent);
|
||||
mm.addMessageListener("debug:netmonitor:updateEvent",
|
||||
this._onUpdateEvent);
|
||||
mm.sendAsyncMessage("debug:netmonitor", {
|
||||
mm.addMessageListener(`${this._msgName}:newEvent`, this._onNewEvent);
|
||||
mm.addMessageListener(`${this._msgName}:updateEvent`, this._onUpdateEvent);
|
||||
mm.sendAsyncMessage(this._msgName, {
|
||||
outerWindowID: this.outerWindowID,
|
||||
action: "start",
|
||||
});
|
||||
|
@ -1600,13 +1599,12 @@ NetworkMonitorChild.prototype = {
|
|||
let weakActor = this._netEvents.get(id);
|
||||
let actor = weakActor ? weakActor.get() : null;
|
||||
if (!actor) {
|
||||
console.error("Received debug:netmonitor:updateEvent for unknown " +
|
||||
"event ID: " + id);
|
||||
console.error(`Received ${this._msgName}:updateEvent for unknown event ID: ${id}`);
|
||||
return;
|
||||
}
|
||||
if (!(method in actor)) {
|
||||
console.error("Received debug:netmonitor:updateEvent unsupported " +
|
||||
"method: " + method);
|
||||
console.error(`Received ${this._msgName}:updateEvent unsupported ` +
|
||||
`method: ${method}`);
|
||||
return;
|
||||
}
|
||||
actor[method].apply(actor, args);
|
||||
|
@ -1615,10 +1613,8 @@ NetworkMonitorChild.prototype = {
|
|||
destroy: function () {
|
||||
let mm = this._messageManager;
|
||||
try {
|
||||
mm.removeMessageListener("debug:netmonitor:newEvent",
|
||||
this._onNewEvent);
|
||||
mm.removeMessageListener("debug:netmonitor:updateEvent",
|
||||
this._onUpdateEvent);
|
||||
mm.removeMessageListener(`${this._msgName}:newEvent`, this._onNewEvent);
|
||||
mm.removeMessageListener(`${this._msgName}:updateEvent`, this._onUpdateEvent);
|
||||
} catch (e) {
|
||||
// On b2g, when registered to a new root docshell,
|
||||
// all message manager functions throw when trying to call them during
|
||||
|
@ -1647,10 +1643,13 @@ NetworkMonitorChild.prototype = {
|
|||
* @param nsIMessageManager messageManager
|
||||
* The message manager for the child app process. This is used for
|
||||
* communication with the NetworkMonitorChild instance of the process.
|
||||
* @param string msgName
|
||||
* The message name to be used for this connection.
|
||||
*/
|
||||
function NetworkEventActorProxy(messageManager) {
|
||||
function NetworkEventActorProxy(messageManager, msgName) {
|
||||
this.id = gSequenceId();
|
||||
this.messageManager = messageManager;
|
||||
this._msgName = msgName;
|
||||
}
|
||||
exports.NetworkEventActorProxy = NetworkEventActorProxy;
|
||||
|
||||
|
@ -1658,7 +1657,7 @@ NetworkEventActorProxy.methodFactory = function (method) {
|
|||
return DevToolsUtils.makeInfallible(function () {
|
||||
let args = Array.slice(arguments);
|
||||
let mm = this.messageManager;
|
||||
mm.sendAsyncMessage("debug:netmonitor:updateEvent", {
|
||||
mm.sendAsyncMessage(`${this._msgName}:updateEvent`, {
|
||||
id: this.id,
|
||||
method: method,
|
||||
args: args,
|
||||
|
@ -1678,7 +1677,7 @@ NetworkEventActorProxy.prototype = {
|
|||
*/
|
||||
init: DevToolsUtils.makeInfallible(function (event) {
|
||||
let mm = this.messageManager;
|
||||
mm.sendAsyncMessage("debug:netmonitor:newEvent", {
|
||||
mm.sendAsyncMessage(`${this._msgName}:newEvent`, {
|
||||
id: this.id,
|
||||
event: event,
|
||||
});
|
||||
|
@ -1726,6 +1725,7 @@ exports.setupParentProcess = setupParentProcess;
|
|||
* The RDP connection prefix that uniquely identifies the connection.
|
||||
*/
|
||||
function NetworkMonitorParent(mm, prefix) {
|
||||
this._msgName = `debug:${prefix}netmonitor`;
|
||||
this.onNetMonitorMessage = this.onNetMonitorMessage.bind(this);
|
||||
this.onNetworkEvent = this.onNetworkEvent.bind(this);
|
||||
this.setMessageManager(mm);
|
||||
|
@ -1738,16 +1738,16 @@ NetworkMonitorParent.prototype = {
|
|||
setMessageManager(mm) {
|
||||
if (this.messageManager) {
|
||||
let oldMM = this.messageManager;
|
||||
oldMM.removeMessageListener("debug:netmonitor", this.onNetMonitorMessage);
|
||||
oldMM.removeMessageListener(this._msgName, this.onNetMonitorMessage);
|
||||
}
|
||||
this.messageManager = mm;
|
||||
if (mm) {
|
||||
mm.addMessageListener("debug:netmonitor", this.onNetMonitorMessage);
|
||||
mm.addMessageListener(this._msgName, this.onNetMonitorMessage);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for "debug:netmonitor" messages received through the message manager
|
||||
* Handler for `debug:${prefix}netmonitor` messages received through the message manager
|
||||
* from the content process.
|
||||
*
|
||||
* @param object msg
|
||||
|
@ -1802,7 +1802,7 @@ NetworkMonitorParent.prototype = {
|
|||
* data about the request is available.
|
||||
*/
|
||||
onNetworkEvent: DevToolsUtils.makeInfallible(function (event) {
|
||||
return new NetworkEventActorProxy(this.messageManager).init(event);
|
||||
return new NetworkEventActorProxy(this.messageManager, this._msgName).init(event);
|
||||
}),
|
||||
|
||||
destroy: function () {
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Test for Bug 1223561</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
<script type="text/javascript" src="file_fullscreen-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<table style="background-color: green"></table>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
function ok(condition, msg) {
|
||||
opener.ok(condition, "[table] " + msg);
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
opener.is(a, b, "[table] " + msg);
|
||||
}
|
||||
|
||||
function info(msg) {
|
||||
opener.info("[table] " + msg);
|
||||
}
|
||||
|
||||
const gTable = document.querySelector("table");
|
||||
|
||||
function begin() {
|
||||
info("The default background of window should be white");
|
||||
addFullscreenChangeContinuation("enter", enteredFullscreen);
|
||||
assertWindowPureColor(window, "white");
|
||||
gTable.requestFullscreen();
|
||||
}
|
||||
|
||||
function enteredFullscreen() {
|
||||
info("The table with green background should be in fullscreen");
|
||||
assertWindowPureColor(window, "green");
|
||||
gTable.style = "background: transparent";
|
||||
info("When the table becames transparent, the black backdrop should appear");
|
||||
assertWindowPureColor(window, "black");
|
||||
addFullscreenChangeContinuation("exit", exitedFullscreen);
|
||||
document.exitFullscreen();
|
||||
}
|
||||
|
||||
function exitedFullscreen() {
|
||||
opener.nextTest();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -53,28 +53,6 @@ support-files =
|
|||
file_bug1260704.png
|
||||
file_formSubmission_img.jpg
|
||||
file_formSubmission_text.txt
|
||||
file_fullscreen-api.html
|
||||
file_fullscreen-backdrop.html
|
||||
file_fullscreen-denied-inner.html
|
||||
file_fullscreen-denied.html
|
||||
file_fullscreen-esc-exit-inner.html
|
||||
file_fullscreen-esc-exit.html
|
||||
file_fullscreen-hidden.html
|
||||
file_fullscreen-lenient-setters.html
|
||||
file_fullscreen-multiple-inner.html
|
||||
file_fullscreen-multiple.html
|
||||
file_fullscreen-navigation.html
|
||||
file_fullscreen-nested.html
|
||||
file_fullscreen-prefixed.html
|
||||
file_fullscreen-plugins.html
|
||||
file_fullscreen-rollback.html
|
||||
file_fullscreen-scrollbar.html
|
||||
file_fullscreen-selector.html
|
||||
file_fullscreen-svg-element.html
|
||||
file_fullscreen-top-layer.html
|
||||
file_fullscreen-unprefix-disabled-inner.html
|
||||
file_fullscreen-unprefix-disabled.html
|
||||
file_fullscreen-utils.js
|
||||
file_iframe_sandbox_a_if1.html
|
||||
file_iframe_sandbox_a_if10.html
|
||||
file_iframe_sandbox_a_if11.html
|
||||
|
@ -461,6 +439,30 @@ skip-if = toolkit == 'android'
|
|||
[test_fullscreen-api.html]
|
||||
tags = fullscreen
|
||||
skip-if = toolkit == 'android'
|
||||
support-files =
|
||||
file_fullscreen-api.html
|
||||
file_fullscreen-backdrop.html
|
||||
file_fullscreen-denied-inner.html
|
||||
file_fullscreen-denied.html
|
||||
file_fullscreen-esc-exit-inner.html
|
||||
file_fullscreen-esc-exit.html
|
||||
file_fullscreen-hidden.html
|
||||
file_fullscreen-lenient-setters.html
|
||||
file_fullscreen-multiple-inner.html
|
||||
file_fullscreen-multiple.html
|
||||
file_fullscreen-navigation.html
|
||||
file_fullscreen-nested.html
|
||||
file_fullscreen-prefixed.html
|
||||
file_fullscreen-plugins.html
|
||||
file_fullscreen-rollback.html
|
||||
file_fullscreen-scrollbar.html
|
||||
file_fullscreen-selector.html
|
||||
file_fullscreen-svg-element.html
|
||||
file_fullscreen-table.html
|
||||
file_fullscreen-top-layer.html
|
||||
file_fullscreen-unprefix-disabled-inner.html
|
||||
file_fullscreen-unprefix-disabled.html
|
||||
file_fullscreen-utils.js
|
||||
[test_fullscreen-api-race.html]
|
||||
tags = fullscreen
|
||||
skip-if = toolkit == 'android' # just copy the conditions from the test above
|
||||
|
|
|
@ -45,6 +45,7 @@ var gTestWindows = [
|
|||
"file_fullscreen-prefixed.html",
|
||||
"file_fullscreen-unprefix-disabled.html",
|
||||
"file_fullscreen-lenient-setters.html",
|
||||
"file_fullscreen-table.html",
|
||||
];
|
||||
|
||||
var testWindow = null;
|
||||
|
|
|
@ -21,9 +21,6 @@ SimpleTest.waitForExplicitFinish();
|
|||
// 6. Add 1.6s of data once video element fired waiting, that canplay is fired once readyState is HAVE_FUTURE_DATA.
|
||||
// 7. Finally load data to the end and ensure that canplaythrough is fired and that readyState is now HAVE_ENOUGH_DATA
|
||||
|
||||
// FIXME: bug 1319293
|
||||
addMSEPrefs(["media.dormant-on-pause-timeout-ms", -1]);
|
||||
|
||||
runWithMSE(function(ms, el) {
|
||||
el.controls = true;
|
||||
once(ms, 'sourceopen').then(function() {
|
||||
|
|
|
@ -154,7 +154,7 @@ VorbisDataDecoder::DoDecode(MediaRawData* aSample)
|
|||
const unsigned char* aData = aSample->Data();
|
||||
size_t aLength = aSample->Size();
|
||||
int64_t aOffset = aSample->mOffset;
|
||||
uint64_t aTstampUsecs = aSample->mTime;
|
||||
int64_t aTstampUsecs = aSample->mTime;
|
||||
int64_t aTotalFrames = 0;
|
||||
|
||||
MOZ_ASSERT(mPacketCount >= 3);
|
||||
|
|
|
@ -373,12 +373,21 @@ nsresult
|
|||
MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface)
|
||||
{
|
||||
mDecoder = CreateDecoder(mMimeType);
|
||||
|
||||
if (!mDecoder) {
|
||||
INVOKE_CALLBACK(Error,
|
||||
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Check if the video codec supports adaptive playback or not.
|
||||
if (aSurface && java::HardwareCodecCapabilityUtils::CheckSupportsAdaptivePlayback(
|
||||
mDecoder, nsCString(TranslateMimeType(mMimeType)))) {
|
||||
// TODO: may need to find a way to not use hard code to decide the max w/h.
|
||||
mFormat->SetInteger(MediaFormat::KEY_MAX_WIDTH, 1920);
|
||||
mFormat->SetInteger(MediaFormat::KEY_MAX_HEIGHT, 1080);
|
||||
}
|
||||
|
||||
MediaCrypto::LocalRef crypto = MediaDrmProxy::GetMediaCrypto(mDrmStubId);
|
||||
bool hascrypto = !!crypto;
|
||||
LOG("Has(%d) MediaCrypto (%s)", hascrypto, NS_ConvertUTF16toUTF8(mDrmStubId).get());
|
||||
|
|
|
@ -255,7 +255,7 @@ int32_t sAggregateBatchTestRedoOrderArr[] = {
|
|||
class TestTransaction : public nsITransaction
|
||||
{
|
||||
protected:
|
||||
virtual ~TestTransaction() {}
|
||||
virtual ~TestTransaction() = default;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -288,11 +288,9 @@ public:
|
|||
: mVal(++sConstructorCount), mFlags(aFlags)
|
||||
{}
|
||||
|
||||
virtual ~SimpleTransaction()
|
||||
{
|
||||
}
|
||||
~SimpleTransaction() override = default;
|
||||
|
||||
NS_IMETHOD DoTransaction()
|
||||
NS_IMETHOD DoTransaction() override
|
||||
{
|
||||
//
|
||||
// Make sure DoTransaction() is called in the order we expect!
|
||||
|
@ -309,7 +307,7 @@ public:
|
|||
return (mFlags & THROWS_DO_ERROR_FLAG) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD UndoTransaction()
|
||||
NS_IMETHOD UndoTransaction() override
|
||||
{
|
||||
//
|
||||
// Make sure UndoTransaction() is called in the order we expect!
|
||||
|
@ -326,7 +324,7 @@ public:
|
|||
return (mFlags & THROWS_UNDO_ERROR_FLAG) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD RedoTransaction()
|
||||
NS_IMETHOD RedoTransaction() override
|
||||
{
|
||||
//
|
||||
// Make sure RedoTransaction() is called in the order we expect!
|
||||
|
@ -343,7 +341,7 @@ public:
|
|||
return (mFlags & THROWS_REDO_ERROR_FLAG) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetIsTransient(bool *aIsTransient)
|
||||
NS_IMETHOD GetIsTransient(bool *aIsTransient) override
|
||||
{
|
||||
if (aIsTransient) {
|
||||
*aIsTransient = (mFlags & TRANSIENT_FLAG) ? true : false;
|
||||
|
@ -351,7 +349,7 @@ public:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD Merge(nsITransaction *aTransaction, bool *aDidMerge)
|
||||
NS_IMETHOD Merge(nsITransaction *aTransaction, bool *aDidMerge) override
|
||||
{
|
||||
if (aDidMerge) {
|
||||
*aDidMerge = (mFlags & MERGE_FLAG) ? true : false;
|
||||
|
@ -403,11 +401,9 @@ public:
|
|||
mNumChildrenPerNode = aNumChildrenPerNode;
|
||||
}
|
||||
|
||||
virtual ~AggregateTransaction()
|
||||
{
|
||||
}
|
||||
~AggregateTransaction() override = default;
|
||||
|
||||
NS_IMETHOD DoTransaction()
|
||||
NS_IMETHOD DoTransaction() override
|
||||
{
|
||||
if (mLevel >= mMaxLevel) {
|
||||
// Only leaf nodes can throw errors!
|
||||
|
@ -479,7 +475,7 @@ class SimpleTransactionFactory : public TestTransactionFactory
|
|||
{
|
||||
public:
|
||||
|
||||
TestTransaction *create(nsITransactionManager *txmgr, int32_t flags)
|
||||
TestTransaction *create(nsITransactionManager *txmgr, int32_t flags) override
|
||||
{
|
||||
return (TestTransaction *)new SimpleTransaction(flags);
|
||||
}
|
||||
|
@ -502,7 +498,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
virtual TestTransaction *create(nsITransactionManager *txmgr, int32_t flags)
|
||||
TestTransaction *create(nsITransactionManager *txmgr, int32_t flags) override
|
||||
{
|
||||
return (TestTransaction *)new AggregateTransaction(txmgr, mMaxLevel,
|
||||
mNumChildrenPerNode,
|
||||
|
|
|
@ -358,7 +358,7 @@ public:
|
|||
RefPtr<Layer> mRoot;
|
||||
RefPtr<GeckoContentController> mController;
|
||||
APZCTreeManagerParent* mApzcTreeManagerParent;
|
||||
CompositorBridgeParent* mParent;
|
||||
RefPtr<CompositorBridgeParent> mParent;
|
||||
LayerManagerComposite* mLayerManager;
|
||||
// Pointer to the CrossProcessCompositorBridgeParent. Used by APZCs to share
|
||||
// their FrameMetrics with the corresponding child process that holds
|
||||
|
|
32
hal/Hal.cpp
32
hal/Hal.cpp
|
@ -264,7 +264,7 @@ public:
|
|||
protected:
|
||||
virtual void GetCurrentInformationInternal(InfoType*) = 0;
|
||||
|
||||
virtual void OnNotificationsDisabled() {
|
||||
void OnNotificationsDisabled() override {
|
||||
mHasValidCache = false;
|
||||
}
|
||||
|
||||
|
@ -276,15 +276,15 @@ private:
|
|||
class BatteryObserversManager : public CachingObserversManager<BatteryInformation>
|
||||
{
|
||||
protected:
|
||||
void EnableNotifications() {
|
||||
void EnableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(EnableBatteryNotifications());
|
||||
}
|
||||
|
||||
void DisableNotifications() {
|
||||
void DisableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(DisableBatteryNotifications());
|
||||
}
|
||||
|
||||
void GetCurrentInformationInternal(BatteryInformation* aInfo) {
|
||||
void GetCurrentInformationInternal(BatteryInformation* aInfo) override {
|
||||
PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
|
||||
}
|
||||
};
|
||||
|
@ -300,15 +300,15 @@ BatteryObservers()
|
|||
class NetworkObserversManager : public CachingObserversManager<NetworkInformation>
|
||||
{
|
||||
protected:
|
||||
void EnableNotifications() {
|
||||
void EnableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(EnableNetworkNotifications());
|
||||
}
|
||||
|
||||
void DisableNotifications() {
|
||||
void DisableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(DisableNetworkNotifications());
|
||||
}
|
||||
|
||||
void GetCurrentInformationInternal(NetworkInformation* aInfo) {
|
||||
void GetCurrentInformationInternal(NetworkInformation* aInfo) override {
|
||||
PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
|
||||
}
|
||||
};
|
||||
|
@ -324,11 +324,11 @@ NetworkObservers()
|
|||
class WakeLockObserversManager : public ObserversManager<WakeLockInformation>
|
||||
{
|
||||
protected:
|
||||
void EnableNotifications() {
|
||||
void EnableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(EnableWakeLockNotifications());
|
||||
}
|
||||
|
||||
void DisableNotifications() {
|
||||
void DisableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(DisableWakeLockNotifications());
|
||||
}
|
||||
};
|
||||
|
@ -344,15 +344,15 @@ WakeLockObservers()
|
|||
class ScreenConfigurationObserversManager : public CachingObserversManager<ScreenConfiguration>
|
||||
{
|
||||
protected:
|
||||
void EnableNotifications() {
|
||||
void EnableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(EnableScreenConfigurationNotifications());
|
||||
}
|
||||
|
||||
void DisableNotifications() {
|
||||
void DisableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(DisableScreenConfigurationNotifications());
|
||||
}
|
||||
|
||||
void GetCurrentInformationInternal(ScreenConfiguration* aInfo) {
|
||||
void GetCurrentInformationInternal(ScreenConfiguration* aInfo) override {
|
||||
PROXY_IF_SANDBOXED(GetCurrentScreenConfiguration(aInfo));
|
||||
}
|
||||
};
|
||||
|
@ -449,11 +449,11 @@ void SetScreenBrightness(double aBrightness)
|
|||
class SystemClockChangeObserversManager : public ObserversManager<int64_t>
|
||||
{
|
||||
protected:
|
||||
void EnableNotifications() {
|
||||
void EnableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(EnableSystemClockChangeNotifications());
|
||||
}
|
||||
|
||||
void DisableNotifications() {
|
||||
void DisableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(DisableSystemClockChangeNotifications());
|
||||
}
|
||||
};
|
||||
|
@ -489,11 +489,11 @@ NotifySystemClockChange(const int64_t& aClockDeltaMS)
|
|||
class SystemTimezoneChangeObserversManager : public ObserversManager<SystemTimezoneChangeInformation>
|
||||
{
|
||||
protected:
|
||||
void EnableNotifications() {
|
||||
void EnableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(EnableSystemTimezoneChangeNotifications());
|
||||
}
|
||||
|
||||
void DisableNotifications() {
|
||||
void DisableNotifications() override {
|
||||
PROXY_IF_SANDBOXED(DisableSystemTimezoneChangeNotifications());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
|
||||
# NB: the IPDL compiler manages .ipdl-->.h/.cpp dependencies itself,
|
||||
# which is why we don't have explicit .h/.cpp targets here
|
||||
export:: $(ALL_IPDLSRCS)
|
||||
ipdl: $(ALL_IPDLSRCS)
|
||||
$(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||
$(PLY_INCLUDE) \
|
||||
$(srcdir)/ipdl.py \
|
||||
|
@ -23,5 +23,9 @@ export:: $(ALL_IPDLSRCS)
|
|||
--outcpp-dir=. \
|
||||
$(IPDLDIRS:%=-I%) \
|
||||
$^
|
||||
|
||||
.PHONY: ipdl
|
||||
|
||||
export:: ipdl
|
||||
endif
|
||||
|
||||
|
|
|
@ -423,7 +423,7 @@ class StructType(_CompoundType):
|
|||
def itercomponents(self):
|
||||
for f in self.fields:
|
||||
yield f
|
||||
|
||||
|
||||
def name(self): return self.qname.baseid
|
||||
def fullname(self): return str(self.qname)
|
||||
|
||||
|
@ -552,7 +552,7 @@ class SymbolTable:
|
|||
self.scopes = [ { } ] # stack({})
|
||||
self.globalScope = self.scopes[0]
|
||||
self.currentScope = self.globalScope
|
||||
|
||||
|
||||
def enterScope(self, node):
|
||||
assert (isinstance(self.scopes[0], dict)
|
||||
and self.globalScope is self.scopes[0])
|
||||
|
@ -843,7 +843,7 @@ class GatherDecls(TcheckVisitor):
|
|||
# If we've already processed this union, don't do it again.
|
||||
if len(utype.components):
|
||||
return
|
||||
|
||||
|
||||
for c in ud.components:
|
||||
cdecl = self.symtab.lookup(str(c))
|
||||
if cdecl is None:
|
||||
|
@ -930,7 +930,7 @@ class GatherDecls(TcheckVisitor):
|
|||
mgdname, p.name)
|
||||
|
||||
p.states = { }
|
||||
|
||||
|
||||
if len(p.transitionStmts):
|
||||
p.startStates = [ ts for ts in p.transitionStmts
|
||||
if ts.state.start ]
|
||||
|
@ -966,7 +966,7 @@ class GatherDecls(TcheckVisitor):
|
|||
and None is self.symtab.lookup(_DELETE_MSG))):
|
||||
# add a special state |state DEAD: null goto DEAD;|
|
||||
deadtrans = TransitionStmt.makeNullStmt(State.DEAD)
|
||||
p.states[State.DEAD] = deadtrans
|
||||
p.states[State.DEAD] = deadtrans
|
||||
if p.decl.type.hasReentrantDelete:
|
||||
dyingtrans = TransitionStmt.makeNullStmt(State.DYING)
|
||||
p.states[State.DYING] = dyingtrans
|
||||
|
@ -979,7 +979,7 @@ class GatherDecls(TcheckVisitor):
|
|||
# already resolved this guy's state
|
||||
if isinstance(actortype.state, Decl):
|
||||
return
|
||||
|
||||
|
||||
if actortype.state is None:
|
||||
# we thought this was a C++ type until type checking,
|
||||
# when we realized it was an IPDL actor type. But
|
||||
|
@ -1182,7 +1182,7 @@ class GatherDecls(TcheckVisitor):
|
|||
mdecl = self.symtab.lookup(mname)
|
||||
if mdecl is not None and mdecl.type.isIPDL() and mdecl.type.isProtocol():
|
||||
mdecl = self.symtab.lookup(mname +'Constructor')
|
||||
|
||||
|
||||
if mdecl is None:
|
||||
self.error(loc, "message `%s' has not been declared", mname)
|
||||
elif not mdecl.type.isMessage():
|
||||
|
@ -1247,7 +1247,7 @@ def checkcycles(p, stack=None):
|
|||
# special case for self-managed protocols
|
||||
if cp is p:
|
||||
continue
|
||||
|
||||
|
||||
if cp in stack:
|
||||
return [stack + [p, cp]]
|
||||
cycles += checkcycles(cp, stack + [p])
|
||||
|
@ -1328,7 +1328,7 @@ class CheckTypes(TcheckVisitor):
|
|||
|
||||
def visitProtocol(self, p):
|
||||
self.ptype = p.decl.type
|
||||
|
||||
|
||||
# check that we require no more "power" than our manager protocols
|
||||
ptype, pname = p.decl.type, p.decl.shortname
|
||||
|
||||
|
@ -1369,7 +1369,7 @@ class CheckTypes(TcheckVisitor):
|
|||
if cycles:
|
||||
self.error(
|
||||
p.decl.loc,
|
||||
"cycle(s) detected in manager/manages heirarchy: %s",
|
||||
"cycle(s) detected in manager/manages hierarchy: %s",
|
||||
formatcycles(cycles))
|
||||
|
||||
if 1 == len(ptype.managers) and ptype is ptype.manager():
|
||||
|
@ -1454,7 +1454,7 @@ class CheckTypes(TcheckVisitor):
|
|||
|
||||
def visitManager(self, mgr):
|
||||
# FIXME/bug 541126: check that the protocol graph is acyclic
|
||||
|
||||
|
||||
pdecl = mgr.of.decl
|
||||
ptype, pname = pdecl.type, pdecl.shortname
|
||||
|
||||
|
@ -1523,7 +1523,7 @@ class CheckTypes(TcheckVisitor):
|
|||
if mtype.isCtor() and not ptype.isManagerOf(mtype.constructedType()):
|
||||
self.error(
|
||||
loc,
|
||||
"ctor for protocol `%s', which is not managed by protocol `%s'",
|
||||
"ctor for protocol `%s', which is not managed by protocol `%s'",
|
||||
mname[:-len('constructor')], pname)
|
||||
|
||||
|
||||
|
@ -1535,7 +1535,7 @@ class CheckTypes(TcheckVisitor):
|
|||
SEND: [ OUT, _YNC ], RECV: [ IN, _YNC ],
|
||||
CALL: [ OUT, INTR ], ANSWER: [ IN, INTR ],
|
||||
} [t.trigger]
|
||||
|
||||
|
||||
if (OUT is impliedDirection and t.msg.type.isIn()
|
||||
or IN is impliedDirection and t.msg.type.isOut()
|
||||
or _YNC is impliedSems and t.msg.type.isInterrupt()
|
||||
|
@ -2147,7 +2147,7 @@ direction as trigger |t|'''
|
|||
U2 = stateName(U2)
|
||||
|
||||
return T1, M1.msg.progname, U1, T2, M2.msg.progname, U2
|
||||
|
||||
|
||||
|
||||
def reportRaceError(self, loc, S, t1Seq, t2Seq):
|
||||
T1, M1, U1, T2, M2, U2 = self._normalizeTransitionSequences(t1Seq, t2Seq)
|
||||
|
|
|
@ -23,7 +23,7 @@ class IPDLCompile:
|
|||
'-d', tmpoutdir,
|
||||
self.specfilename
|
||||
])
|
||||
|
||||
|
||||
proc = subprocess.Popen(args=self.argv,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
@ -69,7 +69,7 @@ exception being raised.'''
|
|||
def ok(self):
|
||||
'''Return True iff compiling self.specstring was successful.'''
|
||||
assert self.completed()
|
||||
|
||||
|
||||
return (not self.exception()
|
||||
and not self.error()
|
||||
and (0 == self.returncode))
|
||||
|
|
|
@ -22,7 +22,7 @@ class IPDLTestCase(unittest.TestCase):
|
|||
|
||||
def shortDescription(self):
|
||||
return '%s test of "%s"'% (self.__class__.__name__, self.filename)
|
||||
|
||||
|
||||
|
||||
class OkTestCase(IPDLTestCase):
|
||||
'''An invocation of the IPDL compiler on a valid specification.
|
||||
|
@ -34,7 +34,7 @@ The IPDL compiler should not produce errors or exceptions.'''
|
|||
def checkPassed(self):
|
||||
self.assertTrue(self.compile.ok(), self.mkFailMsg())
|
||||
|
||||
|
||||
|
||||
class ErrorTestCase(IPDLTestCase):
|
||||
'''An invocation of the IPDL compiler on an *invalid* specification.
|
||||
The IPDL compiler *should* produce errors but not exceptions.'''
|
||||
|
|
|
@ -206,10 +206,26 @@ nsPlaceholderFrame::GetParentStyleContext(nsIFrame** aProviderFrame) const
|
|||
}
|
||||
}
|
||||
|
||||
nsIFrame* parentFrame = GetParent();
|
||||
// Placeholder of backdrop frame is a child of the corresponding top
|
||||
// layer frame, and its style context inherits from that frame. In
|
||||
// case of table, the top layer frame is the table wrapper frame.
|
||||
// However, it will be skipped in CorrectStyleParentFrame below, so
|
||||
// we need to handle it specially here.
|
||||
if ((GetStateBits() & PLACEHOLDER_FOR_TOPLAYER) &&
|
||||
parentFrame->GetType() == nsGkAtoms::tableWrapperFrame) {
|
||||
MOZ_ASSERT(mOutOfFlowFrame->GetType() == nsGkAtoms::backdropFrame,
|
||||
"Only placeholder of backdrop frame can be put inside "
|
||||
"a table wrapper frame");
|
||||
*aProviderFrame = parentFrame;
|
||||
return parentFrame->StyleContext();
|
||||
}
|
||||
|
||||
// Lie about our pseudo so we can step out of all anon boxes and
|
||||
// pseudo-elements. The other option would be to reimplement the
|
||||
// {ib} split gunk here.
|
||||
*aProviderFrame = CorrectStyleParentFrame(GetParent(), nsGkAtoms::placeholderFrame);
|
||||
*aProviderFrame = CorrectStyleParentFrame(parentFrame,
|
||||
nsGkAtoms::placeholderFrame);
|
||||
return *aProviderFrame ? (*aProviderFrame)->StyleContext() : nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,11 @@
|
|||
}
|
||||
|
||||
*|*::-moz-table-wrapper {
|
||||
/* The inherited properties here need to be safe to have on both the
|
||||
* table and the table wrapper, generally because code ignores them
|
||||
* for the table. */
|
||||
display: inherit !important; /* table or inline-table */
|
||||
-moz-top-layer: inherit !important;
|
||||
margin: inherit ! important;
|
||||
padding: 0 ! important;
|
||||
border: none ! important;
|
||||
|
|
|
@ -7,6 +7,8 @@ package org.mozilla.gecko.icons.loader;
|
|||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.util.Log;
|
||||
|
||||
|
@ -82,13 +84,10 @@ public class IconDownloader implements IconLoader {
|
|||
* @param targetFaviconURL URL of the favicon to download.
|
||||
* @return A LoadFaviconResult containing the bitmap(s) extracted from the downloaded file, or
|
||||
* null if no or corrupt data was received.
|
||||
* @throws IOException If attempts to fully read the stream result in such an exception, such as
|
||||
* in the event of a transient connection failure.
|
||||
* @throws URISyntaxException If the underlying call to tryDownload retries and raises such an
|
||||
* exception trying a fallback URL.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
LoadFaviconResult downloadAndDecodeImage(Context context, String targetFaviconURL) throws IOException, URISyntaxException {
|
||||
@Nullable
|
||||
LoadFaviconResult downloadAndDecodeImage(Context context, String targetFaviconURL) {
|
||||
// Try the URL we were given.
|
||||
final HttpURLConnection connection = tryDownload(targetFaviconURL);
|
||||
if (connection == null) {
|
||||
|
@ -101,6 +100,9 @@ public class IconDownloader implements IconLoader {
|
|||
try {
|
||||
stream = connection.getInputStream();
|
||||
return decodeImageFromResponse(context, stream, connection.getHeaderFieldInt("Content-Length", -1));
|
||||
} catch (IOException e) {
|
||||
Log.d(LOGTAG, "IOException while reading and decoding ixon", e);
|
||||
return null;
|
||||
} finally {
|
||||
// Close the stream and free related resources.
|
||||
IOUtils.safeStreamClose(stream);
|
||||
|
@ -114,7 +116,8 @@ public class IconDownloader implements IconLoader {
|
|||
* @param faviconURI URL of Favicon to try and download
|
||||
* @return The HttpResponse containing the downloaded Favicon if successful, null otherwise.
|
||||
*/
|
||||
private HttpURLConnection tryDownload(String faviconURI) throws URISyntaxException, IOException {
|
||||
@Nullable
|
||||
private HttpURLConnection tryDownload(String faviconURI) {
|
||||
final HashSet<String> visitedLinkSet = new HashSet<>();
|
||||
visitedLinkSet.add(faviconURI);
|
||||
return tryDownloadRecurse(faviconURI, visitedLinkSet);
|
||||
|
@ -123,44 +126,54 @@ public class IconDownloader implements IconLoader {
|
|||
/**
|
||||
* Try to download from the favicon URL and recursively follow redirects.
|
||||
*/
|
||||
private HttpURLConnection tryDownloadRecurse(String faviconURI, HashSet<String> visited) throws URISyntaxException, IOException {
|
||||
@Nullable
|
||||
private HttpURLConnection tryDownloadRecurse(String faviconURI, HashSet<String> visited) {
|
||||
if (visited.size() == MAX_REDIRECTS_TO_FOLLOW) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final HttpURLConnection connection = connectTo(faviconURI);
|
||||
HttpURLConnection connection = null;
|
||||
|
||||
// Was the response a failure?
|
||||
final int status = connection.getResponseCode();
|
||||
try {
|
||||
connection = connectTo(faviconURI);
|
||||
|
||||
// Handle HTTP status codes requesting a redirect.
|
||||
if (status >= 300 && status < 400) {
|
||||
final String newURI = connection.getHeaderField("Location");
|
||||
// Was the response a failure?
|
||||
final int status = connection.getResponseCode();
|
||||
|
||||
// Handle mad web servers.
|
||||
try {
|
||||
if (newURI == null || newURI.equals(faviconURI)) {
|
||||
return null;
|
||||
// Handle HTTP status codes requesting a redirect.
|
||||
if (status >= 300 && status < 400) {
|
||||
final String newURI = connection.getHeaderField("Location");
|
||||
|
||||
// Handle mad web servers.
|
||||
try {
|
||||
if (newURI == null || newURI.equals(faviconURI)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (visited.contains(newURI)) {
|
||||
// Already been redirected here - abort.
|
||||
return null;
|
||||
}
|
||||
|
||||
visited.add(newURI);
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
|
||||
if (visited.contains(newURI)) {
|
||||
// Already been redirected here - abort.
|
||||
return null;
|
||||
}
|
||||
|
||||
visited.add(newURI);
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
return tryDownloadRecurse(newURI, visited);
|
||||
}
|
||||
|
||||
return tryDownloadRecurse(newURI, visited);
|
||||
}
|
||||
if (status >= 400) {
|
||||
// Client or Server error. Let's not retry loading from this URL again for some time.
|
||||
FailureCache.get().rememberFailure(faviconURI);
|
||||
|
||||
if (status >= 400) {
|
||||
// Client or Server error. Let's not retry loading from this URL again for some time.
|
||||
FailureCache.get().rememberFailure(faviconURI);
|
||||
|
||||
connection.disconnect();
|
||||
connection.disconnect();
|
||||
return null;
|
||||
}
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -168,9 +181,10 @@ public class IconDownloader implements IconLoader {
|
|||
}
|
||||
|
||||
@VisibleForTesting
|
||||
HttpURLConnection connectTo(String faviconURI) throws URISyntaxException, IOException {
|
||||
@NonNull
|
||||
HttpURLConnection connectTo(String uri) throws URISyntaxException, IOException {
|
||||
final HttpURLConnection connection = (HttpURLConnection) ProxySelector.openConnectionWithProxy(
|
||||
new URI(faviconURI));
|
||||
new URI(uri));
|
||||
|
||||
connection.setRequestProperty("User-Agent", GeckoAppShell.getGeckoInterface().getDefaultUAString());
|
||||
|
||||
|
@ -179,8 +193,6 @@ public class IconDownloader implements IconLoader {
|
|||
// redirects in loops forever.
|
||||
connection.setInstanceFollowRedirects(false);
|
||||
|
||||
connection.connect();
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
@ -195,6 +207,7 @@ public class IconDownloader implements IconLoader {
|
|||
* @throws IOException If attempts to fully read the stream result in such an exception, such as
|
||||
* in the event of a transient connection failure.
|
||||
*/
|
||||
@Nullable
|
||||
private LoadFaviconResult decodeImageFromResponse(Context context, InputStream stream, int contentLength) throws IOException {
|
||||
// This may not be provided, but if it is, it's useful.
|
||||
final int bufferSize;
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
package org.mozilla.gecko.media;
|
||||
|
||||
import org.mozilla.gecko.util.HardwareCodecCapabilityUtils;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCrypto;
|
||||
import android.media.MediaFormat;
|
||||
|
@ -298,6 +300,15 @@ final class JellyBeanAsyncCodec implements AsyncCodec {
|
|||
public void configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags) {
|
||||
assertCallbacks();
|
||||
|
||||
// Video decoder should config with adaptive playback capability.
|
||||
if (surface != null) {
|
||||
if (HardwareCodecCapabilityUtils.checkSupportsAdaptivePlayback(
|
||||
mCodec, format.getString(MediaFormat.KEY_MIME))) {
|
||||
// TODO: may need to find a way to not use hard code to decide the max w/h.
|
||||
format.setInteger(MediaFormat.KEY_MAX_WIDTH, 1920);
|
||||
format.setInteger(MediaFormat.KEY_MAX_HEIGHT, 1080);
|
||||
}
|
||||
}
|
||||
mCodec.configure(format, surface, crypto, flags);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,708 +5,130 @@
|
|||
|
||||
package org.mozilla.gecko.tabs;
|
||||
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Tab;
|
||||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.animation.PropertyAnimator;
|
||||
import org.mozilla.gecko.tabs.TabsPanel.TabsLayout;
|
||||
import org.mozilla.gecko.widget.themed.ThemedRelativeLayout;
|
||||
import org.mozilla.gecko.widget.GridSpacingDecoration;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.GridView;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.animation.ValueAnimator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A tabs layout implementation for the tablet redesign (bug 1014156) and later ported to mobile (bug 1193745).
|
||||
*/
|
||||
|
||||
class TabsGridLayout extends GridView
|
||||
implements TabsLayout,
|
||||
Tabs.OnTabsChangedListener {
|
||||
import android.util.Log;
|
||||
|
||||
public class TabsGridLayout extends TabsLayout {
|
||||
private static final String LOGTAG = "Gecko" + TabsGridLayout.class.getSimpleName();
|
||||
|
||||
public static final int ANIM_DELAY_MULTIPLE_MS = 20;
|
||||
private static final int ANIM_TIME_MS = 200;
|
||||
private static final DecelerateInterpolator ANIM_INTERPOLATOR = new DecelerateInterpolator();
|
||||
private GridSpacingDecoration spacingDecoration;
|
||||
private final int desiredItemWidth;
|
||||
private final int desiredHorizontalItemSpacing;
|
||||
private final int minHorizontalItemSpacing;
|
||||
private final int verticalItemPadding;
|
||||
|
||||
private final SparseArray<PointF> tabLocations = new SparseArray<PointF>();
|
||||
private final boolean isPrivate;
|
||||
private final TabsLayoutAdapter tabsAdapter;
|
||||
private final int columnWidth;
|
||||
private TabsPanel tabsPanel;
|
||||
private int lastSelectedTabId;
|
||||
public TabsGridLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs, R.layout.tabs_layout_item_view);
|
||||
|
||||
public TabsGridLayout(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs, R.attr.tabGridLayoutViewStyle);
|
||||
final Resources resources = context.getResources();
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabsLayout);
|
||||
isPrivate = (a.getInt(R.styleable.TabsLayout_tabs, 0x0) == 1);
|
||||
a.recycle();
|
||||
// Actual span count is updated in onSizeChanged.
|
||||
setLayoutManager(new GridLayoutManager(context, 1));
|
||||
|
||||
tabsAdapter = new TabsGridLayoutAdapter(context);
|
||||
setAdapter(tabsAdapter);
|
||||
desiredItemWidth = resources.getDimensionPixelSize(R.dimen.tab_panel_item_width);
|
||||
desiredHorizontalItemSpacing = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_ideal_item_hspacing);
|
||||
minHorizontalItemSpacing = resources.getDimensionPixelOffset(R.dimen.tab_panel_grid_min_item_hspacing);
|
||||
verticalItemPadding = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_item_vpadding);
|
||||
final int viewPaddingHorizontal = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_hpadding);
|
||||
final int viewPaddingVertical = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_vpadding);
|
||||
|
||||
setRecyclerListener(new RecyclerListener() {
|
||||
@Override
|
||||
public void onMovedToScrapHeap(View view) {
|
||||
TabsLayoutItemView item = (TabsLayoutItemView) view;
|
||||
item.setThumbnail(null);
|
||||
}
|
||||
});
|
||||
|
||||
// The clipToPadding setting in the styles.xml doesn't seem to be working (bug 1101784)
|
||||
// so lets set it manually in code for the moment as it's needed for the padding animation
|
||||
setPadding(viewPaddingHorizontal, viewPaddingVertical, viewPaddingHorizontal, viewPaddingVertical);
|
||||
setClipToPadding(false);
|
||||
setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY);
|
||||
|
||||
setVerticalFadingEdgeEnabled(false);
|
||||
setItemAnimator(new TabsGridLayoutAnimator());
|
||||
|
||||
final Resources resources = getResources();
|
||||
columnWidth = resources.getDimensionPixelSize(R.dimen.tab_panel_column_width);
|
||||
|
||||
final int padding = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_padding);
|
||||
final int paddingTop = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_padding_top);
|
||||
|
||||
// Lets set double the top padding on the bottom so that the last row shows up properly!
|
||||
// Your demise, GridView, cannot come fast enough.
|
||||
final int paddingBottom = paddingTop * 2;
|
||||
|
||||
setPadding(padding, paddingTop, padding, paddingBottom);
|
||||
|
||||
setOnItemClickListener(new OnItemClickListener() {
|
||||
// A TouchHelper handler for swipe to close.
|
||||
final TabsTouchHelperCallback callback = new TabsTouchHelperCallback(this) {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final TabsLayoutItemView tabView = (TabsLayoutItemView) view;
|
||||
final int tabId = tabView.getTabId();
|
||||
final Tab tab = Tabs.getInstance().selectTab(tabId);
|
||||
if (tab == null) {
|
||||
return;
|
||||
}
|
||||
autoHidePanel();
|
||||
Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.OPENED_FROM_TABS_TRAY);
|
||||
protected float alphaForItemSwipeDx(float dX, int distanceToAlphaMin) {
|
||||
return 1f - 2f * Math.abs(dX) / distanceToAlphaMin;
|
||||
}
|
||||
});
|
||||
|
||||
TabSwipeGestureListener mSwipeListener = new TabSwipeGestureListener();
|
||||
setOnTouchListener(mSwipeListener);
|
||||
setOnScrollListener(mSwipeListener.makeScrollListener());
|
||||
}
|
||||
|
||||
private void populateTabLocations(final Tab removedTab) {
|
||||
tabLocations.clear();
|
||||
|
||||
final int firstPosition = getFirstVisiblePosition();
|
||||
final int lastPosition = getLastVisiblePosition();
|
||||
final int numberOfColumns = getNumColumns();
|
||||
final int childCount = getChildCount();
|
||||
final int removedPosition = tabsAdapter.getPositionForTab(removedTab);
|
||||
|
||||
for (int x = 1, i = (removedPosition - firstPosition) + 1; i < childCount; i++, x++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child != null) {
|
||||
// Reset the transformations here in case the user is swiping tabs away fast and they swipe a tab
|
||||
// before the last animation has finished (bug 1179195).
|
||||
resetTransforms(child);
|
||||
|
||||
tabLocations.append(x, new PointF(child.getX(), child.getY()));
|
||||
}
|
||||
}
|
||||
|
||||
final boolean firstChildOffScreen = ((firstPosition > 0) || getChildAt(0).getY() < 0);
|
||||
final boolean lastChildVisible = (lastPosition - childCount == firstPosition - 1);
|
||||
final boolean oneItemOnLastRow = (lastPosition % numberOfColumns == 0);
|
||||
if (firstChildOffScreen && lastChildVisible && oneItemOnLastRow) {
|
||||
// We need to set the view's bottom padding to prevent a sudden jump as the
|
||||
// last item in the row is being removed. We then need to remove the padding
|
||||
// via a sweet animation
|
||||
|
||||
final int removedHeight = getChildAt(0).getMeasuredHeight();
|
||||
final int verticalSpacing =
|
||||
getResources().getDimensionPixelOffset(R.dimen.tab_panel_grid_vspacing);
|
||||
|
||||
ValueAnimator paddingAnimator = ValueAnimator.ofInt(getPaddingBottom() + removedHeight + verticalSpacing, getPaddingBottom());
|
||||
paddingAnimator.setDuration(ANIM_TIME_MS * 2);
|
||||
|
||||
paddingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), (Integer) animation.getAnimatedValue());
|
||||
}
|
||||
});
|
||||
paddingAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTabsPanel(TabsPanel panel) {
|
||||
tabsPanel = panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
setVisibility(View.VISIBLE);
|
||||
Tabs.getInstance().refreshThumbnails();
|
||||
Tabs.registerOnTabsChangedListener(this);
|
||||
refreshTabsData();
|
||||
|
||||
final Tab currentlySelectedTab = Tabs.getInstance().getSelectedTab();
|
||||
final int position = currentlySelectedTab != null ? tabsAdapter.getPositionForTab(currentlySelectedTab) : -1;
|
||||
if (position != -1) {
|
||||
final boolean selectionChanged = lastSelectedTabId != currentlySelectedTab.getId();
|
||||
final boolean positionIsVisible = position >= getFirstVisiblePosition() && position <= getLastVisiblePosition();
|
||||
|
||||
if (selectionChanged || !positionIsVisible) {
|
||||
smoothScrollToPosition(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
lastSelectedTabId = Tabs.getInstance().getSelectedTab().getId();
|
||||
setVisibility(View.GONE);
|
||||
Tabs.unregisterOnTabsChangedListener(this);
|
||||
GeckoAppShell.notifyObservers("Tab:Screenshot:Cancel", "");
|
||||
tabsAdapter.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExpand() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void autoHidePanel() {
|
||||
tabsPanel.autoHidePanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabChanged(Tab tab, Tabs.TabEvents msg, String data) {
|
||||
switch (msg) {
|
||||
case ADDED:
|
||||
// Refresh only if panel is shown. show() will call refreshTabsData() later again.
|
||||
if (tabsPanel.isShown()) {
|
||||
// Refresh the list to make sure the new tab is added in the right position.
|
||||
refreshTabsData();
|
||||
}
|
||||
break;
|
||||
|
||||
case CLOSED:
|
||||
|
||||
// This is limited to >= ICS as animations on GB devices are generally pants
|
||||
if (Build.VERSION.SDK_INT >= 11 && tabsAdapter.getCount() > 0) {
|
||||
animateRemoveTab(tab);
|
||||
}
|
||||
|
||||
final Tabs tabsInstance = Tabs.getInstance();
|
||||
|
||||
if (tabsAdapter.removeTab(tab)) {
|
||||
if (tab.isPrivate() == isPrivate && tabsAdapter.getCount() > 0) {
|
||||
int selected = tabsAdapter.getPositionForTab(tabsInstance.getSelectedTab());
|
||||
updateSelectedStyle(selected);
|
||||
}
|
||||
if (!tab.isPrivate()) {
|
||||
// Make sure we always have at least one normal tab
|
||||
final Iterable<Tab> tabs = tabsInstance.getTabsInOrder();
|
||||
boolean removedTabIsLastNormalTab = true;
|
||||
for (Tab singleTab : tabs) {
|
||||
if (!singleTab.isPrivate()) {
|
||||
removedTabIsLastNormalTab = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (removedTabIsLastNormalTab) {
|
||||
tabsInstance.addTab();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SELECTED:
|
||||
// Update the selected position, then fall through...
|
||||
updateSelectedPosition();
|
||||
case UNSELECTED:
|
||||
// We just need to update the style for the unselected tab...
|
||||
case THUMBNAIL:
|
||||
case TITLE:
|
||||
case RECORDING_CHANGE:
|
||||
case AUDIO_PLAYING_CHANGE:
|
||||
View view = getChildAt(tabsAdapter.getPositionForTab(tab) - getFirstVisiblePosition());
|
||||
if (view == null)
|
||||
return;
|
||||
|
||||
((TabsLayoutItemView) view).assignValues(tab);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the selected position in the list so that it will be scrolled to the right place.
|
||||
private void updateSelectedPosition() {
|
||||
int selected = tabsAdapter.getPositionForTab(Tabs.getInstance().getSelectedTab());
|
||||
updateSelectedStyle(selected);
|
||||
|
||||
if (selected != -1) {
|
||||
setSelection(selected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the selected/unselected style for the tabs.
|
||||
*
|
||||
* @param selected position of the selected tab
|
||||
*/
|
||||
private void updateSelectedStyle(final int selected) {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final int displayCount = tabsAdapter.getCount();
|
||||
|
||||
for (int i = 0; i < displayCount; i++) {
|
||||
final Tab tab = tabsAdapter.getItem(i);
|
||||
final boolean checked = displayCount == 1 || i == selected;
|
||||
final View tabView = getViewForTab(tab);
|
||||
if (tabView != null) {
|
||||
((TabsLayoutItemView) tabView).setChecked(checked);
|
||||
}
|
||||
// setItemChecked doesn't exist until API 11, despite what the API docs say!
|
||||
setItemChecked(i, checked);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void refreshTabsData() {
|
||||
// Store a different copy of the tabs, so that we don't have to worry about
|
||||
// accidentally updating it on the wrong thread.
|
||||
ArrayList<Tab> tabData = new ArrayList<>();
|
||||
|
||||
Iterable<Tab> allTabs = Tabs.getInstance().getTabsInOrder();
|
||||
for (Tab tab : allTabs) {
|
||||
if (tab.isPrivate() == isPrivate)
|
||||
tabData.add(tab);
|
||||
}
|
||||
|
||||
tabsAdapter.setTabs(tabData);
|
||||
updateSelectedPosition();
|
||||
}
|
||||
|
||||
private void resetTransforms(View view) {
|
||||
view.setAlpha(1);
|
||||
view.setTranslationX(0);
|
||||
view.setTranslationY(0);
|
||||
|
||||
((TabsLayoutItemView) view).setCloseVisible(true);
|
||||
};
|
||||
final ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
|
||||
touchHelper.attachToRecyclerView(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeAll() {
|
||||
|
||||
autoHidePanel();
|
||||
|
||||
if (getChildCount() == 0) {
|
||||
closeAllTabs();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean addAtIndexRequiresScroll(int index) {
|
||||
final GridLayoutManager layoutManager = (GridLayoutManager) getLayoutManager();
|
||||
final int spanCount = layoutManager.getSpanCount();
|
||||
final int firstVisibleIndex = layoutManager.findFirstVisibleItemPosition();
|
||||
// When you add an item at the first visible position to a GridLayoutManager and there's
|
||||
// room to scroll, RecyclerView scrolls the new position to anywhere from near the bottom of
|
||||
// its row to completely offscreen (for unknown reasons), so we need to scroll to fix that.
|
||||
// We also scroll when the item being added is the only item on the final row.
|
||||
return index == firstVisibleIndex ||
|
||||
(index == getAdapter().getItemCount() - 1 && index % spanCount == 0);
|
||||
}
|
||||
|
||||
private void updateSpacingDecoration(int horizontalItemSpacing) {
|
||||
if (spacingDecoration != null) {
|
||||
removeItemDecoration(spacingDecoration);
|
||||
}
|
||||
spacingDecoration = new GridSpacingDecoration(horizontalItemSpacing, verticalItemPadding);
|
||||
addItemDecoration(spacingDecoration);
|
||||
updateSelectedPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
|
||||
if (w == oldw) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Iterable<Tab> tabs = Tabs.getInstance().getTabsInOrder();
|
||||
for (Tab tab : tabs) {
|
||||
// In the normal panel we want to close all tabs (both private and normal),
|
||||
// but in the private panel we only want to close private tabs.
|
||||
if (!isPrivate || tab.isPrivate()) {
|
||||
Tabs.getInstance().closeTab(tab, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private View getViewForTab(Tab tab) {
|
||||
final int position = tabsAdapter.getPositionForTab(tab);
|
||||
return getChildAt(position - getFirstVisiblePosition());
|
||||
}
|
||||
|
||||
void closeTab(View v) {
|
||||
if (tabsAdapter.getCount() == 1) {
|
||||
autoHidePanel();
|
||||
}
|
||||
|
||||
TabsLayoutItemView itemView = (TabsLayoutItemView) v.getTag();
|
||||
Tab tab = Tabs.getInstance().getTab(itemView.getTabId());
|
||||
|
||||
Tabs.getInstance().closeTab(tab, true);
|
||||
}
|
||||
|
||||
private void animateRemoveTab(final Tab removedTab) {
|
||||
final int removedPosition = tabsAdapter.getPositionForTab(removedTab);
|
||||
|
||||
final View removedView = getViewForTab(removedTab);
|
||||
|
||||
// The removed position might not have a matching child view
|
||||
// when it's not within the visible range of positions in the strip.
|
||||
if (removedView == null) {
|
||||
return;
|
||||
}
|
||||
final int removedHeight = removedView.getMeasuredHeight();
|
||||
|
||||
populateTabLocations(removedTab);
|
||||
|
||||
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
// We don't animate the removed child view (it just disappears)
|
||||
// but we still need its size to animate all affected children
|
||||
// within the visible viewport.
|
||||
final int childCount = getChildCount();
|
||||
final int firstPosition = getFirstVisiblePosition();
|
||||
final int numberOfColumns = getNumColumns();
|
||||
|
||||
final List<Animator> childAnimators = new ArrayList<>();
|
||||
|
||||
PropertyValuesHolder translateX, translateY;
|
||||
for (int x = 0, i = removedPosition - firstPosition; i < childCount; i++, x++) {
|
||||
final View child = getChildAt(i);
|
||||
ObjectAnimator animator;
|
||||
|
||||
if (i % numberOfColumns == numberOfColumns - 1) {
|
||||
// Animate X & Y
|
||||
translateX = PropertyValuesHolder.ofFloat("translationX", -(columnWidth * numberOfColumns), 0);
|
||||
translateY = PropertyValuesHolder.ofFloat("translationY", removedHeight, 0);
|
||||
animator = ObjectAnimator.ofPropertyValuesHolder(child, translateX, translateY);
|
||||
} else {
|
||||
// Just animate X
|
||||
translateX = PropertyValuesHolder.ofFloat("translationX", columnWidth, 0);
|
||||
animator = ObjectAnimator.ofPropertyValuesHolder(child, translateX);
|
||||
}
|
||||
animator.setStartDelay(x * ANIM_DELAY_MULTIPLE_MS);
|
||||
childAnimators.add(animator);
|
||||
}
|
||||
|
||||
final AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.playTogether(childAnimators);
|
||||
animatorSet.setDuration(ANIM_TIME_MS);
|
||||
animatorSet.setInterpolator(ANIM_INTERPOLATOR);
|
||||
animatorSet.start();
|
||||
|
||||
// Set the starting position of the child views - because we are delaying the start
|
||||
// of the animation, we need to prevent the items being drawn in their final position
|
||||
// prior to the animation starting
|
||||
for (int x = 1, i = (removedPosition - firstPosition) + 1; i < childCount; i++, x++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
final PointF targetLocation = tabLocations.get(x + 1);
|
||||
if (targetLocation == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
child.setX(targetLocation.x);
|
||||
child.setY(targetLocation.y);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void animateCancel(final View view) {
|
||||
PropertyAnimator animator = new PropertyAnimator(ANIM_TIME_MS);
|
||||
animator.attach(view, PropertyAnimator.Property.ALPHA, 1);
|
||||
animator.attach(view, PropertyAnimator.Property.TRANSLATION_X, 0);
|
||||
|
||||
animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
|
||||
@Override
|
||||
public void onPropertyAnimationStart() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertyAnimationEnd() {
|
||||
TabsLayoutItemView tab = (TabsLayoutItemView) view;
|
||||
tab.setCloseVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
animator.start();
|
||||
}
|
||||
|
||||
private class TabsGridLayoutAdapter extends TabsLayoutAdapter {
|
||||
|
||||
final private Button.OnClickListener mCloseClickListener;
|
||||
|
||||
public TabsGridLayoutAdapter(Context context) {
|
||||
super(context, R.layout.tabs_layout_item_view);
|
||||
|
||||
mCloseClickListener = new Button.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
closeTab(v);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
TabsLayoutItemView newView(int position, ViewGroup parent) {
|
||||
final TabsLayoutItemView item = super.newView(position, parent);
|
||||
|
||||
item.setCloseOnClickListener(mCloseClickListener);
|
||||
((ThemedRelativeLayout) item.findViewById(R.id.wrapper)).setPrivateMode(isPrivate);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(TabsLayoutItemView view, Tab tab) {
|
||||
super.bindView(view, tab);
|
||||
|
||||
// If we're recycling this view, there's a chance it was transformed during
|
||||
// the close animation. Remove any of those properties.
|
||||
resetTransforms(view);
|
||||
}
|
||||
}
|
||||
|
||||
private class TabSwipeGestureListener implements View.OnTouchListener {
|
||||
// same value the stock browser uses for after drag animation velocity in pixels/sec
|
||||
// http://androidxref.com/4.0.4/xref/packages/apps/Browser/src/com/android/browser/NavTabScroller.java#61
|
||||
private static final float MIN_VELOCITY = 750;
|
||||
|
||||
private final int mSwipeThreshold;
|
||||
private final int mMinFlingVelocity;
|
||||
|
||||
private final int mMaxFlingVelocity;
|
||||
private VelocityTracker mVelocityTracker;
|
||||
|
||||
private int mTabWidth = 1;
|
||||
|
||||
private View mSwipeView;
|
||||
private Runnable mPendingCheckForTap;
|
||||
|
||||
private float mSwipeStartX;
|
||||
private boolean mSwiping;
|
||||
private boolean mEnabled;
|
||||
|
||||
public TabSwipeGestureListener() {
|
||||
mEnabled = true;
|
||||
|
||||
ViewConfiguration vc = ViewConfiguration.get(TabsGridLayout.this.getContext());
|
||||
mSwipeThreshold = vc.getScaledTouchSlop();
|
||||
mMinFlingVelocity = (int) (TabsGridLayout.this.getContext().getResources().getDisplayMetrics().density * MIN_VELOCITY);
|
||||
mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
mEnabled = enabled;
|
||||
}
|
||||
|
||||
public OnScrollListener makeScrollListener() {
|
||||
return new OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(AbsListView view, int scrollState) {
|
||||
setEnabled(scrollState != GridView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent e) {
|
||||
if (!mEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (e.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
// Check if we should set pressed state on the
|
||||
// touched view after a standard delay.
|
||||
triggerCheckForTap();
|
||||
|
||||
final float x = e.getRawX();
|
||||
final float y = e.getRawY();
|
||||
|
||||
// Find out which view is being touched
|
||||
mSwipeView = findViewAt(x, y);
|
||||
|
||||
if (mSwipeView != null) {
|
||||
if (mTabWidth < 2) {
|
||||
mTabWidth = mSwipeView.getWidth();
|
||||
}
|
||||
|
||||
mSwipeStartX = e.getRawX();
|
||||
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
mVelocityTracker.addMovement(e);
|
||||
}
|
||||
|
||||
view.onTouchEvent(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_UP: {
|
||||
if (mSwipeView == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
cancelCheckForTap();
|
||||
mSwipeView.setPressed(false);
|
||||
|
||||
if (!mSwiping) {
|
||||
final TabsLayoutItemView item = (TabsLayoutItemView) mSwipeView;
|
||||
final int tabId = item.getTabId();
|
||||
final Tab tab = Tabs.getInstance().selectTab(tabId);
|
||||
if (tab != null) {
|
||||
autoHidePanel();
|
||||
Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.OPENED_FROM_TABS_TRAY);
|
||||
}
|
||||
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
break;
|
||||
}
|
||||
|
||||
mVelocityTracker.addMovement(e);
|
||||
mVelocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity);
|
||||
|
||||
float velocityX = Math.abs(mVelocityTracker.getXVelocity());
|
||||
|
||||
boolean dismiss = false;
|
||||
|
||||
float deltaX = mSwipeView.getTranslationX();
|
||||
|
||||
if (Math.abs(deltaX) > mTabWidth / 2) {
|
||||
dismiss = true;
|
||||
} else if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity) {
|
||||
dismiss = mSwiping && (deltaX * mVelocityTracker.getYVelocity() > 0);
|
||||
}
|
||||
if (dismiss) {
|
||||
closeTab(mSwipeView.findViewById(R.id.close));
|
||||
} else {
|
||||
animateCancel(mSwipeView);
|
||||
}
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
mSwipeView = null;
|
||||
|
||||
mSwipeStartX = 0;
|
||||
mSwiping = false;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
if (mSwipeView == null || mVelocityTracker == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
mVelocityTracker.addMovement(e);
|
||||
|
||||
float delta = e.getRawX() - mSwipeStartX;
|
||||
|
||||
boolean isScrollingX = Math.abs(delta) > mSwipeThreshold;
|
||||
boolean isSwipingToClose = isScrollingX;
|
||||
|
||||
// If we're actually swiping, make sure we don't
|
||||
// set pressed state on the swiped view.
|
||||
if (isScrollingX) {
|
||||
cancelCheckForTap();
|
||||
}
|
||||
|
||||
if (isSwipingToClose) {
|
||||
mSwiping = true;
|
||||
TabsGridLayout.this.requestDisallowInterceptTouchEvent(true);
|
||||
|
||||
((TabsLayoutItemView) mSwipeView).setCloseVisible(false);
|
||||
|
||||
// Stops listview from highlighting the touched item
|
||||
// in the list when swiping.
|
||||
MotionEvent cancelEvent = MotionEvent.obtain(e);
|
||||
cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
|
||||
(e.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
|
||||
TabsGridLayout.this.onTouchEvent(cancelEvent);
|
||||
cancelEvent.recycle();
|
||||
}
|
||||
|
||||
if (mSwiping) {
|
||||
mSwipeView.setTranslationX(delta);
|
||||
|
||||
mSwipeView.setAlpha(Math.min(1f, 1f - 2f * Math.abs(delta) / mTabWidth));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private View findViewAt(float rawX, float rawY) {
|
||||
Rect rect = new Rect();
|
||||
|
||||
int[] listViewCoords = new int[2];
|
||||
TabsGridLayout.this.getLocationOnScreen(listViewCoords);
|
||||
|
||||
int x = (int) rawX - listViewCoords[0];
|
||||
int y = (int) rawY - listViewCoords[1];
|
||||
|
||||
for (int i = 0; i < TabsGridLayout.this.getChildCount(); i++) {
|
||||
View child = TabsGridLayout.this.getChildAt(i);
|
||||
child.getHitRect(rect);
|
||||
|
||||
if (rect.contains(x, y)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void triggerCheckForTap() {
|
||||
if (mPendingCheckForTap == null) {
|
||||
mPendingCheckForTap = new CheckForTap();
|
||||
}
|
||||
|
||||
TabsGridLayout.this.postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
|
||||
}
|
||||
|
||||
private void cancelCheckForTap() {
|
||||
if (mPendingCheckForTap == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TabsGridLayout.this.removeCallbacks(mPendingCheckForTap);
|
||||
}
|
||||
|
||||
private class CheckForTap implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!mSwiping && mSwipeView != null && mEnabled) {
|
||||
mSwipeView.setPressed(true);
|
||||
final GridLayoutManager layoutManager = (GridLayoutManager) getLayoutManager();
|
||||
|
||||
final int nonPaddingWidth = w - getPaddingLeft() - getPaddingRight();
|
||||
// We lay out the tabs so that the outer two tab edges are butted up against the
|
||||
// RecyclerView padding, and then all other tab edges get their own padding, so
|
||||
// nonPaddingWidth in terms of tab width w and tab spacing s for n tabs is
|
||||
// n * w + (n - 1) * s
|
||||
// Solving for n gives the formulas below.
|
||||
final int idealSpacingSpanCount = Math.max(1,
|
||||
(nonPaddingWidth + desiredHorizontalItemSpacing) / (desiredItemWidth + desiredHorizontalItemSpacing));
|
||||
final int maxSpanCount = Math.max(1,
|
||||
(nonPaddingWidth + minHorizontalItemSpacing) / (desiredItemWidth + minHorizontalItemSpacing));
|
||||
|
||||
// General caution note: span count can change here at a point where some ItemDecorations
|
||||
// have been computed and some have not, and Android doesn't recompute ItemDecorations after
|
||||
// a setSpanCount call, so we need to always remove and then add back our spacingDecoration
|
||||
// (whose computations depend on spanCount) in order to get a full layout recompute.
|
||||
if (idealSpacingSpanCount == maxSpanCount) {
|
||||
layoutManager.setSpanCount(idealSpacingSpanCount);
|
||||
updateSpacingDecoration(desiredHorizontalItemSpacing);
|
||||
} else {
|
||||
// We're gaining a column by decreasing the item spacing - this actually turns out to be
|
||||
// necessary to fit three columns in landscape mode on many phones. It also allows us
|
||||
// to match the span counts produced by the previous GridLayout implementation.
|
||||
layoutManager.setSpanCount(maxSpanCount);
|
||||
|
||||
// Increase the spacing as much as we can without giving up our increased span count.
|
||||
for (int spacing = minHorizontalItemSpacing + 1; spacing <= desiredHorizontalItemSpacing; spacing++) {
|
||||
if (maxSpanCount * desiredItemWidth + (maxSpanCount - 1) * spacing > nonPaddingWidth) {
|
||||
updateSpacingDecoration(spacing - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// We should never get here if our calculations above were correct.
|
||||
Log.e(LOGTAG, "Span count calculation error");
|
||||
updateSpacingDecoration(minHorizontalItemSpacing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.tabs;
|
||||
|
||||
import org.mozilla.gecko.widget.DefaultItemAnimatorBase;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
||||
class TabsGridLayoutAnimator extends DefaultItemAnimatorBase {
|
||||
public TabsGridLayoutAnimator() {
|
||||
setSupportsChangeAnimations(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean preAnimateRemoveImpl(final RecyclerView.ViewHolder holder) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ public abstract class TabsLayout extends RecyclerView
|
|||
|
||||
private final boolean isPrivate;
|
||||
private TabsPanel tabsPanel;
|
||||
private final TabsLayoutRecyclerAdapter tabsAdapter;
|
||||
private final TabsLayoutAdapter tabsAdapter;
|
||||
|
||||
public TabsLayout(Context context, AttributeSet attrs, int itemViewLayoutResId) {
|
||||
super(context, attrs);
|
||||
|
@ -39,7 +39,7 @@ public abstract class TabsLayout extends RecyclerView
|
|||
isPrivate = (a.getInt(R.styleable.TabsLayout_tabs, 0x0) == 1);
|
||||
a.recycle();
|
||||
|
||||
tabsAdapter = new TabsLayoutRecyclerAdapter(context, itemViewLayoutResId, isPrivate,
|
||||
tabsAdapter = new TabsLayoutAdapter(context, itemViewLayoutResId, isPrivate,
|
||||
/* close on click listener */
|
||||
new Button.OnClickListener() {
|
||||
@Override
|
||||
|
@ -101,8 +101,8 @@ public abstract class TabsLayout extends RecyclerView
|
|||
final int tabIndex = Integer.parseInt(data);
|
||||
tabsAdapter.notifyTabInserted(tab, tabIndex);
|
||||
if (addAtIndexRequiresScroll(tabIndex)) {
|
||||
// (The current Tabs implementation updates the SELECTED tab *after* this
|
||||
// call to ADDED, so don't just call updateSelectedPosition().)
|
||||
// (The SELECTED tab is updated *after* this call to ADDED, so don't just call
|
||||
// updateSelectedPosition().)
|
||||
scrollToPosition(tabIndex);
|
||||
}
|
||||
break;
|
||||
|
@ -124,10 +124,16 @@ public abstract class TabsLayout extends RecyclerView
|
|||
}
|
||||
}
|
||||
|
||||
// Addition of a tab at selected positions (dependent on LayoutManager) will result in a tab
|
||||
// being added out of view - return true if index is such a position.
|
||||
/**
|
||||
* Addition of a tab at selected positions (dependent on LayoutManager) will result in a tab
|
||||
* being added out of view - return true if {@code index} is such a position.
|
||||
*/
|
||||
abstract protected boolean addAtIndexRequiresScroll(int index);
|
||||
|
||||
protected int getSelectedAdapterPosition() {
|
||||
return tabsAdapter.getPositionForTab(Tabs.getInstance().getSelectedTab());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
|
||||
final TabsLayoutItemView item = (TabsLayoutItemView) v;
|
||||
|
@ -143,9 +149,9 @@ public abstract class TabsLayout extends RecyclerView
|
|||
Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.OPENED_FROM_TABS_TRAY);
|
||||
}
|
||||
|
||||
// Updates the selected position in the list so that it will be scrolled to the right place.
|
||||
private void updateSelectedPosition() {
|
||||
final int selected = tabsAdapter.getPositionForTab(Tabs.getInstance().getSelectedTab());
|
||||
/** Updates the selected position in the list so that it will be scrolled to the right place. */
|
||||
protected void updateSelectedPosition() {
|
||||
final int selected = getSelectedAdapterPosition();
|
||||
if (selected != NO_POSITION) {
|
||||
scrollToPosition(selected);
|
||||
}
|
||||
|
@ -199,6 +205,15 @@ public abstract class TabsLayout extends RecyclerView
|
|||
closeTab(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildAttachedToWindow(View child) {
|
||||
// Make sure we reset any attributes that may have been animated in this child's previous
|
||||
// incarnation.
|
||||
child.setTranslationX(0);
|
||||
child.setTranslationY(0);
|
||||
child.setAlpha(1);
|
||||
}
|
||||
|
||||
private Tab getTabForView(View view) {
|
||||
if (view == null) {
|
||||
return null;
|
||||
|
|
|
@ -5,96 +5,123 @@
|
|||
|
||||
package org.mozilla.gecko.tabs;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Tab;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
// Adapter to bind tabs into a list
|
||||
public class TabsLayoutAdapter extends BaseAdapter {
|
||||
public static final String LOGTAG = "Gecko" + TabsLayoutAdapter.class.getSimpleName();
|
||||
public class TabsLayoutAdapter
|
||||
extends RecyclerView.Adapter<TabsLayoutAdapter.TabsListViewHolder> {
|
||||
|
||||
private final Context mContext;
|
||||
private final int mTabLayoutId;
|
||||
private ArrayList<Tab> mTabs;
|
||||
private final LayoutInflater mInflater;
|
||||
private static final String LOGTAG = "Gecko" + TabsLayoutAdapter.class.getSimpleName();
|
||||
|
||||
public TabsLayoutAdapter (Context context, int tabLayoutId) {
|
||||
mContext = context;
|
||||
mInflater = LayoutInflater.from(mContext);
|
||||
mTabLayoutId = tabLayoutId;
|
||||
}
|
||||
private final int tabLayoutId;
|
||||
private @NonNull ArrayList<Tab> tabs;
|
||||
private final LayoutInflater inflater;
|
||||
private final boolean isPrivate;
|
||||
// Click listener for the close button on itemViews.
|
||||
private final Button.OnClickListener closeOnClickListener;
|
||||
|
||||
final void setTabs (ArrayList<Tab> tabs) {
|
||||
mTabs = tabs;
|
||||
notifyDataSetChanged(); // Be sure to call this whenever mTabs changes.
|
||||
}
|
||||
|
||||
final boolean removeTab (Tab tab) {
|
||||
boolean tabRemoved = mTabs.remove(tab);
|
||||
if (tabRemoved) {
|
||||
notifyDataSetChanged(); // Be sure to call this whenever mTabs changes.
|
||||
// The TabsLayoutItemView takes care of caching its own Views, so we don't need to do anything
|
||||
// here except not be abstract.
|
||||
public static class TabsListViewHolder extends RecyclerView.ViewHolder {
|
||||
public TabsListViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
return tabRemoved;
|
||||
}
|
||||
|
||||
final void clear() {
|
||||
mTabs = null;
|
||||
|
||||
notifyDataSetChanged(); // Be sure to call this whenever mTabs changes.
|
||||
public TabsLayoutAdapter(Context context, int tabLayoutId, boolean isPrivate,
|
||||
Button.OnClickListener closeOnClickListener) {
|
||||
inflater = LayoutInflater.from(context);
|
||||
this.tabLayoutId = tabLayoutId;
|
||||
this.isPrivate = isPrivate;
|
||||
this.closeOnClickListener = closeOnClickListener;
|
||||
tabs = new ArrayList<>(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return (mTabs == null ? 0 : mTabs.size());
|
||||
/* package */ final void setTabs(@NonNull ArrayList<Tab> tabs) {
|
||||
this.tabs = tabs;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getItem(int position) {
|
||||
return mTabs.get(position);
|
||||
/* package */ final void clear() {
|
||||
tabs = new ArrayList<>(0);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
final int getPositionForTab(Tab tab) {
|
||||
if (mTabs == null || tab == null)
|
||||
return -1;
|
||||
|
||||
return mTabs.indexOf(tab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
/* package */ final boolean removeTab(Tab tab) {
|
||||
final int position = getPositionForTab(tab);
|
||||
if (position == -1) {
|
||||
return false;
|
||||
}
|
||||
tabs.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
final public TabsLayoutItemView getView(int position, View convertView, ViewGroup parent) {
|
||||
final TabsLayoutItemView view;
|
||||
if (convertView == null) {
|
||||
view = newView(position, parent);
|
||||
} else {
|
||||
view = (TabsLayoutItemView) convertView;
|
||||
/* package */ final int getPositionForTab(Tab tab) {
|
||||
if (tab == null) {
|
||||
return -1;
|
||||
}
|
||||
final Tab tab = mTabs.get(position);
|
||||
bindView(view, tab);
|
||||
return view;
|
||||
|
||||
return tabs.indexOf(tab);
|
||||
}
|
||||
|
||||
TabsLayoutItemView newView(int position, ViewGroup parent) {
|
||||
return (TabsLayoutItemView) mInflater.inflate(mTabLayoutId, parent, false);
|
||||
/* package */ void notifyTabChanged(Tab tab) {
|
||||
final int position = getPositionForTab(tab);
|
||||
if (position != -1) {
|
||||
notifyItemChanged(position);
|
||||
}
|
||||
}
|
||||
|
||||
void bindView(TabsLayoutItemView view, Tab tab) {
|
||||
view.assignValues(tab);
|
||||
/* package */ void notifyTabInserted(Tab tab, int index) {
|
||||
if (index >= 0 && index <= tabs.size()) {
|
||||
tabs.add(index, tab);
|
||||
notifyItemInserted(index);
|
||||
} else {
|
||||
// Add to the end.
|
||||
tabs.add(tab);
|
||||
notifyItemInserted(tabs.size() - 1);
|
||||
// index == -1 is a valid way to add to the end, the other cases are errors.
|
||||
if (index != -1) {
|
||||
Log.e(LOGTAG, "Tab was inserted at an invalid position: " + Integer.toString(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return tabs.size();
|
||||
}
|
||||
|
||||
private Tab getItem(int position) {
|
||||
return tabs.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(TabsListViewHolder viewHolder, int position) {
|
||||
final Tab tab = getItem(position);
|
||||
final TabsLayoutItemView itemView = (TabsLayoutItemView) viewHolder.itemView;
|
||||
itemView.assignValues(tab);
|
||||
// Be careful (re)setting position values here: bind is called on each notifyItemChanged,
|
||||
// so you could be stomping on values that have been set in support of other animations
|
||||
// that are already underway.
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabsListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
final TabsLayoutItemView viewItem = (TabsLayoutItemView) inflater.inflate(tabLayoutId, parent, false);
|
||||
viewItem.setPrivateMode(isPrivate);
|
||||
viewItem.setCloseOnClickListener(closeOnClickListener);
|
||||
|
||||
return new TabsListViewHolder(viewItem);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,13 @@ public class TabsListLayout extends TabsLayout {
|
|||
setLayoutManager(new LinearLayoutManager(context));
|
||||
|
||||
// A TouchHelper handler for swipe to close.
|
||||
final TabsTouchHelperCallback callback = new TabsTouchHelperCallback(this);
|
||||
final TabsTouchHelperCallback callback = new TabsTouchHelperCallback(this) {
|
||||
@Override
|
||||
protected float alphaForItemSwipeDx(float dX, int distanceToAlphaMin) {
|
||||
return Math.max(0.1f,
|
||||
Math.min(1f, 1f - 2f * Math.abs(dX) / distanceToAlphaMin));
|
||||
}
|
||||
};
|
||||
final ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
|
||||
touchHelper.attachToRecyclerView(this);
|
||||
|
||||
|
@ -106,13 +112,4 @@ public class TabsListLayout extends TabsLayout {
|
|||
protected boolean addAtIndexRequiresScroll(int index) {
|
||||
return index == 0 || index == getAdapter().getItemCount() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildAttachedToWindow(View child) {
|
||||
// Make sure we reset any attributes that may have been animated in this child's previous
|
||||
// incarnation.
|
||||
child.setTranslationX(0);
|
||||
child.setTranslationY(0);
|
||||
child.setAlpha(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import android.support.v7.widget.RecyclerView;
|
|||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.view.View;
|
||||
|
||||
class TabsTouchHelperCallback extends ItemTouchHelper.Callback {
|
||||
abstract class TabsTouchHelperCallback extends ItemTouchHelper.Callback {
|
||||
private final DismissListener dismissListener;
|
||||
|
||||
interface DismissListener {
|
||||
|
@ -42,8 +42,16 @@ class TabsTouchHelperCallback extends ItemTouchHelper.Callback {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Alpha on an itemView being swiped should decrease to a min over a distance equal to the
|
||||
// width of the item being swiped.
|
||||
/**
|
||||
* Returns the alpha an itemView should be set to when swiped by an amount {@code dX}, given
|
||||
* that alpha should decrease to its min at distance {@code distanceToAlphaMin}.
|
||||
*/
|
||||
abstract protected float alphaForItemSwipeDx(float dX, int distanceToAlphaMin);
|
||||
|
||||
/**
|
||||
* Alpha on an itemView being swiped should decrease to a min over a distance equal to the
|
||||
* width of the item being swiped.
|
||||
*/
|
||||
@Override
|
||||
public void onChildDraw(Canvas c,
|
||||
RecyclerView recyclerView,
|
||||
|
@ -58,8 +66,7 @@ class TabsTouchHelperCallback extends ItemTouchHelper.Callback {
|
|||
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||
|
||||
viewHolder.itemView.setAlpha(Math.max(0.1f,
|
||||
Math.min(1f, 1f - 2f * Math.abs(dX) / viewHolder.itemView.getWidth())));
|
||||
viewHolder.itemView.setAlpha(alphaForItemSwipeDx(dX, viewHolder.itemView.getWidth()));
|
||||
}
|
||||
|
||||
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
|
|
|
@ -94,32 +94,6 @@ final class UnusedResourcesUtil {
|
|||
R.xml.preferences_default_browser_tablet
|
||||
};
|
||||
|
||||
// We are migrating to Gradle 2.10 and the Android Gradle plugin 2.0. The new plugin does find
|
||||
// more unused resources but we are not ready to remove them yet. Some of the resources are going
|
||||
// to be reused soon. This is a temporary solution so that the gradle migration is not blocked.
|
||||
// See bug 1263390 / bug 1268414.
|
||||
public static final int[] TEMPORARY_UNUSED_WHILE_MIGRATING_GRADLE = {
|
||||
R.color.remote_tabs_setup_button_background_hit,
|
||||
|
||||
R.drawable.remote_tabs_setup_button_background,
|
||||
|
||||
R.style.TabsPanelSectionBase,
|
||||
R.style.TabsPanelSection,
|
||||
R.style.TabsPanelItemBase,
|
||||
R.style.TabsPanelItem,
|
||||
R.style.TabsPanelItem_TextAppearance,
|
||||
R.style.TabsPanelItem_TextAppearance_Header,
|
||||
R.style.TabsPanelItem_TextAppearance_Linkified,
|
||||
R.style.TabWidget,
|
||||
R.style.GeckoDialogTitle,
|
||||
R.style.GeckoDialogTitle_SubTitle,
|
||||
R.style.RemoteTabsPanelItem,
|
||||
R.style.RemoteTabsPanelItem_TextAppearance,
|
||||
R.style.RemoteTabsPanelItem_TextAppearance_Header,
|
||||
R.style.RemoteTabsPanelItem_TextAppearance_Linkified,
|
||||
R.style.RemoteTabsPanelItem_Button,
|
||||
};
|
||||
|
||||
// String resources that are used in the full-pane Activity Stream that are temporarily
|
||||
// not needed while Activity Stream is part of the HomePager
|
||||
public static final int[] TEMPORARY_UNUSED_ACTIVITY_STREAM = {
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* An ItemDecoration for a GridLayoutManager that provides fixed spacing (but not fixed padding)
|
||||
* to create fixed sized items, with no spacing on the outer edges of the outer items.
|
||||
* <p>
|
||||
* So, for example, if there are 2 columns and the spacing is s, then the first column gets a right
|
||||
* padding of s/2 and the second column gets a left paddding of s/2. If there are three columns
|
||||
* then the first column gets a right padding of 2s/3, the second column gets left and right
|
||||
* paddings of s/3, and the third column gets a left padding of 2s/3.
|
||||
* </p>
|
||||
*/
|
||||
public class GridSpacingDecoration extends RecyclerView.ItemDecoration {
|
||||
private final int horizontalSpacing;
|
||||
private final int verticalPadding;
|
||||
|
||||
public GridSpacingDecoration(int horizontalSpacing, int verticalPadding) {
|
||||
this.horizontalSpacing = horizontalSpacing;
|
||||
this.verticalPadding = verticalPadding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||
final int position = parent.getChildAdapterPosition(view);
|
||||
if (position == RecyclerView.NO_POSITION) {
|
||||
return;
|
||||
}
|
||||
|
||||
final GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
|
||||
final int spanCount = layoutManager.getSpanCount();
|
||||
final int column = position % spanCount;
|
||||
|
||||
final int columnLeftOffset = (int) (((float) column / (float) spanCount) * horizontalSpacing);
|
||||
final int columnRightOffset = (int) (((float) (spanCount - (column + 1)) / (float) spanCount) * horizontalSpacing);
|
||||
|
||||
outRect.set(columnLeftOffset, verticalPadding, columnRightOffset, verticalPadding);
|
||||
}
|
||||
}
|
|
@ -685,10 +685,10 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
|||
'tabs/TabHistoryPage.java',
|
||||
'tabs/TabPanelBackButton.java',
|
||||
'tabs/TabsGridLayout.java',
|
||||
'tabs/TabsGridLayoutAnimator.java',
|
||||
'tabs/TabsLayout.java',
|
||||
'tabs/TabsLayoutAdapter.java',
|
||||
'tabs/TabsLayoutItemView.java',
|
||||
'tabs/TabsLayoutRecyclerAdapter.java',
|
||||
'tabs/TabsListLayout.java',
|
||||
'tabs/TabsListLayoutAnimator.java',
|
||||
'tabs/TabsPanel.java',
|
||||
|
@ -770,6 +770,7 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
|||
'widget/FlowLayout.java',
|
||||
'widget/GeckoActionProvider.java',
|
||||
'widget/GeckoPopupMenu.java',
|
||||
'widget/GridSpacingDecoration.java',
|
||||
'widget/HistoryDividerItemDecoration.java',
|
||||
'widget/IconTabWidget.java',
|
||||
'widget/LoginDoorHanger.java',
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
xmlns:gecko="http://schemas.android.com/apk/res-auto"
|
||||
style="@style/TabsItem"
|
||||
android:id="@+id/info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout android:layout_width="fill_parent"
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:duplicateParentState="true"
|
||||
|
@ -60,8 +60,8 @@
|
|||
android:clipToPadding="false">
|
||||
|
||||
<org.mozilla.gecko.tabs.TabsPanelThumbnailView android:id="@+id/thumbnail"
|
||||
android:layout_width="@dimen/tab_thumbnail_width"
|
||||
android:layout_height="@dimen/tab_thumbnail_height"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="2dp"
|
||||
android:outlineProvider="bounds"
|
||||
/>
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
|
||||
<!-- Remote Tabs static view top padding. Less in landscape on phones. -->
|
||||
<dimen name="home_remote_tabs_top_padding">16dp</dimen>
|
||||
<dimen name="tab_panel_grid_padding">48dp</dimen>
|
||||
<dimen name="tab_panel_grid_hpadding">48dp</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -18,15 +18,4 @@
|
|||
<item name="android:nextFocusUp">@+id/info</item>
|
||||
</style>
|
||||
|
||||
<!-- Tabs panel -->
|
||||
<style name="TabsPanelSection" parent="TabsPanelSectionBase">
|
||||
<item name="android:layout_weight">1</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem">
|
||||
<item name="android:layout_marginBottom">20dp</item>
|
||||
<item name="android:layout_gravity">left</item>
|
||||
<item name="android:gravity">left</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -21,14 +21,4 @@
|
|||
<item name="android:verticalSpacing">20dp</item>
|
||||
</style>
|
||||
|
||||
<!-- Tabs panel -->
|
||||
<style name="TabsPanelSection" parent="TabsPanelSectionBase">
|
||||
<item name="android:layout_marginLeft">20dp</item>
|
||||
<item name="android:layout_marginRight">20dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem" parent="TabsPanelItemBase">
|
||||
<!-- To override the values-land style. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<resources>
|
||||
<dimen name="tab_panel_column_width">143dip</dimen>
|
||||
<dimen name="tab_panel_item_width">143dip</dimen>
|
||||
<dimen name="tab_thumbnail_height">100dip</dimen>
|
||||
<dimen name="tab_thumbnail_width">135dip</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<resources>
|
||||
<dimen name="tab_panel_column_width">156dip</dimen>
|
||||
<dimen name="tab_panel_item_width">156dip</dimen>
|
||||
<dimen name="tab_thumbnail_height">110dip</dimen>
|
||||
<dimen name="tab_thumbnail_width">148dip</dimen>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<resources>
|
||||
<dimen name="tab_panel_column_width">176dip</dimen>
|
||||
<dimen name="tab_panel_item_width">176dip</dimen>
|
||||
<dimen name="tab_thumbnail_height">120dip</dimen>
|
||||
<dimen name="tab_thumbnail_width">168dip</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
<item name="menuItemSwitcherLayoutStyle">@style/Widget.MenuItemSwitcherLayout</item>
|
||||
<item name="menuItemDefaultStyle">@style/Widget.MenuItemDefault</item>
|
||||
<item name="menuItemSecondaryActionBarStyle">@style/Widget.MenuItemSecondaryActionBar</item>
|
||||
<item name="tabGridLayoutViewStyle">@style/Widget.TabsGridLayout</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -5,11 +5,6 @@
|
|||
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<style name="GeckoDialogTitle">
|
||||
<!-- Override this to use a Holo theme on v13+ -->
|
||||
<item name="android:textAppearance">@android:style/TextAppearance.Holo.DialogWindowTitle</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Widget.ActionBar.Title" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Title"/>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
<item name="menuItemSwitcherLayoutStyle">@style/Widget.MenuItemSwitcherLayout</item>
|
||||
<item name="menuItemDefaultStyle">@style/Widget.MenuItemDefault</item>
|
||||
<item name="menuItemSecondaryActionBarStyle">@style/Widget.MenuItemSecondaryActionBar</item>
|
||||
<item name="tabGridLayoutViewStyle">@style/Widget.TabsGridLayout</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
|
||||
<resources>
|
||||
|
||||
<dimen name="tab_panel_grid_padding">64dp</dimen>
|
||||
<dimen name="tab_panel_grid_hpadding">64dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
<resources>
|
||||
|
||||
<dimen name="panel_grid_view_column_width">250dp</dimen>
|
||||
<dimen name="tab_panel_grid_padding">48dp</dimen>
|
||||
<dimen name="tab_panel_grid_hpadding">48dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -10,12 +10,6 @@
|
|||
Please refer to values/styles.xml for default styles.
|
||||
-->
|
||||
|
||||
<!-- TabWidget -->
|
||||
<style name="TabWidget">
|
||||
<item name="android:layout_width">300dip</item>
|
||||
<item name="android:layout_height">48dip</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.TopSitesListView" parent="Widget.BookmarksListView">
|
||||
<item name="android:paddingTop">30dp</item>
|
||||
<item name="android:paddingLeft">32dp</item>
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
<!-- Styles for dynamic panel grid views -->
|
||||
<attr name="panelIconViewStyle" format="reference" />
|
||||
|
||||
<!-- Style for the TabsGridLayout -->
|
||||
<attr name="tabGridLayoutViewStyle" format="reference" />
|
||||
|
||||
<!-- Default style for the TopSitesGridView -->
|
||||
<attr name="topSitesGridViewStyle" format="reference" />
|
||||
|
||||
|
|
|
@ -144,10 +144,12 @@
|
|||
|
||||
<dimen name="tab_thumbnail_width">121dp</dimen>
|
||||
<dimen name="tab_thumbnail_height">90dp</dimen>
|
||||
<dimen name="tab_panel_column_width">129dp</dimen>
|
||||
<dimen name="tab_panel_grid_padding">20dp</dimen>
|
||||
<dimen name="tab_panel_grid_vspacing">20dp</dimen>
|
||||
<dimen name="tab_panel_grid_padding_top">19dp</dimen>
|
||||
<dimen name="tab_panel_item_width">129dp</dimen>
|
||||
<dimen name="tab_panel_grid_hpadding">20dp</dimen>
|
||||
<dimen name="tab_panel_grid_vpadding">19dp</dimen>
|
||||
<dimen name="tab_panel_grid_ideal_item_hspacing">20dp</dimen>
|
||||
<dimen name="tab_panel_grid_min_item_hspacing">2dp</dimen>
|
||||
<dimen name="tab_panel_grid_item_vpadding">10dp</dimen>
|
||||
|
||||
<dimen name="tab_highlight_stroke_width">4dp</dimen>
|
||||
|
||||
|
|
|
@ -180,21 +180,6 @@
|
|||
<item name="android:orientation">vertical</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.TabsGridLayout" parent="Widget.GridView">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
<item name="android:paddingTop">0dp</item>
|
||||
<item name="android:stretchMode">spacingWidth</item>
|
||||
<item name="android:scrollbarStyle">outsideOverlay</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:numColumns">auto_fit</item>
|
||||
<item name="android:columnWidth">@dimen/tab_panel_column_width</item>
|
||||
<item name="android:horizontalSpacing">2dp</item>
|
||||
<item name="android:verticalSpacing">@dimen/tab_panel_grid_vspacing</item>
|
||||
<item name="android:drawSelectorOnTop">true</item>
|
||||
<item name="android:clipToPadding">false</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.BookmarkItemView" parent="Widget.TwoLinePageRow"/>
|
||||
|
||||
<style name="Widget.BookmarksListView" parent="Widget.HomeListView"/>
|
||||
|
@ -493,44 +478,6 @@
|
|||
<item name="android:nextFocusLeft">@+id/info</item>
|
||||
</style>
|
||||
|
||||
<!-- Tabs panel -->
|
||||
<style name="TabsPanelSectionBase">
|
||||
<item name="android:orientation">vertical</item>
|
||||
<item name="android:layout_marginLeft">40dp</item>
|
||||
<item name="android:layout_marginRight">40dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelSection" parent="TabsPanelSectionBase">
|
||||
<!-- We set values in landscape. -->
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItemBase">
|
||||
<item name="android:layout_marginBottom">28dp</item>
|
||||
<item name="android:layout_gravity">center</item>
|
||||
<item name="android:gravity">center</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem" parent="TabsPanelItemBase">
|
||||
<!-- We set values in landscape. -->
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.TextAppearance">
|
||||
<item name="android:textColor">#C0C9D0</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:lineSpacingMultiplier">1.35</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.TextAppearance.Header">
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:layout_marginBottom">16dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.TextAppearance.Linkified">
|
||||
<item name="android:clickable">true</item>
|
||||
<item name="android:focusable">true</item>
|
||||
<item name="android:textColor">#0292D6</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.RemoteTabsItemView" parent="Widget.TwoLinePageRow"/>
|
||||
|
||||
<style name="Widget.RemoteTabsClientView" parent="Widget.TwoLinePageRow">
|
||||
|
@ -558,13 +505,6 @@
|
|||
<item name="android:textColor">#FFA4A7A9</item>
|
||||
</style>
|
||||
|
||||
<!-- TabWidget -->
|
||||
<style name="TabWidget">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">40dip</item>
|
||||
<item name="android:layout_weight">1.0</item>
|
||||
</style>
|
||||
|
||||
<!-- Find bar -->
|
||||
<style name="FindBar">
|
||||
<item name="android:background">@color/text_and_tabs_tray_grey</item>
|
||||
|
@ -585,12 +525,6 @@
|
|||
<item name="android:background">@drawable/action_bar_button_inverse</item>
|
||||
</style>
|
||||
|
||||
<style name="GeckoDialogTitle">
|
||||
<item name="android:textAppearance">@android:style/TextAppearance.DialogWindowTitle</item>
|
||||
</style>
|
||||
|
||||
<style name="GeckoDialogTitle.SubTitle" />
|
||||
|
||||
<style name="PopupAnimation">
|
||||
<item name="@android:windowEnterAnimation">@anim/popup_show</item>
|
||||
<item name="@android:windowExitAnimation">@anim/popup_hide</item>
|
||||
|
|
|
@ -95,7 +95,6 @@
|
|||
<item name="android:spinnerStyle">@style/Widget.Spinner</item>
|
||||
<item name="android:windowBackground">@android:color/white</item>
|
||||
<item name="bookmarksListViewStyle">@style/Widget.BookmarksListView</item>
|
||||
<item name="tabGridLayoutViewStyle">@style/Widget.TabsGridLayout</item>
|
||||
<item name="geckoMenuListViewStyle">@style/Widget.GeckoMenuListView</item>
|
||||
<item name="homeListViewStyle">@style/Widget.HomeListView</item>
|
||||
<item name="menuItemActionBarStyle">@style/Widget.MenuItemActionBar</item>
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.mozilla.gecko.util;
|
|||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
import org.mozilla.gecko.AppConstants.Versions;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaCodecInfo.CodecCapabilities;
|
||||
import android.media.MediaCodecList;
|
||||
|
@ -53,6 +54,25 @@ public final class HardwareCodecCapabilityUtils {
|
|||
return false;
|
||||
}
|
||||
|
||||
@WrapForJNI
|
||||
public static boolean checkSupportsAdaptivePlayback(MediaCodec aCodec, String aMimeType) {
|
||||
// isFeatureSupported supported on API level >= 19.
|
||||
if (!Versions.feature19Plus) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
MediaCodecInfo info = aCodec.getCodecInfo();
|
||||
MediaCodecInfo.CodecCapabilities capabilities = info.getCapabilitiesForType(aMimeType);
|
||||
return capabilities != null &&
|
||||
capabilities.isFeatureSupported(
|
||||
MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(LOGTAG, "Retrieve codec information failed", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean getHWEncoderCapability() {
|
||||
if (Versions.feature20Plus) {
|
||||
for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) {
|
||||
|
|
|
@ -16,11 +16,13 @@ import org.mozilla.gecko.icons.Icons;
|
|||
import org.mozilla.gecko.icons.storage.FailureCache;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
@ -109,4 +111,32 @@ public class TestIconDownloader {
|
|||
|
||||
Assert.assertTrue(FailureCache.get().isKnownFailure(faviconUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario: Connected to successfully to server but reading the response code throws an exception.
|
||||
*
|
||||
* Verify that:
|
||||
* * disconnect() is called on HttpUrlConnection
|
||||
*/
|
||||
@Test
|
||||
public void testConnectionIsClosedWhenReadingResponseCodeThrows() throws Exception {
|
||||
final IconRequest request = Icons.with(RuntimeEnvironment.application)
|
||||
.pageUrl("http://www.mozilla.org")
|
||||
.icon(IconDescriptor.createFavicon(
|
||||
"https://www.mozilla.org/media/img/favicon.52506929be4c.ico",
|
||||
32,
|
||||
"image/x-icon"))
|
||||
.build();
|
||||
|
||||
HttpURLConnection mockedConnection = mock(HttpURLConnection.class);
|
||||
doThrow(new IOException()).when(mockedConnection).getResponseCode();
|
||||
|
||||
final IconDownloader downloader = spy(new IconDownloader());
|
||||
doReturn(mockedConnection).when(downloader).connectTo(anyString());
|
||||
IconResponse response = downloader.load(request);
|
||||
|
||||
Assert.assertNull(response);
|
||||
|
||||
verify(mockedConnection).disconnect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -612,54 +612,15 @@ abstract class BaseTest extends BaseRobocopTest {
|
|||
}
|
||||
}
|
||||
|
||||
// A temporary tabs list/grid holder while the list and grid views are being transitioned to
|
||||
// RecyclerViews (bug 1116415 and bug 1310081).
|
||||
private static class TabsView {
|
||||
private AdapterView<ListAdapter> gridView;
|
||||
private RecyclerView listView;
|
||||
|
||||
public TabsView(View view) {
|
||||
if (view instanceof RecyclerView) {
|
||||
listView = (RecyclerView) view;
|
||||
} else {
|
||||
gridView = (AdapterView<ListAdapter>) view;
|
||||
}
|
||||
}
|
||||
|
||||
public void bringPositionIntoView(int index) {
|
||||
if (gridView != null) {
|
||||
gridView.setSelection(index);
|
||||
} else {
|
||||
listView.scrollToPosition(index);
|
||||
}
|
||||
}
|
||||
|
||||
public View getViewAtIndex(int index) {
|
||||
if (gridView != null) {
|
||||
return gridView.getChildAt(index - gridView.getFirstVisiblePosition());
|
||||
} else {
|
||||
final RecyclerView.ViewHolder itemViewHolder = listView.findViewHolderForLayoutPosition(index);
|
||||
return itemViewHolder == null ? null : itemViewHolder.itemView;
|
||||
}
|
||||
}
|
||||
|
||||
public void post(Runnable runnable) {
|
||||
if (gridView != null) {
|
||||
gridView.post(runnable);
|
||||
} else {
|
||||
listView.post(runnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets the AdapterView of the tabs list.
|
||||
* Gets the RecyclerView of the tabs list.
|
||||
*
|
||||
* @return List view in the tabs panel
|
||||
*/
|
||||
private final TabsView getTabsLayout() {
|
||||
private final RecyclerView getTabsLayout() {
|
||||
Element tabs = mDriver.findElement(getActivity(), R.id.tabs);
|
||||
tabs.click();
|
||||
return new TabsView(getActivity().findViewById(R.id.normal_tabs));
|
||||
return (RecyclerView) getActivity().findViewById(R.id.normal_tabs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -670,12 +631,12 @@ abstract class BaseTest extends BaseRobocopTest {
|
|||
private View getTabViewAt(final int index) {
|
||||
final View[] childView = { null };
|
||||
|
||||
final TabsView view = getTabsLayout();
|
||||
final RecyclerView view = getTabsLayout();
|
||||
|
||||
runOnUiThreadSync(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
view.bringPositionIntoView(index);
|
||||
view.scrollToPosition(index);
|
||||
|
||||
// The selection isn't updated synchronously; posting a
|
||||
// runnable to the view's queue guarantees we'll run after the
|
||||
|
@ -684,7 +645,9 @@ abstract class BaseTest extends BaseRobocopTest {
|
|||
@Override
|
||||
public void run() {
|
||||
// Index is relative to all views in the list.
|
||||
childView[0] = view.getViewAtIndex(index);
|
||||
final RecyclerView.ViewHolder itemViewHolder =
|
||||
view.findViewHolderForLayoutPosition(index);
|
||||
childView[0] = itemViewHolder == null ? null : itemViewHolder.itemView;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ interface nsIInterfaceRequestor;
|
|||
interface nsINetAddr;
|
||||
|
||||
%{ C++
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
union NetAddr;
|
||||
|
@ -17,6 +18,8 @@ union NetAddr;
|
|||
%}
|
||||
native NetAddr(mozilla::net::NetAddr);
|
||||
[ptr] native NetAddrPtr(mozilla::net::NetAddr);
|
||||
native NeckoOriginAttributes(mozilla::NeckoOriginAttributes);
|
||||
[ref] native const_OriginAttributesRef(const mozilla::NeckoOriginAttributes);
|
||||
|
||||
/**
|
||||
* nsISocketTransport
|
||||
|
@ -45,12 +48,20 @@ interface nsISocketTransport : nsITransport
|
|||
readonly attribute long port;
|
||||
|
||||
/**
|
||||
* This is only non-empty when "privacy.firstparty.isolate" is enabled.
|
||||
* It is used to create sockets, and will eventually be used to isolate
|
||||
* OCSP cache. It's the only way to carry it down to NSPR layers which are
|
||||
* final consumers. It must be set before the socket transport is built.
|
||||
* The origin attributes are used to create sockets. The first party domain
|
||||
* will eventually be used to isolate OCSP cache and is only non-empty when
|
||||
* "privacy.firstparty.isolate" is enabled. Setting this is the only way to
|
||||
* carry origin attributes down to NSPR layers which are final consumers.
|
||||
* It must be set before the socket transport is built.
|
||||
*/
|
||||
attribute AUTF8String firstPartyDomain;
|
||||
[implicit_jscontext, binaryname(ScriptableOriginAttributes)]
|
||||
attribute jsval originAttributes;
|
||||
|
||||
[noscript, nostdcall, binaryname(GetOriginAttributes)]
|
||||
NeckoOriginAttributes binaryGetOriginAttributes();
|
||||
|
||||
[noscript, nostdcall, binaryname(SetOriginAttributes)]
|
||||
void binarySetOriginAttributes(in const_OriginAttributesRef aOriginAttrs);
|
||||
|
||||
/**
|
||||
* The platform-specific network interface id that this socket
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "prerr.h"
|
||||
#include "NetworkActivityMonitor.h"
|
||||
#include "NSSErrorsService.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsISocketProviderService.h"
|
||||
|
@ -1169,7 +1170,7 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, bool &proxyTransparent, bool &us
|
|||
rv = provider->NewSocket(mNetAddr.raw.family,
|
||||
mHttpsProxy ? mProxyHost.get() : host,
|
||||
mHttpsProxy ? mProxyPort : port,
|
||||
proxyInfo, mFirstPartyDomain,
|
||||
proxyInfo, mOriginAttributes,
|
||||
controlFlags, &fd,
|
||||
getter_AddRefs(secinfo));
|
||||
|
||||
|
@ -1184,7 +1185,7 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, bool &proxyTransparent, bool &us
|
|||
// to the stack (such as pushing an io layer)
|
||||
rv = provider->AddToSocket(mNetAddr.raw.family,
|
||||
host, port, proxyInfo,
|
||||
mFirstPartyDomain, controlFlags, fd,
|
||||
mOriginAttributes, controlFlags, fd,
|
||||
getter_AddRefs(secinfo));
|
||||
}
|
||||
|
||||
|
@ -2391,19 +2392,46 @@ nsSocketTransport::SetNetworkInterfaceId(const nsACString_internal &aNetworkInte
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::GetFirstPartyDomain(nsACString &value)
|
||||
nsSocketTransport::GetScriptableOriginAttributes(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aOriginAttributes)
|
||||
{
|
||||
value = mFirstPartyDomain;
|
||||
if (NS_WARN_IF(!ToJSValue(aCx, mOriginAttributes, aOriginAttributes))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::SetFirstPartyDomain(const nsACString &value)
|
||||
nsSocketTransport::SetScriptableOriginAttributes(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aOriginAttributes)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
NS_ENSURE_FALSE(mFD.IsInitialized(), NS_ERROR_FAILURE);
|
||||
|
||||
mFirstPartyDomain = value;
|
||||
NeckoOriginAttributes attrs;
|
||||
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mOriginAttributes = attrs;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSocketTransport::GetOriginAttributes(NeckoOriginAttributes* aOriginAttributes)
|
||||
{
|
||||
NS_ENSURE_ARG(aOriginAttributes);
|
||||
*aOriginAttributes = mOriginAttributes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSocketTransport::SetOriginAttributes(const NeckoOriginAttributes& aOriginAttributes)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
NS_ENSURE_FALSE(mFD.IsInitialized(), NS_ERROR_FAILURE);
|
||||
|
||||
mOriginAttributes = aOriginAttributes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -303,11 +303,12 @@ private:
|
|||
bool mHttpsProxy;
|
||||
uint32_t mConnectionFlags;
|
||||
|
||||
// This is only non-empty when "privacy.firstparty.isolate" is enabled.
|
||||
// It is used to create sockets. It's the only way to carry it down to NSPR
|
||||
// layers which are final consumers. It must be set before the socket
|
||||
// transport is built.
|
||||
nsCString mFirstPartyDomain;
|
||||
// The origin attributes are used to create sockets. The first party domain
|
||||
// will eventually be used to isolate OCSP cache and is only non-empty when
|
||||
// "privacy.firstparty.isolate" is enabled. Setting this is the only way to
|
||||
// carry origin attributes down to NSPR layers which are final consumers.
|
||||
// It must be set before the socket transport is built.
|
||||
NeckoOriginAttributes mOriginAttributes;
|
||||
|
||||
uint16_t SocketPort() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort; }
|
||||
const nsCString &SocketHost() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyHost : mHost; }
|
||||
|
|
|
@ -77,8 +77,9 @@ TLSFilterTransaction::TLSFilterTransaction(nsAHttpTransaction *aWrapped,
|
|||
|
||||
if (provider && mFD) {
|
||||
mFD->secret = reinterpret_cast<PRFilePrivate *>(this);
|
||||
provider->AddToSocket(PR_AF_INET, aTLSHost, aTLSPort, nullptr, EmptyCString(),
|
||||
0, mFD, getter_AddRefs(mSecInfo));
|
||||
provider->AddToSocket(PR_AF_INET, aTLSHost, aTLSPort, nullptr,
|
||||
NeckoOriginAttributes(), 0, mFD,
|
||||
getter_AddRefs(mSecInfo));
|
||||
}
|
||||
|
||||
if (mTransaction) {
|
||||
|
@ -1593,8 +1594,32 @@ FWD_TS_PTR(GetConnectionFlags, uint32_t);
|
|||
FWD_TS(SetConnectionFlags, uint32_t);
|
||||
FWD_TS_PTR(GetRecvBufferSize, uint32_t);
|
||||
FWD_TS(SetRecvBufferSize, uint32_t);
|
||||
FWD_TS(SetFirstPartyDomain, const nsACString&);
|
||||
FWD_TS(GetFirstPartyDomain, nsACString&);
|
||||
|
||||
nsresult
|
||||
SocketTransportShim::GetOriginAttributes(mozilla::NeckoOriginAttributes* aOriginAttributes)
|
||||
{
|
||||
return mWrapped->GetOriginAttributes(aOriginAttributes);
|
||||
}
|
||||
|
||||
nsresult
|
||||
SocketTransportShim::SetOriginAttributes(const mozilla::NeckoOriginAttributes& aOriginAttributes)
|
||||
{
|
||||
return mWrapped->SetOriginAttributes(aOriginAttributes);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SocketTransportShim::GetScriptableOriginAttributes(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aOriginAttributes)
|
||||
{
|
||||
return mWrapped->GetScriptableOriginAttributes(aCx, aOriginAttributes);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SocketTransportShim::SetScriptableOriginAttributes(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aOriginAttributes)
|
||||
{
|
||||
return mWrapped->SetScriptableOriginAttributes(aCx, aOriginAttributes);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SocketTransportShim::GetHost(nsACString & aHost)
|
||||
|
|
|
@ -3081,10 +3081,10 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
|
|||
|
||||
socketTransport->SetConnectionFlags(tmpFlags);
|
||||
|
||||
nsAutoCString firstPartyDomain =
|
||||
NS_ConvertUTF16toUTF8(mEnt->mConnInfo->GetOriginAttributes().mFirstPartyDomain);
|
||||
if (!firstPartyDomain.IsEmpty()) {
|
||||
socketTransport->SetFirstPartyDomain(firstPartyDomain);
|
||||
NeckoOriginAttributes originAttributes =
|
||||
mEnt->mConnInfo->GetOriginAttributes();
|
||||
if (originAttributes != NeckoOriginAttributes()) {
|
||||
socketTransport->SetOriginAttributes(originAttributes);
|
||||
}
|
||||
|
||||
socketTransport->SetQoSBits(gHttpHandler->GetQoSBits());
|
||||
|
|
|
@ -7,6 +7,12 @@
|
|||
|
||||
interface nsIProxyInfo;
|
||||
[ptr] native PRFileDescStar(struct PRFileDesc);
|
||||
native NeckoOriginAttributes(mozilla::NeckoOriginAttributes);
|
||||
[ref] native const_OriginAttributesRef(const mozilla::NeckoOriginAttributes);
|
||||
|
||||
%{ C++
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
%}
|
||||
|
||||
/**
|
||||
* nsISocketProvider
|
||||
|
@ -36,14 +42,14 @@ interface nsISocketProvider : nsISupports
|
|||
* object typically implements nsITransportSecurityInfo.
|
||||
*/
|
||||
[noscript]
|
||||
void newSocket(in long aFamily,
|
||||
in string aHost,
|
||||
in long aPort,
|
||||
in nsIProxyInfo aProxy,
|
||||
in ACString aFirstPartyDomain,
|
||||
in unsigned long aFlags,
|
||||
out PRFileDescStar aFileDesc,
|
||||
out nsISupports aSecurityInfo);
|
||||
void newSocket(in long aFamily,
|
||||
in string aHost,
|
||||
in long aPort,
|
||||
in nsIProxyInfo aProxy,
|
||||
in const_OriginAttributesRef aOriginAttributes,
|
||||
in unsigned long aFlags,
|
||||
out PRFileDescStar aFileDesc,
|
||||
out nsISupports aSecurityInfo);
|
||||
|
||||
/**
|
||||
* addToSocket
|
||||
|
@ -56,14 +62,14 @@ interface nsISocketProvider : nsISupports
|
|||
* which is an in-param instead.
|
||||
*/
|
||||
[noscript]
|
||||
void addToSocket(in long aFamily,
|
||||
in string aHost,
|
||||
in long aPort,
|
||||
in nsIProxyInfo aProxy,
|
||||
in ACString aFirstPartyDomain,
|
||||
in unsigned long aFlags,
|
||||
in PRFileDescStar aFileDesc,
|
||||
out nsISupports aSecurityInfo);
|
||||
void addToSocket(in long aFamily,
|
||||
in string aHost,
|
||||
in long aPort,
|
||||
in nsIProxyInfo aProxy,
|
||||
in const_OriginAttributesRef aOriginAttributes,
|
||||
in unsigned long aFlags,
|
||||
in PRFileDescStar aFileDesc,
|
||||
out nsISupports aSecurityInfo);
|
||||
|
||||
/**
|
||||
* PROXY_RESOLVES_HOST
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
|
||||
using mozilla::NeckoOriginAttributes;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSOCKSSocketProvider, nsISocketProvider)
|
||||
|
@ -46,7 +48,7 @@ nsSOCKSSocketProvider::NewSocket(int32_t family,
|
|||
const char *host,
|
||||
int32_t port,
|
||||
nsIProxyInfo *proxy,
|
||||
const nsACString &firstPartyDomain,
|
||||
const NeckoOriginAttributes &originAttributes,
|
||||
uint32_t flags,
|
||||
PRFileDesc **result,
|
||||
nsISupports **socksInfo)
|
||||
|
@ -88,7 +90,7 @@ nsSOCKSSocketProvider::AddToSocket(int32_t family,
|
|||
const char *host,
|
||||
int32_t port,
|
||||
nsIProxyInfo *proxy,
|
||||
const nsACString &firstPartyDomain,
|
||||
const NeckoOriginAttributes &originAttributes,
|
||||
uint32_t flags,
|
||||
PRFileDesc *sock,
|
||||
nsISupports **socksInfo)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "nspr.h"
|
||||
|
||||
using mozilla::NeckoOriginAttributes;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsUDPSocketProvider, nsISocketProvider)
|
||||
|
||||
nsUDPSocketProvider::~nsUDPSocketProvider()
|
||||
|
@ -17,7 +19,7 @@ nsUDPSocketProvider::NewSocket(int32_t aFamily,
|
|||
const char *aHost,
|
||||
int32_t aPort,
|
||||
nsIProxyInfo *aProxy,
|
||||
const nsACString &firstPartyDomain,
|
||||
const NeckoOriginAttributes &originAttributes,
|
||||
uint32_t aFlags,
|
||||
PRFileDesc * *aFileDesc,
|
||||
nsISupports **aSecurityInfo)
|
||||
|
@ -37,7 +39,7 @@ nsUDPSocketProvider::AddToSocket(int32_t aFamily,
|
|||
const char *aHost,
|
||||
int32_t aPort,
|
||||
nsIProxyInfo *aProxy,
|
||||
const nsACString &firstPartyDomain,
|
||||
const NeckoOriginAttributes &originAttributes,
|
||||
uint32_t aFlags,
|
||||
struct PRFileDesc * aFileDesc,
|
||||
nsISupports **aSecurityInfo)
|
||||
|
|
|
@ -9,9 +9,15 @@ import sys
|
|||
from mozbuild.preprocessor import Preprocessor
|
||||
|
||||
|
||||
def generate(output, *args):
|
||||
pp = Preprocessor()
|
||||
pp.out = output
|
||||
pp.handleCommandLine(list(args), True)
|
||||
return set(pp.includes)
|
||||
|
||||
def main(args):
|
||||
pp = Preprocessor()
|
||||
pp.handleCommandLine(args, True)
|
||||
pp = Preprocessor()
|
||||
pp.handleCommandLine(args, True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -591,18 +591,18 @@ class RecursiveMakeBackend(CommonBackend):
|
|||
self._process_host_library(obj, backend_file)
|
||||
self._process_linked_libraries(obj, backend_file)
|
||||
|
||||
elif isinstance(obj, FinalTargetFiles):
|
||||
self._process_final_target_files(obj, obj.files, backend_file)
|
||||
|
||||
elif isinstance(obj, FinalTargetPreprocessedFiles):
|
||||
self._process_final_target_pp_files(obj, obj.files, backend_file, 'DIST_FILES')
|
||||
|
||||
elif isinstance(obj, ObjdirFiles):
|
||||
self._process_objdir_files(obj, obj.files, backend_file)
|
||||
|
||||
elif isinstance(obj, ObjdirPreprocessedFiles):
|
||||
self._process_final_target_pp_files(obj, obj.files, backend_file, 'OBJDIR_PP_FILES')
|
||||
|
||||
elif isinstance(obj, FinalTargetFiles):
|
||||
self._process_final_target_files(obj, obj.files, backend_file)
|
||||
|
||||
elif isinstance(obj, FinalTargetPreprocessedFiles):
|
||||
self._process_final_target_pp_files(obj, obj.files, backend_file, 'DIST_FILES')
|
||||
|
||||
elif isinstance(obj, AndroidResDirs):
|
||||
# Order matters.
|
||||
for p in obj.paths:
|
||||
|
@ -1045,8 +1045,9 @@ class RecursiveMakeBackend(CommonBackend):
|
|||
|
||||
def _process_test_manifest(self, obj, backend_file):
|
||||
# Much of the logic in this function could be moved to CommonBackend.
|
||||
self.backend_input_files.add(mozpath.join(obj.topsrcdir,
|
||||
obj.manifest_relpath))
|
||||
for source in obj.source_relpaths:
|
||||
self.backend_input_files.add(mozpath.join(obj.topsrcdir,
|
||||
source))
|
||||
|
||||
# Don't allow files to be defined multiple times unless it is allowed.
|
||||
# We currently allow duplicates for non-test files or test files if
|
||||
|
|
|
@ -963,13 +963,15 @@ VARIABLES = {
|
|||
|
||||
'GENERATED_FILES': (StrictOrderingOnAppendListWithFlagsFactory({
|
||||
'script': unicode,
|
||||
'inputs': list }), list,
|
||||
'inputs': list,
|
||||
'flags': list, }), list,
|
||||
"""Generic generated files.
|
||||
|
||||
This variable contains a list of files for the build system to
|
||||
generate at export time. The generation method may be declared
|
||||
with optional ``script`` and ``inputs`` flags on individual entries.
|
||||
If the optional ``script`` flag is not present on an entry, it
|
||||
with optional ``script``, ``inputs`` and ``flags`` attributes on
|
||||
individual entries.
|
||||
If the optional ``script`` attribute is not present on an entry, it
|
||||
is assumed that rules for generating the file are present in
|
||||
the associated Makefile.in.
|
||||
|
||||
|
@ -1003,6 +1005,9 @@ VARIABLES = {
|
|||
|
||||
The chosen script entry point may optionally return a set of strings,
|
||||
indicating extra files the output depends on.
|
||||
|
||||
When the ``flags`` attribute is present, the given list of flags is
|
||||
passed as extra arguments following the inputs.
|
||||
"""),
|
||||
|
||||
'DEFINES': (InitializedDefines, dict,
|
||||
|
|
|
@ -641,13 +641,17 @@ class TestManifest(ContextDerived):
|
|||
# The relative path of the parsed manifest within the objdir.
|
||||
'manifest_obj_relpath',
|
||||
|
||||
# The relative paths to all source files for this manifest.
|
||||
'source_relpaths',
|
||||
|
||||
# If this manifest is a duplicate of another one, this is the
|
||||
# manifestparser.TestManifest of the other one.
|
||||
'dupe_manifest',
|
||||
)
|
||||
|
||||
def __init__(self, context, path, manifest, flavor=None,
|
||||
install_prefix=None, relpath=None, dupe_manifest=False):
|
||||
install_prefix=None, relpath=None, sources=(),
|
||||
dupe_manifest=False):
|
||||
ContextDerived.__init__(self, context)
|
||||
|
||||
assert flavor in all_test_flavors()
|
||||
|
@ -659,6 +663,7 @@ class TestManifest(ContextDerived):
|
|||
self.install_prefix = install_prefix
|
||||
self.manifest_relpath = relpath
|
||||
self.manifest_obj_relpath = relpath
|
||||
self.source_relpaths = sources
|
||||
self.dupe_manifest = dupe_manifest
|
||||
self.installs = {}
|
||||
self.pattern_installs = []
|
||||
|
@ -886,31 +891,19 @@ class FinalTargetPreprocessedFiles(ContextDerived):
|
|||
self.files = files
|
||||
|
||||
|
||||
class ObjdirFiles(ContextDerived):
|
||||
class ObjdirFiles(FinalTargetFiles):
|
||||
"""Sandbox container object for OBJDIR_FILES, which is a
|
||||
HierarchicalStringList.
|
||||
"""
|
||||
__slots__ = ('files')
|
||||
|
||||
def __init__(self, sandbox, files):
|
||||
ContextDerived.__init__(self, sandbox)
|
||||
self.files = files
|
||||
|
||||
@property
|
||||
def install_target(self):
|
||||
return ''
|
||||
|
||||
|
||||
class ObjdirPreprocessedFiles(ContextDerived):
|
||||
class ObjdirPreprocessedFiles(FinalTargetPreprocessedFiles):
|
||||
"""Sandbox container object for OBJDIR_PP_FILES, which is a
|
||||
HierarchicalStringList.
|
||||
"""
|
||||
__slots__ = ('files')
|
||||
|
||||
def __init__(self, sandbox, files):
|
||||
ContextDerived.__init__(self, sandbox)
|
||||
self.files = files
|
||||
|
||||
@property
|
||||
def install_target(self):
|
||||
return ''
|
||||
|
|
|
@ -128,6 +128,7 @@ ALLOWED_XPCOM_GLUE = {
|
|||
('TestMailCookie', 'mailnews/base/test'),
|
||||
('calbasecomps', 'calendar/base/backend/libical/build'),
|
||||
('purplexpcom', 'extensions/purple/purplexpcom/src'),
|
||||
('ipdlunittest', 'ipc/ipdl/test/cxx/app'),
|
||||
}
|
||||
|
||||
|
||||
|
@ -1228,7 +1229,8 @@ class TreeMetadataEmitter(LoggingMixin):
|
|||
else:
|
||||
script = None
|
||||
method = None
|
||||
yield GeneratedFile(context, script, method, outputs, inputs)
|
||||
yield GeneratedFile(context, script, method, outputs, inputs,
|
||||
flags.flags)
|
||||
|
||||
def _process_test_manifests(self, context):
|
||||
for prefix, info in TEST_MANIFESTS.items():
|
||||
|
@ -1253,6 +1255,8 @@ class TreeMetadataEmitter(LoggingMixin):
|
|||
manifest_dir = mozpath.dirname(path)
|
||||
manifest_reldir = mozpath.dirname(mozpath.relpath(path,
|
||||
context.config.topsrcdir))
|
||||
manifest_sources = [mozpath.relpath(pth, context.config.topsrcdir)
|
||||
for pth in mpmanifest.source_files]
|
||||
install_prefix = mozpath.join(install_root, install_subdir)
|
||||
|
||||
try:
|
||||
|
@ -1264,6 +1268,7 @@ class TreeMetadataEmitter(LoggingMixin):
|
|||
obj = TestManifest(context, path, mpmanifest, flavor=flavor,
|
||||
install_prefix=install_prefix,
|
||||
relpath=mozpath.join(manifest_reldir, mozpath.basename(path)),
|
||||
sources=manifest_sources,
|
||||
dupe_manifest='dupe-manifest' in defaults)
|
||||
|
||||
filtered = mpmanifest.tests
|
||||
|
|
|
@ -328,7 +328,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
/*optional*/ const Flags flags,
|
||||
/*optional*/ const SECItem* stapledOCSPResponseSECItem,
|
||||
/*optional*/ const SECItem* sctsFromTLSSECItem,
|
||||
/*optional*/ const char* firstPartyDomain,
|
||||
/*optional*/ const NeckoOriginAttributes& originAttributes,
|
||||
/*optional out*/ SECOidTag* evOidPolicy,
|
||||
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
|
||||
/*optional out*/ KeySizeStatus* keySizeStatus,
|
||||
|
@ -422,7 +422,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
ValidityCheckingMode::CheckingOff,
|
||||
SHA1Mode::Allowed,
|
||||
NetscapeStepUpPolicy::NeverMatch,
|
||||
firstPartyDomain,
|
||||
originAttributes,
|
||||
builtChain, nullptr, nullptr);
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
|
@ -496,7 +496,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
mCertShortLifetimeInDays, mPinningMode, MIN_RSA_BITS,
|
||||
ValidityCheckingMode::CheckForEV,
|
||||
sha1ModeConfigurations[i], mNetscapeStepUpPolicy,
|
||||
firstPartyDomain, builtChain, pinningTelemetryInfo,
|
||||
originAttributes, builtChain, pinningTelemetryInfo,
|
||||
hostname);
|
||||
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
|
||||
KeyUsage::digitalSignature,// (EC)DHE
|
||||
|
@ -584,7 +584,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
ValidityCheckingMode::CheckingOff,
|
||||
sha1ModeConfigurations[j],
|
||||
mNetscapeStepUpPolicy,
|
||||
firstPartyDomain, builtChain,
|
||||
originAttributes, builtChain,
|
||||
pinningTelemetryInfo, hostname);
|
||||
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
|
||||
KeyUsage::digitalSignature,//(EC)DHE
|
||||
|
@ -649,7 +649,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
pinningDisabled, MIN_RSA_BITS_WEAK,
|
||||
ValidityCheckingMode::CheckingOff,
|
||||
SHA1Mode::Allowed, mNetscapeStepUpPolicy,
|
||||
firstPartyDomain, builtChain, nullptr,
|
||||
originAttributes, builtChain, nullptr,
|
||||
nullptr);
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeCA, KeyUsage::keyCertSign,
|
||||
|
@ -666,7 +666,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
ValidityCheckingMode::CheckingOff,
|
||||
SHA1Mode::Allowed,
|
||||
NetscapeStepUpPolicy::NeverMatch,
|
||||
firstPartyDomain, builtChain, nullptr,
|
||||
originAttributes, builtChain, nullptr,
|
||||
nullptr);
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
|
@ -694,7 +694,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
ValidityCheckingMode::CheckingOff,
|
||||
SHA1Mode::Allowed,
|
||||
NetscapeStepUpPolicy::NeverMatch,
|
||||
firstPartyDomain, builtChain, nullptr,
|
||||
originAttributes, builtChain, nullptr,
|
||||
nullptr);
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
|
@ -719,7 +719,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
ValidityCheckingMode::CheckingOff,
|
||||
SHA1Mode::Allowed,
|
||||
NetscapeStepUpPolicy::NeverMatch,
|
||||
firstPartyDomain, builtChain, nullptr,
|
||||
originAttributes, builtChain, nullptr,
|
||||
nullptr);
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
|
@ -753,7 +753,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
ValidityCheckingMode::CheckingOff,
|
||||
SHA1Mode::Allowed,
|
||||
NetscapeStepUpPolicy::NeverMatch,
|
||||
firstPartyDomain, builtChain, nullptr,
|
||||
originAttributes, builtChain, nullptr,
|
||||
nullptr);
|
||||
rv = BuildCertChain(sslTrust, certDER, time, endEntityOrCA,
|
||||
keyUsage, eku, CertPolicyId::anyPolicy,
|
||||
|
@ -766,7 +766,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
ValidityCheckingMode::CheckingOff,
|
||||
SHA1Mode::Allowed,
|
||||
NetscapeStepUpPolicy::NeverMatch,
|
||||
firstPartyDomain, builtChain, nullptr,
|
||||
originAttributes, builtChain, nullptr,
|
||||
nullptr);
|
||||
rv = BuildCertChain(emailTrust, certDER, time, endEntityOrCA,
|
||||
keyUsage, eku, CertPolicyId::anyPolicy,
|
||||
|
@ -781,7 +781,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
|||
ValidityCheckingMode::CheckingOff,
|
||||
SHA1Mode::Allowed,
|
||||
NetscapeStepUpPolicy::NeverMatch,
|
||||
firstPartyDomain, builtChain,
|
||||
originAttributes, builtChain,
|
||||
nullptr, nullptr);
|
||||
rv = BuildCertChain(objectSigningTrust, certDER, time,
|
||||
endEntityOrCA, keyUsage, eku,
|
||||
|
@ -813,7 +813,7 @@ CertVerifier::VerifySSLServerCert(const UniqueCERTCertificate& peerCert,
|
|||
/*out*/ UniqueCERTCertList& builtChain,
|
||||
/*optional*/ bool saveIntermediatesInPermanentDatabase,
|
||||
/*optional*/ Flags flags,
|
||||
/*optional*/ const char* firstPartyDomain,
|
||||
/*optional*/ const NeckoOriginAttributes& originAttributes,
|
||||
/*optional out*/ SECOidTag* evOidPolicy,
|
||||
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
|
||||
/*optional out*/ KeySizeStatus* keySizeStatus,
|
||||
|
@ -838,7 +838,7 @@ CertVerifier::VerifySSLServerCert(const UniqueCERTCertificate& peerCert,
|
|||
// if VerifyCert succeeded.
|
||||
Result rv = VerifyCert(peerCert.get(), certificateUsageSSLServer, time,
|
||||
pinarg, hostname, builtChain, flags,
|
||||
stapledOCSPResponse, sctsFromTLS, firstPartyDomain,
|
||||
stapledOCSPResponse, sctsFromTLS, originAttributes,
|
||||
evOidPolicy, ocspStaplingStatus, keySizeStatus,
|
||||
sha1ModeResult, pinningTelemetryInfo, ctInfo);
|
||||
if (rv != Success) {
|
||||
|
|
|
@ -15,6 +15,24 @@
|
|||
#include "mozilla/UniquePtr.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
// Silence "RootingAPI.h(718): warning C4324: 'js::DispatchWrapper<T>':
|
||||
// structure was padded due to alignment specifier with [ T=void * ]"
|
||||
#pragma warning(disable:4324)
|
||||
// Silence "Value.h(448): warning C4365: 'return': conversion from 'const
|
||||
// int32_t' to 'JS::Value::PayloadType', signed/unsigned mismatch"
|
||||
#pragma warning(disable:4365)
|
||||
// Silence "warning C5031: #pragma warning(pop): likely mismatch, popping
|
||||
// warning state pushed in different file
|
||||
#pragma warning(disable:5031)
|
||||
#endif /* defined(_MSC_VER) */
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop) /* popping the pragma in Vector.h */
|
||||
#pragma warning(pop) /* popping the pragma in this file */
|
||||
#endif /* defined(_MSC_VER) */
|
||||
|
||||
namespace mozilla { namespace ct {
|
||||
|
||||
// Including MultiLogCTVerifier.h would bring along all of its dependent
|
||||
|
@ -109,7 +127,8 @@ public:
|
|||
Flags flags = 0,
|
||||
/*optional in*/ const SECItem* stapledOCSPResponse = nullptr,
|
||||
/*optional in*/ const SECItem* sctsFromTLS = nullptr,
|
||||
/*optional in*/ const char* firstPartyDomain = nullptr,
|
||||
/*optional in*/ const NeckoOriginAttributes& originAttributes =
|
||||
NeckoOriginAttributes(),
|
||||
/*optional out*/ SECOidTag* evOidPolicy = nullptr,
|
||||
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
|
||||
/*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
|
||||
|
@ -127,7 +146,8 @@ public:
|
|||
/*out*/ UniqueCERTCertList& builtChain,
|
||||
/*optional*/ bool saveIntermediatesInPermanentDatabase = false,
|
||||
/*optional*/ Flags flags = 0,
|
||||
/*optional*/ const char* firstPartyDomain = nullptr,
|
||||
/*optional*/ const NeckoOriginAttributes& originAttributes =
|
||||
NeckoOriginAttributes(),
|
||||
/*optional out*/ SECOidTag* evOidPolicy = nullptr,
|
||||
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
|
||||
/*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче