Merge m-c to fx-team, a=merge

This commit is contained in:
Wes Kocher 2016-09-08 15:29:40 -07:00
commit f9c7432e12
1228 changed files with 37391 additions and 18404 deletions

View File

@ -54,14 +54,14 @@
label="&openLinkCmdInCurrent.label;"
accesskey="&openLinkCmdInCurrent.accesskey;"
oncommand="gContextMenu.openLinkInCurrent();"/>
# label and usercontextid are dynamically set.
# label and data-usercontextid are dynamically set.
<menuitem id="context-openlinkincontainertab"
accesskey="&openLinkCmdInTab.accesskey;"
oncommand="gContextMenu.openLinkInTab(event);"/>
<menuitem id="context-openlinkintab"
label="&openLinkCmdInTab.label;"
accesskey="&openLinkCmdInTab.accesskey;"
usercontextid="0"
data-usercontextid="0"
oncommand="gContextMenu.openLinkInTab(event);"/>
<menu id="context-openlinkinusercontext-menu"

View File

@ -4083,7 +4083,7 @@ function updateEditUIVisibility()
function openNewUserContextTab(event)
{
openUILinkIn(BROWSER_NEW_TAB_URL, "tab", {
userContextId: parseInt(event.target.getAttribute('usercontextid')),
userContextId: parseInt(event.target.getAttribute('data-usercontextid')),
});
}

View File

@ -151,7 +151,7 @@ nsContextMenu.prototype = {
inContainer = true;
var item = document.getElementById("context-openlinkincontainertab");
item.setAttribute("usercontextid", userContextId);
item.setAttribute("data-usercontextid", userContextId);
var label = ContextualIdentityService.getUserContextLabel(userContextId);
item.setAttribute("label",
@ -1017,7 +1017,7 @@ nsContextMenu.prototype = {
let params = {
allowMixedContent: persistAllowMixedContentInChildTab,
userContextId: parseInt(event.target.getAttribute('usercontextid'))
userContextId: parseInt(event.target.getAttribute('data-usercontextid')),
};
openLinkIn(this.linkURL, "tab", this._openLinkInParameters(params));

View File

@ -33,7 +33,7 @@ function startNewTabTestCase(aTestNumber) {
let firstContext = menupopup.firstChild;
is(firstContext.nodeType, Node.ELEMENT_NODE, "We have a first container entry.");
ok(firstContext.hasAttribute("usercontextid"), "We have a usercontextid value.");
ok(firstContext.hasAttribute("data-usercontextid"), "We have a usercontextid value.");
aContextMenu.addEventListener("popuphidden", function onPopupHidden() {
aContextMenu.removeEventListener("popuphidden", onPopupHidden);

View File

@ -36,8 +36,8 @@ function startNewTabTestCase(aTestNumber) {
let firstContext = menupopup.firstChild;
is(firstContext.nodeType, Node.ELEMENT_NODE, "We have a first container entry.");
ok(firstContext.hasAttribute("usercontextid"), "We have a usercontextid value.");
is("0", firstContext.getAttribute("usercontextid"), "We have the right usercontextid value.");
ok(firstContext.hasAttribute("data-usercontextid"), "We have a usercontextid value.");
is("0", firstContext.getAttribute("data-usercontextid"), "We have the right usercontextid value.");
aContextMenu.addEventListener("popuphidden", function onPopupHidden() {
aContextMenu.removeEventListener("popuphidden", onPopupHidden);

View File

@ -431,7 +431,7 @@ function createUserContextMenu(event, addCommandAttribute = true, excludeUserCon
// If we are excluding a userContextId, we want to add a 'no-container' item.
if (excludeUserContextId) {
let menuitem = document.createElement("menuitem");
menuitem.setAttribute("usercontextid", "0");
menuitem.setAttribute("data-usercontextid", "0");
menuitem.setAttribute("label", bundle.getString("userContextNone.label"));
menuitem.setAttribute("accesskey", bundle.getString("userContextNone.accesskey"));
@ -451,7 +451,7 @@ function createUserContextMenu(event, addCommandAttribute = true, excludeUserCon
}
let menuitem = document.createElement("menuitem");
menuitem.setAttribute("usercontextid", identity.userContextId);
menuitem.setAttribute("data-usercontextid", identity.userContextId);
menuitem.setAttribute("label", ContextualIdentityService.getUserContextLabel(identity.userContextId));
if (identity.accessKey) {

View File

@ -460,10 +460,9 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
// require system principal to load. At meanwhile, we strip the loadGroup
// for preventing the assertion of the userContextId mismatching.
// The default internal stylesheets load from the 'resource:' URL.
// Bug 1287607 - The 'chrome:' URL will be also loaded from here, so we do
// the same thing for such URLs as well.
if (!/^resource:\/\//.test(this.href) &&
!/^chrome:\/\//.test(this.href)) {
// Bug 1287607, 1291321 - 'chrome' and 'file' protocols should also be handled in the
// same way.
if (!/^(chrome|file|resource):\/\//.test(this.href)) {
options.window = this.window;
options.principal = this.document.nodePrincipal;
}

View File

@ -48,6 +48,11 @@ let expectedConsoleCalls = [
filename: /helper_serviceworker/,
arguments: ['fetch event: ' + SCOPE_FRAME_URL2],
},
{
level: "log",
filename: /helper_serviceworker/,
arguments: ['message event: ' + MESSAGE],
},
];
let consoleCalls = [];
@ -115,9 +120,10 @@ let onAttach = Task.async(function*(state, response) {
// Now postMessage() the service worker to trigger its message event
// handler. This will generate 1 or 2 to console.log() statements
// depending on if the worker thread needs to spin up again. In either
// case, though, we should not get any console calls because we don't
// have a controlled or registering document.
// depending on if the worker thread needs to spin up again. Although we
// don't have a controlled or registering document in both cases, we still
// could get console calls since we only flush reports when the channel is
// finally destroyed.
info("Completed force refresh. Messaging service worker.");
yield messageServiceWorker(currentFrame.contentWindow, SCOPE, MESSAGE);

View File

@ -98,6 +98,7 @@ public:
protected:
virtual ~EventSource();
MOZ_IS_CLASS_INIT
nsresult Init(nsISupports* aOwner,
const nsAString& aURL,
bool aWithCredentials);

View File

@ -29,6 +29,7 @@
#include "nsJSPrincipals.h"
#include "nsContentPolicyUtils.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIClassOfService.h"
#include "nsITimedChannel.h"
#include "nsIScriptElement.h"
@ -51,6 +52,7 @@
#include "nsINetworkPredictor.h"
#include "ImportManager.h"
#include "mozilla/dom/EncodingUtils.h"
#include "mozilla/ConsoleReportCollector.h"
#include "mozilla/Attributes.h"
#include "mozilla/Unused.h"
@ -514,7 +516,8 @@ nsScriptLoader::nsScriptLoader(nsIDocument *aDocument)
mEnabled(true),
mDeferEnabled(false),
mDocumentParsingDone(false),
mBlockingDOMContentLoaded(false)
mBlockingDOMContentLoaded(false),
mReporter(new ConsoleReportCollector())
{
}
@ -1265,6 +1268,11 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
false);
httpChannel->SetReferrerWithPolicy(mDocument->GetDocumentURI(),
aRequest->mReferrerPolicy);
nsCOMPtr<nsIHttpChannelInternal> internalChannel(do_QueryInterface(httpChannel));
if (internalChannel) {
internalChannel->SetIntegrityMetadata(aRequest->mIntegrity.GetIntegrityString());
}
}
nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(docshell));
@ -1279,7 +1287,12 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
nsAutoPtr<mozilla::dom::SRICheckDataVerifier> sriDataVerifier;
if (!aRequest->mIntegrity.IsEmpty()) {
sriDataVerifier = new SRICheckDataVerifier(aRequest->mIntegrity, mDocument);
nsAutoCString sourceUri;
if (mDocument && mDocument->GetDocumentURI()) {
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
}
sriDataVerifier = new SRICheckDataVerifier(aRequest->mIntegrity, sourceUri,
mReporter);
}
RefPtr<nsScriptLoadHandler> handler =
@ -1505,7 +1518,12 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
("nsScriptLoader::ProcessScriptElement, integrity=%s",
NS_ConvertUTF16toUTF8(integrity).get()));
SRICheck::IntegrityMetadata(integrity, mDocument, &sriMetadata);
nsAutoCString sourceUri;
if (mDocument && mDocument->GetDocumentURI()) {
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
}
SRICheck::IntegrityMetadata(integrity, sourceUri, mReporter,
&sriMetadata);
}
}
@ -2451,8 +2469,16 @@ nsScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
if (!request->mIntegrity.IsEmpty() &&
NS_SUCCEEDED((rv = aSRIStatus))) {
MOZ_ASSERT(aSRIDataVerifier);
if (NS_FAILED(aSRIDataVerifier->Verify(request->mIntegrity, channel,
request->mCORSMode, mDocument))) {
MOZ_ASSERT(mReporter);
nsAutoCString sourceUri;
if (mDocument && mDocument->GetDocumentURI()) {
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
}
rv = aSRIDataVerifier->Verify(request->mIntegrity, channel, sourceUri,
mReporter);
mReporter->FlushConsoleReports(mDocument);
if (NS_FAILED(rv)) {
rv = NS_ERROR_SRI_CORRUPT;
}
} else {
@ -2757,7 +2783,11 @@ nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
("nsScriptLoader::PreloadURI, integrity=%s",
NS_ConvertUTF16toUTF8(aIntegrity).get()));
SRICheck::IntegrityMetadata(aIntegrity, mDocument, &sriMetadata);
nsAutoCString sourceUri;
if (mDocument && mDocument->GetDocumentURI()) {
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
}
SRICheck::IntegrityMetadata(aIntegrity, sourceUri, mReporter, &sriMetadata);
}
RefPtr<nsScriptLoadRequest> request =

View File

@ -638,6 +638,8 @@ private:
// Module map
nsRefPtrHashtable<nsURIHashKey, mozilla::GenericPromise::Private> mFetchingModules;
nsRefPtrHashtable<nsURIHashKey, nsModuleScript> mFetchedModules;
nsCOMPtr<nsIConsoleReportCollector> mReporter;
};
class nsScriptLoadHandler final : public nsIIncrementalStreamLoaderObserver

View File

@ -60,6 +60,7 @@ MSG_DEF(MSG_INVALID_HEADER_VALUE, 1, JSEXN_TYPEERR, "{0} is an invalid header va
MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, JSEXN_TYPEERR, "Headers require name/value tuples when being initialized by a sequence.")
MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, JSEXN_TYPEERR, "Permission denied to pass cross-origin object as {0}.")
MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, JSEXN_TYPEERR, "Missing required {0}.")
MSG_DEF(MSG_REQUEST_INTEGRITY_METADATA_NOT_EMPTY, 0, JSEXN_TYPEERR, "Request integrity metadata should be an empty string when in no-cors mode.")
MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, JSEXN_TYPEERR, "Invalid request method {0}.")
MSG_DEF(MSG_INVALID_REQUEST_MODE, 1, JSEXN_TYPEERR, "Invalid request mode {0}.")
MSG_DEF(MSG_INVALID_REFERRER_URL, 1, JSEXN_TYPEERR, "Invalid referrer URL {0}.")

View File

@ -66,6 +66,7 @@ struct CacheRequest
uint32_t contentPolicyType;
RequestCache requestCache;
RequestRedirect requestRedirect;
nsString integrity;
};
union CacheRequestOrVoid

View File

@ -38,7 +38,7 @@ const int32_t kFirstShippedSchemaVersion = 15;
namespace {
// Update this whenever the DB schema is changed.
const int32_t kLatestSchemaVersion = 21;
const int32_t kLatestSchemaVersion = 22;
// ---------
// The following constants define the SQL schema. These are defined in the
@ -105,7 +105,8 @@ const char* const kTableEntries =
"cache_id INTEGER NOT NULL REFERENCES caches(id) ON DELETE CASCADE, "
"request_redirect INTEGER NOT NULL, "
"request_referrer_policy INTEGER NOT NULL"
"request_referrer_policy INTEGER NOT NULL, "
"request_integrity TEXT NOT NULL"
// New columns must be added at the end of table to migrate and
// validate properly.
")";
@ -1661,6 +1662,7 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
"request_contentpolicytype, "
"request_cache, "
"request_redirect, "
"request_integrity, "
"request_body_id, "
"response_type, "
"response_status, "
@ -1684,6 +1686,7 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
":request_contentpolicytype, "
":request_cache, "
":request_redirect, "
":request_integrity, "
":request_body_id, "
":response_type, "
":response_status, "
@ -1756,6 +1759,9 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
rv = state->BindInt32ByName(NS_LITERAL_CSTRING("request_redirect"),
static_cast<int32_t>(aRequest.requestRedirect()));
rv = state->BindStringByName(NS_LITERAL_CSTRING("request_integrity"),
aRequest.integrity());
rv = BindId(state, NS_LITERAL_CSTRING("request_body_id"), aRequestBodyId);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@ -2051,6 +2057,7 @@ ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
"request_contentpolicytype, "
"request_cache, "
"request_redirect, "
"request_integrity, "
"request_body_id "
"FROM entries "
"WHERE id=:id;"
@ -2117,13 +2124,16 @@ ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
aSavedRequestOut->mValue.requestRedirect() =
static_cast<RequestRedirect>(requestRedirect);
rv = state->GetString(11, aSavedRequestOut->mValue.integrity());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
bool nullBody = false;
rv = state->GetIsNull(11, &nullBody);
rv = state->GetIsNull(12, &nullBody);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedRequestOut->mHasBodyId = !nullBody;
if (aSavedRequestOut->mHasBodyId) {
rv = ExtractId(state, 11, &aSavedRequestOut->mBodyId);
rv = ExtractId(state, 12, &aSavedRequestOut->mBodyId);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
}
@ -2479,6 +2489,7 @@ nsresult MigrateFrom17To18(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom18To19(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom19To20(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom20To21(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom21To22(mozIStorageConnection* aConn, bool& aRewriteSchema);
// Configure migration functions to run for the given starting version.
Migration sMigrationList[] = {
@ -2488,6 +2499,7 @@ Migration sMigrationList[] = {
Migration(18, MigrateFrom18To19),
Migration(19, MigrateFrom19To20),
Migration(20, MigrateFrom20To21),
Migration(21, MigrateFrom21To22),
};
uint32_t sMigrationListLength = sizeof(sMigrationList) / sizeof(Migration);
@ -2959,6 +2971,26 @@ nsresult MigrateFrom20To21(mozIStorageConnection* aConn, bool& aRewriteSchema)
return rv;
}
nsresult MigrateFrom21To22(mozIStorageConnection* aConn, bool& aRewriteSchema)
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aConn);
// Add the request_integrity column.
nsresult rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE entries "
"ADD COLUMN request_integrity TEXT NULL"
));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = aConn->SetSchemaVersion(22);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aRewriteSchema = true;
return rv;
}
} // anonymous namespace
} // namespace db

View File

@ -159,6 +159,8 @@ TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
aOut.requestCache() = aIn->GetCacheMode();
aOut.requestRedirect() = aIn->GetRedirectMode();
aOut.integrity() = aIn->GetIntegrity();
if (aBodyAction == IgnoreBody) {
aOut.body() = void_t();
return;
@ -325,6 +327,7 @@ TypeUtils::ToInternalRequest(const CacheRequest& aIn)
internalRequest->SetContentPolicyType(aIn.contentPolicyType());
internalRequest->SetCacheMode(aIn.requestCache());
internalRequest->SetRedirectMode(aIn.requestRedirect());
internalRequest->SetIntegrity(aIn.integrity());
RefPtr<InternalHeaders> internalHeaders =
ToInternalHeaders(aIn.headers(), aIn.headersGuard());

View File

@ -295,16 +295,13 @@ ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log
}
{
std::vector<ShVariableInfo> staticUseVaryingList;
std::vector<sh::ShaderVariable> staticUseVaryingList;
for (const auto& fragVarying : *fragVaryings) {
const ShVariableInfo varInfo = { fragVarying.type,
(int)fragVarying.elementCount() };
static const char prefix[] = "gl_";
if (StartsWith(fragVarying.name, prefix)) {
if (fragVarying.staticUse) {
staticUseVaryingList.push_back(varInfo);
staticUseVaryingList.push_back(fragVarying);
}
continue;
}
@ -338,13 +335,12 @@ ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log
}
if (staticVertUse && fragVarying.staticUse) {
staticUseVaryingList.push_back(varInfo);
staticUseVaryingList.push_back(fragVarying);
}
}
if (!ShCheckVariablesWithinPackingLimits(mMaxVaryingVectors,
staticUseVaryingList.data(),
staticUseVaryingList.size()))
staticUseVaryingList))
{
*out_log = "Statically used varyings do not fit within packing limits. (see"
" GLSL ES Specification 1.0.17, p111)";

View File

@ -4510,7 +4510,6 @@ skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.
[generated/test_2_conformance2__glsl3__const-array-init.html]
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
[generated/test_2_conformance2__glsl3__forbidden-operators.html]
fail-if = (os == 'mac') || (os == 'win')
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
[generated/test_2_conformance2__glsl3__frag-depth.html]
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
@ -5216,7 +5215,6 @@ skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.
[generated/test_2_conformance__glsl__misc__shaders-with-constant-expression-loop-conditions.html]
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
[generated/test_2_conformance__glsl__misc__shaders-with-invariance.html]
fail-if = (os == 'mac')
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
[generated/test_2_conformance__glsl__misc__shaders-with-mis-matching-uniforms.html]
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
@ -6097,7 +6095,6 @@ skip-if = (os == 'android')
skip-if = (os == 'android')
[generated/test_conformance__glsl__bugs__pow-of-small-constant-in-user-defined-function.html]
skip-if = (os == 'android')
fail-if = (os == 'win' && os_version != '5.1')
[generated/test_conformance__glsl__bugs__pow-with-constant-exponent-should-not-crash.html]
[generated/test_conformance__glsl__bugs__qualcomm-crash.html]
skip-if = (os == 'android')
@ -6695,7 +6692,6 @@ skip-if = (os == 'mac') || (os == 'android') || (os == 'win')
[generated/test_conformance__rendering__point-no-attributes.html]
[generated/test_conformance__rendering__point-size.html]
[generated/test_conformance__rendering__point-specific-shader-variables.html]
fail-if = (os == 'win' && os_version != '5.1')
[generated/test_conformance__rendering__point-with-gl-pointcoord-in-fragment-shader.html]
[generated/test_conformance__rendering__polygon-offset.html]
[generated/test_conformance__rendering__simple.html]

View File

@ -146,8 +146,6 @@ fail-if = (os == 'mac') || (os == 'win')
fail-if = (os == 'mac')
[generated/test_2_conformance__attribs__gl-vertexattribpointer.html]
fail-if = (os == 'mac') || (os == 'win')
[generated/test_2_conformance2__glsl3__forbidden-operators.html]
fail-if = (os == 'mac') || (os == 'win')
[generated/test_2_conformance2__vertex_arrays__vertex-array-object.html]
fail-if = (os == 'mac') || (os == 'win')
[generated/test_2_conformance__rendering__negative-one-index.html]
@ -192,7 +190,6 @@ skip-if = (os == 'linux') || (os == 'android')
# mozalloc_abort in libglsl.so
skip-if = (os == 'linux') || (os == 'android')
[generated/test_conformance__glsl__bugs__pow-of-small-constant-in-user-defined-function.html]
fail-if = (os == 'win' && os_version != '5.1')
skip-if = (os == 'android')
########################################################################
# "tst-linux{32,64}-spot-NNN" Slaves:
@ -550,8 +547,6 @@ fail-if = (os == 'mac')
fail-if = (os == 'mac')
[generated/test_conformance__glsl__misc__shaders-with-invariance.html]
fail-if = (os == 'mac')
[generated/test_2_conformance__glsl__misc__shaders-with-invariance.html]
fail-if = (os == 'mac')
[generated/test_2_conformance2__extensions__ext-color-buffer-float.html]
skip-if = (os == 'mac' && debug)
@ -679,8 +674,6 @@ skip-if = (os == 'win' && os_version == '6.2')
####################
# failure on Windows
[generated/test_conformance__rendering__point-specific-shader-variables.html]
fail-if = (os == 'win' && os_version != '5.1')
[generated/test_2_conformance__canvas__rapid-resizing.html]
fail-if = (os == 'win' && os_version == '5.1')
[generated/test_conformance__glsl__bugs__floor-div-cos-should-not-truncate.html]

View File

@ -6,6 +6,8 @@
#include "mozilla/ConsoleReportCollector.h"
#include "nsIConsoleService.h"
#include "nsIScriptError.h"
#include "nsNetUtil.h"
namespace mozilla {
@ -37,7 +39,8 @@ ConsoleReportCollector::AddConsoleReport(uint32_t aErrorFlags,
}
void
ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument)
ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument,
ReportAction aAction)
{
MOZ_ASSERT(NS_IsMainThread());
@ -45,7 +48,11 @@ ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument)
{
MutexAutoLock lock(mMutex);
mPendingReports.SwapElements(reports);
if (aAction == ReportAction::Forget) {
mPendingReports.SwapElements(reports);
} else {
reports = mPendingReports;
}
}
for (uint32_t i = 0; i < reports.Length(); ++i) {
@ -54,9 +61,12 @@ ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument)
// It would be nice if we did not have to do this since ReportToConsole()
// just turns around and converts it back to a spec.
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), report.mSourceFileURI);
if (NS_FAILED(rv)) {
continue;
if (!report.mSourceFileURI.IsEmpty()) {
nsresult rv = NS_NewURI(getter_AddRefs(uri), report.mSourceFileURI);
MOZ_ALWAYS_SUCCEEDS(rv);
if (NS_FAILED(rv)) {
continue;
}
}
// Convert back from nsTArray<nsString> to the char16_t** format required
@ -100,6 +110,79 @@ ConsoleReportCollector::FlushConsoleReports(nsIConsoleReportCollector* aCollecto
}
}
void
ConsoleReportCollector::FlushReportsByWindowId(uint64_t aWindowId,
ReportAction aAction)
{
MOZ_ASSERT(NS_IsMainThread());
nsTArray<PendingReport> reports;
{
MutexAutoLock lock(mMutex);
if (aAction == ReportAction::Forget) {
mPendingReports.SwapElements(reports);
} else {
reports = mPendingReports;
}
}
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
if (!consoleService) {
NS_WARNING("GetConsoleService failed");
return;
}
nsresult rv;
for (uint32_t i = 0; i < reports.Length(); ++i) {
PendingReport& report = reports[i];
nsXPIDLString errorText;
if (!report.mStringParams.IsEmpty()) {
rv = nsContentUtils::FormatLocalizedString(report.mPropertiesFile,
report.mMessageName.get(),
report.mStringParams,
errorText);
} else {
rv = nsContentUtils::GetLocalizedString(report.mPropertiesFile,
report.mMessageName.get(),
errorText);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
nsCOMPtr<nsIScriptError> errorObject =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
rv = errorObject->InitWithWindowID(errorText,
NS_ConvertUTF8toUTF16(report.mSourceFileURI),
EmptyString(),
report.mLineNumber,
report.mColumnNumber,
report.mErrorFlags,
report.mCategory,
aWindowId);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
consoleService->LogMessage(errorObject);
}
}
void
ConsoleReportCollector::ClearConsoleReports()
{
MutexAutoLock lock(mMutex);
mPendingReports.Clear();
}
ConsoleReportCollector::~ConsoleReportCollector()
{
}

View File

@ -27,11 +27,19 @@ public:
const nsTArray<nsString>& aStringParams) override;
void
FlushConsoleReports(nsIDocument* aDocument) override;
FlushConsoleReports(nsIDocument* aDocument,
ReportAction aAction = ReportAction::Forget) override;
void
FlushConsoleReports(nsIConsoleReportCollector* aCollector) override;
void
FlushReportsByWindowId(uint64_t aWindowId,
ReportAction aAction = ReportAction::Forget) override;
void
ClearConsoleReports() override;
private:
~ConsoleReportCollector();

View File

@ -66,14 +66,25 @@ public:
aLineNumber, aColumnNumber, aMessageName, params);
}
// An enum calss to indicate whether should free the pending reports or not.
// Forget Free the pending reports.
// Save Keep the pending reports.
enum class ReportAction {
Forget,
Save
};
// Flush all pending reports to the console. Main thread only.
//
// aDocument An optional document representing where to flush the
// reports. If provided, then the corresponding window's
// web console will get the reports. Otherwise the reports
// go to the browser console.
// aAction An action to determine whether to reserve the pending
// reports. Defalut action is to forget the report.
virtual void
FlushConsoleReports(nsIDocument* aDocument) = 0;
FlushConsoleReports(nsIDocument* aDocument,
ReportAction aAction = ReportAction::Forget) = 0;
// Flush all pending reports to another collector. May be called from any
// thread.
@ -82,6 +93,21 @@ public:
// ownership of our currently console reports.
virtual void
FlushConsoleReports(nsIConsoleReportCollector* aCollector) = 0;
// Flush all pending reports to the console accroding to window ID. Main
// thread only.
//
// aWindowId A window ID representing where to flush the reports and it's
// typically the inner window ID.
//
// aAction An action to decide whether free the pending reports or not.
virtual void
FlushReportsByWindowId(uint64_t aWindowId,
ReportAction aAction = ReportAction::Forget) = 0;
// Clear all pending reports.
virtual void
ClearConsoleReports() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIConsoleReportCollector, NS_NSICONSOLEREPORTCOLLECTOR_IID)

View File

@ -34,6 +34,7 @@
#include "mozilla/dom/Response.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/URLSearchParams.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
#include "mozilla/Telemetry.h"
#include "InternalRequest.h"
@ -88,6 +89,9 @@ private:
~WorkerFetchResolver()
{}
virtual void
FlushConsoleReport() override;
};
class MainThreadFetchResolver final : public FetchDriverObserver
@ -95,6 +99,8 @@ class MainThreadFetchResolver final : public FetchDriverObserver
RefPtr<Promise> mPromise;
RefPtr<Response> mResponse;
nsCOMPtr<nsIDocument> mDocument;
NS_DECL_OWNINGTHREAD
public:
explicit MainThreadFetchResolver(Promise* aPromise);
@ -102,8 +108,23 @@ public:
void
OnResponseAvailableInternal(InternalResponse* aResponse) override;
void SetDocument(nsIDocument* aDocument)
{
mDocument = aDocument;
}
virtual void OnResponseEnd() override
{
FlushConsoleReport();
}
private:
~MainThreadFetchResolver();
void FlushConsoleReport() override
{
mReporter->FlushConsoleReports(mDocument);
}
};
class MainThreadFetchRunnable : public Runnable
@ -140,6 +161,11 @@ public:
nsCOMPtr<nsILoadGroup> loadGroup = proxy->GetWorkerPrivate()->GetLoadGroup();
MOZ_ASSERT(loadGroup);
fetch = new FetchDriver(mRequest, principal, loadGroup);
nsAutoCString spec;
if (proxy->GetWorkerPrivate()->GetBaseURI()) {
proxy->GetWorkerPrivate()->GetBaseURI()->GetAsciiSpec(spec);
}
fetch->SetWorkerScript(spec);
}
// ...but release it before calling Fetch, because mResolver's callback can
@ -216,6 +242,7 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
RefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(p);
RefPtr<FetchDriver> fetch = new FetchDriver(r, principal, loadGroup);
fetch->SetDocument(doc);
resolver->SetDocument(doc);
aRv = fetch->Fetch(resolver);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
@ -401,6 +428,8 @@ WorkerFetchResolver::OnResponseEnd()
return;
}
FlushConsoleReport();
RefPtr<WorkerFetchResponseEndRunnable> r =
new WorkerFetchResponseEndRunnable(mPromiseProxy);
@ -416,6 +445,44 @@ WorkerFetchResolver::OnResponseEnd()
}
}
void
WorkerFetchResolver::FlushConsoleReport()
{
AssertIsOnMainThread();
MOZ_ASSERT(mPromiseProxy);
if(!mReporter) {
return;
}
workers::WorkerPrivate* worker = mPromiseProxy->GetWorkerPrivate();
if (!worker) {
mReporter->FlushConsoleReports((nsIDocument*)nullptr);
return;
}
if (worker->IsServiceWorker()) {
// Flush to service worker
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
mReporter->FlushConsoleReports((nsIDocument*)nullptr);
return;
}
swm->FlushReportsToAllClients(worker->WorkerName(), mReporter);
return;
}
if (worker->IsSharedWorker()) {
// Flush to shared worker
worker->FlushReportsToSharedWorkers(mReporter);
return;
}
// Flush to dedicated worker
mReporter->FlushConsoleReports(worker->GetDocument());
}
namespace {
nsresult
ExtractFromArrayBuffer(const ArrayBuffer& aBuffer,

View File

@ -319,6 +319,7 @@ FetchDriver::HttpFetch()
internalChan->SetRedirectMode(static_cast<uint32_t>(mRequest->GetRedirectMode()));
mRequest->MaybeSkipCacheIfPerformingRevalidation();
internalChan->SetFetchCacheMode(static_cast<uint32_t>(mRequest->GetCacheMode()));
internalChan->SetIntegrityMetadata(mRequest->GetIntegrity());
}
// Step 5. Proxy authentication will be handled by Necko.
@ -397,10 +398,14 @@ FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse,
MOZ_ASSERT(filteredResponse);
MOZ_ASSERT(mObserver);
mObserver->OnResponseAvailable(filteredResponse);
#ifdef DEBUG
mResponseAvailableCalled = true;
#endif
if (filteredResponse->Type() == ResponseType::Error ||
mRequest->GetIntegrity().IsEmpty()) {
mObserver->OnResponseAvailable(filteredResponse);
#ifdef DEBUG
mResponseAvailableCalled = true;
#endif
}
return filteredResponse.forget();
}
@ -598,6 +603,30 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
// sure the Response is fully initialized before calling this.
mResponse = BeginAndGetFilteredResponse(response, foundOpaqueRedirect);
// From "Main Fetch" step 17: SRI-part1.
if (mResponse->Type() != ResponseType::Error &&
!mRequest->GetIntegrity().IsEmpty() &&
mSRIMetadata.IsEmpty()) {
nsIConsoleReportCollector* aReporter = nullptr;
if (mObserver) {
aReporter = mObserver->GetReporter();
}
nsAutoCString sourceUri;
if (mDocument && mDocument->GetDocumentURI()) {
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
} else if (!mWorkerScript.IsEmpty()) {
sourceUri.Assign(mWorkerScript);
}
SRICheck::IntegrityMetadata(mRequest->GetIntegrity(), sourceUri,
aReporter, &mSRIMetadata);
mSRIDataVerifier = new SRICheckDataVerifier(mSRIMetadata, sourceUri,
aReporter);
// Do not retarget off main thread when using SRI API.
return NS_OK;
}
nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
@ -627,6 +656,46 @@ FetchDriver::OnDataAvailable(nsIRequest* aRequest,
MOZ_ASSERT(mResponse);
MOZ_ASSERT(mPipeOutputStream);
// From "Main Fetch" step 17: SRI-part2.
if (mResponse->Type() != ResponseType::Error &&
!mRequest->GetIntegrity().IsEmpty()) {
MOZ_ASSERT(mSRIDataVerifier);
uint32_t aWrite;
nsTArray<uint8_t> buffer;
nsresult rv;
buffer.SetCapacity(aCount);
while (aCount > 0) {
rv = aInputStream->Read(reinterpret_cast<char*>(buffer.Elements()),
aCount, &aRead);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = mSRIDataVerifier->Update(aRead, (uint8_t*)buffer.Elements());
NS_ENSURE_SUCCESS(rv, rv);
while (aRead > 0) {
rv = mPipeOutputStream->Write(reinterpret_cast<char*>(buffer.Elements()),
aRead, &aWrite);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (aRead < aWrite) {
return NS_ERROR_FAILURE;
}
aRead -= aWrite;
}
aCount -= aWrite;
}
return NS_OK;
}
nsresult rv = aInputStream->ReadSegments(NS_CopySegmentToStream,
mPipeOutputStream,
aCount, &aRead);
@ -651,12 +720,49 @@ FetchDriver::OnStopRequest(nsIRequest* aRequest,
MOZ_ASSERT(mResponse);
MOZ_ASSERT(!mResponse->IsError());
// From "Main Fetch" step 17: SRI-part3.
if (mResponse->Type() != ResponseType::Error &&
!mRequest->GetIntegrity().IsEmpty()) {
MOZ_ASSERT(mSRIDataVerifier);
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
nsIConsoleReportCollector* aReporter = nullptr;
if (mObserver) {
aReporter = mObserver->GetReporter();
}
nsAutoCString sourceUri;
if (mDocument && mDocument->GetDocumentURI()) {
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
} else if (!mWorkerScript.IsEmpty()) {
sourceUri.Assign(mWorkerScript);
}
nsresult rv = mSRIDataVerifier->Verify(mSRIMetadata, channel, sourceUri,
aReporter);
if (NS_FAILED(rv)) {
FailWithNetworkError();
// Cancel request.
return rv;
}
}
if (mPipeOutputStream) {
mPipeOutputStream->Close();
}
}
if (mObserver) {
if (mResponse->Type() != ResponseType::Error &&
!mRequest->GetIntegrity().IsEmpty()) {
//From "Main Fetch" step 23: Process response.
MOZ_ASSERT(mResponse);
mObserver->OnResponseAvailable(mResponse);
#ifdef DEBUG
mResponseAvailableCalled = true;
#endif
}
mObserver->OnResponseEnd();
mObserver = nullptr;
}

View File

@ -11,11 +11,14 @@
#include "nsIInterfaceRequestor.h"
#include "nsIStreamListener.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "mozilla/ConsoleReportCollector.h"
#include "mozilla/dom/SRICheck.h"
#include "mozilla/RefPtr.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/net/ReferrerPolicy.h"
class nsIConsoleReportCollector;
class nsIDocument;
class nsIOutputStream;
class nsILoadGroup;
@ -35,7 +38,8 @@ class InternalResponse;
class FetchDriverObserver
{
public:
FetchDriverObserver() : mGotResponseAvailable(false)
FetchDriverObserver() : mReporter(new ConsoleReportCollector())
, mGotResponseAvailable(false)
{ }
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchDriverObserver);
@ -48,12 +52,19 @@ public:
virtual void OnResponseEnd()
{ };
nsIConsoleReportCollector* GetReporter() const
{
return mReporter;
}
virtual void FlushConsoleReport() = 0;
protected:
virtual ~FetchDriverObserver()
{ };
virtual void OnResponseAvailableInternal(InternalResponse* aResponse) = 0;
nsCOMPtr<nsIConsoleReportCollector> mReporter;
private:
bool mGotResponseAvailable;
};
@ -78,6 +89,13 @@ public:
void
SetDocument(nsIDocument* aDocument);
void
SetWorkerScript(const nsACString& aWorkerScirpt)
{
MOZ_ASSERT(!aWorkerScirpt.IsEmpty());
mWorkerScript = aWorkerScirpt;
}
private:
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsILoadGroup> mLoadGroup;
@ -86,6 +104,9 @@ private:
nsCOMPtr<nsIOutputStream> mPipeOutputStream;
RefPtr<FetchDriverObserver> mObserver;
nsCOMPtr<nsIDocument> mDocument;
nsAutoPtr<SRICheckDataVerifier> mSRIDataVerifier;
SRIMetadata mSRIMetadata;
nsCString mWorkerScript;
#ifdef DEBUG
bool mResponseAvailableCalled;

View File

@ -41,6 +41,7 @@ InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult
copy->mReferrer = mReferrer;
copy->mReferrerPolicy = mReferrerPolicy;
copy->mEnvironmentReferrerPolicy = mEnvironmentReferrerPolicy;
copy->mIntegrity = mIntegrity;
copy->mContentPolicyType = mContentPolicyTypeOverridden ?
mContentPolicyType :
@ -91,6 +92,7 @@ InternalRequest::InternalRequest(const InternalRequest& aOther)
, mResponseTainting(aOther.mResponseTainting)
, mCacheMode(aOther.mCacheMode)
, mRedirectMode(aOther.mRedirectMode)
, mIntegrity(aOther.mIntegrity)
, mAuthenticationFlag(aOther.mAuthenticationFlag)
, mForceOriginHeader(aOther.mForceOriginHeader)
, mPreserveContentCodings(aOther.mPreserveContentCodings)

View File

@ -128,7 +128,8 @@ public:
RequestCredentials aRequestCredentials,
const nsAString& aReferrer,
ReferrerPolicy aReferrerPolicy,
nsContentPolicyType aContentPolicyType)
nsContentPolicyType aContentPolicyType,
const nsAString& aIntegrity)
: mMethod(aMethod)
, mHeaders(aHeaders)
, mContentPolicyType(aContentPolicyType)
@ -140,6 +141,7 @@ public:
, mResponseTainting(LoadTainting::Basic)
, mCacheMode(aCacheMode)
, mRedirectMode(aRequestRedirect)
, mIntegrity(aIntegrity)
, mAuthenticationFlag(false)
, mForceOriginHeader(false)
, mPreserveContentCodings(false)
@ -361,6 +363,19 @@ public:
mRedirectMode = aRedirectMode;
}
const nsString&
GetIntegrity() const
{
return mIntegrity;
}
void
SetIntegrity(const nsAString& aIntegrity)
{
MOZ_ASSERT(mIntegrity.IsEmpty());
mIntegrity.Assign(aIntegrity);
}
nsContentPolicyType
ContentPolicyType() const
{
@ -520,6 +535,8 @@ private:
RequestCache mCacheMode;
RequestRedirect mRedirectMode;
nsString mIntegrity;
MOZ_INIT_OUTSIDE_CTOR bool mAuthenticationFlag;
MOZ_INIT_OUTSIDE_CTOR bool mForceOriginHeader;
MOZ_INIT_OUTSIDE_CTOR bool mPreserveContentCodings;

View File

@ -459,6 +459,10 @@ Request::Constructor(const GlobalObject& aGlobal,
request->SetRedirectMode(aInit.mRedirect.Value());
}
if (aInit.mIntegrity.WasPassed()) {
request->SetIntegrity(aInit.mIntegrity.Value());
}
// Request constructor step 14.
if (aInit.mMethod.WasPassed()) {
nsAutoCString method(aInit.mMethod.Value());
@ -508,6 +512,11 @@ Request::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
if (!request->GetIntegrity().IsEmpty()) {
aRv.ThrowTypeError<MSG_REQUEST_INTEGRITY_METADATA_NOT_EMPTY>();
return nullptr;
}
requestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv);
if (aRv.Failed()) {
return nullptr;

View File

@ -81,6 +81,12 @@ public:
return mRequest->GetRedirectMode();
}
void
GetIntegrity(nsAString& aIntegrity) const
{
aIntegrity = mRequest->GetIntegrity();
}
RequestContext
Context() const
{

View File

@ -58,8 +58,7 @@ NS_IMPL_ISUPPORTS(GamepadManager, nsIObserver)
GamepadManager::GamepadManager()
: mEnabled(false),
mNonstandardEventsEnabled(false),
mShuttingDown(false),
mChild(nullptr)
mShuttingDown(false)
{}
nsresult
@ -104,10 +103,10 @@ GamepadManager::Observe(nsISupports* aSubject,
void
GamepadManager::StopMonitoring()
{
if(mChild) {
mChild->SendGamepadListenerRemoved();
mChild = nullptr;
for (uint32_t i = 0; i < mChannelChildren.Length(); ++i) {
mChannelChildren[i]->SendGamepadListenerRemoved();
}
mChannelChildren.Clear();
mGamepads.Clear();
}
@ -142,9 +141,10 @@ GamepadManager::AddListener(nsGlobalWindow* aWindow)
mListeners.AppendElement(aWindow);
// IPDL child has been created
if (mChild) {
if (!mChannelChildren.IsEmpty()) {
return;
}
PBackgroundChild *actor = BackgroundChild::GetForCurrentThread();
//Try to get the PBackground Child actor
if (actor) {
@ -581,8 +581,11 @@ GamepadManager::ActorCreated(PBackgroundChild *aActor)
return;
}
MOZ_ASSERT(initedChild == child);
mChild = child;
mChild->SendGamepadListenerAdded();
child->SendGamepadListenerAdded();
mChannelChildren.AppendElement(child);
// TODO: Add more event channels to mChannelChildren if you would
// like to support more kinds of devices.
}
//Override nsIIPCBackgroundChildCreateCallback

View File

@ -111,8 +111,8 @@ class GamepadManager final : public nsIObserver,
// Gamepad IPDL child
// This pointer is only used by this singleton instance and
// will be destroyed during the IPDL shutdown chain, so we
// don't need to refcount it here
GamepadEventChannelChild MOZ_NON_OWNING_REF *mChild;
// don't need to refcount it here.
nsTArray<GamepadEventChannelChild *> mChannelChildren;
private:

View File

@ -1,561 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/GamepadService.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/Gamepad.h"
#include "mozilla/dom/GamepadAxisMoveEvent.h"
#include "mozilla/dom/GamepadButtonEvent.h"
#include "mozilla/dom/GamepadEvent.h"
#include "mozilla/dom/GamepadMonitoring.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPtr.h"
#include "nsIDOMEvent.h"
#include "nsIDOMDocument.h"
#include "nsIDOMWindow.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIServiceManager.h"
#include "nsITimer.h"
#include "nsThreadUtils.h"
#include "mozilla/Services.h"
#include <cstddef>
namespace mozilla {
namespace dom {
namespace {
const char* kGamepadEnabledPref = "dom.gamepad.enabled";
const char* kGamepadEventsEnabledPref =
"dom.gamepad.non_standard_events.enabled";
// Amount of time to wait before cleaning up gamepad resources
// when no pages are listening for events.
const int kCleanupDelayMS = 2000;
const nsTArray<RefPtr<nsGlobalWindow> >::index_type NoIndex =
nsTArray<RefPtr<nsGlobalWindow> >::NoIndex;
StaticRefPtr<GamepadService> gGamepadServiceSingleton;
} // namespace
bool GamepadService::sShutdown = false;
NS_IMPL_ISUPPORTS(GamepadService, nsIObserver)
GamepadService::GamepadService()
: mStarted(false),
mShuttingDown(false)
{
mEnabled = IsAPIEnabled();
mNonstandardEventsEnabled =
Preferences::GetBool(kGamepadEventsEnabledPref, false);
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
observerService->AddObserver(this,
NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID,
false);
}
NS_IMETHODIMP
GamepadService::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
observerService->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID);
BeginShutdown();
return NS_OK;
}
void
GamepadService::StopMonitoring()
{
if (mStarted) {
if (XRE_IsParentProcess()) {
MaybeStopGamepadMonitoring();
} else {
ContentChild::GetSingleton()->SendGamepadListenerRemoved();
}
mStarted = false;
}
mGamepads.Clear();
}
void
GamepadService::BeginShutdown()
{
mShuttingDown = true;
if (mTimer) {
mTimer->Cancel();
}
StopMonitoring();
// Don't let windows call back to unregister during shutdown
for (uint32_t i = 0; i < mListeners.Length(); i++) {
mListeners[i]->SetHasGamepadEventListener(false);
}
mListeners.Clear();
sShutdown = true;
}
void
GamepadService::AddListener(nsGlobalWindow* aWindow)
{
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsInnerWindow());
if (mShuttingDown) {
return;
}
if (mListeners.IndexOf(aWindow) != NoIndex) {
return; // already exists
}
if (!mStarted && mEnabled) {
if (XRE_IsParentProcess()) {
StartGamepadMonitoring();
} else {
ContentChild::GetSingleton()->SendGamepadListenerAdded();
}
mStarted = true;
}
mListeners.AppendElement(aWindow);
}
void
GamepadService::RemoveListener(nsGlobalWindow* aWindow)
{
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsInnerWindow());
if (mShuttingDown) {
// Doesn't matter at this point. It's possible we're being called
// as a result of our own destructor here, so just bail out.
return;
}
if (mListeners.IndexOf(aWindow) == NoIndex) {
return; // doesn't exist
}
mListeners.RemoveElement(aWindow);
if (mListeners.Length() == 0 && !mShuttingDown && mStarted) {
if (XRE_IsParentProcess()) {
StartCleanupTimer();
} else {
StopMonitoring();
}
}
}
already_AddRefed<Gamepad>
GamepadService::GetGamepad(uint32_t aIndex)
{
RefPtr<Gamepad> gamepad;
if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
return gamepad.forget();
}
return nullptr;
}
void
GamepadService::AddGamepad(uint32_t aIndex,
const nsAString& aId,
GamepadMappingType aMapping,
uint32_t aNumButtons,
uint32_t aNumAxes)
{
//TODO: bug 852258: get initial button/axis state
RefPtr<Gamepad> gamepad =
new Gamepad(nullptr,
aId,
0, // index is set by global window
aMapping,
aNumButtons,
aNumAxes);
// We store the gamepad related to its index given by the parent process.
mGamepads.Put(aIndex, gamepad);
NewConnectionEvent(aIndex, true);
}
void
GamepadService::RemoveGamepad(uint32_t aIndex)
{
RefPtr<Gamepad> gamepad = GetGamepad(aIndex);
if (!gamepad) {
NS_WARNING("Trying to delete gamepad with invalid index");
return;
}
gamepad->SetConnected(false);
NewConnectionEvent(aIndex, false);
mGamepads.Remove(aIndex);
}
void
GamepadService::NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed,
double aValue)
{
RefPtr<Gamepad> gamepad = GetGamepad(aIndex);
if (mShuttingDown || !gamepad) {
return;
}
gamepad->SetButton(aButton, aPressed, aValue);
// Hold on to listeners in a separate array because firing events
// can mutate the mListeners array.
nsTArray<RefPtr<nsGlobalWindow>> listeners(mListeners);
for (uint32_t i = listeners.Length(); i > 0 ; ) {
--i;
MOZ_ASSERT(listeners[i]->IsInnerWindow());
// Only send events to non-background windows
if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
listeners[i]->GetOuterWindow()->IsBackground()) {
continue;
}
bool first_time = false;
if (!WindowHasSeenGamepad(listeners[i], aIndex)) {
// This window hasn't seen this gamepad before, so
// send a connection event first.
SetWindowHasSeenGamepad(listeners[i], aIndex);
first_time = true;
}
RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
if (listenerGamepad) {
listenerGamepad->SetButton(aButton, aPressed, aValue);
if (first_time) {
FireConnectionEvent(listeners[i], listenerGamepad, true);
}
if (mNonstandardEventsEnabled) {
// Fire event
FireButtonEvent(listeners[i], listenerGamepad, aButton, aValue);
}
}
}
}
void
GamepadService::FireButtonEvent(EventTarget* aTarget,
Gamepad* aGamepad,
uint32_t aButton,
double aValue)
{
nsString name = aValue == 1.0L ? NS_LITERAL_STRING("gamepadbuttondown") :
NS_LITERAL_STRING("gamepadbuttonup");
GamepadButtonEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mGamepad = aGamepad;
init.mButton = aButton;
RefPtr<GamepadButtonEvent> event =
GamepadButtonEvent::Constructor(aTarget, name, init);
event->SetTrusted(true);
bool defaultActionEnabled = true;
aTarget->DispatchEvent(event, &defaultActionEnabled);
}
void
GamepadService::NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue)
{
RefPtr<Gamepad> gamepad = GetGamepad(aIndex);
if (mShuttingDown || !gamepad) {
return;
}
gamepad->SetAxis(aAxis, aValue);
// Hold on to listeners in a separate array because firing events
// can mutate the mListeners array.
nsTArray<RefPtr<nsGlobalWindow> > listeners(mListeners);
for (uint32_t i = listeners.Length(); i > 0 ; ) {
--i;
MOZ_ASSERT(listeners[i]->IsInnerWindow());
// Only send events to non-background windows
if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
listeners[i]->GetOuterWindow()->IsBackground()) {
continue;
}
bool first_time = false;
if (!WindowHasSeenGamepad(listeners[i], aIndex)) {
// This window hasn't seen this gamepad before, so
// send a connection event first.
SetWindowHasSeenGamepad(listeners[i], aIndex);
first_time = true;
}
RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
if (listenerGamepad) {
listenerGamepad->SetAxis(aAxis, aValue);
if (first_time) {
FireConnectionEvent(listeners[i], listenerGamepad, true);
}
if (mNonstandardEventsEnabled) {
// Fire event
FireAxisMoveEvent(listeners[i], listenerGamepad, aAxis, aValue);
}
}
}
}
void
GamepadService::FireAxisMoveEvent(EventTarget* aTarget,
Gamepad* aGamepad,
uint32_t aAxis,
double aValue)
{
GamepadAxisMoveEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mGamepad = aGamepad;
init.mAxis = aAxis;
init.mValue = aValue;
RefPtr<GamepadAxisMoveEvent> event =
GamepadAxisMoveEvent::Constructor(aTarget,
NS_LITERAL_STRING("gamepadaxismove"),
init);
event->SetTrusted(true);
bool defaultActionEnabled = true;
aTarget->DispatchEvent(event, &defaultActionEnabled);
}
void
GamepadService::NewConnectionEvent(uint32_t aIndex, bool aConnected)
{
RefPtr<Gamepad> gamepad = GetGamepad(aIndex);
if (mShuttingDown || !gamepad) {
return;
}
// Hold on to listeners in a separate array because firing events
// can mutate the mListeners array.
nsTArray<RefPtr<nsGlobalWindow> > listeners(mListeners);
if (aConnected) {
for (uint32_t i = listeners.Length(); i > 0 ; ) {
--i;
MOZ_ASSERT(listeners[i]->IsInnerWindow());
// Only send events to non-background windows
if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
listeners[i]->GetOuterWindow()->IsBackground()) {
continue;
}
// We don't fire a connected event here unless the window
// has seen input from at least one device.
if (!listeners[i]->HasSeenGamepadInput()) {
continue;
}
SetWindowHasSeenGamepad(listeners[i], aIndex);
RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
if (listenerGamepad) {
// Fire event
FireConnectionEvent(listeners[i], listenerGamepad, aConnected);
}
}
} else {
// For disconnection events, fire one at every window that has received
// data from this gamepad.
for (uint32_t i = listeners.Length(); i > 0 ; ) {
--i;
// Even background windows get these events, so we don't have to
// deal with the hassle of syncing the state of removed gamepads.
if (WindowHasSeenGamepad(listeners[i], aIndex)) {
RefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
if (listenerGamepad) {
listenerGamepad->SetConnected(false);
// Fire event
FireConnectionEvent(listeners[i], listenerGamepad, false);
listeners[i]->RemoveGamepad(aIndex);
}
}
}
}
}
void
GamepadService::FireConnectionEvent(EventTarget* aTarget,
Gamepad* aGamepad,
bool aConnected)
{
nsString name = aConnected ? NS_LITERAL_STRING("gamepadconnected") :
NS_LITERAL_STRING("gamepaddisconnected");
GamepadEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mGamepad = aGamepad;
RefPtr<GamepadEvent> event =
GamepadEvent::Constructor(aTarget, name, init);
event->SetTrusted(true);
bool defaultActionEnabled = true;
aTarget->DispatchEvent(event, &defaultActionEnabled);
}
void
GamepadService::SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad)
{
RefPtr<Gamepad> gamepad = GetGamepad(aIndex);
if (mShuttingDown || !mEnabled || !gamepad) {
return;
}
aGamepad->SyncState(gamepad);
}
// static
bool
GamepadService::IsServiceRunning()
{
return !!gGamepadServiceSingleton;
}
// static
already_AddRefed<GamepadService>
GamepadService::GetService()
{
if (sShutdown) {
return nullptr;
}
if (!gGamepadServiceSingleton) {
gGamepadServiceSingleton = new GamepadService();
ClearOnShutdown(&gGamepadServiceSingleton);
}
RefPtr<GamepadService> service(gGamepadServiceSingleton);
return service.forget();
}
// static
bool
GamepadService::IsAPIEnabled() {
return Preferences::GetBool(kGamepadEnabledPref, false);
}
bool
GamepadService::WindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex)
{
RefPtr<Gamepad> gamepad = aWindow->GetGamepad(aIndex);
return gamepad != nullptr;
}
void
GamepadService::SetWindowHasSeenGamepad(nsGlobalWindow* aWindow,
uint32_t aIndex,
bool aHasSeen)
{
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsInnerWindow());
if (mListeners.IndexOf(aWindow) == NoIndex) {
// This window isn't even listening for gamepad events.
return;
}
if (aHasSeen) {
aWindow->SetHasSeenGamepadInput(true);
nsCOMPtr<nsISupports> window = ToSupports(aWindow);
RefPtr<Gamepad> gamepad = GetGamepad(aIndex);
MOZ_ASSERT(gamepad);
if (!gamepad) {
return;
}
RefPtr<Gamepad> clonedGamepad = gamepad->Clone(window);
aWindow->AddGamepad(aIndex, clonedGamepad);
} else {
aWindow->RemoveGamepad(aIndex);
}
}
// static
void
GamepadService::TimeoutHandler(nsITimer* aTimer, void* aClosure)
{
// the reason that we use self, instead of just using nsITimerCallback or nsIObserver
// is so that subclasses are free to use timers without worry about the base classes's
// usage.
GamepadService* self = reinterpret_cast<GamepadService*>(aClosure);
if (!self) {
NS_ERROR("no self");
return;
}
if (self->mShuttingDown) {
return;
}
if (self->mListeners.Length() == 0) {
self->StopMonitoring();
}
}
void
GamepadService::StartCleanupTimer()
{
if (mTimer) {
mTimer->Cancel();
}
mTimer = do_CreateInstance("@mozilla.org/timer;1");
if (mTimer) {
mTimer->InitWithFuncCallback(TimeoutHandler,
this,
kCleanupDelayMS,
nsITimer::TYPE_ONE_SHOT);
}
}
void
GamepadService::Update(const GamepadChangeEvent& aEvent)
{
if (aEvent.type() == GamepadChangeEvent::TGamepadAdded) {
const GamepadAdded& a = aEvent.get_GamepadAdded();
AddGamepad(a.index(), a.id(),
static_cast<GamepadMappingType>(a.mapping()),
a.num_buttons(), a.num_axes());
} else if (aEvent.type() == GamepadChangeEvent::TGamepadRemoved) {
const GamepadRemoved& a = aEvent.get_GamepadRemoved();
RemoveGamepad(a.index());
} else if (aEvent.type() == GamepadChangeEvent::TGamepadButtonInformation) {
const GamepadButtonInformation& a = aEvent.get_GamepadButtonInformation();
NewButtonEvent(a.index(), a.button(), a.pressed(), a.value());
} else if (aEvent.type() == GamepadChangeEvent::TGamepadAxisInformation) {
const GamepadAxisInformation& a = aEvent.get_GamepadAxisInformation();
NewAxisMoveEvent(a.index(), a.axis(), a.value());
} else {
MOZ_CRASH("We shouldn't be here!");
}
}
} // namespace dom
} // namespace mozilla

View File

@ -1,138 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_GamepadService_h_
#define mozilla_dom_GamepadService_h_
#include <stdint.h>
#include "nsCOMArray.h"
#include "nsIGamepadServiceTest.h"
#include "nsGlobalWindow.h"
#include "nsIFocusManager.h"
#include "nsIObserver.h"
#include "nsITimer.h"
#include "nsTArray.h"
// Needed for GamepadMappingType
#include "mozilla/dom/GamepadBinding.h"
namespace mozilla {
namespace dom {
class EventTarget;
class GamepadChangeEvent;
class Gamepad;
class GamepadService : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
// Returns true if we actually have a service up and running
static bool IsServiceRunning();
// Get the singleton service
static already_AddRefed<GamepadService> GetService();
// Return true if the API is preffed on.
static bool IsAPIEnabled();
void BeginShutdown();
void StopMonitoring();
// Indicate that |aWindow| wants to receive gamepad events.
void AddListener(nsGlobalWindow* aWindow);
// Indicate that |aWindow| should no longer receive gamepad events.
void RemoveListener(nsGlobalWindow* aWindow);
// Add a gamepad to the list of known gamepads.
void AddGamepad(uint32_t aIndex, const nsAString& aID, GamepadMappingType aMapping,
uint32_t aNumButtons, uint32_t aNumAxes);
// Remove the gamepad at |aIndex| from the list of known gamepads.
void RemoveGamepad(uint32_t aIndex);
// Update the state of |aButton| for the gamepad at |aIndex| for all
// windows that are listening and visible, and fire one of
// a gamepadbutton{up,down} event at them as well.
// aPressed is used for digital buttons, aValue is for analog buttons.
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed,
double aValue);
// Update the state of |aAxis| for the gamepad at |aIndex| for all
// windows that are listening and visible, and fire a gamepadaxismove
// event at them as well.
void NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue);
// Synchronize the state of |aGamepad| to match the gamepad stored at |aIndex|
void SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad);
// Returns gamepad object if index exists, null otherwise
already_AddRefed<Gamepad> GetGamepad(uint32_t aIndex);
// Receive GamepadChangeEvent messages from parent process to fire DOM events
void Update(const GamepadChangeEvent& aGamepadEvent);
protected:
GamepadService();
virtual ~GamepadService() {};
void StartCleanupTimer();
// Fire a gamepadconnected or gamepaddisconnected event for the gamepad
// at |aIndex| to all windows that are listening and have received
// gamepad input.
void NewConnectionEvent(uint32_t aIndex, bool aConnected);
// Fire a gamepadaxismove event to the window at |aTarget| for |aGamepad|.
void FireAxisMoveEvent(EventTarget* aTarget,
Gamepad* aGamepad,
uint32_t axis,
double value);
// Fire one of gamepadbutton{up,down} event at the window at |aTarget| for
// |aGamepad|.
void FireButtonEvent(EventTarget* aTarget,
Gamepad* aGamepad,
uint32_t aButton,
double aValue);
// Fire one of gamepad{connected,disconnected} event at the window at
// |aTarget| for |aGamepad|.
void FireConnectionEvent(EventTarget* aTarget,
Gamepad* aGamepad,
bool aConnected);
// true if this feature is enabled in preferences
bool mEnabled;
// true if non-standard events are enabled in preferences
bool mNonstandardEventsEnabled;
// true if the platform-specific backend has started work
bool mStarted;
// true when shutdown has begun
bool mShuttingDown;
private:
// Returns true if we have already sent data from this gamepad
// to this window. This should only return true if the user
// explicitly interacted with a gamepad while this window
// was focused, by pressing buttons or similar actions.
bool WindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex);
// Indicate that a window has recieved data from a gamepad.
void SetWindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex,
bool aHasSeen = true);
static void TimeoutHandler(nsITimer* aTimer, void* aClosure);
static bool sShutdown;
// Gamepads connected to the system. Copies of these are handed out
// to each window.
nsRefPtrHashtable<nsUint32HashKey, Gamepad> mGamepads;
// Inner windows that are listening for gamepad events.
// has been sent to that window.
nsTArray<RefPtr<nsGlobalWindow> > mListeners;
nsCOMPtr<nsITimer> mTimer;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_GamepadService_h_

View File

@ -204,6 +204,197 @@ SuspendBackgroundVideoDelay()
MediaPrefs::MDSMSuspendBackgroundVideoDelay());
}
class MediaDecoderStateMachine::StateObject
{
public:
virtual ~StateObject() {}
virtual void Enter() {}; // Entry action.
virtual void Exit() {}; // Exit action.
virtual void Step() {} // Perform a 'cycle' of this state object.
virtual State GetState() const = 0;
protected:
using Master = MediaDecoderStateMachine;
explicit StateObject(Master* aPtr) : mMaster(aPtr) {}
// Take a raw pointer in order not to change the life cycle of MDSM.
// It is guaranteed to be valid by MDSM.
Master* mMaster;
};
class MediaDecoderStateMachine::DecodeMetadataState
: public MediaDecoderStateMachine::StateObject
{
public:
explicit DecodeMetadataState(Master* aPtr) : StateObject(aPtr) {}
void Enter() override
{
mMaster->ReadMetadata();
}
State GetState() const override
{
return DECODER_STATE_DECODING_METADATA;
}
};
class MediaDecoderStateMachine::WaitForCDMState
: public MediaDecoderStateMachine::StateObject
{
public:
explicit WaitForCDMState(Master* aPtr) : StateObject(aPtr) {}
State GetState() const override
{
return DECODER_STATE_WAIT_FOR_CDM;
}
};
class MediaDecoderStateMachine::DormantState
: public MediaDecoderStateMachine::StateObject
{
public:
explicit DormantState(Master* aPtr) : StateObject(aPtr) {}
void Enter() override
{
mMaster->DiscardSeekTaskIfExist();
if (mMaster->IsPlaying()) {
mMaster->StopPlayback();
}
mMaster->Reset();
mMaster->mReader->ReleaseResources();
}
State GetState() const override
{
return DECODER_STATE_DORMANT;
}
};
class MediaDecoderStateMachine::DecodingFirstFrameState
: public MediaDecoderStateMachine::StateObject
{
public:
explicit DecodingFirstFrameState(Master* aPtr) : StateObject(aPtr) {}
void Enter() override
{
mMaster->DecodeFirstFrame();
}
State GetState() const override
{
return DECODER_STATE_DECODING_FIRSTFRAME;
}
};
class MediaDecoderStateMachine::DecodingState
: public MediaDecoderStateMachine::StateObject
{
public:
explicit DecodingState(Master* aPtr) : StateObject(aPtr) {}
void Enter() override
{
mMaster->StartDecoding();
}
void Step() override
{
mMaster->StepDecoding();
}
State GetState() const override
{
return DECODER_STATE_DECODING;
}
};
class MediaDecoderStateMachine::SeekingState
: public MediaDecoderStateMachine::StateObject
{
public:
explicit SeekingState(Master* aPtr) : StateObject(aPtr) {}
State GetState() const override
{
return DECODER_STATE_SEEKING;
}
};
class MediaDecoderStateMachine::BufferingState
: public MediaDecoderStateMachine::StateObject
{
public:
explicit BufferingState(Master* aPtr) : StateObject(aPtr) {}
void Enter() override
{
mMaster->StartBuffering();
}
void Step() override
{
mMaster->StepBuffering();
}
State GetState() const override
{
return DECODER_STATE_BUFFERING;
}
};
class MediaDecoderStateMachine::CompletedState
: public MediaDecoderStateMachine::StateObject
{
public:
explicit CompletedState(Master* aPtr) : StateObject(aPtr) {}
void Enter() override
{
mMaster->ScheduleStateMachine();
}
void Exit() override
{
mMaster->mSentPlaybackEndedEvent = false;
}
void Step() override
{
mMaster->StepCompleted();
}
State GetState() const override
{
return DECODER_STATE_COMPLETED;
}
};
class MediaDecoderStateMachine::ShutdownState
: public MediaDecoderStateMachine::StateObject
{
public:
explicit ShutdownState(Master* aPtr) : StateObject(aPtr) {}
void Enter() override
{
mMaster->mIsShutdown = true;
}
void Exit() override
{
MOZ_DIAGNOSTIC_ASSERT(false, "Shouldn't escape the SHUTDOWN state.");
}
State GetState() const override
{
return DECODER_STATE_SHUTDOWN;
}
};
#define INIT_WATCHABLE(name, val) \
name(val, "MediaDecoderStateMachine::" #name)
#define INIT_MIRROR(name, val) \
@ -223,6 +414,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mDispatchedStateMachine(false),
mDelayedScheduler(mTaskQueue),
INIT_WATCHABLE(mState, DECODER_STATE_DECODING_METADATA),
mStateObj(new DecodeMetadataState(this)),
mCurrentFrameID(0),
INIT_WATCHABLE(mObservedDuration, TimeUnit()),
mFragmentEndTime(-1),
@ -872,8 +1064,10 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder)
nsresult rv = mReader->Init();
NS_ENSURE_SUCCESS(rv, rv);
OwnerThread()->Dispatch(
NewRunnableMethod(this, &MediaDecoderStateMachine::EnterState));
RefPtr<MediaDecoderStateMachine> self = this;
OwnerThread()->Dispatch(NS_NewRunnableFunction([self] () {
self->mStateObj->Enter();
}));
return NS_OK;
}
@ -1063,61 +1257,45 @@ MediaDecoderStateMachine::SetState(State aState)
DECODER_LOG("MDSM state: %s -> %s", ToStateStr(), ToStateStr(aState));
ExitState();
MOZ_ASSERT(mState == mStateObj->GetState());
mStateObj->Exit();
mState = aState;
EnterState();
}
void
MediaDecoderStateMachine::ExitState()
{
MOZ_ASSERT(OnTaskQueue());
switch (mState) {
case DECODER_STATE_COMPLETED:
mSentPlaybackEndedEvent = false;
break;
case DECODER_STATE_SHUTDOWN:
MOZ_DIAGNOSTIC_ASSERT(false, "Shouldn't escape the SHUTDOWN state.");
break;
default:
break;
}
}
void
MediaDecoderStateMachine::EnterState()
{
MOZ_ASSERT(OnTaskQueue());
switch (mState) {
case DECODER_STATE_DECODING_METADATA:
ReadMetadata();
mStateObj = MakeUnique<DecodeMetadataState>(this);
break;
case DECODER_STATE_WAIT_FOR_CDM:
mStateObj = MakeUnique<WaitForCDMState>(this);
break;
case DECODER_STATE_DORMANT:
DiscardSeekTaskIfExist();
if (IsPlaying()) {
StopPlayback();
}
Reset();
mReader->ReleaseResources();
mStateObj = MakeUnique<DormantState>(this);
break;
case DECODER_STATE_DECODING_FIRSTFRAME:
DecodeFirstFrame();
mStateObj = MakeUnique<DecodingFirstFrameState>(this);
break;
case DECODER_STATE_DECODING:
StartDecoding();
mStateObj = MakeUnique<DecodingState>(this);
break;
case DECODER_STATE_SEEKING:
mStateObj = MakeUnique<SeekingState>(this);
break;
case DECODER_STATE_BUFFERING:
StartBuffering();
mStateObj = MakeUnique<BufferingState>(this);
break;
case DECODER_STATE_COMPLETED:
ScheduleStateMachine();
mStateObj = MakeUnique<CompletedState>(this);
break;
case DECODER_STATE_SHUTDOWN:
mIsShutdown = true;
mStateObj = MakeUnique<ShutdownState>(this);
break;
default:
MOZ_ASSERT_UNREACHABLE("Invalid state.");
break;
}
MOZ_ASSERT(mState == mStateObj->GetState());
mStateObj->Enter();
}
void MediaDecoderStateMachine::VolumeChanged()
@ -2262,20 +2440,7 @@ MediaDecoderStateMachine::RunStateMachine()
mDelayedScheduler.Reset(); // Must happen on state machine task queue.
mDispatchedStateMachine = false;
switch (mState) {
case DECODER_STATE_DECODING:
StepDecoding();
return;
case DECODER_STATE_BUFFERING:
StepBuffering();
return;
case DECODER_STATE_COMPLETED:
StepCompleted();
return;
default:
return;
}
mStateObj->Step();
}
void

View File

@ -251,6 +251,17 @@ public:
size_t SizeOfAudioQueue() const;
private:
class StateObject;
class DecodeMetadataState;
class WaitForCDMState;
class DormantState;
class DecodingFirstFrameState;
class DecodingState;
class SeekingState;
class BufferingState;
class CompletedState;
class ShutdownState;
static const char* ToStateStr(State aState);
const char* ToStateStr();
@ -346,8 +357,6 @@ protected:
virtual ~MediaDecoderStateMachine();
void SetState(State aState);
void ExitState();
void EnterState();
void BufferedRangeUpdated();
@ -603,6 +612,8 @@ private:
// Accessed on state machine, audio, main, and AV thread.
Watchable<State> mState;
UniquePtr<StateObject> mStateObj;
// Time that buffering started. Used for buffering timeout and only
// accessed on the state machine thread. This is null while we're not
// buffering.

View File

@ -102,8 +102,8 @@ TrackBuffersManager::TrackBuffersManager(MediaSourceDecoder* aParentDecoder,
, mVideoEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold.video",
100 * 1024 * 1024))
, mAudioEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold.audio",
30 * 1024 * 1024))
, mEvictionOccurred(false)
10 * 1024 * 1024))
, mEvictionState(EvictionState::NO_EVICTION_NEEDED)
, mMonitor("TrackBuffersManager")
{
MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread");
@ -278,19 +278,23 @@ TrackBuffersManager::EvictData(const TimeUnit& aPlaybackTime, int64_t aSize)
GetSize() / 1024, EvictionThreshold() / 1024, toEvict / 1024);
if (toEvict <= 0) {
mEvictionState = EvictionState::NO_EVICTION_NEEDED;
return EvictDataResult::NO_DATA_EVICTED;
}
if (toEvict <= 512*1024) {
// Don't bother evicting less than 512KB.
mEvictionState = EvictionState::NO_EVICTION_NEEDED;
return EvictDataResult::CANT_EVICT;
}
if (mBufferFull && mEvictionOccurred) {
if (mBufferFull && mEvictionState == EvictionState::EVICTION_COMPLETED) {
return EvictDataResult::BUFFER_FULL;
}
MSE_DEBUG("Reaching our size limit, schedule eviction of %lld bytes", toEvict);
mEvictionState = EvictionState::EVICTION_NEEDED;
QueueTask(new EvictDataTask(aPlaybackTime, toEvict));
return EvictDataResult::NO_DATA_EVICTED;
@ -411,6 +415,8 @@ TrackBuffersManager::DoEvictData(const TimeUnit& aPlaybackTime,
{
MOZ_ASSERT(OnTaskQueue());
mEvictionState = EvictionState::EVICTION_COMPLETED;
// Video is what takes the most space, only evict there if we have video.
const auto& track = HasVideo() ? mVideoTracks : mAudioTracks;
const auto& buffer = track.mBuffers.LastElement();
@ -452,11 +458,21 @@ TrackBuffersManager::DoEvictData(const TimeUnit& aPlaybackTime,
toEvict = mSizeSourceBuffer - finalSize;
// Still some to remove. Remove data starting from the end, up to 30s ahead
// of the later of the playback time or the next sample to be demuxed.
// 30s is a value chosen as it appears to work with YouTube.
TimeUnit upperLimit =
std::max(aPlaybackTime, track.mNextSampleTime) + TimeUnit::FromSeconds(30);
// See if we can evict data into the future.
// We do not evict data from the currently used buffered interval.
TimeUnit currentPosition = std::max(aPlaybackTime, track.mNextSampleTime);
TimeIntervals futureBuffered(TimeInterval(currentPosition, TimeUnit::FromInfinity()));
futureBuffered.Intersection(track.mBufferedRanges);
futureBuffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
if (futureBuffered.Length() <= 1) {
// We have one continuous segment ahead of us:
// nothing further can be evicted.
return;
}
// Don't evict before the end of the current segment
TimeUnit upperLimit = futureBuffered[0].mEnd;
uint32_t evictedFramesStartIndex = buffer.Length();
for (int32_t i = buffer.Length() - 1; i >= 0; i--) {
const auto& frame = buffer[i];
@ -563,7 +579,6 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
if (mBufferFull && mSizeSourceBuffer < EvictionThreshold()) {
mBufferFull = false;
}
mEvictionOccurred = true;
return dataRemoved;
}
@ -1269,7 +1284,6 @@ TrackBuffersManager::CompleteCodedFrameProcessing()
// 4. If this SourceBuffer is full and cannot accept more media data, then set the buffer full flag to true.
if (mSizeSourceBuffer >= EvictionThreshold()) {
mBufferFull = true;
mEvictionOccurred = false;
}
// 5. If the input buffer does not contain a complete media segment, then jump to the need more data step below.

View File

@ -435,7 +435,13 @@ private:
Atomic<int64_t> mSizeSourceBuffer;
const int64_t mVideoEvictionThreshold;
const int64_t mAudioEvictionThreshold;
Atomic<bool> mEvictionOccurred;
enum class EvictionState
{
NO_EVICTION_NEEDED,
EVICTION_NEEDED,
EVICTION_COMPLETED,
};
Atomic<EvictionState> mEvictionState;
// Monitor to protect following objects accessed across multipple threads.
mutable Monitor mMonitor;

View File

@ -37,12 +37,13 @@ public:
virtual HRESULT Output(int64_t aStreamOffset,
RefPtr<MediaData>& aOutput) = 0;
void Flush() {
virtual void Flush()
{
mDecoder->Flush();
mSeekTargetThreshold.reset();
}
void Drain()
virtual void Drain()
{
if (FAILED(mDecoder->SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0))) {
NS_WARNING("Failed to send DRAIN command to MFT");

View File

@ -525,6 +525,8 @@ WMFVideoMFTManager::Input(MediaRawData* aSample)
NS_ENSURE_TRUE(SUCCEEDED(hr) && mLastInput != nullptr, hr);
mLastDuration = aSample->mDuration;
mLastTime = aSample->mTime;
mSamplesCount++;
// Forward sample data to the decoder.
return mDecoder->Input(mLastInput);
@ -832,6 +834,15 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
HRESULT hr;
aOutData = nullptr;
int typeChangeCount = 0;
bool wasDraining = mDraining;
int64_t sampleCount = mSamplesCount;
if (wasDraining) {
mSamplesCount = 0;
mDraining = false;
}
media::TimeUnit pts;
media::TimeUnit duration;
// Loop until we decode a sample, or an unexpected error that we can't
// handle occurs.
@ -873,12 +884,21 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
}
continue;
}
pts = GetSampleTime(sample);
duration = GetSampleDuration(sample);
if (!pts.IsValid() || !duration.IsValid()) {
return E_FAIL;
}
if (wasDraining && sampleCount == 1 && pts == media::TimeUnit()) {
// WMF is unable to calculate a duration if only a single sample
// was parsed. Additionally, the pts always comes out at 0 under those
// circumstances.
// Seeing that we've only fed the decoder a single frame, the pts
// and duration are known, it's of the last sample.
pts = media::TimeUnit::FromMicroseconds(mLastTime);
duration = media::TimeUnit::FromMicroseconds(mLastDuration);
}
if (mSeekTargetThreshold.isSome()) {
media::TimeUnit pts = GetSampleTime(sample);
media::TimeUnit duration = GetSampleDuration(sample);
if (!pts.IsValid() || !duration.IsValid()) {
return E_FAIL;
}
if ((pts + duration) < mSeekTargetThreshold.ref()) {
LOG("Dropping video frame which pts is smaller than seek target.");
// It is necessary to clear the pointer to release the previous output
@ -907,6 +927,9 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
NS_ENSURE_TRUE(frame, E_FAIL);
aOutData = frame;
// Set the potentially corrected pts and duration.
aOutData->mTime = pts.ToMicroseconds();
aOutData->mDuration = duration.ToMicroseconds();
if (mNullOutputCount) {
mGotValidOutputAfterNullOutput = true;

View File

@ -49,6 +49,19 @@ public:
? "wmf hardware video decoder" : "wmf software video decoder";
}
void Flush() override
{
MFTManager::Flush();
mDraining = false;
mSamplesCount = 0;
}
void Drain() override
{
MFTManager::Drain();
mDraining = true;
}
private:
bool ValidateVideoInfo();
@ -81,6 +94,9 @@ private:
RefPtr<IMFSample> mLastInput;
float mLastDuration;
int64_t mLastTime = 0;
bool mDraining = false;
int64_t mSamplesCount = 0;
bool mDXVAEnabled;
const layers::LayersBackend mLayersBackend;

View File

@ -3246,5 +3246,30 @@ Promise::GetID() {
}
#endif // SPIDERMONKEY_PROMISE
#ifndef SPIDERMONKEY_PROMISE
Promise::PromiseState
Promise::State() const
{
return mState;
}
#else // SPIDERMONKEY_PROMISE
Promise::PromiseState
Promise::State() const
{
JS::Rooted<JSObject*> p(RootingCx(), PromiseObj());
const JS::PromiseState state = JS::GetPromiseState(p);
if (state == JS::PromiseState::Fulfilled) {
return PromiseState::Resolved;
}
if (state == JS::PromiseState::Rejected) {
return PromiseState::Rejected;
}
return PromiseState::Pending;
}
#endif // SPIDERMONKEY_PROMISE
} // namespace dom
} // namespace mozilla

View File

@ -313,6 +313,14 @@ public:
JS::Handle<JSObject*> aPromiseObj);
#endif // SPIDERMONKEY_PROMISE
enum class PromiseState {
Pending,
Resolved,
Rejected
};
PromiseState State() const;
protected:
struct PromiseCapability;
@ -369,12 +377,6 @@ protected:
#endif // SPIDERMONKEY_PROMISE
private:
enum PromiseState {
Pending,
Resolved,
Rejected
};
#ifndef SPIDERMONKEY_PROMISE
friend class PromiseDebugging;

View File

@ -7,15 +7,15 @@
#include "SRICheck.h"
#include "mozilla/Base64.h"
#include "mozilla/LoadTainting.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/SRILogHelper.h"
#include "nsContentUtils.h"
#include "nsIChannel.h"
#include "nsIDocument.h"
#include "nsIConsoleReportCollector.h"
#include "nsIProtocolHandler.h"
#include "nsIScriptError.h"
#include "nsIScriptSecurityManager.h"
#include "nsIIncrementalStreamLoader.h"
#include "nsIUnicharStreamLoader.h"
#include "nsIURI.h"
@ -36,10 +36,11 @@ namespace dom {
* sub-resource will be loaded.
*/
static nsresult
IsEligible(nsIChannel* aChannel, const CORSMode aCORSMode,
const nsIDocument* aDocument)
IsEligible(nsIChannel* aChannel, mozilla::LoadTainting aTainting,
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter)
{
NS_ENSURE_ARG_POINTER(aDocument);
NS_ENSURE_ARG_POINTER(aReporter);
if (!aChannel) {
SRILOG(("SRICheck::IsEligible, null channel"));
@ -47,7 +48,7 @@ IsEligible(nsIChannel* aChannel, const CORSMode aCORSMode,
}
// Was the sub-resource loaded via CORS?
if (aCORSMode != CORS_NONE) {
if (aTainting == LoadTainting::CORS) {
SRILOG(("SRICheck::IsEligible, CORS mode"));
return NS_OK;
}
@ -63,40 +64,38 @@ IsEligible(nsIChannel* aChannel, const CORSMode aCORSMode,
NS_ENSURE_SUCCESS(rv, rv);
if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
nsAutoCString documentSpec;
aDocument->GetDocumentURI()->GetAsciiSpec(documentSpec);
SRILOG(("SRICheck::IsEligible, documentURI=%s; requestURI=%s; finalURI=%s",
documentSpec.get(), requestSpec.get(),
SRILOG(("SRICheck::IsEligible, requestURI=%s; finalURI=%s",
requestSpec.get(),
finalURI ? finalURI->GetSpecOrDefault().get() : ""));
}
// Is the sub-resource same-origin?
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
if (NS_SUCCEEDED(ssm->CheckSameOriginURI(aDocument->GetDocumentURI(),
finalURI, false))) {
if (aTainting == LoadTainting::Basic) {
SRILOG(("SRICheck::IsEligible, same-origin"));
return NS_OK;
}
SRILOG(("SRICheck::IsEligible, NOT same origin"));
NS_ConvertUTF8toUTF16 requestSpecUTF16(requestSpec);
const char16_t* params[] = { requestSpecUTF16.get() };
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
aDocument,
nsContentUtils::eSECURITY_PROPERTIES,
"IneligibleResource",
params, ArrayLength(params));
nsTArray<nsString> params;
params.AppendElement(requestSpecUTF16);
aReporter->AddConsoleReport(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
nsContentUtils::eSECURITY_PROPERTIES,
aSourceFileURI, 0, 0,
NS_LITERAL_CSTRING("IneligibleResource"),
const_cast<const nsTArray<nsString>&>(params));
return NS_ERROR_SRI_NOT_ELIGIBLE;
}
/* static */ nsresult
SRICheck::IntegrityMetadata(const nsAString& aMetadataList,
const nsIDocument* aDocument,
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter,
SRIMetadata* outMetadata)
{
NS_ENSURE_ARG_POINTER(outMetadata);
NS_ENSURE_ARG_POINTER(aDocument);
NS_ENSURE_ARG_POINTER(aReporter);
MOZ_ASSERT(outMetadata->IsEmpty()); // caller must pass empty metadata
if (!Preferences::GetBool("security.sri.enable", false)) {
@ -123,24 +122,26 @@ SRICheck::IntegrityMetadata(const nsAString& aMetadataList,
SRIMetadata metadata(token);
if (metadata.IsMalformed()) {
NS_ConvertUTF8toUTF16 tokenUTF16(token);
const char16_t* params[] = { tokenUTF16.get() };
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
aDocument,
nsContentUtils::eSECURITY_PROPERTIES,
"MalformedIntegrityHash",
params, ArrayLength(params));
nsTArray<nsString> params;
params.AppendElement(tokenUTF16);
aReporter->AddConsoleReport(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
nsContentUtils::eSECURITY_PROPERTIES,
aSourceFileURI, 0, 0,
NS_LITERAL_CSTRING("MalformedIntegrityHash"),
const_cast<const nsTArray<nsString>&>(params));
} else if (!metadata.IsAlgorithmSupported()) {
nsAutoCString alg;
metadata.GetAlgorithm(&alg);
NS_ConvertUTF8toUTF16 algUTF16(alg);
const char16_t* params[] = { algUTF16.get() };
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
aDocument,
nsContentUtils::eSECURITY_PROPERTIES,
"UnsupportedHashAlg",
params, ArrayLength(params));
nsTArray<nsString> params;
params.AppendElement(algUTF16);
aReporter->AddConsoleReport(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
nsContentUtils::eSECURITY_PROPERTIES,
aSourceFileURI, 0, 0,
NS_LITERAL_CSTRING("UnsupportedHashAlg"),
const_cast<const nsTArray<nsString>&>(params));
}
nsAutoCString alg1, alg2;
@ -159,6 +160,8 @@ SRICheck::IntegrityMetadata(const nsAString& aMetadataList,
}
}
outMetadata->mIntegrityString = aMetadataList;
if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
if (outMetadata->IsValid()) {
nsAutoCString alg;
@ -176,11 +179,12 @@ SRICheck::IntegrityMetadata(const nsAString& aMetadataList,
/* static */ nsresult
SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata,
nsIUnicharStreamLoader* aLoader,
const CORSMode aCORSMode,
const nsAString& aString,
const nsIDocument* aDocument)
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter)
{
NS_ENSURE_ARG_POINTER(aLoader);
NS_ENSURE_ARG_POINTER(aReporter);
NS_ConvertUTF16toUTF8 utf8Hash(aString);
nsCOMPtr<nsIChannel> channel;
@ -197,19 +201,20 @@ SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata,
SRILOG(("SRICheck::VerifyIntegrity (unichar stream)"));
}
SRICheckDataVerifier verifier(aMetadata, aDocument);
SRICheckDataVerifier verifier(aMetadata, aSourceFileURI, aReporter);
nsresult rv;
rv = verifier.Update(utf8Hash.Length(), (uint8_t*)utf8Hash.get());
NS_ENSURE_SUCCESS(rv, rv);
return verifier.Verify(aMetadata, channel, aCORSMode, aDocument);
return verifier.Verify(aMetadata, channel, aSourceFileURI, aReporter);
}
//////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////
SRICheckDataVerifier::SRICheckDataVerifier(const SRIMetadata& aMetadata,
const nsIDocument* aDocument)
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter)
: mCryptoHash(nullptr),
mBytesHashed(0),
mInvalidMetadata(false),
@ -220,13 +225,16 @@ SRICheckDataVerifier::SRICheckDataVerifier(const SRIMetadata& aMetadata,
// IntegrityMetadata() checks this and returns "no metadata" if
// it's disabled so we should never make it this far
MOZ_ASSERT(Preferences::GetBool("security.sri.enable", false));
MOZ_ASSERT(aReporter);
if (!aMetadata.IsValid()) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
aDocument,
nsContentUtils::eSECURITY_PROPERTIES,
"NoValidMetadata");
nsTArray<nsString> params;
aReporter->AddConsoleReport(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
nsContentUtils::eSECURITY_PROPERTIES,
aSourceFileURI, 0, 0,
NS_LITERAL_CSTRING("NoValidMetadata"),
const_cast<const nsTArray<nsString>&>(params));
mInvalidMetadata = true;
return; // ignore invalid metadata for forward-compatibility
}
@ -292,9 +300,10 @@ SRICheckDataVerifier::Finish()
nsresult
SRICheckDataVerifier::VerifyHash(const SRIMetadata& aMetadata,
uint32_t aHashIndex,
const nsIDocument* aDocument)
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter)
{
NS_ENSURE_ARG_POINTER(aDocument);
NS_ENSURE_ARG_POINTER(aReporter);
nsAutoCString base64Hash;
aMetadata.GetHash(aHashIndex, &base64Hash);
@ -302,11 +311,13 @@ SRICheckDataVerifier::VerifyHash(const SRIMetadata& aMetadata,
nsAutoCString binaryHash;
if (NS_WARN_IF(NS_FAILED(Base64Decode(base64Hash, binaryHash)))) {
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
aDocument,
nsContentUtils::eSECURITY_PROPERTIES,
"InvalidIntegrityBase64");
nsTArray<nsString> params;
aReporter->AddConsoleReport(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
nsContentUtils::eSECURITY_PROPERTIES,
aSourceFileURI, 0, 0,
NS_LITERAL_CSTRING("InvalidIntegrityBase64"),
const_cast<const nsTArray<nsString>&>(params));
return NS_ERROR_SRI_CORRUPT;
}
@ -314,11 +325,13 @@ SRICheckDataVerifier::VerifyHash(const SRIMetadata& aMetadata,
int8_t hashType;
aMetadata.GetHashType(&hashType, &hashLength);
if (binaryHash.Length() != hashLength) {
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
aDocument,
nsContentUtils::eSECURITY_PROPERTIES,
"InvalidIntegrityLength");
nsTArray<nsString> params;
aReporter->AddConsoleReport(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
nsContentUtils::eSECURITY_PROPERTIES,
aSourceFileURI, 0, 0,
NS_LITERAL_CSTRING("InvalidIntegrityLength"),
const_cast<const nsTArray<nsString>&>(params));
return NS_ERROR_SRI_CORRUPT;
}
@ -343,10 +356,10 @@ SRICheckDataVerifier::VerifyHash(const SRIMetadata& aMetadata,
nsresult
SRICheckDataVerifier::Verify(const SRIMetadata& aMetadata,
nsIChannel* aChannel,
const CORSMode aCORSMode,
const nsIDocument* aDocument)
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter)
{
NS_ENSURE_ARG_POINTER(aDocument);
NS_ENSURE_ARG_POINTER(aReporter);
if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
nsAutoCString requestURL;
@ -360,7 +373,11 @@ SRICheckDataVerifier::Verify(const SRIMetadata& aMetadata,
nsresult rv = Finish();
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(IsEligible(aChannel, aCORSMode, aDocument))) {
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
LoadTainting tainting = loadInfo->GetTainting();
if (NS_FAILED(IsEligible(aChannel, tainting, aSourceFileURI, aReporter))) {
return NS_ERROR_SRI_NOT_ELIGIBLE;
}
@ -369,7 +386,7 @@ SRICheckDataVerifier::Verify(const SRIMetadata& aMetadata,
}
for (uint32_t i = 0; i < aMetadata.HashCount(); i++) {
if (NS_SUCCEEDED(VerifyHash(aMetadata, i, aDocument))) {
if (NS_SUCCEEDED(VerifyHash(aMetadata, i, aSourceFileURI, aReporter))) {
return NS_OK; // stop at the first valid hash
}
}
@ -377,13 +394,14 @@ SRICheckDataVerifier::Verify(const SRIMetadata& aMetadata,
nsAutoCString alg;
aMetadata.GetAlgorithm(&alg);
NS_ConvertUTF8toUTF16 algUTF16(alg);
const char16_t* params[] = { algUTF16.get() };
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
aDocument,
nsContentUtils::eSECURITY_PROPERTIES,
"IntegrityMismatch",
params, ArrayLength(params));
nsTArray<nsString> params;
params.AppendElement(algUTF16);
aReporter->AddConsoleReport(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Sub-resource Integrity"),
nsContentUtils::eSECURITY_PROPERTIES,
aSourceFileURI, 0, 0,
NS_LITERAL_CSTRING("IntegrityMismatch"),
const_cast<const nsTArray<nsString>&>(params));
return NS_ERROR_SRI_CORRUPT;
}

View File

@ -7,14 +7,13 @@
#ifndef mozilla_dom_SRICheck_h
#define mozilla_dom_SRICheck_h
#include "mozilla/CORSMode.h"
#include "nsCOMPtr.h"
#include "nsICryptoHash.h"
#include "SRIMetadata.h"
class nsIChannel;
class nsIDocument;
class nsIUnicharStreamLoader;
class nsIConsoleReportCollector;
namespace mozilla {
namespace dom {
@ -30,7 +29,8 @@ public:
* return the strongest supported hash.
*/
static nsresult IntegrityMetadata(const nsAString& aMetadataList,
const nsIDocument* aDocument,
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter,
SRIMetadata* outMetadata);
/**
@ -39,20 +39,22 @@ public:
*/
static nsresult VerifyIntegrity(const SRIMetadata& aMetadata,
nsIUnicharStreamLoader* aLoader,
const CORSMode aCORSMode,
const nsAString& aString,
const nsIDocument* aDocument);
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter);
};
class SRICheckDataVerifier final
{
public:
SRICheckDataVerifier(const SRIMetadata& aMetadata,
const nsIDocument* aDocument);
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter);
nsresult Update(uint32_t aStringLen, const uint8_t* aString);
nsresult Verify(const SRIMetadata& aMetadata, nsIChannel* aChannel,
const CORSMode aCORSMode, const nsIDocument* aDocument);
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter);
private:
nsCOMPtr<nsICryptoHash> mCryptoHash;
@ -65,7 +67,8 @@ class SRICheckDataVerifier final
nsresult EnsureCryptoHash();
nsresult Finish();
nsresult VerifyHash(const SRIMetadata& aMetadata, uint32_t aHashIndex,
const nsIDocument* aDocument);
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter);
};
} // namespace dom

View File

@ -9,12 +9,15 @@
#include "nsTArray.h"
#include "nsString.h"
#include "SRICheck.h"
namespace mozilla {
namespace dom {
class SRIMetadata final
{
friend class SRICheck;
public:
static const uint32_t MAX_ALTERNATE_HASHES = 256;
static const int8_t UNKNOWN_ALGORITHM = -1;
@ -61,8 +64,14 @@ public:
void GetAlgorithm(nsCString* outAlg) const { *outAlg = mAlgorithm; }
void GetHashType(int8_t* outType, uint32_t* outLength) const;
const nsString& GetIntegrityString() const
{
return mIntegrityString;
}
private:
nsTArray<nsCString> mHashes;
nsString mIntegrityString;
nsCString mAlgorithm;
int8_t mAlgorithmType;
bool mEmpty;

View File

@ -58,17 +58,17 @@
ok(false, "Non-CORS loads with correct hashes redirecting to a different origin should be blocked!");
}
function good_correctDataBlocked() {
ok(true, "A data: URL was blocked correctly.");
function good_correctDataLoaded() {
ok(true, "Since data: URLs are same-origin, they should be loaded.");
}
function bad_correctDataLoaded() {
ok(false, "Since data: URLs are neither same-origin nor CORS, they should be blocked!");
function bad_correctDataBlocked() {
todo(false, "We should not block scripts in data: URIs!");
}
function good_correctDataCORSBlocked() {
ok(true, "A data: URL was blocked correctly even though it was a CORS load.");
function good_correctDataCORSLoaded() {
ok(true, "A data: URL with a CORS load was loaded correctly.");
}
function bad_correctDataCORSLoaded() {
todo(false, "We should not load scripts in data: URIs regardless of CORS mode!");
function bad_correctDataCORSBlocked() {
ok(false, "We should not BLOCK scripts!");
}
window.onload = function() {
@ -112,18 +112,18 @@
onerror="good_correct301Blocked()"
onload="bad_correct301Loaded()"></script>
<!-- data: URLs are not same-origin -->
<!-- data: URLs are same-origin -->
<script src="data:,console.log('data:valid');"
integrity="sha256-W5I4VIN+mCwOfR9kDbvWoY1UOVRXIh4mKRN0Nz0ookg="
onerror="good_correctDataBlocked()"
onload="bad_correctDataLoaded()"></script>
onerror="bad_correctDataBlocked()"
onload="good_correctDataLoaded()"></script>
<!-- data: URLs should always be opaque -->
<!-- not cors-enabled with data: URLs. should trigger onload -->
<script src="data:,console.log('data:valid');"
crossorigin="anonymous"
integrity="sha256-W5I4VIN+mCwOfR9kDbvWoY1UOVRXIh4mKRN0Nz0ookg="
onerror="good_correctDataCORSBlocked()"
onload="bad_correctDataCORSLoaded()"></script>
onerror="bad_correctDataCORSBlocked()"
onload="good_correctDataCORSLoaded()"></script>
<script>
ok(window.hasCORSLoaded, "CORS-enabled resource with a correct hash");

View File

@ -8,11 +8,14 @@
<script type="application/javascript">
function check_styles() {
var redText = document.getElementById('red-text');
var blackText = document.getElementById('black-text');
var greenText = document.getElementById('green-text');
var blueText = document.getElementById('blue-text');
var redTextColor = window.getComputedStyle(redText, null).getPropertyValue('color');
var blackTextColor = window.getComputedStyle(blackText, null).getPropertyValue('color');
var greenTextColor = window.getComputedStyle(greenText, null).getPropertyValue('color');
var blueTextColor = window.getComputedStyle(blueText, null).getPropertyValue('color');
ok(redTextColor == 'rgb(255, 0, 0)', "The first part should be red.");
todo(blackTextColor == 'rgb(0, 0, 0)', "The second part should still be black.");
ok(greenTextColor == 'rgb(0, 255, 0)', "The second part should be green.");
ok(blueTextColor == 'rgb(0, 0, 255)', "The third part should be blue.");
}
SimpleTest.waitForExplicitFinish();
@ -42,17 +45,24 @@
ok(false, "We should load non-CORS cross-domain stylesheets with incorrect hashes!");
}
function good_correctDataBlocked() {
ok(true, "A stylesheet was correctly blocked, because it came from a data: URI.");
function bad_correctDataBlocked() {
ok(false, "We should not block non-CORS cross-domain stylesheets in data: URI!");
}
function bad_correctDataLoaded() {
ok(false, "We should not load stylesheets in data: URIs!");
function good_correctDataLoaded() {
ok(true, "A non-CORS cross-domain stylesheet with data: URI was correctly loaded.");
}
function good_correctDataCORSBlocked() {
ok(true, "A stylesheet was correctly blocked, because it came from a data: URI even though it was a CORS load.");
function bad_correctDataCORSBlocked() {
ok(false, "We should not block CORS stylesheets in data: URI!");
}
function bad_correctDataCORSLoaded() {
todo(false, "We should not load stylesheets in data: URIs regardless of CORS mode!");
function good_correctDataCORSLoaded() {
ok(true, "A CORS stylesheet with data: URI was correctly loaded.");
}
function good_correctHashOpaqueBlocked() {
ok(true, "A non-CORS(Opaque) cross-domain stylesheet with correct hash was correctly blocked.");
}
function bad_correctHashOpaqueLoaded() {
ok(false, "We should not load non-CORS(Opaque) cross-domain stylesheets with correct hashes!");
}
</script>
@ -76,21 +86,28 @@
onload="bad_incorrectHashLoaded()">
<!-- valid non-CORS sha256 hash in a data: URL -->
<link rel="stylesheet" href="data:text/css,.red-text{color:red}"
integrity="sha256-ewUcnAs4+XY5k2JpfUQGFdG5YMZkq80/nIKW67kd7vE="
onerror="good_correctDataBlocked()"
onload="bad_correctDataLoaded()">
<link rel="stylesheet" href="data:text/css,.green-text{color:rgb(0, 255, 0)}"
integrity="sha256-EhVtGGyovvffvYdhyqJxUJ/ekam7zlxxo46iM13cwP0="
onerror="bad_correctDataBlocked()"
onload="good_correctDataLoaded()">
<!-- valid CORS sha256 hash in a data: URL -->
<link rel="stylesheet" href="data:text/css,.red-text{color:red}"
<link rel="stylesheet" href="data:text/css,.blue-text{color:rgb(0, 0, 255)}"
crossorigin="anonymous"
integrity="sha256-ewUcnAs4+XY5k2JpfUQGFdG5YMZkq80/nIKW67kd7vE="
onerror="good_correctDataCORSBlocked()"
onload="bad_correctDataCORSLoaded()">
integrity="sha256-m0Fs2hNSyPOn1030Dp+c8pJFHNmwpeTbB+8J/DcqLss="
onerror="bad_correctDataCORSBlocked()"
onload="good_correctDataCORSLoaded()">
<!-- valid non-CORS sha256 hash -->
<link rel="stylesheet" href="http://example.com/tests/dom/security/test/sri/style1.css"
integrity="sha256-qs8lnkunWoVldk5d5E+652yth4VTSHohlBKQvvgGwa8="
onerror="good_correctHashOpaqueBlocked()"
onload="bad_correctHashOpaqueLoaded()">
</head>
<body>
<p><span id="red-text">This should be red</span> but
<span id="black-text" class="red-text">this should remain black.</span></p>
<span id="green-text" class="green-text">this should be green</span> and
<span id="blue-text" class="blue-text">this should be blue</span></p>
<p id="display"></p>
<div id="content" style="display: none">
</div>

View File

@ -25,6 +25,7 @@ interface Request {
readonly attribute RequestCredentials credentials;
readonly attribute RequestCache cache;
readonly attribute RequestRedirect redirect;
readonly attribute DOMString integrity;
[Throws,
NewObject] Request clone();
@ -45,6 +46,7 @@ dictionary RequestInit {
RequestCredentials credentials;
RequestCache cache;
RequestRedirect redirect;
DOMString integrity;
};
// Gecko currently does not ship RequestContext, so please don't use it in IDL

View File

@ -1541,6 +1541,98 @@ ServiceWorkerManager::LocalizeAndReportToAllClients(
}
}
void
ServiceWorkerManager::FlushReportsToAllClients(const nsACString& aScope,
nsIConsoleReportCollector* aReporter)
{
AutoTArray<uint64_t, 16> windows;
// Report errors to every controlled document.
for (auto iter = mControlledDocuments.Iter(); !iter.Done(); iter.Next()) {
ServiceWorkerRegistrationInfo* reg = iter.UserData();
MOZ_ASSERT(reg);
if (!reg->mScope.Equals(aScope)) {
continue;
}
nsCOMPtr<nsIDocument> doc = do_QueryInterface(iter.Key());
if (!doc || !doc->IsCurrentActiveDocument() || !doc->GetWindow()) {
continue;
}
windows.AppendElement(doc->InnerWindowID());
aReporter->FlushConsoleReports(doc,
nsIConsoleReportCollector::ReportAction::Save);
}
// Report to any documents that have called .register() for this scope. They
// may not be controlled, but will still want to see error reports.
WeakDocumentList* regList = mRegisteringDocuments.Get(aScope);
if (regList) {
for (int32_t i = regList->Length() - 1; i >= 0; --i) {
nsCOMPtr<nsIDocument> doc = do_QueryReferent(regList->ElementAt(i));
if (!doc) {
regList->RemoveElementAt(i);
continue;
}
if (!doc->IsCurrentActiveDocument()) {
continue;
}
uint64_t innerWindowId = doc->InnerWindowID();
if (windows.Contains(innerWindowId)) {
continue;
}
windows.AppendElement(innerWindowId);
aReporter->FlushConsoleReports(doc,
nsIConsoleReportCollector::ReportAction::Save);
}
if (regList->IsEmpty()) {
regList = nullptr;
nsAutoPtr<WeakDocumentList> doomed;
mRegisteringDocuments.RemoveAndForget(aScope, doomed);
}
}
nsresult rv;
InterceptionList* intList = mNavigationInterceptions.Get(aScope);
if (intList) {
for (uint32_t i = 0; i < intList->Length(); ++i) {
nsCOMPtr<nsIInterceptedChannel> channel = intList->ElementAt(i);
nsCOMPtr<nsIChannel> inner;
rv = channel->GetChannel(getter_AddRefs(inner));
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
uint64_t innerWindowId = nsContentUtils::GetInnerWindowID(inner);
if (innerWindowId == 0 || windows.Contains(innerWindowId)) {
continue;
}
windows.AppendElement(innerWindowId);
aReporter->FlushReportsByWindowId(innerWindowId,
nsIConsoleReportCollector::ReportAction::Save);
}
}
// If there are no documents to report to, at least report something to the
// browser console.
if (windows.IsEmpty()) {
aReporter->FlushConsoleReports((nsIDocument*)nullptr);
return;
}
aReporter->ClearConsoleReports();
}
void
ServiceWorkerManager::HandleError(JSContext* aCx,
nsIPrincipal* aPrincipal,

View File

@ -13,6 +13,7 @@
#include "ipc/IPCMessageUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/ConsoleReportCollector.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Preferences.h"
#include "mozilla/TypedEnumBits.h"
@ -33,6 +34,7 @@
#include "nsTObserverArray.h"
class mozIApplicationClearPrivateDataParams;
class nsIConsoleReportCollector;
namespace mozilla {
@ -222,6 +224,10 @@ public:
uint32_t aLineNumber = 0,
uint32_t aColumnNumber = 0);
void
FlushReportsToAllClients(const nsACString& aScope,
nsIConsoleReportCollector* aReporter);
// Always consumes the error by reporting to consoles of all controlled
// documents.
void

View File

@ -1257,6 +1257,7 @@ class FetchEventRunnable : public ExtendableFunctionalEventWorkerRunnable
nsCOMPtr<nsIInputStream> mUploadStream;
nsCString mReferrer;
ReferrerPolicy mReferrerPolicy;
nsString mIntegrity;
public:
FetchEventRunnable(WorkerPrivate* aWorkerPrivate,
KeepAliveToken* aKeepAliveToken,
@ -1382,6 +1383,8 @@ public:
internalChannel->GetFetchCacheMode(&cacheMode);
mCacheMode = static_cast<RequestCache>(cacheMode);
internalChannel->GetIntegrityMetadata(mIntegrity);
mRequestCredentials = InternalRequest::MapChannelToRequestCredentials(channel);
rv = httpChannel->VisitNonDefaultRequestHeaders(this);
@ -1480,7 +1483,8 @@ private:
mRequestCredentials,
NS_ConvertUTF8toUTF16(mReferrer),
mReferrerPolicy,
mContentPolicyType);
mContentPolicyType,
mIntegrity);
internalReq->SetBody(mUploadStream);
// For Telemetry, note that this Request object was created by a Fetch event.
internalReq->SetCreatedByFetchEvent();

View File

@ -3441,6 +3441,51 @@ WorkerPrivateParent<Derived>::UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGr
mLoadInfo.mInterfaceRequestor->MaybeAddTabChild(aBaseLoadGroup);
}
template <class Derived>
void
WorkerPrivateParent<Derived>::FlushReportsToSharedWorkers(
nsIConsoleReportCollector* aReporter)
{
AssertIsOnMainThread();
AutoTArray<RefPtr<SharedWorker>, 10> sharedWorkers;
AutoTArray<WindowAction, 10> windowActions;
GetAllSharedWorkers(sharedWorkers);
// First find out all the shared workers' window.
for (size_t index = 0; index < sharedWorkers.Length(); index++) {
RefPtr<SharedWorker>& sharedWorker = sharedWorkers[index];
// May be null.
nsPIDOMWindowInner* window = sharedWorker->GetOwner();
// Add the owning window to our list so that we will flush the reports later.
if (window && !windowActions.Contains(window)) {
windowActions.AppendElement(WindowAction(window));
}
}
bool reportErrorToBrowserConsole = true;
// Flush the reports.
for (uint32_t index = 0; index < windowActions.Length(); index++) {
WindowAction& windowAction = windowActions[index];
aReporter->FlushConsoleReports(windowAction.mWindow->GetExtantDoc(),
nsIConsoleReportCollector::ReportAction::Save);
reportErrorToBrowserConsole = false;
}
// Finally report to broswer console if there is no any window or shared
// worker.
if (reportErrorToBrowserConsole) {
aReporter->FlushConsoleReports((nsIDocument*)nullptr);
return;
}
aReporter->ClearConsoleReports();
}
template <class Derived>
NS_IMPL_ADDREF_INHERITED(WorkerPrivateParent<Derived>, DOMEventTargetHelper)

View File

@ -18,6 +18,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/CondVar.h"
#include "mozilla/ConsoleReportCollector.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/Move.h"
#include "mozilla/TimeStamp.h"
@ -40,6 +41,7 @@
#endif
class nsIChannel;
class nsIConsoleReportCollector;
class nsIDocument;
class nsIEventTarget;
class nsIPrincipal;
@ -811,6 +813,9 @@ public:
return mLoadInfo.mLoadFailedAsyncRunnable.forget();
}
void
FlushReportsToSharedWorkers(nsIConsoleReportCollector* aReporter);
IMPL_EVENT_HANDLER(message)
IMPL_EVENT_HANDLER(error)

View File

@ -0,0 +1,6 @@
<!DOCTYPE HTML>
<title>Shared workers: create antoehr sharedworekr client</title>
<pre id=log>Hello World</pre>
<script>
var worker = new SharedWorker('sharedWorker_fetch.js');
</script>

View File

@ -0,0 +1,13 @@
addEventListener('fetch', function(event) {
if (event.request.url.indexOf("fail.html") !== -1) {
event.respondWith(fetch("serviceworker.html", {"integrity": "abc"}));
} else if (event.request.url.indexOf("fake.html") !== -1) {
event.respondWith(fetch("serviceworker.html"));
} else {
event.respondWith(new Response("Hello world"));
}
});
addEventListener("activate", function(event) {
event.waitUntil(clients.claim());
});

View File

@ -209,6 +209,10 @@ support-files =
sw_bad_mime_type.js
sw_bad_mime_type.js^headers^
error_reporting_helpers.js
fetch.js
serviceworker.html
create_another_sharedWorker.html
sharedWorker_fetch.js
[test_bug1151916.html]
[test_bug1240436.html]
@ -225,6 +229,7 @@ support-files =
[test_eval_allowed.html]
[test_eventsource_intercept.html]
[test_fetch_event.html]
[test_fetch_integrity.html]
skip-if = (debug && e10s) # Bug 1262224
[test_file_blob_response.html]
[test_file_blob_upload.html]

View File

@ -0,0 +1,31 @@
var clients = new Array();
clients.length = 0;
var broadcast = function(message) {
var length = clients.length;
for (var i = 0; i < length; i++) {
port = clients[i];
port.postMessage(message);
}
}
onconnect = function(e) {
clients.push(e.ports[0]);
if (clients.length == 1) {
clients[0].postMessage("Connected");
} else if (clients.length == 2) {
broadcast("BothConnected");
clients[0].onmessage = function(e) {
if (e.data == "StartFetchWithWrongIntegrity") {
// The fetch will succeed because the integrity value is invalid and we
// are looking for the console message regarding the bad integrity value.
fetch("SharedWorker_SRIFailed.html", {"integrity": "abc"}).then(
function () {
clients[0].postMessage('SRI_failed');
});
}
}
}
}

View File

@ -0,0 +1,178 @@
<!DOCTYPE HTML>
<html>
<head>
<title> Test fetch.integrity on console report for serviceWorker and sharedWorker </title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/SpawnTask.js"></script>
<script src="error_reporting_helpers.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<body>
<div id="content" style="display: none"></div>
<script type="text/javascript">
"use strict";
let security_localizer =
stringBundleService.createBundle("chrome://global/locale/security/security.properties");
function expect_security_console_message(/* msgId, args, ... */) {
let expectations = [];
// process repeated paired arguments of: msgId, args
for (let i = 0; i < arguments.length; i += 4) {
let msgId = arguments[i];
let args = arguments[i + 1];
let filename = arguments[i + 2];
let windowId = arguments[i + 3];
expectations.push({
errorMessage: security_localizer.formatStringFromName(msgId, args, args.length),
sourceName: filename,
windowID: windowId
});
}
return new Promise(resolve => {
SimpleTest.monitorConsole(resolve, expectations);
});
}
// (This doesn't really need to be its own task, but it allows the actual test
// case to be self-contained.)
add_task(function setupPrefs() {
return SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
]});
});
add_task(function* test_integrity_serviceWorker() {
var filename = make_absolute_url("fetch.js");
var filename2 = make_absolute_url("fake.html");
// The SW will claim us once it activates; this is async, start listening now.
let waitForControlled = new Promise((resolve) => {
navigator.serviceWorker.oncontrollerchange = resolve;
});
let registration = yield navigator.serviceWorker.register("fetch.js",
{ scope: "./" });
yield waitForControlled;
info("Test for mNavigationInterceptions.")
// The client_win will reload to another URL after opening filename2.
let client_win = window.open(filename2);
// XXX windowID should be innerWindowID
let mainWindowID = SpecialPowers.getDOMWindowUtils(window).outerWindowID;
let clientWindowID = SpecialPowers.getDOMWindowUtils(client_win).outerWindowID;
let expectedMessage = expect_security_console_message(
"MalformedIntegrityHash",
["abc"],
filename,
mainWindowID,
"NoValidMetadata",
[""],
filename,
mainWindowID
);
let expectedMessage2 = expect_security_console_message(
"MalformedIntegrityHash",
["abc"],
filename,
clientWindowID,
"NoValidMetadata",
[""],
filename,
clientWindowID
);
info("Test for mControlledDocuments and report error message to console.");
// The fetch will succeed because the integrity value is invalid and we are
// looking for the console message regarding the bad integrity value.
yield fetch("fail.html");
yield wait_for_expected_message(expectedMessage);
yield wait_for_expected_message(expectedMessage2);
yield registration.unregister();
client_win.close();
});
add_task(function* test_integrity_sharedWorker() {
var filename = make_absolute_url("sharedWorker_fetch.js");
info("Attch main window to a SharedWorker.");
let sharedWorker = new SharedWorker(filename);
let waitForConnected = new Promise((resolve) => {
sharedWorker.port.onmessage = function (e) {
if (e.data == "Connected") {
resolve();
} else {
reject();
}
}
});
yield waitForConnected;
info("Attch another window to the same SharedWorker.");
// Open another window and its also managed by the shared worker.
let client_win = window.open("create_another_sharedWorker.html");
let waitForBothConnected = new Promise((resolve) => {
sharedWorker.port.onmessage = function (e) {
if (e.data == "BothConnected") {
resolve();
} else {
reject();
}
}
});
yield waitForBothConnected;
// XXX windowID should be innerWindowID
let mainWindowID = SpecialPowers.getDOMWindowUtils(window).outerWindowID;
let clientWindowID = SpecialPowers.getDOMWindowUtils(client_win).outerWindowID;
let expectedMessage = expect_security_console_message(
"MalformedIntegrityHash",
["abc"],
filename,
mainWindowID,
"NoValidMetadata",
[""],
filename,
mainWindowID
);
let expectedMessage2 = expect_security_console_message(
"MalformedIntegrityHash",
["abc"],
filename,
clientWindowID,
"NoValidMetadata",
[""],
filename,
clientWindowID
);
info("Start to fetch a URL with wrong integrity.")
sharedWorker.port.start();
sharedWorker.port.postMessage("StartFetchWithWrongIntegrity");
let waitForSRIFailed = new Promise((resolve) => {
sharedWorker.port.onmessage = function (e) {
if (e.data == "SRI_failed") {
resolve();
} else {
reject();
}
}
});
yield waitForSRIFailed;
yield wait_for_expected_message(expectedMessage);
yield wait_for_expected_message(expectedMessage2);
client_win.close();
});
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -251,6 +251,8 @@ void
PathBuilderD2D::Arc(const Point &aOrigin, Float aRadius, Float aStartAngle,
Float aEndAngle, bool aAntiClockwise)
{
MOZ_ASSERT(aRadius >= 0);
if (aAntiClockwise && aStartAngle < aEndAngle) {
// D2D does things a little differently, and draws the arc by specifying an
// beginning and an end point. This means the circle will be the wrong way

3
gfx/angle/AUTHORS Normal file → Executable file
View File

@ -1,4 +1,4 @@
# This is the official list of The ANGLE Project Authors
# This is the official list of The ANGLE Project Authors
# for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
@ -45,3 +45,4 @@ Maks Naumov
Jinyoung Hur
Sebastian Bergstein
James Ross-Gowan
Nickolay Artamonov

122
gfx/angle/BUILD.gn Normal file → Executable file
View File

@ -4,8 +4,16 @@
# import the use_x11 variable
import("//build/config/dcheck_always_on.gni")
import("//build/config/linux/pkg_config.gni")
import("//build/config/ui.gni")
import("//third_party/angle/build/angle_common.gni")
import("//ui/ozone/ozone.gni")
if (ozone_platform_gbm) {
pkg_config("libdrm") {
packages = [ "libdrm" ]
}
}
angle_git_is_present = exec_script("src/commit_id.py",
[
@ -40,6 +48,16 @@ config("internal_config") {
]
}
config("extra_warnings") {
# Enable more default warnings on Windows.
if (is_win) {
cflags = [
"/we4244", # Conversion: possible loss of data.
"/we4456", # Variable shadowing.
]
}
}
if (is_win) {
copy("copy_compiler_dll") {
sources = [
@ -51,10 +69,7 @@ if (is_win) {
}
}
angle_undefine_configs = [
"//build/config/compiler:chromium_code",
"//build/config/compiler:default_include_dirs",
]
angle_undefine_configs = [ "//build/config/compiler:default_include_dirs" ]
component("translator") {
sources = [
@ -65,10 +80,7 @@ component("translator") {
defines = [ "ANGLE_TRANSLATOR_IMPLEMENTATION" ]
configs -= angle_undefine_configs
configs += [
":internal_config",
"//build/config/compiler:no_chromium_code",
]
configs += [ ":internal_config" ]
public_deps = [
":translator_lib",
@ -97,10 +109,7 @@ static_library("preprocessor") {
sources = rebase_path(compiler_gypi.angle_preprocessor_sources, ".", "src")
configs -= angle_undefine_configs
configs += [
":internal_config",
"//build/config/compiler:no_chromium_code",
]
configs += [ ":internal_config" ]
}
config("translator_static_config") {
@ -130,8 +139,8 @@ static_library("angle_common") {
configs += [
":angle_common_config",
":debug_annotations_config",
":extra_warnings",
":internal_config",
"//build/config/compiler:no_chromium_code",
]
public_deps = [
@ -143,6 +152,26 @@ static_library("angle_common") {
]
}
config("angle_image_util_config") {
include_dirs = [
"include",
"src",
]
}
static_library("angle_image_util") {
sources = rebase_path(gles_gypi.libangle_image_util_sources, ".", "src")
configs -= angle_undefine_configs
configs += [ ":internal_config" ]
public_configs = [ ":angle_image_util_config" ]
public_deps = [
":angle_common",
]
}
static_library("translator_lib") {
sources = rebase_path(compiler_gypi.angle_translator_lib_sources, ".", "src")
defines = []
@ -168,7 +197,6 @@ static_library("translator_lib") {
configs += [
":internal_config",
":translator_static_config",
"//build/config/compiler:no_chromium_code",
]
public_configs = [ ":external_config" ]
@ -180,6 +208,12 @@ static_library("translator_lib") {
public_deps = [
":angle_common",
]
if (is_win) {
# Necessary to suppress some system header xtree warnigns in Release.
# For some reason this warning doesn't get triggered in Chromium
cflags = [ "/wd4718" ]
}
}
static_library("translator_static") {
@ -193,10 +227,7 @@ static_library("translator_static") {
}
configs -= angle_undefine_configs
configs += [
":internal_config",
"//build/config/compiler:no_chromium_code",
]
configs += [ ":internal_config" ]
public_configs = [ ":translator_static_config" ]
public_deps = [
@ -285,6 +316,7 @@ static_library("libANGLE") {
":angle_common",
]
deps = [
":angle_image_util",
":commit_id",
":includes",
":translator_static",
@ -343,6 +375,14 @@ static_library("libANGLE") {
"log",
]
}
if (ozone_platform_gbm) {
configs += [ ":libdrm" ]
defines += [ "ANGLE_USE_OZONE" ]
deps += [ "//third_party/minigbm" ]
sources += rebase_path(gles_gypi.libangle_gl_egl_sources, ".", "src")
sources += rebase_path(gles_gypi.libangle_gl_egl_dl_sources, ".", "src")
sources += rebase_path(gles_gypi.libangle_gl_ozone_sources, ".", "src")
}
}
if (angle_enable_vulkan) {
@ -354,12 +394,13 @@ static_library("libANGLE") {
}
configs -= angle_undefine_configs
configs += [
":commit_id_config",
":debug_annotations_config",
":extra_warnings",
":libANGLE_config",
":internal_config",
"//build/config/compiler:no_chromium_code",
]
if (is_win) {
@ -369,6 +410,17 @@ static_library("libANGLE") {
}
}
config("shared_library_public_config") {
if (is_mac && !is_component_build) {
# Executable targets that depend on the shared libraries below need to have
# the rpath setup in non-component build configurations.
ldflags = [
"-rpath",
"@executable_path/",
]
}
}
shared_library("libGLESv2") {
sources = rebase_path(gles_gypi.libglesv2_sources, ".", "src")
@ -377,13 +429,20 @@ shared_library("libGLESv2") {
[ "/DEF:" + rebase_path("src/libGLESv2/libGLESv2.def", root_build_dir) ]
}
if (is_mac && !is_component_build) {
ldflags = [
"-install_name",
"@rpath/${target_name}.dylib",
]
public_configs = [ ":shared_library_public_config" ]
}
configs -= angle_undefine_configs
configs += [
":internal_config",
":commit_id_config",
":debug_annotations_config",
":libANGLE_config",
"//build/config/compiler:no_chromium_code",
]
defines = [ "LIBGLESV2_IMPLEMENTATION" ]
@ -401,13 +460,21 @@ shared_library("libEGL") {
ldflags = [ "/DEF:" + rebase_path("src/libEGL/libEGL.def", root_build_dir) ]
}
if (is_mac && !is_component_build) {
ldflags = [
"-install_name",
"@rpath/${target_name}.dylib",
]
public_configs = [ ":shared_library_public_config" ]
}
configs -= angle_undefine_configs
configs += [
":internal_config",
":commit_id_config",
":debug_annotations_config",
":extra_warnings",
":internal_config",
":libANGLE_config",
"//build/config/compiler:no_chromium_code",
]
defines = [ "LIBEGL_IMPLEMENTATION" ]
@ -425,7 +492,7 @@ util_gypi = exec_script("//build/gypi_to_gn.py",
config("angle_util_config") {
include_dirs = [ "util" ]
if (is_linux) {
if (is_linux && use_x11) {
libs = [ "X11" ]
}
}
@ -464,12 +531,19 @@ static_library("angle_util") {
]
}
if (use_ozone) {
sources += rebase_path(util_gypi.util_ozone_sources, ".", "util")
}
defines = [
"GL_GLEXT_PROTOTYPES",
"EGL_EGLEXT_PROTOTYPES",
]
configs += [ ":debug_annotations_config" ]
configs += [
":debug_annotations_config",
":extra_warnings",
]
public_configs = [
":angle_util_config",

2
gfx/angle/CONTRIBUTORS Normal file → Executable file
View File

@ -104,10 +104,12 @@ NVIDIA Corporation
Qingqing Deng
Kimmo Kinnunen
Sami Väisänen
Martin Radev
Opera Software ASA
Daniel Bratell
Tomasz Moniuszko
David Landell
Advanced Micro Devices, Inc.
Russ Lind

0
gfx/angle/DEPS Normal file → Executable file
View File

0
gfx/angle/DEPS.chromium Normal file → Executable file
View File

0
gfx/angle/LICENSE Normal file → Executable file
View File

0
gfx/angle/Makefile.in Normal file → Executable file
View File

0
gfx/angle/README.chromium Normal file → Executable file
View File

47
gfx/angle/README.md Normal file → Executable file
View File

@ -1,26 +1,43 @@
# ANGLE - Almost Native Graphics Layer Engine
The goal of ANGLE is to allow users of multiple operating systems to seamlessly run WebGL and other OpenGL ES content by translating OpenGL ES API calls to one of the hardware-supported APIs available for that platform. ANGLE currently provides translation from OpenGL ES 2.0 to desktop OpenGL, Direct3D 9, and Direct3D 11. Support for translation from OpenGL ES 3.0 to all of these APIs is nearing completion, and future plans include enabling validated ES-to-ES support.
The goal of ANGLE is to allow users of multiple operating systems to seamlessly run WebGL and other
OpenGL ES content by translating OpenGL ES API calls to one of the hardware-supported APIs available
for that platform. ANGLE currently provides translation from OpenGL ES 2.0 and 3.0 to desktop
OpenGL, OpenGL ES, Direct3D 9, and Direct3D 11. Support for translation from OpenGL ES to Vulkan is
underway, and future plans include compute shader support (ES 3.1) and MacOS support.
| | Direct3D 9 | Direct3D 11 | Desktop GL | GL ES |
|----------------|:-------------:|:-------------------:|:------------------:|:---------:|
| OpenGL ES 2.0 | complete | complete | complete | planned |
| OpenGL ES 3.0 | | nearing completion | nearing completion | planned |
[Level of OpenGL ES support via backing renderers]
### Level of OpenGL ES support via backing renderers
| | Direct3D 9 | Direct3D 11 | Desktop GL | GL ES | Vulkan |
|----------------|:-------------:|:----------------:|:--------------:|:-------------:|:-------------:|
| OpenGL ES 2.0 | complete | complete | complete | complete | in progress |
| OpenGL ES 3.0 | | complete | complete | in progress | not started |
| OpenGL ES 3.1 | | not started | in progress | in progress | not started |
| | Direct3D 9 | Direct3D 11 | Desktop GL |
|------------:|:--------------:|:--------------:|:-------------:|
| Windows | * | * | * |
| Linux | | | * |
| Mac OS X | | | in progress |
[Platform support via backing renderers]
### Platform support via backing renderers
ANGLE v1.0.772 was certified compliant by passing the ES 2.0.3 conformance tests in October 2011. ANGLE also provides an implementation of the EGL 1.4 specification.
| | Direct3D 9 | Direct3D 11 | Desktop GL | GL ES | Vulkan |
|------------:|:--------------:|:--------------:|:-------------:|:-----------:|:-----------:|
| Windows | complete | complete | complete | complete | in progress |
| Linux | | | complete | | planned |
| Mac OS X | | | in progress | | |
| Chrome OS | | | | complete | planned |
| Android | | | | complete | planned |
ANGLE is used as the default WebGL backend for both Google Chrome and Mozilla Firefox on Windows platforms. Chrome uses ANGLE for all graphics rendering on Windows, including the accelerated Canvas2D implementation and the Native Client sandbox environment.
ANGLE v1.0.772 was certified compliant by passing the ES 2.0.3 conformance tests in October 2011.
ANGLE also provides an implementation of the EGL 1.4 specification.
Portions of the ANGLE shader compiler are used as a shader validator and translator by WebGL implementations across multiple platforms. It is used on Mac OS X, Linux, and in mobile variants of the browsers. Having one shader validator helps to ensure that a consistent set of GLSL ES shaders are accepted across browsers and platforms. The shader translator can be used to translate shaders to other shading languages, and to optionally apply shader modifications to work around bugs or quirks in the native graphics drivers. The translator targets Desktop GLSL, Direct3D HLSL, and even ESSL for native GLES2 platforms.
ANGLE is used as the default WebGL backend for both Google Chrome and Mozilla Firefox on Windows
platforms. Chrome uses ANGLE for all graphics rendering on Windows, including the accelerated
Canvas2D implementation and the Native Client sandbox environment.
Portions of the ANGLE shader compiler are used as a shader validator and translator by WebGL
implementations across multiple platforms. It is used on Mac OS X, Linux, and in mobile variants of
the browsers. Having one shader validator helps to ensure that a consistent set of GLSL ES shaders
are accepted across browsers and platforms. The shader translator can be used to translate shaders
to other shading languages, and to optionally apply shader modifications to work around bugs or
quirks in the native graphics drivers. The translator targets Desktop GLSL, Direct3D HLSL, and even
ESSL for native GLES2 platforms.
## Sources

0
gfx/angle/README.mozilla Normal file → Executable file
View File

0
gfx/angle/include/EGL/egl.h Normal file → Executable file
View File

0
gfx/angle/include/EGL/eglext.h Normal file → Executable file
View File

0
gfx/angle/include/EGL/eglplatform.h Normal file → Executable file
View File

0
gfx/angle/include/GLES2/gl2.h Normal file → Executable file
View File

165
gfx/angle/include/GLES2/gl2ext.h Normal file → Executable file
View File

@ -918,6 +918,68 @@ typedef void(GL_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHCHROMIUMPROC)(GLuint pa
GLint reference,
GLuint mask,
GLenum coverMode);
typedef void(GL_APIENTRYP PFNGLCOVERFILLPATHINSTANCEDCHROMIUMPROC)(GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLenum coverMode,
GLenum transformType,
const GLfloat *transformValues);
typedef void(GL_APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDCHROMIUMPROC)(
GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLenum coverMode,
GLenum transformType,
const GLfloat *transformValues);
typedef void(GL_APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDCHROMIUMPROC)(
GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLenum fillMode,
GLuint mask,
GLenum transformType,
const GLfloat *transformValues);
typedef void(GL_APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDCHROMIUMPROC)(
GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLint reference,
GLuint mask,
GLenum transformType,
const GLfloat *transformValues);
typedef void(GL_APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDCHROMIUMPROC)(
GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLenum fillMode,
GLuint mask,
GLenum coverMode,
GLenum transformType,
const GLfloat *transformValues);
typedef void(GL_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDCHROMIUMPROC)(
GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLint reference,
GLuint mask,
GLenum coverMode,
GLenum transformType,
const GLfloat *transformValues);
typedef void(GL_APIENTRY PFNGLBINDFRAGMENTINPUTLOCATIONCHROMIUMPROC)(GLuint program,
GLint location,
const GLchar *name);
typedef void(GL_APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENCHROMIUMPROC)(GLuint program,
GLint location,
GLenum genMode,
GLint components,
const GLfloat *coeffs);
#ifdef GL_GLEXT_PROTOTYPES
GL_APICALL void GL_APIENTRY glMatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat *m);
GL_APICALL void GL_APIENTRY glMatrixLoadIdentityCHROMIUM(GLenum matrixMode);
@ -947,6 +1009,67 @@ GL_APICALL void GL_APIENTRY glStencilThenCoverStrokePathCHROMIUM(GLuint path,
GLint reference,
GLuint mask,
GLenum coverMode);
GL_APICALL void GL_APIENTRY glCoverFillPathInstancedCHROMIUM(GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLenum coverMode,
GLenum transformType,
const GLfloat *transformValues);
GL_APICALL void GL_APIENTRY glCoverStrokePathInstancedCHROMIUM(GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLenum coverMode,
GLenum transformType,
const GLfloat *transformValues);
GL_APICALL void GL_APIENTRY glStencilFillPathInstancedCHROMIUM(GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLenum fillMode,
GLuint mask,
GLenum transformType,
const GLfloat *transformValues);
GL_APICALL void GL_APIENTRY glStencilStrokePathInstancedCHROMIUM(GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLint reference,
GLuint mask,
GLenum transformType,
const GLfloat *transformValues);
GL_APICALL void GL_APIENTRY
glStencilThenCoverFillPathInstancedCHROMIUM(GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLenum fillMode,
GLuint mask,
GLenum coverMode,
GLenum transformType,
const GLfloat *transformValues);
GL_APICALL void GL_APIENTRY
glStencilThenCoverStrokePathInstancedCHROMIUM(GLsizei numPaths,
GLenum pathNameType,
const void *paths,
GLuint pathBase,
GLint reference,
GLuint mask,
GLenum coverMode,
GLenum transformType,
const GLfloat *transformValues);
GL_APICALL void GL_APIENTRY glBindFragmentInputLocationCHROMIUM(GLuint program,
GLint location,
const GLchar *name);
GL_APICALL void GL_APIENTRY glProgramPathFragmentInputGenCHROMIUM(GLuint program,
GLint location,
GLenum genMode,
GLint components,
const GLfloat *coeffs);
#endif
#endif /* GL_CHROMIUM_path_rendering */
@ -1138,6 +1261,48 @@ GL_APICALL void GL_APIENTRY glGetSyncivAPPLE (GLsync sync, GLenum pname, GLsizei
#define GL_ARM_shader_framebuffer_fetch_depth_stencil 1
#endif /* GL_ARM_shader_framebuffer_fetch_depth_stencil */
#ifndef GL_CHROMIUM_copy_texture
#define GL_CHROMIUM_copy_texture 1
typedef void(GL_APIENTRYP PFNGLCOPYTEXTURECHROMIUMPROC)(GLuint sourceId,
GLuint destId,
GLint internalFormat,
GLenum destType,
GLboolean unpackFlipY,
GLboolean unpackPremultiplyAlpha,
GLboolean unpackUnmultiplyAlpha);
typedef void(GL_APIENTRYP PFNGLCOPYSUBTEXTURECHROMIUMPROC)(GLuint sourceId,
GLuint destId,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLboolean unpackFlipY,
GLboolean unpackPremultiplyAlpha,
GLboolean unpackUnmultiplyAlpha);
#ifdef GL_GLEXT_PROTOTYPES
GL_APICALL void GL_APIENTRY glCopyTextureCHROMIUM(GLuint sourceId,
GLuint destId,
GLint internalFormat,
GLenum destType,
GLboolean unpackFlipY,
GLboolean unpackPremultiplyAlpha,
GLboolean unpackUnmultiplyAlpha);
GL_APICALL void GL_APIENTRY glCopySubTextureCHROMIUM(GLuint sourceId,
GLuint destId,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLboolean unpackFlipY,
GLboolean unpackPremultiplyAlpha,
GLboolean unpackUnmultiplyAlpha);
#endif
#endif /* GL_CHROMIUM_copy_texture */
#ifndef GL_CHROMIUM_sync_query
#define GL_CHROMIUM_sync_query 1
#define GL_COMMANDS_COMPLETED_CHROMIUM 0x84F7

0
gfx/angle/include/GLES2/gl2platform.h Normal file → Executable file
View File

0
gfx/angle/include/GLES3/gl3.h Normal file → Executable file
View File

0
gfx/angle/include/GLES3/gl31.h Normal file → Executable file
View File

0
gfx/angle/include/GLES3/gl32.h Normal file → Executable file
View File

0
gfx/angle/include/GLES3/gl3platform.h Normal file → Executable file
View File

304
gfx/angle/include/GLSLANG/ShaderLang.h Normal file → Executable file
View File

@ -27,6 +27,7 @@
#include "KHR/khrplatform.h"
#include <array>
#include <map>
#include <string>
#include <vector>
@ -48,36 +49,39 @@ typedef unsigned int GLenum;
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 146
#define ANGLE_SH_VERSION 155
typedef enum {
SH_GLES2_SPEC = 0x8B40,
SH_WEBGL_SPEC = 0x8B41,
SH_GLES2_SPEC,
SH_WEBGL_SPEC,
SH_GLES3_SPEC = 0x8B86,
SH_WEBGL2_SPEC = 0x8B87,
SH_GLES3_SPEC,
SH_WEBGL2_SPEC,
// The CSS Shaders spec is a subset of the WebGL spec.
//
// In both CSS vertex and fragment shaders, ANGLE:
// (1) Reserves the "css_" prefix.
// (2) Renames the main function to css_main.
// (3) Disables the gl_MaxDrawBuffers built-in.
//
// In CSS fragment shaders, ANGLE:
// (1) Disables the gl_FragColor built-in.
// (2) Disables the gl_FragData built-in.
// (3) Enables the css_MixColor built-in.
// (4) Enables the css_ColorMatrix built-in.
//
// After passing a CSS shader through ANGLE, the browser is expected to append
// a new main function to it.
// This new main function will call the css_main function.
// It may also perform additional operations like varying assignment, texture
// access, and gl_FragColor assignment in order to implement the CSS Shaders
// blend modes.
//
SH_CSS_SHADERS_SPEC = 0x8B42
SH_GLES3_1_SPEC,
SH_WEBGL3_SPEC,
// The CSS Shaders spec is a subset of the WebGL spec.
//
// In both CSS vertex and fragment shaders, ANGLE:
// (1) Reserves the "css_" prefix.
// (2) Renames the main function to css_main.
// (3) Disables the gl_MaxDrawBuffers built-in.
//
// In CSS fragment shaders, ANGLE:
// (1) Disables the gl_FragColor built-in.
// (2) Disables the gl_FragData built-in.
// (3) Enables the css_MixColor built-in.
// (4) Enables the css_ColorMatrix built-in.
//
// After passing a CSS shader through ANGLE, the browser is expected to append
// a new main function to it.
// This new main function will call the css_main function.
// It may also perform additional operations like varying assignment, texture
// access, and gl_FragColor assignment in order to implement the CSS Shaders
// blend modes.
//
SH_CSS_SHADERS_SPEC
} ShShaderSpec;
typedef enum
@ -113,101 +117,120 @@ typedef enum
// Compile options.
typedef enum {
SH_VALIDATE = 0,
SH_VALIDATE_LOOP_INDEXING = 0x0001,
SH_INTERMEDIATE_TREE = 0x0002,
SH_OBJECT_CODE = 0x0004,
SH_VARIABLES = 0x0008,
SH_LINE_DIRECTIVES = 0x0010,
SH_SOURCE_PATH = 0x0020,
SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = 0x0040,
// If a sampler array index happens to be a loop index,
// 1) if its type is integer, unroll the loop.
// 2) if its type is float, fail the shader compile.
// This is to work around a mac driver bug.
SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX = 0x0080,
SH_VALIDATE = 0,
SH_VALIDATE_LOOP_INDEXING = 0x0001,
SH_INTERMEDIATE_TREE = 0x0002,
SH_OBJECT_CODE = 0x0004,
SH_VARIABLES = 0x0008,
SH_LINE_DIRECTIVES = 0x0010,
SH_SOURCE_PATH = 0x0020,
SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = 0x0040,
// If a sampler array index happens to be a loop index,
// 1) if its type is integer, unroll the loop.
// 2) if its type is float, fail the shader compile.
// This is to work around a mac driver bug.
SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX = 0x0080,
// This is needed only as a workaround for certain OpenGL driver bugs.
SH_EMULATE_BUILT_IN_FUNCTIONS = 0x0100,
// This is needed only as a workaround for certain OpenGL driver bugs.
SH_EMULATE_BUILT_IN_FUNCTIONS = 0x0100,
// This is an experimental flag to enforce restrictions that aim to prevent
// timing attacks.
// It generates compilation errors for shaders that could expose sensitive
// texture information via the timing channel.
// To use this flag, you must compile the shader under the WebGL spec
// (using the SH_WEBGL_SPEC flag).
SH_TIMING_RESTRICTIONS = 0x0200,
// This is an experimental flag to enforce restrictions that aim to prevent
// timing attacks.
// It generates compilation errors for shaders that could expose sensitive
// texture information via the timing channel.
// To use this flag, you must compile the shader under the WebGL spec
// (using the SH_WEBGL_SPEC flag).
SH_TIMING_RESTRICTIONS = 0x0200,
// This flag prints the dependency graph that is used to enforce timing
// restrictions on fragment shaders.
// This flag only has an effect if all of the following are true:
// - The shader spec is SH_WEBGL_SPEC.
// - The compile options contain the SH_TIMING_RESTRICTIONS flag.
// - The shader type is GL_FRAGMENT_SHADER.
SH_DEPENDENCY_GRAPH = 0x0400,
// This flag prints the dependency graph that is used to enforce timing
// restrictions on fragment shaders.
// This flag only has an effect if all of the following are true:
// - The shader spec is SH_WEBGL_SPEC.
// - The compile options contain the SH_TIMING_RESTRICTIONS flag.
// - The shader type is GL_FRAGMENT_SHADER.
SH_DEPENDENCY_GRAPH = 0x0400,
// Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
// This flag only enforces (and can only enforce) the packing
// restrictions for uniform variables in both vertex and fragment
// shaders. ShCheckVariablesWithinPackingLimits() lets embedders
// enforce the packing restrictions for varying variables during
// program link time.
SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800,
// Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
// This flag only enforces (and can only enforce) the packing
// restrictions for uniform variables in both vertex and fragment
// shaders. ShCheckVariablesWithinPackingLimits() lets embedders
// enforce the packing restrictions for varying variables during
// program link time.
SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800,
// This flag ensures all indirect (expression-based) array indexing
// is clamped to the bounds of the array. This ensures, for example,
// that you cannot read off the end of a uniform, whether an array
// vec234, or mat234 type. The ShArrayIndexClampingStrategy enum,
// specified in the ShBuiltInResources when constructing the
// compiler, selects the strategy for the clamping implementation.
SH_CLAMP_INDIRECT_ARRAY_BOUNDS = 0x1000,
// This flag ensures all indirect (expression-based) array indexing
// is clamped to the bounds of the array. This ensures, for example,
// that you cannot read off the end of a uniform, whether an array
// vec234, or mat234 type. The ShArrayIndexClampingStrategy enum,
// specified in the ShBuiltInResources when constructing the
// compiler, selects the strategy for the clamping implementation.
SH_CLAMP_INDIRECT_ARRAY_BOUNDS = 0x1000,
// This flag limits the complexity of an expression.
SH_LIMIT_EXPRESSION_COMPLEXITY = 0x2000,
// This flag limits the complexity of an expression.
SH_LIMIT_EXPRESSION_COMPLEXITY = 0x2000,
// This flag limits the depth of the call stack.
SH_LIMIT_CALL_STACK_DEPTH = 0x4000,
// This flag limits the depth of the call stack.
SH_LIMIT_CALL_STACK_DEPTH = 0x4000,
// This flag initializes gl_Position to vec4(0,0,0,0) at the
// beginning of the vertex shader's main(), and has no effect in the
// fragment shader. It is intended as a workaround for drivers which
// incorrectly fail to link programs if gl_Position is not written.
SH_INIT_GL_POSITION = 0x8000,
// This flag initializes gl_Position to vec4(0,0,0,0) at the
// beginning of the vertex shader's main(), and has no effect in the
// fragment shader. It is intended as a workaround for drivers which
// incorrectly fail to link programs if gl_Position is not written.
SH_INIT_GL_POSITION = 0x8000,
// This flag replaces
// "a && b" with "a ? b : false",
// "a || b" with "a ? true : b".
// This is to work around a MacOSX driver bug that |b| is executed
// independent of |a|'s value.
SH_UNFOLD_SHORT_CIRCUIT = 0x10000,
// This flag replaces
// "a && b" with "a ? b : false",
// "a || b" with "a ? true : b".
// This is to work around a MacOSX driver bug that |b| is executed
// independent of |a|'s value.
SH_UNFOLD_SHORT_CIRCUIT = 0x10000,
// This flag initializes varyings without static use in vertex shader
// at the beginning of main(), and has no effects in the fragment shader.
// It is intended as a workaround for drivers which incorrectly optimize
// out such varyings and cause a link failure.
SH_INIT_VARYINGS_WITHOUT_STATIC_USE = 0x20000,
// This flag initializes output variables to 0 at the beginning of main().
// It is to avoid undefined behaviors.
SH_INIT_OUTPUT_VARIABLES = 0x20000,
// TODO(zmo): obsolete, remove after ANGLE roll into Chromium.
SH_INIT_VARYINGS_WITHOUT_STATIC_USE = 0x20000,
// This flag scalarizes vec/ivec/bvec/mat constructor args.
// It is intended as a workaround for Linux/Mac driver bugs.
SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = 0x40000,
// This flag scalarizes vec/ivec/bvec/mat constructor args.
// It is intended as a workaround for Linux/Mac driver bugs.
SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = 0x40000,
// This flag overwrites a struct name with a unique prefix.
// It is intended as a workaround for drivers that do not handle
// struct scopes correctly, including all Mac drivers and Linux AMD.
SH_REGENERATE_STRUCT_NAMES = 0x80000,
// This flag overwrites a struct name with a unique prefix.
// It is intended as a workaround for drivers that do not handle
// struct scopes correctly, including all Mac drivers and Linux AMD.
SH_REGENERATE_STRUCT_NAMES = 0x80000,
// This flag makes the compiler not prune unused function early in the
// compilation process. Pruning coupled with SH_LIMIT_CALL_STACK_DEPTH
// helps avoid bad shaders causing stack overflows.
SH_DONT_PRUNE_UNUSED_FUNCTIONS = 0x100000,
// This flag makes the compiler not prune unused function early in the
// compilation process. Pruning coupled with SH_LIMIT_CALL_STACK_DEPTH
// helps avoid bad shaders causing stack overflows.
SH_DONT_PRUNE_UNUSED_FUNCTIONS = 0x100000,
// This flag works around a bug in NVIDIA 331 series drivers related
// to pow(x, y) where y is a constant vector.
SH_REMOVE_POW_WITH_CONSTANT_EXPONENT = 0x200000,
// This flag works around a bug in NVIDIA 331 series drivers related
// to pow(x, y) where y is a constant vector.
SH_REMOVE_POW_WITH_CONSTANT_EXPONENT = 0x200000,
// This flag works around bugs in Mac drivers related to do-while by
// transforming them into an other construct.
SH_REWRITE_DO_WHILE_LOOPS = 0x400000,
// This flag works around bugs in Mac drivers related to do-while by
// transforming them into an other construct.
SH_REWRITE_DO_WHILE_LOOPS = 0x400000,
// This flag works around a bug in the HLSL compiler optimizer that folds certain
// constant pow expressions incorrectly. Only applies to the HLSL back-end. It works
// by expanding the integer pow expressions into a series of multiplies.
SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS = 0x800000,
// Flatten "#pragma STDGL invariant(all)" into the declarations of
// varying variables and built-in GLSL variables. This compiler
// option is enabled automatically when needed.
SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL = 0x1000000,
// Some drivers do not take into account the base level of the texture in the results of the
// HLSL GetDimensions builtin. This flag instructs the compiler to manually add the base level
// offsetting.
SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL = 0x2000000,
// This flag works around an issue in translating GLSL function texelFetchOffset on
// INTEL drivers. It works by translating texelFetchOffset into texelFetch.
SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH = 0x4000000,
} ShCompileOptions;
// Defines alternate strategies for implementing array index clamping.
@ -310,6 +333,68 @@ typedef struct
// The maximum number of parameters a function can have when SH_LIMIT_EXPRESSION_COMPLEXITY is
// turned on.
int MaxFunctionParameters;
// GLES 3.1 constants
// maximum number of available image units
int MaxImageUnits;
// maximum number of image uniforms in a vertex shader
int MaxVertexImageUniforms;
// maximum number of image uniforms in a fragment shader
int MaxFragmentImageUniforms;
// maximum number of image uniforms in a compute shader
int MaxComputeImageUniforms;
// maximum total number of image uniforms in a program
int MaxCombinedImageUniforms;
// maximum number of ssbos and images in a shader
int MaxCombinedShaderOutputResources;
// maximum number of groups in each dimension
std::array<int, 3> MaxComputeWorkGroupCount;
// maximum number of threads per work group in each dimension
std::array<int, 3> MaxComputeWorkGroupSize;
// maximum number of total uniform components
int MaxComputeUniformComponents;
// maximum number of texture image units in a compute shader
int MaxComputeTextureImageUnits;
// maximum number of atomic counters in a compute shader
int MaxComputeAtomicCounters;
// maximum number of atomic counter buffers in a compute shader
int MaxComputeAtomicCounterBuffers;
// maximum number of atomic counters in a vertex shader
int MaxVertexAtomicCounters;
// maximum number of atomic counters in a fragment shader
int MaxFragmentAtomicCounters;
// maximum number of atomic counters in a program
int MaxCombinedAtomicCounters;
// maximum binding for an atomic counter
int MaxAtomicCounterBindings;
// maximum number of atomic counter buffers in a vertex shader
int MaxVertexAtomicCounterBuffers;
// maximum number of atomic counter buffers in a fragment shader
int MaxFragmentAtomicCounterBuffers;
// maximum number of atomic counter buffers in a program
int MaxCombinedAtomicCounterBuffers;
// maximum number of buffer object storage in machine units
int MaxAtomicCounterBufferSize;
} ShBuiltInResources;
//
@ -425,6 +510,7 @@ COMPILER_EXPORT const std::vector<sh::Varying> *ShGetVaryings(const ShHandle han
COMPILER_EXPORT const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle);
COMPILER_EXPORT const std::vector<sh::OutputVariable> *ShGetOutputVariables(const ShHandle handle);
COMPILER_EXPORT const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle);
COMPILER_EXPORT sh::WorkGroupSize ShGetComputeShaderLocalGroupSize(const ShHandle handle);
typedef struct
{
@ -438,12 +524,10 @@ typedef struct
// flag above.
// Parameters:
// maxVectors: the available rows of registers.
// varInfoArray: an array of variable info (types and sizes).
// varInfoArraySize: the size of the variable array.
// variables: an array of variables.
COMPILER_EXPORT bool ShCheckVariablesWithinPackingLimits(
int maxVectors,
ShVariableInfo *varInfoArray,
size_t varInfoArraySize);
const std::vector<sh::ShaderVariable> &variables);
// Gives the compiler-assigned register for an interface block.
// The method writes the value to the output variable "indexOut".

31
gfx/angle/include/GLSLANG/ShaderVars.h Normal file → Executable file
View File

@ -10,9 +10,9 @@
#ifndef GLSLANG_SHADERVARS_H_
#define GLSLANG_SHADERVARS_H_
#include <algorithm>
#include <string>
#include <vector>
#include <algorithm>
// Assume ShaderLang.h is included before ShaderVars.h, for sh::GLenum
// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
@ -203,6 +203,9 @@ struct COMPILER_EXPORT InterfaceBlock
// Fields from blocks with non-empty instance names are prefixed with the block name.
std::string fieldPrefix() const;
// Decide whether two interface blocks are the same at shader link time.
bool isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const;
std::string name;
std::string mappedName;
std::string instanceName;
@ -213,6 +216,32 @@ struct COMPILER_EXPORT InterfaceBlock
std::vector<InterfaceBlockField> fields;
};
struct COMPILER_EXPORT WorkGroupSize
{
void fill(int fillValue);
void setLocalSize(int localSizeX, int localSizeY, int localSizeZ);
int &operator[](size_t index);
int operator[](size_t index) const;
size_t size() const;
// Checks whether two work group size declarations match.
// Two work group size declarations are the same if the explicitly specified elements are the
// same or if one of them is specified as one and the other one is not specified
bool isWorkGroupSizeMatching(const WorkGroupSize &right) const;
// Checks whether any of the values are set.
bool isAnyValueSet() const;
// Checks whether all of the values are set.
bool isDeclared() const;
// Checks whether either all of the values are set, or none of them are.
bool isLocalSizeValid() const;
int localSizeQualifiers[3];
};
} // namespace sh
#endif // GLSLANG_SHADERVARS_H_

0
gfx/angle/include/KHR/khrplatform.h Normal file → Executable file
View File

0
gfx/angle/include/angle_gl.h Normal file → Executable file
View File

0
gfx/angle/include/angle_windowsstore.h Normal file → Executable file
View File

0
gfx/angle/include/export.h Normal file → Executable file
View File

0
gfx/angle/include/platform/Platform.h Normal file → Executable file
View File

8
gfx/angle/moz.build Normal file → Executable file
View File

@ -28,6 +28,7 @@ UNIFIED_SOURCES += [
'src/compiler/preprocessor/Preprocessor.cpp',
'src/compiler/preprocessor/Token.cpp',
'src/compiler/preprocessor/Tokenizer.cpp',
'src/compiler/translator/AddDefaultReturnStatements.cpp',
'src/compiler/translator/ArrayReturnValueToOutParameter.cpp',
'src/compiler/translator/ASTMetadataHLSL.cpp',
'src/compiler/translator/blocklayout.cpp',
@ -47,6 +48,7 @@ UNIFIED_SOURCES += [
'src/compiler/translator/Diagnostics.cpp',
'src/compiler/translator/DirectiveHandler.cpp',
'src/compiler/translator/EmulatePrecision.cpp',
'src/compiler/translator/ExpandIntegerPowExpressions.cpp',
'src/compiler/translator/ExtensionGLSL.cpp',
'src/compiler/translator/FlagStd140Structs.cpp',
'src/compiler/translator/ForLoopUnroll.cpp',
@ -57,6 +59,7 @@ UNIFIED_SOURCES += [
'src/compiler/translator/InitializeVariables.cpp',
'src/compiler/translator/Intermediate.cpp',
'src/compiler/translator/IntermNode.cpp',
'src/compiler/translator/IntermNodePatternMatcher.cpp',
'src/compiler/translator/intermOut.cpp',
'src/compiler/translator/IntermTraverse.cpp',
'src/compiler/translator/LoopInfo.cpp',
@ -75,6 +78,7 @@ UNIFIED_SOURCES += [
'src/compiler/translator/RemoveSwitchFallThrough.cpp',
'src/compiler/translator/RewriteDoWhile.cpp',
'src/compiler/translator/RewriteElseBlocks.cpp',
'src/compiler/translator/RewriteTexelFetchOffset.cpp',
'src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp',
'src/compiler/translator/SearchSymbol.cpp',
'src/compiler/translator/SeparateArrayInitialization.cpp',
@ -82,6 +86,8 @@ UNIFIED_SOURCES += [
'src/compiler/translator/SeparateExpressionsReturningArrays.cpp',
'src/compiler/translator/ShaderLang.cpp',
'src/compiler/translator/ShaderVars.cpp',
'src/compiler/translator/SimplifyLoopConditions.cpp',
'src/compiler/translator/SplitSequenceOperator.cpp',
'src/compiler/translator/StructureHLSL.cpp',
'src/compiler/translator/SymbolTable.cpp',
'src/compiler/translator/TextureFunctionHLSL.cpp',
@ -107,6 +113,7 @@ UNIFIED_SOURCES += [
'src/third_party/compiler/ArrayBoundsClamper.cpp',
]
SOURCES += [
'src/compiler/translator/EmulateGLFragColorBroadcast.cpp',
'src/compiler/translator/glslang_lex.cpp',
'src/compiler/translator/glslang_tab.cpp',
]
@ -164,7 +171,6 @@ DEFINES['ANGLE_ENABLE_ESSL'] = "1"
DEFINES['ANGLE_ENABLE_KEYEDMUTEX'] = "1"
EXPORTS.angle += [ 'include/GLSLANG/ShaderLang.h', 'include/GLSLANG/ShaderVars.h', 'include/platform/Platform.h' ]
EXPORTS.angle.KHR += [ 'include/KHR/khrplatform.h' ]
LOCAL_INCLUDES += [ 'include', 'src', 'src/common/third_party/numerics' ]

27
gfx/angle/src/angle.gyp Normal file → Executable file
View File

@ -142,6 +142,33 @@
],
},
{
'target_name': 'angle_image_util',
'type': 'static_library',
'includes': [ '../build/common_defines.gypi', ],
'sources':
[
'<@(libangle_image_util_sources)',
],
'include_dirs':
[
'.',
'../include',
],
'dependencies':
[
'angle_common',
],
'direct_dependent_settings':
{
'include_dirs':
[
'<(angle_path)/include',
'<(angle_path)/src',
],
},
},
{
'target_name': 'copy_scripts',
'type': 'none',

0
gfx/angle/src/commit.h Normal file → Executable file
View File

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