This commit is contained in:
Ryan VanderMeulen 2015-08-24 20:37:14 -04:00
Родитель 7d4906ba75 ad4abd6428
Коммит 125759fa69
690 изменённых файлов: 13127 добавлений и 3547 удалений

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

@ -32,9 +32,9 @@ let principaluri = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService).
newURI(PSEUDOURI, null, null);
let principal = Cc["@mozilla.org/scriptsecuritymanager;1"].
getService(Ci.nsIScriptSecurityManager).
getCodebasePrincipal(principaluri);
let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let principal = ssm.createCodebasePrincipal(principaluri, {});
function toArray(args) {
return Array.prototype.slice.call(args);

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

@ -154,11 +154,10 @@ this.AboutServiceWorkers = {
return;
}
let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(
let principal = Services.scriptSecurityManager.createCodebasePrincipal(
// TODO: Bug 1196652. use originNoSuffix
Services.io.newURI(message.principal.origin, null, null),
message.principal.originAttributes.appId,
message.principal.originAttributes.inBrowser
);
message.principal.originAttributes);
if (!message.scope) {
self.sendError(message.id, "MissingScope");

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

@ -205,9 +205,9 @@ ContentPermissionPrompt.prototype = {
// URL.
let notDenyAppPrincipal = function(type) {
let url = Services.io.newURI(app.origin, null, null);
let principal = secMan.getAppCodebasePrincipal(url,
request.principal.appId,
/*mozbrowser*/false);
let principal =
secMan.createCodebasePrincipal(url,
{appId: request.principal.appId});
let result = Services.perms.testExactPermissionFromPrincipal(principal,
type.access);

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

@ -55,7 +55,8 @@
// the error message.
if (!config.origin) {
let URI = Services.io.newURI(url, null, null);
config.origin = Services.scriptSecurityManager.getNoAppCodebasePrincipal(URI).origin;
config.origin =
Services.scriptSecurityManager.createCodebasePrincipal(URI, {}).origin;
}
switch (mode) {

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

@ -11,7 +11,7 @@ const URL = "http://mochi.test:8888/browser/browser/base/content/test/general/of
registerCleanupFunction(function() {
// Clean up after ourself
let uri = Services.io.newURI(URL, null, null);
var principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
Services.perms.removeFromPrincipal(principal, "offline-app");
Services.prefs.clearUserPref("offline-apps.quota.warn");
Services.prefs.clearUserPref("offline-apps.allow_by_default");

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

@ -564,7 +564,7 @@ var gAllTests = [
var sm = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
var principal = sm.getNoAppCodebasePrincipal(URI);
var principal = sm.createCodebasePrincipal(URI, {});
// Give www.example.com privileges to store offline data
var pm = Cc["@mozilla.org/permissionmanager;1"]
@ -634,7 +634,7 @@ var gAllTests = [
var sm = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
var principal = sm.getNoAppCodebasePrincipal(URI);
var principal = sm.createCodebasePrincipal(URI, {});
// Open the dialog
let wh = new WindowHelper();

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

@ -43,12 +43,10 @@ window.addEventListener("message", function(event) {
var uri1 = ioService.newURI(frames.testFrame.location, null, null);
var uri2 = ioService.newURI(frames.testFrame3.location, null, null);
var principal1 = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(SpecialPowers.Ci.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri1);
var principal2 = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(SpecialPowers.Ci.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri2);
var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(SpecialPowers.Ci.nsIScriptSecurityManager);
var principal1 = ssm.createCodebasePrincipal(uri1, {});
var principal2 = ssm.createCodebasePrincipal(uri2, {});
pm.removeFromPrincipal(principal1, "offline-app");
pm.removeFromPrincipal(principal2, "offline-app");

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

@ -39,9 +39,9 @@ function finishTest() {
var uri = Cc["@mozilla.org/network/io-service;1"].getService(SpecialPowers.Ci.nsIIOService)
.newURI(window.frames[0].location, null, null);
var principal = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(SpecialPowers.Ci.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(SpecialPowers.Ci.nsIScriptSecurityManager);
var principal = ssm.createCodebasePrincipal(uri, {});
pm.removeFromPrincipal(principal, "offline-app");

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

@ -18,7 +18,7 @@ Cu.import("resource://gre/modules/Timer.jsm", tmp);
let {Promise, NewTabUtils, Sanitizer, clearTimeout, setTimeout, DirectoryLinksProvider, PlacesTestUtils} = tmp;
let uri = Services.io.newURI("about:newtab", null, null);
let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
let isMac = ("nsILocalFileMac" in Ci);
let isLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc);

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

@ -254,7 +254,7 @@ FeedConverter.prototype = {
chromeChannel = ios.newChannelFromURIWithLoadInfo(aboutFeedsURI, loadInfo);
chromeChannel.originalURI = result.uri;
chromeChannel.owner =
Services.scriptSecurityManager.getNoAppCodebasePrincipal(aboutFeedsURI);
Services.scriptSecurityManager.createCodebasePrincipal(aboutFeedsURI, {});
} else {
chromeChannel = ios.newChannelFromURIWithLoadInfo(result.uri, loadInfo);
}

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

@ -497,7 +497,7 @@ let AboutPermissions = {
while (row = aResults.getNextRow()) {
let spec = row.getResultByName("url");
let uri = NetUtil.newURI(spec);
let principal = gSecMan.getNoAppCodebasePrincipal(uri);
let principal = gSecMan.createCodebasePrincipal(uri, {});
AboutPermissions.addPrincipal(principal);
}
@ -548,7 +548,7 @@ let AboutPermissions = {
try {
// aLogin.hostname is a string in origin URL format (e.g. "http://foo.com")
let uri = NetUtil.newURI(aLogin.hostname);
let principal = gSecMan.getNoAppCodebasePrincipal(uri);
let principal = gSecMan.createCodebasePrincipal(uri, {});
this.addPrincipal(principal);
} catch (e) {
// newURI will throw for add-ons logins stored in chrome:// URIs
@ -564,7 +564,7 @@ let AboutPermissions = {
try {
// aHostname is a string in origin URL format (e.g. "http://foo.com")
let uri = NetUtil.newURI(aHostname);
let principal = gSecMan.getNoAppCodebasePrincipal(uri);
let principal = gSecMan.createCodebasePrincipal(uri, {});
this.addPrincipal(principal);
} catch (e) {
// newURI will throw for add-ons logins stored in chrome:// URIs

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

@ -95,12 +95,12 @@ var gPermissionManager = {
let uri;
try {
uri = Services.io.newURI(input_url, null, null);
principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
// If we have ended up with an unknown scheme, the following will throw.
principal.origin;
} catch(ex) {
uri = Services.io.newURI("http://" + input_url, null, null);
principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
// If we have ended up with an unknown scheme, the following will throw.
principal.origin;
}

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

@ -8,8 +8,10 @@ const ABOUT_PERMISSIONS_SPEC = "about:permissions";
const TEST_URI_1 = NetUtil.newURI("http://mozilla.com/");
const TEST_URI_2 = NetUtil.newURI("http://mozilla.org/");
const TEST_PRINCIPAL_1 = Services.scriptSecurityManager.getNoAppCodebasePrincipal(TEST_URI_1);
const TEST_PRINCIPAL_2 = Services.scriptSecurityManager.getNoAppCodebasePrincipal(TEST_URI_2);
const TEST_PRINCIPAL_1 =
Services.scriptSecurityManager.createCodebasePrincipal(TEST_URI_1, {});
const TEST_PRINCIPAL_2 =
Services.scriptSecurityManager.createCodebasePrincipal(TEST_URI_2, {});
// values from DefaultPermissions object
const PERM_UNKNOWN = 0;

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

@ -15,9 +15,9 @@ const TEST_URI_XUL = TEST_URL_ROOT + "doc_content_stylesheet.xul";
const XUL_URI = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newURI(TEST_URI_XUL, null, null);
const XUL_PRINCIPAL = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(XUL_URI);
let ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
const XUL_PRINCIPAL = ssm.createCodebasePrincipal(XUL_URI, {});
add_task(function*() {
info("Checking stylesheets on HTML document");

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

@ -995,14 +995,21 @@ PdfStreamConverter.prototype = {
// We can use resource principal when data is fetched by the chrome
// e.g. useful for NoScript
var securityManager = Cc['@mozilla.org/scriptsecuritymanager;1']
.getService(Ci.nsIScriptSecurityManager);
var ssm = Cc['@mozilla.org/scriptsecuritymanager;1']
.getService(Ci.nsIScriptSecurityManager);
var uri = NetUtil.newURI(PDF_VIEWER_WEB_PAGE, null, null);
// FF16 and below had getCodebasePrincipal, it was replaced by
// getNoAppCodebasePrincipal (bug 758258).
var resourcePrincipal = 'getNoAppCodebasePrincipal' in securityManager ?
securityManager.getNoAppCodebasePrincipal(uri) :
securityManager.getCodebasePrincipal(uri);
// FF 43 added createCodebasePrincipal to replace getNoAppCodebasePrincipal
// (bug 1165272).
var resourcePrincipal
if ('createCodebasePrincipal' in ssm) {
resourcePrincipal = ssm.createCodebasePrincipal(uri, {});
} else if ('getNoAppCodebasePrincipal' in ssm) {
resourcePrincipal = ssm.getNoAppCodebasePrincipal(uri)
} else {
resourcePrincipal = ssm.getCodebasePrincipal(uri);
}
aRequest.owner = resourcePrincipal;
channel.asyncOpen(proxy, aContext);
},

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

@ -22,9 +22,9 @@ var SpecialStorageUtils = {
createWrappedSpecialStorage: function (sandbox, swfUrl, privateBrowsing) {
// Creating internal localStorage object based on url and privateBrowsing setting.
var uri = Services.io.newURI(swfUrl, null, null);
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
var ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager);
var principal = ssm.createCodebasePrincipal(uri, {});
var dsm = Components.classes["@mozilla.org/dom/localStorage-manager;1"]
.getService(Components.interfaces.nsIDOMStorageManager);
var storage = dsm.createStorage(null, principal, privateBrowsing);

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

@ -66,7 +66,8 @@ this.Feeds = {
if (aIsFeed) {
// re-create the principal as it may be a CPOW.
let principalURI = BrowserUtils.makeURIFromCPOW(aPrincipal.URI);
let principalToCheck = Services.scriptSecurityManager.getNoAppCodebasePrincipal(principalURI);
let principalToCheck =
Services.scriptSecurityManager.createCodebasePrincipal(principalURI, {});
try {
BrowserUtils.urlSecurityCheck(aLink.href, principalToCheck,
Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);

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

@ -19,22 +19,6 @@ MOZ_ARG_WITH_BOOL(system-icu,
if test -n "$MOZ_NATIVE_ICU"; then
PKG_CHECK_MODULES(MOZ_ICU, icu-i18n >= 50.1)
MOZ_SHARED_ICU=1
elif test -n "$gonkdir" && test "$ANDROID_VERSION" -ge 18; then
dnl Use system's ICU since version is 50.1+.
if test -d "$gonkdir/external/icu/icu4c/source"; then
dnl gonk-L (API version is 21)
MOZ_ICU_GONK_PATH="$gonkdir/external/icu/icu4c/source"
elif test -d "$gonkdir/external/icu4c"; then
MOZ_ICU_GONK_PATH="$gonkdir/external/icu4c"
else
AC_MSG_ERROR([Cannot find ICU source code under gonk])
fi
MOZ_ICU_CFLAGS="-I$MOZ_ICU_GONK_PATH/common -I$MOZ_ICU_GONK_PATH/i18n"
dnl icudata is a datafile under /usr/icu/icudt<version number>l.dat,
dnl not shared library. So we don't link to icudata on B2G.
MOZ_ICU_LIBS='-licui18n -licuuc'
MOZ_NATIVE_ICU=1
MOZ_SHARED_ICU=1
else
MOZ_ICU_CFLAGS='-I$(topsrcdir)/intl/icu/source/common -I$(topsrcdir)/intl/icu/source/i18n'
AC_SUBST_LIST(MOZ_ICU_CFLAGS)

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

@ -56,14 +56,15 @@ if __name__ == '__main__':
parser.add_argument("--partial-mar-file", required=False,
action="store", dest="partial_mar_file",
help="Path to the partial MAR file, relative to the objdir.")
parser.add_argument("--upload-properties", required=True,
parser.add_argument("--upload-properties", required=False,
action="store", dest="upload_properties",
help="Path to the properties written by 'make upload'")
args = parser.parse_args()
json_data = getMarProperties(args.complete_mar_file)
with open(args.upload_properties) as f:
json_data.update(json.load(f))
if args.upload_properties:
with open(args.upload_properties) as f:
json_data.update(json.load(f))
if args.partial_mar_file:
json_data.update(getMarProperties(args.partial_mar_file, partial=True))

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

@ -17,8 +17,10 @@ include $(topsrcdir)/toolkit/mozapps/installer/upload-files.mk
# Clear out DIST_FILES if it was set by upload-files.mk (for Android builds)
DIST_FILES =
ifeq (1,$(MOZ_AUTOMATION_UPLOAD))
# Properties from 'make upload' that are file URLs.
AUTOMATION_UPLOAD_PROPERTIES = $(DIST)/upload-properties.json
AUTOMATION_UPLOAD_PROPERTIES = --upload-properties $(DIST)/upload-properties.json
endif
# Helper variables to convert from MOZ_AUTOMATION_* variables to the
# corresponding the make target
@ -98,7 +100,7 @@ automation/l10n-check: automation/pretty-l10n-check
automation/update-packaging: automation/pretty-update-packaging
automation/build: $(addprefix automation/,$(MOZ_AUTOMATION_TIERS))
$(PYTHON) $(topsrcdir)/build/gen_mach_buildprops.py --complete-mar-file $(DIST)/$(COMPLETE_MAR) $(addprefix --partial-mar-file ,$(wildcard $(DIST)/$(PARTIAL_MAR))) --upload-properties $(AUTOMATION_UPLOAD_PROPERTIES)
$(PYTHON) $(topsrcdir)/build/gen_mach_buildprops.py --complete-mar-file $(DIST)/$(COMPLETE_MAR) $(addprefix --partial-mar-file ,$(wildcard $(DIST)/$(PARTIAL_MAR))) $(AUTOMATION_UPLOAD_PROPERTIES)
# Note: We have to force -j1 here, at least until bug 1036563 is fixed.
AUTOMATION_EXTRA_CMDLINE-l10n-check = -j1

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

@ -26,7 +26,7 @@ class DomainPolicyClone;
[ptr] native JSObjectPtr(JSObject);
[ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone);
[scriptable, uuid(9a8f0b70-6b9f-4e19-8885-7cfe24f4a42d)]
[scriptable, uuid(6e8a4d1e-d9c6-4d86-bf53-d73f58f36148)]
interface nsIScriptSecurityManager : nsISupports
{
/**
@ -150,10 +150,12 @@ interface nsIScriptSecurityManager : nsISupports
* @param appId is the app id of the principal. It can't be UNKNOWN_APP_ID.
* @param inMozBrowser is true if the principal has to be considered as
* inside a mozbrowser frame.
*
* @deprecated use createCodebasePrincipal instead.
*/
nsIPrincipal getAppCodebasePrincipal(in nsIURI uri,
in unsigned long appId,
in boolean inMozBrowser);
[deprecated] nsIPrincipal getAppCodebasePrincipal(in nsIURI uri,
in unsigned long appId,
in boolean inMozBrowser);
/**
* Returns a principal that has the appId and inMozBrowser of the load
@ -175,8 +177,10 @@ interface nsIScriptSecurityManager : nsISupports
* Returns a principal with that has the same origin as uri and is not part
* of an appliction.
* The returned principal will have appId = NO_APP_ID.
*
* @deprecated use createCodebasePrincipal instead.
*/
nsIPrincipal getNoAppCodebasePrincipal(in nsIURI uri);
[deprecated] nsIPrincipal getNoAppCodebasePrincipal(in nsIURI uri);
/**
* Legacy method for getting a principal with no origin attributes.

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

@ -78,6 +78,7 @@ included_inclnames_to_ignore = set([
'selfhosted.out.h', # generated in $OBJDIR
'unicode/locid.h', # ICU
'unicode/numsys.h', # ICU
'unicode/timezone.h', # ICU
'unicode/ucal.h', # ICU
'unicode/uclean.h', # ICU
'unicode/ucol.h', # ICU

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

@ -11,6 +11,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/Casting.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/Element.h"
@ -9360,9 +9361,6 @@ nsDocShell::CreatePrincipalFromReferrer(nsIURI* aReferrer,
nsIPrincipal** aResult)
{
nsresult rv;
nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t appId;
rv = GetAppId(&appId);
@ -9370,12 +9368,14 @@ nsDocShell::CreatePrincipalFromReferrer(nsIURI* aReferrer,
bool isInBrowserElement;
rv = GetIsInBrowserElement(&isInBrowserElement);
NS_ENSURE_SUCCESS(rv, rv);
rv = secMan->GetAppCodebasePrincipal(aReferrer,
appId,
isInBrowserElement,
aResult);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
// TODO: Bug 1165466 - Pass mOriginAttributes directly.
OriginAttributes attrs(appId, isInBrowserElement);
nsCOMPtr<nsIPrincipal> prin =
BasePrincipal::CreateCodebasePrincipal(aReferrer, attrs);
prin.forget(aResult);
return *aResult ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP

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

@ -73,11 +73,9 @@ mozIApplication.prototype = {
this._principal = null;
try {
this._principal = Services.scriptSecurityManager.getAppCodebasePrincipal(
this._principal = Services.scriptSecurityManager.createCodebasePrincipal(
Services.io.newURI(this.origin, null, null),
this.localId,
false /* mozbrowser */
);
{appId: this.localId});
} catch(e) {
dump("Could not create app principal " + e + "\n");
}

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

@ -228,8 +228,8 @@ function installCache(app) {
if (!cacheManifest.exists())
return;
let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(
app.origin, app.localId, false);
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(app.origin, {appId: aApp.localId});
// If the build has been correctly configured, this should not happen!
// If we install the cache anyway, it won't be updateable. If we don't install

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

@ -40,7 +40,7 @@ this.ScriptPreloader = {
let toLoad = aManifest.precompile.length;
let principal =
Services.scriptSecurityManager
.getAppCodebasePrincipal(origin, aApp.localId, false);
.createCodebasePrincipal(origin, {appId: aApp.localId});
aManifest.precompile.forEach((aPath) => {
let uri = Services.io.newURI(aPath, null, origin);

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

@ -820,8 +820,7 @@ this.DOMApplicationRegistry = {
let uri = Services.io.newURI(aOrigin, null, null);
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let principal = secMan.getAppCodebasePrincipal(uri, aId,
/*mozbrowser*/ false);
let principal = secMan.createCodebasePrincipal(uri, {appId: aId});
if (!dataStoreService.checkPermission(principal)) {
return;
}
@ -3361,8 +3360,9 @@ this.DOMApplicationRegistry = {
let requestChannel;
let appURI = NetUtil.newURI(aNewApp.origin, null, null);
let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(
appURI, aNewApp.localId, false);
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(appURI,
{appId: aNewApp.localId});
if (aIsLocalFileInstall) {
requestChannel = NetUtil.newChannel({

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

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gfxPrefs.h"
#include "mozilla/EventForwards.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/TextEvents.h"
@ -284,8 +285,11 @@ TextInputProcessor::MaybeDispatchKeydownForComposition(
return result;
}
uint32_t consumedFlags = 0;
result.mResult = KeydownInternal(*aKeyboardEvent, aKeyFlags, false,
result.mDoDefault);
consumedFlags);
result.mDoDefault = !consumedFlags;
if (NS_WARN_IF(NS_FAILED(result.mResult))) {
result.mCanContinue = false;
return result;
@ -754,9 +758,9 @@ NS_IMETHODIMP
TextInputProcessor::Keydown(nsIDOMKeyEvent* aDOMKeyEvent,
uint32_t aKeyFlags,
uint8_t aOptionalArgc,
bool* aDoDefault)
uint32_t* aConsumedFlags)
{
MOZ_RELEASE_ASSERT(aDoDefault, "aDoDefault must not be nullptr");
MOZ_RELEASE_ASSERT(aConsumedFlags, "aConsumedFlags must not be nullptr");
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
if (!aOptionalArgc) {
aKeyFlags = 0;
@ -769,16 +773,33 @@ TextInputProcessor::Keydown(nsIDOMKeyEvent* aDOMKeyEvent,
if (NS_WARN_IF(!originalKeyEvent)) {
return NS_ERROR_INVALID_ARG;
}
return KeydownInternal(*originalKeyEvent, aKeyFlags, true, *aDoDefault);
return KeydownInternal(*originalKeyEvent, aKeyFlags, true, *aConsumedFlags);
}
TextEventDispatcher::DispatchTo
TextInputProcessor::GetDispatchTo() const
{
// Support asynchronous tests.
if (mForTests) {
return gfxPrefs::TestEventsAsyncEnabled() ?
TextEventDispatcher::eDispatchToParentProcess :
TextEventDispatcher::eDispatchToCurrentProcess;
}
// Otherwise, TextInputProcessor supports only keyboard apps on B2G.
// Keyboard apps on B2G doesn't want to dispatch keyboard events to
// chrome process. Therefore, this should dispatch key events only in
// the current process.
return TextEventDispatcher::eDispatchToCurrentProcess;
}
nsresult
TextInputProcessor::KeydownInternal(const WidgetKeyboardEvent& aKeyboardEvent,
uint32_t aKeyFlags,
bool aAllowToDispatchKeypress,
bool& aDoDefault)
uint32_t& aConsumedFlags)
{
aDoDefault = false;
aConsumedFlags = KEYEVENT_NOT_CONSUMED;
// We shouldn't modify the internal WidgetKeyboardEvent.
WidgetKeyboardEvent keyEvent(aKeyboardEvent);
@ -787,7 +808,8 @@ TextInputProcessor::KeydownInternal(const WidgetKeyboardEvent& aKeyboardEvent,
return rv;
}
aDoDefault = !(aKeyFlags & KEY_DEFAULT_PREVENTED);
aConsumedFlags = (aKeyFlags & KEY_DEFAULT_PREVENTED) ? KEYDOWN_IS_CONSUMED :
KEYEVENT_NOT_CONSUMED;
if (WidgetKeyboardEvent::GetModifierForKeyName(keyEvent.mKeyNameIndex)) {
ModifierKeyData modifierKeyData(keyEvent);
@ -814,19 +836,27 @@ TextInputProcessor::KeydownInternal(const WidgetKeyboardEvent& aKeyboardEvent,
return rv;
}
nsEventStatus status = aDoDefault ? nsEventStatus_eIgnore :
nsEventStatus_eConsumeNoDefault;
if (!mDispatcher->DispatchKeyboardEvent(NS_KEY_DOWN, keyEvent, status)) {
nsEventStatus status = aConsumedFlags ? nsEventStatus_eConsumeNoDefault :
nsEventStatus_eIgnore;
if (!mDispatcher->DispatchKeyboardEvent(NS_KEY_DOWN, keyEvent, status,
GetDispatchTo())) {
// If keydown event isn't dispatched, we don't need to dispatch keypress
// events.
return NS_OK;
}
if (aAllowToDispatchKeypress) {
mDispatcher->MaybeDispatchKeypressEvents(keyEvent, status);
aConsumedFlags |=
(status == nsEventStatus_eConsumeNoDefault) ? KEYDOWN_IS_CONSUMED :
KEYEVENT_NOT_CONSUMED;
if (aAllowToDispatchKeypress &&
mDispatcher->MaybeDispatchKeypressEvents(keyEvent, status,
GetDispatchTo())) {
aConsumedFlags |=
(status == nsEventStatus_eConsumeNoDefault) ? KEYPRESS_IS_CONSUMED :
KEYEVENT_NOT_CONSUMED;
}
aDoDefault = (status != nsEventStatus_eConsumeNoDefault);
return NS_OK;
}
@ -890,7 +920,8 @@ TextInputProcessor::KeyupInternal(const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus status = aDoDefault ? nsEventStatus_eIgnore :
nsEventStatus_eConsumeNoDefault;
mDispatcher->DispatchKeyboardEvent(NS_KEY_UP, keyEvent, status);
mDispatcher->DispatchKeyboardEvent(NS_KEY_UP, keyEvent, status,
GetDispatchTo());
aDoDefault = (status != nsEventStatus_eConsumeNoDefault);
return NS_OK;
}

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

@ -9,6 +9,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/TextEventDispatcherListener.h"
#include "nsAutoPtr.h"
#include "nsITextInputProcessor.h"
@ -17,10 +18,6 @@
namespace mozilla {
namespace widget{
class TextEventDispatcher;
} // namespace widget
class TextInputProcessor final : public nsITextInputProcessor
, public widget::TextEventDispatcherListener
{
@ -60,10 +57,11 @@ private:
nsresult KeydownInternal(const WidgetKeyboardEvent& aKeyboardEvent,
uint32_t aKeyFlags,
bool aAllowToDispatchKeypress,
bool& aDoDefault);
uint32_t& aConsumedFlags);
nsresult KeyupInternal(const WidgetKeyboardEvent& aKeyboardEvent,
uint32_t aKeyFlags,
bool& aDoDefault);
TextEventDispatcher::DispatchTo GetDispatchTo() const;
nsresult IsValidStateForComposition();
void UnlinkFromTextEventDispatcher();
nsresult PrepareKeyboardEventToDispatch(WidgetKeyboardEvent& aKeyboardEvent,

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

@ -7904,8 +7904,12 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
nsPIDOMWindow* win = GetWindow();
if (win && win->IsDesktopModeViewport())
{
return nsViewportInfo(aDisplaySize,
defaultScale,
float viewportWidth = gfxPrefs::DesktopViewportWidth() / fullZoom;
float scaleToFit = aDisplaySize.width / viewportWidth;
float aspectRatio = (float)aDisplaySize.height / aDisplaySize.width;
ScreenSize viewportSize(viewportWidth, viewportWidth * aspectRatio);
return nsViewportInfo(RoundedToInt(viewportSize),
CSSToScreenScale(scaleToFit),
/*allowZoom*/false,
/*allowDoubleTapZoom*/ false);
}
@ -8060,8 +8064,7 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
// Stretch CSS pixel size of viewport to keep device pixel size
// unchanged after full zoom applied.
// See bug 974242.
size.width = Preferences::GetInt("browser.viewport.desktopWidth",
kViewportDefaultScreenWidth) / fullZoom;
size.width = gfxPrefs::DesktopViewportWidth() / fullZoom;
}
}

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

@ -95,7 +95,6 @@
#include "nsThreadUtils.h"
#include "nsILoadContext.h"
#include "nsIPresShell.h"
#include "nsIScriptSecurityManager.h"
#include "nsIScrollableFrame.h"
#include "nsView.h"
#include "nsViewManager.h"
@ -192,6 +191,7 @@
#include "nsRefreshDriver.h"
#include "mozilla/AddonPathService.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/Services.h"
#include "mozilla/Telemetry.h"
#include "nsLocation.h"
@ -256,6 +256,8 @@ static const char kStorageEnabled[] = "dom.storage.enabled";
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
using mozilla::BasePrincipal;
using mozilla::OriginAttributes;
using mozilla::TimeStamp;
using mozilla::TimeDuration;
using mozilla::dom::cache::CacheStorage;
@ -6524,7 +6526,15 @@ nsGlobalWindow::SetFullscreenInternal(FullscreenReason aReason,
// consequential calls to this method, those calls will be skipped
// at the condition above.
if (aReason == eForFullscreenMode) {
mFullscreenMode = aFullScreen;
if (!aFullScreen && !mFullscreenMode) {
// If we are exiting fullscreen mode, but we actually didn't
// entered fullscreen mode, the fullscreen state was only for
// the Fullscreen API. Change the reason here so that we can
// perform transition for it.
aReason = eForFullscreenAPI;
} else {
mFullscreenMode = aFullScreen;
}
} else {
// If we are exiting from DOM fullscreen while we initially make
// the window fullscreen because of fullscreen mode, don't restore
@ -8579,21 +8589,14 @@ nsGlobalWindow::PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessa
return;
}
nsCOMPtr<nsIScriptSecurityManager> ssm =
nsContentUtils::GetSecurityManager();
MOZ_ASSERT(ssm);
nsCOMPtr<nsIPrincipal> principal = nsContentUtils::SubjectPrincipal();
MOZ_ASSERT(principal);
uint32_t appId = principal->GetAppId();
bool isInBrowser = principal->GetIsInBrowserElement();
OriginAttributes attrs = BasePrincipal::Cast(principal)->OriginAttributesRef();
// Create a nsIPrincipal inheriting the app/browser attributes from the
// caller.
nsresult rv = ssm->GetAppCodebasePrincipal(originURI, appId, isInBrowser,
getter_AddRefs(providedPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
providedPrincipal = BasePrincipal::CreateCodebasePrincipal(originURI, attrs);
if (NS_WARN_IF(!providedPrincipal)) {
return;
}
}

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

@ -307,6 +307,12 @@ nsJSUtils::GetScopeChainForElement(JSContext* aCx,
return true;
}
/* static */
void
nsJSUtils::ResetTimeZone()
{
JS::ResetTimeZone();
}
//
// nsDOMJSUtils.h

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

@ -113,6 +113,9 @@ public:
static bool GetScopeChainForElement(JSContext* aCx,
mozilla::dom::Element* aElement,
JS::AutoObjectVector& aScopeChain);
static void ResetTimeZone();
private:
// Implementation for our EvaluateString bits
static nsresult EvaluateString(JSContext* aCx,

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

@ -16,7 +16,6 @@ static const mozilla::LayoutDeviceToScreenScale kViewportMinScale(0.0f);
static const mozilla::LayoutDeviceToScreenScale kViewportMaxScale(10.0f);
static const mozilla::CSSIntSize kViewportMinSize(200, 40);
static const mozilla::CSSIntSize kViewportMaxSize(10000, 10000);
static const int32_t kViewportDefaultScreenWidth = 980;
/**
* Information retrieved from the <meta name="viewport"> tag. See

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

@ -15,7 +15,7 @@
src="data:text/html,&lt;textarea id='textarea' cols='20' rows='4'&gt;&lt;/textarea&gt;"></iframe><br/>
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
@ -2340,8 +2340,8 @@ function runKeyTests()
reset();
var doDefaultKeydown = TIP.keydown(keyA);
ok(!doDefaultKeydown,
description + "TIP.keydown(keyA) should return false because the keypress event should be consumed by the input element");
is(doDefaultKeydown, TIP.KEYPRESS_IS_CONSUMED,
description + "TIP.keydown(keyA) should return 0x02 because the keypress event should be consumed by the input element");
is(events.length, 2,
description + "TIP.keydown(keyA) should cause keydown and keypress event");
checkKeyAttrs("TIP.keydown(keyA)", events[0],
@ -2371,8 +2371,8 @@ function runKeyTests()
reset();
doDefaultKeydown = TIP.keydown(keyEnter);
ok(doDefaultKeydown,
description + "TIP.keydown(keyEnter) should return true");
is(doDefaultKeydown, 0,
description + "TIP.keydown(keyEnter) should return 0");
is(events.length, 2,
description + "TIP.keydown(keyEnter) should cause keydown and keypress event");
checkKeyAttrs("TIP.keydown(keyEnter)", events[0],
@ -2402,8 +2402,8 @@ function runKeyTests()
doDefaultKeydown = TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED);
doDefaultKeyup = TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED);
ok(!doDefaultKeydown,
description + "TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED) should return false because it's marked as consumed at dispatching the event");
is(doDefaultKeydown, TIP.KEYDOWN_IS_CONSUMED,
description + "TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED) should return 0x01 because it's marked as consumed at dispatching the event");
ok(!doDefaultKeyup,
description + "TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED) should return false because it's marked as consumed at dispatching the event");
is(events.length, 2,
@ -2423,7 +2423,7 @@ function runKeyTests()
doDefaultKeydown = TIP.keydown(keyABC);
doDefaultKeyup = TIP.keyup(keyABC);
ok(!doDefaultKeydown,
is(doDefaultKeydown, TIP.KEYPRESS_IS_CONSUMED,
description + "TIP.keydown(keyABC) should return false because the keypress events should be consumed by the input element");
ok(doDefaultKeyup,
description + "TIP.keyup(keyABC) should return true");
@ -2450,8 +2450,8 @@ function runKeyTests()
doDefaultKeydown = TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY);
doDefaultKeyup = TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY);
ok(!doDefaultKeydown,
description + "TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) should return false because the keypress events should be consumed by the input element");
is(doDefaultKeydown, TIP.KEYPRESS_IS_CONSUMED,
description + "TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) should return 0x02 because the keypress events should be consumed by the input element");
ok(doDefaultKeyup,
description + "TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) should return true");
is(events.length, 7,
@ -2480,8 +2480,8 @@ function runKeyTests()
doDefaultKeydown = TIP.keydown(keyWithModifiers);
doDefaultKeyup = TIP.keyup(keyWithModifiers);
ok(doDefaultKeydown,
description + "TIP.keydown(keyWithModifiers) should return true");
is(doDefaultKeydown, 0,
description + "TIP.keydown(keyWithModifiers) should return 0");
ok(doDefaultKeyup,
description + "TIP.keyup(keyWithModifiers) should return true");
is(events.length, 3,
@ -2502,8 +2502,8 @@ function runKeyTests()
doDefaultKeydown = TIP.keydown(keyA);
doDefaultKeyup = TIP.keyup(keyA);
ok(!doDefaultKeydown,
description + "TIP.keydown(keyA) should return false because keydown event's preventDefault should be called");
is(doDefaultKeydown, TIP.KEYDOWN_IS_CONSUMED,
description + "TIP.keydown(keyA) should return 0x01 because keydown event's preventDefault should be called");
ok(doDefaultKeyup,
description + "TIP.keyup(keyA) should return true");
is(events.length, 2,
@ -2521,8 +2521,8 @@ function runKeyTests()
doDefaultKeydown = TIP.keydown(keyA);
doDefaultKeyup = TIP.keyup(keyA);
ok(!doDefaultKeydown,
description + "TIP.keydown(keyA) should return false because keypress event's preventDefault should be called");
is(doDefaultKeydown, TIP.KEYPRESS_IS_CONSUMED,
description + "TIP.keydown(keyA) should return 0x02 because keypress event's preventDefault should be called");
ok(doDefaultKeyup,
description + "TIP.keyup(keyA) should return true");
is(events.length, 3,
@ -2543,8 +2543,8 @@ function runKeyTests()
doDefaultKeydown = TIP.keydown(keyA);
doDefaultKeyup = TIP.keyup(keyA);
ok(!doDefaultKeydown,
description + "TIP.keydown(keyA) should return false because the key event should be consumed by the input element");
is(doDefaultKeydown, TIP.KEYPRESS_IS_CONSUMED,
description + "TIP.keydown(keyA) should return 0x02 because the key event should be consumed by the input element");
ok(!doDefaultKeyup,
description + "TIP.keyup(keyA) should return false because keyup event's preventDefault should be called");
is(events.length, 3,

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

@ -833,14 +833,16 @@ BrowserElementParent.prototype = {
catch(e) {
debug('Malformed referrer -- ' + e);
}
// TODO Bug 1165466: use originAttributes from nsILoadContext.
let attrs = {appId: this._frameLoader.loadContext.appId,
inBrowser: this._frameLoader.loadContext.isInBrowserElement};
// This simply returns null if there is no principal available
// for the requested uri. This is an acceptable fallback when
// calling newChannelFromURI2.
principal =
Services.scriptSecurityManager.getAppCodebasePrincipal(
referrer,
this._frameLoader.loadContext.appId,
this._frameLoader.loadContext.isInBrowserElement);
principal =
Services.scriptSecurityManager.createCodebasePrincipal(
referrer, attrs);
}
debug('Using principal? ' + !!principal);

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

@ -158,15 +158,17 @@ function testAuthJarNoInterfere(e) {
// Set a bunch of auth data that should not conflict with the correct auth data already
// stored in the cache.
var principal = secMan.getAppCodebasePrincipal(uri, 1, false);
var attrs = {appId: 1};
var principal = secMan.createCodebasePrincipal(uri, attrs);
authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
'', 'httpuser', 'wrongpass', false, principal);
principal = secMan.getAppCodebasePrincipal(uri, 1, true);
attrs = {appId: 1, inBrowser: true};
principal = secMan.createCodebasePrincipal(uri, attrs);
authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
'', 'httpuser', 'wrongpass', false, principal);
principal = secMan.getAppCodebasePrincipal(uri, secMan.NO_APP_ID, false);
principal = secMan.createCodebasePrincipal(uri, {});
authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
'', 'httpuser', 'wrongpass', false, principal);
@ -196,7 +198,7 @@ function testAuthJarInterfere(e) {
var uri = ioService.newURI("http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs", null, null);
// Set some auth data that should overwrite the successful stored details.
var principal = secMan.getAppCodebasePrincipal(uri, secMan.NO_APP_ID, true);
var principal = secMan.createCodebasePrincipal(uri, {inBrowser: true});
authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
'', 'httpuser', 'wrongpass', false, principal);

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

@ -20,7 +20,7 @@
// attach to a different origin's CacheStorage
var url = 'http://example.com/';
var uri = Services.io.newURI(url, null, null);
var principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
var principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
var storage = new CacheStorage('content', principal);
// verify we can use the other origin's CacheStorage as normal

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

@ -1728,7 +1728,11 @@ CanvasRenderingContext2D::Scale(double x, double y, ErrorResult& error)
}
Matrix newMatrix = mTarget->GetTransform();
mTarget->SetTransform(newMatrix.PreScale(x, y));
newMatrix.PreScale(x, y);
if (!newMatrix.IsFinite()) {
return;
}
mTarget->SetTransform(newMatrix);
}
void
@ -1740,8 +1744,11 @@ CanvasRenderingContext2D::Rotate(double angle, ErrorResult& error)
return;
}
Matrix rotation = Matrix::Rotation(angle);
mTarget->SetTransform(rotation * mTarget->GetTransform());
Matrix newMatrix = Matrix::Rotation(angle) * mTarget->GetTransform();
if (!newMatrix.IsFinite()) {
return;
}
mTarget->SetTransform(newMatrix);
}
void
@ -1753,7 +1760,12 @@ CanvasRenderingContext2D::Translate(double x, double y, ErrorResult& error)
return;
}
mTarget->SetTransform(Matrix(mTarget->GetTransform()).PreTranslate(x, y));
Matrix newMatrix = mTarget->GetTransform();
newMatrix.PreTranslate(x, y);
if (!newMatrix.IsFinite()) {
return;
}
mTarget->SetTransform(newMatrix);
}
void
@ -1767,8 +1779,12 @@ CanvasRenderingContext2D::Transform(double m11, double m12, double m21,
return;
}
Matrix matrix(m11, m12, m21, m22, dx, dy);
mTarget->SetTransform(matrix * mTarget->GetTransform());
Matrix newMatrix(m11, m12, m21, m22, dx, dy);
newMatrix *= mTarget->GetTransform();
if (!newMatrix.IsFinite()) {
return;
}
mTarget->SetTransform(newMatrix);
}
void
@ -1784,6 +1800,9 @@ CanvasRenderingContext2D::SetTransform(double m11, double m12,
}
Matrix matrix(m11, m12, m21, m22, dx, dy);
if (!matrix.IsFinite()) {
return;
}
mTarget->SetTransform(matrix);
}

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

@ -209,12 +209,23 @@ StartsWith(const std::string& haystack, const char (&needle)[N])
bool
ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log) const
{
{
const std::vector<sh::Uniform>& vertList = *ShGetUniforms(prev->mHandle);
const std::vector<sh::Uniform>& fragList = *ShGetUniforms(mHandle);
if (!prev) {
nsPrintfCString error("Passed in NULL prev ShaderValidator.");
*out_log = error;
return false;
}
for (auto itrFrag = fragList.begin(); itrFrag != fragList.end(); ++itrFrag) {
for (auto itrVert = vertList.begin(); itrVert != vertList.end(); ++itrVert) {
{
const std::vector<sh::Uniform>* vertPtr = ShGetUniforms(prev->mHandle);
const std::vector<sh::Uniform>* fragPtr = ShGetUniforms(mHandle);
if (!vertPtr || !fragPtr) {
nsPrintfCString error("Could not create uniform list.");
*out_log = error;
return false;
}
for (auto itrFrag = fragPtr->begin(); itrFrag != fragPtr->end(); ++itrFrag) {
for (auto itrVert = vertPtr->begin(); itrVert != vertPtr->end(); ++itrVert) {
if (itrVert->name != itrFrag->name)
continue;
@ -231,12 +242,17 @@ ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log
}
}
{
const std::vector<sh::Varying>& vertList = *ShGetVaryings(prev->mHandle);
const std::vector<sh::Varying>& fragList = *ShGetVaryings(mHandle);
const std::vector<sh::Varying>* vertPtr = ShGetVaryings(prev->mHandle);
const std::vector<sh::Varying>* fragPtr = ShGetVaryings(mHandle);
if (!vertPtr || !fragPtr) {
nsPrintfCString error("Could not create varying list.");
*out_log = error;
return false;
}
nsTArray<ShVariableInfo> staticUseVaryingList;
for (auto itrFrag = fragList.begin(); itrFrag != fragList.end(); ++itrFrag) {
for (auto itrFrag = fragPtr->begin(); itrFrag != fragPtr->end(); ++itrFrag) {
const ShVariableInfo varInfo = { itrFrag->type,
(int)itrFrag->elementCount() };
@ -251,7 +267,7 @@ ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log
bool definedInVertShader = false;
bool staticVertUse = false;
for (auto itrVert = vertList.begin(); itrVert != vertList.end(); ++itrVert) {
for (auto itrVert = vertPtr->begin(); itrVert != vertPtr->end(); ++itrVert) {
if (itrVert->name != itrFrag->name)
continue;

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

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<script>
function boom()
{
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.rotate(1e308);
ctx.fillText("A", 1, 1);
}
</script>
</head>
<body onload="boom();"></body>
</html>

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

@ -23,3 +23,5 @@ load 916128-1.html
load 934939-1.html
load 1099143-1.html
load 1183363.html
load 1190705.html

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

@ -14,6 +14,7 @@
#include "mozilla/dom/DataStoreImplBinding.h"
#include "nsIDataStore.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
@ -56,6 +57,9 @@
return NS_ERROR_FAILURE; \
}
using mozilla::BasePrincipal;
using mozilla::OriginAttributes;
namespace mozilla {
namespace dom {
@ -213,17 +217,10 @@ ResetPermission(uint32_t aAppId, const nsAString& aOriginURL,
return rv;
}
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
if (!ssm) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIPrincipal> principal;
rv = ssm->GetAppCodebasePrincipal(uri, aAppId, false,
getter_AddRefs(principal));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
OriginAttributes attrs(aAppId, false);
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateCodebasePrincipal(uri, attrs);
NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
nsCOMPtr<nsIPermissionManager> pm =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);

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

@ -18519,12 +18519,6 @@ FactoryOp::CheckAtLeastOneAppHasPermission(ContentParent* aContentParent,
return false;
}
nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
if (NS_WARN_IF(!secMan)) {
return false;
}
nsCOMPtr<nsIPermissionManager> permMan =
mozilla::services::GetPermissionManager();
if (NS_WARN_IF(!permMan)) {
@ -18548,24 +18542,9 @@ FactoryOp::CheckAtLeastOneAppHasPermission(ContentParent* aContentParent,
return false;
}
nsString origin;
rv = app->GetOrigin(origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), origin, nullptr, nullptr, ioService);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
nsCOMPtr<nsIPrincipal> principal;
rv = secMan->GetAppCodebasePrincipal(uri, appId, false,
getter_AddRefs(principal));
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
app->GetPrincipal(getter_AddRefs(principal));
NS_ENSURE_TRUE(principal, false);
uint32_t permission;
rv = permMan->TestExactPermissionFromPrincipal(principal,

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

@ -116,9 +116,9 @@ function setPermission(url, permission)
let uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
let ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let principal = ssm.createCodebasePrincipal(uri, {});
Components.classes["@mozilla.org/permissionmanager;1"]
.getService(nsIPermissionManager)
@ -131,9 +131,9 @@ function removePermission(url, permission)
let uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
let ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let principal = ssm.createCodebasePrincipal(uri, {});
Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager)
@ -145,9 +145,9 @@ function getPermission(url, permission)
let uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
let ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let principal = ssm.createCodebasePrincipal(uri, {});
return Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager)

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

@ -90,13 +90,10 @@ function testSteps()
let request;
if ("url" in params) {
let uri = ios.newURI(params.url, null, null);
let principal;
if ("appId" in params) {
principal = ssm.getAppCodebasePrincipal(uri, params.appId,
params.inMozBrowser);
} else {
principal = ssm.getNoAppCodebasePrincipal(uri);
}
let principal =
ssm.createCodebasePrincipal(uri,
{appId: params.appId || ssm.NO_APPID,
inBrowser: params.inMozBrowser});
if ("dbVersion" in params) {
request = indexedDB.openForPrincipal(principal, params.dbName,
params.dbVersion);

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

@ -10,9 +10,9 @@ function testSteps()
let uri = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService).
newURI("https://www.example.com", null, null);
let principal = Cc["@mozilla.org/scriptsecuritymanager;1"].
getService(Ci.nsIScriptSecurityManager).
getNoAppCodebasePrincipal(uri);
let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let principal = ssm.createCodebasePrincipal(uri, {});
info("Setting permissions");

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

@ -67,7 +67,7 @@ function testSteps()
let request;
if ("url" in params) {
let uri = ios.newURI(params.url, null, null);
let principal = ssm.getNoAppCodebasePrincipal(uri);
let principal = ssm.createCodebasePrincipal(uri, {});
request = indexedDB.openForPrincipal(principal, params.dbName,
params.dbOptions);
} else {

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

@ -48,9 +48,9 @@ function testSteps()
let uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI("http://appdata.example.com", null, null);
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
let ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager);
let principal = ssm.createCodebasePrincipal(uri, {});
request = indexedDB.openForPrincipal(principal, name, 1);
request.onerror = errorHandler;

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

@ -34,9 +34,9 @@ function testSteps()
let uri = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newURI(url, null, null);
return Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
return ssm.createCodebasePrincipal(uri, {});
}
for (let temporary of [true, false]) {

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

@ -381,7 +381,7 @@ MozInputMethod.prototype = {
},
addInput: function(inputId, inputManifest) {
return this._sendPromise(function(resolverId) {
return this.createPromiseWithId(function(resolverId) {
let appId = this._window.document.nodePrincipal.appId;
cpmm.sendAsyncMessage('InputRegistry:Add', {
@ -573,7 +573,7 @@ MozInputContext.prototype = {
switch (msg.name) {
case "Keyboard:SendKey:Result:OK":
resolver.resolve();
resolver.resolve(true);
break;
case "Keyboard:SendKey:Result:Error":
resolver.reject(json.error);
@ -596,7 +596,7 @@ MozInputContext.prototype = {
break;
case "Keyboard:SetComposition:Result:OK": // Fall through.
case "Keyboard:EndComposition:Result:OK":
resolver.resolve();
resolver.resolve(true);
break;
default:
dump("Could not find a handler for " + msg.name);
@ -738,40 +738,79 @@ MozInputContext.prototype = {
return this.replaceSurroundingText(null, offset, length);
},
sendKey: function ic_sendKey(keyCode, charCode, modifiers, repeat) {
let self = this;
return this._sendPromise(function(resolverId) {
cpmmSendAsyncMessageWithKbID(self, 'Keyboard:SendKey', {
contextId: self._contextId,
sendKey: function ic_sendKey(dictOrKeyCode, charCode, modifiers, repeat) {
if (typeof dictOrKeyCode === 'number') {
// XXX: modifiers are ignored in this API method.
return this._sendPromise((resolverId) => {
cpmmSendAsyncMessageWithKbID(this, 'Keyboard:SendKey', {
contextId: this._contextId,
requestId: resolverId,
method: 'sendKey',
keyCode: dictOrKeyCode,
charCode: charCode,
repeat: repeat
});
});
} else if (typeof dictOrKeyCode === 'object') {
return this._sendPromise((resolverId) => {
cpmmSendAsyncMessageWithKbID(this, 'Keyboard:SendKey', {
contextId: this._contextId,
requestId: resolverId,
method: 'sendKey',
keyboardEventDict: this._getkeyboardEventDict(dictOrKeyCode)
});
});
} else {
// XXX: Should not reach here; implies WebIDL binding error.
throw new TypeError('Unknown argument passed.');
}
},
keydown: function ic_keydown(dict) {
return this._sendPromise((resolverId) => {
cpmmSendAsyncMessageWithKbID(this, 'Keyboard:SendKey', {
contextId: this._contextId,
requestId: resolverId,
method: 'keydown',
keyboardEventDict: this._getkeyboardEventDict(dict)
});
});
},
keyup: function ic_keyup(dict) {
return this._sendPromise((resolverId) => {
cpmmSendAsyncMessageWithKbID(this, 'Keyboard:SendKey', {
contextId: this._contextId,
requestId: resolverId,
keyCode: keyCode,
charCode: charCode,
modifiers: modifiers,
repeat: repeat
method: 'keyup',
keyboardEventDict: this._getkeyboardEventDict(dict)
});
});
},
setComposition: function ic_setComposition(text, cursor, clauses) {
setComposition: function ic_setComposition(text, cursor, clauses, dict) {
let self = this;
return this._sendPromise(function(resolverId) {
return this._sendPromise((resolverId) => {
cpmmSendAsyncMessageWithKbID(self, 'Keyboard:SetComposition', {
contextId: self._contextId,
requestId: resolverId,
text: text,
cursor: (typeof cursor !== 'undefined') ? cursor : text.length,
clauses: clauses || null
clauses: clauses || null,
keyboardEventDict: this._getkeyboardEventDict(dict)
});
});
},
endComposition: function ic_endComposition(text) {
endComposition: function ic_endComposition(text, dict) {
let self = this;
return this._sendPromise(function(resolverId) {
return this._sendPromise((resolverId) => {
cpmmSendAsyncMessageWithKbID(self, 'Keyboard:EndComposition', {
contextId: self._contextId,
requestId: resolverId,
text: text || ''
text: text || '',
keyboardEventDict: this._getkeyboardEventDict(dict)
});
});
},
@ -786,6 +825,43 @@ MozInputContext.prototype = {
}
callback(aResolverId);
});
},
// Take a MozInputMethodKeyboardEventDict dict, creates a keyboardEventDict
// object that can be sent to forms.js
_getkeyboardEventDict: function(dict) {
if (typeof dict !== 'object' || !dict.key) {
return;
}
var keyboardEventDict = {
key: dict.key,
code: dict.code,
repeat: dict.repeat,
flags: 0
};
if (dict.printable) {
keyboardEventDict.flags |=
Ci.nsITextInputProcessor.KEY_FORCE_PRINTABLE_KEY;
}
if (/^[a-zA-Z0-9]$/.test(dict.key)) {
// keyCode must follow the key value in this range;
// disregard the keyCode from content.
keyboardEventDict.keyCode = dict.key.toUpperCase().charCodeAt(0);
} else if (typeof dict.keyCode === 'number') {
// Allow keyCode to be specified for other key values.
keyboardEventDict.keyCode = dict.keyCode;
// Allow keyCode to be explicitly set to zero.
if (dict.keyCode === 0) {
keyboardEventDict.flags |=
Ci.nsITextInputProcessor.KEY_KEEP_KEYCODE_ZERO;
}
}
return keyboardEventDict;
}
};

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

@ -11,6 +11,7 @@ dump("###################################### forms.js loaded\n");
let Ci = Components.interfaces;
let Cc = Components.classes;
let Cu = Components.utils;
let Cr = Components.results;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
@ -18,10 +19,50 @@ XPCOMUtils.defineLazyServiceGetter(Services, "fm",
"@mozilla.org/focus-manager;1",
"nsIFocusManager");
XPCOMUtils.defineLazyGetter(this, "domWindowUtils", function () {
return content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
});
/*
* A WeakMap to map window to objects keeping it's TextInputProcessor instance.
*/
let WindowMap = {
// WeakMap of <window, object> pairs.
_map: null,
/*
* Set the object associated to the window and return it.
*/
_getObjForWin: function(win) {
if (!this._map) {
this._map = new WeakMap();
}
if (this._map.has(win)) {
return this._map.get(win);
} else {
let obj = {
tip: null
};
this._map.set(win, obj);
return obj;
}
},
getTextInputProcessor: function(win) {
if (!win) {
return;
}
let obj = this._getObjForWin(win);
let tip = obj.tip
if (!tip) {
tip = obj.tip = Cc["@mozilla.org/text-input-processor;1"]
.createInstance(Ci.nsITextInputProcessor);
}
if (!tip.beginInputTransaction(win, textInputProcessorCallback)) {
tip = obj.tip = null;
}
return tip;
}
};
const RESIZE_SCROLL_DELAY = 20;
// In content editable node, when there are hidden elements such as <br>, it
@ -41,6 +82,151 @@ let HTMLSelectElement = Ci.nsIDOMHTMLSelectElement;
let HTMLOptGroupElement = Ci.nsIDOMHTMLOptGroupElement;
let HTMLOptionElement = Ci.nsIDOMHTMLOptionElement;
function guessKeyNameFromKeyCode(KeyboardEvent, aKeyCode) {
switch (aKeyCode) {
case KeyboardEvent.DOM_VK_CANCEL:
return "Cancel";
case KeyboardEvent.DOM_VK_HELP:
return "Help";
case KeyboardEvent.DOM_VK_BACK_SPACE:
return "Backspace";
case KeyboardEvent.DOM_VK_TAB:
return "Tab";
case KeyboardEvent.DOM_VK_CLEAR:
return "Clear";
case KeyboardEvent.DOM_VK_RETURN:
return "Enter";
case KeyboardEvent.DOM_VK_SHIFT:
return "Shift";
case KeyboardEvent.DOM_VK_CONTROL:
return "Control";
case KeyboardEvent.DOM_VK_ALT:
return "Alt";
case KeyboardEvent.DOM_VK_PAUSE:
return "Pause";
case KeyboardEvent.DOM_VK_EISU:
return "Eisu";
case KeyboardEvent.DOM_VK_ESCAPE:
return "Escape";
case KeyboardEvent.DOM_VK_CONVERT:
return "Convert";
case KeyboardEvent.DOM_VK_NONCONVERT:
return "NonConvert";
case KeyboardEvent.DOM_VK_ACCEPT:
return "Accept";
case KeyboardEvent.DOM_VK_MODECHANGE:
return "ModeChange";
case KeyboardEvent.DOM_VK_PAGE_UP:
return "PageUp";
case KeyboardEvent.DOM_VK_PAGE_DOWN:
return "PageDown";
case KeyboardEvent.DOM_VK_END:
return "End";
case KeyboardEvent.DOM_VK_HOME:
return "Home";
case KeyboardEvent.DOM_VK_LEFT:
return "ArrowLeft";
case KeyboardEvent.DOM_VK_UP:
return "ArrowUp";
case KeyboardEvent.DOM_VK_RIGHT:
return "ArrowRight";
case KeyboardEvent.DOM_VK_DOWN:
return "ArrowDown";
case KeyboardEvent.DOM_VK_SELECT:
return "Select";
case KeyboardEvent.DOM_VK_PRINT:
return "Print";
case KeyboardEvent.DOM_VK_EXECUTE:
return "Execute";
case KeyboardEvent.DOM_VK_PRINTSCREEN:
return "PrintScreen";
case KeyboardEvent.DOM_VK_INSERT:
return "Insert";
case KeyboardEvent.DOM_VK_DELETE:
return "Delete";
case KeyboardEvent.DOM_VK_WIN:
return "OS";
case KeyboardEvent.DOM_VK_CONTEXT_MENU:
return "ContextMenu";
case KeyboardEvent.DOM_VK_SLEEP:
return "Standby";
case KeyboardEvent.DOM_VK_F1:
return "F1";
case KeyboardEvent.DOM_VK_F2:
return "F2";
case KeyboardEvent.DOM_VK_F3:
return "F3";
case KeyboardEvent.DOM_VK_F4:
return "F4";
case KeyboardEvent.DOM_VK_F5:
return "F5";
case KeyboardEvent.DOM_VK_F6:
return "F6";
case KeyboardEvent.DOM_VK_F7:
return "F7";
case KeyboardEvent.DOM_VK_F8:
return "F8";
case KeyboardEvent.DOM_VK_F9:
return "F9";
case KeyboardEvent.DOM_VK_F10:
return "F10";
case KeyboardEvent.DOM_VK_F11:
return "F11";
case KeyboardEvent.DOM_VK_F12:
return "F12";
case KeyboardEvent.DOM_VK_F13:
return "F13";
case KeyboardEvent.DOM_VK_F14:
return "F14";
case KeyboardEvent.DOM_VK_F15:
return "F15";
case KeyboardEvent.DOM_VK_F16:
return "F16";
case KeyboardEvent.DOM_VK_F17:
return "F17";
case KeyboardEvent.DOM_VK_F18:
return "F18";
case KeyboardEvent.DOM_VK_F19:
return "F19";
case KeyboardEvent.DOM_VK_F20:
return "F20";
case KeyboardEvent.DOM_VK_F21:
return "F21";
case KeyboardEvent.DOM_VK_F22:
return "F22";
case KeyboardEvent.DOM_VK_F23:
return "F23";
case KeyboardEvent.DOM_VK_F24:
return "F24";
case KeyboardEvent.DOM_VK_NUM_LOCK:
return "NumLock";
case KeyboardEvent.DOM_VK_SCROLL_LOCK:
return "ScrollLock";
case KeyboardEvent.DOM_VK_VOLUME_MUTE:
return "VolumeMute";
case KeyboardEvent.DOM_VK_VOLUME_DOWN:
return "VolumeDown";
case KeyboardEvent.DOM_VK_VOLUME_UP:
return "VolumeUp";
case KeyboardEvent.DOM_VK_META:
return "Meta";
case KeyboardEvent.DOM_VK_ALTGR:
return "AltGraph";
case KeyboardEvent.DOM_VK_ATTN:
return "Attn";
case KeyboardEvent.DOM_VK_CRSEL:
return "CrSel";
case KeyboardEvent.DOM_VK_EXSEL:
return "ExSel";
case KeyboardEvent.DOM_VK_EREOF:
return "EraseEof";
case KeyboardEvent.DOM_VK_PLAY:
return "Play";
default:
return "Unidentified";
}
}
let FormVisibility = {
/**
* Searches upwards in the DOM for an element that has been scrolled.
@ -184,6 +370,41 @@ let FormVisibility = {
}
};
// This object implements nsITextInputProcessorCallback
let textInputProcessorCallback = {
onNotify: function(aTextInputProcessor, aNotification) {
try {
switch (aNotification.type) {
case "request-to-commit":
// TODO: Send a notification through asyncMessage to the keyboard here.
aTextInputProcessor.commitComposition();
break;
case "request-to-cancel":
// TODO: Send a notification through asyncMessage to the keyboard here.
aTextInputProcessor.cancelComposition();
break;
case "notify-detached":
// TODO: Send a notification through asyncMessage to the keyboard here.
break;
// TODO: Manage _focusedElement for text input from here instead.
// (except for <select> which will be need to handled elsewhere)
case "notify-focus":
break;
case "notify-blur":
break;
}
} catch (e) {
return false;
}
return true;
}
};
let FormAssistant = {
init: function fa_init() {
addEventListener("focus", this, true, false);
@ -432,7 +653,7 @@ let FormAssistant = {
break;
case "keydown":
if (!this.focusedElement) {
if (!this.focusedElement || this._editing) {
break;
}
@ -440,7 +661,7 @@ let FormAssistant = {
break;
case "keyup":
if (!this.focusedElement) {
if (!this.focusedElement || this._editing) {
break;
}
@ -502,34 +723,132 @@ let FormAssistant = {
case "Forms:Input:SendKey":
CompositionManager.endComposition('');
let flags = domWindowUtils.KEY_FLAG_NOT_SYNTHESIZED_FOR_TESTS;
this._editing = true;
let doKeypress = domWindowUtils.sendKeyEvent('keydown', json.keyCode,
json.charCode, json.modifiers, flags);
if (doKeypress) {
domWindowUtils.sendKeyEvent('keypress', json.keyCode,
json.charCode, json.modifiers, flags);
let win = target.ownerDocument.defaultView;
let tip = WindowMap.getTextInputProcessor(win);
if (!tip) {
if (json.requestId) {
sendAsyncMessage("Forms:SendKey:Result:Error", {
requestId: json.requestId,
error: "Unable to start input transaction."
});
}
break;
}
if(!json.repeat) {
domWindowUtils.sendKeyEvent('keyup', json.keyCode,
json.charCode, json.modifiers, flags);
// If we receive a keyboardEventDict from json, that means the user
// is calling the method with the new arguments.
// Otherwise, we would have to construct our own keyboardEventDict
// based on legacy values we have received.
let keyboardEventDict = json.keyboardEventDict;
let flags = 0;
if (keyboardEventDict) {
if ('flags' in keyboardEventDict) {
flags = keyboardEventDict.flags;
}
} else {
// The naive way to figure out if the key to dispatch is printable.
let printable = !!json.charCode;
// For printable keys, the value should be the actual character.
// For non-printable keys, it should be a value in the D3E spec.
// Here we make some educated guess for it.
let key = printable ?
String.fromCharCode(json.charCode) :
guessKeyNameFromKeyCode(win.KeyboardEvent, json.keyCode);
// keyCode from content is only respected when the key is not an
// an alphanumeric character. We also ask TextInputProcessor not to
// infer this value for non-printable keys to keep the original
// behavior.
let keyCode = (printable && /^[a-zA-Z0-9]$/.test(key)) ?
key.toUpperCase().charCodeAt(0) :
json.keyCode;
keyboardEventDict = {
key: key,
keyCode: keyCode,
// We don't have any information to tell the virtual key the
// user have interacted with.
code: "",
// We do not have the information to infer location of the virtual key
// either (and we would need TextInputProcessor not to compute it).
location: 0,
// This indicates the key is triggered for repeats.
repeat: json.repeat
};
flags = tip.KEY_KEEP_KEY_LOCATION_STANDARD;
if (!printable) {
flags |= tip.KEY_NON_PRINTABLE_KEY;
}
if (!keyboardEventDict.keyCode) {
flags |= tip.KEY_KEEP_KEYCODE_ZERO;
}
}
this._editing = false;
let keyboardEvent = new win.KeyboardEvent("", keyboardEventDict);
if (json.requestId && doKeypress) {
sendAsyncMessage("Forms:SendKey:Result:OK", {
requestId: json.requestId,
selectioninfo: this.getSelectionInfo()
});
let keydownDefaultPrevented = false;
try {
switch (json.method) {
case 'sendKey': {
let consumedFlags = tip.keydown(keyboardEvent, flags);
keydownDefaultPrevented =
!!(tip.KEYDOWN_IS_CONSUMED & consumedFlags);
if (!keyboardEventDict.repeat) {
tip.keyup(keyboardEvent, flags);
}
break;
}
case 'keydown': {
let consumedFlags = tip.keydown(keyboardEvent, flags);
keydownDefaultPrevented =
!!(tip.KEYDOWN_IS_CONSUMED & consumedFlags);
break;
}
case 'keyup': {
tip.keyup(keyboardEvent, flags);
break;
}
}
} catch (err) {
dump("forms.js:" + err.toString() + "\n");
if (json.requestId) {
if (err instanceof Ci.nsIException &&
err.result == Cr.NS_ERROR_ILLEGAL_VALUE) {
sendAsyncMessage("Forms:SendKey:Result:Error", {
requestId: json.requestId,
error: "The values specified are illegal."
});
} else {
sendAsyncMessage("Forms:SendKey:Result:Error", {
requestId: json.requestId,
error: "Unable to type into destroyed input."
});
}
}
break;
}
else if (json.requestId && !doKeypress) {
sendAsyncMessage("Forms:SendKey:Result:Error", {
requestId: json.requestId,
error: "Keydown event got canceled"
});
if (json.requestId) {
if (keydownDefaultPrevented) {
sendAsyncMessage("Forms:SendKey:Result:Error", {
requestId: json.requestId,
error: "Key event(s) was cancelled."
});
} else {
sendAsyncMessage("Forms:SendKey:Result:OK", {
requestId: json.requestId,
selectioninfo: this.getSelectionInfo()
});
}
}
break;
case "Forms:Select:Choice":
@ -642,7 +961,7 @@ let FormAssistant = {
case "Forms:SetComposition": {
CompositionManager.setComposition(target, json.text, json.cursor,
json.clauses);
json.clauses, json.keyboardEventDict);
sendAsyncMessage("Forms:SetComposition:Result:OK", {
requestId: json.requestId,
selectioninfo: this.getSelectionInfo()
@ -651,7 +970,7 @@ let FormAssistant = {
}
case "Forms:EndComposition": {
CompositionManager.endComposition(json.text);
CompositionManager.endComposition(json.text, json.keyboardEventDict);
sendAsyncMessage("Forms:EndComposition:Result:OK", {
requestId: json.requestId,
selectioninfo: this.getSelectionInfo()
@ -1170,7 +1489,8 @@ function replaceSurroundingText(element, text, offset, length) {
let CompositionManager = {
_isStarted: false,
_textInputProcessor: null,
_tip: null,
_KeyboardEventForWin: null,
_clauseAttrMap: {
'raw-input':
Ci.nsITextInputProcessor.ATTR_RAW_CLAUSE,
@ -1182,35 +1502,7 @@ let CompositionManager = {
Ci.nsITextInputProcessor.ATTR_SELECTED_CLAUSE
},
_callback: function cm_callback(aTIP, aNotification)
{
try {
switch (aNotification.type) {
case "request-to-commit":
aTIP.commitComposition();
break;
case "request-to-cancel":
aTIP.cancelComposition();
break;
}
} catch (e) {
return false;
}
return true;
},
_prepareTextInputProcessor: function cm_prepareTextInputProcessor(aWindow)
{
if (!this._textInputProcessor) {
this._textInputProcessor =
Cc["@mozilla.org/text-input-processor;1"].
createInstance(Ci.nsITextInputProcessor);
}
return this._textInputProcessor.beginInputTransaction(aWindow,
this._callback);
},
setComposition: function cm_setComposition(element, text, cursor, clauses) {
setComposition: function cm_setComposition(element, text, cursor, clauses, dict) {
// Check parameters.
if (!element) {
return;
@ -1248,30 +1540,57 @@ let CompositionManager = {
}
let win = element.ownerDocument.defaultView;
if (!this._prepareTextInputProcessor(win)) {
let tip = WindowMap.getTextInputProcessor(win);
if (!tip) {
return;
}
// Update the composing text.
this._textInputProcessor.setPendingCompositionString(text);
tip.setPendingCompositionString(text);
for (var i = 0; i < clauseLens.length; i++) {
if (!clauseLens[i]) {
continue;
}
this._textInputProcessor.appendClauseToPendingComposition(clauseLens[i],
clauseAttrs[i]);
tip.appendClauseToPendingComposition(clauseLens[i], clauseAttrs[i]);
}
if (cursor >= 0) {
this._textInputProcessor.setCaretInPendingComposition(cursor);
tip.setCaretInPendingComposition(cursor);
}
if (!dict) {
this._isStarted = tip.flushPendingComposition();
} else {
let keyboardEvent = new win.KeyboardEvent("", dict);
let flags = dict.flags;
this._isStarted = tip.flushPendingComposition(keyboardEvent, flags);
}
if (this._isStarted) {
this._tip = tip;
this._KeyboardEventForWin = win.KeyboardEvent;
}
this._isStarted = this._textInputProcessor.flushPendingComposition();
},
endComposition: function cm_endComposition(text) {
endComposition: function cm_endComposition(text, dict) {
if (!this._isStarted) {
return;
}
this._textInputProcessor.commitCompositionWith(text ? text : "");
let tip = this._tip;
if (!tip) {
return;
}
text = text || "";
if (!dict) {
tip.commitCompositionWith(text);
} else {
let keyboardEvent = new this._KeyboardEventForWin("", dict);
let flags = dict.flags;
tip.commitCompositionWith(text, keyboardEvent, flags);
}
this._isStarted = false;
this._tip = null;
this._KeyboardEventForWin = null;
},
// Composition ends due to external actions.
@ -1281,5 +1600,7 @@ let CompositionManager = {
}
this._isStarted = false;
this._tip = null;
this._KeyboardEventForWin = null;
}
};

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

@ -26,3 +26,4 @@ support-files =
[test_two_inputs.html]
[test_two_selects.html]
[test_unload.html]
[test_bug1137557.html]

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

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

@ -254,7 +254,7 @@ interface nsITextInputProcessorCallback;
* TIP.keyup(leftShift);
*/
[scriptable, builtinclass, uuid(6617a9f6-3e16-4086-9e1e-c8a6c5d505c7)]
[scriptable, builtinclass, uuid(581f6619-76ed-478c-905d-b8e6553a714a)]
interface nsITextInputProcessor : nsISupports
{
/**
@ -489,6 +489,12 @@ interface nsITextInputProcessor : nsISupports
// or emulating legacy API behavior.
const unsigned long KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT = 0x00000020;
// These values can be used to do bitwise operation with the return value of
// the keydown() method.
const unsigned long KEYEVENT_NOT_CONSUMED = 0x00000000;
const unsigned long KEYDOWN_IS_CONSUMED = 0x00000001;
const unsigned long KEYPRESS_IS_CONSUMED = 0x00000002;
/**
* keydown() may dispatch a keydown event and some keypress events if
* preceding keydown event isn't consumed and they are necessary.
@ -529,13 +535,20 @@ interface nsITextInputProcessor : nsISupports
* each instance and set automatically.
* @param aKeyFlags Special flags. The values can be some of KEY_*
* constants.
* @return true if neither the keydown event or following
* keypress events is *not* consumed.
* Otherwise, i.e., preventDefault() is called, false.
* @return KEYEVENT_NOT_CONSUMED, if the keydown event nor
* the following keypress event(s) are consumed.
* KEYDOWN_IS_CONSUMED, if the keydown event is
* consumed. No keypress event will be dispatched in
* this case.
* KEYPRESS_IS_CONSUMED, if the keypress event(s) is
* consumed when dispatched.
* Note that keypress event is always consumed by
* native code for the printable keys (indicating the
* default action has been taken).
*/
[optional_argc]
boolean keydown(in nsIDOMKeyEvent aKeyboardEvent,
[optional] in unsigned long aKeyFlags);
unsigned long keydown(in nsIDOMKeyEvent aKeyboardEvent,
[optional] in unsigned long aKeyFlags);
/**
* Similar to keydown(), but this dispatches only a keyup event.

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

@ -12,7 +12,6 @@
#include "mozilla/hal_sandbox/PHalParent.h"
#include "nsIAppsService.h"
#include "nsIPrincipal.h"
#include "nsIScriptSecurityManager.h"
#include "nsPrintfCString.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
@ -232,21 +231,10 @@ GetAppPrincipal(uint32_t aAppId)
nsresult rv = appsService->GetAppByLocalId(aAppId, getter_AddRefs(app));
NS_ENSURE_SUCCESS(rv, nullptr);
nsString origin;
rv = app->GetOrigin(origin);
NS_ENSURE_SUCCESS(rv, nullptr);
nsCOMPtr<nsIPrincipal> principal;
app->GetPrincipal(getter_AddRefs(principal));
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), origin);
nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
nsCOMPtr<nsIPrincipal> appPrincipal;
rv = secMan->GetAppCodebasePrincipal(uri, aAppId, false,
getter_AddRefs(appPrincipal));
NS_ENSURE_SUCCESS(rv, nullptr);
return appPrincipal.forget();
return principal.forget();
}
uint32_t

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

@ -1562,23 +1562,15 @@ TabChild::MaybeRequestPreinitCamera()
return;
}
nsString manifestUrl = EmptyString();
appsService->GetManifestURLByLocalId(OwnAppId(), manifestUrl);
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
if (NS_WARN_IF(!secMan)) {
return;
}
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), manifestUrl);
nsCOMPtr<mozIApplication> app;
nsresult rv = appsService->GetAppByLocalId(OwnAppId(), getter_AddRefs(app));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
nsCOMPtr<nsIPrincipal> principal;
rv = secMan->GetAppCodebasePrincipal(uri, OwnAppId(), false,
getter_AddRefs(principal));
if (NS_WARN_IF(NS_FAILED(rv))) {
app->GetPrincipal(getter_AddRefs(principal));
if (NS_WARN_IF(!principal)) {
return;
}

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

@ -354,9 +354,11 @@ OutputStreamManager::Disconnect()
}
}
DecodedStream::DecodedStream(MediaQueue<MediaData>& aAudioQueue,
DecodedStream::DecodedStream(AbstractThread* aOwnerThread,
MediaQueue<MediaData>& aAudioQueue,
MediaQueue<MediaData>& aVideoQueue)
: mMonitor("DecodedStream::mMonitor")
: mOwnerThread(aOwnerThread)
, mMonitor("DecodedStream::mMonitor")
, mPlaying(false)
, mVolume(1.0)
, mAudioQueue(aAudioQueue)
@ -372,11 +374,13 @@ DecodedStream::~DecodedStream()
nsRefPtr<GenericPromise>
DecodedStream::StartPlayback(int64_t aStartTime, const MediaInfo& aInfo)
{
AssertOwnerThread();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
MOZ_ASSERT(mStartTime.isNothing(), "playback already started.");
mStartTime.emplace(aStartTime);
mInfo = aInfo;
ConnectListener();
class R : public nsRunnable {
typedef MozPromiseHolder<GenericPromise> Promise;
@ -408,12 +412,15 @@ DecodedStream::StartPlayback(int64_t aStartTime, const MediaInfo& aInfo)
void DecodedStream::StopPlayback()
{
AssertOwnerThread();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
// Playback didn't even start at all.
if (mStartTime.isNothing()) {
return;
}
mStartTime.reset();
DisconnectListener();
// Clear mData immediately when this playback session ends so we won't
// send data to the wrong stream in SendData() in next playback session.
@ -451,6 +458,19 @@ DecodedStream::CreateData(MozPromiseHolder<GenericPromise>&& aPromise)
auto source = mOutputStreamManager.Graph()->CreateSourceStream(nullptr);
mData.reset(new DecodedStreamData(source, mPlaying, Move(aPromise)));
mOutputStreamManager.Connect(mData->mStream);
// Start to send data to the stream immediately
nsRefPtr<DecodedStream> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
ReentrantMonitorAutoEnter mon(self->GetReentrantMonitor());
// Don't send data if playback has ended.
if (self->mStartTime.isSome()) {
self->SendData();
}
});
// Don't assert success because the owner thread might have begun shutdown
// while we are still dealing with jobs on the main thread.
mOwnerThread->Dispatch(r.forget(), AbstractThread::DontAssertDispatchSuccess);
}
bool
@ -480,6 +500,7 @@ DecodedStream::RemoveOutput(MediaStream* aStream)
void
DecodedStream::SetPlaying(bool aPlaying)
{
AssertOwnerThread();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mPlaying = aPlaying;
if (mData) {
@ -490,6 +511,7 @@ DecodedStream::SetPlaying(bool aPlaying)
void
DecodedStream::SetVolume(double aVolume)
{
AssertOwnerThread();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mVolume = aVolume;
}
@ -497,6 +519,7 @@ DecodedStream::SetVolume(double aVolume)
void
DecodedStream::SetSameOrigin(bool aSameOrigin)
{
AssertOwnerThread();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mSameOrigin = aSameOrigin;
}
@ -504,6 +527,7 @@ DecodedStream::SetSameOrigin(bool aSameOrigin)
void
DecodedStream::InitTracks()
{
AssertOwnerThread();
GetReentrantMonitor().AssertCurrentThreadIn();
if (mData->mStreamInitialized) {
@ -584,6 +608,7 @@ SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime,
void
DecodedStream::SendAudio(double aVolume, bool aIsSameOrigin)
{
AssertOwnerThread();
GetReentrantMonitor().AssertCurrentThreadIn();
if (!mInfo.HasAudio()) {
@ -649,6 +674,7 @@ ZeroDurationAtLastChunk(VideoSegment& aInput)
void
DecodedStream::SendVideo(bool aIsSameOrigin)
{
AssertOwnerThread();
GetReentrantMonitor().AssertCurrentThreadIn();
if (!mInfo.HasVideo()) {
@ -727,6 +753,7 @@ DecodedStream::SendVideo(bool aIsSameOrigin)
void
DecodedStream::AdvanceTracks()
{
AssertOwnerThread();
GetReentrantMonitor().AssertCurrentThreadIn();
StreamTime endPosition = 0;
@ -751,6 +778,7 @@ DecodedStream::AdvanceTracks()
void
DecodedStream::SendData()
{
AssertOwnerThread();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
MOZ_ASSERT(mStartTime.isSome(), "Must be called after StartPlayback()");
@ -781,6 +809,7 @@ DecodedStream::SendData()
int64_t
DecodedStream::AudioEndTime() const
{
AssertOwnerThread();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
if (mStartTime.isSome() && mInfo.HasAudio() && mData) {
CheckedInt64 t = mStartTime.ref() +
@ -795,6 +824,7 @@ DecodedStream::AudioEndTime() const
int64_t
DecodedStream::GetPosition() const
{
AssertOwnerThread();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
// This is only called after MDSM starts playback. So mStartTime is
// guaranteed to be something.
@ -805,8 +835,37 @@ DecodedStream::GetPosition() const
bool
DecodedStream::IsFinished() const
{
AssertOwnerThread();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
return mData && mData->IsFinished();
}
void
DecodedStream::ConnectListener()
{
AssertOwnerThread();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mAudioPushListener = mAudioQueue.PushEvent().Connect(
mOwnerThread, this, &DecodedStream::SendData);
mAudioFinishListener = mAudioQueue.FinishEvent().Connect(
mOwnerThread, this, &DecodedStream::SendData);
mVideoPushListener = mVideoQueue.PushEvent().Connect(
mOwnerThread, this, &DecodedStream::SendData);
mVideoFinishListener = mVideoQueue.FinishEvent().Connect(
mOwnerThread, this, &DecodedStream::SendData);
}
void
DecodedStream::DisconnectListener()
{
AssertOwnerThread();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mAudioPushListener.Disconnect();
mVideoPushListener.Disconnect();
mAudioFinishListener.Disconnect();
mVideoFinishListener.Disconnect();
}
} // namespace mozilla

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

@ -8,8 +8,10 @@
#define DecodedStream_h_
#include "nsTArray.h"
#include "MediaEventSource.h"
#include "MediaInfo.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Maybe.h"
#include "mozilla/MozPromise.h"
@ -100,7 +102,8 @@ private:
class DecodedStream {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodedStream);
public:
DecodedStream(MediaQueue<MediaData>& aAudioQueue,
DecodedStream(AbstractThread* aOwnerThread,
MediaQueue<MediaData>& aAudioQueue,
MediaQueue<MediaData>& aVideoQueue);
// Mimic MDSM::StartAudioThread.
@ -125,8 +128,6 @@ public:
bool IsFinished() const;
bool HasConsumers() const;
void SendData();
protected:
virtual ~DecodedStream();
@ -137,6 +138,16 @@ private:
void AdvanceTracks();
void SendAudio(double aVolume, bool aIsSameOrigin);
void SendVideo(bool aIsSameOrigin);
void SendData();
void AssertOwnerThread() const {
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
}
void ConnectListener();
void DisconnectListener();
const nsRefPtr<AbstractThread> mOwnerThread;
UniquePtr<DecodedStreamData> mData;
// Data about MediaStreams that are being fed by the decoder.
@ -160,6 +171,11 @@ private:
MediaQueue<MediaData>& mAudioQueue;
MediaQueue<MediaData>& mVideoQueue;
MediaEventListener mAudioPushListener;
MediaEventListener mVideoPushListener;
MediaEventListener mAudioFinishListener;
MediaEventListener mVideoFinishListener;
};
} // namespace mozilla

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

@ -221,7 +221,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mSentLoadedMetadataEvent(false),
mSentFirstFrameLoadedEvent(false),
mSentPlaybackEndedEvent(false),
mDecodedStream(new DecodedStream(mAudioQueue, mVideoQueue)),
mDecodedStream(new DecodedStream(mTaskQueue, mAudioQueue, mVideoQueue)),
mResource(aDecoder->GetResource()),
mBuffered(mTaskQueue, TimeIntervals(),
"MediaDecoderStateMachine::mBuffered (Mirror)"),
@ -369,14 +369,12 @@ int64_t MediaDecoderStateMachine::GetDecodedAudioDuration()
return audioDecoded;
}
void MediaDecoderStateMachine::SendStreamData()
void MediaDecoderStateMachine::DiscardStreamData()
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
MOZ_ASSERT(!mAudioSink, "Should've been stopped in RunStateMachine()");
mDecodedStream->SendData();
const auto clockTime = GetClock();
while (true) {
const MediaData* a = AudioQueue().PeekFront();
@ -568,10 +566,6 @@ MediaDecoderStateMachine::OnAudioDecoded(AudioData* aAudioSample)
if (mIsAudioPrerolling && DonePrerollingAudio()) {
StopPrerollingAudio();
}
// Schedule the state machine to send stream data as soon as possible.
if (mAudioCaptured) {
ScheduleStateMachine();
}
return;
}
@ -767,10 +761,6 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
return;
}
CheckIfDecodeComplete();
// Schedule the state machine to notify track ended as soon as possible.
if (mAudioCaptured) {
ScheduleStateMachine();
}
return;
}
case DECODER_STATE_SEEKING: {
@ -857,7 +847,7 @@ MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
// frame pushed in the queue, schedule the state machine as soon as
// possible to render the video frame or delay the state machine thread
// accurately.
if (mAudioCaptured || VideoQueue().GetSize() == 1) {
if (VideoQueue().GetSize() == 1) {
ScheduleStateMachine();
}
@ -2651,7 +2641,7 @@ void MediaDecoderStateMachine::UpdateRenderedVideoFrames()
}
if (mAudioCaptured) {
SendStreamData();
DiscardStreamData();
}
TimeStamp nowTime;

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

@ -323,10 +323,8 @@ public:
mDecoder = nullptr;
}
// Copy queued audio/video data in the reader to any output MediaStreams that
// need it.
void SendStreamData();
void FinishStreamData();
// Discard audio/video data that are already played by MSG.
void DiscardStreamData();
bool HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs);
bool HaveEnoughDecodedVideo();

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

@ -76,7 +76,7 @@ struct EventTypeTraits<void> {
* Test if a method function or lambda accepts one or more arguments.
*/
template <typename T>
class TakeArgs {
class TakeArgsHelper {
template <typename C> static FalseType test(void(C::*)(), int);
template <typename C> static FalseType test(void(C::*)() const, int);
template <typename C> static FalseType test(void(C::*)() volatile, int);
@ -87,6 +87,9 @@ public:
typedef decltype(test(DeclVal<T>(), 0)) Type;
};
template <typename T>
struct TakeArgs : public TakeArgsHelper<T>::Type {};
template <typename T> struct EventTarget;
template <>
@ -118,6 +121,193 @@ private:
T* const mPtr;
};
/**
* A helper class to pass event data to the listeners. Optimized to save
* copy when Move is possible or |Function| takes no arguments.
*/
template<typename Target, typename Function>
class ListenerHelper {
// Define our custom runnable to minimize copy of the event data.
// NS_NewRunnableFunction will result in 2 copies of the event data.
// One is captured by the lambda and the other is the copy of the lambda.
template <typename T>
class R : public nsRunnable {
typedef typename RemoveCV<typename RemoveReference<T>::Type>::Type ArgType;
public:
template <typename U>
R(RevocableToken* aToken, const Function& aFunction, U&& aEvent)
: mToken(aToken), mFunction(aFunction), mEvent(Forward<U>(aEvent)) {}
NS_IMETHOD Run() override {
// Don't call the listener if it is disconnected.
if (!mToken->IsRevoked()) {
// Enable move whenever possible since mEvent won't be used anymore.
mFunction(Move(mEvent));
}
return NS_OK;
}
private:
nsRefPtr<RevocableToken> mToken;
Function mFunction;
ArgType mEvent;
};
public:
ListenerHelper(RevocableToken* aToken, Target* aTarget, const Function& aFunc)
: mToken(aToken), mTarget(aTarget), mFunction(aFunc) {}
// |F| takes one argument.
template <typename F, typename T>
typename EnableIf<TakeArgs<F>::value, void>::Type
Dispatch(const F& aFunc, T&& aEvent) {
nsCOMPtr<nsIRunnable> r = new R<T>(mToken, aFunc, Forward<T>(aEvent));
EventTarget<Target>::Dispatch(mTarget.get(), r.forget());
}
// |F| takes no arguments. Don't bother passing aEvent.
template <typename F, typename T>
typename EnableIf<!TakeArgs<F>::value, void>::Type
Dispatch(const F& aFunc, T&&) {
const nsRefPtr<RevocableToken>& token = mToken;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
// Don't call the listener if it is disconnected.
if (!token->IsRevoked()) {
aFunc();
}
});
EventTarget<Target>::Dispatch(mTarget.get(), r.forget());
}
template <typename T>
void Dispatch(T&& aEvent) {
Dispatch(mFunction, Forward<T>(aEvent));
}
private:
nsRefPtr<RevocableToken> mToken;
const nsRefPtr<Target> mTarget;
Function mFunction;
};
/**
* Define whether an event data should be copied or moved to the listeners.
*
* @Copy Data will always be copied. Each listener gets a copy.
* @Move Data will always be moved.
* @Both Data will be moved when possible or copied when necessary.
*/
enum class EventPassMode : int8_t {
Copy,
Move,
Both
};
class ListenerBase {
public:
ListenerBase() : mToken(new RevocableToken()) {}
~ListenerBase() {
MOZ_ASSERT(Token()->IsRevoked(), "Must disconnect the listener.");
}
RevocableToken* Token() const {
return mToken;
}
private:
const nsRefPtr<RevocableToken> mToken;
};
/**
* Stored by MediaEventSource to send notifications to the listener.
* Since virtual methods can not be templated, this class is specialized
* to provide different Dispatch() overloads depending on EventPassMode.
*/
template <typename ArgType, EventPassMode Mode = EventPassMode::Copy>
class Listener : public ListenerBase {
public:
virtual ~Listener() {}
virtual void Dispatch(const ArgType& aEvent) = 0;
};
template <typename ArgType>
class Listener<ArgType, EventPassMode::Both> : public ListenerBase {
public:
virtual ~Listener() {}
virtual void Dispatch(const ArgType& aEvent) = 0;
virtual void Dispatch(ArgType&& aEvent) = 0;
};
template <typename ArgType>
class Listener<ArgType, EventPassMode::Move> : public ListenerBase {
public:
virtual ~Listener() {}
virtual void Dispatch(ArgType&& aEvent) = 0;
};
/**
* Store the registered target thread and function so it knows where and to
* whom to send the event data.
*/
template <typename Target, typename Function, typename ArgType, EventPassMode>
class ListenerImpl : public Listener<ArgType, EventPassMode::Copy> {
public:
ListenerImpl(Target* aTarget, const Function& aFunction)
: mHelper(ListenerBase::Token(), aTarget, aFunction) {}
void Dispatch(const ArgType& aEvent) override {
mHelper.Dispatch(aEvent);
}
private:
ListenerHelper<Target, Function> mHelper;
};
template <typename Target, typename Function, typename ArgType>
class ListenerImpl<Target, Function, ArgType, EventPassMode::Both>
: public Listener<ArgType, EventPassMode::Both> {
public:
ListenerImpl(Target* aTarget, const Function& aFunction)
: mHelper(ListenerBase::Token(), aTarget, aFunction) {}
void Dispatch(const ArgType& aEvent) override {
mHelper.Dispatch(aEvent);
}
void Dispatch(ArgType&& aEvent) override {
mHelper.Dispatch(Move(aEvent));
}
private:
ListenerHelper<Target, Function> mHelper;
};
template <typename Target, typename Function, typename ArgType>
class ListenerImpl<Target, Function, ArgType, EventPassMode::Move>
: public Listener<ArgType, EventPassMode::Move> {
public:
ListenerImpl(Target* aTarget, const Function& aFunction)
: mHelper(ListenerBase::Token(), aTarget, aFunction) {}
void Dispatch(ArgType&& aEvent) override {
mHelper.Dispatch(Move(aEvent));
}
private:
ListenerHelper<Target, Function> mHelper;
};
/**
* Select EventPassMode based on ListenerMode and if the type is copyable.
*
* @Copy Selected when ListenerMode is NonExclusive because each listener
* must get a copy.
*
* @Move Selected when ListenerMode is Exclusive and the type is move-only.
*
* @Both Selected when ListenerMode is Exclusive and the type is copyable.
* The data will be moved when possible and copied when necessary.
*/
template <typename ArgType, ListenerMode Mode>
struct PassModePicker {
// TODO: pick EventPassMode::Both when we can detect if a type is
// copy-constructible to allow copy-only types in Exclusive mode.
static const EventPassMode Value =
Mode == ListenerMode::NonExclusive ?
EventPassMode::Copy : EventPassMode::Move;
};
} // namespace detail
template <typename T, ListenerMode> class MediaEventSource;
@ -167,89 +357,15 @@ template <typename EventType, ListenerMode Mode = ListenerMode::NonExclusive>
class MediaEventSource {
static_assert(!IsReference<EventType>::value, "Ref-type not supported!");
typedef typename detail::EventTypeTraits<EventType>::ArgType ArgType;
static const detail::EventPassMode PassMode
= detail::PassModePicker<ArgType, Mode>::Value;
typedef detail::Listener<ArgType, PassMode> Listener;
/**
* Stored by MediaEventSource to send notifications to the listener.
*/
class Listener {
public:
Listener() : mToken(new RevocableToken()) {}
template<typename Target, typename Func>
using ListenerImpl = detail::ListenerImpl<Target, Func, ArgType, PassMode>;
virtual ~Listener() {
MOZ_ASSERT(Token()->IsRevoked(), "Must disconnect the listener.");
}
virtual void Dispatch(const ArgType& aEvent) = 0;
RevocableToken* Token() const {
return mToken;
}
private:
const nsRefPtr<RevocableToken> mToken;
};
/**
* Store the registered target thread and function so it knows where and to
* whom to send the event data.
*/
template<typename Target, typename Function>
class ListenerImpl : public Listener {
public:
explicit ListenerImpl(Target* aTarget, const Function& aFunction)
: mTarget(aTarget), mFunction(aFunction) {}
// |Function| takes one argument.
void Dispatch(const ArgType& aEvent, TrueType) {
// Define our custom runnable to minimize copy of the event data.
// NS_NewRunnableFunction will result in 2 copies of the event data.
// One is captured by the lambda and the other is the copy of the lambda.
class R : public nsRunnable {
public:
R(RevocableToken* aToken,
const Function& aFunction, const ArgType& aEvent)
: mToken(aToken), mFunction(aFunction), mEvent(aEvent) {}
NS_IMETHOD Run() override {
// Don't call the listener if it is disconnected.
if (!mToken->IsRevoked()) {
// Enable move whenever possible since mEvent won't be used anymore.
mFunction(Move(mEvent));
}
return NS_OK;
}
private:
nsRefPtr<RevocableToken> mToken;
Function mFunction;
ArgType mEvent;
};
nsCOMPtr<nsIRunnable> r = new R(this->Token(), mFunction, aEvent);
detail::EventTarget<Target>::Dispatch(mTarget.get(), r.forget());
}
// |Function| takes no arguments. Don't bother passing aEvent.
void Dispatch(const ArgType& aEvent, FalseType) {
nsRefPtr<RevocableToken> token = this->Token();
const Function& function = mFunction;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
// Don't call the listener if it is disconnected.
if (!token->IsRevoked()) {
function();
}
});
detail::EventTarget<Target>::Dispatch(mTarget.get(), r.forget());
}
void Dispatch(const ArgType& aEvent) override {
Dispatch(aEvent, typename detail::TakeArgs<Function>::Type());
}
private:
const nsRefPtr<Target> mTarget;
Function mFunction;
};
template <typename Method>
using TakeArgs = detail::TakeArgs<Method>;
template<typename Target, typename Function>
MediaEventListener
@ -263,8 +379,8 @@ class MediaEventSource {
// |Method| takes one argument.
template <typename Target, typename This, typename Method>
MediaEventListener
ConnectInternal(Target* aTarget, This* aThis, Method aMethod, TrueType) {
typename EnableIf<TakeArgs<Method>::value, MediaEventListener>::Type
ConnectInternal(Target* aTarget, This* aThis, Method aMethod) {
detail::RawPtr<This> thiz(aThis);
auto f = [=] (ArgType&& aEvent) {
(thiz.get()->*aMethod)(Move(aEvent));
@ -274,8 +390,8 @@ class MediaEventSource {
// |Method| takes no arguments. Don't bother passing the event data.
template <typename Target, typename This, typename Method>
MediaEventListener
ConnectInternal(Target* aTarget, This* aThis, Method aMethod, FalseType) {
typename EnableIf<!TakeArgs<Method>::value, MediaEventListener>::Type
ConnectInternal(Target* aTarget, This* aThis, Method aMethod) {
detail::RawPtr<This> thiz(aThis);
auto f = [=] () {
(thiz.get()->*aMethod)();
@ -318,21 +434,20 @@ public:
template <typename This, typename Method>
MediaEventListener
Connect(AbstractThread* aTarget, This* aThis, Method aMethod) {
return ConnectInternal(aTarget, aThis, aMethod,
typename detail::TakeArgs<Method>::Type());
return ConnectInternal(aTarget, aThis, aMethod);
}
template <typename This, typename Method>
MediaEventListener
Connect(nsIEventTarget* aTarget, This* aThis, Method aMethod) {
return ConnectInternal(aTarget, aThis, aMethod,
typename detail::TakeArgs<Method>::Type());
return ConnectInternal(aTarget, aThis, aMethod);
}
protected:
MediaEventSource() : mMutex("MediaEventSource::mMutex") {}
void NotifyInternal(const ArgType& aEvent) {
template <typename T>
void NotifyInternal(T&& aEvent) {
MutexAutoLock lock(mMutex);
for (int32_t i = mListeners.Length() - 1; i >= 0; --i) {
auto&& l = mListeners[i];
@ -342,7 +457,7 @@ protected:
mListeners.RemoveElementAt(i);
continue;
}
l->Dispatch(aEvent);
l->Dispatch(Forward<T>(aEvent));
}
}
@ -359,8 +474,9 @@ private:
template <typename EventType, ListenerMode Mode = ListenerMode::NonExclusive>
class MediaEventProducer : public MediaEventSource<EventType, Mode> {
public:
void Notify(const EventType& aEvent) {
this->NotifyInternal(aEvent);
template <typename T>
void Notify(T&& aEvent) {
this->NotifyInternal(Forward<T>(aEvent));
}
};

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

@ -783,6 +783,7 @@ MediaFormatReader::NotifyNewOutput(TrackType aTrack, MediaData* aSample)
}
decoder.mOutput.AppendElement(aSample);
decoder.mNumSamplesOutput++;
decoder.mNumSamplesOutputTotal++;
ScheduleUpdate(aTrack);
}
@ -1120,9 +1121,9 @@ MediaFormatReader::Update(TrackType aTrack)
if (aTrack == TrackInfo::kVideoTrack) {
uint64_t delta =
decoder.mNumSamplesOutput - mLastReportedNumDecodedFrames;
decoder.mNumSamplesOutputTotal - mLastReportedNumDecodedFrames;
a.mDecoded = static_cast<uint32_t>(delta);
mLastReportedNumDecodedFrames = decoder.mNumSamplesOutput;
mLastReportedNumDecodedFrames = decoder.mNumSamplesOutputTotal;
}
if (decoder.HasPromise()) {

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

@ -206,6 +206,7 @@ private:
, mDrainComplete(false)
, mNumSamplesInput(0)
, mNumSamplesOutput(0)
, mNumSamplesOutputTotal(0)
, mSizeOfQueue(0)
, mIsHardwareAccelerated(false)
, mLastStreamSourceID(UINT32_MAX)
@ -263,6 +264,7 @@ private:
nsTArray<nsRefPtr<MediaData>> mOutput;
uint64_t mNumSamplesInput;
uint64_t mNumSamplesOutput;
uint64_t mNumSamplesOutputTotal;
// These get overriden in the templated concrete class.
// Indicate if we have a pending promise for decoded frame.

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

@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "XiphExtradata.h"
namespace mozilla {
bool XiphHeadersToExtradata(MediaByteBuffer* aCodecSpecificConfig,
const nsTArray<const unsigned char*>& aHeaders,
const nsTArray<size_t>& aHeaderLens)
{
size_t nheaders = aHeaders.Length();
if (!nheaders || nheaders > 255) return false;
aCodecSpecificConfig->AppendElement(nheaders - 1);
for (size_t i = 0; i < nheaders - 1; i++) {
size_t headerLen;
for (headerLen = aHeaderLens[i]; headerLen >= 255; headerLen -= 255) {
aCodecSpecificConfig->AppendElement(255);
}
aCodecSpecificConfig->AppendElement(headerLen);
}
for (size_t i = 0; i < nheaders; i++) {
aCodecSpecificConfig->AppendElements(aHeaders[i], aHeaderLens[i]);
}
return true;
}
bool XiphExtradataToHeaders(nsTArray<unsigned char*>& aHeaders,
nsTArray<size_t>& aHeaderLens,
unsigned char* aData,
size_t aAvailable)
{
size_t total = 0;
if (aAvailable < 1) {
return false;
}
aAvailable--;
int nHeaders = *aData++ + 1;
for (int i = 0; i < nHeaders - 1; i++) {
size_t headerLen = 0;
for (;;) {
// After this test, we know that (aAvailable - total > headerLen) and
// (headerLen >= 0) so (aAvailable - total > 0). The loop decrements
// aAvailable by 1 and total remains fixed, so we know that in the next
// iteration (aAvailable - total >= 0). Thus (aAvailable - total) can
// never underflow.
if (aAvailable - total <= headerLen) {
return false;
}
// Since we know (aAvailable > total + headerLen), this can't overflow
// unless total is near 0 and both aAvailable and headerLen are within
// 255 bytes of the maximum representable size. However, that is
// impossible, since we would have had to have gone through this loop
// more than 255 times to make headerLen that large, and thus decremented
// aAvailable more than 255 times.
headerLen += *aData;
aAvailable--;
if (*aData++ != 255) break;
}
// And this check ensures updating total won't cause (aAvailable - total)
// to underflow.
if (aAvailable - total < headerLen) {
return false;
}
aHeaderLens.AppendElement(headerLen);
// Since we know aAvailable >= total + headerLen, this can't overflow.
total += headerLen;
}
aHeaderLens.AppendElement(aAvailable);
for (int i = 0; i < nHeaders; i++) {
aHeaders.AppendElement(aData);
aData += aHeaderLens[i];
}
return true;
}
} // namespace mozilla

28
dom/media/XiphExtradata.h Normal file
Просмотреть файл

@ -0,0 +1,28 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(XiphExtradata_h)
#define XiphExtradata_h
#include "MediaData.h"
namespace mozilla {
/* This converts a list of headers to the canonical form of extradata for Xiph
codecs in non-Ogg containers. We use it to pass those headers from demuxer
to decoder even when demuxing from an Ogg cotainer. */
bool XiphHeadersToExtradata(MediaByteBuffer* aCodecSpecificConfig,
const nsTArray<const unsigned char*>& aHeaders,
const nsTArray<size_t>& aHeaderLens);
/* This converts a set of extradata back into a list of headers. */
bool XiphExtradataToHeaders(nsTArray<unsigned char*>& aHeaders,
nsTArray<size_t>& aHeaderLens,
unsigned char* aData,
size_t aAvailable);
} // namespace mozilla
#endif // XiphExtradata_h

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

@ -6,6 +6,7 @@
#include "gtest/gtest.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/UniquePtr.h"
#include "MediaEventSource.h"
#include "VideoUtils.h"
@ -294,3 +295,29 @@ TEST(MediaEventSource, CopyEvent2)
listener1.Disconnect();
listener2.Disconnect();
}
/*
* Test move-only types.
*/
TEST(MediaEventSource, MoveOnly)
{
nsRefPtr<TaskQueue> queue = new TaskQueue(
GetMediaThreadPool(MediaThreadType::PLAYBACK));
MediaEventProducer<UniquePtr<int>, ListenerMode::Exclusive> source;
auto func = [] (UniquePtr<int>&& aEvent) {
EXPECT_EQ(*aEvent, 20);
};
MediaEventListener listener = source.Connect(queue, func);
// It is OK to pass an rvalue which is move-only.
source.Notify(UniquePtr<int>(new int(20)));
// It is an error to pass an lvalue which is move-only.
// UniquePtr<int> event(new int(30));
// source.Notify(event);
queue->BeginShutdown();
queue->AwaitShutdownAndIdle();
listener.Disconnect();
}

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

@ -11,6 +11,7 @@
#include "mozilla/ErrorResult.h"
#include "mp4_demuxer/MoofParser.h"
#include "mozilla/Logging.h"
#include "mozilla/Maybe.h"
#include "MediaData.h"
#ifdef MOZ_FMP4
#include "MP4Stream.h"
@ -177,16 +178,6 @@ public:
(*aData)[3] == 0x6b) {
return true;
}
// 0xa3 // SimpleBlock
if (aData->Length() >= 1 &&
(*aData)[0] == 0xa3) {
return true;
}
// 0xa1 // Block
if (aData->Length() >= 1 &&
(*aData)[0] == 0xa1) {
return true;
}
return false;
}
@ -194,6 +185,19 @@ public:
int64_t& aStart, int64_t& aEnd) override
{
bool initSegment = IsInitSegmentPresent(aData);
if (mLastMapping && (initSegment || IsMediaSegmentPresent(aData))) {
// The last data contained a complete cluster but we can only detect it
// now that a new one is starting.
// We use mOffset as end position to ensure that any blocks not reported
// by WebMBufferParser are properly skipped.
mCompleteMediaSegmentRange = MediaByteRange(mLastMapping.ref().mSyncOffset,
mOffset);
mLastMapping.reset();
MSE_DEBUG(WebMContainerParser, "New cluster found at start, ending previous one");
return false;
}
if (initSegment) {
mOffset = 0;
mParser = WebMBufferedParser(0);
@ -242,38 +246,66 @@ public:
return false;
}
// Calculate media range for first media segment.
// Check if we have a cluster finishing in the current data.
uint32_t endIdx = mapping.Length() - 1;
// Calculate media range for first media segment
uint32_t segmentEndIdx = endIdx;
while (mapping[0].mSyncOffset != mapping[segmentEndIdx].mSyncOffset) {
segmentEndIdx -= 1;
}
if (segmentEndIdx > 0 && mOffset >= mapping[segmentEndIdx].mEndOffset) {
mCompleteMediaHeaderRange = MediaByteRange(mParser.mInitEndOffset,
mapping[0].mEndOffset);
mCompleteMediaSegmentRange = MediaByteRange(mParser.mInitEndOffset,
mapping[segmentEndIdx].mEndOffset);
}
// Exclude frames that we don't have enough data to cover the end of.
while (mOffset < mapping[endIdx].mEndOffset && endIdx > 0) {
bool foundNewCluster = false;
while (mapping[0].mSyncOffset != mapping[endIdx].mSyncOffset) {
endIdx -= 1;
foundNewCluster = true;
}
if (endIdx == 0) {
int32_t completeIdx = endIdx;
while (completeIdx >= 0 && mOffset < mapping[completeIdx].mEndOffset) {
MSE_DEBUG(WebMContainerParser, "block is incomplete, missing: %lld",
mapping[completeIdx].mEndOffset - mOffset);
completeIdx -= 1;
}
// Save parsed blocks for which we do not have all data yet.
mOverlappedMapping.AppendElements(mapping.Elements() + completeIdx + 1,
mapping.Length() - completeIdx - 1);
if (completeIdx < 0) {
mLastMapping.reset();
return false;
}
uint64_t frameDuration = mapping[endIdx].mTimecode - mapping[endIdx - 1].mTimecode;
if (mCompleteMediaHeaderRange.IsNull()) {
mCompleteMediaHeaderRange = MediaByteRange(mapping[0].mSyncOffset,
mapping[0].mEndOffset);
}
mLastMapping = Some(mapping[completeIdx]);
if (foundNewCluster && mOffset >= mapping[endIdx].mEndOffset) {
// We now have all information required to delimit a complete cluster.
int64_t endOffset = mapping[endIdx+1].mSyncOffset;
if (mapping[endIdx+1].mInitOffset > mapping[endIdx].mInitOffset) {
// We have a new init segment before this cluster.
endOffset = mapping[endIdx+1].mInitOffset;
}
mCompleteMediaSegmentRange = MediaByteRange(mapping[endIdx].mSyncOffset,
endOffset);
} else if (mapping[endIdx].mClusterEndOffset >= 0 &&
mOffset >= mapping[endIdx].mClusterEndOffset) {
mCompleteMediaSegmentRange = MediaByteRange(mapping[endIdx].mSyncOffset,
mParser.EndSegmentOffset(mapping[endIdx].mClusterEndOffset));
}
if (!completeIdx) {
return false;
}
uint64_t frameDuration =
mapping[completeIdx].mTimecode - mapping[completeIdx - 1].mTimecode;
aStart = mapping[0].mTimecode / NS_PER_USEC;
aEnd = (mapping[endIdx].mTimecode + frameDuration) / NS_PER_USEC;
aEnd = (mapping[completeIdx].mTimecode + frameDuration) / NS_PER_USEC;
MSE_DEBUG(WebMContainerParser, "[%lld, %lld] [fso=%lld, leo=%lld, l=%u endIdx=%u]",
aStart, aEnd, mapping[0].mSyncOffset, mapping[endIdx].mEndOffset, mapping.Length(), endIdx);
mapping.RemoveElementsAt(0, endIdx + 1);
mOverlappedMapping.AppendElements(mapping);
MSE_DEBUG(WebMContainerParser, "[%lld, %lld] [fso=%lld, leo=%lld, l=%u processedIdx=%u fs=%lld]",
aStart, aEnd, mapping[0].mSyncOffset,
mapping[completeIdx].mEndOffset, mapping.Length(), completeIdx,
mCompleteMediaSegmentRange.mEnd);
return true;
}
@ -288,6 +320,7 @@ private:
WebMBufferedParser mParser;
nsTArray<WebMTimeDataOffset> mOverlappedMapping;
int64_t mOffset;
Maybe<WebMTimeDataOffset> mLastMapping;
};
#ifdef MOZ_FMP4

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

@ -100,6 +100,11 @@ public:
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
virtual bool IsExpectingMoreData() override
{
return false;
}
// Used by SourceBuffer.
void AppendData(MediaByteBuffer* aData);
void Ended();

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

@ -97,6 +97,7 @@ TrackBuffersManager::TrackBuffersManager(dom::SourceBufferAttributes* aAttribute
, mAppendState(AppendState::WAITING_FOR_SEGMENT)
, mBufferFull(false)
, mFirstInitializationSegmentReceived(false)
, mNewSegmentStarted(false)
, mActiveTrack(false)
, mType(aType)
, mParser(ContainerParser::CreateForMIMEType(aType))
@ -655,10 +656,12 @@ TrackBuffersManager::SegmentParserLoop()
// This is a new initialization segment. Obsolete the old one.
RecreateParser(false);
}
mNewSegmentStarted = true;
continue;
}
if (mParser->IsMediaSegmentPresent(mInputBuffer)) {
SetAppendState(AppendState::PARSING_MEDIA_SEGMENT);
mNewSegmentStarted = true;
continue;
}
// We have neither an init segment nor a media segment, this is either
@ -669,7 +672,7 @@ TrackBuffersManager::SegmentParserLoop()
}
int64_t start, end;
mParser->ParseStartAndEndTimestamps(mInputBuffer, start, end);
bool newData = mParser->ParseStartAndEndTimestamps(mInputBuffer, start, end);
mProcessedInput += mInputBuffer->Length();
// 5. If the append state equals PARSING_INIT_SEGMENT, then run the
@ -696,6 +699,22 @@ TrackBuffersManager::SegmentParserLoop()
NeedMoreData();
return;
}
// We can't feed some demuxers (WebMDemuxer) with data that do not have
// monotonizally increasing timestamps. So we check if we have a
// discontinuity from the previous segment parsed.
// If so, recreate a new demuxer to ensure that the demuxer is only fed
// monotonically increasing data.
if (newData) {
if (mNewSegmentStarted && mLastParsedEndTime.isSome() &&
start < mLastParsedEndTime.ref().ToMicroseconds()) {
ResetDemuxingState();
return;
}
mNewSegmentStarted = false;
mLastParsedEndTime = Some(TimeUnit::FromMicroseconds(end));
}
// 3. If the input buffer contains one or more complete coded frames, then run the coded frame processing algorithm.
nsRefPtr<TrackBuffersManager> self = this;
mProcessingRequest.Begin(CodedFrameProcessing()
@ -756,6 +775,7 @@ TrackBuffersManager::ShutdownDemuxers()
mAudioTracks.mDemuxer = nullptr;
}
mInputDemuxer = nullptr;
mLastParsedEndTime.reset();
}
void
@ -780,6 +800,58 @@ TrackBuffersManager::CreateDemuxerforMIMEType()
return;
}
// We reset the demuxer by creating a new one and initializing it.
void
TrackBuffersManager::ResetDemuxingState()
{
MOZ_ASSERT(mParser && mParser->HasInitData());
RecreateParser(true);
mCurrentInputBuffer = new SourceBufferResource(mType);
// The demuxer isn't initialized yet ; we don't want to notify it
// that data has been appended yet ; so we simply append the init segment
// to the resource.
mCurrentInputBuffer->AppendData(mParser->InitData());
CreateDemuxerforMIMEType();
if (!mInputDemuxer) {
RejectAppend(NS_ERROR_FAILURE, __func__);
return;
}
mDemuxerInitRequest.Begin(mInputDemuxer->Init()
->Then(GetTaskQueue(), __func__,
this,
&TrackBuffersManager::OnDemuxerResetDone,
&TrackBuffersManager::OnDemuxerInitFailed));
}
void
TrackBuffersManager::OnDemuxerResetDone(nsresult)
{
MOZ_ASSERT(OnTaskQueue());
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
mDemuxerInitRequest.Complete();
if (mAbort) {
RejectAppend(NS_ERROR_ABORT, __func__);
return;
}
// Recreate track demuxers.
uint32_t numVideos = mInputDemuxer->GetNumberTracks(TrackInfo::kVideoTrack);
if (numVideos) {
// We currently only handle the first video track.
mVideoTracks.mDemuxer = mInputDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
MOZ_ASSERT(mVideoTracks.mDemuxer);
}
uint32_t numAudios = mInputDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
if (numAudios) {
// We currently only handle the first audio track.
mAudioTracks.mDemuxer = mInputDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
MOZ_ASSERT(mAudioTracks.mDemuxer);
}
SegmentParserLoop();
}
void
TrackBuffersManager::AppendDataToCurrentInputBuffer(MediaByteBuffer* aData)
{
@ -1056,6 +1128,14 @@ TrackBuffersManager::CodedFrameProcessing()
// The mediaRange is offset by the init segment position previously added.
uint32_t length =
mediaRange.mEnd - (mProcessedInput - mInputBuffer->Length());
if (!length) {
// We've completed our earlier media segment and no new data is to be
// processed. This happens with some containers that can't detect that a
// media segment is ending until a new one starts.
nsRefPtr<CodedFrameProcessingPromise> p = mProcessingPromise.Ensure(__func__);
CompleteCodedFrameProcessing();
return p;
}
nsRefPtr<MediaByteBuffer> segment = new MediaByteBuffer;
if (!segment->AppendElements(mInputBuffer->Elements(), length, fallible)) {
return CodedFrameProcessingPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);

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

@ -113,6 +113,7 @@ private:
void InitializationSegmentReceived();
void ShutdownDemuxers();
void CreateDemuxerforMIMEType();
void ResetDemuxingState();
void NeedMoreData();
void RejectAppend(nsresult aRejectValue, const char* aName);
// Will return a promise that will be resolved once all frames of the current
@ -151,6 +152,8 @@ private:
// TODO: Unused for now.
Atomic<bool> mBufferFull;
bool mFirstInitializationSegmentReceived;
// Set to true once a new segment is started.
bool mNewSegmentStarted;
bool mActiveTrack;
Maybe<media::TimeUnit> mGroupStartTimestamp;
media::TimeUnit mGroupEndTimestamp;
@ -171,9 +174,11 @@ private:
nsRefPtr<MediaDataDemuxer> mInputDemuxer;
// Length already processed in current media segment.
uint32_t mProcessedInput;
Maybe<media::TimeUnit> mLastParsedEndTime;
void OnDemuxerInitDone(nsresult);
void OnDemuxerInitFailed(DemuxerFailureReason aFailure);
void OnDemuxerResetDone(nsresult);
MozPromiseRequestHolder<MediaDataDemuxer::InitPromise> mDemuxerInitRequest;
bool mEncrypted;

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

@ -149,6 +149,7 @@ EXPORTS += [
'VideoSegment.h',
'VideoUtils.h',
'VorbisUtils.h',
'XiphExtradata.h',
]
EXPORTS.mozilla += [
@ -245,6 +246,7 @@ UNIFIED_SOURCES += [
'VideoTrackList.cpp',
'VideoUtils.cpp',
'WebVTTListener.cpp',
'XiphExtradata.cpp',
]
if CONFIG['OS_TARGET'] == 'WINNT':

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

@ -6,6 +6,7 @@
#include "VorbisDecoder.h"
#include "VorbisUtils.h"
#include "XiphExtradata.h"
#include "mozilla/PodOperations.h"
#include "nsAutoPtr.h"
@ -71,23 +72,17 @@ VorbisDataDecoder::Init()
PodZero(&mVorbisDsp);
PodZero(&mVorbisBlock);
size_t available = mInfo.mCodecSpecificConfig->Length();
uint8_t *p = mInfo.mCodecSpecificConfig->Elements();
for(int i = 0; i < 3; i++) {
if (available < 2) {
nsAutoTArray<unsigned char*,4> headers;
nsAutoTArray<size_t,4> headerLens;
if (!XiphExtradataToHeaders(headers, headerLens,
mInfo.mCodecSpecificConfig->Elements(),
mInfo.mCodecSpecificConfig->Length())) {
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
}
for (size_t i = 0; i < headers.Length(); i++) {
if (NS_FAILED(DecodeHeader(headers[i], headerLens[i]))) {
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
}
available -= 2;
size_t length = BigEndian::readUint16(p);
p += 2;
if (available < length) {
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
}
available -= length;
if (NS_FAILED(DecodeHeader((const unsigned char*)p, length))) {
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
}
p += length;
}
MOZ_ASSERT(mPacketCount == 3);

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

@ -89,7 +89,7 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
mReaderCallback = aCallback;
mReaderTaskQueue = AbstractThread::GetCurrent()->AsTaskQueue();
MOZ_ASSERT(!mReaderTaskQueue);
MOZ_ASSERT(mReaderTaskQueue);
if (mLooper.get() != nullptr) {
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);

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

@ -34,6 +34,7 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
nsTArray<WebMTimeDataOffset>& aMapping,
ReentrantMonitor& aReentrantMonitor)
{
static const uint32_t EBML_ID = 0x1a45dfa3;
static const uint32_t SEGMENT_ID = 0x18538067;
static const uint32_t SEGINFO_ID = 0x1549a966;
static const uint32_t TRACKS_ID = 0x1654AE6B;
@ -102,6 +103,12 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
case CLUSTER_ID:
mClusterOffset = mCurrentOffset + (p - aBuffer) -
(mElement.mID.mLength + mElement.mSize.mLength);
// Handle "unknown" length;
if (mElement.mSize.mValue + 1 != uint64_t(1) << (mElement.mSize.mLength * 7)) {
mClusterEndOffset = mClusterOffset + mElement.mID.mLength + mElement.mSize.mLength + mElement.mSize.mValue;
} else {
mClusterEndOffset = -1;
}
mState = READ_ELEMENT_ID;
break;
case SIMPLEBLOCK_ID:
@ -119,6 +126,10 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
mSkipBytes = mElement.mSize.mValue;
mState = CHECK_INIT_FOUND;
break;
case EBML_ID:
mLastInitStartOffset = mCurrentOffset + (p - aBuffer) -
(mElement.mID.mLength + mElement.mSize.mLength);
/* FALLTHROUGH */
default:
mSkipBytes = mElement.mSize.mValue;
mState = SKIP_DATA;
@ -172,7 +183,8 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
MOZ_ASSERT(mGotTimecodeScale);
uint64_t absTimecode = mClusterTimecode + mBlockTimecode;
absTimecode *= mTimecodeScale;
WebMTimeDataOffset entry(endOffset, absTimecode, mClusterOffset);
WebMTimeDataOffset entry(endOffset, absTimecode, mLastInitStartOffset,
mClusterOffset, mClusterEndOffset);
aMapping.InsertElementAt(idx, entry);
}
}
@ -192,7 +204,9 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
left = std::min(left, mSkipBytes);
p += left;
mSkipBytes -= left;
} else {
}
if (!mSkipBytes) {
mBlockEndOffset = mCurrentOffset + (p - aBuffer);
mState = mNextState;
}
break;
@ -206,6 +220,7 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
if (!mSkipBytes) {
if (mInitEndOffset < 0) {
mInitEndOffset = mCurrentOffset + (p - aBuffer);
mBlockEndOffset = mCurrentOffset + (p - aBuffer);
}
mState = READ_ELEMENT_ID;
}
@ -217,6 +232,16 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
mCurrentOffset += aLength;
}
int64_t
WebMBufferedParser::EndSegmentOffset(int64_t aOffset)
{
if (mLastInitStartOffset > aOffset || mClusterOffset > aOffset) {
return std::min(mLastInitStartOffset >= 0 ? mLastInitStartOffset : INT64_MAX,
mClusterOffset >= 0 ? mClusterOffset : INT64_MAX);
}
return mBlockEndOffset;
}
// SyncOffsetComparator and TimeComparator are slightly confusing, in that
// the nsTArray they're used with (mTimeMapping) is sorted by mEndOffset and
// these comparators are used on the other fields of WebMTimeDataOffset.
@ -344,6 +369,13 @@ void WebMBufferedState::NotifyDataArrived(const unsigned char* aBuffer, uint32_t
i += 1;
}
}
if (mRangeParsers.IsEmpty()) {
return;
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mLastBlockOffset = mRangeParsers.LastElement().mBlockEndOffset;
}
void WebMBufferedState::Reset() {
@ -398,6 +430,13 @@ int64_t WebMBufferedState::GetInitEndOffset()
return mRangeParsers[0].mInitEndOffset;
}
int64_t WebMBufferedState::GetLastBlockOffset()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mLastBlockOffset;
}
bool WebMBufferedState::GetStartTime(uint64_t *aTime)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);

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

@ -17,8 +17,14 @@ namespace mozilla {
// that offset.
struct WebMTimeDataOffset
{
WebMTimeDataOffset(int64_t aEndOffset, uint64_t aTimecode, int64_t aSyncOffset)
: mEndOffset(aEndOffset), mSyncOffset(aSyncOffset), mTimecode(aTimecode)
WebMTimeDataOffset(int64_t aEndOffset, uint64_t aTimecode,
int64_t aInitOffset, int64_t aSyncOffset,
int64_t aClusterEndOffset)
: mEndOffset(aEndOffset)
, mInitOffset(aInitOffset)
, mSyncOffset(aSyncOffset)
, mClusterEndOffset(aClusterEndOffset)
, mTimecode(aTimecode)
{}
bool operator==(int64_t aEndOffset) const {
@ -34,7 +40,9 @@ struct WebMTimeDataOffset
}
int64_t mEndOffset;
int64_t mInitOffset;
int64_t mSyncOffset;
int64_t mClusterEndOffset;
uint64_t mTimecode;
};
@ -47,9 +55,17 @@ struct WebMTimeDataOffset
struct WebMBufferedParser
{
explicit WebMBufferedParser(int64_t aOffset)
: mStartOffset(aOffset), mCurrentOffset(aOffset), mInitEndOffset(-1),
mState(READ_ELEMENT_ID), mVIntRaw(false), mClusterSyncPos(0),
mTimecodeScale(1000000), mGotTimecodeScale(false)
: mStartOffset(aOffset)
, mCurrentOffset(aOffset)
, mInitEndOffset(-1)
, mBlockEndOffset(-1)
, mState(READ_ELEMENT_ID)
, mVIntRaw(false)
, mLastInitStartOffset(-1)
, mClusterSyncPos(0)
, mClusterEndOffset(-1)
, mTimecodeScale(1000000)
, mGotTimecodeScale(false)
{
if (mStartOffset != 0) {
mState = FIND_CLUSTER_SYNC;
@ -83,19 +99,28 @@ struct WebMBufferedParser
return mCurrentOffset < aOffset;
}
// Returns the start offset of the init (EBML) or media segment (Cluster)
// following the aOffset position. If none were found, returns mBlockEndOffset.
// This allows to determine the end of the interval containg aOffset.
int64_t EndSegmentOffset(int64_t aOffset);
// The offset at which this parser started parsing. Used to merge
// adjacent parsers, in which case the later parser adopts the earlier
// parser's mStartOffset.
int64_t mStartOffset;
// Current offset with the stream. Updated in chunks as Append() consumes
// Current offset within the stream. Updated in chunks as Append() consumes
// data.
int64_t mCurrentOffset;
// Tracks element's end offset. This indicates the end of the init segment.
// Will only be set if a Segment Information has been found.
// Tracks element's end offset. This indicates the end of the first init
// segment. Will only be set if a Segment Information has been found.
int64_t mInitEndOffset;
// End offset of the last block parsed.
// Will only be set if a complete block has been parsed.
int64_t mBlockEndOffset;
private:
enum State {
// Parser start state. Expects to begin at a valid EBML element. Move
@ -175,6 +200,10 @@ private:
bool mVIntRaw;
// EBML start offset. This indicates the start of the last init segment
// parsed. Will only be set if an EBML element has been found.
int64_t mLastInitStartOffset;
// Current match position within CLUSTER_SYNC_ID. Used to find sync
// within arbitrary data.
uint32_t mClusterSyncPos;
@ -195,6 +224,9 @@ private:
// been parsed.
int64_t mClusterOffset;
// End offset of the cluster currently being parsed. -1 if unknown.
int64_t mClusterEndOffset;
// Start offset of the block currently being parsed. Used as the byte
// offset for the offset-to-time mapping once the block timecode has been
// parsed.
@ -225,7 +257,10 @@ class WebMBufferedState final
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebMBufferedState)
public:
WebMBufferedState() : mReentrantMonitor("WebMBufferedState") {
WebMBufferedState()
: mReentrantMonitor("WebMBufferedState")
, mLastBlockOffset(-1)
{
MOZ_COUNT_CTOR(WebMBufferedState);
}
@ -242,6 +277,8 @@ public:
// Returns end offset of init segment or -1 if none found.
int64_t GetInitEndOffset();
// Returns the end offset of the last complete block or -1 if none found.
int64_t GetLastBlockOffset();
// Returns start time
bool GetStartTime(uint64_t *aTime);
@ -255,12 +292,14 @@ private:
MOZ_COUNT_DTOR(WebMBufferedState);
}
// Synchronizes access to the mTimeMapping array.
// Synchronizes access to the mTimeMapping array and mLastBlockOffset.
ReentrantMonitor mReentrantMonitor;
// Sorted (by offset) map of data offsets to timecodes. Populated
// on the main thread as data is received and parsed by WebMBufferedParsers.
nsTArray<WebMTimeDataOffset> mTimeMapping;
// The last complete block parsed. -1 if not set.
int64_t mLastBlockOffset;
// Sorted (by offset) live parser instances. Main thread only.
nsTArray<WebMBufferedParser> mRangeParsers;

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

@ -16,6 +16,7 @@
#include "MediaDataDemuxer.h"
#include "nsAutoRef.h"
#include "NesteggPacketHolder.h"
#include "XiphExtradata.h"
#include <algorithm>
#include <stdint.h>
@ -35,40 +36,39 @@ extern PRLogModuleInfo* gNesteggLog;
// Functions for reading and seeking using WebMDemuxer required for
// nestegg_io. The 'user data' passed to these functions is the
// demuxer's MediaResourceIndex
// demuxer.
static int webmdemux_read(void* aBuffer, size_t aLength, void* aUserData)
{
MOZ_ASSERT(aUserData);
MediaResourceIndex* resource =
reinterpret_cast<MediaResourceIndex*>(aUserData);
int64_t length = resource->GetLength();
MOZ_ASSERT(aLength < UINT32_MAX);
WebMDemuxer* demuxer = reinterpret_cast<WebMDemuxer*>(aUserData);
int64_t length = demuxer->GetEndDataOffset();
uint32_t count = aLength;
if (length >= 0 && count + resource->Tell() > length) {
count = uint32_t(length - resource->Tell());
int64_t position = demuxer->GetResource()->Tell();
if (length >= 0 && count + position > length) {
count = length - position;
}
uint32_t bytes = 0;
nsresult rv = resource->Read(static_cast<char*>(aBuffer), count, &bytes);
bool eof = !bytes;
nsresult rv =
demuxer->GetResource()->Read(static_cast<char*>(aBuffer), count, &bytes);
bool eof = bytes < aLength;
return NS_FAILED(rv) ? -1 : eof ? 0 : 1;
}
static int webmdemux_seek(int64_t aOffset, int aWhence, void* aUserData)
{
MOZ_ASSERT(aUserData);
MediaResourceIndex* resource =
reinterpret_cast<MediaResourceIndex*>(aUserData);
nsresult rv = resource->Seek(aWhence, aOffset);
WebMDemuxer* demuxer = reinterpret_cast<WebMDemuxer*>(aUserData);
nsresult rv = demuxer->GetResource()->Seek(aWhence, aOffset);
return NS_SUCCEEDED(rv) ? 0 : -1;
}
static int64_t webmdemux_tell(void* aUserData)
{
MOZ_ASSERT(aUserData);
MediaResourceIndex* resource =
reinterpret_cast<MediaResourceIndex*>(aUserData);
return resource->Tell();
WebMDemuxer* demuxer = reinterpret_cast<WebMDemuxer*>(aUserData);
return demuxer->GetResource()->Tell();
}
static void webmdemux_log(nestegg* aContext,
@ -122,12 +122,15 @@ WebMDemuxer::WebMDemuxer(MediaResource* aResource)
, mVideoTrack(0)
, mAudioTrack(0)
, mSeekPreroll(0)
, mLastAudioFrameTime(0)
, mLastVideoFrameTime(0)
, mAudioCodec(-1)
, mVideoCodec(-1)
, mHasVideo(false)
, mHasAudio(false)
, mNeedReIndex(true)
, mLastWebMBlockOffset(-1)
, mIsExpectingMoreData(true)
{
if (!gNesteggLog) {
gNesteggLog = PR_NewLogModule("Nestegg");
@ -252,7 +255,7 @@ WebMDemuxer::ReadMetadata()
io.read = webmdemux_read;
io.seek = webmdemux_seek;
io.tell = webmdemux_tell;
io.userdata = &mResource;
io.userdata = this;
int64_t maxOffset = mBufferedState->GetInitEndOffset();
if (maxOffset == -1) {
maxOffset = mResource.GetLength();
@ -378,6 +381,8 @@ WebMDemuxer::ReadMetadata()
return NS_ERROR_FAILURE;
}
nsAutoTArray<const unsigned char*,4> headers;
nsAutoTArray<size_t,4> headerLens;
for (uint32_t header = 0; header < nheaders; ++header) {
unsigned char* data = 0;
size_t length = 0;
@ -385,13 +390,24 @@ WebMDemuxer::ReadMetadata()
if (r == -1) {
return NS_ERROR_FAILURE;
}
// Vorbis has 3 headers write length + data for each header
if (nheaders > 1) {
uint8_t c[2];
BigEndian::writeUint16(&c[0], length);
mInfo.mAudio.mCodecSpecificConfig->AppendElements(&c[0], 2);
headers.AppendElement(data);
headerLens.AppendElement(length);
}
// Vorbis has 3 headers, convert to Xiph extradata format to send them to
// the demuxer.
// TODO: This is already the format WebM stores them in. Would be nice
// to avoid having libnestegg split them only for us to pack them again,
// but libnestegg does not give us an API to access this data directly.
if (nheaders > 1) {
if (!XiphHeadersToExtradata(mInfo.mAudio.mCodecSpecificConfig,
headers, headerLens)) {
return NS_ERROR_FAILURE;
}
mInfo.mAudio.mCodecSpecificConfig->AppendElements(data, length);
}
else {
mInfo.mAudio.mCodecSpecificConfig->AppendElements(headers[0],
headerLens[0]);
}
uint64_t duration = 0;
r = nestegg_duration(mContext, &duration);
@ -428,6 +444,8 @@ WebMDemuxer::EnsureUpToDateIndex()
if (!mInitData && mBufferedState->GetInitEndOffset() != -1) {
mInitData = mResource.MediaReadAt(0, mBufferedState->GetInitEndOffset());
}
mLastWebMBlockOffset = mBufferedState->GetLastBlockOffset();
mIsExpectingMoreData = mResource.GetResource()->IsExpectingMoreData();
mNeedReIndex = false;
}
@ -454,6 +472,8 @@ WebMDemuxer::GetCrypto()
bool
WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples)
{
EnsureUpToDateIndex();
nsRefPtr<NesteggPacketHolder> holder(NextPacket(aType));
if (!holder) {
@ -689,6 +709,10 @@ WebMDemuxer::SeekInternal(const media::TimeUnit& aTarget)
}
WEBM_DEBUG("got offset from buffered state: %" PRIu64 "", offset);
}
mLastAudioFrameTime = 0;
mLastVideoFrameTime = 0;
return NS_OK;
}

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

@ -85,6 +85,18 @@ public:
// Pushes a packet to the front of the video packet queue.
virtual void PushVideoPacket(NesteggPacketHolder* aItem);
// Public accessor for nestegg callbacks
MediaResourceIndex* GetResource()
{
return &mResource;
}
int64_t GetEndDataOffset()
{
return mLastWebMBlockOffset < 0 || mIsExpectingMoreData
? mResource.GetLength() : mLastWebMBlockOffset;
}
private:
friend class WebMTrackDemuxer;
@ -152,6 +164,12 @@ private:
bool mHasVideo;
bool mHasAudio;
bool mNeedReIndex;
// The last complete block parsed by the WebMBufferedState. -1 if not set.
// We cache those values rather than retrieving them for performance reasons
// as nestegg only performs 1-byte read at a time.
int64_t mLastWebMBlockOffset;
bool mIsExpectingMoreData;
};
class WebMTrackDemuxer : public MediaTrackDemuxer

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

@ -21,6 +21,7 @@
extern "C" {
#include "pocketsphinx/pocketsphinx.h"
#include "sphinxbase/logmath.h"
#include "sphinxbase/sphinx_config.h"
#include "sphinxbase/jsgf.h"
}
@ -33,8 +34,10 @@ class DecodeResultTask : public nsRunnable
{
public:
DecodeResultTask(const nsString& hypstring,
float64 confidence,
WeakPtr<dom::SpeechRecognition> recognition)
: mResult(hypstring),
mConfidence(confidence),
mRecognition(recognition),
mWorkerThread(do_GetCurrentThread())
{
@ -59,7 +62,7 @@ public:
new SpeechRecognitionAlternative(mRecognition);
alternative->mTranscript = mResult;
alternative->mConfidence = 100;
alternative->mConfidence = mConfidence;
result->mItems.AppendElement(alternative);
}
@ -77,6 +80,7 @@ public:
private:
nsString mResult;
float64 mConfidence;
WeakPtr<dom::SpeechRecognition> mRecognition;
nsCOMPtr<nsIThread> mWorkerThread;
};
@ -95,7 +99,9 @@ public:
{
char const* hyp;
int rv;
int32 score;
int32 final;
int32 logprob;
float64 confidence;
nsAutoCString hypoValue;
rv = ps_start_utt(mPs);
@ -103,15 +109,18 @@ public:
FALSE);
rv = ps_end_utt(mPs);
confidence = 0;
if (rv >= 0) {
hyp = ps_get_hyp(mPs, &score);
if (hyp) {
hyp = ps_get_hyp_final(mPs, &final);
if (hyp && final) {
logprob = ps_get_prob(mPs);
confidence = logmath_exp(ps_get_logmath(mPs), logprob);
hypoValue.Assign(hyp);
}
}
nsCOMPtr<nsIRunnable> resultrunnable =
new DecodeResultTask(NS_ConvertUTF8toUTF16(hypoValue), mRecognition);
new DecodeResultTask(NS_ConvertUTF8toUTF16(hypoValue), confidence, mRecognition);
return NS_DispatchToMainThread(resultrunnable);
}
@ -154,7 +163,7 @@ PocketSphinxSpeechRecognitionService::PocketSphinxSpeechRecognitionService()
// FOR B2G PATHS HARDCODED (APPEND /DATA ON THE BEGINING, FOR DESKTOP, ONLY
// MODELS/ RELATIVE TO ROOT
mPSConfig = cmd_ln_init(nullptr, ps_args(), TRUE, "-hmm",
mPSConfig = cmd_ln_init(nullptr, ps_args(), TRUE, "-bestpath", "yes", "-hmm",
ToNewUTF8String(aStringAMPath), // acoustic model
"-dict", ToNewUTF8String(aStringDictPath), nullptr);
if (mPSConfig == nullptr) {
@ -268,11 +277,11 @@ PocketSphinxSpeechRecognitionService::ValidateAndSetGrammarList(
int result = ps_set_jsgf_string(mPSHandle, "name",
NS_ConvertUTF16toUTF8(grammar).get());
ps_set_search(mPSHandle, "name");
if (result != 0) {
ISGrammarCompiled = false;
} else {
ps_set_search(mPSHandle, "name");
ISGrammarCompiled = true;
}
} else {

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

@ -236,8 +236,9 @@ let PaymentManager = {
if (systemAppId != Ci.nsIScriptSecurityManager.NO_APP_ID) {
this.LOG("Granting firefox-accounts permission to " + provider.uri);
let uri = Services.io.newURI(provider.uri, null, null);
let principal = Services.scriptSecurityManager
.getAppCodebasePrincipal(uri, systemAppId, true);
let attrs = {appId: systemAppId, inBrowser: true};
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(uri, attrs);
Services.perms.addFromPrincipal(principal, "firefox-accounts",
Ci.nsIPermissionManager.ALLOW_ACTION,

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

@ -35,10 +35,14 @@ XPCOMUtils.defineLazyServiceGetter(this,
PermissionSettings.prototype = {
get: function get(aPermName, aManifestURL, aOrigin, aBrowserFlag) {
// TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js
debug("Get called with: " + aPermName + ", " + aManifestURL + ", " + aOrigin + ", " + aBrowserFlag);
let uri = Services.io.newURI(aOrigin, null, null);
let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(uri,
{appId: appID,
inBrowser: aBrowserFlag});
let result = Services.perms.testExactPermanentPermission(principal, aPermName);
switch (result)
@ -59,11 +63,12 @@ PermissionSettings.prototype = {
isExplicit: function isExplicit(aPermName, aManifestURL, aOrigin,
aBrowserFlag) {
// TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js
debug("isExplicit: " + aPermName + ", " + aManifestURL + ", " + aOrigin);
let uri = Services.io.newURI(aOrigin, null, null);
let app = appsService.getAppByManifestURL(aManifestURL);
let principal = Services.scriptSecurityManager
.getAppCodebasePrincipal(uri, app.localId, aBrowserFlag);
.createCodebasePrincipal(uri, {appId: app.localId, inBrowser: aBrowserFlag});
return isExplicitInPermissionsTable(aPermName,
principal.appStatus,
@ -99,9 +104,13 @@ PermissionSettings.prototype = {
},
remove: function remove(aPermName, aManifestURL, aOrigin) {
// TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js
let uri = Services.io.newURI(aOrigin, null, null);
let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, true);
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(uri,
{appId: appID,
inBrowser: true});
if (principal.appStatus !== Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) {
let errorMsg = "PermissionSettings.js: '" + aOrigin + "'" +

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

@ -67,9 +67,13 @@ this.PermissionSettingsModule = {
_internalAddPermission: function _internalAddPermission(aData, aAllowAllChanges, aCallbacks) {
// TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.jsm
let uri = Services.io.newURI(aData.origin, null, null);
let app = appsService.getAppByManifestURL(aData.manifestURL);
let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, app.localId, aData.browserFlag);
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(uri,
{appId: app.localId,
inBrowser: aData.browserFlag});
let action;
switch (aData.value)
@ -103,10 +107,14 @@ this.PermissionSettingsModule = {
},
getPermission: function getPermission(aPermName, aManifestURL, aOrigin, aBrowserFlag) {
// TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.jsm
debug("getPermission: " + aPermName + ", " + aManifestURL + ", " + aOrigin);
let uri = Services.io.newURI(aOrigin, null, null);
let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(uri,
{appId: appID,
inBrowser: aBrowserFlag});
let result = Services.perms.testExactPermissionFromPrincipal(principal, aPermName);
switch (result)

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

@ -5288,10 +5288,9 @@ StorageDirectoryHelper::RunOnMainThread()
rv = secMan->GetSimpleCodebasePrincipal(uri,
getter_AddRefs(principal));
} else {
rv = secMan->GetAppCodebasePrincipal(uri,
originProps.mAppId,
originProps.mInMozBrowser,
getter_AddRefs(principal));
OriginAttributes attrs(originProps.mAppId, originProps.mInMozBrowser);
principal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
rv = principal ? NS_OK : NS_ERROR_FAILURE;
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;

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

@ -27,9 +27,9 @@ function make_uri(url) {
// Ensure "fullscreen" permissions are not present on the test URI.
var pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
var uri = make_uri("http://mochi.test:8888");
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
var ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
var principal = ssm.createCodebasePrincipal(uri, {});
pm.removeFromPrincipal(principal, "fullscreen");
SpecialPowers.pushPrefEnv({"set": [

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

@ -18,11 +18,11 @@ function startTest()
.getService(Components.interfaces.nsIDOMStorageManager);
var uri = ios.newURI(url, "", null);
var principal = ssm.getNoAppCodebasePrincipal(uri);
var principal = ssm.createCodebasePrincipal(uri, {});
var storage = dsm.createStorage(window, principal, "");
storage.setItem("chromekey", "chromevalue");
var aframe = document.getElementById("aframe");
aframe.onload = function()
{

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

@ -192,17 +192,54 @@ interface MozInputContext: EventTarget {
attribute EventHandler onsurroundingtextchange;
/*
* send a character with its key events.
* @param modifiers see http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/base/nsIDOMWindowUtils.idl#206
* @param repeat indicates whether a key would be sent repeatedly.
* @return true if succeeds. Otherwise false if the input context becomes void.
* Alternative: sendKey(KeyboardEvent event), but we will likely
* waste memory for creating the KeyboardEvent object.
* Note that, if you want to send a key n times repeatedly, make sure set
* parameter repeat to true and invoke sendKey n-1 times, and then set
* repeat to false in the last invoke.
*/
Promise<boolean> sendKey(long keyCode, long charCode, long modifiers, optional boolean repeat);
* Send a string/character with its key events. There are two ways of invocating
* the method for backward compability purpose.
*
* (1) The recommended way, allow specifying DOM level 3 properties like |code|.
* @param dictOrKeyCode See MozInputMethodKeyboardEventDict.
* @param charCode disregarded
* @param modifiers disregarded
* @param repeat disregarded
*
* (2) Deprecated, reserved for backward compability.
* @param dictOrKeyCode keyCode of the key to send, should be one of the DOM_VK_ value in KeyboardEvent.
* @param charCode charCode of the character, should be 0 for non-printable keys.
* @param modifiers this paramater is no longer honored.
* @param repeat indicates whether a key would be sent repeatedly.
*
* @return A promise. Resolve to true if succeeds.
* Rejects to a string indicating the error.
*
* Note that, if you want to send a key n times repeatedly, make sure set
* parameter repeat to true and invoke sendKey n times, and invoke keyup
* after the end of the input.
*/
Promise<boolean> sendKey((MozInputMethodRequiredKeyboardEventDict or long) dictOrKeyCode,
optional long charCode,
optional long modifiers,
optional boolean repeat);
/*
* Send a string/character with keydown, and keypress events.
* keyup should be called afterwards to ensure properly sequence.
*
* @param dict See MozInputMethodKeyboardEventDict.
*
* @return A promise. Resolve to true if succeeds.
* Rejects to a string indicating the error.
*/
Promise<boolean> keydown(MozInputMethodRequiredKeyboardEventDict dict);
/*
* Send a keyup event. keydown should be called first to ensure properly sequence.
*
* @param dict See MozInputMethodKeyboardEventDict.
*
* @return A promise. Resolve to true if succeeds.
* Rejects to a string indicating the error.
*
*/
Promise<boolean> keyup(MozInputMethodRequiredKeyboardEventDict dict);
/*
* Set current composing text. This method will start composition or update
@ -218,7 +255,11 @@ interface MozInputContext: EventTarget {
* cursor will be positioned after the composition text.
* @param clauses The array of composition clause information. If not set,
* only one clause is supported.
*
* @param dict The properties of the keyboard event that cause the composition
* to set. keydown or keyup event will be fired if it's necessary.
* For compatibility, we recommend that you should always set this argument
* if it's caused by a key operation.
*
* The composing text, which is shown with underlined style to distinguish
* from the existing text, is used to compose non-ASCII characters from
* keystrokes, e.g. Pinyin or Hiragana. The composing text is the
@ -231,9 +272,10 @@ interface MozInputContext: EventTarget {
* To finish composition and commit text to current input field, an IME
* should call |endComposition|.
*/
// XXXbz what is this promise resolved with?
Promise<any> setComposition(DOMString text, optional long cursor,
optional sequence<CompositionClauseParameters> clauses);
Promise<boolean> setComposition(DOMString text,
optional long cursor,
optional sequence<CompositionClauseParameters> clauses,
optional MozInputMethodKeyboardEventDict dict);
/*
* End composition, clear the composing text and commit given text to
@ -241,6 +283,10 @@ interface MozInputContext: EventTarget {
* position.
* @param text The text to commited before cursor position. If empty string
* is given, no text will be committed.
* @param dict The properties of the keyboard event that cause the composition
* to end. keydown or keyup event will be fired if it's necessary.
* For compatibility, we recommend that you should always set this argument
* if it's caused by a key operation.
*
* Note that composition always ends automatically with nothing to commit if
* the composition does not explicitly end by calling |endComposition|, but
@ -248,8 +294,8 @@ interface MozInputContext: EventTarget {
* |replaceSurroundingText|, |deleteSurroundingText|, user moving the
* cursor, changing the focus, etc.
*/
// XXXbz what is this promise resolved with?
Promise<any> endComposition(optional DOMString text);
Promise<boolean> endComposition(optional DOMString text,
optional MozInputMethodKeyboardEventDict dict);
};
enum CompositionClauseSelectionType {
@ -263,3 +309,66 @@ dictionary CompositionClauseParameters {
DOMString selectionType = "raw-input";
long length;
};
/*
* A MozInputMethodKeyboardEventDictBase contains the following properties,
* indicating the properties of the keyboard event caused.
*
* This is the base dictionary type for us to create two child types that could
* be used as argument type in two types of methods, as WebIDL parser required.
*
*/
dictionary MozInputMethodKeyboardEventDictBase {
/*
* String/character to output, or a registered name of non-printable key.
* (To be defined in the inheriting dictionary types.)
*/
// DOMString key;
/*
* String/char indicating the virtual hardware key pressed. Optional.
* Must be a value defined in
* http://www.w3.org/TR/DOM-Level-3-Events-code/#keyboard-chording-virtual
* If your keyboard app emulates physical keyboard layout, this value should
* not be empty string. Otherwise, it should be empty string.
*/
DOMString code = "";
/*
* keyCode of the keyboard event. Optional.
* To be disregarded if |key| is an alphanumeric character.
* If the key causes inputting a character and if your keyboard app emulates
* a physical keyboard layout, this value should be same as the value used
* by Firefox for desktop. If the key causes inputting an ASCII character
* but if your keyboard app doesn't emulate any physical keyboard layouts,
* the value should be proper value for the key value.
*/
long? keyCode;
/*
* Indicates whether a key would be sent repeatedly. Optional.
*/
boolean repeat = false;
/*
* Optional. True if |key| property is explicitly referring to a printable key.
* When this is set, key will be printable even if the |key| value matches any
* of the registered name of non-printable keys.
*/
boolean printable = false;
};
/*
* For methods like setComposition() and endComposition(), the optional
* dictionary type argument is really optional when all of it's property
* are optional.
* This dictionary type is used to denote that argument.
*/
dictionary MozInputMethodKeyboardEventDict : MozInputMethodKeyboardEventDictBase {
DOMString? key;
};
/*
* For methods like keydown() and keyup(), the dictionary type argument is
* considered required only if at least one of it's property is required.
* This dictionary type is used to denote that argument.
*/
dictionary MozInputMethodRequiredKeyboardEventDict : MozInputMethodKeyboardEventDictBase {
required DOMString key;
};

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

@ -0,0 +1,22 @@
:this file must be enconded in utf8
:and its Content-Type must be equal to text/event-stream
retry:500
data: 2
unknow: unknow
event: other_event_name
retry:500
data: 2
unknow: unknow
event: click
retry:500
event: blur
retry:500
event:keypress
retry:500

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

@ -0,0 +1,3 @@
Content-Type: text/event-stream
Cache-Control: no-cache, must-revalidate
Access-Control-Allow-Origin: *

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

@ -0,0 +1,75 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1182103 - Test EventSource scenarios with fetch interception</title>
<script type="text/javascript">
var prefix = "http://mochi.test:8888/tests/dom/workers/test/serviceworkers/eventsource/";
function ok(aCondition, aMessage) {
parent.postMessage({status: "callback", data: "ok", condition: aCondition, message: aMessage}, "*");
}
function doUnregister() {
navigator.serviceWorker.getRegistration().then(swr => {
swr.unregister().then(function(result) {
ok(result, "Unregister should return true.");
parent.postMessage({status: "callback", data: "done"}, "*");
}, function(e) {
ok(false, "Unregistering the SW failed with " + e);
});
});
}
function doEventSource() {
var source = new EventSource(prefix + "eventsource.resource");
source.onmessage = function(e) {
source.onmessage = null;
source.close();
ok(true, "EventSource should work with cors responses");
doUnregister();
};
source.onerror = function(error) {
source.onerror = null;
source.close();
ok(false, "Something went wrong");
};
}
function onLoad() {
if (!parent) {
dump("eventsource/eventsource_cors_response.html shouldn't be launched directly!");
}
window.addEventListener("message", function onMessage(e) {
if (e.data.status === "callback") {
switch(e.data.data) {
case "eventsource":
doEventSource();
window.removeEventListener("message", onMessage);
break;
default:
ok(false, "Something went wrong")
break
}
}
});
navigator.serviceWorker.ready.then(function() {
parent.postMessage({status: "callback", data: "ready"}, "*");
});
navigator.serviceWorker.addEventListener("message", function(event) {
parent.postMessage(event.data, "*");
});
}
</script>
</head>
<body onload="onLoad()">
</body>
</html>

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

@ -0,0 +1,19 @@
// Cross origin request
var prefix = 'http://example.com/tests/dom/workers/test/serviceworkers/eventsource/';
self.importScripts('eventsource_worker_helper.js');
self.addEventListener('fetch', function (event) {
var request = event.request;
var url = new URL(request.url);
if (url.pathname !== '/tests/dom/workers/test/serviceworkers/eventsource/eventsource.resource') {
return;
}
ok(request.mode === 'cors', 'EventSource should make a CORS request');
var fetchRequest = new Request(prefix + 'eventsource.resource', { mode: 'cors'});
event.respondWith(fetch(fetchRequest).then((fetchResponse) => {
return fetchResponse;
}));
});

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

@ -0,0 +1,75 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1182103 - Test EventSource scenarios with fetch interception</title>
<script type="text/javascript">
var prefix = "https://example.com/tests/dom/workers/test/serviceworkers/eventsource/";
function ok(aCondition, aMessage) {
parent.postMessage({status: "callback", data: "ok", condition: aCondition, message: aMessage}, "*");
}
function doUnregister() {
navigator.serviceWorker.getRegistration().then(swr => {
swr.unregister().then(function(result) {
ok(result, "Unregister should return true.");
parent.postMessage({status: "callback", data: "done"}, "*");
}, function(e) {
ok(false, "Unregistering the SW failed with " + e);
});
});
}
function doEventSource() {
var source = new EventSource(prefix + "eventsource.resource");
source.onmessage = function(e) {
source.onmessage = null;
source.close();
ok(false, "Something went wrong");
};
source.onerror = function(error) {
source.onerror = null;
source.close();
ok(true, "EventSource should not work with mixed content cors responses");
doUnregister();
};
}
function onLoad() {
if (!parent) {
dump("eventsource/eventsource_cors_response.html shouldn't be launched directly!");
}
window.addEventListener("message", function onMessage(e) {
if (e.data.status === "callback") {
switch(e.data.data) {
case "eventsource":
doEventSource();
window.removeEventListener("message", onMessage);
break;
default:
ok(false, "Something went wrong")
break
}
}
});
navigator.serviceWorker.ready.then(function() {
parent.postMessage({status: "callback", data: "ready"}, "*");
});
navigator.serviceWorker.addEventListener("message", function(event) {
parent.postMessage(event.data, "*");
});
}
</script>
</head>
<body onload="onLoad()">
</body>
</html>

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

@ -0,0 +1,18 @@
var prefix = 'http://example.com/tests/dom/workers/test/serviceworkers/eventsource/';
self.importScripts('eventsource_worker_helper.js');
self.addEventListener('fetch', function (event) {
var request = event.request;
var url = new URL(request.url);
if (url.pathname !== '/tests/dom/workers/test/serviceworkers/eventsource/eventsource.resource') {
return;
}
ok(request.mode === 'cors', 'EventSource should make a CORS request');
var fetchRequest = new Request(prefix + 'eventsource.resource', { mode: 'cors'});
event.respondWith(fetch(fetchRequest).then((fetchResponse) => {
return fetchResponse;
}));
});

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

@ -0,0 +1,75 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1182103 - Test EventSource scenarios with fetch interception</title>
<script type="text/javascript">
var prefix = "http://mochi.test:8888/tests/dom/workers/test/serviceworkers/eventsource/";
function ok(aCondition, aMessage) {
parent.postMessage({status: "callback", data: "ok", condition: aCondition, message: aMessage}, "*");
}
function doUnregister() {
navigator.serviceWorker.getRegistration().then(swr => {
swr.unregister().then(function(result) {
ok(result, "Unregister should return true.");
parent.postMessage({status: "callback", data: "done"}, "*");
}, function(e) {
ok(false, "Unregistering the SW failed with " + e);
});
});
}
function doEventSource() {
var source = new EventSource(prefix + "eventsource.resource");
source.onmessage = function(e) {
source.onmessage = null;
source.close();
ok(false, "Something went wrong");
};
source.onerror = function(error) {
source.onerror = null;
source.close();
ok(true, "EventSource should not work with opaque responses");
doUnregister();
};
}
function onLoad() {
if (!parent) {
dump("eventsource/eventsource_opaque_response.html shouldn't be launched directly!");
}
window.addEventListener("message", function onMessage(e) {
if (e.data.status === "callback") {
switch(e.data.data) {
case "eventsource":
doEventSource();
window.removeEventListener("message", onMessage);
break;
default:
ok(false, "Something went wrong")
break
}
}
});
navigator.serviceWorker.ready.then(function() {
parent.postMessage({status: "callback", data: "ready"}, "*");
});
navigator.serviceWorker.addEventListener("message", function(event) {
parent.postMessage(event.data, "*");
});
}
</script>
</head>
<body onload="onLoad()">
</body>
</html>

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

@ -0,0 +1,19 @@
// Cross origin request
var prefix = 'http://example.com/tests/dom/workers/test/serviceworkers/eventsource/';
self.importScripts('eventsource_worker_helper.js');
self.addEventListener('fetch', function (event) {
var request = event.request;
var url = new URL(request.url);
if (url.pathname !== '/tests/dom/workers/test/serviceworkers/eventsource/eventsource.resource') {
return;
}
ok(request.mode === 'cors', 'EventSource should make a CORS request');
var fetchRequest = new Request(prefix + 'eventsource.resource', { mode: 'no-cors'});
event.respondWith(fetch(fetchRequest).then((fetchResponse) => {
return fetchResponse;
}));
});

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

@ -0,0 +1,27 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1182103 - Test EventSource scenarios with fetch interception</title>
<script type="text/javascript">
function getURLParam (aTarget, aValue) {
return decodeURI(aTarget.search.replace(new RegExp("^(?:.*[&\\?]" + encodeURI(aValue).replace(/[\.\+\*]/g, "\\$&") + "(?:\\=([^&]*))?)?.*$", "i"), "$1"));
}
function onLoad() {
navigator.serviceWorker.ready.then(function() {
parent.postMessage({status: "callback", data: "done"}, "*");
});
navigator.serviceWorker.register(getURLParam(document.location, "script"), {scope: "."});
}
</script>
</head>
<body onload="onLoad()">
</body>
</html>

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

@ -0,0 +1,75 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1182103 - Test EventSource scenarios with fetch interception</title>
<script type="text/javascript">
var prefix = "http://mochi.test:8888/tests/dom/workers/test/serviceworkers/eventsource/";
function ok(aCondition, aMessage) {
parent.postMessage({status: "callback", data: "ok", condition: aCondition, message: aMessage}, "*");
}
function doUnregister() {
navigator.serviceWorker.getRegistration().then(swr => {
swr.unregister().then(function(result) {
ok(result, "Unregister should return true.");
parent.postMessage({status: "callback", data: "done"}, "*");
}, function(e) {
ok(false, "Unregistering the SW failed with " + e);
});
});
}
function doEventSource() {
var source = new EventSource(prefix + "eventsource.resource");
source.onmessage = function(e) {
source.onmessage = null;
source.close();
ok(true, "EventSource should work with synthetic responses");
doUnregister();
};
source.onerror = function(error) {
source.onmessage = null;
source.close();
ok(false, "Something went wrong");
};
}
function onLoad() {
if (!parent) {
dump("eventsource/eventsource_synthetic_response.html shouldn't be launched directly!");
}
window.addEventListener("message", function onMessage(e) {
if (e.data.status === "callback") {
switch(e.data.data) {
case "eventsource":
doEventSource();
window.removeEventListener("message", onMessage);
break;
default:
ok(false, "Something went wrong")
break
}
}
});
navigator.serviceWorker.ready.then(function() {
parent.postMessage({status: "callback", data: "ready"}, "*");
});
navigator.serviceWorker.addEventListener("message", function(event) {
parent.postMessage(event.data, "*");
});
}
</script>
</head>
<body onload="onLoad()">
</body>
</html>

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

@ -0,0 +1,24 @@
self.importScripts('eventsource_worker_helper.js');
self.addEventListener('fetch', function (event) {
var request = event.request;
var url = new URL(request.url);
if (url.pathname !== '/tests/dom/workers/test/serviceworkers/eventsource/eventsource.resource') {
return;
}
ok(request.mode === 'cors', 'EventSource should make a CORS request');
var headerList = {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache, must-revalidate'
};
var headers = new Headers(headerList);
var init = {
headers: headers,
mode: 'cors'
};
var body = 'data: data0\r\r';
var response = new Response(body, init);
event.respondWith(response);
});

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

@ -0,0 +1,12 @@
function ok(aCondition, aMessage) {
return new Promise(function(resolve, reject) {
self.clients.matchAll().then(function(res) {
if (!res.length) {
reject();
return;
}
res[0].postMessage({status: "callback", data: "ok", condition: aCondition, message: aMessage});
resolve();
});
});
}

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

@ -0,0 +1,43 @@
<!DOCTYPE html>
<script>
var obj, embed;
function ok(v, msg) {
window.opener.postMessage({status: "ok", result: !!v, message: msg}, "*");
}
function finish() {
document.documentElement.removeChild(obj);
document.documentElement.removeChild(embed);
window.opener.postMessage({status: "done"}, "*");
}
function test_object() {
obj = document.createElement("object");
obj.setAttribute('data', "object");
document.documentElement.appendChild(obj);
}
function test_embed() {
embed = document.createElement("embed");
embed.setAttribute('src', "embed");
document.documentElement.appendChild(embed);
}
navigator.serviceWorker.addEventListener("message", function onMessage(e) {
if (e.data.context === "object") {
ok(false, "<object> should not be intercepted");
} else if (e.data.context === "embed") {
ok(false, "<embed> should not be intercepted");
} else if (e.data.context === "fetch" && e.data.resource === "foo.txt") {
navigator.serviceWorker.removeEventListener("message", onMessage);
finish();
}
}, false);
test_object();
test_embed();
// SW will definitely intercept fetch API, use this to see if plugins are
// intercepted before fetch().
fetch("foo.txt");
</script>

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

@ -0,0 +1,7 @@
self.addEventListener("fetch", function(event) {
var resource = event.request.url.split('/').pop();
if (event.client) {
event.client.postMessage({context: event.request.context,
resource: resource});
}
});

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