mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-28 21:28:55 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
8457c6a69a
@ -989,8 +989,8 @@ pref("browser.autofocus", false);
|
||||
// Enable wakelock
|
||||
pref("dom.wakelock.enabled", true);
|
||||
|
||||
// Disable touch caret by default
|
||||
pref("touchcaret.enabled", false);
|
||||
// Enable touch caret by default
|
||||
pref("touchcaret.enabled", true);
|
||||
|
||||
// Disable selection caret by default
|
||||
pref("selectioncaret.enabled", false);
|
||||
|
@ -22,9 +22,6 @@ const Cu = Components.utils;
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
|
||||
// Preloading the CSP jsm in this process early on.
|
||||
Cu.import("resource://gre/modules/CSPUtils.jsm");
|
||||
|
||||
function debug(msg) {
|
||||
log(msg);
|
||||
}
|
||||
|
@ -490,8 +490,6 @@
|
||||
@BINPATH@/components/formautofill.manifest
|
||||
@BINPATH@/components/FormAutofillContentService.js
|
||||
@BINPATH@/components/FormAutofillStartup.js
|
||||
@BINPATH@/components/contentSecurityPolicy.manifest
|
||||
@BINPATH@/components/contentSecurityPolicy.js
|
||||
@BINPATH@/components/contentAreaDropListener.manifest
|
||||
@BINPATH@/components/contentAreaDropListener.js
|
||||
@BINPATH@/components/messageWakeupService.js
|
||||
|
@ -9,33 +9,17 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const reporter = Cc["@mozilla.org/datareporting/service;1"]
|
||||
.getService(Ci.nsISupports)
|
||||
.wrappedJSObject
|
||||
.healthReporter;
|
||||
|
||||
const policy = Cc["@mozilla.org/datareporting/service;1"]
|
||||
.getService(Ci.nsISupports)
|
||||
.wrappedJSObject
|
||||
.policy;
|
||||
|
||||
const prefs = new Preferences("datareporting.healthreport.");
|
||||
|
||||
|
||||
let healthReportWrapper = {
|
||||
init: function () {
|
||||
if (!reporter) {
|
||||
healthReportWrapper.handleInitFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
reporter.onInit().then(healthReportWrapper.refreshPayload,
|
||||
healthReportWrapper.handleInitFailure);
|
||||
|
||||
let iframe = document.getElementById("remote-report");
|
||||
iframe.addEventListener("load", healthReportWrapper.initRemotePage, false);
|
||||
let report = this._getReportURI();
|
||||
iframe.src = report.spec;
|
||||
iframe.src = this._getReportURI().spec;
|
||||
iframe.onload = () => {
|
||||
MozSelfSupport.getHealthReportPayload().then(this.updatePayload,
|
||||
this.handleInitFailure);
|
||||
};
|
||||
prefs.observe("uploadEnabled", this.updatePrefState, healthReportWrapper);
|
||||
},
|
||||
|
||||
@ -48,36 +32,30 @@ let healthReportWrapper = {
|
||||
return Services.io.newURI(url, null, null);
|
||||
},
|
||||
|
||||
onOptIn: function () {
|
||||
policy.recordHealthReportUploadEnabled(true,
|
||||
"Health report page sent opt-in command.");
|
||||
this.updatePrefState();
|
||||
},
|
||||
|
||||
onOptOut: function () {
|
||||
policy.recordHealthReportUploadEnabled(false,
|
||||
"Health report page sent opt-out command.");
|
||||
setDataSubmission: function (enabled) {
|
||||
MozSelfSupport.healthReportDataSubmissionEnabled = enabled;
|
||||
this.updatePrefState();
|
||||
},
|
||||
|
||||
updatePrefState: function () {
|
||||
try {
|
||||
let prefs = {
|
||||
enabled: policy.healthReportUploadEnabled,
|
||||
}
|
||||
this.injectData("prefs", prefs);
|
||||
} catch (e) {
|
||||
this.reportFailure(this.ERROR_PREFS_FAILED);
|
||||
enabled: MozSelfSupport.healthReportDataSubmissionEnabled,
|
||||
};
|
||||
healthReportWrapper.injectData("prefs", prefs);
|
||||
}
|
||||
catch (ex) {
|
||||
healthReportWrapper.reportFailure(healthReportWrapper.ERROR_PREFS_FAILED);
|
||||
}
|
||||
},
|
||||
|
||||
refreshPayload: function () {
|
||||
reporter.collectAndObtainJSONPayload().then(healthReportWrapper.updatePayload,
|
||||
healthReportWrapper.handlePayloadFailure);
|
||||
MozSelfSupport.getHealthReportPayload().then(this.updatePayload,
|
||||
this.handlePayloadFailure);
|
||||
},
|
||||
|
||||
updatePayload: function (data) {
|
||||
healthReportWrapper.injectData("payload", data);
|
||||
updatePayload: function (payload) {
|
||||
healthReportWrapper.injectData("payload", JSON.stringify(payload));
|
||||
},
|
||||
|
||||
injectData: function (type, content) {
|
||||
@ -99,10 +77,10 @@ let healthReportWrapper = {
|
||||
handleRemoteCommand: function (evt) {
|
||||
switch (evt.detail.command) {
|
||||
case "DisableDataSubmission":
|
||||
this.onOptOut();
|
||||
this.setDataSubmission(false);
|
||||
break;
|
||||
case "EnableDataSubmission":
|
||||
this.onOptIn();
|
||||
this.setDataSubmission(true);
|
||||
break;
|
||||
case "RequestCurrentPrefs":
|
||||
this.updatePrefState();
|
||||
|
@ -17,6 +17,7 @@ DIRS += [
|
||||
'search',
|
||||
'sessionstore',
|
||||
'shell',
|
||||
'selfsupport',
|
||||
'sidebar',
|
||||
'tabview',
|
||||
'translation',
|
||||
|
74
browser/components/selfsupport/SelfSupportService.js
Normal file
74
browser/components/selfsupport/SelfSupportService.js
Normal file
@ -0,0 +1,74 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const policy = Cc["@mozilla.org/datareporting/service;1"]
|
||||
.getService(Ci.nsISupports)
|
||||
.wrappedJSObject
|
||||
.policy;
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "reporter", () => {
|
||||
return Cc["@mozilla.org/datareporting/service;1"]
|
||||
.getService(Ci.nsISupports)
|
||||
.wrappedJSObject
|
||||
.healthReporter;
|
||||
});
|
||||
|
||||
function MozSelfSupportInterface() {
|
||||
}
|
||||
|
||||
MozSelfSupportInterface.prototype = {
|
||||
classDescription: "MozSelfSupport",
|
||||
classID: Components.ID("{d30aae8b-f352-4de3-b936-bb9d875df0bb}"),
|
||||
contractID: "@mozilla.org/mozselfsupport;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
|
||||
Ci.nsIObserver]),
|
||||
|
||||
_window: null,
|
||||
|
||||
init: function (window) {
|
||||
this._window = window;
|
||||
|
||||
// FIXME: Remove this hack after static attributes work for JS-implemented
|
||||
// WebIDL (see bug 863952). For a detailed description of how this works,
|
||||
// see the comment accompanying the init function of amInstallTrigger.js.
|
||||
return window.MozSelfSupportImpl._create(this._window, this);
|
||||
},
|
||||
|
||||
get healthReportDataSubmissionEnabled() {
|
||||
return policy.healthReportUploadEnabled;
|
||||
},
|
||||
|
||||
set healthReportDataSubmissionEnabled(enabled) {
|
||||
let reason = "Self-support interface sent " +
|
||||
(enabled ? "opt-in" : "opt-out") +
|
||||
" command.";
|
||||
policy.recordHealthReportUploadEnabled(enabled, reason);
|
||||
},
|
||||
|
||||
getHealthReportPayload: function () {
|
||||
return new this._window.Promise(function (aResolve, aReject) {
|
||||
if (reporter) {
|
||||
let resolvePayload = function () {
|
||||
reporter.collectAndObtainJSONPayload(true).then(aResolve, aReject);
|
||||
};
|
||||
|
||||
if (reporter.initialized) {
|
||||
resolvePayload();
|
||||
} else {
|
||||
reporter.onInit().then(resolvePayload, aReject);
|
||||
}
|
||||
} else {
|
||||
aReject(new Error("No reporter"));
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MozSelfSupportInterface]);
|
@ -0,0 +1,4 @@
|
||||
component {d30aae8b-f352-4de3-b936-bb9d875df0bb} SelfSupportService.js
|
||||
contract @mozilla.org/mozselfsupport;1 {d30aae8b-f352-4de3-b936-bb9d875df0bb}
|
||||
|
||||
category JavaScript-global-privileged-property MozSelfSupport @mozilla.org/mozselfsupport;1
|
10
browser/components/selfsupport/moz.build
Normal file
10
browser/components/selfsupport/moz.build
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'SelfSupportService.js',
|
||||
'SelfSupportService.manifest',
|
||||
]
|
@ -452,8 +452,6 @@
|
||||
@BINPATH@/components/formautofill.manifest
|
||||
@BINPATH@/components/FormAutofillContentService.js
|
||||
@BINPATH@/components/FormAutofillStartup.js
|
||||
@BINPATH@/components/contentSecurityPolicy.manifest
|
||||
@BINPATH@/components/contentSecurityPolicy.js
|
||||
@BINPATH@/components/contentAreaDropListener.manifest
|
||||
@BINPATH@/components/contentAreaDropListener.js
|
||||
@BINPATH@/browser/components/BrowserProfileMigrators.manifest
|
||||
@ -489,6 +487,8 @@
|
||||
#endif
|
||||
#ifdef MOZ_SERVICES_HEALTHREPORT
|
||||
@BINPATH@/components/HealthReportComponents.manifest
|
||||
@BINPATH@/browser/components/SelfSupportService.manifest
|
||||
@BINPATH@/browser/components/SelfSupportService.js
|
||||
#endif
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
@BINPATH@/components/SyncComponents.manifest
|
||||
|
@ -60,6 +60,8 @@ http://127.0.0.1:80 privileged
|
||||
http://127.0.0.1:8888 privileged
|
||||
http://test:80 privileged
|
||||
http://mochi.test:8888 privileged
|
||||
http://test1.mochi.test:8888
|
||||
http://test2.mochi.test:8888
|
||||
http://example.org:80 privileged
|
||||
http://test1.example.org:80 privileged
|
||||
http://test2.example.org:80 privileged
|
||||
|
@ -530,10 +530,10 @@ nsPrincipal::Read(nsIObjectInputStream* aStream)
|
||||
rv = SetCsp(csp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// need to link in the CSP context here (link in a reference to this
|
||||
// nsIPrincipal and to the URI of the protected resource).
|
||||
// need to link in the CSP context here (link in the URI of the protected
|
||||
// resource).
|
||||
if (csp) {
|
||||
csp->SetRequestContext(codebase, nullptr, this, nullptr);
|
||||
csp->SetRequestContext(codebase, nullptr, nullptr);
|
||||
}
|
||||
|
||||
SetDomain(domain);
|
||||
|
@ -5094,6 +5094,9 @@ if test -n "$MOZ_APPLEMEDIA"; then
|
||||
# hack in frameworks for fmp4 - see bug 1029974
|
||||
# We load VideoToolbox and CoreMedia dynamically, so they don't appear here.
|
||||
LDFLAGS="$LDFLAGS -framework AudioToolbox"
|
||||
dnl Verify CoreMedia is available.
|
||||
AC_CHECK_HEADER([CoreMedia/CoreMedia.h], [],
|
||||
[AC_MSG_ERROR([MacOS X 10.7 SDK or later is required])])
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
|
12
content/base/crashtests/1024428-1.html
Normal file
12
content/base/crashtests/1024428-1.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
var s = host.createShadowRoot();
|
||||
s.innerHTML = '<input type="range" />';
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -151,3 +151,4 @@ load 942979.html
|
||||
load 978646.html
|
||||
load 1026714.html
|
||||
pref(dom.webcomponents.enabled,true) load 1027461-1.html
|
||||
pref(dom.webcomponents.enabled,true) load 1024428-1.html
|
||||
|
@ -151,7 +151,7 @@ interface nsIContentPolicy : nsISupports
|
||||
const nsContentPolicyType TYPE_BEACON = 19;
|
||||
|
||||
/* When adding new content types, please update nsContentBlocker,
|
||||
* NS_CP_ContentTypeName, contentSecurityPolicy.js, all nsIContentPolicy
|
||||
* NS_CP_ContentTypeName, nsCSPContext, all nsIContentPolicy
|
||||
* implementations, and other things that are not listed here that are
|
||||
* related to nsIContentPolicy. */
|
||||
|
||||
|
@ -17,17 +17,10 @@ interface nsIPrincipal;
|
||||
* one of these per document/principal.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(3e923bf6-a974-4f3b-91c4-b4fd48b37732)]
|
||||
[scriptable, uuid(ee599622-99e3-491a-890e-6ee254bf1390)]
|
||||
interface nsIContentSecurityPolicy : nsISerializable
|
||||
{
|
||||
|
||||
/**
|
||||
* Set to true when the CSP has been read in and parsed and is ready to
|
||||
* enforce. This is a barrier for the nsDocument so it doesn't load any
|
||||
* sub-content until either it knows that a CSP is ready or will not be used.
|
||||
*/
|
||||
readonly attribute boolean isInitialized;
|
||||
|
||||
/**
|
||||
* Accessor method for a read-only string version of the policy at a given
|
||||
* index.
|
||||
@ -50,14 +43,11 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
* Parse and install a CSP policy.
|
||||
* @param aPolicy
|
||||
* String representation of the policy (e.g., header value)
|
||||
* @param selfURI
|
||||
* the URI of the protected document/principal
|
||||
* @param reportOnly
|
||||
* Should this policy affect content, script and style processing or
|
||||
* just send reports if it is violated?
|
||||
*/
|
||||
void appendPolicy(in AString policyString, in nsIURI selfURI,
|
||||
in boolean reportOnly);
|
||||
void appendPolicy(in AString policyString, in boolean reportOnly);
|
||||
|
||||
/**
|
||||
* Whether this policy allows in-page script.
|
||||
@ -188,7 +178,6 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
*/
|
||||
void setRequestContext(in nsIURI selfURI,
|
||||
in nsIURI referrer,
|
||||
in nsIPrincipal documentPrincipal,
|
||||
in nsIChannel aChannel);
|
||||
|
||||
/**
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,2 +0,0 @@
|
||||
component {d1680bb4-1ac0-4772-9437-1188375e44f2} contentSecurityPolicy.js
|
||||
contract @mozilla.org/contentsecuritypolicy;1 {d1680bb4-1ac0-4772-9437-1188375e44f2}
|
@ -198,19 +198,10 @@ SOURCES += [
|
||||
EXTRA_COMPONENTS += [
|
||||
'contentAreaDropListener.js',
|
||||
'contentAreaDropListener.manifest',
|
||||
'contentSecurityPolicy.manifest',
|
||||
'messageWakeupService.js',
|
||||
'messageWakeupService.manifest',
|
||||
]
|
||||
|
||||
EXTRA_PP_COMPONENTS += [
|
||||
'contentSecurityPolicy.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'CSPUtils.jsm',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
MSVC_ENABLE_PGO = True
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIPropertyBag2.h"
|
||||
#include "nsIStringStream.h"
|
||||
#include "nsIUploadChannel.h"
|
||||
@ -235,12 +234,6 @@ nsCSPContext::~nsCSPContext()
|
||||
mShouldLoadCache.Clear();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCSPContext::GetIsInitialized(bool *outIsInitialized)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCSPContext::GetPolicy(uint32_t aIndex, nsAString& outStr)
|
||||
{
|
||||
@ -272,16 +265,11 @@ nsCSPContext::RemovePolicy(uint32_t aIndex)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCSPContext::AppendPolicy(const nsAString& aPolicyString,
|
||||
nsIURI* aSelfURI,
|
||||
bool aReportOnly)
|
||||
{
|
||||
CSPCONTEXTLOG(("nsCSPContext::AppendPolicy: %s",
|
||||
NS_ConvertUTF16toUTF8(aPolicyString).get()));
|
||||
|
||||
if (aSelfURI) {
|
||||
// aSelfURI will be disregarded since we will remove it with bug 991474
|
||||
NS_WARNING("aSelfURI should be a nullptr in AppendPolicy and removed in bug 991474");
|
||||
}
|
||||
// Use the mSelfURI from setRequestContext, see bug 991474
|
||||
NS_ASSERTION(mSelfURI, "mSelfURI required for AppendPolicy, but not set");
|
||||
nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(aPolicyString, mSelfURI, aReportOnly, mInnerWindowID);
|
||||
@ -547,7 +535,6 @@ getInnerWindowID(nsIRequest* aRequest) {
|
||||
NS_IMETHODIMP
|
||||
nsCSPContext::SetRequestContext(nsIURI* aSelfURI,
|
||||
nsIURI* aReferrer,
|
||||
nsIPrincipal* aDocumentPrincipal,
|
||||
nsIChannel* aChannel)
|
||||
{
|
||||
NS_PRECONDITION(aSelfURI || aChannel, "Need aSelfURI or aChannel to set the context properly");
|
||||
|
@ -28,7 +28,6 @@ using namespace mozilla;
|
||||
|
||||
/* Keeps track of whether or not CSP is enabled */
|
||||
bool CSPService::sCSPEnabled = true;
|
||||
bool CSPService::sNewBackendEnabled = true;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo* gCspPRLog;
|
||||
@ -37,7 +36,6 @@ static PRLogModuleInfo* gCspPRLog;
|
||||
CSPService::CSPService()
|
||||
{
|
||||
Preferences::AddBoolVarCache(&sCSPEnabled, "security.csp.enable");
|
||||
Preferences::AddBoolVarCache(&sNewBackendEnabled, "security.csp.newbackend.enable");
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (!gCspPRLog)
|
||||
@ -100,8 +98,9 @@ CSPService::ShouldLoad(uint32_t aContentType,
|
||||
|
||||
|
||||
// These content types are not subject to CSP content policy checks:
|
||||
// TYPE_CSP_REPORT, TYPE_REFRESH, TYPE_DOCUMENT
|
||||
// (their mappings are null in contentSecurityPolicy.js)
|
||||
// TYPE_CSP_REPORT -- csp can't block csp reports
|
||||
// TYPE_REFRESH -- never passed to ShouldLoad (see nsIContentPolicy.idl)
|
||||
// TYPE_DOCUMENT -- used for frame-ancestors
|
||||
if (aContentType == nsIContentPolicy::TYPE_CSP_REPORT ||
|
||||
aContentType == nsIContentPolicy::TYPE_REFRESH ||
|
||||
aContentType == nsIContentPolicy::TYPE_DOCUMENT) {
|
||||
|
@ -26,7 +26,6 @@ public:
|
||||
|
||||
CSPService();
|
||||
static bool sCSPEnabled;
|
||||
static bool sNewBackendEnabled;
|
||||
|
||||
protected:
|
||||
virtual ~CSPService();
|
||||
|
@ -2643,8 +2643,9 @@ nsDocument::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages)
|
||||
}
|
||||
|
||||
static nsresult
|
||||
AppendCSPFromHeader(nsIContentSecurityPolicy* csp, const nsAString& aHeaderValue,
|
||||
nsIURI* aSelfURI, bool aReportOnly)
|
||||
AppendCSPFromHeader(nsIContentSecurityPolicy* csp,
|
||||
const nsAString& aHeaderValue,
|
||||
bool aReportOnly)
|
||||
{
|
||||
// Need to tokenize the header value since multiple headers could be
|
||||
// concatenated into one comma-separated list of policies.
|
||||
@ -2653,7 +2654,7 @@ AppendCSPFromHeader(nsIContentSecurityPolicy* csp, const nsAString& aHeaderValue
|
||||
nsCharSeparatedTokenizer tokenizer(aHeaderValue, ',');
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsSubstring& policy = tokenizer.nextToken();
|
||||
rv = csp->AppendPolicy(policy, aSelfURI, aReportOnly);
|
||||
rv = csp->AppendPolicy(policy, aReportOnly);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
#ifdef PR_LOGGING
|
||||
{
|
||||
@ -2764,17 +2765,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
}
|
||||
}
|
||||
|
||||
// Create new CSP object:
|
||||
// * by default we are trying to use the new C++ implmentation
|
||||
// * however, we still support XCSP headers during the transition phase
|
||||
// and fall back to the JS implementation if we find an XCSP header.
|
||||
|
||||
if (CSPService::sNewBackendEnabled) {
|
||||
csp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
|
||||
}
|
||||
else {
|
||||
csp = do_CreateInstance("@mozilla.org/contentsecuritypolicy;1", &rv);
|
||||
}
|
||||
csp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
#ifdef PR_LOGGING
|
||||
@ -2788,7 +2779,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
aChannel->GetURI(getter_AddRefs(selfURI));
|
||||
|
||||
// Store the request context for violation reports
|
||||
csp->SetRequestContext(nullptr, nullptr, nullptr, aChannel);
|
||||
csp->SetRequestContext(nullptr, nullptr, aChannel);
|
||||
|
||||
// ----- if the doc is an app and we want a default CSP, apply it.
|
||||
if (applyAppDefaultCSP) {
|
||||
@ -2802,24 +2793,24 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
}
|
||||
|
||||
if (appCSP) {
|
||||
csp->AppendPolicy(appCSP, selfURI, false);
|
||||
csp->AppendPolicy(appCSP, false);
|
||||
}
|
||||
}
|
||||
|
||||
// ----- if the doc is an app and specifies a CSP in its manifest, apply it.
|
||||
if (applyAppManifestCSP) {
|
||||
csp->AppendPolicy(appManifestCSP, selfURI, false);
|
||||
csp->AppendPolicy(appManifestCSP, false);
|
||||
}
|
||||
|
||||
// ----- if there's a full-strength CSP header, apply it.
|
||||
if (!cspHeaderValue.IsEmpty()) {
|
||||
rv = AppendCSPFromHeader(csp, cspHeaderValue, selfURI, false);
|
||||
rv = AppendCSPFromHeader(csp, cspHeaderValue, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// ----- if there's a report-only CSP header, apply it.
|
||||
if (!cspROHeaderValue.IsEmpty()) {
|
||||
rv = AppendCSPFromHeader(csp, cspROHeaderValue, selfURI, true);
|
||||
rv = AppendCSPFromHeader(csp, cspROHeaderValue, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
@ -4334,7 +4325,7 @@ void
|
||||
nsIDocument::SetContainer(nsDocShell* aContainer)
|
||||
{
|
||||
if (aContainer) {
|
||||
mDocumentContainer = aContainer->asWeakPtr();
|
||||
mDocumentContainer = aContainer;
|
||||
} else {
|
||||
mDocumentContainer = WeakPtr<nsDocShell>();
|
||||
}
|
||||
|
@ -108,16 +108,13 @@ nsresult runTest(uint32_t aExpectedPolicyCount, // this should be 0 for policies
|
||||
// arguments can be nullptrs.
|
||||
csp->SetRequestContext(selfURI,
|
||||
nullptr, // nsIURI* aReferrer
|
||||
nullptr, // nsIPrincipal* aDocumentPrincipal
|
||||
dummyChannel);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// append a policy
|
||||
nsString policyStr;
|
||||
policyStr.AssignASCII(aPolicy);
|
||||
// Second argument in AppendPolicy needs to be a nullptr,
|
||||
// because we are using the selfURI set in SetRequestingContext
|
||||
rv = csp->AppendPolicy(policyStr, nullptr, false);
|
||||
rv = csp->AppendPolicy(policyStr, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// when executing fuzzy tests we do not care about the actual output
|
||||
|
@ -44,7 +44,7 @@
|
||||
let appchan = SpecialPowers.Services.io.newChannel(gManifestURL, null, null);
|
||||
|
||||
try {
|
||||
csp.setRequestContext(null, null, null, appchan);
|
||||
csp.setRequestContext(null, null, appchan);
|
||||
ok(true, "setRequestContext hasn't thown");
|
||||
} catch(e) {
|
||||
ok(false, "setRequestContext throws");
|
||||
|
@ -1,159 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import('resource://gre/modules/CSPUtils.jsm');
|
||||
|
||||
var ioService = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
var self = ioService.newURI("http://test1.example.com:80", null, null);
|
||||
|
||||
function testValidSRCsHostSourceWithSchemeAndPath() {
|
||||
var csps = [
|
||||
"http://test1.example.com",
|
||||
"http://test1.example.com/",
|
||||
"http://test1.example.com/path-1",
|
||||
"http://test1.example.com/path-1/",
|
||||
"http://test1.example.com/path-1/path_2/",
|
||||
"http://test1.example.com/path-1/path_2/file.js",
|
||||
"http://test1.example.com/path-1/path_2/file_1.js",
|
||||
"http://test1.example.com/path-1/path_2/file-2.js",
|
||||
"http://test1.example.com/path-1/path_2/f.js",
|
||||
"http://test1.example.com/path-1/path_2/f.oo.js"
|
||||
]
|
||||
|
||||
var obj;
|
||||
var expected = "http://test1.example.com";
|
||||
for (let i in csps) {
|
||||
var src = csps[i];
|
||||
obj = CSPSourceList.fromString(src, undefined, self);
|
||||
dump("expected: " + expected + "\n");
|
||||
dump("got: " + obj._sources[0] + "\n");
|
||||
do_check_eq(1, obj._sources.length);
|
||||
do_check_eq(obj._sources[0], expected);
|
||||
}
|
||||
}
|
||||
|
||||
function testValidSRCsRegularHost() {
|
||||
var csps = [
|
||||
"test1.example.com",
|
||||
"test1.example.com/",
|
||||
"test1.example.com/path-1",
|
||||
"test1.example.com/path-1/",
|
||||
"test1.example.com/path-1/path_2/",
|
||||
"test1.example.com/path-1/path_2/file.js",
|
||||
"test1.example.com/path-1/path_2/file_1.js",
|
||||
"test1.example.com/path-1/path_2/file-2.js",
|
||||
"test1.example.com/path-1/path_2/f.js",
|
||||
"test1.example.com/path-1/path_2/f.oo.js"
|
||||
]
|
||||
|
||||
var obj;
|
||||
var expected = "http://test1.example.com";
|
||||
for (let i in csps) {
|
||||
var src = csps[i];
|
||||
obj = CSPSourceList.fromString(src, undefined, self);
|
||||
do_check_eq(1, obj._sources.length);
|
||||
do_check_eq(obj._sources[0], expected);
|
||||
}
|
||||
}
|
||||
|
||||
function testValidSRCsWildCardHost() {
|
||||
var csps = [
|
||||
"*.example.com",
|
||||
"*.example.com/",
|
||||
"*.example.com/path-1",
|
||||
"*.example.com/path-1/",
|
||||
"*.example.com/path-1/path_2/",
|
||||
"*.example.com/path-1/path_2/file.js",
|
||||
"*.example.com/path-1/path_2/file_1.js",
|
||||
"*.example.com/path-1/path_2/file-2.js",
|
||||
"*.example.com/path-1/path_2/f.js",
|
||||
"*.example.com/path-1/path_2/f.oo.js"
|
||||
]
|
||||
|
||||
var obj;
|
||||
var expected = "http://*.example.com";
|
||||
for (let i in csps) {
|
||||
var src = csps[i];
|
||||
obj = CSPSourceList.fromString(src, undefined, self);
|
||||
do_check_eq(1, obj._sources.length);
|
||||
do_check_eq(obj._sources[0], expected);
|
||||
}
|
||||
}
|
||||
|
||||
function testValidSRCsRegularPort() {
|
||||
var csps = [
|
||||
"test1.example.com:80",
|
||||
"test1.example.com:80/",
|
||||
"test1.example.com:80/path-1",
|
||||
"test1.example.com:80/path-1/",
|
||||
"test1.example.com:80/path-1/path_2",
|
||||
"test1.example.com:80/path-1/path_2/",
|
||||
"test1.example.com:80/path-1/path_2/file.js",
|
||||
"test1.example.com:80/path-1/path_2/f.ile.js"
|
||||
]
|
||||
|
||||
var obj;
|
||||
var expected = "http://test1.example.com";
|
||||
for (let i in csps) {
|
||||
var src = csps[i];
|
||||
obj = CSPSourceList.fromString(src, undefined, self);
|
||||
do_check_eq(1, obj._sources.length);
|
||||
do_check_eq(obj._sources[0], expected);
|
||||
}
|
||||
}
|
||||
|
||||
function testValidSRCsWildCardPort() {
|
||||
var csps = [
|
||||
"test1.example.com:*",
|
||||
"test1.example.com:*/",
|
||||
"test1.example.com:*/path-1",
|
||||
"test1.example.com:*/path-1/",
|
||||
"test1.example.com:*/path-1/path_2",
|
||||
"test1.example.com:*/path-1/path_2/",
|
||||
"test1.example.com:*/path-1/path_2/file.js",
|
||||
"test1.example.com:*/path-1/path_2/f.ile.js"
|
||||
]
|
||||
|
||||
var obj;
|
||||
var expected = "http://test1.example.com:*";
|
||||
for (let i in csps) {
|
||||
var src = csps[i];
|
||||
obj = CSPSourceList.fromString(src, undefined, self);
|
||||
do_check_eq(1, obj._sources.length);
|
||||
do_check_eq(obj._sources[0], expected);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function testInvalidSRCs() {
|
||||
var csps = [
|
||||
"test1.example.com:88path-1/",
|
||||
"test1.example.com:80.js",
|
||||
"test1.example.com:*.js",
|
||||
"test1.example.com:*."
|
||||
]
|
||||
|
||||
var obj;
|
||||
var expected = [];
|
||||
for (let i in csps) {
|
||||
var src = csps[i];
|
||||
obj = CSPSourceList.fromString(src, undefined, self);
|
||||
do_check_eq(0, obj._sources.length);
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
testValidSRCsHostSourceWithSchemeAndPath();
|
||||
testValidSRCsRegularHost();
|
||||
testValidSRCsWildCardHost();
|
||||
testValidSRCsRegularPort();
|
||||
testValidSRCsWildCardPort();
|
||||
testInvalidSRCs();
|
||||
do_test_finished();
|
||||
}
|
@ -75,11 +75,11 @@ function makeTest(id, expectedJSON, useReportOnlyPolicy, callback) {
|
||||
dump("Created test " + id + " : " + policy + "\n\n");
|
||||
|
||||
// make the reports seem authentic by "binding" them to a channel.
|
||||
csp.setRequestContext(selfuri, null, null, selfchan);
|
||||
csp.setRequestContext(selfuri, null, selfchan);
|
||||
|
||||
// Load up the policy
|
||||
// set as report-only if that's the case
|
||||
csp.appendPolicy(policy, selfuri, useReportOnlyPolicy);
|
||||
csp.appendPolicy(policy, useReportOnlyPolicy);
|
||||
|
||||
// prime the report server
|
||||
var handler = makeReportHandler("/test" + id, "Test " + id, expectedJSON);
|
||||
|
@ -1,879 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
//load('CSPUtils.jsm');
|
||||
Cu.import('resource://gre/modules/CSPUtils.jsm');
|
||||
Cu.import('resource://gre/modules/NetUtil.jsm');
|
||||
|
||||
var httpServer = new HttpServer();
|
||||
httpServer.start(-1);
|
||||
|
||||
const POLICY_FROM_URI = "default-src 'self'; img-src *";
|
||||
const POLICY_PORT = httpServer.identity.primaryPort;
|
||||
const POLICY_URI = "http://localhost:" + POLICY_PORT + "/policy";
|
||||
const POLICY_URI_RELATIVE = "/policy";
|
||||
|
||||
//converts string to nsIURI
|
||||
function URI(uriString) {
|
||||
var ioService = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
return ioService.newURI(uriString, null, null);
|
||||
}
|
||||
|
||||
|
||||
// helper to assert that an array has the given value somewhere.
|
||||
function do_check_in_array(arr, val, stack) {
|
||||
if (!stack)
|
||||
stack = Components.stack.caller;
|
||||
|
||||
var text = val + " in [" + arr.join(",") + "]";
|
||||
|
||||
for(var i in arr) {
|
||||
//dump(".......... " + i + "> " + arr[i] + "\n");
|
||||
if(arr[i] == val) {
|
||||
//succeed
|
||||
++_passedChecks;
|
||||
dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
|
||||
stack.lineNumber + "] " + text + "\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
do_throw(text, stack);
|
||||
}
|
||||
|
||||
// helper to assert that an object or array must have a given key
|
||||
function do_check_has_key(foo, key, stack) {
|
||||
if (!stack)
|
||||
stack = Components.stack.caller;
|
||||
|
||||
var keys = [];
|
||||
for (let k in foo) { keys.push(k); }
|
||||
var text = key + " in [" + keys.join(",") + "]";
|
||||
|
||||
for (var x in foo) {
|
||||
if (x == key) {
|
||||
//succeed
|
||||
++_passedChecks;
|
||||
dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
|
||||
stack.lineNumber + "] " + text + "\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
do_throw(text, stack);
|
||||
}
|
||||
|
||||
// helper to use .equals on stuff
|
||||
function do_check_equivalent(foo, bar, stack) {
|
||||
if (!stack)
|
||||
stack = Components.stack.caller;
|
||||
|
||||
var text = foo + ".equals(" + bar + ")";
|
||||
|
||||
if(foo.equals && foo.equals(bar)) {
|
||||
++_passedChecks;
|
||||
dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
|
||||
stack.lineNumber + "] " + text + "\n");
|
||||
return;
|
||||
}
|
||||
do_throw(text, stack);
|
||||
}
|
||||
|
||||
var tests = [];
|
||||
function test(fcn) {
|
||||
tests.push(fcn);
|
||||
}
|
||||
|
||||
test(
|
||||
function test_CSPHost_fromstring() {
|
||||
var h;
|
||||
|
||||
h = CSPHost.fromString("*");
|
||||
do_check_neq(null, h); // "* lone wildcard should work"
|
||||
|
||||
h = CSPHost.fromString("foo.bar");
|
||||
do_check_neq(null, h); // "standard tuple failed"
|
||||
|
||||
h = CSPHost.fromString("*.bar");
|
||||
do_check_neq(null, h); // "wildcard failed"
|
||||
|
||||
h = CSPHost.fromString("foo.*.bar");
|
||||
do_check_eq(null, h); // "wildcard in wrong place worked"
|
||||
|
||||
h = CSPHost.fromString("com");
|
||||
do_check_neq(null, h); // "lone symbol should not fail"
|
||||
|
||||
h = CSPHost.fromString("f00b4r.com");
|
||||
do_check_neq(null, h); // "Numbers in hosts should work"
|
||||
|
||||
h = CSPHost.fromString("foo-bar.com");
|
||||
do_check_neq(null, h); // "dashes in hosts should work"
|
||||
|
||||
|
||||
h = CSPHost.fromString("foo!bar.com");
|
||||
do_check_eq(null, h); // "special chars in hosts should fail"
|
||||
|
||||
h = CSPHost.fromString("{app-url-is-uid}");
|
||||
do_check_neq(null, h); // "Packaged apps URLs failed"
|
||||
});
|
||||
|
||||
test(
|
||||
function test_CSPHost_clone() {
|
||||
h = CSPHost.fromString("*.a.b.c");
|
||||
h2 = h.clone();
|
||||
for(var i in h._segments) {
|
||||
// "cloned segments should match"
|
||||
do_check_eq(h._segments[i], h2._segments[i]);
|
||||
}
|
||||
});
|
||||
|
||||
test(
|
||||
function test_CSPHost_permits() {
|
||||
var h = CSPHost.fromString("*.b.c");
|
||||
var h2 = CSPHost.fromString("a.b.c");
|
||||
do_check_true( h.permits(h2)); //"CSPHost *.b.c should allow CSPHost a.b.c"
|
||||
do_check_true( h.permits("a.b.c")); //"CSPHost *.b.c should allow string a.b.c"
|
||||
do_check_false(h.permits("b.c")); //"CSPHost *.b.c should not allow string b.c"
|
||||
do_check_false(h.permits("a.a.c")); //"CSPHost *.b.c should not allow string a.a.c"
|
||||
do_check_false(h2.permits(h)); //"CSPHost a.b.c should not allow CSPHost *.b.c"
|
||||
do_check_false(h2.permits("b.c")); //"CSPHost a.b.c should not allow string b.c"
|
||||
do_check_true( h2.permits("a.b.c")); //"CSPHost a.b.c should allow string a.b.c"
|
||||
});
|
||||
|
||||
|
||||
///////////////////// Test the Source object //////////////////////
|
||||
|
||||
test(
|
||||
function test_CSPSource_fromString() {
|
||||
// can't do these tests because "self" is not defined.
|
||||
//"basic source should not be null.");
|
||||
do_check_neq(null, CSPSource.fromString("a.com", undefined, "http://abc.com"));
|
||||
|
||||
//"ldh characters should all work for host.");
|
||||
do_check_neq(null, CSPSource.fromString("a2-c.com", undefined, "https://a.com"));
|
||||
|
||||
//"wildcard should work in first token for host.");
|
||||
do_check_neq(null, CSPSource.fromString("*.a.com", undefined, "http://abc.com"));
|
||||
|
||||
//print(" --- Ignore the following two errors if they print ---");
|
||||
//"wildcard should not work in non-first token for host.");
|
||||
do_check_eq(null, CSPSource.fromString("x.*.a.com", undefined, "http://a.com"));
|
||||
|
||||
//"funny characters (#) should not work for host.");
|
||||
do_check_eq(null, CSPSource.fromString("a#2-c.com", undefined, "http://a.com"));
|
||||
|
||||
//print(" --- Stop ignoring errors that print ---\n");
|
||||
|
||||
//"failed to parse host with port.");
|
||||
do_check_neq(null, CSPSource.create("a.com:23", undefined, "http://a.com"));
|
||||
//"failed to parse host with scheme.");
|
||||
do_check_neq(null, CSPSource.create("https://a.com", undefined, "http://a.com"));
|
||||
//"failed to parse host with scheme and port.");
|
||||
do_check_neq(null, CSPSource.create("https://a.com:200", undefined, "http://a.com"));
|
||||
|
||||
//Check to make sure we don't match multiple instances with regex
|
||||
do_check_eq(null, CSPSource.create("http://foo.com:bar.com:23"));
|
||||
//Port parsing should work for all schemes
|
||||
do_check_neq(null, CSPSource.create("data:"));
|
||||
do_check_neq(null, CSPSource.create("javascript:"));
|
||||
|
||||
//"app:// URLs should work, including the {} characters.");
|
||||
do_check_neq(null, CSPSource.fromString("{app-host-is-uid}", undefined, "app://{app-host-is-uid}"));
|
||||
});
|
||||
|
||||
test(
|
||||
function test_CSPSource_fromString_withSelf() {
|
||||
var src;
|
||||
src = CSPSource.create("a.com", undefined, "https://foobar.com:443");
|
||||
//"src should inherit port *
|
||||
do_check_true(src.permits("https://a.com:443"));
|
||||
//"src should inherit and require https scheme
|
||||
do_check_false(src.permits("http://a.com"));
|
||||
//"src should inherit scheme 'https'"
|
||||
do_check_true(src.permits("https://a.com"));
|
||||
|
||||
src = CSPSource.create("http://a.com", undefined, "https://foobar.com:443");
|
||||
//"src should inherit and require http scheme"
|
||||
do_check_false(src.permits("https://a.com"));
|
||||
//"src should inherit scheme 'http'"
|
||||
do_check_true(src.permits("http://a.com"));
|
||||
//"src should inherit port and scheme from parent"
|
||||
//"src should inherit default port for 'http'"
|
||||
do_check_true(src.permits("http://a.com:80"));
|
||||
|
||||
src = CSPSource.create("'self'", undefined, "https://foobar.com:443");
|
||||
//"src should inherit port *
|
||||
do_check_true(src.permits("https://foobar.com:443"));
|
||||
//"src should inherit and require https scheme
|
||||
do_check_false(src.permits("http://foobar.com"));
|
||||
//"src should inherit scheme 'https'"
|
||||
do_check_true(src.permits("https://foobar.com"));
|
||||
//"src should reject other hosts"
|
||||
do_check_false(src.permits("https://a.com"));
|
||||
|
||||
src = CSPSource.create("javascript:", undefined, "https://foobar.com:443");
|
||||
//"hostless schemes should be parseable."
|
||||
var aUri = NetUtil.newURI("javascript:alert('foo');");
|
||||
do_check_true(src.permits(aUri));
|
||||
//"src should reject other hosts"
|
||||
do_check_false(src.permits("https://a.com"));
|
||||
//"nothing else should be allowed"
|
||||
do_check_false(src.permits("https://foobar.com"));
|
||||
|
||||
src = CSPSource.create("{app-host-is-uid}", undefined, "app://{app-host-is-uid}");
|
||||
//"src should inherit and require 'app' scheme"
|
||||
do_check_false(src.permits("https://{app-host-is-uid}"));
|
||||
//"src should inherit scheme 'app'"
|
||||
do_check_true(src.permits("app://{app-host-is-uid}"));
|
||||
|
||||
});
|
||||
|
||||
///////////////////// Test the source list //////////////////////
|
||||
|
||||
test(
|
||||
function test_CSPSourceList_fromString() {
|
||||
var sd = CSPSourceList.fromString("'none'");
|
||||
//"'none' -- should parse"
|
||||
do_check_neq(null,sd);
|
||||
// "'none' should be a zero-length list"
|
||||
do_check_eq(0, sd._sources.length);
|
||||
do_check_true(sd.isNone());
|
||||
|
||||
sd = CSPSourceList.fromString("*");
|
||||
//"'*' should be a zero-length list"
|
||||
do_check_eq(0, sd._sources.length);
|
||||
|
||||
//print(" --- Ignore the following three errors if they print ---");
|
||||
//"funny char in host"
|
||||
do_check_true(CSPSourceList.fromString("f!oo.bar").isNone());
|
||||
//"funny char in scheme"
|
||||
do_check_true(CSPSourceList.fromString("ht!ps://f-oo.bar").isNone());
|
||||
//"funny char in port"
|
||||
do_check_true(CSPSourceList.fromString("https://f-oo.bar:3f").isNone());
|
||||
//print(" --- Stop ignoring errors that print ---\n");
|
||||
});
|
||||
|
||||
test(
|
||||
function test_CSPSourceList_fromString_twohost() {
|
||||
var str = "foo.bar:21 https://ras.bar";
|
||||
var parsed = "http://foo.bar:21 https://ras.bar";
|
||||
var sd = CSPSourceList.fromString(str, undefined, URI("http://self.com:80"));
|
||||
//"two-host list should parse"
|
||||
do_check_neq(null,sd);
|
||||
//"two-host list should parse to two hosts"
|
||||
do_check_eq(2, sd._sources.length);
|
||||
//"two-host list should contain original data"
|
||||
do_check_eq(parsed, sd.toString());
|
||||
});
|
||||
|
||||
test(
|
||||
function test_CSPSourceList_permits() {
|
||||
var nullSourceList = CSPSourceList.fromString("'none'");
|
||||
var simpleSourceList = CSPSourceList.fromString("a.com", undefined, URI("http://self.com"));
|
||||
var doubleSourceList = CSPSourceList.fromString("https://foo.com http://bar.com:88",
|
||||
undefined,
|
||||
URI("http://self.com:88"));
|
||||
var allSourceList = CSPSourceList.fromString("*");
|
||||
var allAndMoreSourceList = CSPSourceList.fromString("* https://bar.com 'none'");
|
||||
var wildcardHostSourceList = CSPSourceList.fromString("*.foo.com",
|
||||
undefined, URI("http://self.com"));
|
||||
var allDoubledHostSourceList = CSPSourceList.fromString("**");
|
||||
var allGarbageHostSourceList = CSPSourceList.fromString("*a");
|
||||
|
||||
//'none' should permit none."
|
||||
do_check_false( nullSourceList.permits("http://a.com"));
|
||||
//a.com should permit a.com"
|
||||
do_check_true( simpleSourceList.permits("http://a.com"));
|
||||
//wrong host"
|
||||
do_check_false( simpleSourceList.permits("http://b.com"));
|
||||
//double list permits http://bar.com:88"
|
||||
do_check_true( doubleSourceList.permits("http://bar.com:88"));
|
||||
//double list permits https://bar.com:88"
|
||||
do_check_false( doubleSourceList.permits("https://bar.com:88"));
|
||||
//double list does not permit http://bar.com:443"
|
||||
do_check_false( doubleSourceList.permits("http://bar.com:443"));
|
||||
//"double list permits https://foo.com:88" (should not inherit port)
|
||||
do_check_false( doubleSourceList.permits("https://foo.com:88"));
|
||||
//"double list does not permit foo.com on http"
|
||||
do_check_false( doubleSourceList.permits("http://foo.com"));
|
||||
|
||||
//"* does not permit specific host"
|
||||
do_check_true( allSourceList.permits("http://x.com:23"));
|
||||
//"* does not permit a long host with no port"
|
||||
do_check_true( allSourceList.permits("http://a.b.c.d.e.f.g.h.i.j.k.l.x.com"));
|
||||
|
||||
//* short circuts parsing
|
||||
do_check_true(allAndMoreSourceList.permits("http://a.com"));
|
||||
|
||||
//"** permits all"
|
||||
do_check_false(allDoubledHostSourceList.permits("http://barbaz.com"));
|
||||
//"*a permits all"
|
||||
do_check_false(allGarbageHostSourceList.permits("http://barbaz.com"));
|
||||
|
||||
//"*.foo.com does not permit somerandom.foo.com"
|
||||
do_check_true(wildcardHostSourceList.permits("http://somerandom.foo.com"));
|
||||
//"*.foo.com permits all"
|
||||
do_check_false(wildcardHostSourceList.permits("http://barbaz.com"));
|
||||
});
|
||||
|
||||
//////////////// TEST CSP REP SPEC COMPLIANT PARSER ////////////
|
||||
test(
|
||||
function test_CSPRep_fromString() {
|
||||
|
||||
var cspr;
|
||||
var cspr_allowval;
|
||||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC, SD.SCRIPT_SRC, SD.FONT_SRC,
|
||||
SD.OBJECT_SRC, SD.FRAME_SRC, SD.CONNECT_SRC];
|
||||
|
||||
// check default policy "default-src *"
|
||||
cspr = CSPRep.fromString("default-src *", URI("http://self.com:80"));
|
||||
// "DEFAULT_SRC directive is missing when specified in fromString"
|
||||
do_check_has_key(cspr._directives, SD.DEFAULT_SRC);
|
||||
|
||||
for(var x in DEFAULTS) {
|
||||
// each of these should be equivalent to DEFAULT_SRC
|
||||
//DEFAULTS[x] + " does not use default rule."
|
||||
do_check_true(cspr.permits("http://bar.com", DEFAULTS[x]));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test(
|
||||
function test_CSPRep_fromString_oneDir() {
|
||||
|
||||
var cspr;
|
||||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC,
|
||||
SD.FRAME_SRC, SD.CONNECT_SRC];
|
||||
|
||||
// check one-directive policies
|
||||
cspr = CSPRep.fromString("default-src bar.com; script-src https://foo.com",
|
||||
URI("http://self.com"));
|
||||
|
||||
for(var x in DEFAULTS) {
|
||||
//DEFAULTS[x] + " does not use default rule."
|
||||
do_check_false(cspr.permits("http://bar.com:22", DEFAULTS[x]));
|
||||
//DEFAULTS[x] + " does not use default rule."
|
||||
do_check_true(cspr.permits("http://bar.com:80", DEFAULTS[x]));
|
||||
//DEFAULTS[x] + " does not use default rule."
|
||||
do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
|
||||
//DEFAULTS[x] + " does not use default rule."
|
||||
do_check_false(cspr.permits("https://foo.com", DEFAULTS[x]));
|
||||
}
|
||||
//"script-src false positive in policy.
|
||||
do_check_false(cspr.permits("http://bar.com:22", SD.SCRIPT_SRC));
|
||||
//"script-src false negative in policy.
|
||||
do_check_true(cspr.permits("https://foo.com:443", SD.SCRIPT_SRC));
|
||||
});
|
||||
|
||||
test(
|
||||
function test_CSPRep_fromString_twoDir() {
|
||||
var cspr;
|
||||
|
||||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
|
||||
var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.FRAME_SRC,
|
||||
SD.CONNECT_SRC];
|
||||
|
||||
// check two-directive policies
|
||||
var polstr = "default-src allow.com; " +
|
||||
"script-src https://foo.com; " +
|
||||
"img-src bar.com:*";
|
||||
cspr = CSPRep.fromString(polstr, URI("http://self.com"));
|
||||
|
||||
for(var x in DEFAULTS) {
|
||||
do_check_true(cspr.permits("http://allow.com", DEFAULTS[x]));
|
||||
//DEFAULTS[x] + " does not use default rule.
|
||||
do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
|
||||
//DEFAULTS[x] + " does not use default rule.
|
||||
do_check_false(cspr.permits("http://bar.com:400", DEFAULTS[x]));
|
||||
//DEFAULTS[x] + " does not use default rule.
|
||||
}
|
||||
//"img-src does not use default rule.
|
||||
do_check_false(cspr.permits("http://allow.com:22", SD.IMG_SRC));
|
||||
//"img-src does not use default rule.
|
||||
do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
|
||||
//"img-src does not use default rule.
|
||||
do_check_true(cspr.permits("http://bar.com:88", SD.IMG_SRC));
|
||||
|
||||
//"script-src does not use default rule.
|
||||
do_check_false(cspr.permits("http://allow.com:22", SD.SCRIPT_SRC));
|
||||
//"script-src does not use default rule.
|
||||
do_check_true(cspr.permits("https://foo.com:443", SD.SCRIPT_SRC));
|
||||
//"script-src does not use default rule.
|
||||
do_check_false(cspr.permits("http://bar.com:400", SD.SCRIPT_SRC));
|
||||
});
|
||||
|
||||
test(function test_CSPRep_fromString_withself() {
|
||||
var cspr;
|
||||
var self = "https://self.com:34";
|
||||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
|
||||
// check one-directive policies
|
||||
cspr = CSPRep.fromString("default-src 'self'; script-src 'self' https://*:*",
|
||||
URI(self));
|
||||
//"img-src does not enforce default rule, 'self'.
|
||||
do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
|
||||
//"img-src does not allow self
|
||||
do_check_true(cspr.permits(self, SD.IMG_SRC));
|
||||
//"script-src is too relaxed
|
||||
do_check_false(cspr.permits("http://evil.com", SD.SCRIPT_SRC));
|
||||
//"script-src should allow self
|
||||
do_check_true(cspr.permits(self, SD.SCRIPT_SRC));
|
||||
//"script-src is too strict on host/port
|
||||
do_check_true(cspr.permits("https://evil.com:100", SD.SCRIPT_SRC));
|
||||
});
|
||||
|
||||
|
||||
//////////////// TEST FRAME ANCESTOR DEFAULTS /////////////////
|
||||
// (see bug 555068)
|
||||
test(function test_FrameAncestor_defaults() {
|
||||
var cspr;
|
||||
var self = "http://self.com:34";
|
||||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
|
||||
cspr = CSPRep.fromString("default-src 'none'", URI(self));
|
||||
|
||||
//"frame-ancestors should default to * not 'default-src' value"
|
||||
do_check_true(cspr.permits("https://foo.com:400", SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits("http://self.com:34", SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits("https://self.com:34", SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits("http://self.com", SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits("http://subd.self.com:34", SD.FRAME_ANCESTORS));
|
||||
|
||||
cspr = CSPRep.fromString("default-src 'none'; frame-ancestors 'self'", URI(self));
|
||||
|
||||
//"frame-ancestors should only allow self"
|
||||
do_check_true(cspr.permits("http://self.com:34", SD.FRAME_ANCESTORS));
|
||||
do_check_false(cspr.permits("https://foo.com:400", SD.FRAME_ANCESTORS));
|
||||
do_check_false(cspr.permits("https://self.com:34", SD.FRAME_ANCESTORS));
|
||||
do_check_false(cspr.permits("http://self.com", SD.FRAME_ANCESTORS));
|
||||
do_check_false(cspr.permits("http://subd.self.com:34", SD.FRAME_ANCESTORS));
|
||||
});
|
||||
|
||||
|
||||
test(function test_FrameAncestor_TLD_defaultPorts() {
|
||||
var cspr;
|
||||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
var self = "http://self"; //TLD only, no .com or anything.
|
||||
|
||||
cspr = CSPRep.fromString("default-src 'self'; frame-ancestors 'self' http://foo:80 bar:80 http://three", URI(self));
|
||||
|
||||
//"frame-ancestors should default to * not 'allow' value"
|
||||
do_check_true(cspr.permits("http://self", SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits("http://self:80", SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits("http://foo", SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits("http://foo:80", SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits("http://bar", SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits("http://three:80", SD.FRAME_ANCESTORS));
|
||||
|
||||
do_check_false(cspr.permits("https://foo:400", SD.FRAME_ANCESTORS));
|
||||
do_check_false(cspr.permits("https://self:34", SD.FRAME_ANCESTORS));
|
||||
do_check_false(cspr.permits("https://bar", SD.FRAME_ANCESTORS));
|
||||
do_check_false(cspr.permits("http://three:81", SD.FRAME_ANCESTORS));
|
||||
do_check_false(cspr.permits("https://three:81", SD.FRAME_ANCESTORS));
|
||||
});
|
||||
|
||||
test(function test_FrameAncestor_ignores_userpass_bug779918() {
|
||||
var cspr;
|
||||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
var self = "http://self.com/bar";
|
||||
var testPolicy = "default-src 'self'; frame-ancestors 'self'";
|
||||
|
||||
cspr = CSPRep.fromString(testPolicy, URI(self));
|
||||
|
||||
// wrapped in URI() because of source parsing
|
||||
do_check_true(cspr.permits(URI("http://username:password@self.com/foo"), SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits(URI("http://other:pass1@self.com/foo"), SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits(URI("http://self.com:80/foo"), SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits(URI("http://self.com/foo"), SD.FRAME_ANCESTORS));
|
||||
|
||||
// construct fake ancestry with CSP applied to the child.
|
||||
// [aChildUri] -> [aParentUri] -> (root/top)
|
||||
// and then test "permitsAncestry" on the child/self docshell.
|
||||
function testPermits(aChildUri, aParentUri, aContentType) {
|
||||
let cspObj = Cc["@mozilla.org/contentsecuritypolicy;1"]
|
||||
.createInstance(Ci.nsIContentSecurityPolicy);
|
||||
cspObj.appendPolicy(testPolicy, aChildUri, false);
|
||||
let docshellparent = Cc["@mozilla.org/docshell;1"]
|
||||
.createInstance(Ci.nsIDocShell);
|
||||
let docshellchild = Cc["@mozilla.org/docshell;1"]
|
||||
.createInstance(Ci.nsIDocShell);
|
||||
docshellparent.setCurrentURI(aParentUri);
|
||||
docshellchild.setCurrentURI(aChildUri);
|
||||
docshellparent.addChild(docshellchild);
|
||||
return cspObj.permitsAncestry(docshellchild);
|
||||
};
|
||||
|
||||
// check parent without userpass
|
||||
do_check_true(testPermits(URI("http://username:password@self.com/foo"),
|
||||
URI("http://self.com/bar")));
|
||||
do_check_true(testPermits(URI("http://user1:pass1@self.com/foo"),
|
||||
URI("http://self.com/bar")));
|
||||
do_check_true(testPermits(URI("http://self.com/foo"),
|
||||
URI("http://self.com/bar")));
|
||||
|
||||
// check parent with userpass
|
||||
do_check_true(testPermits(URI("http://username:password@self.com/foo"),
|
||||
URI("http://username:password@self.com/bar")));
|
||||
do_check_true(testPermits(URI("http://user1:pass1@self.com/foo"),
|
||||
URI("http://username:password@self.com/bar")));
|
||||
do_check_true(testPermits(URI("http://self.com/foo"),
|
||||
URI("http://username:password@self.com/bar")));
|
||||
});
|
||||
|
||||
test(function test_CSP_ReportURI_parsing() {
|
||||
var cspr;
|
||||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
var self = "http://self.com:34";
|
||||
var parsedURIs = [];
|
||||
|
||||
var uri_valid_absolute = self + "/report.py";
|
||||
var uri_other_host_absolute = "http://foo.org:34/report.py";
|
||||
var uri_valid_relative = "/report.py";
|
||||
var uri_valid_relative_expanded = self + uri_valid_relative;
|
||||
var uri_valid_relative2 = "foo/bar/report.py";
|
||||
var uri_valid_relative2_expanded = self + "/" + uri_valid_relative2;
|
||||
var uri_invalid_relative = "javascript:alert(1)";
|
||||
var uri_other_scheme_absolute = "https://self.com/report.py";
|
||||
var uri_other_scheme_and_host_absolute = "https://foo.com/report.py";
|
||||
|
||||
cspr = CSPRep.fromString("default-src *; report-uri " + uri_valid_absolute, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, uri_valid_absolute);
|
||||
do_check_eq(parsedURIs.length, 1);
|
||||
|
||||
cspr = CSPRep.fromString("default-src *; report-uri " + uri_other_host_absolute, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, uri_other_host_absolute);
|
||||
do_check_eq(parsedURIs.length, 1); // the empty string is in there.
|
||||
|
||||
cspr = CSPRep.fromString("default-src *; report-uri " + uri_invalid_relative, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, "");
|
||||
do_check_eq(parsedURIs.length, 1);
|
||||
|
||||
cspr = CSPRep.fromString("default-src *; report-uri " + uri_valid_relative, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, uri_valid_relative_expanded);
|
||||
do_check_eq(parsedURIs.length, 1);
|
||||
|
||||
cspr = CSPRep.fromString("default-src *; report-uri " + uri_valid_relative2, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
dump(parsedURIs.length);
|
||||
do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
|
||||
do_check_eq(parsedURIs.length, 1);
|
||||
|
||||
// make sure cross-scheme reporting works
|
||||
cspr = CSPRep.fromString("default-src *; report-uri " + uri_other_scheme_absolute, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
dump(parsedURIs.length);
|
||||
do_check_in_array(parsedURIs, uri_other_scheme_absolute);
|
||||
do_check_eq(parsedURIs.length, 1);
|
||||
|
||||
// make sure cross-scheme, cross-host reporting works
|
||||
cspr = CSPRep.fromString("default-src *; report-uri " + uri_other_scheme_and_host_absolute, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
dump(parsedURIs.length);
|
||||
do_check_in_array(parsedURIs, uri_other_scheme_and_host_absolute);
|
||||
do_check_eq(parsedURIs.length, 1);
|
||||
|
||||
// combination!
|
||||
cspr = CSPRep.fromString("default-src *; report-uri " +
|
||||
uri_valid_relative2 + " " +
|
||||
uri_valid_absolute, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
|
||||
do_check_in_array(parsedURIs, uri_valid_absolute);
|
||||
do_check_eq(parsedURIs.length, 2);
|
||||
|
||||
cspr = CSPRep.fromString("default-src *; report-uri " +
|
||||
uri_valid_relative2 + " " +
|
||||
uri_other_host_absolute + " " +
|
||||
uri_valid_absolute, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
|
||||
do_check_in_array(parsedURIs, uri_other_host_absolute);
|
||||
do_check_in_array(parsedURIs, uri_valid_absolute);
|
||||
do_check_eq(parsedURIs.length, 3);
|
||||
});
|
||||
|
||||
test(
|
||||
function test_bug634778_duplicateDirective_Detection() {
|
||||
var cspr;
|
||||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
var self = "http://self.com:34";
|
||||
var firstDomain = "http://first.com";
|
||||
var secondDomain = "http://second.com";
|
||||
var thirdDomain = "http://third.com";
|
||||
|
||||
// check for duplicate "default-src" directives
|
||||
// Spec says first directive persists (subsequent re-statement is
|
||||
// ignored)
|
||||
cspr = CSPRep.fromString("default-src " + self + "; default-src " +
|
||||
firstDomain, URI(self));
|
||||
do_check_true(cspr.permits(self, SD.DEFAULT_SRC));
|
||||
do_check_false(cspr.permits(firstDomain, SD.DEFAULT_SRC));
|
||||
|
||||
// check for duplicate report-uri directives
|
||||
cspr = CSPRep.fromString("default-src *; report-uri " + self + "/report.py; report-uri "
|
||||
+ firstDomain + "/report.py", URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, self + "/report.py");
|
||||
do_check_eq(parsedURIs.length, 1);
|
||||
|
||||
// check for three directives with duplicates
|
||||
cspr = CSPRep.fromString("img-src " + firstDomain + "; default-src " + self
|
||||
+ "; img-src " + secondDomain, URI(self));
|
||||
do_check_true(cspr.permits(firstDomain, SD.IMG_SRC));
|
||||
do_check_false(cspr.permits(secondDomain, SD.IMG_SRC));
|
||||
do_check_true(cspr.permits(self, SD.DEFAULT_SRC));
|
||||
|
||||
// check for three directives with duplicates
|
||||
cspr = CSPRep.fromString("img-src " + firstDomain + "; default-src " + self
|
||||
+ "; img-src " + secondDomain, URI(self));
|
||||
do_check_true(cspr.permits(firstDomain, SD.IMG_SRC));
|
||||
do_check_false(cspr.permits(secondDomain, SD.IMG_SRC));
|
||||
|
||||
// check for three directives with duplicates
|
||||
cspr = CSPRep.fromString("default-src " + self + "; img-src " + firstDomain
|
||||
+ "; img-src " + secondDomain, URI(self));
|
||||
do_check_true(cspr.permits(firstDomain, SD.IMG_SRC));
|
||||
do_check_false(cspr.permits(secondDomain, SD.IMG_SRC));
|
||||
|
||||
// check for four directives with duplicates
|
||||
cspr = CSPRep.fromString("default-src " + self + "; img-src " + firstDomain
|
||||
+ "; img-src " + secondDomain + "; img-src "
|
||||
+ thirdDomain, URI(self));
|
||||
do_check_true(cspr.permits(firstDomain, SD.IMG_SRC));
|
||||
do_check_false(cspr.permits(secondDomain, SD.IMG_SRC));
|
||||
do_check_false(cspr.permits(thirdDomain, SD.IMG_SRC));
|
||||
|
||||
// check for four directives with two duplicates
|
||||
cspr = CSPRep.fromString("default-src " + self + "; style-src "
|
||||
+ firstDomain + "; media-src " + firstDomain
|
||||
+ "; media-src " + secondDomain + "; style-src "
|
||||
+ thirdDomain, URI(self));
|
||||
do_check_true(cspr.permits(self, SD.DEFAULT_SRC));
|
||||
do_check_true(cspr.permits(firstDomain, SD.STYLE_SRC));
|
||||
do_check_true(cspr.permits(firstDomain, SD.MEDIA_SRC));
|
||||
do_check_false(cspr.permits(secondDomain, SD.MEDIA_SRC));
|
||||
do_check_false(cspr.permits(thirdDomain, SD.STYLE_SRC));
|
||||
});
|
||||
|
||||
test(
|
||||
function test_bug672961_withNonstandardSelfPort() {
|
||||
/**
|
||||
* When a protected document has a non-standard port, other host names
|
||||
* listed as sources should inherit the scheme of the protected document
|
||||
* but NOT the port. Other hosts should use the default port for the
|
||||
* inherited scheme. For example, since 443 is default for HTTPS:
|
||||
*
|
||||
* Document with CSP: https://foobar.com:4443
|
||||
* Transmitted policy:
|
||||
* "default-src 'self' a.com"
|
||||
* Explicit policy:
|
||||
* "default-src https://foobar.com:4443 https://a.com:443"
|
||||
*
|
||||
* This test examines scheme and nonstandard port inheritance.
|
||||
*/
|
||||
|
||||
var src;
|
||||
src = CSPSource.create("a.com", undefined, "https://foobar.com:4443");
|
||||
//"src should inherit and require https scheme
|
||||
do_check_false(src.permits("http://a.com"));
|
||||
//"src should inherit scheme 'https'"
|
||||
do_check_true(src.permits("https://a.com"));
|
||||
//"src should get default port
|
||||
do_check_true(src.permits("https://a.com:443"));
|
||||
|
||||
src = CSPSource.create("http://a.com", undefined, "https://foobar.com:4443");
|
||||
//"src should require http scheme"
|
||||
do_check_false(src.permits("https://a.com"));
|
||||
//"src should keep scheme 'http'"
|
||||
do_check_true(src.permits("http://a.com"));
|
||||
//"src should inherit default port for 'http'"
|
||||
do_check_true(src.permits("http://a.com:80"));
|
||||
|
||||
src = CSPSource.create("'self'", undefined, "https://foobar.com:4443");
|
||||
//"src should inherit nonstandard port from self
|
||||
do_check_true(src.permits("https://foobar.com:4443"));
|
||||
do_check_false(src.permits("https://foobar.com"));
|
||||
do_check_false(src.permits("https://foobar.com:443"));
|
||||
|
||||
//"src should inherit and require https scheme from self
|
||||
do_check_false(src.permits("http://foobar.com:4443"));
|
||||
do_check_false(src.permits("http://foobar.com"));
|
||||
|
||||
});
|
||||
|
||||
test(
|
||||
function test_bug634773_noneAndStarAreDifferent() {
|
||||
/**
|
||||
* Bug 634773 is that default-src * and default-src 'none' end up "equal" via
|
||||
* CSPSourceList.prototype.equals(), which is wrong. This tests that
|
||||
* doesn't happen.
|
||||
*/
|
||||
|
||||
var p_none = CSPSourceList.fromString("'none'", undefined, "http://foo.com", false);
|
||||
var p_all = CSPSourceList.fromString("*", undefined, "http://foo.com", false);
|
||||
var p_one = CSPSourceList.fromString("bar.com", undefined, "http://foo.com", false);
|
||||
|
||||
do_check_false(p_none.equals(p_all));
|
||||
do_check_false(p_none.equals(p_one));
|
||||
do_check_false(p_all.equals(p_none));
|
||||
do_check_false(p_all.equals(p_one));
|
||||
|
||||
do_check_true(p_all.permits("http://bar.com"));
|
||||
do_check_true(p_one.permits("http://bar.com"));
|
||||
do_check_false(p_none.permits("http://bar.com"));
|
||||
});
|
||||
|
||||
|
||||
test(
|
||||
function test_bug764937_defaultSrcMissing() {
|
||||
var cspObj = Cc["@mozilla.org/contentsecuritypolicy;1"]
|
||||
.createInstance(Ci.nsIContentSecurityPolicy);
|
||||
var selfURI = URI("http://self.com/");
|
||||
|
||||
function testPermits(cspObj, aUri, aContentType) {
|
||||
return cspObj.shouldLoad(aContentType, aUri, null, null, null, null)
|
||||
== Ci.nsIContentPolicy.ACCEPT;
|
||||
};
|
||||
|
||||
const policy = "script-src 'self'";
|
||||
cspObj.appendPolicy(policy, selfURI, false);
|
||||
|
||||
// Spec-Compliant policy default-src defaults to *.
|
||||
// This means all images are allowed, and only 'self'
|
||||
// script is allowed.
|
||||
do_check_true(testPermits(cspObj,
|
||||
URI("http://bar.com/foo.png"),
|
||||
Ci.nsIContentPolicy.TYPE_IMAGE));
|
||||
do_check_true(testPermits(cspObj,
|
||||
URI("http://self.com/foo.png"),
|
||||
Ci.nsIContentPolicy.TYPE_IMAGE));
|
||||
do_check_true(testPermits(cspObj,
|
||||
URI("http://self.com/foo.js"),
|
||||
Ci.nsIContentPolicy.TYPE_SCRIPT));
|
||||
do_check_false(testPermits(cspObj,
|
||||
URI("http://bar.com/foo.js"),
|
||||
Ci.nsIContentPolicy.TYPE_SCRIPT));
|
||||
|
||||
});
|
||||
|
||||
test(function test_equals_does_case_insensitive_comparison() {
|
||||
// NOTE: For scheme, host and keyword-host:
|
||||
// (1) compare the same lower-case in two distinct objects
|
||||
// (2) compare upper-case with lower-case inputs
|
||||
// to test case insensitivity.
|
||||
|
||||
// CSPSource equals ignores case
|
||||
var upperCaseHost = "http://FOO.COM";
|
||||
var lowerCaseHost = "http://foo.com";
|
||||
var src1 = CSPSource.fromString(lowerCaseHost);
|
||||
var src2 = CSPSource.fromString(lowerCaseHost);
|
||||
do_check_true(src1.equals(src2))
|
||||
var src3 = CSPSource.fromString(upperCaseHost);
|
||||
do_check_true(src1.equals(src3))
|
||||
|
||||
// CSPHost equals ignores case
|
||||
var upperCaseScheme = "HTTP";
|
||||
var lowerCaseScheme = "http";
|
||||
src1 = CSPHost.fromString(lowerCaseScheme);
|
||||
src2 = CSPHost.fromString(lowerCaseScheme);
|
||||
do_check_true(src1.equals(src2));
|
||||
src3 = CSPHost.fromString(upperCaseScheme);
|
||||
do_check_true(src1.equals(src3));
|
||||
|
||||
// CSPSourceList equals (mainly for testing keywords)
|
||||
var upperCaseKeywords = "'SELF'";
|
||||
var lowerCaseKeywords = "'self'";
|
||||
src1 = CSPSourceList.fromString(lowerCaseKeywords);
|
||||
src2 = CSPSourceList.fromString(lowerCaseKeywords);
|
||||
do_check_true(src1.equals(src2))
|
||||
src3 = CSPSourceList.fromString(upperCaseKeywords);
|
||||
do_check_true(src1.equals(src3))
|
||||
|
||||
});
|
||||
|
||||
test(function test_csp_permits_case_insensitive() {
|
||||
var cspr;
|
||||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
|
||||
// checks directives can be case-insensitive
|
||||
var selfHost = "http://self.com";
|
||||
var testPolicy1 = "DEFAULT-src 'self';";
|
||||
cspr = CSPRep.fromString(testPolicy1, URI(selfHost));
|
||||
do_check_true(cspr.permits(URI("http://self.com"), SD.DEFAULT_SRC));
|
||||
|
||||
// checks hosts can be case-insensitive
|
||||
var testPolicy2 = "default-src 'self' http://FOO.COM";
|
||||
cspr = CSPRep.fromString(testPolicy2, URI(selfHost));
|
||||
do_check_true(cspr.permits(URI("http://foo.com"), SD.DEFAULT_SRC));
|
||||
|
||||
// checks schemes can be case-insensitive
|
||||
var testPolicy3 = "default-src 'self' HTTP://foo.com";
|
||||
cspr = CSPRep.fromString(testPolicy3, URI(selfHost));
|
||||
do_check_true(cspr.permits(URI("http://foo.com"), SD.DEFAULT_SRC));
|
||||
|
||||
// checks keywords can be case-insensitive
|
||||
var testPolicy4 = "default-src 'NONE'";
|
||||
cspr = CSPRep.fromString(testPolicy4, URI(selfHost));
|
||||
do_check_false(cspr.permits(URI("http://foo.com"), SD.DEFAULT_SRC));
|
||||
});
|
||||
/*
|
||||
|
||||
test(function test_CSPRep_fromPolicyURI_failswhenmixed() {
|
||||
var cspr;
|
||||
var self = "http://localhost:" + POLICY_PORT;
|
||||
var closed_policy = CSPRep.fromString("default-src 'none'");
|
||||
var my_uri_policy = "policy-uri " + POLICY_URI;
|
||||
|
||||
//print(" --- Ignore the following two errors if they print ---");
|
||||
cspr = CSPRep.fromString("default-src *; " + my_uri_policy, URI(self));
|
||||
|
||||
//"Parsing should fail when 'policy-uri' is mixed with default-src directive"
|
||||
do_check_equivalent(cspr, closed_policy);
|
||||
cspr = CSPRep.fromString("img-src 'self'; " + my_uri_policy, URI(self));
|
||||
|
||||
//"Parsing should fail when 'policy-uri' is mixed with other directives"
|
||||
do_check_equivalent(cspr, closed_policy);
|
||||
//print(" --- Stop ignoring errors that print ---\n");
|
||||
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: test reporting
|
||||
// TODO: test refinements (?)
|
||||
// TODO: test 'eval' and 'inline' keywords
|
||||
|
||||
function run_test() {
|
||||
function policyresponder(request,response) {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "text/csp", false);
|
||||
response.bodyOutputStream.write(POLICY_FROM_URI, POLICY_FROM_URI.length);
|
||||
}
|
||||
//server.registerDirectory("/", nsILocalFileForBasePath);
|
||||
httpServer.registerPathHandler("/policy", policyresponder);
|
||||
|
||||
for(let i in tests) {
|
||||
add_task(tests[i]);
|
||||
}
|
||||
|
||||
do_register_cleanup(function () {
|
||||
//teardown
|
||||
httpServer.stop(function() { });
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,7 +22,6 @@ support-files =
|
||||
|
||||
[test_bug553888.js]
|
||||
[test_bug737966.js]
|
||||
[test_csputils.js]
|
||||
[test_cspreports.js]
|
||||
[test_error_codes.js]
|
||||
run-sequentially = Hardcoded 4444 port.
|
||||
@ -32,4 +31,3 @@ skip-if = os == 'mac'
|
||||
[test_xhr_document.js]
|
||||
[test_xhr_standalone.js]
|
||||
[test_xmlserializer.js]
|
||||
[test_csp_ignores_path.js]
|
||||
|
@ -930,6 +930,18 @@ nsTextInputListener::EditAction()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextInputListener::BeforeEditAction()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextInputListener::CancelEditAction()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// END nsIEditorObserver
|
||||
|
||||
|
||||
@ -1042,7 +1054,7 @@ public:
|
||||
PrepareEditorEvent(nsTextEditorState &aState,
|
||||
nsIContent *aOwnerContent,
|
||||
const nsAString &aCurrentValue)
|
||||
: mState(aState.asWeakPtr())
|
||||
: mState(&aState)
|
||||
, mOwnerContent(aOwnerContent)
|
||||
, mCurrentValue(aCurrentValue)
|
||||
{
|
||||
|
@ -248,6 +248,17 @@ MediaDecoderReader::RequestAudioData()
|
||||
!AudioQueue().IsFinished()) {
|
||||
if (!DecodeAudioData()) {
|
||||
AudioQueue().Finish();
|
||||
break;
|
||||
}
|
||||
// AudioQueue size is still zero, post a task to try again. Don't spin
|
||||
// waiting in this while loop since it somehow prevents audio EOS from
|
||||
// coming in gstreamer 1.x when there is still video buffer waiting to be
|
||||
// consumed. (|mVideoSinkBufferCount| > 0)
|
||||
if (AudioQueue().GetSize() == 0 && mTaskQueue) {
|
||||
RefPtr<nsIRunnable> task(NS_NewRunnableMethod(
|
||||
this, &MediaDecoderReader::RequestAudioData));
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (AudioQueue().GetSize() > 0) {
|
||||
|
@ -211,27 +211,34 @@ public:
|
||||
}
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder* CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE {
|
||||
BlankVideoDataCreator* decoder = new BlankVideoDataCreator(
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE {
|
||||
BlankVideoDataCreator* creator = new BlankVideoDataCreator(
|
||||
aConfig.display_width, aConfig.display_height, aImageContainer);
|
||||
return new BlankMediaDataDecoder<BlankVideoDataCreator>(decoder,
|
||||
aVideoTaskQueue,
|
||||
aCallback);
|
||||
nsRefPtr<MediaDataDecoder> decoder =
|
||||
new BlankMediaDataDecoder<BlankVideoDataCreator>(creator,
|
||||
aVideoTaskQueue,
|
||||
aCallback);
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder* CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE {
|
||||
BlankAudioDataCreator* decoder = new BlankAudioDataCreator(
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE {
|
||||
BlankAudioDataCreator* creator = new BlankAudioDataCreator(
|
||||
aConfig.channel_count, aConfig.samples_per_second);
|
||||
return new BlankMediaDataDecoder<BlankAudioDataCreator>(decoder,
|
||||
aAudioTaskQueue,
|
||||
aCallback);
|
||||
|
||||
nsRefPtr<MediaDataDecoder> decoder =
|
||||
new BlankMediaDataDecoder<BlankAudioDataCreator>(creator,
|
||||
aAudioTaskQueue,
|
||||
aCallback);
|
||||
return decoder.forget();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -125,10 +125,10 @@ private:
|
||||
}
|
||||
|
||||
// The platform decoder.
|
||||
RefPtr<MediaDataDecoder> mDecoder;
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
// TaskQueue on which decoder can choose to decode.
|
||||
// Only non-null up until the decoder is created.
|
||||
RefPtr<MediaTaskQueue> mTaskQueue;
|
||||
nsRefPtr<MediaTaskQueue> mTaskQueue;
|
||||
// Callback that receives output and error notifications from the decoder.
|
||||
nsAutoPtr<DecoderCallback> mCallback;
|
||||
// Monitor that protects all non-threadsafe state; the primitives
|
||||
|
@ -93,11 +93,12 @@ public:
|
||||
// Returns nullptr if the decoder can't be created.
|
||||
// It is safe to store a reference to aConfig.
|
||||
// Called on decode thread.
|
||||
virtual MediaDataDecoder* CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) = 0;
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) = 0;
|
||||
|
||||
// Creates an AAC decoder with the specified properties.
|
||||
// Asynchronous decoding of audio should be done in runnables dispatched to
|
||||
@ -109,9 +110,10 @@ public:
|
||||
// COINIT_MULTITHREADED.
|
||||
// It is safe to store a reference to aConfig.
|
||||
// Called on decode thread.
|
||||
virtual MediaDataDecoder* CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) = 0;
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) = 0;
|
||||
|
||||
virtual ~PlatformDecoderModule() {}
|
||||
|
||||
|
@ -66,22 +66,26 @@ AppleDecoderModule::Shutdown()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MediaDataDecoder*
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
AppleDecoderModule::CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
mozilla::layers::LayersBackend aLayersBackend,
|
||||
mozilla::layers::ImageContainer* aImageContainer,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
return new AppleVTDecoder(aConfig, aVideoTaskQueue, aCallback, aImageContainer);
|
||||
nsRefPtr<MediaDataDecoder> decoder =
|
||||
new AppleVTDecoder(aConfig, aVideoTaskQueue, aCallback, aImageContainer);
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
MediaDataDecoder*
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
AppleDecoderModule::CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
return new AppleATDecoder(aConfig, aAudioTaskQueue, aCallback);
|
||||
nsRefPtr<MediaDataDecoder> decoder =
|
||||
new AppleATDecoder(aConfig, aAudioTaskQueue, aCallback);
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -25,18 +25,18 @@ public:
|
||||
virtual nsresult Shutdown() MOZ_OVERRIDE;
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder*
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
mozilla::layers::LayersBackend aLayersBackend,
|
||||
mozilla::layers::ImageContainer* aImageContainer,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder* CreateAACDecoder(
|
||||
const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
static void Init();
|
||||
private:
|
||||
|
@ -5,7 +5,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "EMEDecoderModule.h"
|
||||
#include "mtransport/runnable_utils.h"
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@ -193,7 +192,7 @@ EMEDecoderModule::Shutdown()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MediaDataDecoder*
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
EMEDecoderModule::CreateH264Decoder(const VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
@ -203,24 +202,25 @@ EMEDecoderModule::CreateH264Decoder(const VideoDecoderConfig& aConfig,
|
||||
if (mCDMDecodesVideo) {
|
||||
NS_WARNING("Support for CDM that decodes video not yet supported");
|
||||
return nullptr;
|
||||
} else {
|
||||
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateH264Decoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
aCallback));
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new EMEDecryptor(decoder,
|
||||
aCallback,
|
||||
mTaskQueue,
|
||||
mProxy);
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateH264Decoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
aCallback));
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
|
||||
aCallback,
|
||||
mTaskQueue,
|
||||
mProxy));
|
||||
return emeDecoder.forget();
|
||||
}
|
||||
|
||||
MediaDataDecoder*
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
EMEDecoderModule::CreateAACDecoder(const AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
@ -228,19 +228,20 @@ EMEDecoderModule::CreateAACDecoder(const AudioDecoderConfig& aConfig,
|
||||
if (mCDMDecodesAudio) {
|
||||
NS_WARNING("Support for CDM that decodes audio not yet supported");
|
||||
return nullptr;
|
||||
} else {
|
||||
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateAACDecoder(aConfig,
|
||||
aAudioTaskQueue,
|
||||
aCallback));
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new EMEDecryptor(decoder,
|
||||
aCallback,
|
||||
mTaskQueue,
|
||||
mProxy);
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateAACDecoder(aConfig,
|
||||
aAudioTaskQueue,
|
||||
aCallback));
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
|
||||
aCallback,
|
||||
mTaskQueue,
|
||||
mProxy));
|
||||
return emeDecoder.forget();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
virtual nsresult Shutdown() MOZ_OVERRIDE;
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder*
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
@ -41,10 +41,10 @@ public:
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder* CreateAACDecoder(
|
||||
const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
|
@ -25,23 +25,27 @@ public:
|
||||
|
||||
virtual nsresult Shutdown() MOZ_OVERRIDE { return NS_OK; }
|
||||
|
||||
virtual MediaDataDecoder* CreateH264Decoder(
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
mozilla::layers::LayersBackend aLayersBackend,
|
||||
mozilla::layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback)
|
||||
MOZ_OVERRIDE
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE
|
||||
{
|
||||
return new FFmpegH264Decoder<V>(aVideoTaskQueue, aCallback, aConfig,
|
||||
aImageContainer);
|
||||
nsRefPtr<MediaDataDecoder> decoder =
|
||||
new FFmpegH264Decoder<V>(aVideoTaskQueue, aCallback, aConfig,
|
||||
aImageContainer);
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
virtual MediaDataDecoder* CreateAACDecoder(
|
||||
const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback)
|
||||
MOZ_OVERRIDE
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE
|
||||
{
|
||||
return new FFmpegAACDecoder<V>(aAudioTaskQueue, aCallback, aConfig);
|
||||
nsRefPtr<MediaDataDecoder> decoder =
|
||||
new FFmpegAACDecoder<V>(aAudioTaskQueue, aCallback, aConfig);
|
||||
return decoder.forget();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -63,29 +63,33 @@ WMFDecoderModule::Shutdown()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MediaDataDecoder*
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
WMFDecoderModule::CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
mozilla::layers::LayersBackend aLayersBackend,
|
||||
mozilla::layers::ImageContainer* aImageContainer,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
return new WMFMediaDataDecoder(new WMFVideoMFTManager(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
sDXVAEnabled),
|
||||
aVideoTaskQueue,
|
||||
aCallback);
|
||||
nsRefPtr<MediaDataDecoder> decoder =
|
||||
new WMFMediaDataDecoder(new WMFVideoMFTManager(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
sDXVAEnabled),
|
||||
aVideoTaskQueue,
|
||||
aCallback);
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
MediaDataDecoder*
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
WMFDecoderModule::CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
return new WMFMediaDataDecoder(new WMFAudioMFTManager(aConfig),
|
||||
aAudioTaskQueue,
|
||||
aCallback);
|
||||
nsRefPtr<MediaDataDecoder> decoder =
|
||||
new WMFMediaDataDecoder(new WMFAudioMFTManager(aConfig),
|
||||
aAudioTaskQueue,
|
||||
aCallback);
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -25,18 +25,18 @@ public:
|
||||
virtual nsresult Shutdown() MOZ_OVERRIDE;
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder*
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
mozilla::layers::LayersBackend aLayersBackend,
|
||||
mozilla::layers::ImageContainer* aImageContainer,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder* CreateAACDecoder(
|
||||
const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
static void Init();
|
||||
private:
|
||||
|
@ -271,5 +271,12 @@ GMPChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::RecvCrashPluginNow()
|
||||
{
|
||||
abort();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
@ -47,6 +47,8 @@ private:
|
||||
virtual bool DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor) MOZ_OVERRIDE;
|
||||
virtual bool RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvCrashPluginNow() MOZ_OVERRIDE;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
virtual void ProcessingError(Result aWhat) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -101,6 +101,14 @@ GMPParent::Init(GeckoMediaPluginService *aService, nsIFile* aPluginDir)
|
||||
return ReadGMPMetaData();
|
||||
}
|
||||
|
||||
void
|
||||
GMPParent::Crash()
|
||||
{
|
||||
if (mState != GMPStateNotLoaded) {
|
||||
unused << SendCrashPluginNow();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPParent::LoadProcess()
|
||||
{
|
||||
|
@ -62,6 +62,8 @@ public:
|
||||
nsresult Init(GeckoMediaPluginService *aService, nsIFile* aPluginDir);
|
||||
nsresult CloneFrom(const GMPParent* aOther);
|
||||
|
||||
void Crash();
|
||||
|
||||
nsresult LoadProcess();
|
||||
|
||||
// Called internally to close this if we don't need it
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "GMPVideoDecoderParent.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "GeckoChildProcessHost.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
#include "nsXPCOMPrivate.h"
|
||||
@ -145,6 +146,11 @@ GeckoMediaPluginService::Init()
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false)));
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (prefs) {
|
||||
prefs->AddObserver("media.gmp.plugin.crash", this, false);
|
||||
}
|
||||
|
||||
// Kick off scanning for plugins
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
unused << GetThread(getter_AddRefs(thread));
|
||||
@ -155,7 +161,26 @@ GeckoMediaPluginService::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aSomeData)
|
||||
{
|
||||
if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
|
||||
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
|
||||
nsCOMPtr<nsIPrefBranch> branch( do_QueryInterface(aSubject) );
|
||||
if (branch) {
|
||||
bool crashNow = false;
|
||||
if (NS_LITERAL_STRING("media.gmp.plugin.crash").Equals(aSomeData)) {
|
||||
branch->GetBoolPref("media.gmp.plugin.crash", &crashNow);
|
||||
}
|
||||
if (crashNow) {
|
||||
nsCOMPtr<nsIThread> gmpThread;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
gmpThread = mGMPThread;
|
||||
}
|
||||
if (gmpThread) {
|
||||
gmpThread->Dispatch(WrapRunnable(this, &GeckoMediaPluginService::CrashPlugins),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
|
||||
nsCOMPtr<nsIThread> gmpThread;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
@ -340,6 +365,17 @@ GeckoMediaPluginService::UnloadPlugins()
|
||||
mPlugins.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::CrashPlugins()
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
|
||||
mPlugins[i]->Crash();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::LoadFromEnvironment()
|
||||
{
|
||||
|
@ -44,6 +44,7 @@ private:
|
||||
const nsTArray<nsCString>& aTags);
|
||||
|
||||
void UnloadPlugins();
|
||||
void CrashPlugins();
|
||||
|
||||
void LoadFromEnvironment();
|
||||
void ProcessPossiblePlugin(nsIFile* aDir);
|
||||
|
@ -27,6 +27,8 @@ child:
|
||||
async PGMPDecryptor();
|
||||
async PGMPVideoDecoder();
|
||||
async PGMPVideoEncoder();
|
||||
|
||||
async CrashPluginNow();
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
@ -630,9 +630,11 @@ bool GStreamerReader::DecodeAudioData()
|
||||
}
|
||||
|
||||
int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer);
|
||||
timestamp = gst_segment_to_stream_time(&mAudioSegment,
|
||||
GST_FORMAT_TIME, timestamp);
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
|
||||
timestamp = gst_segment_to_stream_time(&mAudioSegment,
|
||||
GST_FORMAT_TIME, timestamp);
|
||||
}
|
||||
timestamp = GST_TIME_AS_USECONDS(timestamp);
|
||||
|
||||
int64_t offset = GST_BUFFER_OFFSET(buffer);
|
||||
|
@ -72,7 +72,7 @@ AudioListener::SetOrientation(double aX, double aY, double aZ,
|
||||
void
|
||||
AudioListener::RegisterPannerNode(PannerNode* aPannerNode)
|
||||
{
|
||||
mPanners.AppendElement(aPannerNode->asWeakPtr());
|
||||
mPanners.AppendElement(aPannerNode);
|
||||
|
||||
// Let the panner node know about our parameters
|
||||
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_POSITION, mPosition);
|
||||
|
@ -700,7 +700,7 @@ SpeechRecognition::Start(const Optional<NonNull<DOMMediaStream>>& aStream, Error
|
||||
mRecognitionService = do_GetService(speechRecognitionServiceCID.get(), &rv);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
rv = mRecognitionService->Initialize(this->asWeakPtr());
|
||||
rv = mRecognitionService->Initialize(this);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
MediaStreamConstraints constraints;
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
int32_t aModType) const MOZ_OVERRIDE;
|
||||
|
||||
|
||||
// nsSVGElement overrides
|
||||
virtual bool IsEventAttributeName(nsIAtom* aName) MOZ_OVERRIDE;
|
||||
|
||||
|
||||
@ -65,8 +66,6 @@ public:
|
||||
virtual bool IsTransformable() MOZ_OVERRIDE { return true; }
|
||||
|
||||
protected:
|
||||
// nsSVGElement overrides
|
||||
|
||||
nsAutoPtr<nsSVGAnimatedTransformList> mTransforms;
|
||||
|
||||
// XXX maybe move this to property table, to save space on un-animated elems?
|
||||
@ -77,4 +76,3 @@ protected:
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // SVGTransformableElement_h
|
||||
|
||||
|
@ -242,12 +242,4 @@ public:
|
||||
sSVGAnimatedRectTearoffTable;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
template<>
|
||||
struct HasDangerousPublicDestructor<nsSVGViewBox>
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // __NS_SVGVIEWBOX_H__
|
||||
|
@ -1466,6 +1466,7 @@ Navigator::GetBattery(ErrorResult& aRv)
|
||||
/* static */ already_AddRefed<Promise>
|
||||
Navigator::GetDataStores(nsPIDOMWindow* aWindow,
|
||||
const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!aWindow || !aWindow->GetDocShell()) {
|
||||
@ -1480,16 +1481,18 @@ Navigator::GetDataStores(nsPIDOMWindow* aWindow,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> promise;
|
||||
aRv = service->GetDataStores(aWindow, aName, getter_AddRefs(promise));
|
||||
aRv = service->GetDataStores(aWindow, aName, aOwner, getter_AddRefs(promise));
|
||||
|
||||
nsRefPtr<Promise> p = static_cast<Promise*>(promise.get());
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Navigator::GetDataStores(const nsAString& aName, ErrorResult& aRv)
|
||||
Navigator::GetDataStores(const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
return GetDataStores(mWindow, aName, aRv);
|
||||
return GetDataStores(mWindow, aName, aOwner, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
|
@ -161,13 +161,15 @@ public:
|
||||
|
||||
static already_AddRefed<Promise> GetDataStores(nsPIDOMWindow* aWindow,
|
||||
const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> GetDataStores(const nsAString &aName,
|
||||
already_AddRefed<Promise> GetDataStores(const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Feature Detection API
|
||||
already_AddRefed<Promise> GetFeature(const nsAString &aName,
|
||||
already_AddRefed<Promise> GetFeature(const nsAString& aName,
|
||||
ErrorResult& aRv);
|
||||
|
||||
bool Vibrate(uint32_t aDuration);
|
||||
|
@ -40,6 +40,21 @@ WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context)
|
||||
mColorAttachments[0].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0;
|
||||
}
|
||||
|
||||
WebGLFramebuffer::Attachment::Attachment(GLenum aAttachmentPoint)
|
||||
: mAttachmentPoint(aAttachmentPoint)
|
||||
, mNeedsFinalize(false)
|
||||
{}
|
||||
|
||||
WebGLFramebuffer::Attachment::~Attachment()
|
||||
{}
|
||||
|
||||
void
|
||||
WebGLFramebuffer::Attachment::Reset()
|
||||
{
|
||||
mTexturePtr = nullptr;
|
||||
mRenderbufferPtr = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLFramebuffer::Attachment::IsDeleteRequested() const
|
||||
{
|
||||
|
@ -26,8 +26,11 @@ class WebGLFramebuffer MOZ_FINAL
|
||||
, public WebGLRefCountedObject<WebGLFramebuffer>
|
||||
, public LinkedListElement<WebGLFramebuffer>
|
||||
, public WebGLContextBoundObject
|
||||
, public SupportsWeakPtr<WebGLFramebuffer>
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLFramebuffer)
|
||||
|
||||
WebGLFramebuffer(WebGLContext* context);
|
||||
|
||||
struct Attachment
|
||||
@ -40,10 +43,8 @@ public:
|
||||
GLint mTexImageLevel;
|
||||
mutable bool mNeedsFinalize;
|
||||
|
||||
Attachment(GLenum aAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0)
|
||||
: mAttachmentPoint(aAttachmentPoint)
|
||||
, mNeedsFinalize(false)
|
||||
{}
|
||||
Attachment(GLenum aAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0);
|
||||
~Attachment();
|
||||
|
||||
bool IsDefined() const {
|
||||
return Texture() || Renderbuffer();
|
||||
@ -79,10 +80,7 @@ public:
|
||||
bool HasUninitializedImageData() const;
|
||||
void SetImageDataStatus(WebGLImageDataStatus x);
|
||||
|
||||
void Reset() {
|
||||
mTexturePtr = nullptr;
|
||||
mRenderbufferPtr = nullptr;
|
||||
}
|
||||
void Reset();
|
||||
|
||||
const WebGLRectangleObject& RectangleObject() const;
|
||||
|
||||
|
@ -11,20 +11,6 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
WebGLFramebufferAttachable::AttachmentPoint*
|
||||
WebGLFramebufferAttachable::Contains(const WebGLFramebuffer* fb, GLenum attachment)
|
||||
{
|
||||
AttachmentPoint* first = mAttachmentPoints.begin();
|
||||
AttachmentPoint* last = mAttachmentPoints.end();
|
||||
|
||||
for (; first != last; ++first) {
|
||||
if (first->mFB == fb && first->mAttachment == attachment)
|
||||
return first;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFramebufferAttachable::AttachTo(WebGLFramebuffer* fb, GLenum attachment)
|
||||
{
|
||||
@ -32,10 +18,10 @@ WebGLFramebufferAttachable::AttachTo(WebGLFramebuffer* fb, GLenum attachment)
|
||||
if (!fb)
|
||||
return;
|
||||
|
||||
if (Contains(fb, attachment))
|
||||
if (mAttachmentPoints.Contains(AttachmentPoint(fb, attachment)))
|
||||
return; // Already attached. Ignore.
|
||||
|
||||
mAttachmentPoints.append(AttachmentPoint(fb, attachment));
|
||||
mAttachmentPoints.AppendElement(AttachmentPoint(fb, attachment));
|
||||
}
|
||||
|
||||
void
|
||||
@ -45,20 +31,21 @@ WebGLFramebufferAttachable::DetachFrom(WebGLFramebuffer* fb, GLenum attachment)
|
||||
if (!fb)
|
||||
return;
|
||||
|
||||
AttachmentPoint* point = Contains(fb, attachment);
|
||||
if (!point) {
|
||||
const size_t i = mAttachmentPoints.IndexOf(AttachmentPoint(fb, attachment));
|
||||
if (i == mAttachmentPoints.NoIndex) {
|
||||
MOZ_ASSERT(false, "Is not attached to FB");
|
||||
return;
|
||||
}
|
||||
|
||||
mAttachmentPoints.erase(point);
|
||||
mAttachmentPoints.RemoveElementAt(i);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFramebufferAttachable::NotifyFBsStatusChanged()
|
||||
{
|
||||
AttachmentPoint* first = mAttachmentPoints.begin();
|
||||
AttachmentPoint* last = mAttachmentPoints.end();
|
||||
for ( ; first != last; ++first)
|
||||
first->mFB->NotifyAttachableChanged();
|
||||
for (size_t i = 0; i < mAttachmentPoints.Length(); ++i) {
|
||||
MOZ_ASSERT(mAttachmentPoints[i].mFB,
|
||||
"Unexpected null pointer; seems that a WebGLFramebuffer forgot to call DetachFrom before dying");
|
||||
mAttachmentPoints[i].mFB->NotifyAttachableChanged();
|
||||
}
|
||||
}
|
||||
|
@ -7,12 +7,12 @@
|
||||
#define WEBGLFRAMEBUFFERATTACHABLE_H_
|
||||
|
||||
#include "GLDefs.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "WebGLFramebuffer.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLFramebuffer;
|
||||
|
||||
class WebGLFramebufferAttachable
|
||||
{
|
||||
struct AttachmentPoint
|
||||
@ -22,13 +22,15 @@ class WebGLFramebufferAttachable
|
||||
, mAttachment(attachment)
|
||||
{}
|
||||
|
||||
const WebGLFramebuffer* mFB;
|
||||
WeakPtr<const WebGLFramebuffer> mFB;
|
||||
GLenum mAttachment;
|
||||
|
||||
bool operator==(const AttachmentPoint& o) const {
|
||||
return mFB == o.mFB && mAttachment == o.mAttachment;
|
||||
}
|
||||
};
|
||||
|
||||
Vector<AttachmentPoint> mAttachmentPoints;
|
||||
|
||||
AttachmentPoint* Contains(const WebGLFramebuffer* fb, GLenum attachment);
|
||||
nsTArray<AttachmentPoint> mAttachmentPoints;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -322,7 +322,7 @@ private:
|
||||
// Returns mResult as an ArrayBufferView, or an error
|
||||
virtual void Resolve() MOZ_OVERRIDE
|
||||
{
|
||||
TypedArrayCreator<Uint8Array> ret(mResult);
|
||||
TypedArrayCreator<ArrayBuffer> ret(mResult);
|
||||
mResultPromise->MaybeResolve(ret);
|
||||
}
|
||||
};
|
||||
@ -987,7 +987,7 @@ private:
|
||||
{
|
||||
if (mSign) {
|
||||
// Return the computed MAC
|
||||
TypedArrayCreator<Uint8Array> ret(mResult);
|
||||
TypedArrayCreator<ArrayBuffer> ret(mResult);
|
||||
mResultPromise->MaybeResolve(ret);
|
||||
} else {
|
||||
// Compare the MAC to the provided signature
|
||||
@ -1116,7 +1116,7 @@ private:
|
||||
virtual void Resolve() MOZ_OVERRIDE
|
||||
{
|
||||
if (mSign) {
|
||||
TypedArrayCreator<Uint8Array> ret(mSignature);
|
||||
TypedArrayCreator<ArrayBuffer> ret(mSignature);
|
||||
mResultPromise->MaybeResolve(ret);
|
||||
} else {
|
||||
mResultPromise->MaybeResolve(mVerified);
|
||||
@ -1745,7 +1745,7 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
TypedArrayCreator<Uint8Array> ret(mResult);
|
||||
TypedArrayCreator<ArrayBuffer> ret(mResult);
|
||||
mResultPromise->MaybeResolve(ret);
|
||||
}
|
||||
};
|
||||
|
@ -1807,3 +1807,15 @@ TestArray.addTest(
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Test that we return ArrayBuffers not ArrayBufferViews",
|
||||
function() {
|
||||
var that = this;
|
||||
|
||||
crypto.subtle.digest("SHA-256", tv.sha256.data)
|
||||
.then(complete(that, function (x) {
|
||||
return x instanceof ArrayBuffer;
|
||||
}), error(that));
|
||||
}
|
||||
);
|
||||
|
@ -3,14 +3,14 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var util = {
|
||||
// Compare the contents of two ArrayBufferViews
|
||||
// Compare the contents of two ArrayBuffer(View)s
|
||||
memcmp: function util_memcmp(x, y) {
|
||||
if (!x || !y) { return false; }
|
||||
|
||||
var xb = new Uint8Array(x);
|
||||
var yb = new Uint8Array(y);
|
||||
if (x.byteLength !== y.byteLength) { return false; }
|
||||
|
||||
var xb = new Uint8Array(x.buffer, x.byteOffset, x.byteLength);
|
||||
var yb = new Uint8Array(y.buffer, y.byteOffset, y.byteLength);
|
||||
for (var i=0; i<xb.byteLength; ++i) {
|
||||
if (xb[i] !== yb[i]) {
|
||||
return false;
|
||||
|
@ -322,16 +322,18 @@ class MOZ_STACK_CLASS GetDataStoreInfosData
|
||||
{
|
||||
public:
|
||||
GetDataStoreInfosData(nsClassHashtable<nsStringHashKey, HashApp>& aAccessStores,
|
||||
const nsAString& aName, uint32_t aAppId,
|
||||
nsTArray<DataStoreInfo>& aStores)
|
||||
const nsAString& aName, const nsAString& aManifestURL,
|
||||
uint32_t aAppId, nsTArray<DataStoreInfo>& aStores)
|
||||
: mAccessStores(aAccessStores)
|
||||
, mName(aName)
|
||||
, mManifestURL(aManifestURL)
|
||||
, mAppId(aAppId)
|
||||
, mStores(aStores)
|
||||
{}
|
||||
|
||||
nsClassHashtable<nsStringHashKey, HashApp>& mAccessStores;
|
||||
nsString mName;
|
||||
nsString mManifestURL;
|
||||
uint32_t mAppId;
|
||||
nsTArray<DataStoreInfo>& mStores;
|
||||
};
|
||||
@ -354,6 +356,11 @@ GetDataStoreInfosEnumerator(const uint32_t& aAppId,
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
if (!data->mManifestURL.IsEmpty() &&
|
||||
!data->mManifestURL.Equals(aInfo->mManifestURL)) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
DataStoreInfo* accessInfo = nullptr;
|
||||
if (!apps->Get(data->mAppId, &accessInfo)) {
|
||||
return PL_DHASH_NEXT;
|
||||
@ -873,6 +880,7 @@ DataStoreService::InstallAccessDataStore(uint32_t aAppId,
|
||||
NS_IMETHODIMP
|
||||
DataStoreService::GetDataStores(nsIDOMWindow* aWindow,
|
||||
const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
nsISupports** aDataStores)
|
||||
{
|
||||
// FIXME This will be a thread-safe method.
|
||||
@ -909,7 +917,7 @@ DataStoreService::GetDataStores(nsIDOMWindow* aWindow,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = GetDataStoreInfos(aName, appId, principal, stores);
|
||||
rv = GetDataStoreInfos(aName, aOwner, appId, principal, stores);
|
||||
if (NS_FAILED(rv)) {
|
||||
RejectPromise(window, promise, rv);
|
||||
promise.forget(aDataStores);
|
||||
@ -924,6 +932,7 @@ DataStoreService::GetDataStores(nsIDOMWindow* aWindow,
|
||||
|
||||
nsTArray<DataStoreSetting> array;
|
||||
if (!contentChild->SendDataStoreGetStores(nsAutoString(aName),
|
||||
nsAutoString(aOwner),
|
||||
IPC::Principal(principal),
|
||||
&array)) {
|
||||
RejectPromise(window, promise, NS_ERROR_FAILURE);
|
||||
@ -1048,6 +1057,7 @@ DataStoreService::GetDataStoresResolve(nsPIDOMWindow* aWindow,
|
||||
// name and available for this 'aAppId'.
|
||||
nsresult
|
||||
DataStoreService::GetDataStoreInfos(const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
uint32_t aAppId,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsTArray<DataStoreInfo>& aStores)
|
||||
@ -1083,13 +1093,14 @@ DataStoreService::GetDataStoreInfos(const nsAString& aName,
|
||||
}
|
||||
|
||||
DataStoreInfo* info = nullptr;
|
||||
if (apps->Get(aAppId, &info)) {
|
||||
if (apps->Get(aAppId, &info) &&
|
||||
(aOwner.IsEmpty() || aOwner.Equals(info->mManifestURL))) {
|
||||
DataStoreInfo* owned = aStores.AppendElement();
|
||||
owned->Init(info->mName, info->mOriginURL, info->mManifestURL, false,
|
||||
info->mEnabled);
|
||||
}
|
||||
|
||||
GetDataStoreInfosData data(mAccessStores, aName, aAppId, aStores);
|
||||
GetDataStoreInfosData data(mAccessStores, aName, aOwner, aAppId, aStores);
|
||||
apps->EnumerateRead(GetDataStoreInfosEnumerator, &data);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1336,6 +1347,7 @@ DataStoreService::RemoveCounter(uint32_t aId)
|
||||
|
||||
nsresult
|
||||
DataStoreService::GetDataStoresFromIPC(const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsTArray<DataStoreSetting>* aValue)
|
||||
{
|
||||
@ -1349,7 +1361,7 @@ DataStoreService::GetDataStoresFromIPC(const nsAString& aName,
|
||||
}
|
||||
|
||||
nsTArray<DataStoreInfo> stores;
|
||||
rv = GetDataStoreInfos(aName, appId, aPrincipal, stores);
|
||||
rv = GetDataStoreInfos(aName, aOwner, appId, aPrincipal, stores);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
nsresult GenerateUUID(nsAString& aID);
|
||||
|
||||
nsresult GetDataStoresFromIPC(const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsTArray<DataStoreSetting>* aValue);
|
||||
|
||||
@ -83,8 +84,8 @@ private:
|
||||
void GetDataStoresResolve(nsPIDOMWindow* aWindow, Promise* aPromise,
|
||||
const nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
nsresult GetDataStoreInfos(const nsAString& aName, uint32_t aAppId,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsresult GetDataStoreInfos(const nsAString& aName, const nsAString& aOwner,
|
||||
uint32_t aAppId, nsIPrincipal* aPrincipal,
|
||||
nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
void DeleteDataStores(uint32_t aAppId);
|
||||
|
@ -8,7 +8,7 @@
|
||||
interface nsIDOMWindow;
|
||||
interface nsIPrincipal;
|
||||
|
||||
[scriptable, uuid(43a731b9-0b5d-400a-8711-8c912c3c3572)]
|
||||
[scriptable, uuid(9b59c49a-0cd7-11e4-b096-74d02b97e723)]
|
||||
interface nsIDataStoreService : nsISupports
|
||||
{
|
||||
void installDataStore(in unsigned long appId,
|
||||
@ -24,7 +24,8 @@ interface nsIDataStoreService : nsISupports
|
||||
in boolean readOnly);
|
||||
|
||||
nsISupports getDataStores(in nsIDOMWindow window,
|
||||
in DOMString name);
|
||||
in DOMString name,
|
||||
in DOMString owner);
|
||||
|
||||
boolean checkPermission(in nsIPrincipal principal);
|
||||
};
|
||||
|
@ -6,6 +6,8 @@
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var gHostedManifestURL = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_app_install.html';
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
@ -22,19 +24,68 @@
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
ok(stores[0].owner, 'The dataStore.owner exists');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
var tests = [
|
||||
// Get datastore with name 'foo'
|
||||
function() {
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
ok(stores[0].owner, 'The dataStore.owner exists');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
runTest();
|
||||
}, cbError);
|
||||
},
|
||||
|
||||
navigator.getDataStores('bar').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('bar') returns 1 element");
|
||||
is(stores[0].name, 'bar', 'The dataStore.name is bar');
|
||||
ok(stores[0].owner, 'The dataStore.owner exists');
|
||||
is(stores[0].readOnly, false, 'The dataStore bar is in readonly');
|
||||
// Get datastore with name 'bar'
|
||||
function() {
|
||||
navigator.getDataStores('bar').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('bar') returns 1 element");
|
||||
is(stores[0].name, 'bar', 'The dataStore.name is bar');
|
||||
ok(stores[0].owner, 'The dataStore.owner exists');
|
||||
is(stores[0].readOnly, false, 'The dataStore bar is in readonly');
|
||||
runTest();
|
||||
}, cbError);
|
||||
},
|
||||
|
||||
// Get datastore with name 'foo' and a specified owner
|
||||
function() {
|
||||
navigator.getDataStores('foo', gHostedManifestURL).then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo','" + gHostedManifestURL +
|
||||
"') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
ok(stores[0].owner, 'The dataStore.owner exists');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
runTest();
|
||||
}, cbError);
|
||||
},
|
||||
|
||||
// Get datastore with name 'foo' and an arbitrary non-existent owner
|
||||
function() {
|
||||
navigator.getDataStores('foo', 'non-existent').then(function(stores) {
|
||||
is(stores.length, 0, "getDataStores('foo','non-existent') returns 0 element");
|
||||
runTest();
|
||||
}, cbError);
|
||||
},
|
||||
|
||||
// Get datastore with an arbitrary non-existent name
|
||||
function() {
|
||||
navigator.getDataStores('non-existent').then(function(stores) {
|
||||
is(stores.length, 0, "getDataStores('non-existent') returns 0 element");
|
||||
runTest();
|
||||
}, cbError);
|
||||
},
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
}, cbError);
|
||||
}, cbError);
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</html>
|
||||
|
@ -296,6 +296,20 @@ static uint32_t CountNewlinesInNativeLength(nsIContent* aContent,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* static */ uint32_t
|
||||
ContentEventHandler::GetNativeTextLength(nsIContent* aContent,
|
||||
uint32_t aStartOffset,
|
||||
uint32_t aEndOffset)
|
||||
{
|
||||
MOZ_ASSERT(aEndOffset >= aStartOffset,
|
||||
"aEndOffset must be equals or larger than aStartOffset");
|
||||
if (aStartOffset == aEndOffset) {
|
||||
return 0;
|
||||
}
|
||||
return GetTextLength(aContent, LINE_BREAK_TYPE_NATIVE, aEndOffset) -
|
||||
GetTextLength(aContent, LINE_BREAK_TYPE_NATIVE, aStartOffset);
|
||||
}
|
||||
|
||||
/* static */ uint32_t
|
||||
ContentEventHandler::GetNativeTextLength(nsIContent* aContent,
|
||||
uint32_t aMaxLength)
|
||||
|
@ -85,6 +85,12 @@ public:
|
||||
nsRange* aRange,
|
||||
uint32_t* aOffset,
|
||||
LineBreakType aLineBreakType);
|
||||
// Computes the native text length between aStartOffset and aEndOffset of
|
||||
// aContent. Currently, this method supports only text node or br element
|
||||
// for aContent.
|
||||
static uint32_t GetNativeTextLength(nsIContent* aContent,
|
||||
uint32_t aStartOffset,
|
||||
uint32_t aEndOffset);
|
||||
// Get the native text length of a content node excluding any children
|
||||
static uint32_t GetNativeTextLength(nsIContent* aContent,
|
||||
uint32_t aMaxLength = UINT32_MAX);
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
#include "mozilla/InternalMutationEvent.h"
|
||||
#include "mozilla/ipc/MessageChannel.h"
|
||||
#include "mozilla/MiscEvents.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,8 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDocShell.h" // XXX Why does only this need to be included here?
|
||||
#include "nsIEditor.h"
|
||||
#include "nsIEditorObserver.h"
|
||||
#include "nsIReflowObserver.h"
|
||||
#include "nsISelectionListener.h"
|
||||
#include "nsIScrollObserver.h"
|
||||
@ -29,11 +31,12 @@ class EventStateManager;
|
||||
|
||||
// IMEContentObserver notifies widget of any text and selection changes
|
||||
// in the currently focused editor
|
||||
class IMEContentObserver MOZ_FINAL : public nsISelectionListener,
|
||||
public nsStubMutationObserver,
|
||||
public nsIReflowObserver,
|
||||
public nsIScrollObserver,
|
||||
public nsSupportsWeakReference
|
||||
class IMEContentObserver MOZ_FINAL : public nsISelectionListener
|
||||
, public nsStubMutationObserver
|
||||
, public nsIReflowObserver
|
||||
, public nsIScrollObserver
|
||||
, public nsSupportsWeakReference
|
||||
, public nsIEditorObserver
|
||||
{
|
||||
public:
|
||||
IMEContentObserver();
|
||||
@ -41,7 +44,9 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IMEContentObserver,
|
||||
nsISelectionListener)
|
||||
NS_DECL_NSIEDITOROBSERVER
|
||||
NS_DECL_NSISELECTIONLISTENER
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
@ -72,22 +77,148 @@ public:
|
||||
nsresult GetSelectionAndRoot(nsISelection** aSelection,
|
||||
nsIContent** aRoot) const;
|
||||
|
||||
struct TextChangeData
|
||||
{
|
||||
// mStartOffset is the start offset of modified or removed text in
|
||||
// original content and inserted text in new content.
|
||||
uint32_t mStartOffset;
|
||||
// mRemovalEndOffset is the end offset of modified or removed text in
|
||||
// original content. If the value is same as mStartOffset, no text hasn't
|
||||
// been removed yet.
|
||||
uint32_t mRemovedEndOffset;
|
||||
// mAddedEndOffset is the end offset of inserted text or same as
|
||||
// mStartOffset if just removed. The vlaue is offset in the new content.
|
||||
uint32_t mAddedEndOffset;
|
||||
|
||||
bool mCausedOnlyByComposition;
|
||||
bool mStored;
|
||||
|
||||
TextChangeData()
|
||||
: mStartOffset(0)
|
||||
, mRemovedEndOffset(0)
|
||||
, mAddedEndOffset(0)
|
||||
, mCausedOnlyByComposition(false)
|
||||
, mStored(false)
|
||||
{
|
||||
}
|
||||
|
||||
TextChangeData(uint32_t aStartOffset,
|
||||
uint32_t aRemovedEndOffset,
|
||||
uint32_t aAddedEndOffset,
|
||||
bool aCausedByComposition)
|
||||
: mStartOffset(aStartOffset)
|
||||
, mRemovedEndOffset(aRemovedEndOffset)
|
||||
, mAddedEndOffset(aAddedEndOffset)
|
||||
, mCausedOnlyByComposition(aCausedByComposition)
|
||||
, mStored(true)
|
||||
{
|
||||
MOZ_ASSERT(aRemovedEndOffset >= aStartOffset,
|
||||
"removed end offset must not be smaller than start offset");
|
||||
MOZ_ASSERT(aAddedEndOffset >= aStartOffset,
|
||||
"added end offset must not be smaller than start offset");
|
||||
}
|
||||
// Positive if text is added. Negative if text is removed.
|
||||
int64_t Difference() const
|
||||
{
|
||||
return mAddedEndOffset - mRemovedEndOffset;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
~IMEContentObserver() {}
|
||||
|
||||
void MaybeNotifyIMEOfTextChange(const TextChangeData& aTextChangeData);
|
||||
void MaybeNotifyIMEOfSelectionChange(bool aCausedByComposition);
|
||||
void MaybeNotifyIMEOfPositionChange();
|
||||
|
||||
void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
|
||||
void ObserveEditableNode();
|
||||
/**
|
||||
* UnregisterObservers() unresiters all listeners and observers.
|
||||
* @param aPostEvent When true, DOM event will be posted to the thread.
|
||||
* Otherwise, dispatched when safe.
|
||||
*/
|
||||
void UnregisterObservers(bool aPostEvent);
|
||||
void StoreTextChangeData(const TextChangeData& aTextChangeData);
|
||||
void FlushMergeableNotifications();
|
||||
|
||||
#ifdef DEBUG
|
||||
void TestMergingTextChangeData();
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
nsCOMPtr<nsISelection> mSelection;
|
||||
nsCOMPtr<nsIContent> mRootContent;
|
||||
nsCOMPtr<nsINode> mEditableNode;
|
||||
nsCOMPtr<nsIDocShell> mDocShell;
|
||||
nsCOMPtr<nsIEditor> mEditor;
|
||||
|
||||
/**
|
||||
* FlatTextCache stores flat text length from start of the content to
|
||||
* mNodeOffset of mContainerNode.
|
||||
*/
|
||||
struct FlatTextCache
|
||||
{
|
||||
// mContainerNode and mNodeOffset represent a point in DOM tree. E.g.,
|
||||
// if mContainerNode is a div element, mNodeOffset is index of its child.
|
||||
nsCOMPtr<nsINode> mContainerNode;
|
||||
int32_t mNodeOffset;
|
||||
// Length of flat text generated from contents between the start of content
|
||||
// and a child node whose index is mNodeOffset of mContainerNode.
|
||||
uint32_t mFlatTextLength;
|
||||
|
||||
FlatTextCache()
|
||||
: mNodeOffset(0)
|
||||
, mFlatTextLength(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
mContainerNode = nullptr;
|
||||
mNodeOffset = 0;
|
||||
mFlatTextLength = 0;
|
||||
}
|
||||
|
||||
void Cache(nsINode* aContainer, int32_t aNodeOffset,
|
||||
uint32_t aFlatTextLength)
|
||||
{
|
||||
MOZ_ASSERT(aContainer, "aContainer must not be null");
|
||||
MOZ_ASSERT(
|
||||
aNodeOffset <= static_cast<int32_t>(aContainer->GetChildCount()),
|
||||
"aNodeOffset must be same as or less than the count of children");
|
||||
mContainerNode = aContainer;
|
||||
mNodeOffset = aNodeOffset;
|
||||
mFlatTextLength = aFlatTextLength;
|
||||
}
|
||||
|
||||
bool Match(nsINode* aContainer, int32_t aNodeOffset) const
|
||||
{
|
||||
return aContainer == mContainerNode && aNodeOffset == mNodeOffset;
|
||||
}
|
||||
};
|
||||
// mEndOfAddedTextCache caches text length from the start of content to
|
||||
// the end of the last added content only while an edit action is being
|
||||
// handled by the editor and no other mutation (e.g., removing node)
|
||||
// occur.
|
||||
FlatTextCache mEndOfAddedTextCache;
|
||||
// mStartOfRemovingTextRangeCache caches text length from the start of content
|
||||
// to the start of the last removed content only while an edit action is being
|
||||
// handled by the editor and no other mutation (e.g., adding node) occur.
|
||||
FlatTextCache mStartOfRemovingTextRangeCache;
|
||||
|
||||
TextChangeData mTextChangeData;
|
||||
|
||||
EventStateManager* mESM;
|
||||
|
||||
nsIMEUpdatePreference mUpdatePreference;
|
||||
uint32_t mPreAttrChangeLength;
|
||||
int64_t mPreCharacterDataChangeLength;
|
||||
|
||||
bool mIsEditorInTransaction;
|
||||
bool mIsSelectionChangeEventPending;
|
||||
bool mSelectionChangeCausedOnlyByComposition;
|
||||
bool mIsPositionChangeEventPending;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -14,10 +14,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=375008
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=375008">Mozilla Bug 375008</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<div>
|
||||
<input id='witness'>
|
||||
</div>
|
||||
|
||||
<div id='not-focusable'>
|
||||
<!-- Disabled elements -->
|
||||
<button hidden disabled>foo</button>
|
||||
@ -52,6 +48,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=375008
|
||||
<option hidden>foo</option>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input id='witness'>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
@ -2290,6 +2290,7 @@ ContentParent::RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
|
||||
bool
|
||||
ContentParent::RecvDataStoreGetStores(
|
||||
const nsString& aName,
|
||||
const nsString& aOwner,
|
||||
const IPC::Principal& aPrincipal,
|
||||
InfallibleTArray<DataStoreSetting>* aValue)
|
||||
{
|
||||
@ -2298,7 +2299,7 @@ ContentParent::RecvDataStoreGetStores(
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = service->GetDataStoresFromIPC(aName, aPrincipal, aValue);
|
||||
nsresult rv = service->GetDataStoresFromIPC(aName, aOwner, aPrincipal, aValue);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -577,6 +577,7 @@ private:
|
||||
|
||||
virtual bool RecvDataStoreGetStores(
|
||||
const nsString& aName,
|
||||
const nsString& aOwner,
|
||||
const IPC::Principal& aPrincipal,
|
||||
InfallibleTArray<DataStoreSetting>* aValue) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -603,7 +603,7 @@ parent:
|
||||
async AudioChannelChangedNotification();
|
||||
async AudioChannelChangeDefVolChannel(int32_t aChannel, bool aHidden);
|
||||
|
||||
sync DataStoreGetStores(nsString aName, Principal aPrincipal)
|
||||
sync DataStoreGetStores(nsString aName, nsString aOwner, Principal aPrincipal)
|
||||
returns (DataStoreSetting[] dataStores);
|
||||
|
||||
async FilePathUpdateNotify(nsString aType,
|
||||
|
@ -19,7 +19,6 @@ const BrowserElementIsPreloaded = true;
|
||||
Cu.import("resource://gre/modules/AppsServiceChild.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
|
||||
Cu.import("resource://gre/modules/CSPUtils.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Geometry.jsm");
|
||||
@ -70,7 +69,7 @@ const BrowserElementIsPreloaded = true;
|
||||
Cc["@mozilla.org/thread-manager;1"].getService(Ci["nsIThreadManager"]);
|
||||
Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci["nsIAppStartup"]);
|
||||
Cc["@mozilla.org/uriloader;1"].getService(Ci["nsIURILoader"]);
|
||||
Cc["@mozilla.org/contentsecuritypolicy;1"].createInstance(Ci["nsIContentSecurityPolicy"]);
|
||||
Cc["@mozilla.org/cspcontext;1"].createInstance(Ci["nsIContentSecurityPolicy"]);
|
||||
|
||||
/* Applications Specific Helper */
|
||||
try {
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "nsIDocument.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIIDNService.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/PeerIdentity.h"
|
||||
@ -100,6 +101,59 @@ using dom::OwningBooleanOrMediaTrackConstraints;
|
||||
using dom::SupportedAudioConstraints;
|
||||
using dom::SupportedVideoConstraints;
|
||||
|
||||
|
||||
static bool
|
||||
HostHasPermission(nsIURI &docURI)
|
||||
{
|
||||
nsAdoptingCString hostName;
|
||||
docURI.GetAsciiHost(hostName); //normalize UTF8 to ASCII equivalent
|
||||
nsAdoptingCString domainWhiteList =
|
||||
Preferences::GetCString("media.getusermedia.screensharing.allowed_domains");
|
||||
domainWhiteList.StripWhitespace();
|
||||
|
||||
if (domainWhiteList.IsEmpty() || hostName.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
// Get UTF8 to ASCII domain name normalization service
|
||||
nsCOMPtr<nsIIDNService> idnService
|
||||
= do_GetService("@mozilla.org/network/idn-service;1", &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PRUint32 begin = 0;
|
||||
PRUint32 end = 0;
|
||||
nsCString domainName;
|
||||
/*
|
||||
Test each domain name in the comma separated list
|
||||
after converting from UTF8 to ASCII. Each domain
|
||||
must match exactly: no wildcards are used.
|
||||
*/
|
||||
do {
|
||||
end = domainWhiteList.FindChar(',', begin);
|
||||
if (end == (PRUint32)-1) {
|
||||
// Last or only domain name in the comma separated list
|
||||
end = domainWhiteList.Length();
|
||||
}
|
||||
|
||||
rv = idnService->ConvertUTF8toACE(Substring(domainWhiteList, begin, end - begin),
|
||||
domainName);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (hostName.EqualsIgnoreCase(domainName.Data(), domainName.Length())) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("Failed to convert UTF-8 host to ASCII");
|
||||
}
|
||||
|
||||
begin = end + 1;
|
||||
} while (end < domainWhiteList.Length());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ErrorCallbackRunnable::ErrorCallbackRunnable(
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
|
||||
@ -1488,12 +1542,20 @@ MediaManager::GetUserMedia(bool aPrivileged,
|
||||
onError.forget(), windowID, listener, mPrefs);
|
||||
}
|
||||
|
||||
// deny screensharing request if support is disabled
|
||||
if (c.mVideo.IsMediaTrackConstraints() &&
|
||||
!Preferences::GetBool("media.getusermedia.screensharing.enabled", false)) {
|
||||
nsIURI* docURI = aWindow->GetDocumentURI();
|
||||
|
||||
if (c.mVideo.IsMediaTrackConstraints()) {
|
||||
auto& tc = c.mVideo.GetAsMediaTrackConstraints();
|
||||
if (tc.mMediaSource != dom::MediaSourceEnum::Camera && tc.mMediaSource != dom::MediaSourceEnum::Browser) {
|
||||
return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
// deny screensharing request if support is disabled
|
||||
if (tc.mMediaSource != dom::MediaSourceEnum::Camera) {
|
||||
if (!Preferences::GetBool("media.getusermedia.screensharing.enabled", false)) {
|
||||
return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
}
|
||||
/* Deny screensharing if the requesting document is not from a host
|
||||
on the whitelist. */
|
||||
if (!HostHasPermission(*docURI)) {
|
||||
return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1510,7 +1572,6 @@ MediaManager::GetUserMedia(bool aPrivileged,
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
nsIURI* docURI = aWindow->GetDocumentURI();
|
||||
|
||||
bool isLoop = false;
|
||||
nsCOMPtr<nsIURI> loopURI;
|
||||
|
@ -60,15 +60,21 @@ var globalPasted = false;
|
||||
function pasteArea()
|
||||
{
|
||||
var pasteArea = document.getElementById("paste-selection-area");
|
||||
var pasteAreaRect = pasteArea.getBoundingClientRect();
|
||||
var pasteAreaCenterX = pasteAreaRect.left + pasteAreaRect.width/2;
|
||||
var pasteAreaCenterY = pasteAreaRect.top + pasteAreaRect.height/2;
|
||||
var util = SpecialPowers.getDOMWindowUtils(window);
|
||||
|
||||
pasteArea.focus();
|
||||
synthesizeMouse(pasteArea, 8, 8, { button: 1 });
|
||||
util.sendMouseEventToWindow("mousedown", pasteAreaCenterX, pasteAreaCenterY, 1, 1, 0, true);
|
||||
util.sendMouseEventToWindow("mouseup", pasteAreaCenterX, pasteAreaCenterY, 1, 1, 0, true);
|
||||
|
||||
var usesMouseButtonPaste = SpecialPowers.getBoolPref("middlemouse.paste");
|
||||
if (usesMouseButtonPaste) {
|
||||
// The data transfer should contain the selection data when the selection clipboard is supported,
|
||||
// not the global clipboard data.
|
||||
var expectedText = supportsSelectionClipboard ? "COPY TEXT" : "CLIPBOARD";
|
||||
is(document.getElementById("paste-selection-area").value, expectedText, "data pasted properly from selection");
|
||||
is(document.getElementById("paste-selection-area").value, expectedText, "In pasteArea(): data pasted properly from selection");
|
||||
ok(selectionPasted, "selection event fired");
|
||||
}
|
||||
else {
|
||||
@ -92,7 +98,7 @@ function pastedSelection(event)
|
||||
ok(navigator.platform.indexOf("Mac") == -1 && navigator.platform.indexOf("Win") == -1, "middle click enabled on right platforms");
|
||||
|
||||
var expectedText = supportsSelectionClipboard ? "COPY TEXT" : "CLIPBOARD";
|
||||
is(event.clipboardData.getData("text/plain"), expectedText, "data pasted properly from selection");
|
||||
is(event.clipboardData.getData("text/plain"), expectedText, "In pastedSelection(): data pasted properly from selection");
|
||||
|
||||
selectionPasted = true;
|
||||
}
|
||||
|
41
dom/webidl/MozSelfSupport.webidl
Normal file
41
dom/webidl/MozSelfSupport.webidl
Normal file
@ -0,0 +1,41 @@
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* The MozSelfSupport interface allows external Mozilla support sites such as
|
||||
* FHR and SUMO to access data and control settings that are not otherwise
|
||||
* exposed to external content.
|
||||
*
|
||||
* At the moment, this is a ChromeOnly interface, but the plan is to allow
|
||||
* specific Mozilla domains to access it directly.
|
||||
*/
|
||||
[ChromeOnly,
|
||||
JSImplementation="@mozilla.org/mozselfsupport;1"]
|
||||
interface MozSelfSupportImpl
|
||||
{
|
||||
/**
|
||||
* Controls whether uploading FHR data is allowed.
|
||||
*/
|
||||
attribute boolean healthReportDataSubmissionEnabled;
|
||||
|
||||
/**
|
||||
* Retrieves the FHR payload object, which is of the form:
|
||||
*
|
||||
* {
|
||||
* version: Number,
|
||||
* clientID: String,
|
||||
* clientIDVersion: Number,
|
||||
* thisPingDate: String,
|
||||
* geckoAppInfo: Object,
|
||||
* data: Object
|
||||
* }
|
||||
*
|
||||
* Refer to the getJSONPayload function in healthreporter.jsm for more
|
||||
* information.
|
||||
*
|
||||
* @return Promise<Object>
|
||||
* Resolved when the FHR payload data has been collected.
|
||||
*/
|
||||
Promise getHealthReportPayload();
|
||||
};
|
@ -123,7 +123,7 @@ Navigator implements NavigatorBattery;
|
||||
[NoInterfaceObject]
|
||||
interface NavigatorDataStore {
|
||||
[Throws, NewObject, Func="Navigator::HasDataStoreSupport"]
|
||||
Promise getDataStores(DOMString name);
|
||||
Promise getDataStores(DOMString name, optional DOMString? owner = null);
|
||||
};
|
||||
Navigator implements NavigatorDataStore;
|
||||
|
||||
|
@ -260,6 +260,7 @@ WEBIDL_FILES = [
|
||||
'MozMobileMessageManager.webidl',
|
||||
'MozNamedAttrMap.webidl',
|
||||
'MozPowerManager.webidl',
|
||||
'MozSelfSupport.webidl',
|
||||
'MozTimeManager.webidl',
|
||||
'MozWakeLock.webidl',
|
||||
'MutationEvent.webidl',
|
||||
|
@ -248,6 +248,9 @@ WifiCertService::Shutdown()
|
||||
mRequestThread->Shutdown();
|
||||
mRequestThread = nullptr;
|
||||
}
|
||||
|
||||
mListener = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -239,11 +239,16 @@ WifiProxyService::Shutdown()
|
||||
mEventThreadList[i].mThread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mEventThreadList.Clear();
|
||||
|
||||
if (mControlThread) {
|
||||
mControlThread->Shutdown();
|
||||
mControlThread = nullptr;
|
||||
}
|
||||
|
||||
mListener = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1780,6 +1780,7 @@ function WifiWorker() {
|
||||
}).bind(this));
|
||||
|
||||
Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
|
||||
this.wantScanResults = [];
|
||||
|
||||
@ -2433,6 +2434,7 @@ WifiWorker.prototype = {
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWorkerHolder,
|
||||
Ci.nsIWifi,
|
||||
Ci.nsIObserver,
|
||||
Ci.nsISettingsServiceCallback]),
|
||||
|
||||
disconnectedByWifi: false,
|
||||
@ -3504,22 +3506,28 @@ WifiWorker.prototype = {
|
||||
|
||||
// nsIObserver implementation
|
||||
observe: function observe(subject, topic, data) {
|
||||
// Note that this function gets called for any and all settings changes,
|
||||
// so we need to carefully check if we have the one we're interested in.
|
||||
// The string we're interested in will be a JSON string that looks like:
|
||||
// {"key":"wifi.enabled","value":"true"}.
|
||||
if (topic !== kMozSettingsChangedObserverTopic) {
|
||||
return;
|
||||
}
|
||||
switch (topic) {
|
||||
case kMozSettingsChangedObserverTopic:
|
||||
// The string we're interested in will be a JSON string that looks like:
|
||||
// {"key":"wifi.enabled","value":"true"}.
|
||||
|
||||
let setting = JSON.parse(data);
|
||||
// To avoid WifiWorker setting the wifi again, don't need to deal with
|
||||
// the "mozsettings-changed" event fired from internal setting.
|
||||
if (setting.message && setting.message === "fromInternalSetting") {
|
||||
return;
|
||||
}
|
||||
let setting = JSON.parse(data);
|
||||
// To avoid WifiWorker setting the wifi again, don't need to deal with
|
||||
// the "mozsettings-changed" event fired from internal setting.
|
||||
if (setting.message && setting.message === "fromInternalSetting") {
|
||||
return;
|
||||
}
|
||||
|
||||
this.handle(setting.key, setting.value);
|
||||
this.handle(setting.key, setting.value);
|
||||
break;
|
||||
|
||||
case "xpcom-shutdown":
|
||||
let wifiService = Cc["@mozilla.org/wifi/service;1"].getService(Ci.nsIWifiProxyService);
|
||||
wifiService.shutdown();
|
||||
let wifiCertService = Cc["@mozilla.org/wifi/certservice;1"].getService(Ci.nsIWifiCertService);
|
||||
wifiCertService.shutdown();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handle: function handle(aName, aResult) {
|
||||
|
@ -206,15 +206,18 @@ class NavigatorGetDataStoresRunnable MOZ_FINAL : public WorkerMainThreadRunnable
|
||||
{
|
||||
nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
|
||||
const nsString mName;
|
||||
const nsString mOwner;
|
||||
ErrorResult& mRv;
|
||||
|
||||
public:
|
||||
NavigatorGetDataStoresRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
Promise* aWorkerPromise,
|
||||
const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv)
|
||||
: WorkerMainThreadRunnable(aWorkerPrivate)
|
||||
, mName(aName)
|
||||
, mOwner(aOwner)
|
||||
, mRv(aRv)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
@ -246,7 +249,8 @@ protected:
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Navigator::GetDataStores(window, mName, mRv);
|
||||
nsRefPtr<Promise> promise =
|
||||
Navigator::GetDataStores(window, mName, mOwner, mRv);
|
||||
promise->AppendNativeHandler(mPromiseWorkerProxy);
|
||||
return true;
|
||||
}
|
||||
@ -255,6 +259,7 @@ protected:
|
||||
already_AddRefed<Promise>
|
||||
WorkerNavigator::GetDataStores(JSContext* aCx,
|
||||
const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
@ -267,7 +272,7 @@ WorkerNavigator::GetDataStores(JSContext* aCx,
|
||||
}
|
||||
|
||||
nsRefPtr<NavigatorGetDataStoresRunnable> runnable =
|
||||
new NavigatorGetDataStoresRunnable(workerPrivate, promise, aName, aRv);
|
||||
new NavigatorGetDataStoresRunnable(workerPrivate, promise, aName, aOwner, aRv);
|
||||
runnable->Dispatch(aCx);
|
||||
|
||||
return promise.forget();
|
||||
|
@ -110,6 +110,7 @@ public:
|
||||
|
||||
already_AddRefed<Promise> GetDataStores(JSContext* aCx,
|
||||
const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv);
|
||||
};
|
||||
|
||||
|
@ -896,6 +896,7 @@ nsEditor::BeginPlaceHolderTransaction(nsIAtom *aName)
|
||||
NS_PRECONDITION(mPlaceHolderBatch >= 0, "negative placeholder batch count!");
|
||||
if (!mPlaceHolderBatch)
|
||||
{
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfBefore);
|
||||
// time to turn on the batch
|
||||
BeginUpdateViewBatch();
|
||||
mPlaceHolderTxn = nullptr;
|
||||
@ -978,8 +979,10 @@ nsEditor::EndPlaceHolderTransaction()
|
||||
// notify editor observers of action but if composing, it's done by
|
||||
// text event handler.
|
||||
if (!mComposition) {
|
||||
NotifyEditorObservers();
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
|
||||
}
|
||||
} else {
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfCancel);
|
||||
}
|
||||
}
|
||||
mPlaceHolderBatch--;
|
||||
@ -1854,17 +1857,35 @@ private:
|
||||
bool mIsComposing;
|
||||
};
|
||||
|
||||
void nsEditor::NotifyEditorObservers(void)
|
||||
void
|
||||
nsEditor::NotifyEditorObservers(NotificationForEditorObservers aNotification)
|
||||
{
|
||||
for (int32_t i = 0; i < mEditorObservers.Count(); i++) {
|
||||
mEditorObservers[i]->EditAction();
|
||||
}
|
||||
switch (aNotification) {
|
||||
case eNotifyEditorObserversOfEnd:
|
||||
for (int32_t i = 0; i < mEditorObservers.Count(); i++) {
|
||||
mEditorObservers[i]->EditAction();
|
||||
}
|
||||
|
||||
if (!mDispatchInputEvent) {
|
||||
return;
|
||||
}
|
||||
if (!mDispatchInputEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
FireInputEvent();
|
||||
FireInputEvent();
|
||||
break;
|
||||
case eNotifyEditorObserversOfBefore:
|
||||
for (int32_t i = 0; i < mEditorObservers.Count(); i++) {
|
||||
mEditorObservers[i]->BeforeEditAction();
|
||||
}
|
||||
break;
|
||||
case eNotifyEditorObserversOfCancel:
|
||||
for (int32_t i = 0; i < mEditorObservers.Count(); i++) {
|
||||
mEditorObservers[i]->CancelEditAction();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Handle all notifications here");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -2076,7 +2097,7 @@ nsEditor::EndIMEComposition()
|
||||
mComposition = nullptr;
|
||||
|
||||
// notify editor observers of action
|
||||
NotifyEditorObservers();
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
|
||||
}
|
||||
|
||||
|
||||
|
@ -178,7 +178,13 @@ public:
|
||||
already_AddRefed<nsIDocument> GetDocument();
|
||||
already_AddRefed<nsIPresShell> GetPresShell();
|
||||
already_AddRefed<nsIWidget> GetWidget();
|
||||
void NotifyEditorObservers();
|
||||
enum NotificationForEditorObservers
|
||||
{
|
||||
eNotifyEditorObserversOfEnd,
|
||||
eNotifyEditorObserversOfBefore,
|
||||
eNotifyEditorObserversOfCancel
|
||||
};
|
||||
void NotifyEditorObservers(NotificationForEditorObservers aNotification);
|
||||
|
||||
/* ------------ nsIEditor methods -------------- */
|
||||
NS_DECL_NSIEDITOR
|
||||
|
@ -865,6 +865,8 @@ nsPlaintextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent)
|
||||
nsresult rv = GetSelection(getter_AddRefs(selection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfBefore);
|
||||
|
||||
nsRefPtr<nsCaret> caretP = ps->GetCaret();
|
||||
|
||||
{
|
||||
@ -885,7 +887,7 @@ nsPlaintextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent)
|
||||
// notified at followed compositionend event.
|
||||
// NOTE: We must notify after the auto batch will be gone.
|
||||
if (IsIMEComposing()) {
|
||||
NotifyEditorObservers();
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
|
||||
}
|
||||
|
||||
return rv;
|
||||
@ -1100,6 +1102,8 @@ nsPlaintextEditor::Undo(uint32_t aCount)
|
||||
|
||||
ForceCompositionEnd();
|
||||
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfBefore);
|
||||
|
||||
nsAutoRules beginRulesSniffing(this, EditAction::undo, nsIEditor::eNone);
|
||||
|
||||
nsTextRulesInfo ruleInfo(EditAction::undo);
|
||||
@ -1112,8 +1116,8 @@ nsPlaintextEditor::Undo(uint32_t aCount)
|
||||
result = nsEditor::Undo(aCount);
|
||||
result = mRules->DidDoAction(selection, &ruleInfo, result);
|
||||
}
|
||||
|
||||
NotifyEditorObservers();
|
||||
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1127,6 +1131,8 @@ nsPlaintextEditor::Redo(uint32_t aCount)
|
||||
|
||||
ForceCompositionEnd();
|
||||
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfBefore);
|
||||
|
||||
nsAutoRules beginRulesSniffing(this, EditAction::redo, nsIEditor::eNone);
|
||||
|
||||
nsTextRulesInfo ruleInfo(EditAction::redo);
|
||||
@ -1139,8 +1145,8 @@ nsPlaintextEditor::Redo(uint32_t aCount)
|
||||
result = nsEditor::Redo(aCount);
|
||||
result = mRules->DidDoAction(selection, &ruleInfo, result);
|
||||
}
|
||||
|
||||
NotifyEditorObservers();
|
||||
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
Editor Observer interface to outside world
|
||||
*/
|
||||
|
||||
[scriptable, uuid(e52a09fd-d33a-4f85-be0a-fbd348f0fa27)]
|
||||
[scriptable, uuid(f3ee57a6-890c-4ce0-a584-8a84bba0292e)]
|
||||
|
||||
/**
|
||||
* A generic editor observer interface.
|
||||
@ -23,4 +23,14 @@ interface nsIEditorObserver : nsISupports {
|
||||
* Called after the editor completes a user action.
|
||||
*/
|
||||
void EditAction();
|
||||
/**
|
||||
* Called when editor starts to handle a user action. I.e., This must be
|
||||
* called before the first DOM change.
|
||||
*/
|
||||
void BeforeEditAction();
|
||||
/**
|
||||
* Called after BeforeEditAction() is called but EditorAction() won't be
|
||||
* called.
|
||||
*/
|
||||
void CancelEditAction();
|
||||
};
|
||||
|
@ -95,6 +95,9 @@ RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
|
||||
|
||||
gfx::Point quadrantTranslation(quadrantRect.x, quadrantRect.y);
|
||||
|
||||
MOZ_ASSERT(aSource != BUFFER_BOTH);
|
||||
RefPtr<SourceSurface> snapshot = GetSourceSurface(aSource);
|
||||
|
||||
// direct2d is much slower when using OP_SOURCE so use OP_OVER and
|
||||
// (maybe) a clear instead. Normally we need to draw in a single operation
|
||||
// (to avoid flickering) but direct2d is ok since it defers rendering.
|
||||
@ -102,19 +105,11 @@ RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
|
||||
// cases.
|
||||
if (aTarget->GetBackendType() == BackendType::DIRECT2D && aOperator == CompositionOp::OP_SOURCE) {
|
||||
aOperator = CompositionOp::OP_OVER;
|
||||
if (mDTBuffer->GetFormat() == SurfaceFormat::B8G8R8A8) {
|
||||
if (snapshot->GetFormat() == SurfaceFormat::B8G8R8A8) {
|
||||
aTarget->ClearRect(ToRect(fillRect));
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<gfx::SourceSurface> snapshot;
|
||||
if (aSource == BUFFER_BLACK) {
|
||||
snapshot = mDTBuffer->Snapshot();
|
||||
} else {
|
||||
MOZ_ASSERT(aSource == BUFFER_WHITE);
|
||||
snapshot = mDTBufferOnWhite->Snapshot();
|
||||
}
|
||||
|
||||
if (aOperator == CompositionOp::OP_SOURCE) {
|
||||
// OP_SOURCE is unbounded in Azure, and we really don't want that behaviour here.
|
||||
// We also can't do a ClearRect+FillRect since we need the drawing to happen
|
||||
@ -181,6 +176,21 @@ RotatedBuffer::DrawBufferWithRotation(gfx::DrawTarget *aTarget, ContextSource aS
|
||||
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aOperator,aMask, aMaskTransform);
|
||||
}
|
||||
|
||||
TemporaryRef<SourceSurface>
|
||||
SourceRotatedBuffer::GetSourceSurface(ContextSource aSource) const
|
||||
{
|
||||
RefPtr<SourceSurface> surf;
|
||||
if (aSource == BUFFER_BLACK) {
|
||||
surf = mSource;
|
||||
} else {
|
||||
MOZ_ASSERT(aSource == BUFFER_WHITE);
|
||||
surf = mSourceOnWhite;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(surf);
|
||||
return surf;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
RotatedContentBuffer::IsClippingCheap(DrawTarget* aTarget, const nsIntRegion& aRegion)
|
||||
{
|
||||
@ -737,6 +747,19 @@ RotatedContentBuffer::BorrowDrawTargetForPainting(PaintState& aPaintState,
|
||||
return result;
|
||||
}
|
||||
|
||||
TemporaryRef<SourceSurface>
|
||||
RotatedContentBuffer::GetSourceSurface(ContextSource aSource) const
|
||||
{
|
||||
MOZ_ASSERT(mDTBuffer);
|
||||
if (aSource == BUFFER_BLACK) {
|
||||
return mDTBuffer->Snapshot();
|
||||
} else {
|
||||
MOZ_ASSERT(mDTBufferOnWhite);
|
||||
MOZ_ASSERT(aSource == BUFFER_WHITE);
|
||||
return mDTBufferOnWhite->Snapshot();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,12 +52,9 @@ class RotatedBuffer {
|
||||
public:
|
||||
typedef gfxContentType ContentType;
|
||||
|
||||
RotatedBuffer(gfx::DrawTarget* aDTBuffer, gfx::DrawTarget* aDTBufferOnWhite,
|
||||
const nsIntRect& aBufferRect,
|
||||
RotatedBuffer(const nsIntRect& aBufferRect,
|
||||
const nsIntPoint& aBufferRotation)
|
||||
: mDTBuffer(aDTBuffer)
|
||||
, mDTBufferOnWhite(aDTBufferOnWhite)
|
||||
, mBufferRect(aBufferRect)
|
||||
: mBufferRect(aBufferRect)
|
||||
, mBufferRotation(aBufferRotation)
|
||||
, mDidSelfCopy(false)
|
||||
{ }
|
||||
@ -89,8 +86,10 @@ public:
|
||||
const nsIntRect& BufferRect() const { return mBufferRect; }
|
||||
const nsIntPoint& BufferRotation() const { return mBufferRotation; }
|
||||
|
||||
virtual bool HaveBuffer() const { return mDTBuffer; }
|
||||
virtual bool HaveBufferOnWhite() const { return mDTBufferOnWhite; }
|
||||
virtual bool HaveBuffer() const = 0;
|
||||
virtual bool HaveBufferOnWhite() const = 0;
|
||||
|
||||
virtual TemporaryRef<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
@ -116,8 +115,6 @@ protected:
|
||||
gfx::SourceSurface* aMask,
|
||||
const gfx::Matrix* aMaskTransform) const;
|
||||
|
||||
RefPtr<gfx::DrawTarget> mDTBuffer;
|
||||
RefPtr<gfx::DrawTarget> mDTBufferOnWhite;
|
||||
/** The area of the ThebesLayer that is covered by the buffer as a whole */
|
||||
nsIntRect mBufferRect;
|
||||
/**
|
||||
@ -136,6 +133,27 @@ protected:
|
||||
bool mDidSelfCopy;
|
||||
};
|
||||
|
||||
class SourceRotatedBuffer : public RotatedBuffer
|
||||
{
|
||||
public:
|
||||
SourceRotatedBuffer(gfx::SourceSurface* aSource, gfx::SourceSurface* aSourceOnWhite,
|
||||
const nsIntRect& aBufferRect,
|
||||
const nsIntPoint& aBufferRotation)
|
||||
: RotatedBuffer(aBufferRect, aBufferRotation)
|
||||
, mSource(aSource)
|
||||
, mSourceOnWhite(aSourceOnWhite)
|
||||
{ }
|
||||
|
||||
virtual TemporaryRef<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const;
|
||||
|
||||
virtual bool HaveBuffer() const { return !!mSource; }
|
||||
virtual bool HaveBufferOnWhite() const { return !!mSourceOnWhite; }
|
||||
|
||||
private:
|
||||
RefPtr<gfx::SourceSurface> mSource;
|
||||
RefPtr<gfx::SourceSurface> mSourceOnWhite;
|
||||
};
|
||||
|
||||
// Mixin class for classes which need logic for loaning out a draw target.
|
||||
// See comments on BorrowDrawTargetForQuadrantUpdate.
|
||||
class BorrowDrawTarget
|
||||
@ -308,6 +326,8 @@ public:
|
||||
gfx::DrawTarget* GetDTBuffer() { return mDTBuffer; }
|
||||
gfx::DrawTarget* GetDTBufferOnWhite() { return mDTBufferOnWhite; }
|
||||
|
||||
virtual TemporaryRef<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const;
|
||||
|
||||
/**
|
||||
* Complete the drawing operation. The region to draw must have been
|
||||
* drawn before this is called. The contents of the buffer are drawn
|
||||
@ -398,6 +418,9 @@ protected:
|
||||
*/
|
||||
virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) {}
|
||||
|
||||
RefPtr<gfx::DrawTarget> mDTBuffer;
|
||||
RefPtr<gfx::DrawTarget> mDTBufferOnWhite;
|
||||
|
||||
/**
|
||||
* These members are only set transiently. They're used to map mDTBuffer
|
||||
* when we're using surfaces that require explicit map/unmap. Only one
|
||||
|
@ -54,6 +54,12 @@ DIBTextureClient::Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!");
|
||||
if (mDrawTarget) {
|
||||
if (mReadbackSink) {
|
||||
RefPtr<SourceSurface> snapshot = mDrawTarget->Snapshot();
|
||||
RefPtr<DataSourceSurface> dataSurf = snapshot->GetDataSurface();
|
||||
mReadbackSink->ProcessReadback(dataSurf);
|
||||
}
|
||||
|
||||
mDrawTarget->Flush();
|
||||
mDrawTarget = nullptr;
|
||||
}
|
||||
|
@ -1026,7 +1026,9 @@ APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, bool* aOutInOverscroll
|
||||
bool inOverscrolledApzc = false;
|
||||
for (AsyncPanZoomController* apzc = mRootApzc; apzc; apzc = apzc->GetPrevSibling()) {
|
||||
target = GetAPZCAtPoint(apzc, point, &inOverscrolledApzc);
|
||||
if (target) {
|
||||
// If we hit an overscrolled APZC, 'target' will be nullptr but it's still
|
||||
// a hit so we don't search further siblings.
|
||||
if (target || inOverscrolledApzc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
#include "nsTArray.h" // for nsAutoTArray
|
||||
#include "ReadbackProcessor.h"
|
||||
#include "ClientThebesLayer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -55,13 +57,20 @@ public:
|
||||
nsAutoTArray<Layer*, 12> children;
|
||||
SortChildrenBy3DZOrder(children);
|
||||
|
||||
ReadbackProcessor readback;
|
||||
readback.BuildUpdates(this);
|
||||
|
||||
for (uint32_t i = 0; i < children.Length(); i++) {
|
||||
Layer* child = children.ElementAt(i);
|
||||
if (child->GetEffectiveVisibleRegion().IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ToClientLayer(child)->RenderLayer();
|
||||
if (child->GetType() != TYPE_THEBES) {
|
||||
ToClientLayer(child)->RenderLayer();
|
||||
} else {
|
||||
static_cast<ClientThebesLayer*>(child)->RenderLayer(&readback);
|
||||
}
|
||||
|
||||
if (!ClientManager()->GetRepeatTransaction() &&
|
||||
!child->GetInvalidRegion().IsEmpty()) {
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "mozilla/layers/LayerTransactionChild.h"
|
||||
#include "mozilla/layers/TextureClientPool.h" // for TextureClientPool
|
||||
#include "mozilla/layers/SimpleTextureClientPool.h" // for SimpleTextureClientPool
|
||||
#include "ClientReadbackLayer.h" // for ClientReadbackLayer
|
||||
#include "nsAString.h"
|
||||
#include "nsIWidget.h" // for nsIWidget
|
||||
#include "nsIWidgetListener.h"
|
||||
@ -116,6 +117,13 @@ ClientLayerManager::Mutated(Layer* aLayer)
|
||||
mForwarder->Mutated(Hold(aLayer));
|
||||
}
|
||||
|
||||
already_AddRefed<ReadbackLayer>
|
||||
ClientLayerManager::CreateReadbackLayer()
|
||||
{
|
||||
nsRefPtr<ReadbackLayer> layer = new ClientReadbackLayer(this);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
|
||||
{
|
||||
|
@ -88,6 +88,7 @@ public:
|
||||
virtual already_AddRefed<ContainerLayer> CreateContainerLayer();
|
||||
virtual already_AddRefed<ImageLayer> CreateImageLayer();
|
||||
virtual already_AddRefed<CanvasLayer> CreateCanvasLayer();
|
||||
virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer();
|
||||
virtual already_AddRefed<ColorLayer> CreateColorLayer();
|
||||
virtual already_AddRefed<RefLayer> CreateRefLayer();
|
||||
|
||||
|
33
gfx/layers/client/ClientReadbackLayer.h
Normal file
33
gfx/layers/client/ClientReadbackLayer.h
Normal file
@ -0,0 +1,33 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_CLIENTREADBACKLAYER_H
|
||||
#define GFX_CLIENTREADBACKLAYER_H
|
||||
|
||||
#include "ClientLayerManager.h"
|
||||
#include "ReadbackLayer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ClientReadbackLayer :
|
||||
public ReadbackLayer,
|
||||
public ClientLayer
|
||||
{
|
||||
public:
|
||||
ClientReadbackLayer(ClientLayerManager *aManager)
|
||||
: ReadbackLayer(aManager, nullptr)
|
||||
{
|
||||
mImplData = static_cast<ClientLayer*>(this);
|
||||
}
|
||||
|
||||
virtual Layer* AsLayer() { return this; }
|
||||
virtual void RenderLayer() {}
|
||||
};
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
||||
|
||||
#endif /* GFX_CLIENTREADBACKLAYER_H */
|
@ -24,6 +24,7 @@
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
#include "nsRect.h" // for nsIntRect
|
||||
#include "gfx2DGlue.h"
|
||||
#include "ReadbackProcessor.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -104,7 +105,7 @@ ClientThebesLayer::PaintThebes()
|
||||
}
|
||||
|
||||
void
|
||||
ClientThebesLayer::RenderLayer()
|
||||
ClientThebesLayer::RenderLayer(ReadbackProcessor *aReadback)
|
||||
{
|
||||
if (GetMaskLayer()) {
|
||||
ToClientLayer(GetMaskLayer())->RenderLayer();
|
||||
@ -120,9 +121,16 @@ ClientThebesLayer::RenderLayer()
|
||||
MOZ_ASSERT(mContentClient->GetForwarder());
|
||||
}
|
||||
|
||||
nsTArray<ReadbackProcessor::Update> readbackUpdates;
|
||||
nsIntRegion readbackRegion;
|
||||
if (aReadback && UsedForReadback()) {
|
||||
aReadback->GetThebesLayerUpdates(this, &readbackUpdates);
|
||||
}
|
||||
|
||||
IntPoint origin(mVisibleRegion.GetBounds().x, mVisibleRegion.GetBounds().y);
|
||||
mContentClient->BeginPaint();
|
||||
PaintThebes();
|
||||
mContentClient->EndPaint();
|
||||
mContentClient->EndPaint(&readbackUpdates);
|
||||
}
|
||||
|
||||
bool
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user