Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2017-04-11 10:22:53 +02:00
commit f053c5e039
180 changed files with 2703 additions and 1319 deletions

View File

@ -248,64 +248,29 @@ endif
distclean::
$(RM) $(DIST_GARBAGE)
ifeq ($(OS_ARCH),WINNT)
# we want to copy PDB files on Windows
MAKE_SYM_STORE_ARGS := -c --vcs-info
ifdef PDBSTR_PATH
MAKE_SYM_STORE_ARGS += -i
endif
ifdef MSVC_HAS_DIA_SDK
DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms.exe
else
DUMP_SYMS_BIN ?= $(topsrcdir)/toolkit/crashreporter/tools/win32/dump_syms_vc$(_MSC_VER).exe
endif
# PDB files don't get moved to dist, so we need to scan the whole objdir
MAKE_SYM_STORE_PATH := .
endif
ifeq ($(OS_ARCH),Darwin)
# need to pass arch flags for universal builds
MAKE_SYM_STORE_ARGS := -c -a $(OS_TEST) --vcs-info
MAKE_SYM_STORE_PATH := $(DIST)/bin
DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
endif
ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
MAKE_SYM_STORE_ARGS := -c --vcs-info
DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
MAKE_SYM_STORE_PATH := $(DIST)/bin
endif
MAKE_SYM_STORE_ARGS += --install-manifest=$(DEPTH)/_build_manifests/install/dist_include,$(DIST)/include
SYM_STORE_SOURCE_DIRS := $(topsrcdir)
ifdef MOZ_CRASHREPORTER
include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
endif
.PHONY: generatesymbols
generatesymbols:
echo building symbol store
$(RM) -r $(DIST)/crashreporter-symbols
$(RM) '$(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip'
$(RM) '$(DIST)/$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
$(NSINSTALL) -D $(DIST)/crashreporter-symbols
OBJCOPY='$(OBJCOPY)' \
$(PYTHON) $(topsrcdir)/toolkit/crashreporter/tools/symbolstore.py \
$(MAKE_SYM_STORE_ARGS) \
$(foreach dir,$(SYM_STORE_SOURCE_DIRS),-s $(dir)) \
$(DUMP_SYMS_BIN) \
$(DIST)/crashreporter-symbols \
$(MAKE_SYM_STORE_PATH)
.PHONY: prepsymbolsarchive
prepsymbolsarchive:
echo packing symbols
$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
ifndef MOZ_AUTOMATION
prepsymbolsarchive: recurse_syms
endif
.PHONY: symbolsfullarchive
symbolsfullarchive: generatesymbols
symbolsfullarchive: prepsymbolsarchive
$(RM) '$(DIST)/$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
cd $(DIST)/crashreporter-symbols && \
zip -r5D '../$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip' . -x '*test*' -x '*Test*'
.PHONY: symbolsarchive
symbolsarchive: generatesymbols
symbolsarchive: prepsymbolsarchive
$(RM) '$(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip'
cd $(DIST)/crashreporter-symbols && \
zip -r5D '../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip' . -i '*.sym'

View File

@ -642,34 +642,25 @@ var LightWeightThemeWebInstaller = {
return;
}
let allowButtonText =
gNavigatorBundle.getString("lwthemeInstallRequest.allowButton");
let allowButtonAccesskey =
gNavigatorBundle.getString("lwthemeInstallRequest.allowButton.accesskey");
let message =
gNavigatorBundle.getFormattedString("lwthemeInstallRequest.message",
[uri.host]);
let buttons = [{
label: allowButtonText,
accessKey: allowButtonAccesskey,
callback() {
let strings = {
header: gNavigatorBundle.getFormattedString("webextPerms.header", [data.name]),
text: gNavigatorBundle.getFormattedString("lwthemeInstallRequest.message2",
[uri.host]),
acceptText: gNavigatorBundle.getString("lwthemeInstallRequest.allowButton2"),
acceptKey: gNavigatorBundle.getString("lwthemeInstallRequest.allowButton.accesskey2"),
cancelText: gNavigatorBundle.getString("webextPerms.cancel.label"),
cancelKey: gNavigatorBundle.getString("webextPerms.cancel.accessKey"),
msgs: []
};
ExtensionsUI.showPermissionsPrompt(gBrowser.selectedBrowser, strings, null,
"installWeb").then(answer => {
if (answer) {
LightWeightThemeWebInstaller._install(data, notify);
}
}];
this._removePreviousNotifications();
let notificationBox = gBrowser.getNotificationBox();
let notificationBar =
notificationBox.appendNotification(message, "lwtheme-install-request", "",
notificationBox.PRIORITY_INFO_MEDIUM,
buttons);
notificationBar.persistence = 1;
});
},
_install(newLWTheme, notify) {
let previousLWTheme = this._manager.currentTheme;
let listener = {
onEnabling(aAddon, aRequiresRestart) {
if (!aRequiresRestart) {
@ -698,7 +689,7 @@ var LightWeightThemeWebInstaller = {
onEnabled(aAddon) {
if (notify) {
LightWeightThemeWebInstaller._postInstallNotification(newLWTheme, previousLWTheme);
ExtensionsUI.showInstallNotification(gBrowser.selectedBrowser, newLWTheme);
}
}
};
@ -708,49 +699,6 @@ var LightWeightThemeWebInstaller = {
AddonManager.removeAddonListener(listener);
},
_postInstallNotification(newTheme, previousTheme) {
function text(id) {
return gNavigatorBundle.getString("lwthemePostInstallNotification." + id);
}
let buttons = [{
label: text("undoButton"),
accessKey: text("undoButton.accesskey"),
callback() {
LightWeightThemeWebInstaller._manager.forgetUsedTheme(newTheme.id);
LightWeightThemeWebInstaller._manager.currentTheme = previousTheme;
}
}, {
label: text("manageButton"),
accessKey: text("manageButton.accesskey"),
callback() {
BrowserOpenAddonsMgr("addons://list/theme");
}
}];
this._removePreviousNotifications();
let notificationBox = gBrowser.getNotificationBox();
let notificationBar =
notificationBox.appendNotification(text("message"),
"lwtheme-install-notification", "",
notificationBox.PRIORITY_INFO_MEDIUM,
buttons);
notificationBar.persistence = 1;
notificationBar.timeout = Date.now() + 20000; // 20 seconds
},
_removePreviousNotifications() {
let box = gBrowser.getNotificationBox();
["lwtheme-install-request",
"lwtheme-install-notification"].forEach(function(value) {
let notification = box.getNotificationWithValue(value);
if (notification)
box.removeNotification(notification);
});
},
_preview(dataString, baseURI) {
if (!this._isAllowed(baseURI))
return;

View File

@ -67,7 +67,7 @@ var CompactTheme = {
// Don't touch things on the browser if gBrowserInit.onLoad hasn't
// yet fired.
if (this.initialized) {
gBrowser.tabContainer._positionPinnedTabs();
gBrowser.tabContainer.themeLayoutChanged();
}
},

View File

@ -3024,7 +3024,8 @@ var BrowserOnClick = {
case "Browser:CertExceptionError":
this.onCertError(msg.target, msg.data.elementId,
msg.data.isTopFrame, msg.data.location,
msg.data.securityInfoAsString);
msg.data.securityInfoAsString,
msg.data.originAttributesAsString);
break;
case "Browser:OpenCaptivePortalPage":
CaptivePortalWatcher.ensureCaptivePortalTab();
@ -3088,7 +3089,8 @@ var BrowserOnClick = {
uri.host, uri.port);
},
onCertError(browser, elementId, isTopFrame, location, securityInfoAsString) {
onCertError(browser, elementId, isTopFrame, location, securityInfoAsString,
originAttributesAsString) {
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
let securityInfo;
@ -3138,7 +3140,8 @@ var BrowserOnClick = {
securityInfo = getSecurityInfo(securityInfoAsString);
let errorInfo = getDetailedCertErrorInfo(location,
securityInfo);
securityInfo,
JSON.parse(originAttributesAsString));
browser.messageManager.sendAsyncMessage( "CertErrorDetails", {
code: securityInfo.errorCode,
info: errorInfo
@ -3150,7 +3153,8 @@ var BrowserOnClick = {
.getService(Ci.nsIClipboardHelper);
securityInfo = getSecurityInfo(securityInfoAsString);
let detailedInfo = getDetailedCertErrorInfo(location,
securityInfo);
securityInfo,
JSON.parse(originAttributesAsString));
gClipboardHelper.copyString(detailedInfo);
break;
@ -3415,7 +3419,7 @@ function getSecurityInfo(securityInfoAsString) {
* Returns a string with detailed information about the certificate validation
* failure from the specified URI that can be used to send a report.
*/
function getDetailedCertErrorInfo(location, securityInfo) {
function getDetailedCertErrorInfo(location, securityInfo, originAttributes) {
if (!securityInfo)
return "";
@ -3436,8 +3440,8 @@ function getDetailedCertErrorInfo(location, securityInfo) {
let uri = Services.io.newURI(location);
let hasHSTS = sss.isSecureURI(sss.HEADER_HSTS, uri, flags);
let hasHPKP = sss.isSecureURI(sss.HEADER_HPKP, uri, flags);
let hasHSTS = sss.isSecureURI(sss.HEADER_HSTS, uri, flags, originAttributes);
let hasHPKP = sss.isSecureURI(sss.HEADER_HPKP, uri, flags, originAttributes);
certErrorDetails += "\r\n\r\n" +
gNavigatorBundle.getFormattedString("certErrorDetailsHSTS.label",
[hasHSTS]);

View File

@ -293,6 +293,14 @@ addMessageListener("DeceptiveBlockedDetails", (message) => {
});
});
function getSerializedOriginAttributes(docShell) {
let originAttributes = {};
if (docShell.failedChannel) {
originAttributes = docShell.failedChannel.loadInfo.originAttributes;
}
return JSON.stringify(originAttributes);
}
var AboutNetAndCertErrorListener = {
init(chromeGlobal) {
addMessageListener("CertErrorDetails", this);
@ -601,6 +609,7 @@ var ClickEventHandler = {
elementId: targetElement.getAttribute("id"),
isTopFrame: (ownerDoc.defaultView.parent === ownerDoc.defaultView),
securityInfoAsString: getSerializedSecurityInfo(docShell),
originAttributesAsString: getSerializedOriginAttributes(docShell),
});
},

View File

@ -6063,9 +6063,21 @@
]]></body>
</method>
<field name="_lastNumPinned">0</field>
<method name="_positionPinnedTabs">
<method name="themeLayoutChanged">
<body><![CDATA[
this._positionPinnedTabs(true);
]]></body>
</method>
<field name="_lastNumPinned">0</field>
<field name="_pinnedTabsLayoutCache">null</field>
<method name="_positionPinnedTabs">
<parameter name="aThemeLayoutChanged"/>
<body><![CDATA[
if (aThemeLayoutChanged) {
this._pinnedTabsLayoutCache = null;
}
var numPinned = this.tabbrowser._numPinnedTabs;
var doPosition = this.getAttribute("overflow") == "true" &&
numPinned > 0;
@ -6073,21 +6085,24 @@
if (doPosition) {
this.setAttribute("positionpinnedtabs", "true");
let scrollButtonWidth = this.mTabstrip._scrollButtonDown.getBoundingClientRect().width;
let paddingStart = this.mTabstrip.scrollboxPaddingStart;
let pinnedTabWidth;
let width = 0;
for (let i = numPinned - 1; i >= 0; i--) {
let tab = this.childNodes[i];
if (!pinnedTabWidth) {
pinnedTabWidth = tab.getBoundingClientRect().width;
}
width += pinnedTabWidth;
tab.style.marginInlineStart = -(width + scrollButtonWidth + paddingStart) + "px";
let layoutData = this._pinnedTabsLayoutCache;
if (!layoutData) {
let tabstrip = this.mTabstrip;
layoutData = this._pinnedTabsLayoutCache = {
pinnedTabWidth: this.childNodes[0].getBoundingClientRect().width,
paddingStart: tabstrip.scrollboxPaddingStart,
scrollButtonWidth: tabstrip._scrollButtonDown.getBoundingClientRect().width
};
}
this.style.paddingInlineStart = width + paddingStart + "px";
let width = 0;
for (let i = numPinned - 1; i >= 0; i--) {
let tab = this.childNodes[i];
width += layoutData.pinnedTabWidth;
tab.style.marginInlineStart =
-(width + layoutData.scrollButtonWidth + layoutData.paddingStart) + "px";
}
this.style.paddingInlineStart = width + layoutData.paddingStart + "px";
} else {
this.removeAttribute("positionpinnedtabs");

View File

@ -259,10 +259,13 @@ add_task(function* checkAdvancedDetails() {
.QueryInterface(Ci.nsITransportSecurityInfo)
.QueryInterface(Ci.nsISerializable);
let serializedSecurityInfo = serhelper.serializeToString(serializable);
let originAttributes = docShell.failedChannel.loadInfo.originAttributes;
let serializedOriginAttributes = JSON.stringify(originAttributes);
return {
divDisplay: content.getComputedStyle(div).display,
text: text.textContent,
securityInfoAsString: serializedSecurityInfo
securityInfoAsString: serializedSecurityInfo,
originAttributesAsString: serializedOriginAttributes,
};
});
isnot(message.divDisplay, "none", "Debug information is visible");
@ -328,10 +331,13 @@ add_task(function* checkAdvancedDetailsForHSTS() {
.QueryInterface(Ci.nsITransportSecurityInfo)
.QueryInterface(Ci.nsISerializable);
let serializedSecurityInfo = serhelper.serializeToString(serializable);
let originAttributes = docShell.failedChannel.loadInfo.originAttributes;
let serializedOriginAttributes = JSON.stringify(originAttributes);
return {
divDisplay: content.getComputedStyle(div).display,
text: text.textContent,
securityInfoAsString: serializedSecurityInfo
securityInfoAsString: serializedSecurityInfo,
originAttributesAsString: serializedOriginAttributes,
};
});
isnot(message.divDisplay, "none", "Debug information is visible");

View File

@ -4,16 +4,35 @@
const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
var tempScope = {};
Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", tempScope);
var LightweightThemeManager = tempScope.LightweightThemeManager;
const {LightweightThemeManager} = Cu.import("resource://gre/modules/LightweightThemeManager.jsm", {});
function wait_for_notification(aCallback) {
PopupNotifications.panel.addEventListener("popupshown", function() {
aCallback(PopupNotifications.panel);
}, {once: true});
/**
* Wait for the given PopupNotification to display
*
* @param {string} name
* The name of the notification to wait for.
*
* @returns {Promise}
* Resolves with the notification window.
*/
function promisePopupNotificationShown(name) {
return new Promise(resolve => {
function popupshown() {
let notification = PopupNotifications.getNotification(name);
if (!notification) { return; }
ok(notification, `${name} notification shown`);
ok(PopupNotifications.isPanelOpen, "notification panel open");
PopupNotifications.panel.removeEventListener("popupshown", popupshown);
resolve(PopupNotifications.panel.firstChild);
}
PopupNotifications.panel.addEventListener("popupshown", popupshown);
});
}
var TESTS = [
function test_install_http() {
is(LightweightThemeManager.currentTheme, null, "Should be no lightweight theme selected");
@ -55,20 +74,17 @@ function test_install_lwtheme() {
gBrowser.selectedBrowser.removeEventListener("pageshow", arguments.callee);
let promise = promisePopupNotificationShown("addon-installed");
BrowserTestUtils.synthesizeMouse("#theme-install", 2, 2, {}, gBrowser.selectedBrowser);
let notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
waitForCondition(
() => notificationBox.getNotificationWithValue("lwtheme-install-notification"),
() => {
is(LightweightThemeManager.currentTheme.id, "test", "Should have installed the test theme");
promise.then(() => {
is(LightweightThemeManager.currentTheme.id, "test", "Should have installed the test theme");
LightweightThemeManager.currentTheme = null;
gBrowser.removeTab(gBrowser.selectedTab);
Services.perms.remove(makeURI("http://example.com/"), "install");
LightweightThemeManager.currentTheme = null;
gBrowser.removeTab(gBrowser.selectedTab);
Services.perms.remove(makeURI("http://example.com/"), "install");
runNextTest();
}
);
runNextTest();
});
});
}
];

View File

@ -516,7 +516,6 @@ this.tabs = class extends ExtensionAPI {
},
async move(tabIds, moveProperties) {
let index = moveProperties.index;
let tabsMoved = [];
if (!Array.isArray(tabIds)) {
tabIds = [tabIds];
@ -539,6 +538,7 @@ this.tabs = class extends ExtensionAPI {
-> tabA to 0, tabB to 0 if tabA and tabB are in different windows
*/
let indexMap = new Map();
let lastInsertion = new Map();
let tabs = tabIds.map(tabId => tabTracker.getTab(tabId));
for (let nativeTab of tabs) {
@ -546,7 +546,7 @@ this.tabs = class extends ExtensionAPI {
let window = destinationWindow || nativeTab.ownerGlobal;
let gBrowser = window.gBrowser;
let insertionPoint = indexMap.get(window) || index;
let insertionPoint = indexMap.get(window) || moveProperties.index;
// If the index is -1 it should go to the end of the tabs.
if (insertionPoint == -1) {
insertionPoint = gBrowser.tabs.length;
@ -562,7 +562,16 @@ this.tabs = class extends ExtensionAPI {
continue;
}
indexMap.set(window, insertionPoint + 1);
// If this is not the first tab to be inserted into this window and
// the insertion point is the same as the last insertion and
// the tab is further to the right than the current insertion point
// then you need to bump up the insertion point. See bug 1323311.
if (lastInsertion.has(window) &&
lastInsertion.get(window) === insertionPoint &&
nativeTab._tPos > insertionPoint) {
insertionPoint++;
indexMap.set(window, insertionPoint);
}
if (nativeTab.ownerGlobal != window) {
// If the window we are moving the tab in is different, then move the tab
@ -572,6 +581,7 @@ this.tabs = class extends ExtensionAPI {
// If the window we are moving is the same, just move the tab.
gBrowser.moveTabTo(nativeTab, insertionPoint);
}
lastInsertion.set(window, nativeTab._tPos);
tabsMoved.push(nativeTab);
}

View File

@ -108,6 +108,7 @@ support-files =
[browser_ext_tabs_insertCSS.js]
[browser_ext_tabs_removeCSS.js]
[browser_ext_tabs_move.js]
[browser_ext_tabs_move_array.js]
[browser_ext_tabs_move_window.js]
[browser_ext_tabs_move_window_multiple.js]
[browser_ext_tabs_move_window_pinned.js]

View File

@ -0,0 +1,72 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* moveMultiple() {
let tabs = [];
for (let k of [1, 2, 3, 4]) {
let tab = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser, `http://example.com/?${k}`);
tabs.push(tab);
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {permissions: ["tabs"]},
background: async function() {
function num(url) {
return parseInt(url.slice(-1), 10);
}
async function check(expected) {
let tabs = await browser.tabs.query({url: "http://example.com/*"});
let endings = tabs.map(tab => num(tab.url));
browser.test.assertTrue(
expected.every((v, i) => v === endings[i]),
`Tab order should be ${expected}, got ${endings}.`
);
}
async function reset() {
let tabs = await browser.tabs.query({url: "http://example.com/*"});
await browser.tabs.move(
tabs.sort((a, b) => (num(a.url) - num(b.url))).map(tab => tab.id),
{index: 0}
);
}
async function move(moveIndexes, moveTo) {
let tabs = await browser.tabs.query({url: "http://example.com/*"});
await browser.tabs.move(
moveIndexes.map(e => tabs[e - 1].id),
{index: moveTo});
}
let tests = [
// Start -> After first tab -> After second tab
// [1, 2, 3, 4] -> [1, 4, 2, 3] -> [1, 4, 3, 2]
{"move": [4, 3], "index": 1, "result": [1, 4, 3, 2]},
// [1, 2, 3, 4] -> [2, 3, 1, 4] -> [3, 1, 2, 4]
{"move": [1, 2], "index": 2, "result": [3, 1, 2, 4]},
// [1, 2, 3, 4] -> [1, 2, 4, 3] -> [2, 4, 1, 3]
{"move": [4, 1], "index": 2, "result": [2, 4, 1, 3]},
// [1, 2, 3, 4] -> [2, 3, 1, 4] -> [2, 3, 1, 4]
{"move": [1, 4], "index": 2, "result": [2, 3, 1, 4]},
];
for (let test of tests) {
await reset();
await move(test.move, test.index);
await check(test.result);
}
browser.test.notifyPass("tabs.move");
},
});
yield extension.startup();
yield extension.awaitFinish("tabs.move");
yield extension.unload();
for (let tab of tabs) {
yield BrowserTestUtils.removeTab(tab);
}
});

View File

@ -126,7 +126,7 @@ var TabStateInternal = {
// Store the serialized contentPrincipal of this tab to use for the icon.
if (!("iconLoadingPrincipal" in tabData)) {
tabData.iconLoadingPrincipal = Utils.serializePrincipal(browser.contentPrincipal);
tabData.iconLoadingPrincipal = Utils.serializePrincipal(browser.mIconLoadingPrincipal);
}
// If there is a userTypedValue set, then either the user has typed something

View File

@ -901,7 +901,6 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY updateAvailable.message "Update your &brandShorterName; for the latest in speed and privacy.">
<!ENTITY updateAvailable.whatsnew.label "See whats new.">
<!ENTITY updateAvailable.whatsnew.href "http://www.mozilla.org/">
<!ENTITY updateAvailable.header.message "A new &brandShorterName; update is available.">
<!ENTITY updateAvailable.acceptButton.label "Download Update">
<!ENTITY updateAvailable.acceptButton.accesskey "D">
@ -911,7 +910,6 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY updateManual.message "Download a fresh copy of &brandShorterName; and well help you to install it.">
<!ENTITY updateManual.whatsnew.label "See whats new.">
<!ENTITY updateManual.whatsnew.href "http://www.mozilla.org/">
<!ENTITY updateManual.header.message "&brandShorterName; cant update to the latest version.">
<!ENTITY updateManual.acceptButton.label "Download &brandShorterName;">
<!ENTITY updateManual.acceptButton.accesskey "D">
@ -920,9 +918,9 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY updateManual.panelUI.label "Download a fresh copy of &brandShorterName;">
<!ENTITY updateRestart.message "After a quick restart, &brandShorterName; will restore all your open tabs and windows.">
<!ENTITY updateRestart.header.message "Restart &brandShorterName; to apply update.">
<!ENTITY updateRestart.header.message "Restart &brandShorterName; to apply the update.">
<!ENTITY updateRestart.acceptButton.label "Restart and Restore">
<!ENTITY updateRestart.acceptButton.accesskey "R">
<!ENTITY updateRestart.cancelButton.label "Not Now">
<!ENTITY updateRestart.cancelButton.accesskey "N">
<!ENTITY updateRestart.panelUI.label "Restart &brandShorterName; to apply update">
<!ENTITY updateRestart.panelUI.label "Restart &brandShorterName; to apply the update">

View File

@ -222,17 +222,11 @@ compactLightTheme.description=A compact theme with a light color scheme.
compactDarkTheme.name=Compact Dark
compactDarkTheme.description=A compact theme with a dark color scheme.
# LOCALIZATION NOTE (lwthemeInstallRequest.message): %S will be replaced with
# LOCALIZATION NOTE (lwthemeInstallRequest.message2): %S will be replaced with
# the host name of the site.
lwthemeInstallRequest.message=This site (%S) attempted to install a theme.
lwthemeInstallRequest.allowButton=Allow
lwthemeInstallRequest.allowButton.accesskey=a
lwthemePostInstallNotification.message=A new theme has been installed.
lwthemePostInstallNotification.undoButton=Undo
lwthemePostInstallNotification.undoButton.accesskey=U
lwthemePostInstallNotification.manageButton=Manage Themes…
lwthemePostInstallNotification.manageButton.accesskey=M
lwthemeInstallRequest.message2=This site (%S) attempted to install a theme.
lwthemeInstallRequest.allowButton2=Allow
lwthemeInstallRequest.allowButton.accesskey2=a
# LOCALIZATION NOTE (lwthemeNeedsRestart.message):
# %S will be replaced with the new theme name.

View File

@ -1,18 +1,22 @@
ach
af
an
ar
as
ast
be
az
bg
bn-BD
bn-IN
br
bs
ca
cak
cs
cy
da
de
dsb
el
en-GB
en-US
@ -25,16 +29,19 @@ es-MX
et
eu
fa
ff
fi
fr
fy-NL
ga-IE
gd
gl
gn
gu-IN
he
hi-IN
hr
hsb
hu
hy-AM
id
@ -42,16 +49,20 @@ is
it
ja linux win32
ja-JP-mac osx
ka
kab
kk
km
kn
ko
ku
lij
lt
lv
mai
mk
ml
mr
ms
nb-NO
nl
nn-NO
@ -75,8 +86,9 @@ te
th
tr
uk
ur
uz
vi
xh
zh-CN
zh-TW
zu

View File

@ -79,6 +79,9 @@ HiddenFrame.prototype = {
}
};
this._webProgress.addProgressListener(this._listener, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
this._browser.document.location = XUL_PAGE;
let docShell = this._browser.getInterface(Ci.nsIDocShell);
docShell.createAboutBlankContentViewer(Services.scriptSecurityManager.getSystemPrincipal());
docShell.useGlobalHistory = false;
this._browser.loadURI(XUL_PAGE, 0, null, null, null);
}
};

View File

@ -61,16 +61,6 @@ automation/upload: automation/package-tests
automation/upload: automation/buildsymbols
automation/upload: automation/update-packaging
# buildsymbols will modify our test binaries, which can interfere with
# packaging them. A finer-grained dependency can help performance here
# once bug 1329020 is fixed.
automation/package-tests: automation/buildsymbols
# automation/package should depend on build (which is implicit due to the way
# client.mk invokes automation/build), but buildsymbols changes the
# binaries/libs, and that's what we package/test.
automation/package: automation/buildsymbols
# The installer and packager all run stage-package, and may conflict
# with each other.
automation/installer: automation/package

View File

@ -68,10 +68,29 @@ CURRENT_DIRS := $($(CURRENT_TIER)_dirs)
# Need a list of compile targets because we can't use pattern rules:
# https://savannah.gnu.org/bugs/index.php?42833
# Only recurse the paths starting with RECURSE_BASE_DIR when provided.
.PHONY: $(compile_targets)
$(compile_targets):
.PHONY: $(compile_targets) $(syms_targets)
$(compile_targets) $(syms_targets):
$(if $(filter $(RECURSE_BASE_DIR)%,$@),$(call RECURSE,$(@F),$(@D)))
$(syms_targets): %/syms: %/target
# Only hook symbols targets into the main compile graph in automation.
ifdef MOZ_AUTOMATION
ifdef MOZ_CRASHREPORTER
recurse_compile: $(syms_targets)
endif
endif
# Create a separate rule that depends on every 'syms' target so that
# symbols can be dumped on demand locally.
.PHONY: recurse_syms
recurse_syms: $(syms_targets)
# Ensure dump_syms gets built before any syms targets, all of which depend on it.
ifneq (,$(filter toolkit/crashreporter/google-breakpad/src/tools/%/dump_syms/host,$(compile_targets)))
$(syms_targets): $(filter toolkit/crashreporter/google-breakpad/src/tools/%/dump_syms/host,$(compile_targets))
endif
# The compile tier has different rules from other tiers.
ifneq ($(CURRENT_TIER),compile)

View File

@ -547,6 +547,8 @@ host:: $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(HOST_RUST_PROGR
target:: $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(RUST_LIBRARY_FILE) $(RUST_PROGRAMS)
syms::
include $(MOZILLA_DIR)/config/makefiles/target_binaries.mk
endif
@ -878,6 +880,26 @@ $(ASOBJS):
$(AS) $(ASOUTOPTION)$@ $(ASFLAGS) $($(notdir $<)_FLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS)
endif
define syms_template
syms:: $(2)
$(2): $(1)
$$(call py_action,dumpsymbols,$$(abspath $$<) $$(abspath $$@))
endef
ifndef MOZ_PROFILE_GENERATE
ifneq (,$(filter $(DIST)/bin%,$(FINAL_TARGET)))
DUMP_SYMS_TARGETS := $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS)
endif
endif
ifdef MOZ_AUTOMATION
ifeq (,$(filter 1,$(MOZ_AUTOMATION_BUILD_SYMBOLS)))
DUMP_SYMS_TARGETS :=
endif
endif
$(foreach file,$(DUMP_SYMS_TARGETS),$(eval $(call syms_template,$(file),$(file)_syms.track)))
ifdef MOZ_RUST
cargo_host_flag := --target=$(RUST_HOST_TARGET)
cargo_target_flag := --target=$(RUST_TARGET)

View File

@ -8940,10 +8940,20 @@ return /******/ (function(modules) { // webpackBootstrap
let flags = (httpActivity.private) ?
Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
let host = httpActivity.hostname;
if (!uri) {
// isSecureURI only cares about the host, not the scheme.
let host = httpActivity.hostname;
uri = Services.io.newURI("https://" + host);
}
info.hsts = sss.isSecureHost(sss.HEADER_HSTS, host, flags);
info.hpkp = sss.isSecureHost(sss.HEADER_HPKP, host, flags);
let originAttributes = {};
if (httpActivity.channel) {
originAttributes = httpActivity.channel.loadInfo.originAttributes;
}
info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags,
originAttributes);
info.hpkp = sss.isSecureURI(sss.HEADER_HPKP, uri, flags,
originAttributes);
} else {
DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo",
"Could not get HSTS/HPKP status as hostname is not available.");

View File

@ -148,6 +148,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
[browser_markup_remove_xul_attributes.js]
skip-if = e10s # Bug 1036409 - The last selected node isn't reselected
[browser_markup_search_01.js]
[browser_markup_tag_delete_whitespace_node.js]
[browser_markup_tag_edit_01.js]
[browser_markup_tag_edit_02.js]
[browser_markup_tag_edit_03.js]

View File

@ -0,0 +1,51 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// After deleting a node, whitespace siblings that had an impact on the layout might no
// longer have any impact. This tests that the markup view is correctly rendered after
// deleting a node that triggers such a change.
const HTML =
`<div>
<p id="container">
<span>1</span> <span id="after-whitespace">2</span>
</p>
</div>`;
const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Test deleting a node that will modify the whitespace nodes rendered in the " +
"markup view.");
info("Select node #after-whitespace and make sure it is focused");
yield selectNode("#after-whitespace", inspector);
yield clickContainer("#after-whitespace", inspector);
info("Delete the node with the delete key");
let mutated = inspector.once("markupmutation");
EventUtils.sendKey("delete", inspector.panelWin);
yield Promise.all([mutated, inspector.once("inspector-updated")]);
// TODO: There is still an issue with selection here. When the span is deleted, the
// selection goes to text-node. But since the text-node gets removed from the markup
// view after losing its impact on the layout, the selection remains on a node which
// is no longer part of the markup view (but still a valid node in the content DOM).
let parentNodeFront = yield inspector.selection.nodeFront.parentNode();
let nodeFront = yield getNodeFront("#container", inspector);
is(parentNodeFront, nodeFront, "Selection is as expected after deletion");
info("Check that the node was really removed");
let node = yield getNodeFront("#after-whitespace", inspector);
ok(!node, "The node can't be found in the page anymore");
info("Undo the deletion to restore the original markup");
yield undoChange(inspector);
node = yield getNodeFront("#after-whitespace", inspector);
ok(node, "The node is back");
});

View File

@ -716,6 +716,15 @@ netmonitor.context.copyImageAsDataUri=Copy Image as Data URI
# for the Copy Image As Data URI menu item displayed in the context menu for a request
netmonitor.context.copyImageAsDataUri.accesskey=I
# LOCALIZATION NOTE (netmonitor.context.saveImageAs): This is the label displayed
# on the context menu that save the Image
netmonitor.context.saveImageAs=Save Image As
# LOCALIZATION NOTE (netmonitor.context.copyImageAsDataUri.accesskey): This is the access key
# for the Copy Image As Data URI menu item displayed in the context menu for a request
netmonitor.context.saveImageAs.accesskey=V
# LOCALIZATION NOTE (netmonitor.context.copyAllAsHar): This is the label displayed
# on the context menu that copies all as HAR format
netmonitor.context.copyAllAsHar=Copy All As HAR

View File

@ -9,6 +9,7 @@ const { Curl } = require("devtools/client/shared/curl");
const { gDevTools } = require("devtools/client/framework/devtools");
const Menu = require("devtools/client/framework/menu");
const MenuItem = require("devtools/client/framework/menu-item");
const FileSaver = require("devtools/client/shared/file-saver");
const clipboardHelper = require("devtools/shared/platform/clipboard");
const { HarExporter } = require("./har/har-exporter");
const { NetMonitorController } = require("./netmonitor-controller");
@ -155,6 +156,16 @@ RequestListContextMenu.prototype = {
click: () => this.saveAllAsHar(),
}));
menu.append(new MenuItem({
id: "request-list-context-save-image-as",
label: L10N.getStr("netmonitor.context.saveImageAs"),
accesskey: L10N.getStr("netmonitor.context.saveImageAs.accesskey"),
visible: !!(selectedRequest &&
selectedRequest.responseContent &&
selectedRequest.responseContent.content.mimeType.includes("image/")),
click: () => this.saveImageAs(),
}));
menu.append(new MenuItem({
type: "separator",
visible: !!(NetMonitorController.supportsCustomRequest &&
@ -323,6 +334,26 @@ RequestListContextMenu.prototype = {
});
},
/**
* Save image as.
*/
saveImageAs() {
const { encoding, text } = this.selectedRequest.responseContent.content;
let fileName = this.selectedRequest.urlDetails.baseNameWithQuery;
let data;
if (encoding === "base64") {
let decoded = atob(text);
data = new Uint8Array(decoded.length);
for (let i = 0; i < decoded.length; ++i) {
data[i] = decoded.charCodeAt(i);
}
} else {
data = text;
}
let blob = new Blob([data]);
FileSaver.saveAs(blob, fileName, document);
},
/**
* Copy response data as a string.
*/

View File

@ -90,6 +90,11 @@ const XHTML_NS = "http://www.w3.org/1999/xhtml";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const IMAGE_FETCHING_TIMEOUT = 500;
// SKIP_TO_* arguments are used with the DocumentWalker, driving the strategy to use if
// the starting node is incompatible with the filter function of the walker.
const SKIP_TO_PARENT = "SKIP_TO_PARENT";
const SKIP_TO_SIBLING = "SKIP_TO_SIBLING";
// The possible completions to a ':' with added score to give certain values
// some preference.
const PSEUDO_SELECTORS = [
@ -934,12 +939,12 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
return "[WalkerActor " + this.actorID + "]";
},
getDocumentWalker: function (node, whatToShow) {
getDocumentWalker: function (node, whatToShow, skipTo) {
// Allow native anon content (like <video> controls) if preffed on
let nodeFilter = this.showAllAnonymousContent
? allAnonymousContentTreeWalkerFilter
: standardTreeWalkerFilter;
return new DocumentWalker(node, this.rootWin, whatToShow, nodeFilter);
? allAnonymousContentTreeWalkerFilter
: standardTreeWalkerFilter;
return new DocumentWalker(node, this.rootWin, whatToShow, nodeFilter, skipTo);
},
destroy: function () {
@ -1370,7 +1375,10 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
// We're going to create a few document walkers with the same filter,
// make it easier.
let getFilteredWalker = documentWalkerNode => {
return this.getDocumentWalker(documentWalkerNode, options.whatToShow);
let { whatToShow } = options;
// Use SKIP_TO_SIBLING to force the walker to use a sibling of the provided node
// in case this one is incompatible with the walker's filter function.
return this.getDocumentWalker(documentWalkerNode, whatToShow, SKIP_TO_SIBLING);
};
// Need to know the first and last child.
@ -1396,7 +1404,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
// Start by reading backward from the starting point if we're centering...
let backwardWalker = getFilteredWalker(start);
if (start != firstChild && options.center) {
if (backwardWalker.currentNode != firstChild && options.center) {
backwardWalker.previousSibling();
let backwardCount = Math.floor(maxNodes / 2);
let backwardNodes = this._readBackward(backwardWalker, backwardCount);
@ -1518,9 +1526,14 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
*/
_readForward: function (walker, count) {
let ret = [];
let node = walker.currentNode;
do {
ret.push(this._ref(node));
if (!walker.isSkippedNode(node)) {
// The walker can be on a node that would be filtered out if it didn't find any
// other node to fallback to.
ret.push(this._ref(node));
}
node = walker.nextSibling();
} while (node && --count);
return ret;
@ -1532,9 +1545,14 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
*/
_readBackward: function (walker, count) {
let ret = [];
let node = walker.currentNode;
do {
ret.push(this._ref(node));
if (!walker.isSkippedNode(node)) {
// The walker can be on a node that would be filtered out if it didn't find any
// other node to fallback to.
ret.push(this._ref(node));
}
node = walker.previousSibling();
} while (node && --count);
ret.reverse();
@ -2968,14 +2986,20 @@ function isNodeDead(node) {
*
* @param {DOMNode} node
* @param {Window} rootWin
* @param {Int} whatToShow See nodeFilterConstants / inIDeepTreeWalker for
* options.
* @param {Function} filter A custom filter function Taking in a DOMNode
* and returning an Int. See WalkerActor.nodeFilter for an example.
* @param {Number} whatToShow
* See nodeFilterConstants / inIDeepTreeWalker for options.
* @param {Function} filter
* A custom filter function Taking in a DOMNode and returning an Int. See
* WalkerActor.nodeFilter for an example.
* @param {String} skipTo
* Either SKIP_TO_PARENT or SKIP_TO_SIBLING. If the provided node is not compatible
* with the filter function for this walker, try to find a compatible one either
* in the parents or in the siblings of the node.
*/
function DocumentWalker(node, rootWin,
whatToShow = nodeFilterConstants.SHOW_ALL,
filter = standardTreeWalkerFilter) {
filter = standardTreeWalkerFilter,
skipTo = SKIP_TO_PARENT) {
if (!rootWin.location) {
throw new Error("Got an invalid root window in DocumentWalker");
}
@ -2989,19 +3013,11 @@ function DocumentWalker(node, rootWin,
this.filter = filter;
// Make sure that the walker knows about the initial node (which could
// be skipped due to a filter). Note that simply calling parentNode()
// causes currentNode to be updated.
this.walker.currentNode = node;
while (node &&
this.filter(node) === nodeFilterConstants.FILTER_SKIP) {
node = this.walker.parentNode();
}
// be skipped due to a filter).
this.walker.currentNode = this.getStartingNode(node, skipTo);
}
DocumentWalker.prototype = {
get node() {
return this.walker.node;
},
get whatToShow() {
return this.walker.whatToShow;
},
@ -3023,8 +3039,7 @@ DocumentWalker.prototype = {
}
let nextNode = this.walker.nextNode();
while (nextNode &&
this.filter(nextNode) === nodeFilterConstants.FILTER_SKIP) {
while (nextNode && this.isSkippedNode(nextNode)) {
nextNode = this.walker.nextNode();
}
@ -3038,8 +3053,7 @@ DocumentWalker.prototype = {
}
let firstChild = this.walker.firstChild();
while (firstChild &&
this.filter(firstChild) === nodeFilterConstants.FILTER_SKIP) {
while (firstChild && this.isSkippedNode(firstChild)) {
firstChild = this.walker.nextSibling();
}
@ -3053,8 +3067,7 @@ DocumentWalker.prototype = {
}
let lastChild = this.walker.lastChild();
while (lastChild &&
this.filter(lastChild) === nodeFilterConstants.FILTER_SKIP) {
while (lastChild && this.isSkippedNode(lastChild)) {
lastChild = this.walker.previousSibling();
}
@ -3063,7 +3076,7 @@ DocumentWalker.prototype = {
previousSibling: function () {
let node = this.walker.previousSibling();
while (node && this.filter(node) === nodeFilterConstants.FILTER_SKIP) {
while (node && this.isSkippedNode(node)) {
node = this.walker.previousSibling();
}
return node;
@ -3071,11 +3084,62 @@ DocumentWalker.prototype = {
nextSibling: function () {
let node = this.walker.nextSibling();
while (node && this.filter(node) === nodeFilterConstants.FILTER_SKIP) {
while (node && this.isSkippedNode(node)) {
node = this.walker.nextSibling();
}
return node;
}
},
getStartingNode: function (node, skipTo) {
// Keep a reference on the starting node in case we can't find a node compatible with
// the filter.
let startingNode = node;
if (skipTo === SKIP_TO_PARENT) {
while (node && this.isSkippedNode(node)) {
node = node.parentNode;
}
} else if (skipTo === SKIP_TO_SIBLING) {
node = this.getClosestAcceptedSibling(node);
}
return node || startingNode;
},
/**
* Loop on all of the provided node siblings until finding one that is compliant with
* the filter function.
*/
getClosestAcceptedSibling: function (node) {
if (this.filter(node) === nodeFilterConstants.FILTER_ACCEPT) {
// node is already valid, return immediately.
return node;
}
// Loop on starting node siblings.
let previous = node;
let next = node;
while (previous || next) {
previous = previous && previous.previousSibling;
next = next && next.nextSibling;
if (this.filter(previous) === nodeFilterConstants.FILTER_ACCEPT) {
// A valid node was found in the previous siblings of the node.
return previous;
}
if (this.filter(next) === nodeFilterConstants.FILTER_ACCEPT) {
// A valid node was found in the next siblings of the node.
return next;
}
}
return null;
},
isSkippedNode: function (node) {
return this.filter(node) === nodeFilterConstants.FILTER_SKIP;
},
};
function isInXULDocument(el) {

View File

@ -644,8 +644,14 @@ var NetworkHelper = {
uri = Services.io.newURI("https://" + host);
}
info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags);
info.hpkp = sss.isSecureURI(sss.HEADER_HPKP, uri, flags);
let originAttributes = {};
if (httpActivity.channel) {
originAttributes = httpActivity.channel.loadInfo.originAttributes;
}
info.hsts = sss.isSecureURI(sss.HEADER_HSTS, uri, flags,
originAttributes);
info.hpkp = sss.isSecureURI(sss.HEADER_HPKP, uri, flags,
originAttributes);
} else {
DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo",
"Could not get HSTS/HPKP status as hostname is not available.");

View File

@ -32,8 +32,7 @@ support-files =
[test_network_get.html]
[test_network_longstring.html]
[test_network_post.html]
[test_network_security-hpkp.html]
[test_network_security-hsts.html]
[test_network_security.html]
[test_nsiconsolemessage.html]
[test_object_actor.html]
[test_object_actor_native_getters.html]

View File

@ -1,105 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for the network actor (HPKP detection)</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for the network actor (HPKP detection)</p>
<iframe src="https://example.com/chrome/devtools/shared/webconsole/test/network_requests_iframe.html"></iframe>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
let gCurrentTestCase = -1;
const HPKP_PREF = "security.cert_pinning.process_headers_from_non_builtin_roots";
// Static pins tested by unit/test_security-info-static-hpkp.js.
const TEST_CASES = [
{
desc: "no Public Key Pinning",
url: "https://example.com",
usesPinning: false,
},
{
desc: "dynamic Public Key Pinning with this request",
url: "https://include-subdomains.pinning-dynamic.example.com/" +
"browser/browser/base/content/test/general/pinning_headers.sjs",
usesPinning: true,
},
{
desc: "dynamic Public Key Pinning with previous request",
url: "https://include-subdomains.pinning-dynamic.example.com/",
usesPinning: true,
}
];
function startTest() {
// Need to enable this pref or pinning headers are rejected due test
// certificate.
Services.prefs.setBoolPref(HPKP_PREF, true);
SimpleTest.registerCleanupFunction(() => {
Services.prefs.setBoolPref(HPKP_PREF, false);
// Reset pinning state.
let gSSService = Cc["@mozilla.org/ssservice;1"]
.getService(Ci.nsISiteSecurityService);
let gIOService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
for (let {url} of TEST_CASES) {
let uri = gIOService.newURI(url);
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
}
});
info("Test detection of Public Key Pinning.");
removeEventListener("load", startTest);
attachConsoleToTab(["NetworkActivity"], onAttach);
}
function onAttach(state, response) {
onNetworkEventUpdate = onNetworkEventUpdate.bind(null, state);
state.dbgClient.addListener("networkEventUpdate", onNetworkEventUpdate);
runNextCase(state);
}
function runNextCase(state) {
gCurrentTestCase++;
if (gCurrentTestCase === TEST_CASES.length) {
info("Tests ran. Cleaning up.");
closeDebugger(state, SimpleTest.finish);
return;
}
let { desc, url } = TEST_CASES[gCurrentTestCase];
info("Testing site with " + desc);
let iframe = document.querySelector("iframe").contentWindow;
iframe.wrappedJSObject.makeXhrCallback("GET", url);
}
function onNetworkEventUpdate(state, type, packet) {
function onSecurityInfo(received) {
let data = TEST_CASES[gCurrentTestCase];
is(received.securityInfo.hpkp, data.usesPinning,
"Public Key Pinning detected correctly.");
runNextCase(state);
}
if (packet.updateType === "securityInfo") {
state.client.getSecurityInfo(packet.from, onSecurityInfo);
}
}
addEventListener("load", startTest);
</script>
</body>
</html>

View File

@ -1,100 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for the network actor (HSTS detection)</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for the network actor (HSTS detection)</p>
<iframe src="https://example.com/chrome/devtools/shared/webconsole/test/network_requests_iframe.html"></iframe>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
let gCurrentTestCase = -1;
const TEST_CASES = [
{
desc: "no HSTS",
url: "https://example.com",
usesHSTS: false,
},
{
desc: "HSTS from this response",
url: "https://example.com/"+
"browser/browser/base/content/test/general/browser_star_hsts.sjs",
usesHSTS: true,
},
{
desc: "stored HSTS from previous response",
url: "https://example.com/",
usesHSTS: true,
}
];
function startTest()
{
SimpleTest.registerCleanupFunction(() => {
// Reset HSTS state.
let gSSService = Cc["@mozilla.org/ssservice;1"]
.getService(Ci.nsISiteSecurityService);
let gIOService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
let uri = gIOService.newURI(TEST_CASES[0].url);
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
});
info("Test detection of HTTP Strict Transport Security.");
removeEventListener("load", startTest);
attachConsoleToTab(["NetworkActivity"], onAttach);
}
function onAttach(aState, aResponse)
{
onNetworkEventUpdate = onNetworkEventUpdate.bind(null, aState);
aState.dbgClient.addListener("networkEventUpdate", onNetworkEventUpdate);
runNextCase(aState);
}
function runNextCase(aState) {
gCurrentTestCase++;
if (gCurrentTestCase === TEST_CASES.length) {
info("Tests ran. Cleaning up.");
closeDebugger(aState, SimpleTest.finish);
return;
}
let { desc, url } = TEST_CASES[gCurrentTestCase];
info("Testing site with " + desc);
let iframe = document.querySelector("iframe").contentWindow;
iframe.wrappedJSObject.makeXhrCallback("GET", url);
}
function onNetworkEventUpdate(aState, aType, aPacket)
{
function onSecurityInfo(packet) {
let data = TEST_CASES[gCurrentTestCase];
is(packet.securityInfo.hsts, data.usesHSTS,
"Strict Transport Security detected correctly.");
runNextCase(aState);
}
if (aPacket.updateType === "securityInfo") {
aState.client.getSecurityInfo(aPacket.from, onSecurityInfo);
}
}
addEventListener("load", startTest);
</script>
</body>
</html>

View File

@ -0,0 +1,196 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for the network actor (HPKP detection)</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for the network actor (HPKP detection)</p>
<iframe src="https://example.com/chrome/devtools/shared/webconsole/test/network_requests_iframe.html"></iframe>
<script class="testbody" type="text/javascript">
Cu.import("resource://testing-common/BrowserTestUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
SimpleTest.waitForExplicitFinish();
let gCurrentTestCase = -1;
const HPKP_PREF = "security.cert_pinning.process_headers_from_non_builtin_roots";
// Static pins tested by unit/test_security-info-static-hpkp.js.
const TEST_CASES = [
{
desc: "no HSTS or HPKP",
url: "https://example.com",
usesHSTS: false,
usesPinning: false,
},
{
desc: "HSTS from this response, no Public Key Pinning",
url: "https://example.com/" +
"browser/browser/base/content/test/general/browser_star_hsts.sjs",
usesHSTS: true,
usesPinning: false,
},
{
desc: "stored HSTS from previous response, no Public Key Pinning",
url: "https://example.com/",
usesHSTS: true,
usesPinning: false,
},
{
desc: "no Public Key Pinning or HSTS",
url: "https://include-subdomains.pinning-dynamic.example.com/",
usesHSTS: false,
usesPinning: false,
},
{
desc: "dynamic Public Key Pinning with this request, no HSTS",
url: "https://include-subdomains.pinning-dynamic.example.com/" +
"browser/browser/base/content/test/general/pinning_headers.sjs",
usesHSTS: false,
usesPinning: true,
},
{
desc: "dynamic Public Key Pinning with previous request, no HSTS",
url: "https://include-subdomains.pinning-dynamic.example.com/",
usesHSTS: false,
usesPinning: true,
}
];
const TEST_MODES = [ "public", "private" ];
let ALL_TESTS = [];
function startTest() {
// Need to enable this pref or pinning headers are rejected due test
// certificate.
Services.prefs.setBoolPref(HPKP_PREF, true);
SimpleTest.registerCleanupFunction(() => {
Services.prefs.setBoolPref(HPKP_PREF, false);
// Reset pinning state.
let gSSService = Cc["@mozilla.org/ssservice;1"]
.getService(Ci.nsISiteSecurityService);
let gIOService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
for (let {url} of TEST_CASES) {
let uri = gIOService.newURI(url);
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
Ci.nsISocketProvider.NO_PERMANENT_STORAGE,
{ privateBrowsingId: 1 });
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
Ci.nsISocketProvider.NO_PERMANENT_STORAGE,
{ privateBrowsingId: 1 });
}
});
info("Test detection of HTTP Strict Transport Security" +
" and Public Key Pinning.");
for (let mode of TEST_MODES) {
for (let testCase of TEST_CASES) {
let test = { mode };
for (let attr in testCase) {
test[attr] = testCase[attr];
}
ALL_TESTS.push(test);
}
}
removeEventListener("load", startTest);
attachConsoleToTab(["NetworkActivity"], onAttach);
}
function onAttach(state, response) {
let callback = onNetworkEventUpdate.bind(null, state);
state.dbgClient.addListener("networkEventUpdate", callback);
runNextCase(state);
}
function runNextCase(state) {
gCurrentTestCase++;
if (gCurrentTestCase === ALL_TESTS.length) {
info("Tests ran. Cleaning up.");
closeDebugger(state, SimpleTest.finish);
return;
}
let { desc, url, mode } = ALL_TESTS[gCurrentTestCase];
info("Testing site with " + desc);
if (mode == "private") {
info("Cleaning up the previous window.");
closeDebugger(state, runInPrivateWindow);
} else {
let iframe = document.querySelector("iframe").contentWindow;
iframe.wrappedJSObject.makeXhrCallback("GET", url);
}
}
function onNetworkEventUpdate(state, type, packet) {
function onSecurityInfo(received) {
let data = ALL_TESTS[gCurrentTestCase];
is(received.securityInfo.hsts, data.usesHSTS,
"Strict Transport Security detected correctly.");
is(received.securityInfo.hpkp, data.usesPinning,
"Public Key Pinning detected correctly.");
runNextCase(state);
}
if (packet.updateType === "securityInfo") {
state.client.getSecurityInfo(packet.from, onSecurityInfo);
}
}
function whenDelayedStartupFinished(aWindow, aCallback) {
SpecialPowers.Services.obs.addObserver(function observer(aSubject, aTopic) {
if (aWindow == aSubject) {
SpecialPowers.Services.obs.removeObserver(observer, aTopic);
SimpleTest.executeSoon(aCallback);
}
}, "browser-delayed-startup-finished", false);
}
let mainWindow =
window.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShellTreeItem).
rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindow);
function runInPrivateWindow() {
let win = mainWindow.OpenBrowserWindow({private: true});
Task.spawn(function* () {
yield new Promise(resolve => whenDelayedStartupFinished(win, resolve));
let browser = win.gBrowser.selectedBrowser;
let url = ALL_TESTS[gCurrentTestCase].url;
win.gBrowser.selectedTab = win.gBrowser.getTabForBrowser(browser);
yield new Promise(function(resolve) {
attachConsoleToTab(["NetworkActivity"], function(state) {
let callback = onNetworkEventUpdate.bind(null, state);
state.dbgClient.addListener("networkEventUpdate", callback);
resolve();
});
});
yield BrowserTestUtils.loadURI(browser, url);
});
}
SimpleTest.requestLongerTimeout(6); // We'll open 6 new windows.
addEventListener("load", startTest);
</script>
</body>
</html>

View File

@ -1574,6 +1574,10 @@ Navigator::NotifyActiveVRDisplaysChanged()
VRServiceTest*
Navigator::RequestVRServiceTest()
{
// Ensure that the Mock VR devices are not released prematurely
nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow);
win->NotifyVREventListenerAdded();
if (!mVRServiceTest) {
mVRServiceTest = VRServiceTest::CreateTestService(mWindow);
}

View File

@ -78,10 +78,12 @@ Gamepad::SetConnected(bool aConnected)
}
void
Gamepad::SetButton(uint32_t aButton, bool aPressed, double aValue)
Gamepad::SetButton(uint32_t aButton, bool aPressed,
bool aTouched, double aValue)
{
MOZ_ASSERT(aButton < mButtons.Length());
mButtons[aButton]->SetPressed(aPressed);
mButtons[aButton]->SetTouched(aTouched);
mButtons[aButton]->SetValue(aValue);
UpdateTimestamp();
}
@ -101,6 +103,7 @@ void
Gamepad::SetPose(const GamepadPoseState& aPose)
{
mPose->SetPoseState(aPose);
UpdateTimestamp();
}
void
@ -116,6 +119,7 @@ Gamepad::SyncState(Gamepad* aOther)
mConnected = aOther->mConnected;
for (uint32_t i = 0; i < mButtons.Length(); ++i) {
mButtons[i]->SetPressed(aOther->mButtons[i]->Pressed());
mButtons[i]->SetTouched(aOther->mButtons[i]->Touched());
mButtons[i]->SetValue(aOther->mButtons[i]->Value());
}

View File

@ -51,7 +51,8 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Gamepad)
void SetConnected(bool aConnected);
void SetButton(uint32_t aButton, bool aPressed, double aValue);
void SetButton(uint32_t aButton, bool aPressed,
bool aTouched, double aValue);
void SetAxis(uint32_t aAxis, double aValue);
void SetIndex(uint32_t aIndex);
void SetPose(const GamepadPoseState& aPose);

View File

@ -19,8 +19,9 @@ class GamepadButton : public nsISupports,
{
public:
explicit GamepadButton(nsISupports* aParent) : mParent(aParent),
mValue(0),
mPressed(false),
mValue(0)
mTouched(false)
{
}
@ -39,6 +40,11 @@ public:
mPressed = aPressed;
}
void SetTouched(bool aTouched)
{
mTouched = aTouched;
}
void SetValue(double aValue)
{
mValue = aValue;
@ -49,6 +55,11 @@ public:
return mPressed;
}
bool Touched() const
{
return mTouched;
}
double Value() const
{
return mValue;
@ -59,8 +70,9 @@ private:
protected:
nsCOMPtr<nsISupports> mParent;
bool mPressed;
double mValue;
bool mPressed;
bool mTouched;
};
} // namespace dom

View File

@ -269,7 +269,8 @@ GamepadManager::RemoveGamepad(uint32_t aIndex, GamepadServiceType aServiceType)
void
GamepadManager::NewButtonEvent(uint32_t aIndex, GamepadServiceType aServiceType,
uint32_t aButton, bool aPressed, double aValue)
uint32_t aButton, bool aPressed, bool aTouched,
double aValue)
{
if (mShuttingDown) {
return;
@ -282,7 +283,7 @@ GamepadManager::NewButtonEvent(uint32_t aIndex, GamepadServiceType aServiceType,
return;
}
gamepad->SetButton(aButton, aPressed, aValue);
gamepad->SetButton(aButton, aPressed, aTouched, aValue);
// Hold on to listeners in a separate array because firing events
// can mutate the mListeners array.
@ -303,7 +304,7 @@ GamepadManager::NewButtonEvent(uint32_t aIndex, GamepadServiceType aServiceType,
RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(newIndex);
if (listenerGamepad) {
listenerGamepad->SetButton(aButton, aPressed, aValue);
listenerGamepad->SetButton(aButton, aPressed, aTouched, aValue);
if (firstTime) {
FireConnectionEvent(listeners[i], listenerGamepad, true);
}
@ -650,7 +651,7 @@ GamepadManager::Update(const GamepadChangeEvent& aEvent)
if (aEvent.type() == GamepadChangeEvent::TGamepadButtonInformation) {
const GamepadButtonInformation& a = aEvent.get_GamepadButtonInformation();
NewButtonEvent(a.index(), a.service_type(), a.button(),
a.pressed(), a.value());
a.pressed(), a.touched(), a.value());
return;
}
if (aEvent.type() == GamepadChangeEvent::TGamepadAxisInformation) {

View File

@ -62,7 +62,7 @@ class GamepadManager final : public nsIObserver,
// a gamepadbutton{up,down} event at them as well.
// aPressed is used for digital buttons, aValue is for analog buttons.
void NewButtonEvent(uint32_t aIndex, GamepadServiceType aServiceType, uint32_t aButton,
bool aPressed, double aValue);
bool aPressed, bool aTouched, double aValue);
// Update the state of |aAxis| for the gamepad at |aIndex| for all
// windows that are listening and visible, and fire a gamepadaxismove

View File

@ -117,17 +117,30 @@ GamepadPlatformService::RemoveGamepad(uint32_t aIndex)
void
GamepadPlatformService::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
bool aPressed, double aValue)
bool aPressed, bool aTouched,
double aValue)
{
// This method is called by monitor thread populated in
// platform-dependent backends
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(!NS_IsMainThread());
GamepadButtonInformation a(aIndex, GamepadServiceType::Standard,
aButton, aPressed, aValue);
aButton, aValue, aPressed, aTouched);
NotifyGamepadChange<GamepadButtonInformation>(a);
}
void
GamepadPlatformService::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
bool aPressed, bool aTouched)
{
// This method is called by monitor thread populated in
// platform-dependent backends
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(!NS_IsMainThread());
// When only a digital button is available the value will be synthesized.
NewButtonEvent(aIndex, aButton, aPressed, aTouched, aPressed ? 1.0L : 0.0L);
}
void
GamepadPlatformService::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
bool aPressed)
@ -137,7 +150,7 @@ GamepadPlatformService::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(!NS_IsMainThread());
// When only a digital button is available the value will be synthesized.
NewButtonEvent(aIndex, aButton, aPressed, aPressed ? 1.0L : 0.0L);
NewButtonEvent(aIndex, aButton, aPressed, aPressed, aPressed ? 1.0L : 0.0L);
}
void

View File

@ -46,11 +46,15 @@ class GamepadPlatformService final
// Update the state of |aButton| for the gamepad at |aIndex| for all
// windows that are listening and visible, and fire one of
// a gamepadbutton{up,down} event at them as well.
// aPressed is used for digital buttons, aValue is for analog buttons.
// aPressed is used for digital buttons, aTouched is for detecting touched
// events, aValue is for analog buttons.
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed,
double aValue);
bool aTouched, double aValue);
// When only a digital button is available the value will be synthesized.
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed);
// When only a digital button are available the value will be synthesized.
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed,
bool aTouched);
// Update the state of |aAxis| for the gamepad at |aIndex| for all
// windows that are listening and visible, and fire a gamepadaxismove

View File

@ -168,6 +168,7 @@ GamepadServiceTest::RemoveGamepad(uint32_t aIndex)
void
GamepadServiceTest::NewButtonEvent(uint32_t aIndex,
uint32_t aButton,
bool aTouched,
bool aPressed)
{
if (mShuttingDown) {
@ -175,7 +176,7 @@ GamepadServiceTest::NewButtonEvent(uint32_t aIndex,
}
GamepadButtonInformation a(aIndex, GamepadServiceType::Standard,
aButton, aPressed, aPressed ? 1.0 : 0);
aButton, aPressed ? 1.0 : 0, aPressed, aTouched);
GamepadChangeEvent e(a);
uint32_t id = ++mEventNumber;
@ -191,6 +192,7 @@ void
GamepadServiceTest::NewButtonValueEvent(uint32_t aIndex,
uint32_t aButton,
bool aPressed,
bool aTouched,
double aValue)
{
if (mShuttingDown) {
@ -198,7 +200,7 @@ GamepadServiceTest::NewButtonValueEvent(uint32_t aIndex,
}
GamepadButtonInformation a(aIndex, GamepadServiceType::Standard,
aButton, aPressed, aValue);
aButton, aValue, aPressed, aTouched);
GamepadChangeEvent e(a);
uint32_t id = ++mEventNumber;

View File

@ -43,8 +43,9 @@ public:
uint32_t aNumHaptics,
ErrorResult& aRv);
void RemoveGamepad(uint32_t aIndex);
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed);
void NewButtonValueEvent(uint32_t aIndex, uint32_t aButton, bool aPressed, double aValue);
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed, bool aTouched);
void NewButtonValueEvent(uint32_t aIndex, uint32_t aButton, bool aPressed, bool aTouched,
double aValue);
void NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue);
void NewPoseMove(uint32_t aIndex,
const Nullable<Float32Array>& aOrient,

View File

@ -38,8 +38,9 @@ struct GamepadButtonInformation {
uint32_t index;
GamepadServiceType service_type;
uint32_t button;
bool pressed;
double value;
bool pressed;
bool touched;
};
struct GamepadPoseInformation {

View File

@ -40,7 +40,8 @@ GamepadTestChannelParent::RecvGamepadTestEvent(const uint32_t& aID,
}
if (aEvent.type() == GamepadChangeEvent::TGamepadButtonInformation) {
const GamepadButtonInformation& a = aEvent.get_GamepadButtonInformation();
service->NewButtonEvent(a.index(), a.button(), a.pressed(), a.value());
service->NewButtonEvent(a.index(), a.button(), a.pressed(), a.touched(),
a.value());
return IPC_OK();
}
if (aEvent.type() == GamepadChangeEvent::TGamepadAxisInformation) {

View File

@ -62,12 +62,20 @@ function nextTest() {
SimpleTest.executeSoon(runNextTest);
}
var gLinuxE10sSkipList = [
{ "test": "file_fullscreen-plugins.html", "reason": "bug 1330553" },
{ "test": "file_fullscreen-api.html", "reason": "bug 1332040" },
{ "test": "file_fullscreen-scrollbar.html", "reason": "bug 1350875" }
];
function shouldSkipTest(test) {
if (test == "file_fullscreen-plugins.html") {
if (!SpecialPowers.isMainProcess() &&
navigator.platform.indexOf('Linux') >= 0) {
// Bug 1330553
return true;
if (!SpecialPowers.isMainProcess() &&
navigator.platform.indexOf('Linux') >= 0) {
for (let item of gLinuxE10sSkipList) {
if (item.test == test) {
todo(false, `${test} skipped due to ${item.reason}`);
return true;
}
}
}
return false;

View File

@ -571,6 +571,9 @@ MediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
case MediaEventType::CancelVideoSuspendTimer:
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozcancelvideosuspendtimer"));
break;
case MediaEventType::VideoOnlySeekBegin:
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozvideoonlyseekbegin"));
break;
case MediaEventType::VideoOnlySeekCompleted:
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozvideoonlyseekcompleted"));
}

View File

@ -141,8 +141,8 @@ static_assert(LOW_BUFFER_THRESHOLD_USECS > AMPLE_AUDIO_USECS,
} // namespace detail
// Amount of excess usecs of data to add in to the "should we buffer" calculation.
static const uint32_t EXHAUSTED_DATA_MARGIN_USECS = 100000;
// Amount of excess data to add in to the "should we buffer" calculation.
static constexpr auto EXHAUSTED_DATA_MARGIN = TimeUnit::FromMicroseconds(100000);
static const uint32_t MIN_VIDEO_QUEUE_SIZE = 3;
static const uint32_t MAX_VIDEO_QUEUE_SIZE = 10;
@ -944,6 +944,12 @@ public:
{
mSeekJob = Move(aSeekJob);
// Dispatch a mozvideoonlyseekbegin event to indicate UI for corresponding
// changes.
if (mSeekJob.mTarget->IsVideoOnly()) {
mMaster->mOnPlaybackEvent.Notify(MediaEventType::VideoOnlySeekBegin);
}
// Always switch off the blank decoder otherwise we might become visible
// in the middle of seeking and won't have a valid video frame to show
// when seek is done.
@ -3294,8 +3300,8 @@ MediaDecoderStateMachine::HasLowDecodedAudio()
{
MOZ_ASSERT(OnTaskQueue());
return IsAudioDecoding()
&& GetDecodedAudioDuration().ToMicroseconds()
< EXHAUSTED_DATA_MARGIN_USECS * mPlaybackRate;
&& GetDecodedAudioDuration()
< EXHAUSTED_DATA_MARGIN.MultDouble(mPlaybackRate);
}
bool

View File

@ -124,6 +124,7 @@ enum class MediaEventType : int8_t
ExitVideoSuspend,
StartVideoSuspendTimer,
CancelVideoSuspendTimer,
VideoOnlySeekBegin,
VideoOnlySeekCompleted,
};

View File

@ -1648,9 +1648,12 @@ PeerConnectionWrapper.prototype = {
ok(rem.bytesReceived <= res.bytesSent, "No more than sent bytes");
}
ok(rem.jitter !== undefined, "Rtcp jitter");
ok(rem.mozRtt !== undefined, "Rtcp rtt");
ok(rem.mozRtt >= 0, "Rtcp rtt " + rem.mozRtt + " >= 0");
ok(rem.mozRtt < 60000, "Rtcp rtt " + rem.mozRtt + " < 1 min");
if (rem.roundTripTime) {
ok(rem.roundTripTime > 0,
"Rtcp rtt " + rem.roundTripTime + " >= 0");
ok(rem.roundTripTime < 60000,
"Rtcp rtt " + rem.roundTripTime + " < 1 min");
}
} else {
ok(rem.type == "outbound-rtp", "Rtcp is outbound");
ok(rem.packetsSent !== undefined, "Rtcp packetsSent");

View File

@ -14,7 +14,7 @@ var statsExpectedByType = {
"inbound-rtp": {
expected: ["id", "timestamp", "type", "ssrc", "isRemote", "mediaType",
"packetsReceived", "packetsLost", "bytesReceived", "jitter",],
optional: ["mozRtt", "remoteId", "nackCount",],
optional: ["roundTripTime", "remoteId", "nackCount",],
localVideoOnly: ["discardedPackets", "framerateStdDev", "framerateMean",
"bitrateMean", "bitrateStdDev", "firCount", "pliCount",],
unimplemented: ["mediaTrackId", "transportId", "codecId", "framesDecoded",
@ -22,6 +22,7 @@ var statsExpectedByType = {
"sliCount", "qpSum", "packetsRepaired", "fractionLost",
"burstPacketsLost", "burstLossCount", "burstDiscardCount",
"gapDiscardRate", "gapLossRate",],
deprecated: ["mozRtt"],
},
"outbound-rtp": {
expected: ["id", "timestamp", "type", "ssrc", "isRemote", "mediaType",
@ -31,7 +32,8 @@ var statsExpectedByType = {
"framerateMean", "framerateStdDev", "framesEncoded", "firCount",
"pliCount",],
unimplemented: ["mediaTrackId", "transportId", "codecId",
"sliCount", "qpSum", "roundTripTime", "targetBitrate",],
"sliCount", "qpSum", "targetBitrate",],
deprecated: [],
},
"codec": { skip: true },
"peer-connection": { skip: true },
@ -81,6 +83,14 @@ var checkExpectedFields = report => report.forEach(stat => {
ok(!Object.keys(stat).includes(field), "Unimplemented field " + stat.type
+ "." + field + " does not exist.");
});
//
// Ensure that all deprecated fields are not present
//
expectations.deprecated.forEach(field => {
ok(!Object.keys(stat).includes(field), "Deprecated field " + stat.type
+ "." + field + " does not exist.");
});
});
var pedanticChecks = report => {
@ -201,12 +211,13 @@ var pedanticChecks = report => {
// Optional fields
//
// mozRtt
// roundTripTime
if (stat.inner.isRemote) {
ok(stat.mozRtt >= 0, stat.type + ".mozRtt is sane.");
ok(stat.roundTripTime >= 0, stat.type + ".roundTripTime is sane with" +
"value of:" + stat.roundTripTime);
} else {
is(stat.mozRtt, undefined, stat.type
+ ".mozRtt is only set when isRemote is true");
is(stat.roundTripTime, undefined, stat.type
+ ".roundTripTime is only set when isRemote is true");
}
//
@ -362,40 +373,46 @@ var pedanticChecks = report => {
// This MUST be run after PC_*_WAIT_FOR_MEDIA_FLOW to ensure that we have RTP
// before checking for RTCP.
var waitForRtcp = async pc => {
var waitForSyncedRtcp = async pc => {
// Ensures that RTCP is present
let ensureRtcp = async () => pc.getStats().then(stats => {
let ensureSyncedRtcp = async () => {
let stats = await pc.getStats();
for (let [k, v] of stats) {
if (v.type.endsWith("bound-rtp") && !v.remoteId) {
throw new Error(v.id + " is missing remoteId: "
+ JSON.stringify(v));
}
if (v.type == "inbound-rtp" && v.isRemote == true
&& v.roundTripTime === undefined) {
throw new Error(v.id + " is missing roundTripTime: "
+ JSON.stringify(v));
}
}
return stats;
});
}
const waitPeriod = 500;
for (let totalTime = 10000; totalTime > 0; totalTime -= waitPeriod) {
const maxTime = 15000;
for (let totalTime = maxTime; totalTime > 0; totalTime -= waitPeriod) {
try {
return await ensureRtcp();
return await ensureSyncedRtcp();
} catch (e) {
info(e);
await wait(waitPeriod);
}
}
throw new Error("Waiting for RTCP timed out after at least " + totalTime
throw new Error("Waiting for synced RTCP timed out after at least " + maxTime
+ "ms");
}
var PC_LOCAL_TEST_LOCAL_STATS = test => {
return waitForRtcp(test.pcLocal).then(stats => {
return waitForSyncedRtcp(test.pcLocal).then(stats => {
checkExpectedFields(stats);
pedanticChecks(stats);
});
}
var PC_REMOTE_TEST_REMOTE_STATS = test => {
return waitForRtcp(test.pcRemote).then(stats => {
return waitForSyncedRtcp(test.pcRemote).then(stats => {
checkExpectedFields(stats);
pedanticChecks(stats);
});

View File

@ -344,7 +344,7 @@ struct ParamTraits<mozilla::dom::RTCInboundRTPStreamStats>
WriteParam(aMsg, aParam.mJitter);
WriteParam(aMsg, aParam.mMozAvSyncDelay);
WriteParam(aMsg, aParam.mMozJitterBufferDelay);
WriteParam(aMsg, aParam.mMozRtt);
WriteParam(aMsg, aParam.mRoundTripTime);
WriteParam(aMsg, aParam.mPacketsLost);
WriteParam(aMsg, aParam.mPacketsReceived);
WriteRTCRTPStreamStats(aMsg, aParam);
@ -358,7 +358,7 @@ struct ParamTraits<mozilla::dom::RTCInboundRTPStreamStats>
!ReadParam(aMsg, aIter, &(aResult->mJitter)) ||
!ReadParam(aMsg, aIter, &(aResult->mMozAvSyncDelay)) ||
!ReadParam(aMsg, aIter, &(aResult->mMozJitterBufferDelay)) ||
!ReadParam(aMsg, aIter, &(aResult->mMozRtt)) ||
!ReadParam(aMsg, aIter, &(aResult->mRoundTripTime)) ||
!ReadParam(aMsg, aIter, &(aResult->mPacketsLost)) ||
!ReadParam(aMsg, aIter, &(aResult->mPacketsReceived)) ||
!ReadRTCRTPStreamStats(aMsg, aIter, aResult) ||

View File

@ -34,8 +34,8 @@ function checkTimestamp(){
index = i;
// Press a button to make the gamepad visible
// to the page.
GamepadService.newButtonEvent(index, 0, true);
GamepadService.newButtonEvent(index, 0, true);
GamepadService.newButtonEvent(index, 0, true, true);
GamepadService.newButtonEvent(index, 0, true, true);
ok(true, "test");
});
}
@ -56,7 +56,7 @@ function buttonpresshandler(e) {
} else {
ok(timea <= e.gamepad.timestamp, "Timestamp less than last timestamp");
}
GamepadService.newButtonEvent(index, 0, false);
GamepadService.newButtonEvent(index, 0, false, false);
if (!firstPress) {
testOver = true;
SpecialPowers.executeSoon(cleanup);

View File

@ -21,8 +21,8 @@ let SpecialPowers = window.parent.SpecialPowers;
var gamepad_index;
function pressButton() {
GamepadService.newButtonEvent(gamepad_index, 0, true);
GamepadService.newButtonEvent(gamepad_index, 0, false);
GamepadService.newButtonEvent(gamepad_index, 0, true, true);
GamepadService.newButtonEvent(gamepad_index, 0, false, false);
}
// Add a gamepad

View File

@ -35,8 +35,8 @@ window.addEventListener("gamepadbuttondown", function() {
});
function pressButton() {
GamepadService.newButtonEvent(gamepad_index, 0, true);
GamepadService.newButtonEvent(gamepad_index, 0, false);
GamepadService.newButtonEvent(gamepad_index, 0, true, true);
GamepadService.newButtonEvent(gamepad_index, 0, false, false);
}
function startTest() {

View File

@ -47,17 +47,21 @@ function gamepad_loaded() {
w1.addEventListener("gamepadbuttonup", () => {
ok(!f1.contentWindow.gamepad.buttons[0].pressed,
"frame 1 no button pressed");
ok(!f1.contentWindow.gamepad.buttons[0].touched,
"frame 1 no button touched");
});
w2.addEventListener("gamepadbuttonup", () => {
ok(!f2.contentWindow.gamepad.buttons[0].pressed,
"frame 2 no button pressed");
ok(!f2.contentWindow.gamepad.buttons[0].touched,
"frame 2 no button touched");
setFrameVisible(f2, false);
SpecialPowers.executeSoon(function() {
GamepadService.newButtonEvent(index, 0, true);
GamepadService.newButtonEvent(index, 0, true, true);
});
})
// Now press the button, but don't release it.
GamepadService.newButtonEvent(index, 0, true);
GamepadService.newButtonEvent(index, 0, true, true);
}
window.addEventListener("gamepadbuttondown", function() {
@ -74,10 +78,12 @@ var tests = [
function check_button_pressed() {
// At this point the both frames should see the button as pressed.
ok(f1.contentWindow.gamepad.buttons[0].pressed, "frame 1 sees button pressed");
ok(f1.contentWindow.gamepad.buttons[0].touched, "frame 1 sees button touched");
ok(f2.contentWindow.gamepad.buttons[0].pressed, "frame 2 sees button pressed");
ok(f2.contentWindow.gamepad.buttons[0].touched, "frame 2 sees button touched");
// Now release the button, then hide the second frame.
GamepadService.newButtonEvent(index, 0, false);
GamepadService.newButtonEvent(index, 0, false, false);
}
function check_second_frame_no_button_press () {
@ -86,7 +92,9 @@ function check_second_frame_no_button_press () {
* but the second frame should not, since it's hidden.
*/
ok(f1.contentWindow.gamepad.buttons[0].pressed, "frame 1 sees button pressed");
ok(f1.contentWindow.gamepad.buttons[0].touched, "frame 1 sees button touched");
ok(!f2.contentWindow.gamepad.buttons[0].pressed, "frame 2 should not see button pressed");
ok(!f2.contentWindow.gamepad.buttons[0].touched, "frame 2 should not see button touched");
// Now unhide the second frame.
setFrameVisible(f2, true);
@ -94,6 +102,7 @@ function check_second_frame_no_button_press () {
// Now that the frame is visible again, it should see the button
// that was pressed.
ok(f2.contentWindow.gamepad.buttons[0].pressed, "frame 2 sees button pressed");
ok(f2.contentWindow.gamepad.buttons[0].touched, "frame 2 sees button touched");
// cleanup
GamepadService.removeGamepad(index);
SimpleTest.finish();

View File

@ -20,8 +20,8 @@ window.addEventListener("gamepadbuttondown", function() {
});
function pressButton() {
GamepadService.newButtonEvent(index, 0, true);
GamepadService.newButtonEvent(index, 0, false);
GamepadService.newButtonEvent(index, 0, true, true);
GamepadService.newButtonEvent(index, 0, false, false);
}
function setFrameVisible(f, visible) {

View File

@ -42,7 +42,7 @@ function startTest() {
0).then(function(i) {
index = i;
// Simulate button events on the gamepad we added
GamepadService.newButtonEvent(index, 0, true);
GamepadService.newButtonEvent(index, 0, true, true);
});
}
@ -59,12 +59,14 @@ function connecthandler(e) {
function buttontest1() {
var gamepads = navigator.getGamepads();
is(gamepads[0].buttons[0].pressed, true, "gamepad button should register as pressed");
GamepadService.newButtonValueEvent(index, 1, true, 0.5);
is(gamepads[0].buttons[0].touched, true, "gamepad button should register as touched");
GamepadService.newButtonValueEvent(index, 1, true, true, 0.5);
}
function buttontest2() {
var gamepads = navigator.getGamepads();
is(gamepads[0].buttons[1].pressed, true, "gamepad button should register as pressed");
is(gamepads[0].buttons[1].touched, true, "gamepad button should register as touched");
is(gamepads[0].buttons[1].value, 0.5, "gamepad button value should be 0.5");
GamepadService.removeGamepad(index);
SimpleTest.finish();

View File

@ -51,7 +51,7 @@ function startTest() {
0).then(function(index) {
internal_index1 = index;
// Press a button to make the gamepad visible to the page.
GamepadService.newButtonEvent(internal_index1, 0, true);
GamepadService.newButtonEvent(internal_index1, 0, true, true);
});
}
@ -75,7 +75,7 @@ function check_first_gamepad(e) {
2,
0).then(function(index) {
internal_index2 = index;
GamepadService.newButtonEvent(internal_index2, 0, true);
GamepadService.newButtonEvent(internal_index2, 0, true, true);
});
ok(true, "Done checking first gamepad");
}

View File

@ -30,6 +30,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
, divRect
, unLockedCoords
, lockedCoords
, mouseMoveIntervalID
, isUnlocked = false
, isLocked = false;
@ -50,6 +51,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
function moveUnlocked(e) {
info("Got mousemove via moveUnlocked");
clearInterval(mouseMoveIntervalID);
var firstCall = !unLockedCoords;
if (!firstCall) {
todo(false, "mousemove is fired twice.");
@ -72,6 +74,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
function moveLocked(e) {
info("Got mousemove via moveLocked");
clearInterval(mouseMoveIntervalID);
div.removeEventListener("mousemove", moveLocked);
isLocked = !!document.pointerLockElement;
@ -96,8 +99,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
div.removeEventListener("mousemove", moveUnlocked);
div.addEventListener("mousemove", moveLocked);
divRect = div.getBoundingClientRect();
synthesizeNativeMouseMove(div, (divRect.width / 4) * 3,
(divRect.height / 4) * 3);
// Bug 1295815
// Retrigger synthesizeNativeMouseMove until it actually happens.
mouseMoveIntervalID = setInterval(() => {
synthesizeNativeMouseMove(div, (divRect.width / 4) * 3,
(divRect.height / 4) * 3);
}, 100);
} else {
info("Got pointerlockchange for exiting");
}
@ -111,7 +118,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
synthesizeNativeMouseMove(div, 0, 0, () => {
div.addEventListener("mousemove", moveUnlocked);
divRect = div.getBoundingClientRect();
synthesizeNativeMouseMove(div, divRect.width / 2, divRect.height / 2);
// Bug 1295815
// Retrigger synthesizeNativeMouseMove until it actually happens.
mouseMoveIntervalID = setInterval(() => {
synthesizeNativeMouseMove(div, divRect.width / 2, divRect.height / 2);
}, 100);
});
});
div.requestFullscreen();

View File

@ -11,6 +11,7 @@
[Pref="dom.gamepad.enabled"]
interface GamepadButton {
readonly attribute boolean pressed;
readonly attribute boolean touched;
readonly attribute double value;
};

View File

@ -23,11 +23,13 @@ interface GamepadServiceTest
void newButtonEvent(unsigned long index,
unsigned long button,
boolean pressed);
boolean pressed,
boolean touched);
void newButtonValueEvent(unsigned long index,
unsigned long button,
boolean pressed,
boolean touched,
double value);
void newAxisMoveEvent(unsigned long index,

View File

@ -42,7 +42,7 @@ dictionary RTCRTPStreamStats : RTCStats {
// Local only measurements, RTCP related but not communicated via RTCP. Not
// present in RTCP case.
unsigned long firCount;
unsigned long firCount;
unsigned long pliCount;
unsigned long nackCount;
};
@ -54,7 +54,7 @@ dictionary RTCInboundRTPStreamStats : RTCRTPStreamStats {
unsigned long packetsLost;
long mozAvSyncDelay;
long mozJitterBufferDelay;
long mozRtt;
long roundTripTime;
// Video decoder measurement, not present in RTCP case
unsigned long discardedPackets;

View File

@ -176,6 +176,18 @@ VRControllerHost::GetButtonPressed()
return mButtonPressed;
}
void
VRControllerHost::SetButtonTouched(uint64_t aBit)
{
mButtonTouched = aBit;
}
uint64_t
VRControllerHost::GetButtonTouched()
{
return mButtonTouched;
}
void
VRControllerHost::SetPose(const dom::GamepadPoseState& aPose)
{

View File

@ -90,6 +90,8 @@ public:
const VRControllerInfo& GetControllerInfo() const;
void SetButtonPressed(uint64_t aBit);
uint64_t GetButtonPressed();
void SetButtonTouched(uint64_t aBit);
uint64_t GetButtonTouched();
void SetPose(const dom::GamepadPoseState& aPose);
const dom::GamepadPoseState& GetPose();
dom::GamepadHand GetHand();
@ -103,6 +105,8 @@ protected:
VRControllerInfo mControllerInfo;
// The current button pressed bit of button mask.
uint64_t mButtonPressed;
// The current button touched bit of button mask.
uint64_t mButtonTouched;
uint64_t mVibrateIndex;
dom::GamepadPoseState mPose;
};

View File

@ -116,13 +116,19 @@ VRManager::Destroy()
mInitialized = false;
}
void
VRManager::Shutdown()
{
mVRDisplays.Clear();
mVRControllers.Clear();
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
mManagers[i]->Shutdown();
}
}
void
VRManager::Init()
{
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
mManagers[i]->Init();
}
mInitialized = true;
}
@ -159,6 +165,7 @@ VRManager::NotifyVsync(const TimeStamp& aVsyncTimestamp)
bool bHaveEventListener = false;
bool bHaveControllerListener = false;
bool bHaveActiveDisplay = false;
for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
VRManagerParent *vmp = iter.Get()->GetKey();
@ -172,6 +179,9 @@ VRManager::NotifyVsync(const TimeStamp& aVsyncTimestamp)
for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) {
gfx::VRDisplayHost* display = iter.UserData();
display->NotifyVSync();
if (display->GetDisplayInfo().GetIsPresenting()) {
bHaveActiveDisplay = true;
}
}
if (bHaveEventListener) {
@ -209,6 +219,11 @@ VRManager::NotifyVsync(const TimeStamp& aVsyncTimestamp)
}
}
}
if (!bHaveEventListener && !bHaveControllerListener && !bHaveActiveDisplay) {
// Shut down the VR devices when not in use
Shutdown();
}
}
void
@ -406,7 +421,6 @@ VRManager::CreateVRTestSystem()
RefPtr<VRSystemManager> mgr = VRSystemManagerPuppet::Create();
if (mgr) {
mgr->Init();
mManagers.AppendElement(mgr);
mVRTestSystemCreated = true;
}

View File

@ -63,6 +63,7 @@ private:
void Init();
void Destroy();
void Shutdown();
void DispatchVRDisplayInfoUpdate();
void RefreshVRControllers();

View File

@ -87,10 +87,10 @@ VRSystemManager::RemoveGamepad(uint32_t aIndex)
void
VRSystemManager::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
bool aPressed, double aValue)
bool aPressed, bool aTouched, double aValue)
{
dom::GamepadButtonInformation a(aIndex, dom::GamepadServiceType::VR,
aButton, aPressed, aValue);
aButton, aValue, aPressed, aTouched);
VRManager* vm = VRManager::Get();
MOZ_ASSERT(vm);

View File

@ -251,8 +251,8 @@ protected:
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRSystemManager)
virtual bool Init() = 0;
virtual void Destroy() = 0;
virtual void Shutdown() = 0;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) = 0;
virtual bool GetIsPresenting() = 0;
virtual void HandleInput() = 0;
@ -262,7 +262,8 @@ public:
virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
double aIntensity, double aDuration, uint32_t aPromiseID) = 0;
virtual void StopVibrateHaptic(uint32_t aControllerIdx) = 0;
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed, double aValue);
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed, bool aTouched,
double aValue);
void NewAxisMove(uint32_t aIndex, uint32_t aAxis, double aValue);
void NewPoseState(uint32_t aIndex, const dom::GamepadPoseState& aPose);
void AddGamepad(const VRControllerInfo& controllerInfo);

View File

@ -493,6 +493,12 @@ VRSystemManagerOSVR::Init()
void
VRSystemManagerOSVR::Destroy()
{
Shutdown();
}
void
VRSystemManagerOSVR::Shutdown()
{
if (mOSVRInitialized) {
MOZ_ASSERT(NS_GetCurrentThread() == mOSVRThread);
@ -515,7 +521,7 @@ VRSystemManagerOSVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
// make sure context, interface and display are initialized
CheckOSVRStatus();
if (!mOSVRInitialized) {
if (!Init()) {
return;
}

View File

@ -64,8 +64,8 @@ class VRSystemManagerOSVR : public VRSystemManager
{
public:
static already_AddRefed<VRSystemManagerOSVR> Create();
virtual bool Init() override;
virtual void Destroy() override;
virtual void Shutdown() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
virtual bool GetIsPresenting() override;
virtual void HandleInput() override;
@ -89,6 +89,8 @@ protected:
{
}
bool Init();
RefPtr<impl::VRDisplayOSVR> mHMDInfo;
bool mOSVRInitialized;
bool mClientContextInitialized;

View File

@ -57,7 +57,6 @@ using namespace mozilla::dom;
namespace {
#ifdef OVR_CAPI_LIMITED_MOZILLA
static pfn_ovr_Initialize ovr_Initialize = nullptr;
static pfn_ovr_Shutdown ovr_Shutdown = nullptr;
static pfn_ovr_GetLastErrorInfo ovr_GetLastErrorInfo = nullptr;
@ -148,24 +147,40 @@ static const uint32_t kNumOculusButton = static_cast<uint32_t>
NumButtonType);
static const uint32_t kNumOculusHaptcs = 1;
static bool
InitializeOculusCAPI()
ovrFovPort
ToFovPort(const VRFieldOfView& aFOV)
{
static PRLibrary *ovrlib = nullptr;
ovrFovPort fovPort;
fovPort.LeftTan = tan(aFOV.leftDegrees * M_PI / 180.0);
fovPort.RightTan = tan(aFOV.rightDegrees * M_PI / 180.0);
fovPort.UpTan = tan(aFOV.upDegrees * M_PI / 180.0);
fovPort.DownTan = tan(aFOV.downDegrees * M_PI / 180.0);
return fovPort;
}
if (!ovrlib) {
VRFieldOfView
FromFovPort(const ovrFovPort& aFOV)
{
VRFieldOfView fovInfo;
fovInfo.leftDegrees = atan(aFOV.LeftTan) * 180.0 / M_PI;
fovInfo.rightDegrees = atan(aFOV.RightTan) * 180.0 / M_PI;
fovInfo.upDegrees = atan(aFOV.UpTan) * 180.0 / M_PI;
fovInfo.downDegrees = atan(aFOV.DownTan) * 180.0 / M_PI;
return fovInfo;
}
} // namespace
bool
VRSystemManagerOculus::LoadOvrLib()
{
if (!mOvrLib) {
nsTArray<nsCString> libSearchPaths;
nsCString libName;
nsCString searchPath;
#if defined(_WIN32)
static const char dirSep = '\\';
#else
static const char dirSep = '/';
#endif
#if defined(_WIN32)
static const int pathLen = 260;
searchPath.SetCapacity(pathLen);
int realLen = ::GetSystemDirectoryA(searchPath.BeginWriting(), pathLen);
@ -174,37 +189,9 @@ InitializeOculusCAPI()
libSearchPaths.AppendElement(searchPath);
}
libName.AppendPrintf("LibOVRRT%d_%d.dll", BUILD_BITS, OVR_PRODUCT_VERSION);
#elif defined(__APPLE__)
searchPath.Truncate();
searchPath.AppendPrintf("/Library/Frameworks/LibOVRRT_%d.framework/Versions/%d", OVR_PRODUCT_VERSION, OVR_MAJOR_VERSION);
libSearchPaths.AppendElement(searchPath);
if (PR_GetEnv("HOME")) {
searchPath.Truncate();
searchPath.AppendPrintf("%s/Library/Frameworks/LibOVRRT_%d.framework/Versions/%d", PR_GetEnv("HOME"), OVR_PRODUCT_VERSION, OVR_MAJOR_VERSION);
libSearchPaths.AppendElement(searchPath);
}
// The following will match the va_list overload of AppendPrintf if the product version is 0
// That's bad times.
//libName.AppendPrintf("LibOVRRT_%d", OVR_PRODUCT_VERSION);
libName.Append("LibOVRRT_");
libName.AppendInt(OVR_PRODUCT_VERSION);
#else
libSearchPaths.AppendElement(nsCString("/usr/local/lib"));
libSearchPaths.AppendElement(nsCString("/usr/lib"));
libName.AppendPrintf("libOVRRT%d_%d.so.%d", BUILD_BITS, OVR_PRODUCT_VERSION, OVR_MAJOR_VERSION);
#error "Unsupported platform!"
#endif
// If the pref is present, we override libName
nsAdoptingCString prefLibPath = mozilla::Preferences::GetCString("dom.vr.ovr_lib_path");
if (prefLibPath && prefLibPath.get()) {
libSearchPaths.InsertElementsAt(0, 1, prefLibPath);
}
nsAdoptingCString prefLibName = mozilla::Preferences::GetCString("dom.vr.ovr_lib_name");
if (prefLibName && prefLibName.get()) {
libName.Assign(prefLibName);
}
// search the path/module dir
libSearchPaths.InsertElementsAt(0, 1, nsCString());
@ -228,22 +215,19 @@ InitializeOculusCAPI()
fullName.AppendPrintf("%s%c%s", libPath.BeginReading(), dirSep, libName.BeginReading());
}
ovrlib = PR_LoadLibrary(fullName.BeginReading());
if (ovrlib)
mOvrLib = PR_LoadLibrary(fullName.BeginReading());
if (mOvrLib) {
break;
}
}
if (!ovrlib) {
if (!mOvrLib) {
return false;
}
}
// was it already initialized?
if (ovr_Initialize)
return true;
#define REQUIRE_FUNCTION(_x) do { \
*(void **)&_x = (void *) PR_FindSymbol(ovrlib, #_x); \
*(void **)&_x = (void *) PR_FindSymbol(mOvrLib, #_x); \
if (!_x) { printf_stderr(#_x " symbol missing\n"); goto fail; } \
} while (0)
@ -310,43 +294,20 @@ InitializeOculusCAPI()
fail:
ovr_Initialize = nullptr;
PR_UnloadLibrary(mOvrLib);
mOvrLib = nullptr;
return false;
}
#else
#include <OVR_Version.h>
// we're statically linked; it's available
static bool InitializeOculusCAPI()
void
VRSystemManagerOculus::UnloadOvrLib()
{
return true;
if (mOvrLib) {
PR_UnloadLibrary(mOvrLib);
mOvrLib = nullptr;
}
}
#endif
ovrFovPort
ToFovPort(const VRFieldOfView& aFOV)
{
ovrFovPort fovPort;
fovPort.LeftTan = tan(aFOV.leftDegrees * M_PI / 180.0);
fovPort.RightTan = tan(aFOV.rightDegrees * M_PI / 180.0);
fovPort.UpTan = tan(aFOV.upDegrees * M_PI / 180.0);
fovPort.DownTan = tan(aFOV.downDegrees * M_PI / 180.0);
return fovPort;
}
VRFieldOfView
FromFovPort(const ovrFovPort& aFOV)
{
VRFieldOfView fovInfo;
fovInfo.leftDegrees = atan(aFOV.LeftTan) * 180.0 / M_PI;
fovInfo.rightDegrees = atan(aFOV.RightTan) * 180.0 / M_PI;
fovInfo.upDegrees = atan(aFOV.UpTan) * 180.0 / M_PI;
fovInfo.downDegrees = atan(aFOV.DownTan) * 180.0 / M_PI;
return fovInfo;
}
} // namespace
VRDisplayOculus::VRDisplayOculus(ovrSession aSession)
: VRDisplayHost(VRDeviceType::Oculus)
, mSession(aSession)
@ -684,8 +645,6 @@ VRDisplayOculus::StopPresentation()
}
mIsPresenting = false;
ovr_SubmitFrame(mSession, 0, nullptr, nullptr, 0);
if (mTextureSet) {
ovr_DestroyTextureSwapChain(mSession, mTextureSet);
mTextureSet = nullptr;
@ -1108,57 +1067,67 @@ VRSystemManagerOculus::Create()
return nullptr;
}
if (!InitializeOculusCAPI()) {
return nullptr;
}
RefPtr<VRSystemManagerOculus> manager = new VRSystemManagerOculus();
return manager.forget();
}
bool
VRSystemManagerOculus::Init()
VRSystemManagerOculus::Startup()
{
if (!mOculusInitialized) {
nsIThread* thread = nullptr;
NS_GetCurrentThread(&thread);
mOculusThread = already_AddRefed<nsIThread>(thread);
ovrInitParams params;
memset(&params, 0, sizeof(params));
params.Flags = ovrInit_RequestVersion;
params.RequestedMinorVersion = OVR_MINOR_VERSION;
params.LogCallback = nullptr;
params.ConnectionTimeoutMS = 0;
ovrResult orv = ovr_Initialize(&params);
if (orv == ovrSuccess) {
mOculusInitialized = true;
}
if (mStarted) {
return true;
}
return mOculusInitialized;
if (!LoadOvrLib()) {
return false;
}
nsIThread* thread = nullptr;
NS_GetCurrentThread(&thread);
mOculusThread = already_AddRefed<nsIThread>(thread);
ovrInitParams params;
memset(&params, 0, sizeof(params));
params.Flags = ovrInit_RequestVersion;
params.RequestedMinorVersion = OVR_MINOR_VERSION;
params.LogCallback = nullptr;
params.ConnectionTimeoutMS = 0;
ovrResult orv = ovr_Initialize(&params);
if (orv == ovrSuccess) {
mStarted = true;
}
return mStarted;
}
void
VRSystemManagerOculus::Destroy()
{
if (mOculusInitialized) {
Shutdown();
}
void
VRSystemManagerOculus::Shutdown()
{
if (mStarted) {
RemoveControllers();
MOZ_ASSERT(NS_GetCurrentThread() == mOculusThread);
mOculusThread = nullptr;
mSession = nullptr;
mHMDInfo = nullptr;
ovr_Shutdown();
mOculusInitialized = false;
UnloadOvrLib();
mStarted = false;
}
}
void
VRSystemManagerOculus::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
{
if (!mOculusInitialized) {
if (!Startup()) {
return;
}
@ -1322,7 +1291,9 @@ VRSystemManagerOculus::HandleButtonPress(uint32_t aControllerIdx,
const uint64_t diff = (controller->GetButtonPressed() ^ aButtonPressed);
if (diff & aButtonMask) {
// TODO: Bug 1336003 for button touched support.
NewButtonEvent(aControllerIdx, aButton, aButtonMask & aButtonPressed,
aButtonMask & aButtonPressed,
(aButtonMask & aButtonPressed) ? 1.0L : 0.0L);
}
}
@ -1356,7 +1327,8 @@ VRSystemManagerOculus::HandleTriggerPress(uint32_t aControllerIdx, uint32_t aBut
MOZ_ASSERT(false, "We only support indexTrigger and handTrigger in Oculus.");
}
NewButtonEvent(aControllerIdx, aButton, aValue > 0.1f, aValue);
// TODO: Bug 1336003 for button touched support.
NewButtonEvent(aControllerIdx, aButton, aValue > 0.1f, aValue > 0.1f, aValue);
}
void
@ -1434,10 +1406,6 @@ void
VRSystemManagerOculus::GetControllers(nsTArray<RefPtr<VRControllerHost>>&
aControllerResult)
{
if (!mOculusInitialized) {
return;
}
aControllerResult.Clear();
for (uint32_t i = 0; i < mOculusController.Length(); ++i) {
aControllerResult.AppendElement(mOculusController[i]);

View File

@ -136,8 +136,8 @@ class VRSystemManagerOculus : public VRSystemManager
{
public:
static already_AddRefed<VRSystemManagerOculus> Create();
virtual bool Init() override;
virtual void Destroy() override;
virtual void Shutdown() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
virtual bool GetIsPresenting() override;
virtual void HandleInput() override;
@ -151,9 +151,13 @@ public:
protected:
VRSystemManagerOculus()
: mSession(nullptr), mOculusInitialized(false)
: mOvrLib(nullptr), mSession(nullptr), mStarted(false)
{ }
bool Startup();
bool LoadOvrLib();
void UnloadOvrLib();
private:
void HandleButtonPress(uint32_t aControllerIdx,
uint32_t aButton,
@ -168,12 +172,12 @@ private:
float aValue);
void HandleTouchEvent(uint32_t aControllerIdx, uint32_t aButton,
uint64_t aTouchMask, uint64_t aTouched);
PRLibrary* mOvrLib;
RefPtr<impl::VRDisplayOculus> mHMDInfo;
nsTArray<RefPtr<impl::VRControllerOculus>> mOculusController;
RefPtr<nsIThread> mOculusThread;
ovrSession mSession;
bool mOculusInitialized;
bool mStarted;
};
} // namespace gfx

View File

@ -542,7 +542,6 @@ VRControllerOpenVR::StopVibrateHaptic()
VRSystemManagerOpenVR::VRSystemManagerOpenVR()
: mVRSystem(nullptr)
, mOpenVRInstalled(false)
{
}
@ -559,43 +558,33 @@ VRSystemManagerOpenVR::Create()
return nullptr;
}
if (!vr_IsRuntimeInstalled()) {
return nullptr;
}
RefPtr<VRSystemManagerOpenVR> manager = new VRSystemManagerOpenVR();
return manager.forget();
}
bool
VRSystemManagerOpenVR::Init()
{
if (mOpenVRInstalled)
return true;
if (!vr_IsRuntimeInstalled())
return false;
mOpenVRInstalled = true;
return true;
}
void
VRSystemManagerOpenVR::Destroy()
{
if (mOpenVRInstalled) {
if (mOpenVRHMD) {
mOpenVRHMD = nullptr;
}
RemoveControllers();
mVRSystem = nullptr;
mOpenVRInstalled = false;
Shutdown();
}
void
VRSystemManagerOpenVR::Shutdown()
{
if (mOpenVRHMD) {
mOpenVRHMD = nullptr;
}
RemoveControllers();
mVRSystem = nullptr;
}
void
VRSystemManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
{
if (!mOpenVRInstalled) {
return;
}
if (!vr_IsHmdPresent()) {
if (mOpenVRHMD) {
mOpenVRHMD = nullptr;
@ -666,7 +655,9 @@ VRSystemManagerOpenVR::HandleInput()
const uint32_t trackedIndex = controller->GetTrackedIndex();
MOZ_ASSERT(mVRSystem->GetTrackedDeviceClass(trackedIndex)
== vr::TrackedDeviceClass_Controller);
== vr::TrackedDeviceClass_Controller ||
mVRSystem->GetTrackedDeviceClass(trackedIndex)
== vr::TrackedDeviceClass_GenericTracker);
if (mVRSystem->GetControllerState(trackedIndex, &state)) {
for (uint32_t j = 0; j < vr::k_unControllerStateAxisCount; ++j) {
@ -686,14 +677,14 @@ VRSystemManagerOpenVR::HandleInput()
HandleButtonPress(i, buttonIdx,
vr::ButtonMaskFromId(
static_cast<vr::EVRButtonId>(vr::k_EButton_Axis0 + j)),
state.ulButtonPressed);
state.ulButtonPressed, state.ulButtonTouched);
++buttonIdx;
break;
case vr::EVRControllerAxisType::k_eControllerAxis_Trigger:
HandleTriggerPress(i, buttonIdx,
vr::ButtonMaskFromId(
static_cast<vr::EVRButtonId>(vr::k_EButton_Axis0 + j)),
state.rAxis[j].x, state.ulButtonPressed);
state.rAxis[j].x, state.ulButtonPressed, state.ulButtonTouched);
++buttonIdx;
break;
}
@ -707,54 +698,55 @@ VRSystemManagerOpenVR::HandleInput()
BTN_MASK_FROM_ID(k_EButton_A)) {
HandleButtonPress(i, buttonIdx,
BTN_MASK_FROM_ID(k_EButton_A),
state.ulButtonPressed);
state.ulButtonPressed, state.ulButtonTouched);
++buttonIdx;
}
if (supportedButtons &
BTN_MASK_FROM_ID(k_EButton_Grip)) {
HandleButtonPress(i, buttonIdx,
BTN_MASK_FROM_ID(k_EButton_Grip),
state.ulButtonPressed);
state.ulButtonPressed, state.ulButtonTouched);
++buttonIdx;
}
if (supportedButtons &
BTN_MASK_FROM_ID(k_EButton_ApplicationMenu)) {
HandleButtonPress(i, buttonIdx,
BTN_MASK_FROM_ID(k_EButton_ApplicationMenu),
state.ulButtonPressed);
state.ulButtonPressed, state.ulButtonTouched);
++buttonIdx;
}
if (supportedButtons &
BTN_MASK_FROM_ID(k_EButton_DPad_Left)) {
HandleButtonPress(i, buttonIdx,
BTN_MASK_FROM_ID(k_EButton_DPad_Left),
state.ulButtonPressed);
state.ulButtonPressed, state.ulButtonTouched);
++buttonIdx;
}
if (supportedButtons &
BTN_MASK_FROM_ID(k_EButton_DPad_Up)) {
HandleButtonPress(i, buttonIdx,
BTN_MASK_FROM_ID(k_EButton_DPad_Up),
state.ulButtonPressed);
state.ulButtonPressed, state.ulButtonTouched);
++buttonIdx;
}
if (supportedButtons &
BTN_MASK_FROM_ID(k_EButton_DPad_Right)) {
HandleButtonPress(i, buttonIdx,
BTN_MASK_FROM_ID(k_EButton_DPad_Right),
state.ulButtonPressed);
state.ulButtonPressed, state.ulButtonTouched);
++buttonIdx;
}
if (supportedButtons &
BTN_MASK_FROM_ID(k_EButton_DPad_Down)) {
HandleButtonPress(i, buttonIdx,
BTN_MASK_FROM_ID(k_EButton_DPad_Down),
state.ulButtonPressed);
state.ulButtonPressed, state.ulButtonTouched);
++buttonIdx;
}
MOZ_ASSERT(buttonIdx ==
controller->GetControllerInfo().GetNumButtons());
controller->SetButtonPressed(state.ulButtonPressed);
controller->SetButtonTouched(state.ulButtonTouched);
// Start to process pose
const ::vr::TrackedDevicePose_t& pose = poses[trackedIndex];
@ -801,21 +793,25 @@ void
VRSystemManagerOpenVR::HandleButtonPress(uint32_t aControllerIdx,
uint32_t aButton,
uint64_t aButtonMask,
uint64_t aButtonPressed)
uint64_t aButtonPressed,
uint64_t aButtonTouched)
{
RefPtr<impl::VRControllerOpenVR> controller(mOpenVRController[aControllerIdx]);
MOZ_ASSERT(controller);
const uint64_t diff = (controller->GetButtonPressed() ^ aButtonPressed);
const uint64_t pressedDiff = (controller->GetButtonPressed() ^ aButtonPressed);
const uint64_t touchedDiff = (controller->GetButtonTouched() ^ aButtonTouched);
if (!diff) {
if (!pressedDiff && !touchedDiff) {
return;
}
if (diff & aButtonMask) {
// diff & aButtonPressed would be true while a new button press
// event, otherwise it is an old press event and needs to notify
if (pressedDiff & aButtonMask ||
touchedDiff & aButtonMask) {
// diff & (aButtonPressed, aButtonTouched) would be true while a new button pressed or
// touched event, otherwise it is an old event and needs to notify
// the button has been released.
NewButtonEvent(aControllerIdx, aButton, aButtonMask & aButtonPressed,
aButtonMask & aButtonTouched,
(aButtonMask & aButtonPressed) ? 1.0L : 0.0L);
}
}
@ -825,17 +821,21 @@ VRSystemManagerOpenVR::HandleTriggerPress(uint32_t aControllerIdx,
uint32_t aButton,
uint64_t aButtonMask,
float aValue,
uint64_t aButtonPressed)
uint64_t aButtonPressed,
uint64_t aButtonTouched)
{
RefPtr<impl::VRControllerOpenVR> controller(mOpenVRController[aControllerIdx]);
MOZ_ASSERT(controller);
const uint64_t diff = (controller->GetButtonPressed() ^ aButtonPressed);
const uint64_t pressedDiff = (controller->GetButtonPressed() ^ aButtonPressed);
const uint64_t touchedDiff = (controller->GetButtonTouched() ^ aButtonTouched);
const float oldValue = controller->GetTrigger();
// Avoid sending duplicated events in IPC channels.
if ((oldValue != aValue) ||
(diff & aButtonMask)) {
NewButtonEvent(aControllerIdx, aButton, aButtonMask & aButtonPressed, aValue);
(pressedDiff & aButtonMask) ||
(touchedDiff & aButtonMask)) {
NewButtonEvent(aControllerIdx, aButton, aButtonMask & aButtonPressed,
aButtonMask & aButtonTouched, aValue);
controller->SetTrigger(aValue);
}
}
@ -898,10 +898,6 @@ VRSystemManagerOpenVR::StopVibrateHaptic(uint32_t aControllerIdx)
void
VRSystemManagerOpenVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
{
if (!mOpenVRInstalled) {
return;
}
aControllerResult.Clear();
for (uint32_t i = 0; i < mOpenVRController.Length(); ++i) {
aControllerResult.AppendElement(mOpenVRController[i]);

View File

@ -111,8 +111,8 @@ class VRSystemManagerOpenVR : public VRSystemManager
public:
static already_AddRefed<VRSystemManagerOpenVR> Create();
virtual bool Init() override;
virtual void Destroy() override;
virtual void Shutdown() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
virtual bool GetIsPresenting() override;
virtual void HandleInput() override;
@ -134,12 +134,14 @@ private:
void HandleButtonPress(uint32_t aControllerIdx,
uint32_t aButton,
uint64_t aButtonMask,
uint64_t aButtonPressed);
uint64_t aButtonPressed,
uint64_t aButtonTouched);
void HandleTriggerPress(uint32_t aControllerIdx,
uint32_t aButton,
uint64_t aButtonMask,
float aValue,
uint64_t aButtonPressed);
uint64_t aButtonPressed,
uint64_t aButtonTouched);
void HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue);
void HandlePoseTracking(uint32_t aControllerIdx,
@ -150,7 +152,6 @@ private:
RefPtr<impl::VRDisplayOpenVR> mOpenVRHMD;
nsTArray<RefPtr<impl::VRControllerOpenVR>> mOpenVRController;
vr::IVRSystem *mVRSystem;
bool mOpenVRInstalled;
};
} // namespace gfx

View File

@ -269,6 +269,29 @@ VRControllerPuppet::GetButtonPressState()
return mButtonPressState;
}
void
VRControllerPuppet::SetButtonTouchState(uint32_t aButton, bool aTouched)
{
const uint64_t buttonMask = kPuppetButtonMask[aButton];
uint64_t touchedBit = GetButtonTouched();
if (aTouched) {
touchedBit |= kPuppetButtonMask[aButton];
} else if (touchedBit & buttonMask) {
// this button was touched but is released now.
uint64_t mask = 0xff ^ buttonMask;
touchedBit &= mask;
}
mButtonTouchState = touchedBit;
}
uint64_t
VRControllerPuppet::GetButtonTouchState()
{
return mButtonTouchState;
}
void
VRControllerPuppet::SetAxisMoveState(uint32_t aAxis, double aValue)
{
@ -323,14 +346,14 @@ VRSystemManagerPuppet::Create()
return manager.forget();
}
bool
VRSystemManagerPuppet::Init()
void
VRSystemManagerPuppet::Destroy()
{
return true;
Shutdown();
}
void
VRSystemManagerPuppet::Destroy()
VRSystemManagerPuppet::Shutdown()
{
mPuppetHMD = nullptr;
}
@ -362,7 +385,8 @@ VRSystemManagerPuppet::HandleInput()
for (uint32_t i = 0; i < mPuppetController.Length(); ++i) {
controller = mPuppetController[i];
for (uint32_t j = 0; j < kNumPuppetButtonMask; ++j) {
HandleButtonPress(i, j, kPuppetButtonMask[i], controller->GetButtonPressState());
HandleButtonPress(i, j, kPuppetButtonMask[i], controller->GetButtonPressState(),
controller->GetButtonTouchState());
}
controller->SetButtonPressed(controller->GetButtonPressState());
@ -377,21 +401,25 @@ void
VRSystemManagerPuppet::HandleButtonPress(uint32_t aControllerIdx,
uint32_t aButton,
uint64_t aButtonMask,
uint64_t aButtonPressed)
uint64_t aButtonPressed,
uint64_t aButtonTouched)
{
RefPtr<impl::VRControllerPuppet> controller(mPuppetController[aControllerIdx]);
MOZ_ASSERT(controller);
const uint64_t diff = (controller->GetButtonPressed() ^ aButtonPressed);
const uint64_t pressedDiff = (controller->GetButtonPressed() ^ aButtonPressed);
const uint64_t touchedDiff = (controller->GetButtonTouched() ^ aButtonTouched);
if (!diff) {
if (!pressedDiff && !touchedDiff) {
return;
}
if (diff & aButtonMask) {
// diff & aButtonPressed would be true while a new button press
// event, otherwise it is an old press event and needs to notify
if (pressedDiff & aButtonMask
|| touchedDiff & aButtonMask) {
// diff & (aButtonPressed, aButtonTouched) would be true while a new button pressed or
// touched event, otherwise it is an old event and needs to notify
// the button has been released.
NewButtonEvent(aControllerIdx, aButton, aButtonMask & aButtonPressed,
aButtonMask & aButtonPressed,
(aButtonMask & aButtonPressed) ? 1.0L : 0.0L);
}
}

View File

@ -62,6 +62,8 @@ public:
explicit VRControllerPuppet(dom::GamepadHand aHand);
void SetButtonPressState(uint32_t aButton, bool aPressed);
uint64_t GetButtonPressState();
void SetButtonTouchState(uint32_t aButton, bool aTouched);
uint64_t GetButtonTouchState();
void SetAxisMoveState(uint32_t aAxis, double aValue);
double GetAxisMoveState(uint32_t aAxis);
void SetPoseMoveState(const dom::GamepadPoseState& aPose);
@ -74,6 +76,7 @@ protected:
private:
uint64_t mButtonPressState;
uint64_t mButtonTouchState;
float mAxisMoveState[3];
float mAxisMove[3];
dom::GamepadPoseState mPoseState;
@ -86,8 +89,8 @@ class VRSystemManagerPuppet : public VRSystemManager
public:
static already_AddRefed<VRSystemManagerPuppet> Create();
virtual bool Init() override;
virtual void Destroy() override;
virtual void Shutdown() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
virtual bool GetIsPresenting() override;
virtual void HandleInput() override;
@ -109,7 +112,8 @@ private:
void HandleButtonPress(uint32_t aControllerIdx,
uint32_t aButton,
uint64_t aButtonMask,
uint64_t aButtonPressed);
uint64_t aButtonPressed,
uint64_t aButtonTouched);
void HandleAxisMove(uint32_t aControllerIndex, uint32_t aAxis,
float aValue);
void HandlePoseTracking(uint32_t aControllerIndex,

View File

@ -23,8 +23,6 @@
#ifndef mozilla_ovr_capi_dynamic_h_
#define mozilla_ovr_capi_dynamic_h_
#define OVR_CAPI_LIMITED_MOZILLA 1
#ifdef HAVE_64BIT_BUILD
#define OVR_PTR_SIZE 8
#define OVR_ON64(x) x

View File

@ -444,7 +444,7 @@ jit::CheckLogging()
" profiling Profiling-related information\n"
" trackopts Optimization tracking information gathered by the Gecko profiler. "
"(Note: call enableGeckoProfiling() in your script to enable it).\n"
" trackopts-ext Encoding information about optimization tracking"
" trackopts-ext Encoding information about optimization tracking\n"
" dump-mir-expr Dump the MIR expressions\n"
" cfg Control flow graph generation\n"
" all Everything\n"
@ -459,6 +459,8 @@ jit::CheckLogging()
" bl-dbg-osr Baseline debug mode on stack recompile messages\n"
" bl-all All baseline spew\n"
"\n"
" cacheir-logs CacheIR IC attach logging\n"
"\n"
);
exit(0);
/*NOTREACHED*/

View File

@ -17,6 +17,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=780847
<div id="content">
<div id="ruler" style="position:absolute; left:0; top:0; width:1mozmm; height:0;"></div>
<!-- XXX Though B2G isn't supported anymore, we probably want to keep this
test's B2G special-cases around, and just make them apply to Android.
(We may need to do so, for this test to be runnable on Android...?)
See bug 1355206 for more.
-->
<!-- the iframe holding this test is only 300px tall on B2G, so we need to
make the t target shorter than normal to test the bottom edge fluffing
-->

View File

@ -189,8 +189,7 @@ var tests = [
function() {SpecialPowers.pushPrefEnv({'clear': [['layout.accessiblecaret.enabled']]}, nextTest);} ,
];
if (navigator.appVersion.indexOf("Android") == -1 &&
SpecialPowers.Services.appinfo.name != "B2G") {
if (navigator.appVersion.indexOf("Android") == -1) {
tests.push([ 'bug512295-1.html' , 'bug512295-1-ref.html' ]);
tests.push([ 'bug512295-2.html' , 'bug512295-2-ref.html' ]);
tests.push([ 'bug923376.html' , 'bug923376-ref.html' ]);
@ -204,8 +203,7 @@ if (navigator.appVersion.indexOf("Android") == -1 &&
is(SpecialPowers.getIntPref("layout.spellcheckDefault"), 0, "Spellcheck should be turned off for this platform or this if..else check removed");
}
if (navigator.platform.indexOf("Linux") >= 0 &&
SpecialPowers.Services.appinfo.name != "B2G") {
if (navigator.platform.indexOf("Linux") >= 0) {
tests = tests.concat([
// eDirPrevious, Shift+click
[ 'multi-range-user-select.html#prev1S_' , 'multi-range-user-select-ref.html#prev1S_' ] ,

View File

@ -174,7 +174,7 @@ nsImageRenderer::PrepareImage()
case eStyleImageType_Element:
{
nsAutoString elementId =
NS_LITERAL_STRING("#") + nsDependentString(mImage->GetElementId());
NS_LITERAL_STRING("#") + nsDependentAtomString(mImage->GetElementId());
nsCOMPtr<nsIURI> targetURI;
nsCOMPtr<nsIURI> base = mForFrame->GetContent()->GetBaseURI();
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), elementId,

View File

@ -82,7 +82,7 @@ fuzzy(3,18000) fails-if(OSX) fuzzy-if(skiaContent,4,16462) == border-image-repea
== border-image-repeating-radial-gradient-repeat-round-2.html border-image-repeating-radial-gradient-repeat-round-2.html
# border-image-source (-moz-)element
fails == border-image-element.html border-image-element.html
== border-image-element.html border-image-element.html
# svg-as-border-image
fails == svg-as-border-image-1a.html svg-as-border-image-1a.html

View File

@ -1863,7 +1863,7 @@ pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1
== 1105137-1.html 1105137-1.html
== 1116480-1-fakeitalic-overflow.html 1116480-1-fakeitalic-overflow.html
skip-if(stylo) == 1111753-1.html 1111753-1.html # Bug 1302946
fails == 1114526-1.html 1114526-1.html
== 1114526-1.html 1114526-1.html
fuzzy-if(skiaContent,1,800000) == 1119117-1a.html 1119117-1a.html
fuzzy-if(skiaContent,1,800000) == 1119117-1b.html 1119117-1b.html
fails == 1120431-1.html 1120431-1.html

View File

@ -91,7 +91,7 @@ pref(layout.css.background-blend-mode.enabled,true) == background-blending-backg
pref(layout.css.background-blend-mode.enabled,true) == background-blend-mode-body-image.html background-blend-mode-body-image.html
== background-blend-mode-body-transparent-image.html background-blend-mode-body-transparent-image.html
fails pref(layout.css.background-blend-mode.enabled,true) == background-blending-moz-element.html background-blending-moz-element.html
pref(layout.css.background-blend-mode.enabled,true) == background-blending-moz-element.html background-blending-moz-element.html
fuzzy(1,40000) pref(layout.css.background-blend-mode.enabled,true) == mix-blend-mode-soft-light.html mix-blend-mode-soft-light.html

View File

@ -1,48 +1,48 @@
# DO NOT EDIT! This is a auto-generated temporary list for Stylo testing
random == bug-364968.html bug-364968.html
fails == bug-463204.html bug-463204.html
fails == canvas-outside-document.html canvas-outside-document.html
fails == mozsetimageelement-01.html mozsetimageelement-01.html
== bug-463204.html bug-463204.html
== canvas-outside-document.html canvas-outside-document.html
== mozsetimageelement-01.html mozsetimageelement-01.html
== mozsetimageelement-02.html mozsetimageelement-02.html
== image-outside-document-invalidate.html image-outside-document-invalidate.html
== canvas-outside-document-invalidate-01.html canvas-outside-document-invalidate-01.html
skip-if(stylo) == canvas-outside-document-invalidate-02.html canvas-outside-document-invalidate-02.html # Bug 1324700
#fails with Skia due to Skia bug http://code.google.com/p/skia/issues/detail?id=568
fails == element-paint-simple.html element-paint-simple.html # Bug 1341761
fails == element-paint-repeated.html element-paint-repeated.html
fails == element-paint-recursion.html element-paint-recursion.html
fails HTTP(..) == element-paint-continuation.html element-paint-continuation.html
== element-paint-simple.html element-paint-simple.html # Bug 1341761
== element-paint-repeated.html element-paint-repeated.html
== element-paint-recursion.html element-paint-recursion.html
HTTP(..) == element-paint-continuation.html element-paint-continuation.html
fails == element-paint-transform-01.html element-paint-transform-01.html
fails == element-paint-transform-02.html element-paint-transform-02.html
fails == element-paint-background-size-01.html element-paint-background-size-01.html
fails == element-paint-background-size-02.html element-paint-background-size-02.html
== element-paint-background-size-01.html element-paint-background-size-01.html
== element-paint-background-size-02.html element-paint-background-size-02.html
fails == element-paint-transform-repeated.html element-paint-transform-repeated.html
fails == element-paint-transform-03.html element-paint-transform-03.html
fails == element-paint-native-widget.html element-paint-native-widget.html
fails-if(usesRepeatResampling) == element-paint-subimage-sampling-restriction.html element-paint-subimage-sampling-restriction.html
fails == element-paint-clippath.html element-paint-clippath.html
fails == element-paint-sharpness-01a.html element-paint-sharpness-01a.html
== element-paint-clippath.html element-paint-clippath.html
== element-paint-sharpness-01a.html element-paint-sharpness-01a.html
fuzzy-if(skiaContent,1,326) == element-paint-sharpness-01b.html element-paint-sharpness-01b.html
== element-paint-sharpness-01c.html element-paint-sharpness-01c.html
fails == element-paint-sharpness-02a.html element-paint-sharpness-02a.html
fails == element-paint-sharpness-02b.html element-paint-sharpness-02b.html
fails == element-paint-paintserversize-rounding-01.html element-paint-paintserversize-rounding-01.html
fails == element-paint-paintserversize-rounding-02.html element-paint-paintserversize-rounding-02.html
fails == element-paint-multiple-backgrounds-01a.html element-paint-multiple-backgrounds-01a.html
fails == element-paint-multiple-backgrounds-01b.html element-paint-multiple-backgrounds-01b.html
fails == element-paint-multiple-backgrounds-01c.html element-paint-multiple-backgrounds-01c.html
fails == gradient-html-01.html gradient-html-01.html
fails == gradient-html-02.html gradient-html-02.html
== element-paint-sharpness-02a.html element-paint-sharpness-02a.html
== element-paint-sharpness-02b.html element-paint-sharpness-02b.html
== element-paint-paintserversize-rounding-01.html element-paint-paintserversize-rounding-01.html
== element-paint-paintserversize-rounding-02.html element-paint-paintserversize-rounding-02.html
== element-paint-multiple-backgrounds-01a.html element-paint-multiple-backgrounds-01a.html
== element-paint-multiple-backgrounds-01b.html element-paint-multiple-backgrounds-01b.html
== element-paint-multiple-backgrounds-01c.html element-paint-multiple-backgrounds-01c.html
== gradient-html-01.html gradient-html-01.html
== gradient-html-02.html gradient-html-02.html
random-if(!cocoaWidget) == gradient-html-03.html gradient-html-03.html
fails == gradient-html-04.html gradient-html-04.html
fails == gradient-html-05.html gradient-html-05.html
== gradient-html-04.html gradient-html-04.html
== gradient-html-05.html gradient-html-05.html
fuzzy(1,9674) random-if(!cocoaWidget) == gradient-html-06a.html gradient-html-06a.html
fuzzy(1,9674) random-if(!cocoaWidget) == gradient-html-06b.html gradient-html-06b.html
== gradient-html-06c.html gradient-html-06c.html
fails == gradient-html-06d.html gradient-html-06d.html
== gradient-html-06d.html gradient-html-06d.html
random-if(!cocoaWidget) fuzzy-if(cocoaWidget,2,42305) == gradient-html-07a.html gradient-html-07a.html
fails == gradient-html-07c.html gradient-html-07c.html
fails HTTP == invalidate-1.html invalidate-1.html
fails == pattern-html-01.html pattern-html-01.html
== gradient-html-07c.html gradient-html-07c.html
HTTP == invalidate-1.html invalidate-1.html
== pattern-html-01.html pattern-html-01.html
fails == pattern-html-02.html pattern-html-02.html
fails == referenced-from-binding-01.html referenced-from-binding-01.html
== referenced-from-binding-01.html referenced-from-binding-01.html

View File

@ -6,5 +6,5 @@ default-preferences pref(layout.css.filters.enabled,true)
# Some platforms render this complex filter chain a little differently, and that's ok.
== long-chain.html long-chain.html
fails == moz-element.html moz-element.html
== moz-element.html moz-element.html
== same-filter.html same-filter.html

View File

@ -987,6 +987,12 @@ Gecko_SetUrlImageValue(nsStyleImage* aImage, ServoBundledURI aURI)
aImage->SetImageRequest(req.forget());
}
void
Gecko_SetImageElement(nsStyleImage* aImage, nsIAtom* aAtom) {
MOZ_ASSERT(aImage);
aImage->SetElementId(do_AddRef(aAtom));
}
void
Gecko_CopyImageValueFrom(nsStyleImage* aImage, const nsStyleImage* aOther)
{

View File

@ -237,11 +237,11 @@ void Gecko_SetListStyleType(nsStyleList* style_struct, uint32_t type);
void Gecko_CopyListStyleTypeFrom(nsStyleList* dst, const nsStyleList* src);
// background-image style.
// TODO: support element() and -moz-image()
void Gecko_SetNullImageValue(nsStyleImage* image);
void Gecko_SetGradientImageValue(nsStyleImage* image, nsStyleGradient* gradient);
void Gecko_SetUrlImageValue(nsStyleImage* image,
ServoBundledURI uri);
void Gecko_SetImageElement(nsStyleImage* image, nsIAtom* atom);
void Gecko_CopyImageValueFrom(nsStyleImage* image, const nsStyleImage* other);
void Gecko_InitializeImageCropRect(nsStyleImage* image);

View File

@ -2293,7 +2293,8 @@ nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage,
{
nsAutoString elementId;
nsStyleUtil::AppendEscapedCSSIdent(
nsDependentString(aStyleImage.GetElementId()), elementId);
nsDependentAtomString(aStyleImage.GetElementId()),
elementId);
nsAutoString elementString = NS_LITERAL_STRING("-moz-element(#") +
elementId +
NS_LITERAL_STRING(")");

View File

@ -1389,8 +1389,11 @@ static void SetStyleImage(nsStyleContext* aStyleContext,
break;
}
case eCSSUnit_Element:
aResult.SetElementId(aValue.GetStringBufferValue());
{
nsCOMPtr<nsIAtom> atom = NS_Atomize(aValue.GetStringBufferValue());
aResult.SetElementId(atom.forget());
break;
}
case eCSSUnit_Initial:
case eCSSUnit_Unset:
case eCSSUnit_None:

View File

@ -2186,7 +2186,7 @@ nsStyleImage::DoCopy(const nsStyleImage& aOther)
} else if (aOther.mType == eStyleImageType_Gradient) {
SetGradientData(aOther.mGradient);
} else if (aOther.mType == eStyleImageType_Element) {
SetElementId(aOther.mElementId);
SetElementId(do_AddRef(aOther.mElementId));
} else if (aOther.mType == eStyleImageType_URL) {
SetURLValue(do_AddRef(aOther.mURLValue));
}
@ -2206,7 +2206,7 @@ nsStyleImage::SetNull()
} else if (mType == eStyleImageType_Image) {
NS_RELEASE(mImage);
} else if (mType == eStyleImageType_Element) {
free(mElementId);
NS_RELEASE(mElementId);
} else if (mType == eStyleImageType_URL) {
NS_RELEASE(mURLValue);
}
@ -2251,14 +2251,14 @@ nsStyleImage::SetGradientData(nsStyleGradient* aGradient)
}
void
nsStyleImage::SetElementId(const char16_t* aElementId)
nsStyleImage::SetElementId(already_AddRefed<nsIAtom> aElementId)
{
if (mType != eStyleImageType_Null) {
SetNull();
}
if (aElementId) {
mElementId = NS_strdup(aElementId);
if (nsCOMPtr<nsIAtom> atom = aElementId) {
mElementId = atom.forget().take();
mType = eStyleImageType_Element;
}
}
@ -2500,7 +2500,7 @@ nsStyleImage::operator==(const nsStyleImage& aOther) const
}
if (mType == eStyleImageType_Element) {
return NS_strcmp(mElementId, aOther.mElementId) == 0;
return mElementId == aOther.mElementId;
}
if (mType == eStyleImageType_URL) {

View File

@ -432,7 +432,7 @@ struct nsStyleImage
void SetNull();
void SetImageRequest(already_AddRefed<nsStyleImageRequest> aImage);
void SetGradientData(nsStyleGradient* aGradient);
void SetElementId(const char16_t* aElementId);
void SetElementId(already_AddRefed<nsIAtom> aElementId);
void SetCropRect(mozilla::UniquePtr<nsStyleSides> aCropRect);
void SetURLValue(already_AddRefed<URLValue> aData);
@ -458,7 +458,7 @@ struct nsStyleImage
NS_ASSERTION(mType == eStyleImageType_Gradient, "Data is not a gradient!");
return mGradient;
}
const char16_t* GetElementId() const {
const nsIAtom* GetElementId() const {
NS_ASSERTION(mType == eStyleImageType_Element, "Data is not an element!");
return mElementId;
}
@ -558,7 +558,7 @@ private:
URLValue* mURLValue; // See the comment in SetStyleImage's 'case
// eCSSUnit_URL' section to know why we need to
// store URLValues separately from mImage.
char16_t* mElementId;
nsIAtom* mElementId;
};
// This is _currently_ used only in conjunction with eStyleImageType_Image.

View File

@ -265,8 +265,6 @@ to mochitest command.
* ... `-moz-min-content` [12]
* ... `-moz-fit-content` [12]
* ... `-moz-available` [10]
* -moz-element() function for &lt;image&gt; servo/servo#15443
* test_value_storage.html `-moz-element` [49]
* -moz-anchor-decoration value on text-decoration
* test_value_storage.html `-moz-anchor-decoration` [10]
* several prefixed values in cursor property

View File

@ -0,0 +1,23 @@
diff --git a/media/libcubeb/src/cubeb_resampler.cpp b/media/libcubeb/src/cubeb_resampler.cpp
--- a/media/libcubeb/src/cubeb_resampler.cpp
+++ b/media/libcubeb/src/cubeb_resampler.cpp
@@ -50,18 +50,17 @@ passthrough_resampler<T>::passthrough_re
template<typename T>
long passthrough_resampler<T>::fill(void * input_buffer, long * input_frames_count,
void * output_buffer, long output_frames)
{
if (input_buffer) {
assert(input_frames_count);
}
- assert((input_buffer && output_buffer &&
- *input_frames_count + static_cast<int>(samples_to_frames(internal_input_buffer.length())) >= output_frames) ||
+ assert((input_buffer && output_buffer) ||
(output_buffer && !input_buffer && (!input_frames_count || *input_frames_count == 0)) ||
(input_buffer && !output_buffer && output_frames == 0));
if (input_buffer) {
if (!output_buffer) {
output_frames = *input_frames_count;
}
internal_input_buffer.push(static_cast<T*>(input_buffer),

View File

@ -54,8 +54,7 @@ long passthrough_resampler<T>::fill(void * input_buffer, long * input_frames_cou
if (input_buffer) {
assert(input_frames_count);
}
assert((input_buffer && output_buffer &&
*input_frames_count + static_cast<int>(samples_to_frames(internal_input_buffer.length())) >= output_frames) ||
assert((input_buffer && output_buffer) ||
(output_buffer && !input_buffer && (!input_frames_count || *input_frames_count == 0)) ||
(input_buffer && !output_buffer && output_frames == 0));

View File

@ -66,3 +66,6 @@ if [ -n "$rev" ]; then
else
echo "Remember to update README_MOZILLA with the version details."
fi
echo "Applying a patch on top of $rev"
patch -p3 < disable-assert.patch

View File

@ -223,6 +223,9 @@ bool WebrtcAudioConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
fractionLost,
*cumulativeLost,
*rttMs);
// Note: rrtMs is 0 when unavailable before the VoE rework. It is likely
// that after the audio moves to the new Call API that rttMs will be -1
// when unavailable.
if (!result) {
return false;
}

View File

@ -876,12 +876,7 @@ bool WebrtcVideoConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
*cumulativeLost = ind->second.rtcp_stats.cumulative_lost;
*bytesReceived = ind->second.rtp_stats.MediaPayloadBytes();
*packetsReceived = ind->second.rtp_stats.transmitted.packets;
int64_t rtt = mSendStream->GetRtt(); // TODO: BUG 1241066, mozRtt is 0 or 1
if (rtt >= 0) {
*rttMs = rtt;
} else {
*rttMs = 0;
}
int64_t rtt = mSendStream->GetRtt();
#ifdef DEBUG
if (rtt > INT32_MAX) {
CSFLogError(logTag,
@ -889,6 +884,11 @@ bool WebrtcVideoConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
" maximum size of an RTCP RTT.", __FUNCTION__, this);
}
#endif
if (rtt > 0) {
*rttMs = rtt;
} else {
*rttMs = 0;
}
// Note: timestamp is not correct per the spec... should be time the rtcp
// was received (remote) or sent (local)
*timestamp = webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();

View File

@ -267,11 +267,11 @@ EverySecondTelemetryCallback_s(nsAutoPtr<RTCStatsQueries> aQueryList) {
}
Accumulate(id, s.mJitter.Value());
}
if (s.mMozRtt.WasPassed()) {
if (s.mRoundTripTime.WasPassed()) {
MOZ_ASSERT(s.mIsRemote);
HistogramID id = isAudio ? WEBRTC_AUDIO_QUALITY_OUTBOUND_RTT :
WEBRTC_VIDEO_QUALITY_OUTBOUND_RTT;
Accumulate(id, s.mMozRtt.Value());
Accumulate(id, s.mRoundTripTime.Value());
}
if (lastInboundStats && s.mBytesReceived.WasPassed()) {
auto& laststats = *lastInboundStats;

View File

@ -3640,7 +3640,9 @@ PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
s.mPacketsReceived.Construct(packetsReceived);
s.mBytesReceived.Construct(bytesReceived);
s.mPacketsLost.Construct(packetsLost);
s.mMozRtt.Construct(rtt);
if (rtt > 0) {
s.mRoundTripTime.Construct(rtt);
}
query->report->mInboundRTPStreamStats.Value().AppendElement(s,
fallible);
}

View File

@ -8,6 +8,7 @@ package org.mozilla.gecko.widget;
import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.ViewUtils;
import android.view.View;
/**
@ -38,10 +39,13 @@ public class GridSpacingDecoration extends RecyclerView.ItemDecoration {
final GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
final int spanCount = layoutManager.getSpanCount();
final int column = position % spanCount;
// If we're RTL then column counts start from the right, but view is still LTR (i.e. offsets
// are still LTR), so compute offsets using the LTR column position (also note that this
// only works because offsets in a given column are the same for LTR and RTL layouts).
final int LTRColumn = ViewUtils.isLayoutRtl(parent) ? (spanCount - 1) - (position % spanCount) : position % spanCount;
final int columnLeftOffset = (int) (((float) column / (float) spanCount) * horizontalSpacing);
final int columnRightOffset = (int) (((float) (spanCount - (column + 1)) / (float) spanCount) * horizontalSpacing);
final int columnLeftOffset = (int) (((float) LTRColumn / (float) spanCount) * horizontalSpacing);
final int columnRightOffset = (int) (((float) (spanCount - (LTRColumn + 1)) / (float) spanCount) * horizontalSpacing);
outRect.set(columnLeftOffset, verticalPadding, columnRightOffset, verticalPadding);
}

View File

@ -176,7 +176,7 @@ public class GeckoView extends LayerView
if ("GeckoView:DOMTitleChanged".equals(event)) {
if (mContentListener != null) {
mContentListener.onTitleChanged(GeckoView.this, message.getString("title"));
mContentListener.onTitleChange(GeckoView.this, message.getString("title"));
}
} else if ("GeckoView:LocationChange".equals(event)) {
if (mNavigationListener == null) {
@ -197,7 +197,7 @@ public class GeckoView extends LayerView
}
} else if ("GeckoView:SecurityChanged".equals(event)) {
if (mProgressListener != null) {
mProgressListener.onSecurityChanged(GeckoView.this, message.getInt("status"));
mProgressListener.onSecurityChange(GeckoView.this, message.getInt("status"));
}
}
}
@ -613,7 +613,7 @@ public class GeckoView extends LayerView
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
public void onAlert(GeckoView view, String message, GeckoView.PromptResult result);
void onAlert(GeckoView view, String message, GeckoView.PromptResult result);
/**
* Tell the host application to display a confirmation dialog.
@ -622,7 +622,7 @@ public class GeckoView extends LayerView
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
public void onConfirm(GeckoView view, String message, GeckoView.PromptResult result);
void onConfirm(GeckoView view, String message, GeckoView.PromptResult result);
/**
* Tell the host application to display an input prompt dialog.
@ -632,7 +632,7 @@ public class GeckoView extends LayerView
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
public void onPrompt(GeckoView view, String message, String defaultValue, GeckoView.PromptResult result);
void onPrompt(GeckoView view, String message, String defaultValue, GeckoView.PromptResult result);
/**
* Tell the host application to display a remote debugging request dialog.
@ -640,7 +640,7 @@ public class GeckoView extends LayerView
* @param result A PromptResult used to send back the result without blocking.
* Defaults to cancel requests.
*/
public void onDebugRequest(GeckoView view, GeckoView.PromptResult result);
void onDebugRequest(GeckoView view, GeckoView.PromptResult result);
}
public interface ProgressListener {
@ -653,21 +653,21 @@ public class GeckoView extends LayerView
* @param view The GeckoView that initiated the callback.
* @param url The resource being loaded.
*/
public void onPageStart(GeckoView view, String url);
void onPageStart(GeckoView view, String url);
/**
* A View has finished loading content from the network.
* @param view The GeckoView that initiated the callback.
* @param success Whether the page loaded successfully or an error occurred.
*/
public void onPageStop(GeckoView view, boolean success);
void onPageStop(GeckoView view, boolean success);
/**
* The security status has been updated.
* @param view The GeckoView that initiated the callback.
* @param status The new security status.
*/
public void onSecurityChanged(GeckoView view, int status);
void onSecurityChange(GeckoView view, int status);
}
public interface ContentListener {
@ -677,7 +677,7 @@ public class GeckoView extends LayerView
* @param view The GeckoView that initiated the callback.
* @param title The title sent from the content.
*/
public void onTitleChanged(GeckoView view, String title);
void onTitleChange(GeckoView view, String title);
}
public interface NavigationListener {
@ -686,20 +686,20 @@ public class GeckoView extends LayerView
* @param view The GeckoView that initiated the callback.
* @param url The resource being loaded.
*/
public void onLocationChange(GeckoView view, String url);
void onLocationChange(GeckoView view, String url);
/**
* The view's ability to go back has changed.
* @param view The GeckoView that initiated the callback.
* @param canGoBack The new value for the ability.
*/
public void onCanGoBack(GeckoView view, boolean canGoBack);
void onCanGoBack(GeckoView view, boolean canGoBack);
/**
* The view's ability to go forward has changed.
* @param view The GeckoView that initiated the callback.
* @param canGoForward The new value for the ability.
*/
public void onCanGoForward(GeckoView view, boolean canGoForward);
void onCanGoForward(GeckoView view, boolean canGoForward);
}
}

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