From 274d644ee12583195729a4a500d1a97b3b070fa5 Mon Sep 17 00:00:00 2001 From: Michael Layzell Date: Sun, 9 Aug 2015 18:47:20 -0400 Subject: [PATCH 01/49] Bug 1192666 - Emit '[]' around origin strings for ipv6 origins, r=ehsan --- caps/nsPrincipal.cpp | 15 ++++++++++++--- caps/tests/unit/test_origin.js | 6 ++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/caps/nsPrincipal.cpp b/caps/nsPrincipal.cpp index 302e6188cfae..9d562592a36c 100644 --- a/caps/nsPrincipal.cpp +++ b/caps/nsPrincipal.cpp @@ -111,7 +111,7 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin) return NS_ERROR_FAILURE; } - nsAutoCString hostPort; + nsAutoCString host; // chrome: URLs don't have a meaningful origin, so make // sure we just get the full spec for them. @@ -120,10 +120,10 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin) bool isChrome; nsresult rv = origin->SchemeIs("chrome", &isChrome); if (NS_SUCCEEDED(rv) && !isChrome) { - rv = origin->GetAsciiHost(hostPort); + rv = origin->GetAsciiHost(host); // Some implementations return an empty string, treat it as no support // for asciiHost by that implementation. - if (hostPort.IsEmpty()) { + if (host.IsEmpty()) { rv = NS_ERROR_FAILURE; } } @@ -159,6 +159,15 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin) } if (NS_SUCCEEDED(rv) && !isChrome) { + nsAutoCString hostPort; + if (host.FindChar(':') != -1) { + hostPort.Assign("["); + hostPort.Append(host); + hostPort.Append("]"); + } else { + hostPort.Assign(host); + } + if (port != -1) { hostPort.Append(':'); hostPort.AppendInt(port, 10); diff --git a/caps/tests/unit/test_origin.js b/caps/tests/unit/test_origin.js index c0b98d469d62..8ec957428d12 100644 --- a/caps/tests/unit/test_origin.js +++ b/caps/tests/unit/test_origin.js @@ -47,6 +47,12 @@ function run_test() { var nullPrin = Cu.getObjectPrincipal(new Cu.Sandbox(null)); do_check_true(/^moz-nullprincipal:\{([0-9]|[a-z]|\-){36}\}$/.test(nullPrin.origin)); checkOriginAttributes(nullPrin); + var ipv6Prin = ssm.createCodebasePrincipal(makeURI('https://[2001:db8::ff00:42:8329]:123'), {}); + do_check_eq(ipv6Prin.origin, 'https://[2001:db8::ff00:42:8329]:123'); + checkOriginAttributes(ipv6Prin); + var ipv6NPPrin = ssm.createCodebasePrincipal(makeURI('https://[2001:db8::ff00:42:8329]'), {}); + do_check_eq(ipv6NPPrin.origin, 'https://[2001:db8::ff00:42:8329]'); + checkOriginAttributes(ipv6NPPrin); var ep = ssm.createExpandedPrincipal([exampleCom, nullPrin, exampleOrg]); checkOriginAttributes(ep); checkCrossOrigin(exampleCom, exampleOrg); From 7022197117a4ca8a88bc81469ace21286886f1fd Mon Sep 17 00:00:00 2001 From: Michael Layzell Date: Fri, 31 Jul 2015 10:51:45 -0700 Subject: [PATCH 02/49] Bug 1189070 - Don't discard localhost or IP address entries from the permissions database when migrating, r=ehsan --- extensions/cookie/nsPermissionManager.cpp | 265 +++++++++++++++-- .../test_permmanager_load_invalid_entries.js | 2 +- .../test/unit/test_permmanager_migrate_4-7.js | 11 + ...test_permmanager_migrate_4-7_no_history.js | 11 + .../unit/test_permmanager_migrate_5-7a.js | 11 + .../unit/test_permmanager_migrate_5-7b.js | 8 +- .../unit/test_permmanager_migrate_6-7a.js | 11 + .../test/unit/test_permmanager_migrate_7-8.js | 266 ++++++++++++++++++ extensions/cookie/test/unit/xpcshell.ini | 1 + 9 files changed, 553 insertions(+), 33 deletions(-) create mode 100644 extensions/cookie/test/unit/test_permmanager_migrate_7-8.js diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp index 25981936f1d0..cbc106efb63d 100644 --- a/extensions/cookie/nsPermissionManager.cpp +++ b/extensions/cookie/nsPermissionManager.cpp @@ -204,7 +204,7 @@ public: int64_t aModificationTime) = 0; }; -class UpgradeHostToOriginDBMigration final : public UpgradeHostToOriginHelper { +class MOZ_STACK_CLASS UpgradeHostToOriginDBMigration final : public UpgradeHostToOriginHelper { public: UpgradeHostToOriginDBMigration(mozIStorageConnection* aDBConn, int64_t* aID) : mDBConn(aDBConn) , mID(aID) @@ -256,7 +256,7 @@ private: int64_t* mID; }; -class UpgradeHostToOriginHostfileImport final : public UpgradeHostToOriginHelper { +class MOZ_STACK_CLASS UpgradeHostToOriginHostfileImport final : public UpgradeHostToOriginHelper { public: UpgradeHostToOriginHostfileImport(nsPermissionManager* aPm, nsPermissionManager::DBOperationType aOperation, @@ -285,6 +285,93 @@ private: int64_t mID; }; +class MOZ_STACK_CLASS UpgradeIPHostToOriginDB final : public UpgradeHostToOriginHelper { +public: + UpgradeIPHostToOriginDB(mozIStorageConnection* aDBConn, int64_t* aID) : mDBConn(aDBConn) + , mID(aID) + { + mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "INSERT INTO moz_perms" + "(id, origin, type, permission, expireType, expireTime, modificationTime) " + "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"), getter_AddRefs(mStmt)); + + mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "SELECT id FROM moz_perms WHERE origin = ?1 AND type = ?2"), + getter_AddRefs(mLookupStmt)); + } + + nsresult + Insert(const nsACString& aOrigin, const nsAFlatCString& aType, + uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, + int64_t aModificationTime) final + { + // Every time the migration code wants to insert an origin into + // the database we need to check to see if someone has already + // created a permissions entry for that permission. If they have, + // we don't want to insert a duplicate row. + // + // We can afford to do this lookup unconditionally and not perform + // caching, as a origin type pair should only be attempted to be + // inserted once. + + nsresult rv = mLookupStmt->Reset(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mLookupStmt->BindUTF8StringByIndex(0, aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mLookupStmt->BindUTF8StringByIndex(1, aType); + NS_ENSURE_SUCCESS(rv, rv); + + // Check if we already have the row in the database, if we do, then + // we don't want to be inserting it again. + bool moreStmts = false; + if (NS_FAILED(mLookupStmt->ExecuteStep(&moreStmts)) || moreStmts) { + mLookupStmt->Reset(); + NS_WARNING("A permissions entry was going to be re-migrated, " + "but was already found in the permissions database."); + return NS_OK; + } + + // Actually insert the statement into the database. + rv = mStmt->BindInt64ByIndex(0, *mID); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindUTF8StringByIndex(1, aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindUTF8StringByIndex(2, aType); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt32ByIndex(3, aPermission); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt32ByIndex(4, aExpireType); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt64ByIndex(5, aExpireTime); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt64ByIndex(6, aModificationTime); + NS_ENSURE_SUCCESS(rv, rv); + + // Increment the working identifier, as we are about to use this one + (*mID)++; + + rv = mStmt->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } + +private: + nsCOMPtr mStmt; + nsCOMPtr mLookupStmt; + nsCOMPtr mDBConn; + int64_t* mID; +}; + + nsresult UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsAFlatCString& aType, uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, @@ -344,10 +431,12 @@ UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsAFlatCString& aTyp MOZ_ASSERT(tldService); // We should always have a tldService if (tldService) { rv = tldService->GetBaseDomainFromHost(aHost, 0, eTLD1); - NS_ENSURE_SUCCESS(rv, rv); - } else { - // We should never hit this branch, but we produce a fake eTLD1 - // to avoid crashing in a release build in case we hit this branch + } + + if (!tldService || NS_FAILED(rv)) { + // If the lookup on the tldService for the base domain for the host failed, + // that means that we just want to directly use the host as the host name + // for the lookup. eTLD1 = aHost; } @@ -446,32 +535,45 @@ UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsAFlatCString& aTyp // This has a relatively high liklihood of applying the permission to the correct // origin. if (!foundHistory) { - rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + aHost); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr principal; - rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal)); - NS_ENSURE_SUCCESS(rv, rv); + nsAutoCString hostSegment; + nsCOMPtr principal; + nsAutoCString origin; - nsAutoCString origin; - rv = principal->GetOrigin(origin); - NS_ENSURE_SUCCESS(rv, rv); - - aHelper->Insert(origin, aType, aPermission, - aExpireType, aExpireTime, aModificationTime); + // If this is an ipv6 URI, we need to surround it in '[', ']' before trying to + // parse it as a URI. + if (aHost.FindChar(':') != -1) { + hostSegment.Assign("["); + hostSegment.Append(aHost); + hostSegment.Append("]"); + } else { + hostSegment.Assign(aHost); } - rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("https://") + aHost); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr principal; - rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal)); - NS_ENSURE_SUCCESS(rv, rv); - nsAutoCString origin; - rv = principal->GetOrigin(origin); - NS_ENSURE_SUCCESS(rv, rv); + // http:// URI default + rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + hostSegment); + NS_ENSURE_SUCCESS(rv, rv); - aHelper->Insert(origin, aType, aPermission, - aExpireType, aExpireTime, aModificationTime); - } + rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = principal->GetOrigin(origin); + NS_ENSURE_SUCCESS(rv, rv); + + aHelper->Insert(origin, aType, aPermission, + aExpireType, aExpireTime, aModificationTime); + + // https:// URI default + rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("https://") + hostSegment); + NS_ENSURE_SUCCESS(rv, rv); + + rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = principal->GetOrigin(origin); + NS_ENSURE_SUCCESS(rv, rv); + + aHelper->Insert(origin, aType, aPermission, + aExpireType, aExpireTime, aModificationTime); } return NS_OK; @@ -614,7 +716,7 @@ nsPermissionManager::AppClearDataObserverInit() // nsPermissionManager Implementation #define PERMISSIONS_FILE_NAME "permissions.sqlite" -#define HOSTS_SCHEMA_VERSION 7 +#define HOSTS_SCHEMA_VERSION 8 #define HOSTPERM_FILE_NAME "hostperm.1" @@ -1059,8 +1161,8 @@ nsPermissionManager::InitDB(bool aRemoveFile) // and then back up their old database as moz_perms_v6 nsCOMPtr countStmt; - mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT COUNT(*) FROM moz_perms"), - getter_AddRefs(countStmt)); + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT COUNT(*) FROM moz_perms"), + getter_AddRefs(countStmt)); bool hasResult = false; if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(countStmt->ExecuteStep(&hasResult)) && @@ -1139,6 +1241,107 @@ nsPermissionManager::InitDB(bool aRemoveFile) NS_ENSURE_SUCCESS(rv, rv); } + // fall through to the next upgrade + + // The version 7-8 migration is the re-migration of localhost and ip-address + // entries due to errors in the previous version 7 migration which caused + // localhost and ip-address entries to be incorrectly discarded. + // The version 7 migration logic has been corrected, and thus this logic only + // needs to execute if the user is currently on version 7. + case 7: + { + // This migration will be relatively expensive as we need to perform + // database lookups for each origin which we want to insert. Fortunately, + // it shouldn't be too expensive as we only want to insert a small number + // of entries created for localhost or IP addresses. + + // We only want to perform the re-migration if moz_hosts is a backup + bool hostsIsBackupExists = false; + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_is_backup"), + &hostsIsBackupExists); + + // Only perform this migration if the original schema version was 7, and + // the moz_hosts table is a backup. + if (dbSchemaVersion == 7 && hostsIsBackupExists) { + nsCOMPtr tldService = + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); + MOZ_ASSERT(tldService); // We should always have a tldService + + nsCOMPtr stmt; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "SELECT host, type, permission, expireType, expireTime, " + "modificationTime, appId, isInBrowserElement FROM moz_hosts"), + getter_AddRefs(stmt)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr idStmt; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "SELECT MAX(id) FROM moz_hosts"), getter_AddRefs(idStmt)); + int64_t id = 0; + bool hasResult = false; + if (NS_SUCCEEDED(rv) && + NS_SUCCEEDED(idStmt->ExecuteStep(&hasResult)) && + hasResult) { + id = idStmt->AsInt32(0) + 1; + } + + nsAutoCString host, type; + uint32_t permission; + uint32_t expireType; + int64_t expireTime; + int64_t modificationTime; + uint32_t appId; + bool isInBrowserElement; + + while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) { + // Read in the old row + rv = stmt->GetUTF8String(0, host); + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + + nsAutoCString eTLD1; + rv = tldService->GetBaseDomainFromHost(host, 0, eTLD1); + if (NS_SUCCEEDED(rv)) { + // We only care about entries which the tldService can't handle + continue; + } + + rv = stmt->GetUTF8String(1, type); + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + permission = stmt->AsInt32(2); + expireType = stmt->AsInt32(3); + expireTime = stmt->AsInt64(4); + modificationTime = stmt->AsInt64(5); + if (NS_WARN_IF(stmt->AsInt64(6) < 0)) { + continue; + } + appId = static_cast(stmt->AsInt64(6)); + isInBrowserElement = static_cast(stmt->AsInt32(7)); + + // Perform the meat of the migration by deferring to the + // UpgradeHostToOriginAndInsert function. + UpgradeIPHostToOriginDB upHelper(mDBConn, &id); + rv = UpgradeHostToOriginAndInsert(host, type, permission, + expireType, expireTime, + modificationTime, appId, + isInBrowserElement, + &upHelper); + if (NS_FAILED(rv)) { + NS_WARNING("Unexpected failure when upgrading migrating permission " + "from host to origin"); + } + } + } + + // Even if we didn't perform the migration, we want to bump the schema + // version to 8. + rv = mDBConn->SetSchemaVersion(8); + NS_ENSURE_SUCCESS(rv, rv); + } + // current version. case HOSTS_SCHEMA_VERSION: break; diff --git a/extensions/cookie/test/unit/test_permmanager_load_invalid_entries.js b/extensions/cookie/test/unit/test_permmanager_load_invalid_entries.js index d91cec6ce422..1dd3682010bc 100644 --- a/extensions/cookie/test/unit/test_permmanager_load_invalid_entries.js +++ b/extensions/cookie/test/unit/test_permmanager_load_invalid_entries.js @@ -121,7 +121,7 @@ function run_test() { // The schema should be upgraded to 6, and a 'modificationTime' column should // exist with all records having a value of 0. - do_check_eq(connection.schemaVersion, 7); + do_check_eq(connection.schemaVersion, 8); let select = connection.createStatement("SELECT modificationTime FROM moz_perms") let numMigrated = 0; diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_4-7.js b/extensions/cookie/test/unit/test_permmanager_migrate_4-7.js index c7bec00663a9..f8040e7429fe 100644 --- a/extensions/cookie/test/unit/test_permmanager_migrate_4-7.js +++ b/extensions/cookie/test/unit/test_permmanager_migrate_4-7.js @@ -85,6 +85,9 @@ add_task(function test() { insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false), @@ -139,6 +142,14 @@ add_task(function test() { // following entries ["ftp://sub.foo.com:8000", "B", 1, 0, 0], ["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + ["https://192.0.2.235", "A", 1, 0, 0], ]; let found = expected.map((it) => 0); diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js b/extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js index e849fc1b3458..4a82be67a8b3 100644 --- a/extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js +++ b/extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js @@ -122,6 +122,9 @@ add_task(function test() { insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("263.123.555.676", "A", 1, 0, 0, 0, 0, false), insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false), @@ -160,6 +163,14 @@ add_task(function test() { ["https://bar.ca^appId=1000&inBrowser=1", "A", 1, 0, 0], ["file:///some/path/to/file.html", "A", 1, 0, 0], ["file:///another/file.html", "A", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://263.123.555.676", "A", 1, 0, 0], + ["https://263.123.555.676", "A", 1, 0, 0], ]; let found = expected.map((it) => 0); diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_5-7a.js b/extensions/cookie/test/unit/test_permmanager_migrate_5-7a.js index 751dac11fe35..590b781723ff 100644 --- a/extensions/cookie/test/unit/test_permmanager_migrate_5-7a.js +++ b/extensions/cookie/test/unit/test_permmanager_migrate_5-7a.js @@ -139,6 +139,9 @@ add_task(function test() { insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false), @@ -193,6 +196,14 @@ add_task(function test() { // following entries ["ftp://sub.foo.com:8000", "B", 1, 0, 0], ["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + ["https://192.0.2.235", "A", 1, 0, 0], ]; let found = expected.map((it) => 0); diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_5-7b.js b/extensions/cookie/test/unit/test_permmanager_migrate_5-7b.js index 74c8e9c072e8..43df63eea4b9 100644 --- a/extensions/cookie/test/unit/test_permmanager_migrate_5-7b.js +++ b/extensions/cookie/test/unit/test_permmanager_migrate_5-7b.js @@ -75,6 +75,9 @@ add_task(function test() { insertOrigin("https://foo.com", "A", 2, 0, 0, 0), insertOrigin("http://foo.com", "A", 2, 0, 0, 0), insertOrigin("http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0), + + insertOrigin("http://127.0.0.1", "B", 2, 0, 0, 0), + insertOrigin("http://localhost", "B", 2, 0, 0, 0), ]; let created4 = []; // Didn't create any v4 entries, so the DB should be empty @@ -88,7 +91,10 @@ add_task(function test() { let expected = [ ["https://foo.com", "A", 2, 0, 0, 0], ["http://foo.com", "A", 2, 0, 0, 0], - ["http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0] + ["http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0], + + ["http://127.0.0.1", "B", 2, 0, 0, 0], + ["http://localhost", "B", 2, 0, 0, 0], ]; let found = expected.map((it) => 0); diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_6-7a.js b/extensions/cookie/test/unit/test_permmanager_migrate_6-7a.js index 095653a34388..8bd7ca7d03a4 100644 --- a/extensions/cookie/test/unit/test_permmanager_migrate_6-7a.js +++ b/extensions/cookie/test/unit/test_permmanager_migrate_6-7a.js @@ -139,6 +139,9 @@ add_task(function test() { insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false), @@ -193,6 +196,14 @@ add_task(function test() { // following entries ["ftp://sub.foo.com:8000", "B", 1, 0, 0], ["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + ["https://192.0.2.235", "A", 1, 0, 0], ]; let found = expected.map((it) => 0); diff --git a/extensions/cookie/test/unit/test_permmanager_migrate_7-8.js b/extensions/cookie/test/unit/test_permmanager_migrate_7-8.js new file mode 100644 index 000000000000..a70c020d725f --- /dev/null +++ b/extensions/cookie/test/unit/test_permmanager_migrate_7-8.js @@ -0,0 +1,266 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", + "resource://testing-common/PlacesTestUtils.jsm"); + +let PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) +{ + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +function run_test() { + run_next_test(); +} + +add_task(function test() { + /* Create and set up the permissions database */ + let profile = do_get_profile(); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 7; + + /* + * V5 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_perms (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")"); + + let stmt6Insert = db.createStatement( + "INSERT INTO moz_perms (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")"); + + /* + * V4 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")"); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")"); + + /* + * The v4 table is a backup + */ + db.executeSimpleSQL("CREATE TABLE moz_hosts_is_backup (dummy INTEGER PRIMARY KEY)"); + + let id = 0; + + function insertOrigin(origin, type, permission, expireType, expireTime, modificationTime) { + let thisId = id++; + + stmt6Insert.bindByName("id", thisId); + stmt6Insert.bindByName("origin", origin); + stmt6Insert.bindByName("type", type); + stmt6Insert.bindByName("permission", permission); + stmt6Insert.bindByName("expireType", expireType); + stmt6Insert.bindByName("expireTime", expireTime); + stmt6Insert.bindByName("modificationTime", modificationTime); + + stmt6Insert.execute(); + + return { + id: thisId, + origin: origin, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime + }; + } + + function insertHost(host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + stmtInsert.execute(); + + return { + id: thisId, + host: host, + type: type, + permission: permission, + expireType: expireType, + expireTime: expireTime, + modificationTime: modificationTime, + appId: appId, + isInBrowserElement: isInBrowserElement + }; + } + + let created7 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0), + insertOrigin("https://192.0.2.235", "A", 2, 0, 0), + ]; + + // Add some rows to the database + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true), + insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), + insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), + // Although ipv6 addresses are written with [] around the IP address, + // the .host property doesn't contain these []s, which means that we + // write it like this + insertHost("2001:db8::ff00:42:8329", "C", 1, 0, 0, 0, 0, false), + insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", "A", 1, 0, 0, 0, 0, false), + insertHost("moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", "B", 1, 0, 0, 0, 0, false), + insertHost("", "A", 1, 0, 0, 0, 0, false), + insertHost("", "B", 1, 0, 0, 0, 0, false), + ]; + + // CLose the db connection + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + // We should have kept the previously migrated entries + ["https://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["https://localhost:8080", "A", 1, 0, 0], + ["ftp://127.0.0.1:8080", "A", 1, 0, 0], + + ["http://[2001:db8::ff00:42:8329]", "C", 1, 0, 0], + ["https://[2001:db8::ff00:42:8329]", "C", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + + // There should only be one entry of this type in the database + ["https://192.0.2.235", "A", 2, 0, 0], + ]; + + let found = expected.map((it) => 0); + + // Add some places to the places database + yield PlacesTestUtils.addVisits(Services.io.newURI("https://foo.com/some/other/subdirectory", null, null)); + yield PlacesTestUtils.addVisits(Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory", null, null)); + yield PlacesTestUtils.addVisits(Services.io.newURI("ftp://127.0.0.1:8080", null, null)); + yield PlacesTestUtils.addVisits(Services.io.newURI("https://localhost:8080", null, null)); + + // Force initialization of the nsPermissionManager + let enumerator = Services.perms.enumerator; + while (enumerator.hasMoreElements()) { + let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); + let isExpected = false; + + expected.forEach((it, i) => { + if (permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4]) { + isExpected = true; + found[i]++; + } + }); + + do_check_true(isExpected, + "Permission " + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + ", " + + permission.type + ", " + + permission.capability + ", " + + permission.expireType + ", " + + permission.expireTime); + } + + found.forEach((count, i) => { + do_check_true(count == 1, "Expected count = 1, got count = " + count + " for permission " + expected[i]); + }); + + // Check to make sure that all of the tables which we care about are present + { + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + do_check_true(db.tableExists("moz_perms")); + do_check_true(db.tableExists("moz_hosts")); + do_check_true(db.tableExists("moz_hosts_is_backup")); + do_check_false(db.tableExists("moz_perms_v6")); + + let mozHostsStmt = db.createStatement("SELECT " + + "host, type, permission, expireType, expireTime, " + + "modificationTime, appId, isInBrowserElement " + + "FROM moz_hosts WHERE id = :id"); + + // Check that the moz_hosts table still contains the correct values. + created.forEach((it) => { + mozHostsStmt.reset(); + mozHostsStmt.bindByName("id", it.id); + mozHostsStmt.executeStep(); + do_check_eq(mozHostsStmt.getUTF8String(0), it.host); + do_check_eq(mozHostsStmt.getUTF8String(1), it.type); + do_check_eq(mozHostsStmt.getInt64(2), it.permission); + do_check_eq(mozHostsStmt.getInt64(3), it.expireType); + do_check_eq(mozHostsStmt.getInt64(4), it.expireTime); + do_check_eq(mozHostsStmt.getInt64(5), it.modificationTime); + do_check_eq(mozHostsStmt.getInt64(6), it.appId); + do_check_eq(mozHostsStmt.getInt64(7), it.isInBrowserElement); + }); + + // Check that there are the right number of values + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + mozHostsCount.executeStep(); + do_check_eq(mozHostsCount.getInt64(0), created.length); + + // Check that there are the right number of values in the permissions database + let mozPermsCount = db.createStatement("SELECT count(*) FROM moz_perms"); + mozPermsCount.executeStep(); + do_check_eq(mozPermsCount.getInt64(0), expected.length); + + db.close(); + } +}); diff --git a/extensions/cookie/test/unit/xpcshell.ini b/extensions/cookie/test/unit/xpcshell.ini index e3990cb1548e..3ba80e5309f6 100644 --- a/extensions/cookie/test/unit/xpcshell.ini +++ b/extensions/cookie/test/unit/xpcshell.ini @@ -43,3 +43,4 @@ skip-if = debug == true [test_permmanager_migrate_6-7a.js] [test_permmanager_migrate_6-7b.js] [test_permmanager_migrate_4-7_no_history.js] +[test_permmanager_migrate_7-8.js] From ec3cfdec9c51db4783a0db90c5e9b7e5df9907d0 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Mon, 10 Aug 2015 12:16:30 -0400 Subject: [PATCH 03/49] Bug 1191298 - don't fail on unknown audio constraints e.g. getUserMedia({ audio: {} }) (regression) r=jesup --- dom/media/MediaManager.cpp | 57 +++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index d88fe5d1cce7..84e51e1d1942 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -1690,11 +1690,11 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, } if (vc.mAdvanced.WasPassed() && videoType != dom::MediaSourceEnum::Camera) { - // iterate through advanced, forcing mediaSource to match "root" - const char *camera = EnumToASCII(dom::MediaSourceEnumValues::strings, - dom::MediaSourceEnum::Camera); + // iterate through advanced, forcing all unset mediaSources to match "root" + const char *unset = EnumToASCII(dom::MediaSourceEnumValues::strings, + dom::MediaSourceEnum::Camera); for (MediaTrackConstraintSet& cs : vc.mAdvanced.Value()) { - if (cs.mMediaSource.EqualsASCII(camera)) { + if (cs.mMediaSource.EqualsASCII(unset)) { cs.mMediaSource = vc.mMediaSource; } } @@ -1729,15 +1729,46 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, audioType = StringToEnum(dom::MediaSourceEnumValues::strings, ac.mMediaSource, audioType); - // Only enable AudioCapture if the pref is enabled. If it's not, we can deny - // right away. - if (audioType == dom::MediaSourceEnum::AudioCapture && - !Preferences::GetBool("media.getusermedia.audiocapture.enabled")) { - nsRefPtr error = - new MediaStreamError(aWindow, - NS_LITERAL_STRING("PermissionDeniedError")); - onFailure->OnError(error); - return NS_OK; + // Work around WebIDL default since spec uses same dictionary w/audio & video. + if (audioType == dom::MediaSourceEnum::Camera) { + audioType = dom::MediaSourceEnum::Microphone; + ac.mMediaSource.AssignASCII(EnumToASCII(dom::MediaSourceEnumValues::strings, + audioType)); + } + + switch (audioType) { + case dom::MediaSourceEnum::Microphone: + break; + + case dom::MediaSourceEnum::AudioCapture: + // Only enable AudioCapture if the pref is enabled. If it's not, we can + // deny right away. + if (!Preferences::GetBool("media.getusermedia.audiocapture.enabled")) { + nsRefPtr error = + new MediaStreamError(aWindow, + NS_LITERAL_STRING("PermissionDeniedError")); + onFailure->OnError(error); + return NS_OK; + } + break; + + case dom::MediaSourceEnum::Other: + default: { + nsRefPtr error = + new MediaStreamError(aWindow, NS_LITERAL_STRING("NotFoundError")); + onFailure->OnError(error); + return NS_OK; + } + } + if (ac.mAdvanced.WasPassed()) { + // iterate through advanced, forcing all unset mediaSources to match "root" + const char *unset = EnumToASCII(dom::MediaSourceEnumValues::strings, + dom::MediaSourceEnum::Camera); + for (MediaTrackConstraintSet& cs : ac.mAdvanced.Value()) { + if (cs.mMediaSource.EqualsASCII(unset)) { + cs.mMediaSource = ac.mMediaSource; + } + } } } StreamListeners* listeners = AddWindowID(windowID); From 7edae5b34837f6d26d8ca1638e02c1e10aef707f Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Tue, 11 Aug 2015 15:15:06 -0400 Subject: [PATCH 04/49] Bug 1188376: Split Hello Telemetry values from general WebRTC r=jib --- .../src/peerconnection/PeerConnectionCtx.cpp | 46 +++- .../src/peerconnection/PeerConnectionImpl.cpp | 23 +- .../src/peerconnection/PeerConnectionImpl.h | 4 + .../WebrtcGlobalInformation.cpp | 50 +++-- toolkit/components/telemetry/Histograms.json | 198 ++++++++++++++++++ 5 files changed, 289 insertions(+), 32 deletions(-) diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp index cf6f8abe6d7e..f9f6b97d1f38 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp @@ -205,6 +205,7 @@ EverySecondTelemetryCallback_s(nsAutoPtr aQueryList) { for (auto q = aQueryList->begin(); q != aQueryList->end(); ++q) { PeerConnectionImpl::ExecuteStatsQuery_s(*q); auto& r = *(*q)->report; + bool isHello = (*q)->isHello; if (r.mInboundRTPStreamStats.WasPassed()) { // First, get reports from a second ago, if any, for calculations below const Sequence *lastInboundStats = nullptr; @@ -237,9 +238,15 @@ EverySecondTelemetryCallback_s(nsAutoPtr aQueryList) { } if (s.mMozRtt.WasPassed()) { MOZ_ASSERT(s.mIsRemote); - Accumulate(isAudio? WEBRTC_AUDIO_QUALITY_OUTBOUND_RTT : - WEBRTC_VIDEO_QUALITY_OUTBOUND_RTT, - s.mMozRtt.Value()); + ID id; + if (isAudio) { + id = isHello ? LOOP_AUDIO_QUALITY_OUTBOUND_RTT : + WEBRTC_AUDIO_QUALITY_OUTBOUND_RTT; + } else { + id = isHello ? LOOP_VIDEO_QUALITY_OUTBOUND_RTT : + WEBRTC_VIDEO_QUALITY_OUTBOUND_RTT; + } + Accumulate(id, s.mMozRtt.Value()); } if (lastInboundStats && s.mBytesReceived.WasPassed()) { auto& laststats = *lastInboundStats; @@ -249,15 +256,32 @@ EverySecondTelemetryCallback_s(nsAutoPtr aQueryList) { if (lasts.mBytesReceived.WasPassed()) { auto delta_ms = int32_t(s.mTimestamp.Value() - lasts.mTimestamp.Value()); - if (delta_ms > 0 && delta_ms < 60000) { - Accumulate(s.mIsRemote? - (isAudio? WEBRTC_AUDIO_QUALITY_OUTBOUND_BANDWIDTH_KBITS : - WEBRTC_VIDEO_QUALITY_OUTBOUND_BANDWIDTH_KBITS) : - (isAudio? WEBRTC_AUDIO_QUALITY_INBOUND_BANDWIDTH_KBITS : - WEBRTC_VIDEO_QUALITY_INBOUND_BANDWIDTH_KBITS), - ((s.mBytesReceived.Value() - - lasts.mBytesReceived.Value()) * 8) / delta_ms); + // In theory we're called every second, so delta *should* be in that range. + // Small deltas could cause errors due to division + if (delta_ms > 500 && delta_ms < 60000) { + ID id; + if (s.mIsRemote) { + if (isAudio) { + id = isHello ? LOOP_AUDIO_QUALITY_OUTBOUND_BANDWIDTH_KBITS : + WEBRTC_AUDIO_QUALITY_OUTBOUND_BANDWIDTH_KBITS; + } else { + id = isHello ? LOOP_VIDEO_QUALITY_OUTBOUND_BANDWIDTH_KBITS : + WEBRTC_VIDEO_QUALITY_OUTBOUND_BANDWIDTH_KBITS; + } + } else { + if (isAudio) { + id = isHello ? LOOP_AUDIO_QUALITY_INBOUND_BANDWIDTH_KBITS : + WEBRTC_AUDIO_QUALITY_INBOUND_BANDWIDTH_KBITS; + } else { + id = isHello ? LOOP_VIDEO_QUALITY_INBOUND_BANDWIDTH_KBITS : + WEBRTC_VIDEO_QUALITY_INBOUND_BANDWIDTH_KBITS; + } + } + Accumulate(id, ((s.mBytesReceived.Value() - + lasts.mBytesReceived.Value()) * 8) / delta_ms); } + // We could accumulate values until enough time has passed + // and then Accumulate() but this isn't that important. } } } diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index dbcfa0d38418..a4dcec661b20 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -380,6 +380,7 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal) , mIdentity(nullptr) #endif , mPrivacyRequested(false) + , mIsLoop(false) , mSTSThread(nullptr) , mAllowIceLoopback(false) , mAllowIceLinkLocal(false) @@ -693,6 +694,12 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver, location->Release(); CopyUTF16toUTF8(locationAStr, locationCStr); +#define HELLO_CLICKER_URL_START "https://hello.firefox.com/" +#define HELLO_INITIATOR_URL_START "about:loop" + mIsLoop = (strncmp(HELLO_CLICKER_URL_START, locationCStr.get(), + strlen(HELLO_CLICKER_URL_START)) == 0) || + (strncmp(HELLO_INITIATOR_URL_START, locationCStr.get(), + strlen(HELLO_INITIATOR_URL_START)) == 0); } PR_snprintf( @@ -2482,7 +2489,9 @@ PeerConnectionImpl::ShutdownMedia() // End of call to be recorded in Telemetry if (!mStartTime.IsNull()){ TimeDuration timeDelta = TimeStamp::Now() - mStartTime; - Telemetry::Accumulate(Telemetry::WEBRTC_CALL_DURATION, timeDelta.ToSeconds()); + Telemetry::Accumulate(mIsLoop ? Telemetry::LOOP_CALL_DURATION : + Telemetry::WEBRTC_CALL_DURATION, + timeDelta.ToSeconds()); } #endif @@ -2764,10 +2773,12 @@ void PeerConnectionImpl::IceConnectionStateChange( if (!mIceStartTime.IsNull()){ TimeDuration timeDelta = TimeStamp::Now() - mIceStartTime; if (isSucceeded(domState)) { - Telemetry::Accumulate(Telemetry::WEBRTC_ICE_SUCCESS_TIME, + Telemetry::Accumulate(mIsLoop ? Telemetry::LOOP_ICE_SUCCESS_TIME : + Telemetry::WEBRTC_ICE_SUCCESS_TIME, timeDelta.ToMilliseconds()); } else if (isFailed(domState)) { - Telemetry::Accumulate(Telemetry::WEBRTC_ICE_FAILURE_TIME, + Telemetry::Accumulate(mIsLoop ? Telemetry::LOOP_ICE_FAILURE_TIME : + Telemetry::WEBRTC_ICE_FAILURE_TIME, timeDelta.ToMilliseconds()); } } @@ -2927,6 +2938,7 @@ PeerConnectionImpl::BuildStatsQuery_m( query->iceStartTime = mIceStartTime; query->failed = isFailed(mIceConnectionState); + query->isHello = mIsLoop; // Populate SDP on main if (query->internalStats) { @@ -3385,8 +3397,11 @@ PeerConnectionImpl::startCallTelem() { mStartTime = TimeStamp::Now(); // Increment session call counter + // If we want to track Loop calls independently here, we need two mConnectionCounters int &cnt = PeerConnectionCtx::GetInstance()->mConnectionCounter; - Telemetry::GetHistogramById(Telemetry::WEBRTC_CALL_COUNT)->Subtract(cnt); + if (cnt > 0) { + Telemetry::GetHistogramById(Telemetry::WEBRTC_CALL_COUNT)->Subtract(cnt); + } cnt++; Telemetry::GetHistogramById(Telemetry::WEBRTC_CALL_COUNT)->Add(cnt); } diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h index e04f6c7bc492..bcd503349dca 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h @@ -214,6 +214,7 @@ class RTCStatsQuery { std::string error; // A timestamp to help with telemetry. mozilla::TimeStamp iceStartTime; + bool isHello; // Just for convenience, maybe integrate into the report later bool failed; @@ -476,6 +477,8 @@ public: } #endif + bool IsLoop() const { return mIsLoop; } + // this method checks to see if we've made a promise to protect media. bool PrivacyRequested() const { return mPrivacyRequested; } @@ -743,6 +746,7 @@ private: // A name for this PC that we are willing to expose to content. std::string mName; + bool mIsLoop; // For telemetry; doesn't have to be 100% right // The target to run stuff on nsCOMPtr mSTSThread; diff --git a/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp b/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp index 28e365761655..33486b36ce6c 100644 --- a/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp +++ b/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp @@ -825,7 +825,8 @@ struct StreamResult { static void StoreLongTermICEStatisticsImpl_m( nsresult result, - nsAutoPtr query) { + nsAutoPtr query, + bool aIsLoop) { using namespace Telemetry; @@ -925,10 +926,12 @@ static void StoreLongTermICEStatisticsImpl_m( for (auto i = streamResults.begin(); i != streamResults.end(); ++i) { if (i->second.streamSucceeded) { - Telemetry::Accumulate(Telemetry::WEBRTC_CANDIDATE_TYPES_GIVEN_SUCCESS, + Telemetry::Accumulate(aIsLoop ? Telemetry::LOOP_CANDIDATE_TYPES_GIVEN_SUCCESS : + Telemetry::WEBRTC_CANDIDATE_TYPES_GIVEN_SUCCESS, i->second.candidateTypeBitpattern); } else { - Telemetry::Accumulate(Telemetry::WEBRTC_CANDIDATE_TYPES_GIVEN_FAILURE, + Telemetry::Accumulate(aIsLoop ? Telemetry::LOOP_CANDIDATE_TYPES_GIVEN_FAILURE : + Telemetry::WEBRTC_CANDIDATE_TYPES_GIVEN_FAILURE, i->second.candidateTypeBitpattern); } } @@ -944,25 +947,30 @@ static void StoreLongTermICEStatisticsImpl_m( continue; } if (s.mBitrateMean.WasPassed()) { - Accumulate(WEBRTC_VIDEO_ENCODER_BITRATE_AVG_PER_CALL_KBPS, + Accumulate(aIsLoop ? LOOP_VIDEO_ENCODER_BITRATE_AVG_PER_CALL_KBPS : + WEBRTC_VIDEO_ENCODER_BITRATE_AVG_PER_CALL_KBPS, uint32_t(s.mBitrateMean.Value() / 1000)); } if (s.mBitrateStdDev.WasPassed()) { - Accumulate(WEBRTC_VIDEO_ENCODER_BITRATE_STD_DEV_PER_CALL_KBPS, + Accumulate(aIsLoop? LOOP_VIDEO_ENCODER_BITRATE_STD_DEV_PER_CALL_KBPS : + WEBRTC_VIDEO_ENCODER_BITRATE_STD_DEV_PER_CALL_KBPS, uint32_t(s.mBitrateStdDev.Value() / 1000)); } if (s.mFramerateMean.WasPassed()) { - Accumulate(WEBRTC_VIDEO_ENCODER_FRAMERATE_AVG_PER_CALL, + Accumulate(aIsLoop ? LOOP_VIDEO_ENCODER_FRAMERATE_AVG_PER_CALL : + WEBRTC_VIDEO_ENCODER_FRAMERATE_AVG_PER_CALL, uint32_t(s.mFramerateMean.Value())); } if (s.mFramerateStdDev.WasPassed()) { - Accumulate(WEBRTC_VIDEO_ENCODER_FRAMERATE_10X_STD_DEV_PER_CALL, + Accumulate(aIsLoop ? LOOP_VIDEO_ENCODER_FRAMERATE_10X_STD_DEV_PER_CALL : + WEBRTC_VIDEO_ENCODER_FRAMERATE_10X_STD_DEV_PER_CALL, uint32_t(s.mFramerateStdDev.Value() * 10)); } if (s.mDroppedFrames.WasPassed() && !query->iceStartTime.IsNull()) { double mins = (TimeStamp::Now() - query->iceStartTime).ToSeconds() / 60; if (mins > 0) { - Accumulate(WEBRTC_VIDEO_ENCODER_DROPPED_FRAMES_PER_CALL_FPM, + Accumulate(aIsLoop ? LOOP_VIDEO_ENCODER_DROPPED_FRAMES_PER_CALL_FPM : + WEBRTC_VIDEO_ENCODER_DROPPED_FRAMES_PER_CALL_FPM, uint32_t(double(s.mDroppedFrames.Value()) / mins)); } } @@ -978,25 +986,30 @@ static void StoreLongTermICEStatisticsImpl_m( continue; } if (s.mBitrateMean.WasPassed()) { - Accumulate(WEBRTC_VIDEO_DECODER_BITRATE_AVG_PER_CALL_KBPS, + Accumulate(aIsLoop ? LOOP_VIDEO_DECODER_BITRATE_AVG_PER_CALL_KBPS : + WEBRTC_VIDEO_DECODER_BITRATE_AVG_PER_CALL_KBPS, uint32_t(s.mBitrateMean.Value() / 1000)); } if (s.mBitrateStdDev.WasPassed()) { - Accumulate(WEBRTC_VIDEO_DECODER_BITRATE_STD_DEV_PER_CALL_KBPS, + Accumulate(aIsLoop ? LOOP_VIDEO_DECODER_BITRATE_STD_DEV_PER_CALL_KBPS : + WEBRTC_VIDEO_DECODER_BITRATE_STD_DEV_PER_CALL_KBPS, uint32_t(s.mBitrateStdDev.Value() / 1000)); } if (s.mFramerateMean.WasPassed()) { - Accumulate(WEBRTC_VIDEO_DECODER_FRAMERATE_AVG_PER_CALL, + Accumulate(aIsLoop ? LOOP_VIDEO_DECODER_FRAMERATE_AVG_PER_CALL : + WEBRTC_VIDEO_DECODER_FRAMERATE_AVG_PER_CALL, uint32_t(s.mFramerateMean.Value())); } if (s.mFramerateStdDev.WasPassed()) { - Accumulate(WEBRTC_VIDEO_DECODER_FRAMERATE_10X_STD_DEV_PER_CALL, + Accumulate(aIsLoop ? LOOP_VIDEO_DECODER_FRAMERATE_10X_STD_DEV_PER_CALL : + WEBRTC_VIDEO_DECODER_FRAMERATE_10X_STD_DEV_PER_CALL, uint32_t(s.mFramerateStdDev.Value() * 10)); } if (s.mDiscardedPackets.WasPassed() && !query->iceStartTime.IsNull()) { double mins = (TimeStamp::Now() - query->iceStartTime).ToSeconds() / 60; if (mins > 0) { - Accumulate(WEBRTC_VIDEO_DECODER_DISCARDED_PACKETS_PER_CALL_PPM, + Accumulate(aIsLoop ? LOOP_VIDEO_DECODER_DISCARDED_PACKETS_PER_CALL_PPM : + WEBRTC_VIDEO_DECODER_DISCARDED_PACKETS_PER_CALL_PPM, uint32_t(double(s.mDiscardedPackets.Value()) / mins)); } } @@ -1012,7 +1025,8 @@ static void StoreLongTermICEStatisticsImpl_m( } static void GetStatsForLongTermStorage_s( - nsAutoPtr query) { + nsAutoPtr query, + bool aIsLoop) { MOZ_ASSERT(query); @@ -1048,13 +1062,15 @@ static void GetStatsForLongTermStorage_s( WrapRunnableNM( &StoreLongTermICEStatisticsImpl_m, rv, - query), + query, + aIsLoop), NS_DISPATCH_NORMAL); } void WebrtcGlobalInformation::StoreLongTermICEStatistics( PeerConnectionImpl& aPc) { - Telemetry::Accumulate(Telemetry::WEBRTC_ICE_FINAL_CONNECTION_STATE, + Telemetry::Accumulate(aPc.IsLoop() ? Telemetry::LOOP_ICE_FINAL_CONNECTION_STATE : + Telemetry::WEBRTC_ICE_FINAL_CONNECTION_STATE, static_cast(aPc.IceConnectionState())); if (aPc.IceConnectionState() == PCImplIceConnectionState::New) { @@ -1071,7 +1087,7 @@ void WebrtcGlobalInformation::StoreLongTermICEStatistics( RUN_ON_THREAD(aPc.GetSTSThread(), WrapRunnableNM(&GetStatsForLongTermStorage_s, - query), + query, aPc.IsLoop()), NS_DISPATCH_NORMAL); } diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 1b9dbf2c2267..3e0970584b5b 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -8671,5 +8671,203 @@ "expires_in_version": "44", "kind": "boolean", "description": "Was there an error while performing the v7 permissions DB migration?" + }, + "LOOP_ICE_FINAL_CONNECTION_STATE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 7, + "description": "The ICE connection state when the PC was closed" + }, + "LOOP_ICE_SUCCESS_TIME": { + "expires_in_version": "never", + "kind": "exponential", + "high": "10000", + "n_buckets": "20", + "description": "The length of time (in milliseconds) it took for ICE to complete, given that ICE succeeded." + }, + "LOOP_ICE_FAILURE_TIME": { + "expires_in_version": "never", + "kind": "exponential", + "high": "10000", + "n_buckets": "20", + "description": "The length of time (in milliseconds) it took for ICE to complete, given that it failed." + }, + "LOOP_ICE_SUCCESS_RATE": { + "expires_in_version": "never", + "kind": "boolean", + "description": "The number of failed ICE Connections (0) vs. number of successful ICE connections (1)." + }, + "LOOP_CANDIDATE_TYPES_GIVEN_SUCCESS": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 128, + "description": "A bitpattern indicating what types of candidates were present. Bit 0: Remote server reflexive. Bit 1: Remote relayed. Bit 2: Local server reflexive. Bits 3-6: Local UDP, TCP, TLS, and HTTPS relay respectively." + }, + "LOOP_CANDIDATE_TYPES_GIVEN_FAILURE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 128, + "description": "Identical to LOOP_CANDIDATE_TYPES_GIVEN_SUCCEESS, except recorded only when ICE fails on the stream in question." + }, + "LOOP_VIDEO_QUALITY_INBOUND_BANDWIDTH_KBITS": { + "expires_in_version": "never", + "kind": "exponential", + "high": 1000000, + "n_buckets": 1000, + "description": "Locally measured data rate of inbound video (kbit/s). Computed every second of a call." + }, + "LOOP_AUDIO_QUALITY_INBOUND_BANDWIDTH_KBITS": { + "expires_in_version": "never", + "kind": "exponential", + "high": 1000000, + "n_buckets": 1000, + "description": "Locally measured data rate on inbound audio (kbit/s). Computed every second of a call." + }, + "LOOP_VIDEO_QUALITY_OUTBOUND_BANDWIDTH_KBITS": { + "expires_in_version": "never", + "kind": "exponential", + "high": 1000000, + "n_buckets": 1000, + "description": "Data rate deduced from RTCP from remote recipient of outbound video (kbit/s). Computed every second of a call (for easy comparison)." + }, + "LOOP_AUDIO_QUALITY_OUTBOUND_BANDWIDTH_KBITS": { + "expires_in_version": "never", + "kind": "exponential", + "high": 1000000, + "n_buckets": 1000, + "description": "Data rate deduced from RTCP from remote recipient of outbound audio (kbit/s). Computed every second of a call (for easy comparison)." + }, + "LOOP_VIDEO_ERROR_RECOVERY_MS": { + "expires_in_version": "never", + "kind": "exponential", + "high": 10000, + "n_buckets": 500, + "description": "Time to recover from a video error in ms" + }, + "LOOP_VIDEO_RECOVERY_BEFORE_ERROR_PER_MIN": { + "expires_in_version": "never", + "kind": "exponential", + "high": 1000, + "n_buckets": 200, + "description": "Number of losses recovered before error per min" + }, + "LOOP_VIDEO_RECOVERY_AFTER_ERROR_PER_MIN": { + "expires_in_version": "never", + "kind": "exponential", + "high": 1000, + "n_buckets": 200, + "description": "Number of losses recovered after error per min" + }, + "LOOP_VIDEO_DECODE_ERROR_TIME_PERMILLE": { + "expires_in_version": "never", + "kind": "exponential", + "high": 1000, + "n_buckets": 100, + "description": "Percentage*10 (permille) of call decoding with errors or frozen due to errors" + }, + "LOOP_VIDEO_QUALITY_OUTBOUND_RTT": { + "expires_in_version": "never", + "kind": "exponential", + "high": 10000, + "n_buckets": 1000, + "description": "Roundtrip time of outbound video (ms). Sampled every second of a call." + }, + "LOOP_AUDIO_QUALITY_OUTBOUND_RTT": { + "expires_in_version": "never", + "kind": "exponential", + "high": 10000, + "n_buckets": 1000, + "description": "Roundtrip time of outbound audio (ms). Sampled every second of a call." + }, + "LOOP_VIDEO_ENCODER_BITRATE_AVG_PER_CALL_KBPS": { + "expires_in_version": "never", + "kind": "exponential", + "high": 10000, + "n_buckets": 100, + "description": "Video encoder's average bitrate (in kbits/s) over an entire call" + }, + "LOOP_VIDEO_ENCODER_BITRATE_STD_DEV_PER_CALL_KBPS": { + "expires_in_version": "never", + "kind": "exponential", + "high": 5000, + "n_buckets": 100, + "description": "Standard deviation from video encoder's average bitrate (in kbits/s) over an entire call" + }, + "LOOP_VIDEO_ENCODER_FRAMERATE_AVG_PER_CALL": { + "expires_in_version": "never", + "kind": "exponential", + "high": 200, + "n_buckets": 50, + "description": "Video encoder's average framerate (in fps) over an entire call" + }, + "LOOP_VIDEO_ENCODER_FRAMERATE_10X_STD_DEV_PER_CALL": { + "expires_in_version": "never", + "kind": "exponential", + "high": 200, + "n_buckets": 50, + "description": "Standard deviation from video encoder's average framerate (in 1/10 fps) over an entire call" + }, + "LOOP_VIDEO_ENCODER_DROPPED_FRAMES_PER_CALL_FPM": { + "expires_in_version": "never", + "kind": "exponential", + "high": 50000, + "n_buckets": 100, + "description": "Video encoder's number of frames dropped (in frames/min) over an entire call" + }, + "LOOP_VIDEO_DECODER_BITRATE_AVG_PER_CALL_KBPS": { + "expires_in_version": "never", + "kind": "exponential", + "high": 10000, + "n_buckets": 100, + "description": "Video decoder's average bitrate (in kbits/s) over an entire call" + }, + "LOOP_VIDEO_DECODER_BITRATE_STD_DEV_PER_CALL_KBPS": { + "expires_in_version": "never", + "kind": "exponential", + "high": 5000, + "n_buckets": 100, + "description": "Standard deviation from video decoder's average bitrate (in kbits/s) over an entire call" + }, + "LOOP_VIDEO_DECODER_FRAMERATE_AVG_PER_CALL": { + "expires_in_version": "never", + "kind": "exponential", + "high": "200", + "n_buckets": "50", + "description": "Video decoder's average framerate (in fps) over an entire call" + }, + "LOOP_VIDEO_DECODER_FRAMERATE_10X_STD_DEV_PER_CALL": { + "expires_in_version": "never", + "kind": "exponential", + "high": "200", + "n_buckets": "50", + "description": "Standard deviation from video decoder's average framerate (in 1/10 fps) over an entire call" + }, + "LOOP_VIDEO_DECODER_DISCARDED_PACKETS_PER_CALL_PPM": { + "expires_in_version": "never", + "kind": "exponential", + "high": 50000, + "n_buckets": 100, + "description": "Video decoder's number of discarded packets (in packets/min) over an entire call" + }, + "LOOP_CALL_DURATION": { + "expires_in_version": "never", + "kind": "exponential", + "high": "10000", + "n_buckets": "1000", + "description": "The length of time (in seconds) that a call lasted." + }, + "LOOP_ICE_ADD_CANDIDATE_ERRORS_GIVEN_SUCCESS": { + "expires_in_version": "never", + "kind": "linear", + "high": "30", + "n_buckets": "29", + "description": "The number of times AddIceCandidate failed on a given PeerConnection, given that ICE succeeded." + }, + "LOOP_ICE_ADD_CANDIDATE_ERRORS_GIVEN_FAILURE": { + "expires_in_version": "never", + "kind": "linear", + "high": "30", + "n_buckets": "29", + "description": "The number of times AddIceCandidate failed on a given PeerConnection, given that ICE failed." } } From 48627b966eea5c01687e8308a3da41bfcdc2a157 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Tue, 11 Aug 2015 15:15:06 -0400 Subject: [PATCH 05/49] Bug 1188407: switch packetloss to a rate from total-packets-lost-per-update r=jib --- .../src/peerconnection/PeerConnectionCtx.cpp | 36 ++++++++++++------- toolkit/components/telemetry/Histograms.json | 8 ++--- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp index f9f6b97d1f38..01112aab83dd 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp @@ -220,21 +220,31 @@ EverySecondTelemetryCallback_s(nsAutoPtr aQueryList) { for (decltype(array.Length()) i = 0; i < array.Length(); i++) { auto& s = array[i]; bool isAudio = (s.mId.Value().Find("audio") != -1); - if (s.mPacketsLost.WasPassed()) { - Accumulate(s.mIsRemote? - (isAudio? WEBRTC_AUDIO_QUALITY_OUTBOUND_PACKETLOSS : - WEBRTC_VIDEO_QUALITY_OUTBOUND_PACKETLOSS) : - (isAudio? WEBRTC_AUDIO_QUALITY_INBOUND_PACKETLOSS : - WEBRTC_VIDEO_QUALITY_INBOUND_PACKETLOSS), - s.mPacketsLost.Value()); + if (s.mPacketsLost.WasPassed() && s.mPacketsReceived.WasPassed() && + (s.mPacketsLost.Value() + s.mPacketsReceived.Value()) != 0) { + ID id; + if (s.mIsRemote) { + id = isAudio ? WEBRTC_AUDIO_QUALITY_OUTBOUND_PACKETLOSS_RATE : + WEBRTC_VIDEO_QUALITY_OUTBOUND_PACKETLOSS_RATE; + } else { + id = isAudio ? WEBRTC_AUDIO_QUALITY_INBOUND_PACKETLOSS_RATE : + WEBRTC_VIDEO_QUALITY_INBOUND_PACKETLOSS_RATE; + } + // *1000 so we can read in 10's of a percent (permille) + Accumulate(id, + (s.mPacketsLost.Value() * 1000) / + (s.mPacketsLost.Value() + s.mPacketsReceived.Value())); } if (s.mJitter.WasPassed()) { - Accumulate(s.mIsRemote? - (isAudio? WEBRTC_AUDIO_QUALITY_OUTBOUND_JITTER : - WEBRTC_VIDEO_QUALITY_OUTBOUND_JITTER) : - (isAudio? WEBRTC_AUDIO_QUALITY_INBOUND_JITTER : - WEBRTC_VIDEO_QUALITY_INBOUND_JITTER), - s.mJitter.Value()); + ID id; + if (s.mIsRemote) { + id = isAudio ? WEBRTC_AUDIO_QUALITY_OUTBOUND_JITTER : + WEBRTC_VIDEO_QUALITY_OUTBOUND_JITTER; + } else { + id = isAudio ? WEBRTC_AUDIO_QUALITY_INBOUND_JITTER : + WEBRTC_VIDEO_QUALITY_INBOUND_JITTER; + } + Accumulate(id, s.mJitter.Value()); } if (s.mMozRtt.WasPassed()) { MOZ_ASSERT(s.mIsRemote); diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 3e0970584b5b..01045ebaf310 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -6194,28 +6194,28 @@ "n_buckets": 1000, "description": "Data rate deduced from RTCP from remote recipient of outbound audio (kbit/s). Computed every second of a call (for easy comparison)." }, - "WEBRTC_VIDEO_QUALITY_INBOUND_PACKETLOSS": { + "WEBRTC_VIDEO_QUALITY_INBOUND_PACKETLOSS_RATE": { "expires_in_version": "never", "kind": "exponential", "high": 1000, "n_buckets": 100, "description": "Locally measured packet loss on inbound video (permille). Sampled every second of a call." }, - "WEBRTC_AUDIO_QUALITY_INBOUND_PACKETLOSS": { + "WEBRTC_AUDIO_QUALITY_INBOUND_PACKETLOSS_RATE": { "expires_in_version": "never", "kind": "exponential", "high": 1000, "n_buckets": 100, "description": "Locally measured packet loss on inbound audio (permille). Sampled every second of a call." }, - "WEBRTC_VIDEO_QUALITY_OUTBOUND_PACKETLOSS": { + "WEBRTC_VIDEO_QUALITY_OUTBOUND_PACKETLOSS_RATE": { "expires_in_version": "never", "kind": "exponential", "high": 1000, "n_buckets": 100, "description": "RTCP-reported packet loss by remote recipient of outbound video (permille). Sampled every second of a call (for easy comparison)." }, - "WEBRTC_AUDIO_QUALITY_OUTBOUND_PACKETLOSS": { + "WEBRTC_AUDIO_QUALITY_OUTBOUND_PACKETLOSS_RATE": { "expires_in_version": "never", "kind": "exponential", "high": 1000, From b7e53859ada3658b2812d3333bdd11e52ebeb92b Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Mon, 10 Aug 2015 10:19:08 -0700 Subject: [PATCH 06/49] Bug 1182544 - Use channel->ascynOpen2 in dom/xml/XMLDocument.cpp (r=sicking) --- dom/security/nsContentSecurityManager.cpp | 21 +++++++++--- dom/xml/XMLDocument.cpp | 40 ++--------------------- 2 files changed, 19 insertions(+), 42 deletions(-) diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index 9817db54684c..946d60ff5cc4 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -116,6 +116,8 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) nsContentPolicyType contentPolicyType = aLoadInfo->GetContentPolicyType(); nsCString mimeTypeGuess; nsCOMPtr requestingContext = nullptr; + nsContentPolicyType internalContentPolicyType = + aLoadInfo->InternalContentPolicyType(); switch(contentPolicyType) { case nsIContentPolicy::TYPE_OTHER: { @@ -139,12 +141,24 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) case nsIContentPolicy::TYPE_XMLHTTPREQUEST: { // alias nsIContentPolicy::TYPE_DATAREQUEST: - mimeTypeGuess = NS_LITERAL_CSTRING(TEXT_EVENT_STREAM); requestingContext = aLoadInfo->LoadingNode(); + MOZ_ASSERT(!requestingContext || + requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE, + "type_xml requires requestingContext of type Document"); + + if (internalContentPolicyType == + nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST) { + mimeTypeGuess = NS_LITERAL_CSTRING("application/xml"); + } + else { + MOZ_ASSERT(internalContentPolicyType == + nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE, + "can not set mime type guess for unexpected internal type"); + mimeTypeGuess = NS_LITERAL_CSTRING(TEXT_EVENT_STREAM); + } break; } - case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST: { mimeTypeGuess = EmptyCString(); requestingContext = aLoadInfo->LoadingNode(); @@ -161,9 +175,6 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) } case nsIContentPolicy::TYPE_MEDIA: { - nsContentPolicyType internalContentPolicyType = - aLoadInfo->InternalContentPolicyType(); - if (internalContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_TRACK) { mimeTypeGuess = NS_LITERAL_CSTRING("text/vtt"); } diff --git a/dom/xml/XMLDocument.cpp b/dom/xml/XMLDocument.cpp index 62a6c58ef0c8..860ef187cd67 100644 --- a/dom/xml/XMLDocument.cpp +++ b/dom/xml/XMLDocument.cpp @@ -332,41 +332,7 @@ XMLDocument::Load(const nsAString& aUrl, ErrorResult& aRv) return false; } - // Check to see whether the current document is allowed to load this URI. - // It's important to use the current document's principal for this check so - // that we don't end up in a case where code with elevated privileges is - // calling us and changing the principal of this document. - - // Enforce same-origin even for chrome loaders to avoid someone accidentally - // using a document that content has a reference to and turn that into a - // chrome document. - if (!nsContentUtils::IsSystemPrincipal(principal)) { - rv = principal->CheckMayLoad(uri, false, false); - if (NS_FAILED(rv)) { - aRv.Throw(rv); - return false; - } - - int16_t shouldLoad = nsIContentPolicy::ACCEPT; - rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, - uri, - principal, - callingDoc ? callingDoc.get() : - static_cast(this), - NS_LITERAL_CSTRING("application/xml"), - nullptr, - &shouldLoad, - nsContentUtils::GetContentPolicy(), - nsContentUtils::GetSecurityManager()); - if (NS_FAILED(rv)) { - aRv.Throw(rv); - return false; - } - if (NS_CP_REJECTED(shouldLoad)) { - aRv.Throw(NS_ERROR_CONTENT_BLOCKED); - return false; - } - } else { + if (nsContentUtils::IsSystemPrincipal(principal)) { // We're called from chrome, check to make sure the URI we're // about to load is also chrome. @@ -444,7 +410,7 @@ XMLDocument::Load(const nsAString& aUrl, ErrorResult& aRv) uri, callingDoc ? callingDoc.get() : static_cast(this), - nsILoadInfo::SEC_NORMAL, + nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED, nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, loadGroup, req, @@ -478,7 +444,7 @@ XMLDocument::Load(const nsAString& aUrl, ErrorResult& aRv) // mChannelIsPending. // Start an asynchronous read of the XML document - rv = channel->AsyncOpen(listener, nullptr); + rv = channel->AsyncOpen2(listener); if (NS_FAILED(rv)) { mChannelIsPending = false; aRv.Throw(rv); From 4b7d4aaed504196441c16e160939500ac3d0b006 Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Mon, 10 Aug 2015 10:25:20 -0700 Subject: [PATCH 07/49] Bug 1187165 - Use channel->ascynOpen2 in dom/base/ImportManager (r=sicking) --- dom/base/ImportManager.cpp | 51 +++++------------------ dom/security/nsContentSecurityManager.cpp | 16 ++++++- 2 files changed, 25 insertions(+), 42 deletions(-) diff --git a/dom/base/ImportManager.cpp b/dom/base/ImportManager.cpp index 5f64ebfea903..539594b01dd5 100644 --- a/dom/base/ImportManager.cpp +++ b/dom/base/ImportManager.cpp @@ -463,51 +463,22 @@ void ImportLoader::Open() { AutoError ae(this, false); - // Imports should obey to the master documents CSP. - nsCOMPtr master = mImportParent->MasterDocument(); - nsIPrincipal* principal = Principal(); - int16_t shouldLoad = nsIContentPolicy::ACCEPT; - nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SUBDOCUMENT, - mURI, - principal, - mImportParent, - NS_LITERAL_CSTRING("text/html"), - /* extra = */ nullptr, - &shouldLoad, - nsContentUtils::GetContentPolicy(), - nsContentUtils::GetSecurityManager()); - if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) { - NS_WARN_IF_FALSE(NS_CP_ACCEPTED(shouldLoad), "ImportLoader rejected by CSP"); - return; - } + nsCOMPtr loadGroup = + mImportParent->MasterDocument()->GetDocumentLoadGroup(); - nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager(); - rv = secMan->CheckLoadURIWithPrincipal(principal, mURI, - nsIScriptSecurityManager::STANDARD); - NS_ENSURE_SUCCESS_VOID(rv); - - nsCOMPtr loadGroup = master->GetDocumentLoadGroup(); nsCOMPtr channel; - rv = NS_NewChannel(getter_AddRefs(channel), - mURI, - mImportParent, - nsILoadInfo::SEC_NORMAL, - nsIContentPolicy::TYPE_SUBDOCUMENT, - loadGroup, - nullptr, // aCallbacks - nsIRequest::LOAD_BACKGROUND); + nsresult rv = NS_NewChannel(getter_AddRefs(channel), + mURI, + mImportParent, + nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, + nsIContentPolicy::TYPE_SUBDOCUMENT, + loadGroup, + nullptr, // aCallbacks + nsIRequest::LOAD_BACKGROUND); NS_ENSURE_SUCCESS_VOID(rv); - - // Init CORSListenerProxy and omit credentials. - nsRefPtr corsListener = - new nsCORSListenerProxy(this, principal, - /* aWithCredentials */ false); - rv = corsListener->Init(channel, DataURIHandling::Allow); - NS_ENSURE_SUCCESS_VOID(rv); - - rv = channel->AsyncOpen(corsListener, nullptr); + rv = channel->AsyncOpen2(this); NS_ENSURE_SUCCESS_VOID(rv); BlockScripts(); diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index 946d60ff5cc4..376041d84ef7 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -130,8 +130,20 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) case nsIContentPolicy::TYPE_IMAGE: case nsIContentPolicy::TYPE_STYLESHEET: case nsIContentPolicy::TYPE_OBJECT: - case nsIContentPolicy::TYPE_DOCUMENT: - case nsIContentPolicy::TYPE_SUBDOCUMENT: + case nsIContentPolicy::TYPE_DOCUMENT: { + MOZ_ASSERT(false, "contentPolicyType not supported yet"); + break; + } + + case nsIContentPolicy::TYPE_SUBDOCUMENT: { + mimeTypeGuess = NS_LITERAL_CSTRING("text/html"); + requestingContext = aLoadInfo->LoadingNode(); + MOZ_ASSERT(!requestingContext || + requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE, + "type_subdocument requires requestingContext of type Document"); + break; + } + case nsIContentPolicy::TYPE_REFRESH: case nsIContentPolicy::TYPE_XBL: case nsIContentPolicy::TYPE_PING: { From a606a3d7018da400f4b132458868843edd20df48 Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Mon, 10 Aug 2015 10:20:40 -0700 Subject: [PATCH 08/49] Bug 1188644 - Use channel->ascynOpen2 in netwerk/test (r=mcmanus) --- netwerk/test/TestCallbacks.cpp | 283 ----------------------------- netwerk/test/TestHttp.cpp | 188 ------------------- netwerk/test/TestRes.cpp | 264 --------------------------- netwerk/test/TestStreamChannel.cpp | 200 -------------------- netwerk/test/TestStreamLoader.cpp | 4 +- netwerk/test/TestUpload.cpp | 4 +- netwerk/test/moz.build | 2 - 7 files changed, 4 insertions(+), 941 deletions(-) delete mode 100644 netwerk/test/TestCallbacks.cpp delete mode 100644 netwerk/test/TestHttp.cpp delete mode 100644 netwerk/test/TestRes.cpp delete mode 100644 netwerk/test/TestStreamChannel.cpp diff --git a/netwerk/test/TestCallbacks.cpp b/netwerk/test/TestCallbacks.cpp deleted file mode 100644 index e6f17c9435f8..000000000000 --- a/netwerk/test/TestCallbacks.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "TestCommon.h" -#include -#ifdef WIN32 -#include -#endif -#include "nspr.h" -#include "nscore.h" -#include "nsCOMPtr.h" -#include "nsIServiceManager.h" -#include "nsIStreamListener.h" -#include "nsIInputStream.h" -#include "nsIChannel.h" -#include "nsIURL.h" -#include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsIDNSService.h" -#include "mozilla/Attributes.h" - -#include "nsISimpleEnumerator.h" -#include "nsNetUtil.h" -#include "nsIScriptSecurityManager.h" -#include "nsServiceManagerUtils.h" -#include "nsStringAPI.h" - -static bool gError = false; -static int32_t gKeepRunning = 0; - -#define NS_IEQUALS_IID \ - { 0x11c5c8ee, 0x1dd2, 0x11b2, \ - { 0xa8, 0x93, 0xbb, 0x23, 0xa1, 0xb6, 0x27, 0x76 }} - -class nsIEquals : public nsISupports { -public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_IEQUALS_IID) - NS_IMETHOD Equals(void *aPtr, bool *_retval) = 0; -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsIEquals, NS_IEQUALS_IID) - -class ConsumerContext final : public nsIEquals { - - ~ConsumerContext() {} - -public: - NS_DECL_THREADSAFE_ISUPPORTS - - ConsumerContext() { } - - NS_IMETHOD Equals(void *aPtr, bool *_retval) override { - *_retval = true; - if (aPtr != this) *_retval = false; - return NS_OK; - } -}; - -NS_IMPL_ISUPPORTS(ConsumerContext, nsIEquals) - -class Consumer : public nsIStreamListener { - - virtual ~Consumer(); - -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - - Consumer(); - nsresult Init(nsIURI *aURI, nsIChannel *aChannel, nsISupports *aContext); - nsresult Validate(nsIRequest *request, nsISupports *aContext); - - // member data - bool mOnStart; // have we received an OnStart? - bool mOnStop; // have we received an onStop? - int32_t mOnDataCount; // number of times OnData was called. - nsCOMPtr mURI; - nsCOMPtr mChannel; - nsCOMPtr mContext; -}; - -// nsISupports implementation -NS_IMPL_ISUPPORTS(Consumer, nsIStreamListener, nsIRequestObserver) - - -// nsIRequestObserver implementation -NS_IMETHODIMP -Consumer::OnStartRequest(nsIRequest *request, nsISupports* aContext) { - fprintf(stderr, "Consumer::OnStart() -> in\n\n"); - - if (mOnStart) { - fprintf(stderr, "INFO: multiple OnStarts received\n"); - } - mOnStart = true; - - nsresult rv = Validate(request, aContext); - if (NS_FAILED(rv)) return rv; - - fprintf(stderr, "Consumer::OnStart() -> out\n\n"); - return rv; -} - -NS_IMETHODIMP -Consumer::OnStopRequest(nsIRequest *request, nsISupports *aContext, - nsresult aStatus) { - fprintf(stderr, "Consumer::OnStop() -> in\n\n"); - - if (!mOnStart) { - gError = true; - fprintf(stderr, "ERROR: No OnStart received\n"); - } - - if (mOnStop) { - fprintf(stderr, "INFO: multiple OnStops received\n"); - } - - fprintf(stderr, "INFO: received %d OnData()s\n", mOnDataCount); - - mOnStop = true; - - nsresult rv = Validate(request, aContext); - if (NS_FAILED(rv)) return rv; - - fprintf(stderr, "Consumer::OnStop() -> out\n\n"); - return rv; -} - - -// nsIStreamListener implementation -NS_IMETHODIMP -Consumer::OnDataAvailable(nsIRequest *request, nsISupports *aContext, - nsIInputStream *aIStream, - uint64_t aOffset, uint32_t aLength) { - fprintf(stderr, "Consumer::OnData() -> in\n\n"); - - if (!mOnStart) { - gError = true; - fprintf(stderr, "ERROR: No OnStart received\n"); - } - - mOnDataCount += 1; - - nsresult rv = Validate(request, aContext); - if (NS_FAILED(rv)) return rv; - - fprintf(stderr, "Consumer::OnData() -> out\n\n"); - return rv; -} - -// Consumer implementation -Consumer::Consumer() { - mOnStart = mOnStop = false; - mOnDataCount = 0; - gKeepRunning++; -} - -Consumer::~Consumer() { - fprintf(stderr, "Consumer::~Consumer -> in\n\n"); - - if (!mOnStart) { - gError = true; - fprintf(stderr, "ERROR: Never got an OnStart\n"); - } - - if (!mOnStop) { - gError = true; - fprintf(stderr, "ERROR: Never got an OnStop \n"); - } - - fprintf(stderr, "Consumer::~Consumer -> out\n\n"); - if (--gKeepRunning == 0) - QuitPumpingEvents(); -} - -nsresult -Consumer::Init(nsIURI *aURI, nsIChannel* aChannel, nsISupports *aContext) { - mURI = aURI; - mChannel = aChannel; - mContext = do_QueryInterface(aContext); - return NS_OK; -} - -nsresult -Consumer::Validate(nsIRequest* request, nsISupports *aContext) { - nsresult rv = NS_OK; - nsCOMPtr uri; - nsCOMPtr aChannel = do_QueryInterface(request); - - rv = aChannel->GetURI(getter_AddRefs(uri)); - if (NS_FAILED(rv)) return rv; - - bool same = false; - - rv = mURI->Equals(uri, &same); - if (NS_FAILED(rv)) return rv; - - if (!same) - fprintf(stderr, "INFO: URIs do not match\n"); - - rv = mContext->Equals((void*)aContext, &same); - if (NS_FAILED(rv)) return rv; - - if (!same) { - gError = true; - fprintf(stderr, "ERROR: Contexts do not match\n"); - } - return rv; -} - -nsresult StartLoad(const char *); - -int main(int argc, char *argv[]) { - if (test_common_init(&argc, &argv) != 0) - return -1; - - nsresult rv = NS_OK; - bool cmdLineURL = false; - - if (argc > 1) { - // run in signle url mode - cmdLineURL = true; - } - - rv = NS_InitXPCOM2(nullptr, nullptr, nullptr); - if (NS_FAILED(rv)) return -1; - - if (cmdLineURL) { - rv = StartLoad(argv[1]); - } else { - rv = StartLoad("http://badhostnamexyz/test.txt"); - } - if (NS_FAILED(rv)) return -1; - - // Enter the message pump to allow the URL load to proceed. - PumpEvents(); - - NS_ShutdownXPCOM(nullptr); - if (gError) { - fprintf(stderr, "\n\n-------ERROR-------\n\n"); - } - return 0; -} - -nsresult StartLoad(const char *aURISpec) { - nsresult rv = NS_OK; - - // create a context - ConsumerContext *context = new ConsumerContext; - nsCOMPtr contextSup = do_QueryInterface(context, &rv); - if (NS_FAILED(rv)) return rv; - - // create a uri - nsCOMPtr uri; - rv = NS_NewURI(getter_AddRefs(uri), aURISpec); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr secman = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - if (NS_FAILED(rv)) return rv; - nsCOMPtr systemPrincipal; - rv = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal)); - if (NS_FAILED(rv)) return rv; - - // create a channel - nsCOMPtr channel; - rv = NS_NewChannel(getter_AddRefs(channel), - uri, - systemPrincipal, - nsILoadInfo::SEC_NORMAL, - nsIContentPolicy::TYPE_OTHER); - if (NS_FAILED(rv)) return rv; - - Consumer *consumer = new Consumer; - rv = consumer->Init(uri, channel, contextSup); - if (NS_FAILED(rv)) return rv; - - // kick off the load - nsCOMPtr request; - return channel->AsyncOpen(static_cast(consumer), contextSup); -} diff --git a/netwerk/test/TestHttp.cpp b/netwerk/test/TestHttp.cpp deleted file mode 100644 index 3bb87592ce9e..000000000000 --- a/netwerk/test/TestHttp.cpp +++ /dev/null @@ -1,188 +0,0 @@ -#include "nsNetUtil.h" -#include "nsIEventQueueService.h" -#include "nsIServiceManager.h" -#include "nsIComponentRegistrar.h" -#include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsIProgressEventSink.h" -#include -#include "nsIContentPolicy.h" -#include "mozilla/LoadInfo.h" -#include "nsContentUtils.h" - -#define RETURN_IF_FAILED(rv, step) \ - PR_BEGIN_MACRO \ - if (NS_FAILED(rv)) { \ - printf(">>> %s failed: rv=%x\n", step, rv); \ - return rv;\ - } \ - PR_END_MACRO - -static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); -static nsIEventQueue* gEventQ = nullptr; -static bool gKeepRunning = true; - -//----------------------------------------------------------------------------- -// nsIStreamListener implementation -//----------------------------------------------------------------------------- - -class MyListener : public nsIStreamListener -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - - MyListener() { } - virtual ~MyListener() {} -}; - -NS_IMPL_ISUPPORTS(MyListener, - nsIRequestObserver, - nsIStreamListener) - -NS_IMETHODIMP -MyListener::OnStartRequest(nsIRequest *req, nsISupports *ctxt) -{ - printf(">>> OnStartRequest\n"); - return NS_OK; -} - -NS_IMETHODIMP -MyListener::OnStopRequest(nsIRequest *req, nsISupports *ctxt, nsresult status) -{ - printf(">>> OnStopRequest status=%x\n", status); - gKeepRunning = false; - return NS_OK; -} - -NS_IMETHODIMP -MyListener::OnDataAvailable(nsIRequest *req, nsISupports *ctxt, - nsIInputStream *stream, - uint64_t offset, uint32_t count) -{ - printf(">>> OnDataAvailable [count=%u]\n", count); - - char buf[256]; - nsresult rv; - uint32_t bytesRead=0; - - while (count) { - uint32_t amount = std::min(count, sizeof(buf)); - - rv = stream->Read(buf, amount, &bytesRead); - if (NS_FAILED(rv)) { - printf(">>> stream->Read failed with rv=%x\n", rv); - return rv; - } - - fwrite(buf, 1, bytesRead, stdout); - - count -= bytesRead; - } - return NS_OK; -} - -//----------------------------------------------------------------------------- -// NotificationCallbacks implementation -//----------------------------------------------------------------------------- - -class MyNotifications : public nsIInterfaceRequestor - , public nsIProgressEventSink -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSIPROGRESSEVENTSINK - - MyNotifications() { } - virtual ~MyNotifications() {} -}; - -NS_IMPL_ISUPPORTS(MyNotifications, - nsIInterfaceRequestor, - nsIProgressEventSink) - -NS_IMETHODIMP -MyNotifications::GetInterface(const nsIID &iid, void **result) -{ - return QueryInterface(iid, result); -} - -NS_IMETHODIMP -MyNotifications::OnStatus(nsIRequest *req, nsISupports *ctx, - nsresult status, const char16_t *statusText) -{ - printf("status: %x\n", status); - return NS_OK; -} - -NS_IMETHODIMP -MyNotifications::OnProgress(nsIRequest *req, nsISupports *ctx, - uint64_t progress, uint64_t progressMax) -{ - printf("progress: %llu/%llu\n", progress, progressMax); - return NS_OK; -} - -//----------------------------------------------------------------------------- -// main, etc.. -//----------------------------------------------------------------------------- - - -int main(int argc, char **argv) -{ - nsresult rv; - - if (argc == 1) { - printf("usage: TestHttp \n"); - return -1; - } - { - nsCOMPtr servMan; - NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr); - nsCOMPtr registrar = do_QueryInterface(servMan); - NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); - if (registrar) - registrar->AutoRegister(nullptr); - - // Create the Event Queue for this thread... - nsCOMPtr eqs = - do_GetService(kEventQueueServiceCID, &rv); - RETURN_IF_FAILED(rv, "do_GetService(EventQueueService)"); - - rv = eqs->CreateMonitoredThreadEventQueue(); - RETURN_IF_FAILED(rv, "CreateMonitoredThreadEventQueue"); - - rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); - RETURN_IF_FAILED(rv, "GetThreadEventQueue"); - - nsCOMPtr uri; - nsCOMPtr chan; - nsCOMPtr listener = new MyListener(); - nsCOMPtr callbacks = new MyNotifications(); - - rv = NS_NewURI(getter_AddRefs(uri), argv[1]); - RETURN_IF_FAILED(rv, "NS_NewURI"); - - rv = NS_NewChannel(getter_AddRefs(chan), - uri, - nsContentUtils::GetSystemPrincipal(), - nsILoadInfo::SEC_NORMAL, - nsIContentPolicy::TYPE_OTHER); - - RETURN_IF_FAILED(rv, "NS_NewChannel"); - - rv = chan->AsyncOpen(listener, nullptr); - RETURN_IF_FAILED(rv, "AsyncOpen"); - - while (gKeepRunning) - gEventQ->ProcessPendingEvents(); - - printf(">>> done\n"); - } // this scopes the nsCOMPtrs - // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM - rv = NS_ShutdownXPCOM(nullptr); - NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); - return 0; -} diff --git a/netwerk/test/TestRes.cpp b/netwerk/test/TestRes.cpp deleted file mode 100644 index 82bd994e108d..000000000000 --- a/netwerk/test/TestRes.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* 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 "nsIResProtocolHandler.h" -#include "nsIServiceManager.h" -#include "nsIInputStream.h" -#include "nsIComponentManager.h" -#include "nsIComponentRegistrar.h" -#include "nsIStreamListener.h" -#include "nsIEventQueueService.h" -#include "nsIURI.h" -#include "nsCRT.h" -#include "nsNetCID.h" -#include "nsIScriptSecurityManager.h" -#include "nsILoadInfo.h" -#include "nsNetUtil.h" - -static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); -static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); - -//////////////////////////////////////////////////////////////////////////////// - -nsresult -SetupMapping() -{ - nsresult rv; - - nsCOMPtr serv(do_GetService(kIOServiceCID, &rv)); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr ph; - rv = serv->GetProtocolHandler("res", getter_AddRefs(ph)); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr resPH = do_QueryInterface(ph, &rv); - if (NS_FAILED(rv)) return rv; - - rv = resPH->AppendSubstitution("foo", "file://y|/"); - if (NS_FAILED(rv)) return rv; - - rv = resPH->AppendSubstitution("foo", "file://y|/mozilla/dist/win32_D.OBJ/bin/"); - if (NS_FAILED(rv)) return rv; - - return rv; -} - -//////////////////////////////////////////////////////////////////////////////// - -nsresult -TestOpenInputStream(const char* url) -{ - nsresult rv; - - nsCOMPtr secman = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - if (NS_FAILED(rv)) return rv; - nsCOMPtr systemPrincipal; - rv = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal)); - if (NS_FAILED(rv)) return rv; - nsCOMPtr uri; - rv = NS_NewURI(getter_AddRefs(uri), url); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr channel; - rv = NS_NewChannel(getter_AddRefs(channel), - uri, - systemPrincipal, - nsILoadInfo::SEC_NORMAL, - nsIContentPolicy::TYPE_OTHER); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr in; - rv = channel->Open(getter_AddRefs(in)); - if (NS_FAILED(rv)) { - fprintf(stdout, "failed to OpenInputStream for %s\n", url); - return NS_OK; - } - - char buf[1024]; - while (1) { - uint32_t amt; - rv = in->Read(buf, sizeof(buf), &amt); - if (NS_FAILED(rv)) return rv; - if (amt == 0) break; // eof - - char* str = buf; - while (amt-- > 0) { - fputc(*str++, stdout); - } - } - nsCOMPtr uri; - char* str; - - rv = channel->GetOriginalURI(getter_AddRefs(uri)); - if (NS_FAILED(rv)) return rv; - rv = uri->GetSpec(&str); - if (NS_FAILED(rv)) return rv; - fprintf(stdout, "%s resolved to ", str); - free(str); - - rv = channel->GetURI(getter_AddRefs(uri)); - if (NS_FAILED(rv)) return rv; - rv = uri->GetSpec(&str); - if (NS_FAILED(rv)) return rv; - fprintf(stdout, "%s\n", str); - free(str); - - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// - -bool gDone = false; -nsIEventQueue* gEventQ = nullptr; - -class Listener : public nsIStreamListener -{ -public: - NS_DECL_ISUPPORTS - - Listener() {} - virtual ~Listener() {} - - NS_IMETHOD OnStartRequest(nsIRequest *request, nsISupports *ctxt) { - nsresult rv; - nsCOMPtr uri; - nsCOMPtr channel = do_QueryInterface(request); - - rv = channel->GetURI(getter_AddRefs(uri)); - if (NS_SUCCEEDED(rv)) { - char* str; - rv = uri->GetSpec(&str); - if (NS_SUCCEEDED(rv)) { - fprintf(stdout, "Starting to load %s\n", str); - free(str); - } - } - return NS_OK; - } - - NS_IMETHOD OnStopRequest(nsIRequest *request, nsISupports *ctxt, - nsresult aStatus) { - nsresult rv; - nsCOMPtr uri; - nsCOMPtr channel = do_QueryInterface(request); - - rv = channel->GetURI(getter_AddRefs(uri)); - if (NS_SUCCEEDED(rv)) { - char* str; - rv = uri->GetSpec(&str); - if (NS_SUCCEEDED(rv)) { - fprintf(stdout, "Ending load %s, status=%x\n", str, aStatus); - free(str); - } - } - gDone = true; - return NS_OK; - } - - NS_IMETHOD OnDataAvailable(nsIRequest *request, nsISupports *ctxt, - nsIInputStream *inStr, - uint64_t sourceOffset, uint32_t count) { - nsresult rv; - char buf[1024]; - while (count > 0) { - uint32_t amt; - rv = inStr->Read(buf, sizeof(buf), &amt); - count -= amt; - char* c = buf; - while (amt-- > 0) { - fputc(*c++, stdout); - } - } - return NS_OK; - } -}; - -NS_IMPL_ISUPPORTS(Listener, nsIStreamListener, nsIRequestObserver) - -nsresult -TestAsyncRead(const char* url) -{ - nsresult rv; - - nsCOMPtr eventQService = - do_GetService(kEventQueueServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr secman = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - if (NS_FAILED(rv)) return rv; - nsCOMPtr systemPrincipal; - rv = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal)); - if (NS_FAILED(rv)) return rv; - nsCOMPtr uri; - rv = NS_NewURI(getter_AddRefs(uri), url); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr channel; - rv = NS_NewChannel(getter_AddRefs(channel), - uri, - systemPrincipal, - nsILoadInfo::SEC_NORMAL, - nsIContentPolicy::TYPE_OTHER); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr listener = new Listener(); - if (listener == nullptr) - return NS_ERROR_OUT_OF_MEMORY; - rv = channel->AsyncOpen(nullptr, listener); - if (NS_FAILED(rv)) return rv; - - while (!gDone) { - PLEvent* event; - rv = gEventQ->GetEvent(&event); - if (NS_FAILED(rv)) return rv; - rv = gEventQ->HandleEvent(event); - if (NS_FAILED(rv)) return rv; - } - - return rv; -} - -int -main(int argc, char* argv[]) -{ - nsresult rv; - { - nsCOMPtr servMan; - NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr); - nsCOMPtr registrar = do_QueryInterface(servMan); - NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); - if (registrar) - registrar->AutoRegister(nullptr); - - NS_ASSERTION(NS_SUCCEEDED(rv), "AutoregisterComponents failed"); - - if (argc < 2) { - printf("usage: %s resource://foo/\n", argv[0]); - return -1; - } - - rv = SetupMapping(); - NS_ASSERTION(NS_SUCCEEDED(rv), "SetupMapping failed"); - if (NS_FAILED(rv)) return rv; - - rv = TestOpenInputStream(argv[1]); - NS_ASSERTION(NS_SUCCEEDED(rv), "TestOpenInputStream failed"); - - rv = TestAsyncRead(argv[1]); - NS_ASSERTION(NS_SUCCEEDED(rv), "TestAsyncRead failed"); - } // this scopes the nsCOMPtrs - // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM - rv = NS_ShutdownXPCOM(nullptr); - NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); - return rv; -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/netwerk/test/TestStreamChannel.cpp b/netwerk/test/TestStreamChannel.cpp deleted file mode 100644 index 80ee03d736e2..000000000000 --- a/netwerk/test/TestStreamChannel.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "TestCommon.h" -#include "nsIComponentRegistrar.h" -#include "nsIStreamTransportService.h" -#include "nsIAsyncInputStream.h" -#include "nsIProgressEventSink.h" -#include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsIRequest.h" -#include "nsIServiceManager.h" -#include "nsIComponentManager.h" -#include "nsCOMPtr.h" -#include "nsMemory.h" -#include "nsStringAPI.h" -#include "nsIFileStreams.h" -#include "nsIStreamListener.h" -#include "nsIFile.h" -#include "nsNetUtil.h" -#include "nsAutoLock.h" -#include "mozilla/Logging.h" -#include - -//////////////////////////////////////////////////////////////////////////////// - -// -// set NSPR_LOG_MODULES=Test:5 -// -static PRLogModuleInfo *gTestLog = nullptr; -#define LOG(args) MOZ_LOG(gTestLog, mozilla::LogLevel::Debug, args) - -//////////////////////////////////////////////////////////////////////////////// - -static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID); - -//////////////////////////////////////////////////////////////////////////////// - -class MyListener : public nsIStreamListener -{ -public: - NS_DECL_ISUPPORTS - - MyListener() {} - virtual ~MyListener() {} - - NS_IMETHOD OnStartRequest(nsIRequest *req, nsISupports *ctx) - { - LOG(("MyListener::OnStartRequest\n")); - return NS_OK; - } - - NS_IMETHOD OnDataAvailable(nsIRequest *req, nsISupports *ctx, - nsIInputStream *stream, - uint32_t offset, uint32_t count) - { - LOG(("MyListener::OnDataAvailable [offset=%u count=%u]\n", offset, count)); - - char buf[500]; - nsresult rv; - - while (count) { - uint32_t n, amt = std::min(count, sizeof(buf)); - - rv = stream->Read(buf, amt, &n); - if (NS_FAILED(rv)) { - LOG((" read returned 0x%08x\n", rv)); - return rv; - } - - LOG((" read %u bytes\n", n)); - count -= n; - } - - return NS_OK; - } - - NS_IMETHOD OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status) - { - LOG(("MyListener::OnStopRequest [status=%x]\n", status)); - QuitPumpingEvents(); - return NS_OK; - } -}; - -NS_IMPL_ISUPPORTS(MyListener, - nsIRequestObserver, - nsIStreamListener) - -//////////////////////////////////////////////////////////////////////////////// - -class MyCallbacks : public nsIInterfaceRequestor - , public nsIProgressEventSink -{ -public: - NS_DECL_ISUPPORTS - - MyCallbacks() {} - virtual ~MyCallbacks() {} - - NS_IMETHOD GetInterface(const nsID &iid, void **result) - { - return QueryInterface(iid, result); - } - - NS_IMETHOD OnStatus(nsIRequest *req, nsISupports *ctx, nsresult status, - const char16_t *statusArg) - { - LOG(("MyCallbacks::OnStatus [status=%x]\n", status)); - return NS_OK; - } - - NS_IMETHOD OnProgress(nsIRequest *req, nsISupports *ctx, - uint64_t progress, uint64_t progressMax) - { - LOG(("MyCallbacks::OnProgress [progress=%llu/%llu]\n", progress, progressMax)); - return NS_OK; - } -}; - -NS_IMPL_ISUPPORTS(MyCallbacks, - nsIInterfaceRequestor, - nsIProgressEventSink) - -//////////////////////////////////////////////////////////////////////////////// - -/** - * asynchronously copy file. - */ -static nsresult -RunTest(nsIFile *file) -{ - nsresult rv; - - LOG(("RunTest\n")); - - nsCOMPtr stream; - rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr uri = do_CreateInstance(kSimpleURICID); - if (uri) - uri->SetSpec(NS_LITERAL_CSTRING("foo://bar")); - - nsCOMPtr chan; - rv = NS_NewInputStreamChannel(getter_AddRefs(chan), uri, stream); - if (NS_FAILED(rv)) return rv; - - rv = chan->SetNotificationCallbacks(new MyCallbacks()); - if (NS_FAILED(rv)) return rv; - - rv = chan->AsyncOpen(new MyListener(), nullptr); - if (NS_FAILED(rv)) return rv; - - PumpEvents(); - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// - -int -main(int argc, char* argv[]) -{ - if (test_common_init(&argc, &argv) != 0) - return -1; - - nsresult rv; - - if (argc < 2) { - printf("usage: %s \n", argv[0]); - return -1; - } - char* fileName = argv[1]; - { - nsCOMPtr servMan; - NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr); - nsCOMPtr registrar = do_QueryInterface(servMan); - NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); - if (registrar) - registrar->AutoRegister(nullptr); - - gTestLog = PR_NewLogModule("Test"); - - nsCOMPtr file; - rv = NS_NewNativeLocalFile(nsDependentCString(fileName), false, getter_AddRefs(file)); - if (NS_FAILED(rv)) return rv; - - rv = RunTest(file); - NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); - - // give background threads a chance to finish whatever work they may - // be doing. - PR_Sleep(PR_SecondsToInterval(1)); - } // this scopes the nsCOMPtrs - // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM - rv = NS_ShutdownXPCOM(nullptr); - NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); - return NS_OK; -} diff --git a/netwerk/test/TestStreamLoader.cpp b/netwerk/test/TestStreamLoader.cpp index 6e7e4de67b6f..6b26b854ca2e 100644 --- a/netwerk/test/TestStreamLoader.cpp +++ b/netwerk/test/TestStreamLoader.cpp @@ -74,7 +74,7 @@ int main(int argc, char **argv) rv = NS_NewChannel(getter_AddRefs(chan), uri, systemPrincipal, - nsILoadInfo::SEC_NORMAL, + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS, nsIContentPolicy::TYPE_OTHER); if (NS_FAILED(rv)) @@ -89,7 +89,7 @@ int main(int argc, char **argv) if (NS_FAILED(rv)) return -1; - rv = chan->AsyncOpen(loader, nullptr); + rv = chan->AsyncOpen2(loader); if (NS_FAILED(rv)) return -1; diff --git a/netwerk/test/TestUpload.cpp b/netwerk/test/TestUpload.cpp index 00bf4e70ca65..6e18d89395dd 100644 --- a/netwerk/test/TestUpload.cpp +++ b/netwerk/test/TestUpload.cpp @@ -140,7 +140,7 @@ main(int argc, char* argv[]) rv = NS_NewChannel(getter_AddRefs(channel), uri, systemPrincipal, - nsILoadInfo::SEC_NORMAL, + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS, nsIContentPolicy::TYPE_OTHER); if (NS_FAILED(rv)) return -1; @@ -158,7 +158,7 @@ main(int argc, char* argv[]) } NS_ADDREF(listener); - channel->AsyncOpen(listener, nullptr); + channel->AsyncOpen2(listener); PumpEvents(); } // this scopes the nsCOMPtrs diff --git a/netwerk/test/moz.build b/netwerk/test/moz.build index 35813296f9a6..92ade90ad59f 100644 --- a/netwerk/test/moz.build +++ b/netwerk/test/moz.build @@ -21,7 +21,6 @@ GeckoSimplePrograms([ 'PropertiesTest', 'ReadNTLM', 'TestBlockingSocket', - 'TestCallbacks', 'TestDNS', 'TestIncrementalDownload', 'TestOpen', @@ -39,7 +38,6 @@ GeckoSimplePrograms([ # TestIDN', # TestIOThreads', # TestSocketTransport', -# TestStreamChannel', # TestStreamPump', # TestStreamTransport', # TestUDPSocketProvider', From 1b577f8a20a9b6eac90857dbf9f8d16c6c489dc4 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Tue, 4 Aug 2015 10:38:24 -0700 Subject: [PATCH 09/49] Bug 1191099 - Replace AutoFunctionVector usage with Rooted; r=jonco --HG-- extra : rebase_source : e391f78394c02a50b8dd5c2163c0ab84e5f06733 --- js/src/NamespaceImports.h | 7 +++++-- js/src/frontend/Parser.h | 4 ++-- js/src/jsapi.h | 6 +++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h index a2e792cf2321..e8a3bcac4876 100644 --- a/js/src/NamespaceImports.h +++ b/js/src/NamespaceImports.h @@ -13,6 +13,7 @@ // These includes are needed these for some typedefs (e.g. HandleValue) and // functions (e.g. NullValue())... #include "js/CallNonGenericMethod.h" +#include "js/TraceableVector.h" #include "js/TypeDecls.h" #include "js/Value.h" @@ -33,7 +34,6 @@ class AutoVectorRooter; typedef AutoVectorRooter AutoValueVector; typedef AutoVectorRooter AutoIdVector; typedef AutoVectorRooter AutoObjectVector; -typedef AutoVectorRooter AutoFunctionVector; typedef AutoVectorRooter AutoVector; class AutoIdArray; @@ -81,9 +81,12 @@ using JS::AutoVectorRooter; typedef AutoVectorRooter AutoValueVector; typedef AutoVectorRooter AutoIdVector; typedef AutoVectorRooter AutoObjectVector; -typedef AutoVectorRooter AutoFunctionVector; typedef AutoVectorRooter AutoScriptVector; +using ValueVector = TraceableVector; +using IdVector = TraceableVector; +using ScriptVector = TraceableVector; + using JS::AutoIdArray; using JS::AutoHashMapRooter; diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 41056dc3f002..8bc4b48f4a06 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -227,7 +227,7 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext the same name. */ // All inner functions in this context. Only filled in when parsing syntax. - AutoFunctionVector innerFunctions; + Rooted> innerFunctions; // In a function context, points to a Directive struct that can be updated // to reflect new directives encountered in the Directive Prologue that @@ -265,7 +265,7 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext oldpc(prs->pc), lexdeps(prs->context), funcStmts(nullptr), - innerFunctions(prs->context), + innerFunctions(prs->context, TraceableVector(prs->context)), newDirectives(newDirectives), inDeclDestructuring(false) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 5aabaccf5413..584f38a0c541 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -29,6 +29,7 @@ #include "js/Id.h" #include "js/Principals.h" #include "js/RootingAPI.h" +#include "js/TraceableVector.h" #include "js/TracingAPI.h" #include "js/Utility.h" #include "js/Value.h" @@ -215,9 +216,12 @@ class MOZ_STACK_CLASS AutoVectorRooter : public AutoVectorRooterBase typedef AutoVectorRooter AutoValueVector; typedef AutoVectorRooter AutoIdVector; typedef AutoVectorRooter AutoObjectVector; -typedef AutoVectorRooter AutoFunctionVector; typedef AutoVectorRooter AutoScriptVector; +using ValueVector = js::TraceableVector; +using IdVector = js::TraceableVector; +using ScriptVector = js::TraceableVector; + template class AutoHashMapRooter : protected AutoGCRooter { From 275873aa38d6a5eaaf175c88f7a8c4f96dec6cea Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Tue, 4 Aug 2015 14:32:27 -0700 Subject: [PATCH 10/49] Bug 1191117 - Remove RootedGeneric and replace with normal Rooted usage; r=jonco --HG-- extra : rebase_source : 68b41d7a31da792aa688896828ddfe4c8c154d85 --- js/src/NamespaceImports.h | 2 -- js/src/jsapi.h | 37 ----------------------------- js/src/jsobj.cpp | 16 ++++++------- js/src/jspropertytree.cpp | 8 +++---- js/src/jspropertytree.h | 2 +- js/src/jsscript.cpp | 2 +- js/src/vm/GlobalObject.cpp | 2 +- js/src/vm/NativeObject.h | 4 ++-- js/src/vm/Shape-inl.h | 11 ++++----- js/src/vm/Shape.cpp | 33 +++++++++++++------------- js/src/vm/Shape.h | 47 ++++++++++++++++++++++++++++++++++--- js/src/vm/UnboxedObject.cpp | 7 +++--- 12 files changed, 84 insertions(+), 87 deletions(-) diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h index e8a3bcac4876..3319e137818f 100644 --- a/js/src/NamespaceImports.h +++ b/js/src/NamespaceImports.h @@ -41,7 +41,6 @@ class AutoIdArray; template class AutoVectorRooter; template class AutoHashMapRooter; template class AutoHashSetRooter; -template class RootedGeneric; class MOZ_STACK_CLASS SourceBufferHolder; @@ -91,7 +90,6 @@ using JS::AutoIdArray; using JS::AutoHashMapRooter; using JS::AutoHashSetRooter; -using JS::RootedGeneric; using JS::CallArgs; using JS::CallNonGenericMethod; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 584f38a0c541..feb7773a98e4 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -478,43 +478,6 @@ class JS_PUBLIC_API(CustomAutoRooter) : private AutoGCRooter MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; -/* - * RootedGeneric allows a class to instantiate its own Rooted type by - * including the method: - * - * void trace(JSTracer* trc); - * - * The trace() method must trace all of the class's fields. - */ -template -class RootedGeneric : private CustomAutoRooter -{ - public: - template - explicit RootedGeneric(CX* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : CustomAutoRooter(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - template - explicit RootedGeneric(CX* cx, const T& initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : CustomAutoRooter(cx), value(initial) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - operator const T&() const { return value; } - T operator->() const { return value; } - - private: - virtual void trace(JSTracer* trc) { value->trace(trc); } - - T value; - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - /* A handle to an array of rooted values. */ class HandleValueArray { diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 33c07b55fee5..53f903ad3f78 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -528,14 +528,13 @@ js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level) Reverse(shapes.begin(), shapes.end()); for (Shape* shape : shapes) { - StackShape unrootedChild(shape); - RootedGeneric child(cx, &unrootedChild); - child->attrs |= GetSealedOrFrozenAttributes(child->attrs, level); + Rooted child(cx, StackShape(shape)); + child.setAttrs(child.attrs() | GetSealedOrFrozenAttributes(child.attrs(), level)); - if (!JSID_IS_EMPTY(child->propid) && level == IntegrityLevel::Frozen) - MarkTypePropertyNonWritable(cx, nobj, child->propid); + if (!JSID_IS_EMPTY(child.get().propid) && level == IntegrityLevel::Frozen) + MarkTypePropertyNonWritable(cx, nobj, child.get().propid); - last = cx->compartment()->propertyTree.getChild(cx, last, *child); + last = cx->compartment()->propertyTree.getChild(cx, last, child); if (!last) return false; } @@ -1360,9 +1359,8 @@ InitializePropertiesFromCompatibleNativeObject(JSContext* cx, Reverse(shapes.begin(), shapes.end()); for (Shape* shape : shapes) { - StackShape unrootedChild(shape); - RootedGeneric child(cx, &unrootedChild); - shape = cx->compartment()->propertyTree.getChild(cx, shape, *child); + Rooted child(cx, StackShape(shape)); + shape = cx->compartment()->propertyTree.getChild(cx, shape, child); if (!shape) return false; } diff --git a/js/src/jspropertytree.cpp b/js/src/jspropertytree.cpp index 313bc361e300..885459dbae18 100644 --- a/js/src/jspropertytree.cpp +++ b/js/src/jspropertytree.cpp @@ -126,7 +126,7 @@ Shape::removeChild(Shape* child) } Shape* -PropertyTree::getChild(ExclusiveContext* cx, Shape* parentArg, StackShape& unrootedChild) +PropertyTree::getChild(ExclusiveContext* cx, Shape* parentArg, Handle child) { RootedShape parent(cx, parentArg); MOZ_ASSERT(parent); @@ -144,10 +144,10 @@ PropertyTree::getChild(ExclusiveContext* cx, Shape* parentArg, StackShape& unroo KidsPointer* kidp = &parent->kids; if (kidp->isShape()) { Shape* kid = kidp->toShape(); - if (kid->matches(unrootedChild)) + if (kid->matches(child)) existingShape = kid; } else if (kidp->isHash()) { - if (KidsHash::Ptr p = kidp->toHash()->lookup(unrootedChild)) + if (KidsHash::Ptr p = kidp->toHash()->lookup(child)) existingShape = *p; } else { /* If kidp->isNull(), we always insert. */ @@ -181,7 +181,7 @@ PropertyTree::getChild(ExclusiveContext* cx, Shape* parentArg, StackShape& unroo if (existingShape) return existingShape; - Shape* shape = Shape::new_(cx, unrootedChild, parent->numFixedSlots()); + Shape* shape = Shape::new_(cx, child, parent->numFixedSlots()); if (!shape) return nullptr; diff --git a/js/src/jspropertytree.h b/js/src/jspropertytree.h index ef125d8d7fa5..6e408982502b 100644 --- a/js/src/jspropertytree.h +++ b/js/src/jspropertytree.h @@ -96,7 +96,7 @@ class PropertyTree JSCompartment* compartment() { return compartment_; } - Shape* getChild(ExclusiveContext* cx, Shape* parent, StackShape& child); + Shape* getChild(ExclusiveContext* cx, Shape* parent, Handle child); }; } /* namespace js */ diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index df2292e28d55..6c495e852015 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -179,7 +179,7 @@ Bindings::initWithTemporaryStorage(ExclusiveContext* cx, MutableHandle unsigned attrs = JSPROP_PERMANENT | JSPROP_ENUMERATE | (bi->kind() == Binding::CONSTANT ? JSPROP_READONLY : 0); - StackShape child(base, NameToId(bi->name()), slot, attrs, 0); + Rooted child(cx, StackShape(base, NameToId(bi->name()), slot, attrs, 0)); shape = cx->compartment()->propertyTree.getChild(cx, shape, child); if (!shape) diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 1d85bcf95438..44b5fd3f12ff 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -669,7 +669,7 @@ GlobalObject::addIntrinsicValue(JSContext* cx, Handle global, Rooted base(cx, last->base()->unowned()); RootedId id(cx, NameToId(name)); - StackShape child(base, id, slot, 0, 0); + Rooted child(cx, StackShape(base, id, slot, 0, 0)); Shape* shape = cx->compartment()->propertyTree.getChild(cx, last, child); if (!shape) return false; diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 606316f9cfd2..25d065add92d 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -660,9 +660,9 @@ class NativeObject : public JSObject private: static Shape* getChildPropertyOnDictionary(ExclusiveContext* cx, HandleNativeObject obj, - HandleShape parent, StackShape& child); + HandleShape parent, MutableHandle child); static Shape* getChildProperty(ExclusiveContext* cx, HandleNativeObject obj, - HandleShape parent, StackShape& child); + HandleShape parent, MutableHandle child); public: /* Add a property whose id is not yet in this scope. */ diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index 8b0660b6977b..dc3c1f521a84 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -79,10 +79,9 @@ Shape::search(ExclusiveContext* cx, Shape* start, jsid id, ShapeTable::Entry** p } inline Shape* -Shape::new_(ExclusiveContext* cx, StackShape& unrootedOther, uint32_t nfixed) +Shape::new_(ExclusiveContext* cx, Handle other, uint32_t nfixed) { - RootedGeneric other(cx, &unrootedOther); - Shape* shape = other->isAccessorShape() + Shape* shape = other.isAccessorShape() ? js::Allocate(cx) : js::Allocate(cx); if (!shape) { @@ -90,10 +89,10 @@ Shape::new_(ExclusiveContext* cx, StackShape& unrootedOther, uint32_t nfixed) return nullptr; } - if (other->isAccessorShape()) - new (shape) AccessorShape(*other, nfixed); + if (other.isAccessorShape()) + new (shape) AccessorShape(other, nfixed); else - new (shape) Shape(*other, nfixed); + new (shape) Shape(other, nfixed); return shape; } diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 045988665e3f..ead74200c3a9 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -335,8 +335,8 @@ Shape::replaceLastProperty(ExclusiveContext* cx, StackBaseShape& base, if (!nbase) return nullptr; - StackShape child(shape); - child.base = nbase; + Rooted child(cx, StackShape(shape)); + child.setBase(nbase); return cx->compartment()->propertyTree.getChild(cx, shape->parent, child); } @@ -348,7 +348,7 @@ Shape::replaceLastProperty(ExclusiveContext* cx, StackBaseShape& base, */ /* static */ Shape* NativeObject::getChildPropertyOnDictionary(ExclusiveContext* cx, HandleNativeObject obj, - HandleShape parent, StackShape& child) + HandleShape parent, MutableHandle child) { /* * Shared properties have no slot, but slot_ will reflect that of parent. @@ -385,15 +385,14 @@ NativeObject::getChildPropertyOnDictionary(ExclusiveContext* cx, HandleNativeObj if (obj->inDictionaryMode()) { MOZ_ASSERT(parent == obj->lastProperty()); - RootedGeneric childRoot(cx, &child); - shape = childRoot->isAccessorShape() ? Allocate(cx) : Allocate(cx); + shape = child.isAccessorShape() ? Allocate(cx) : Allocate(cx); if (!shape) return nullptr; - if (childRoot->hasSlot() && childRoot->slot() >= obj->lastProperty()->base()->slotSpan()) { - if (!obj->setSlotSpan(cx, childRoot->slot() + 1)) + if (child.hasSlot() && child.slot() >= obj->lastProperty()->base()->slotSpan()) { + if (!obj->setSlotSpan(cx, child.slot() + 1)) return nullptr; } - shape->initDictionaryShape(*childRoot, obj->numFixedSlots(), &obj->shape_); + shape->initDictionaryShape(child, obj->numFixedSlots(), &obj->shape_); } return shape; @@ -401,13 +400,13 @@ NativeObject::getChildPropertyOnDictionary(ExclusiveContext* cx, HandleNativeObj /* static */ Shape* NativeObject::getChildProperty(ExclusiveContext* cx, - HandleNativeObject obj, HandleShape parent, StackShape& unrootedChild) + HandleNativeObject obj, HandleShape parent, + MutableHandle child) { - RootedGeneric child(cx, &unrootedChild); - Shape* shape = getChildPropertyOnDictionary(cx, obj, parent, *child); + Shape* shape = getChildPropertyOnDictionary(cx, obj, parent, child); if (!obj->inDictionaryMode()) { - shape = cx->compartment()->propertyTree.getChild(cx, parent, *child); + shape = cx->compartment()->propertyTree.getChild(cx, parent, child); if (!shape) return nullptr; //MOZ_ASSERT(shape->parent == parent); @@ -577,9 +576,9 @@ NativeObject::addPropertyInternal(ExclusiveContext* cx, return nullptr; } - StackShape child(nbase, id, slot, attrs, flags); + Rooted child(cx, StackShape(nbase, id, slot, attrs, flags)); child.updateGetterSetter(getter, setter); - shape = getChildProperty(cx, obj, last, child); + shape = getChildProperty(cx, obj, last, &child); } if (shape) { @@ -643,7 +642,7 @@ js::ReshapeForAllocKind(JSContext* cx, Shape* shape, TaggedProto proto, return nullptr; } - StackShape child(nbase, id, i, JSPROP_ENUMERATE, 0); + Rooted child(cx, StackShape(nbase, id, i, JSPROP_ENUMERATE, 0)); newShape = cx->compartment()->propertyTree.getChild(cx, newShape, child); if (!newShape) return nullptr; @@ -836,10 +835,10 @@ NativeObject::putProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId MOZ_ASSERT(shape == obj->lastProperty()); /* Find or create a property tree node labeled by our arguments. */ - StackShape child(nbase, id, slot, attrs, flags); + Rooted child(cx, StackShape(nbase, id, slot, attrs, flags)); child.updateGetterSetter(getter, setter); RootedShape parent(cx, shape->parent); - Shape* newShape = getChildProperty(cx, obj, parent, child); + Shape* newShape = getChildProperty(cx, obj, parent, &child); if (!newShape) { obj->checkShapeConsistency(); diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 6ceadc0b8381..99203669a270 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -735,7 +735,7 @@ class Shape : public gc::TenuredCell Shape(const Shape& other) = delete; /* Allocate a new shape based on the given StackShape. */ - static inline Shape* new_(ExclusiveContext* cx, StackShape& unrootedOther, uint32_t nfixed); + static inline Shape* new_(ExclusiveContext* cx, Handle other, uint32_t nfixed); /* * Whether this shape has a valid slot value. This may be true even if @@ -1098,7 +1098,7 @@ struct InitialShapeEntry typedef HashSet InitialShapeSet; -struct StackShape +struct StackShape : public JS::Traceable { /* For performance, StackShape only roots when absolutely necessary. */ UnownedBaseShape* base; @@ -1177,10 +1177,51 @@ struct StackShape return hash; } - // For RootedGeneric + // Traceable implementation. + static void trace(StackShape* stackShape, JSTracer* trc) { stackShape->trace(trc); } void trace(JSTracer* trc); }; +template +class StackShapeOperations { + const StackShape& ss() const { return static_cast(this)->get(); } + + public: + bool hasSlot() const { return ss().hasSlot(); } + bool hasMissingSlot() const { return ss().hasMissingSlot(); } + uint32_t slot() const { return ss().slot(); } + uint32_t maybeSlot() const { return ss().maybeSlot(); } + uint32_t slotSpan() const { return ss().slotSpan(); } + bool isAccessorShape() const { return ss().isAccessorShape(); } + uint8_t attrs() const { return ss().attrs; } +}; + +template +class MutableStackShapeOperations : public StackShapeOperations { + StackShape& ss() { return static_cast(this)->get(); } + + public: + void updateGetterSetter(GetterOp rawGetter, SetterOp rawSetter) { + ss().updateGetterSetter(rawGetter, rawSetter); + } + void setSlot(uint32_t slot) { ss().setSlot(slot); } + void setBase(UnownedBaseShape* base) { ss().base = base; } + void setAttrs(uint8_t attrs) { ss().attrs = attrs; } +}; + +template <> +class RootedBase : public MutableStackShapeOperations> +{}; + +template <> +class HandleBase : public StackShapeOperations> +{}; + +template <> +class MutableHandleBase + : public MutableStackShapeOperations> +{}; + inline Shape::Shape(const StackShape& other, uint32_t nfixed) : base_(other.base), diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index c1c8baeceab7..13cb4443be36 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -496,10 +496,9 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) for (size_t i = 0; i < layout.properties().length(); i++) { const UnboxedLayout::Property& property = layout.properties()[i]; - StackShape unrootedChild(shape->base()->unowned(), NameToId(property.name), i, - JSPROP_ENUMERATE, 0); - RootedGeneric child(cx, &unrootedChild); - shape = cx->compartment()->propertyTree.getChild(cx, shape, *child); + Rooted child(cx, StackShape(shape->base()->unowned(), NameToId(property.name), + i, JSPROP_ENUMERATE, 0)); + shape = cx->compartment()->propertyTree.getChild(cx, shape, child); if (!shape) return false; } From dafe6580393ce5b8a11cc9ae2da1a847077b88cb Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Fri, 7 Aug 2015 15:22:30 -0400 Subject: [PATCH 11/49] Bug 1189060 - let webrtcUI.jsm etc. block initial Offer/Answer exchange through hook. r=florian,fabrice,mfinkle,mt --HG-- extra : transplant_source : %CBwD%14%7D4%9E%EB%AC%5C7K%E4p%3Dr%8Fjl%8A --- browser/base/content/content.js | 2 + browser/modules/ContentWebRTC.jsm | 90 +++++++++++++++++++---- browser/modules/webrtcUI.jsm | 43 ++++++++++- dom/media/PeerConnection.js | 83 +++++++++++++++++---- mobile/android/chrome/content/WebrtcUI.js | 33 ++++++++- mobile/android/chrome/content/browser.js | 4 +- toolkit/modules/AppConstants.jsm | 8 ++ webapprt/WebRTCHandler.jsm | 13 +++- 8 files changed, 239 insertions(+), 37 deletions(-) diff --git a/browser/base/content/content.js b/browser/base/content/content.js index b5541e474c72..0e3436de2cf6 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -525,6 +525,8 @@ addEventListener("DOMServiceWorkerFocusClient", function(event) { }, false); ContentWebRTC.init(); +addMessageListener("rtcpeer:Allow", ContentWebRTC); +addMessageListener("rtcpeer:Deny", ContentWebRTC); addMessageListener("webrtc:Allow", ContentWebRTC); addMessageListener("webrtc:Deny", ContentWebRTC); addMessageListener("webrtc:StopSharing", ContentWebRTC); diff --git a/browser/modules/ContentWebRTC.jsm b/browser/modules/ContentWebRTC.jsm index e059c60d3d2f..f31f1cf65500 100644 --- a/browser/modules/ContentWebRTC.jsm +++ b/browser/modules/ContentWebRTC.jsm @@ -22,7 +22,8 @@ this.ContentWebRTC = { return; this._initialized = true; - Services.obs.addObserver(handleRequest, "getUserMedia:request", false); + Services.obs.addObserver(handleGUMRequest, "getUserMedia:request", false); + Services.obs.addObserver(handlePCRequest, "PeerConnection:request", false); Services.obs.addObserver(updateIndicators, "recording-device-events", false); Services.obs.addObserver(removeBrowserSpecificIndicator, "recording-window-ended", false); }, @@ -31,17 +32,31 @@ this.ContentWebRTC = { handleEvent: function(aEvent) { let contentWindow = aEvent.target.defaultView; let mm = getMessageManagerForWindow(contentWindow); - for (let key of contentWindow.pendingGetUserMediaRequests.keys()) + for (let key of contentWindow.pendingGetUserMediaRequests.keys()) { mm.sendAsyncMessage("webrtc:CancelRequest", key); + } + for (let key of contentWindow.pendingPeerConnectionRequests.keys()) { + mm.sendAsyncMessage("rtcpeer:CancelRequest", key); + } }, receiveMessage: function(aMessage) { switch (aMessage.name) { - case "webrtc:Allow": + case "rtcpeer:Allow": + case "rtcpeer:Deny": { + let callID = aMessage.data.callID; + let contentWindow = Services.wm.getOuterWindowWithId(aMessage.data.windowID); + forgetPCRequest(contentWindow, callID); + let topic = (aMessage.name == "rtcpeer:Allow") ? "PeerConnection:response:allow" : + "PeerConnection:response:deny"; + Services.obs.notifyObservers(null, topic, callID); + break; + } + case "webrtc:Allow": { let callID = aMessage.data.callID; let contentWindow = Services.wm.getOuterWindowWithId(aMessage.data.windowID); let devices = contentWindow.pendingGetUserMediaRequests.get(callID); - forgetRequest(contentWindow, callID); + forgetGUMRequest(contentWindow, callID); let allowedDevices = Cc["@mozilla.org/supports-array;1"] .createInstance(Ci.nsISupportsArray); @@ -50,8 +65,9 @@ this.ContentWebRTC = { Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", callID); break; + } case "webrtc:Deny": - denyRequest(aMessage.data); + denyGUMRequest(aMessage.data); break; case "webrtc:StopSharing": Services.obs.notifyObservers(null, "getUserMedia:revoke", aMessage.data); @@ -60,7 +76,30 @@ this.ContentWebRTC = { } }; -function handleRequest(aSubject, aTopic, aData) { +function handlePCRequest(aSubject, aTopic, aData) { + // Need to access JS object behind XPCOM wrapper added by observer API (using a + // WebIDL interface didn't work here as object comes from JSImplemented code). + aSubject = aSubject.wrappedJSObject; + let { windowID, callID, isSecure } = aSubject; + let contentWindow = Services.wm.getOuterWindowWithId(windowID); + + if (!contentWindow.pendingPeerConnectionRequests) { + setupPendingListsInitially(contentWindow); + } + contentWindow.pendingPeerConnectionRequests.add(callID); + + let request = { + callID: callID, + windowID: windowID, + documentURI: contentWindow.document.documentURI, + secure: isSecure, + }; + + let mm = getMessageManagerForWindow(contentWindow); + mm.sendAsyncMessage("rtcpeer:Request", request); +} + +function handleGUMRequest(aSubject, aTopic, aData) { let constraints = aSubject.getConstraints(); let secure = aSubject.isSecure; let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID); @@ -74,7 +113,7 @@ function handleRequest(aSubject, aTopic, aData) { function (error) { // bug 827146 -- In the future, the UI should catch NotFoundError // and allow the user to plug in a device, instead of immediately failing. - denyRequest({callID: aSubject.callID}, error); + denyGUMRequest({callID: aSubject.callID}, error); }, aSubject.innerWindowID); } @@ -123,13 +162,12 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec requestTypes.push(sharingAudio ? "AudioCapture" : "Microphone"); if (!requestTypes.length) { - denyRequest({callID: aCallID}, "NotFoundError"); + denyGUMRequest({callID: aCallID}, "NotFoundError"); return; } if (!aContentWindow.pendingGetUserMediaRequests) { - aContentWindow.pendingGetUserMediaRequests = new Map(); - aContentWindow.addEventListener("unload", ContentWebRTC); + setupPendingListsInitially(aContentWindow); } aContentWindow.pendingGetUserMediaRequests.set(aCallID, devices); @@ -149,7 +187,7 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec mm.sendAsyncMessage("webrtc:Request", request); } -function denyRequest(aData, aError) { +function denyGUMRequest(aData, aError) { let msg = null; if (aError) { msg = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); @@ -161,16 +199,36 @@ function denyRequest(aData, aError) { return; let contentWindow = Services.wm.getOuterWindowWithId(aData.windowID); if (contentWindow.pendingGetUserMediaRequests) - forgetRequest(contentWindow, aData.callID); + forgetGUMRequest(contentWindow, aData.callID); } -function forgetRequest(aContentWindow, aCallID) { +function forgetGUMRequest(aContentWindow, aCallID) { aContentWindow.pendingGetUserMediaRequests.delete(aCallID); - if (aContentWindow.pendingGetUserMediaRequests.size) - return; + forgetPendingListsEventually(aContentWindow); +} - aContentWindow.removeEventListener("unload", ContentWebRTC); +function forgetPCRequest(aContentWindow, aCallID) { + aContentWindow.pendingPeerConnectionRequests.delete(aCallID); + forgetPendingListsEventually(aContentWindow); +} + +function setupPendingListsInitially(aContentWindow) { + if (aContentWindow.pendingGetUserMediaRequests) { + return; + } + aContentWindow.pendingGetUserMediaRequests = new Map(); + aContentWindow.pendingPeerConnectionRequests = new Set(); + aContentWindow.addEventListener("unload", ContentWebRTC); +} + +function forgetPendingListsEventually(aContentWindow) { + if (aContentWindow.pendingGetUserMediaRequests.size || + aContentWindow.pendingPeerConnectionRequests.size) { + return; + } aContentWindow.pendingGetUserMediaRequests = null; + aContentWindow.pendingPeerConnectionRequests = null; + aContentWindow.removeEventListener("unload", ContentWebRTC); } function updateIndicators() { diff --git a/browser/modules/webrtcUI.jsm b/browser/modules/webrtcUI.jsm index 792c58bf1dcd..94988ff0a876 100644 --- a/browser/modules/webrtcUI.jsm +++ b/browser/modules/webrtcUI.jsm @@ -29,6 +29,8 @@ this.webrtcUI = { let mm = Cc["@mozilla.org/globalmessagemanager;1"] .getService(Ci.nsIMessageListenerManager); + mm.addMessageListener("rtcpeer:Request", this); + mm.addMessageListener("rtcpeer:CancelRequest", this); mm.addMessageListener("webrtc:Request", this); mm.addMessageListener("webrtc:CancelRequest", this); mm.addMessageListener("webrtc:UpdateBrowserIndicators", this); @@ -44,6 +46,8 @@ this.webrtcUI = { let mm = Cc["@mozilla.org/globalmessagemanager;1"] .getService(Ci.nsIMessageListenerManager); + mm.removeMessageListener("rtcpeer:Request", this); + mm.removeMessageListener("rtcpeer:CancelRequest", this); mm.removeMessageListener("webrtc:Request", this); mm.removeMessageListener("webrtc:CancelRequest", this); mm.removeMessageListener("webrtc:UpdateBrowserIndicators", this); @@ -124,6 +128,43 @@ this.webrtcUI = { receiveMessage: function(aMessage) { switch (aMessage.name) { + + // Add-ons can override stock permission behavior by doing: + // + // var stockReceiveMessage = webrtcUI.receiveMessage; + // + // webrtcUI.receiveMessage = function(aMessage) { + // switch (aMessage.name) { + // case "rtcpeer:Request": { + // // new code. + // break; + // ... + // default: + // return stockReceiveMessage.call(this, aMessage); + // + // Intercepting gUM and peerConnection requests should let an add-on + // limit PeerConnection activity with automatic rules and/or prompts + // in a sensible manner that avoids double-prompting in typical + // gUM+PeerConnection scenarios. For example: + // + // State Sample Action + // -------------------------------------------------------------- + // No IP leaked yet + No gUM granted Warn user + // No IP leaked yet + gUM granted Avoid extra dialog + // No IP leaked yet + gUM request pending. Delay until gUM grant + // IP already leaked Too late to warn + + case "rtcpeer:Request": { + // Always allow. This code-point exists for add-ons to override. + let request = aMessage.data; + let mm = aMessage.target.messageManager; + mm.sendAsyncMessage("rtcpeer:Allow", { callID: request.callID, + windowID: request.windowID }); + break; + } + case "rtcpeer:CancelRequest": + // No data to release. This code-point exists for add-ons to override. + break; case "webrtc:Request": prompt(aMessage.target, aMessage.data); break; @@ -441,7 +482,7 @@ function prompt(aBrowser, aRequest) { return; } - let mm = notification.browser.messageManager + let mm = notification.browser.messageManager; mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID, windowID: aRequest.windowID, devices: allowedDevices}); diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index c67365daff04..a1c762847097 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -13,6 +13,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "PeerConnectionIdp", "resource://gre/modules/media/PeerConnectionIdp.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "convertToRTCStatsReport", "resource://gre/modules/media/RTCStatsReport.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "AppConstants", + "resource://gre/modules/AppConstants.jsm"); const PC_CONTRACT = "@mozilla.org/dom/peerconnection;1"; const PC_OBS_CONTRACT = "@mozilla.org/dom/peerconnectionobserver;1"; @@ -40,11 +42,14 @@ function GlobalPCList() { this._list = {}; this._networkdown = false; // XXX Need to query current state somehow this._lifecycleobservers = {}; + this._nextId = 1; Services.obs.addObserver(this, "inner-window-destroyed", true); Services.obs.addObserver(this, "profile-change-net-teardown", true); Services.obs.addObserver(this, "network:offline-about-to-go-offline", true); Services.obs.addObserver(this, "network:offline-status-changed", true); Services.obs.addObserver(this, "gmp-plugin-crash", true); + Services.obs.addObserver(this, "PeerConnection:response:allow", true); + Services.obs.addObserver(this, "PeerConnection:response:deny", true); if (Cc["@mozilla.org/childprocessmessagemanager;1"]) { let mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsIMessageListenerManager); mm.addMessageListener("gmp-plugin-crash", this); @@ -78,9 +83,23 @@ GlobalPCList.prototype = { } else { this._list[winID] = [Cu.getWeakReference(pc)]; } + pc._globalPCListId = this._nextId++; this.removeNullRefs(winID); }, + findPC: function(globalPCListId) { + for (let winId in this._list) { + if (this._list.hasOwnProperty(winId)) { + for (let pcref of this._list[winId]) { + let pc = pcref.get(); + if (pc && pc._globalPCListId == globalPCListId) { + return pc; + } + } + } + } + }, + removeNullRefs: function(winID) { if (this._list[winID] === undefined) { return; @@ -187,6 +206,18 @@ GlobalPCList.prototype = { let data = { pluginID, pluginName }; this.handleGMPCrash(data); } + } else if (topic == "PeerConnection:response:allow" || + topic == "PeerConnection:response:deny") { + var pc = this.findPC(data); + if (pc) { + if (topic == "PeerConnection:response:allow") { + pc._settlePermission.allow(); + } else { + let err = new pc._win.DOMException("The operation is insecure.", + "SecurityError"); + pc._settlePermission.deny(err); + } + } } }, @@ -355,6 +386,7 @@ RTCPeerConnection.prototype = { } // Save the appId this._appId = Cu.getWebIDLCallerPrincipal().appId; + this._https = this._win.document.documentURIObject.schemeIs("https"); // Get the offline status for this appId let appOffline = false; @@ -690,13 +722,12 @@ RTCPeerConnection.prototype = { let origin = Cu.getWebIDLCallerPrincipal().origin; return this._chain(() => { - let p = this._certificateReady.then( - () => new this._win.Promise((resolve, reject) => { + let p = Promise.all([this.getPermission(), this._certificateReady]) + .then(() => new this._win.Promise((resolve, reject) => { this._onCreateOfferSuccess = resolve; this._onCreateOfferFailure = reject; this._impl.createOffer(options); - }) - ); + })); p = this._addIdentityAssertion(p, origin); return p.then( sdp => new this._win.mozRTCSessionDescription({ type: "offer", sdp: sdp })); @@ -715,8 +746,8 @@ RTCPeerConnection.prototype = { return this._legacyCatch(onSuccess, onError, () => { let origin = Cu.getWebIDLCallerPrincipal().origin; return this._chain(() => { - let p = this._certificateReady.then( - () => new this._win.Promise((resolve, reject) => { + let p = Promise.all([this.getPermission(), this._certificateReady]) + .then(() => new this._win.Promise((resolve, reject) => { // We give up line-numbers in errors by doing this here, but do all // state-checks inside the chain, to support the legacy feature that // callers don't have to wait for setRemoteDescription to finish. @@ -731,8 +762,7 @@ RTCPeerConnection.prototype = { this._onCreateAnswerSuccess = resolve; this._onCreateAnswerFailure = reject; this._impl.createAnswer(); - }) - ); + })); p = this._addIdentityAssertion(p, origin); return p.then(sdp => { return new this._win.mozRTCSessionDescription({ type: "answer", sdp: sdp }); @@ -741,6 +771,27 @@ RTCPeerConnection.prototype = { }); }, + getPermission: function() { + if (this._havePermission) { + return this._havePermission; + } + if (AppConstants.MOZ_B2G || + Services.prefs.getBoolPref("media.navigator.permission.disabled")) { + return this._havePermission = Promise.resolve(); + } + return this._havePermission = new Promise((resolve, reject) => { + this._settlePermission = { allow: resolve, deny: reject }; + let outerId = this._win.QueryInterface(Ci.nsIInterfaceRequestor). + getInterface(Ci.nsIDOMWindowUtils).outerWindowID; + let request = { windowID: outerId, + innerWindowId: this._winID, + callID: this._globalPCListId, + isSecure: this._https }; + request.wrappedJSObject = request; + Services.obs.notifyObservers(request, "PeerConnection:request", null); + }); + }, + setLocalDescription: function(desc, onSuccess, onError) { return this._legacyCatch(onSuccess, onError, () => { this._localType = desc.type; @@ -771,11 +822,12 @@ RTCPeerConnection.prototype = { "InvalidParameterError"); } - return this._chain(() => new this._win.Promise((resolve, reject) => { + return this._chain(() => this.getPermission() + .then(() => new this._win.Promise((resolve, reject) => { this._onSetLocalDescriptionSuccess = resolve; this._onSetLocalDescriptionFailure = reject; this._impl.setLocalDescription(type, desc.sdp); - })); + }))); }); }, @@ -858,11 +910,12 @@ RTCPeerConnection.prototype = { let origin = Cu.getWebIDLCallerPrincipal().origin; return this._chain(() => { - let setRem = new this._win.Promise((resolve, reject) => { - this._onSetRemoteDescriptionSuccess = resolve; - this._onSetRemoteDescriptionFailure = reject; - this._impl.setRemoteDescription(type, desc.sdp); - }); + let setRem = this.getPermission() + .then(() => new this._win.Promise((resolve, reject) => { + this._onSetRemoteDescriptionSuccess = resolve; + this._onSetRemoteDescriptionFailure = reject; + this._impl.setRemoteDescription(type, desc.sdp); + })); if (desc.type === "rollback") { return setRem; diff --git a/mobile/android/chrome/content/WebrtcUI.js b/mobile/android/chrome/content/WebrtcUI.js index 1efe59b34632..296bbb196011 100644 --- a/mobile/android/chrome/content/WebrtcUI.js +++ b/mobile/android/chrome/content/WebrtcUI.js @@ -3,14 +3,33 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; +this.EXPORTED_SYMBOLS = ["WebrtcUI"]; + XPCOMUtils.defineLazyModuleGetter(this, "Notifications", "resource://gre/modules/Notifications.jsm"); var WebrtcUI = { _notificationId: null, + // Add-ons can override stock permission behavior by doing: + // + // var stockObserve = WebrtcUI.observe; + // + // webrtcUI.observe = function(aSubject, aTopic, aData) { + // switch (aTopic) { + // case "PeerConnection:request": { + // // new code. + // break; + // ... + // default: + // return stockObserve.call(this, aSubject, aTopic, aData); + // + // See browser/modules/webrtcUI.jsm for details. + observe: function(aSubject, aTopic, aData) { if (aTopic === "getUserMedia:request") { - this.handleRequest(aSubject, aTopic, aData); + this.handleGumRequest(aSubject, aTopic, aData); + } else if (aTopic === "PeerConnection:request") { + this.handlePCRequest(aSubject, aTopic, aData); } else if (aTopic === "recording-device-events") { switch (aData) { case "shutdown": @@ -72,7 +91,17 @@ var WebrtcUI = { } }, - handleRequest: function handleRequest(aSubject, aTopic, aData) { + handlePCRequest: function handlePCRequest(aSubject, aTopic, aData) { + aSubject = aSubject.wrappedJSObject; + let { callID } = aSubject; + // Also available: windowID, isSecure, innerWindowID. For contentWindow do: + // + // let contentWindow = Services.wm.getOuterWindowWithId(windowID); + + Services.obs.notifyObservers(null, "PeerConnection:response:allow", callID); + }, + + handleGumRequest: function handleGumRequest(aSubject, aTopic, aData) { let constraints = aSubject.getConstraints(); let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID); diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index fdc523884570..f81d743214db 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -162,7 +162,9 @@ if (AppConstants.NIGHTLY_BUILD) { } if (AppConstants.MOZ_WEBRTC) { lazilyLoadedObserverScripts.push( - ["WebrtcUI", ["getUserMedia:request", "recording-device-events"], "chrome://browser/content/WebrtcUI.js"]) + ["WebrtcUI", ["getUserMedia:request", + "PeerConnection:request", + "recording-device-events"], "chrome://browser/content/WebrtcUI.js"]) } lazilyLoadedObserverScripts.forEach(function (aScript) { diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index c4ece380ac0a..5a278c2d2971 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -101,6 +101,14 @@ this.AppConstants = Object.freeze({ false, #endif +# MOZ_B2G covers both device and desktop b2g + MOZ_B2G: +#ifdef MOZ_B2G + true, +#else + false, +#endif + # NOTE! XP_LINUX has to go after MOZ_WIDGET_ANDROID otherwise Android # builds will be misidentified as linux. platform: diff --git a/webapprt/WebRTCHandler.jsm b/webapprt/WebRTCHandler.jsm index 2f2ba8b517eb..2ee7f279c637 100644 --- a/webapprt/WebRTCHandler.jsm +++ b/webapprt/WebRTCHandler.jsm @@ -13,7 +13,15 @@ let Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -function handleRequest(aSubject, aTopic, aData) { +function handlePCRequest(aSubject, aTopic, aData) { + aSubject = aSubject.wrappedJSObject; + let { windowID, innerWindowID, callID, isSecure } = aSubject; + let contentWindow = Services.wm.getOuterWindowWithId(windowID); + + Services.obs.notifyObservers(null, "PeerConnection:response:allow", callID); +} + +function handleGumRequest(aSubject, aTopic, aData) { let { windowID, callID } = aSubject; let constraints = aSubject.getConstraints(); let contentWindow = Services.wm.getOuterWindowWithId(windowID); @@ -100,4 +108,5 @@ function denyRequest(aCallID, aError) { Services.obs.notifyObservers(msg, "getUserMedia:response:deny", aCallID); } -Services.obs.addObserver(handleRequest, "getUserMedia:request", false); +Services.obs.addObserver(handleGumRequest, "getUserMedia:request", false); +Services.obs.addObserver(handlePCRequest, "PeerConnection:request", false); From 27be58a915de077a33d12b33c821e2662a1b5a99 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 11 Aug 2015 13:48:55 -0400 Subject: [PATCH 12/49] Bug 1189060 - add CreateOfferRequest.webidl interface for add-ons r=florian,peterv --HG-- extra : transplant_source : %97%9C%D9%9Bx%21%01_6%29%98T%9C%0F%CE%E3%40%A0%8AE --- browser/modules/ContentWebRTC.jsm | 8 +++----- browser/modules/webrtcUI.jsm | 10 +++++++--- dom/media/PeerConnection.js | 27 +++++++++++++++++++++------ dom/media/PeerConnection.manifest | 2 ++ dom/webidl/CreateOfferRequest.webidl | 16 ++++++++++++++++ dom/webidl/moz.build | 1 + 6 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 dom/webidl/CreateOfferRequest.webidl diff --git a/browser/modules/ContentWebRTC.jsm b/browser/modules/ContentWebRTC.jsm index f31f1cf65500..38d3fc0d859c 100644 --- a/browser/modules/ContentWebRTC.jsm +++ b/browser/modules/ContentWebRTC.jsm @@ -77,10 +77,7 @@ this.ContentWebRTC = { }; function handlePCRequest(aSubject, aTopic, aData) { - // Need to access JS object behind XPCOM wrapper added by observer API (using a - // WebIDL interface didn't work here as object comes from JSImplemented code). - aSubject = aSubject.wrappedJSObject; - let { windowID, callID, isSecure } = aSubject; + let { windowID, innerWindowID, callID, isSecure } = aSubject; let contentWindow = Services.wm.getOuterWindowWithId(windowID); if (!contentWindow.pendingPeerConnectionRequests) { @@ -89,8 +86,9 @@ function handlePCRequest(aSubject, aTopic, aData) { contentWindow.pendingPeerConnectionRequests.add(callID); let request = { - callID: callID, windowID: windowID, + innerWindowID: innerWindowID, + callID: callID, documentURI: contentWindow.document.documentURI, secure: isSecure, }; diff --git a/browser/modules/webrtcUI.jsm b/browser/modules/webrtcUI.jsm index 94988ff0a876..8c7f71c6ddff 100644 --- a/browser/modules/webrtcUI.jsm +++ b/browser/modules/webrtcUI.jsm @@ -156,10 +156,14 @@ this.webrtcUI = { case "rtcpeer:Request": { // Always allow. This code-point exists for add-ons to override. - let request = aMessage.data; + let { callID, windowID } = aMessage.data; + // Also available: isSecure, innerWindowID. For contentWindow: + // + // let contentWindow = Services.wm.getOuterWindowWithId(windowID); + let mm = aMessage.target.messageManager; - mm.sendAsyncMessage("rtcpeer:Allow", { callID: request.callID, - windowID: request.windowID }); + mm.sendAsyncMessage("rtcpeer:Allow", + { callID: callID, windowID: windowID }); break; } case "rtcpeer:CancelRequest": diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index a1c762847097..5c42b479febd 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -25,6 +25,7 @@ const PC_STATS_CONTRACT = "@mozilla.org/dom/rtcstatsreport;1"; const PC_STATIC_CONTRACT = "@mozilla.org/dom/peerconnectionstatic;1"; const PC_SENDER_CONTRACT = "@mozilla.org/dom/rtpsender;1"; const PC_RECEIVER_CONTRACT = "@mozilla.org/dom/rtpreceiver;1"; +const PC_COREQUEST_CONTRACT = "@mozilla.org/dom/createofferrequest;1"; const PC_CID = Components.ID("{bdc2e533-b308-4708-ac8e-a8bfade6d851}"); const PC_OBS_CID = Components.ID("{d1748d4c-7f6a-4dc5-add6-d55b7678537e}"); @@ -35,6 +36,7 @@ const PC_STATS_CID = Components.ID("{7fe6e18b-0da3-4056-bf3b-440ef3809e06}"); const PC_STATIC_CID = Components.ID("{0fb47c47-a205-4583-a9fc-cbadf8c95880}"); const PC_SENDER_CID = Components.ID("{4fff5d46-d827-4cd4-a970-8fd53977440e}"); const PC_RECEIVER_CID = Components.ID("{d974b814-8fde-411c-8c45-b86791b81030}"); +const PC_COREQUEST_CID = Components.ID("{74b2122d-65a8-4824-aa9e-3d664cb75dc2}"); // Global list of PeerConnection objects, so they can be cleaned up when // a page is torn down. (Maps inner window ID to an array of PC objects). @@ -783,11 +785,10 @@ RTCPeerConnection.prototype = { this._settlePermission = { allow: resolve, deny: reject }; let outerId = this._win.QueryInterface(Ci.nsIInterfaceRequestor). getInterface(Ci.nsIDOMWindowUtils).outerWindowID; - let request = { windowID: outerId, - innerWindowId: this._winID, - callID: this._globalPCListId, - isSecure: this._https }; - request.wrappedJSObject = request; + + let chrome = new CreateOfferRequest(outerId, this._winID, + this._globalPCListId, false); + let request = this._win.CreateOfferRequest._create(this._win, chrome); Services.obs.notifyObservers(request, "PeerConnection:request", null); }); }, @@ -1489,6 +1490,19 @@ RTCRtpReceiver.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]), }; +function CreateOfferRequest(windowID, innerWindowID, callID, isSecure) { + this.windowID = windowID; + this.innerWindowID = innerWindowID; + this.callID = callID; + this.isSecure = isSecure; +} +CreateOfferRequest.prototype = { + classDescription: "CreateOfferRequest", + classID: PC_COREQUEST_CID, + contractID: PC_COREQUEST_CONTRACT, + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]), +}; + this.NSGetFactory = XPCOMUtils.generateNSGetFactory( [GlobalPCList, RTCIceCandidate, @@ -1498,5 +1512,6 @@ this.NSGetFactory = XPCOMUtils.generateNSGetFactory( RTCRtpReceiver, RTCRtpSender, RTCStatsReport, - PeerConnectionObserver] + PeerConnectionObserver, + CreateOfferRequest] ); diff --git a/dom/media/PeerConnection.manifest b/dom/media/PeerConnection.manifest index 290ce0278101..d30fe3d6e4cc 100644 --- a/dom/media/PeerConnection.manifest +++ b/dom/media/PeerConnection.manifest @@ -7,6 +7,7 @@ component {7fe6e18b-0da3-4056-bf3b-440ef3809e06} PeerConnection.js component {0fb47c47-a205-4583-a9fc-cbadf8c95880} PeerConnection.js component {4fff5d46-d827-4cd4-a970-8fd53977440e} PeerConnection.js component {d974b814-8fde-411c-8c45-b86791b81030} PeerConnection.js +component {74b2122d-65a8-4824-aa9e-3d664cb75dc2} PeerConnection.js contract @mozilla.org/dom/peerconnection;1 {bdc2e533-b308-4708-ac8e-a8bfade6d851} contract @mozilla.org/dom/peerconnectionobserver;1 {d1748d4c-7f6a-4dc5-add6-d55b7678537e} @@ -17,3 +18,4 @@ contract @mozilla.org/dom/rtcstatsreport;1 {7fe6e18b-0da3-4056-bf3b-440ef3809e06 contract @mozilla.org/dom/peerconnectionstatic;1 {0fb47c47-a205-4583-a9fc-cbadf8c95880} contract @mozilla.org/dom/rtpsender;1 {4fff5d46-d827-4cd4-a970-8fd53977440e} contract @mozilla.org/dom/rtpreceiver;1 {d974b814-8fde-411c-8c45-b86791b81030} +contract @mozilla.org/dom/createofferrequest;1 {74b2122d-65a8-4824-aa9e-3d664cb75dc2} diff --git a/dom/webidl/CreateOfferRequest.webidl b/dom/webidl/CreateOfferRequest.webidl new file mode 100644 index 000000000000..134fe33fa206 --- /dev/null +++ b/dom/webidl/CreateOfferRequest.webidl @@ -0,0 +1,16 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This is an internal IDL file + */ + +[ChromeOnly, + JSImplementation="@mozilla.org/dom/createofferrequest;1"] +interface CreateOfferRequest { + readonly attribute unsigned long long windowID; + readonly attribute unsigned long long innerWindowID; + readonly attribute DOMString callID; + readonly attribute boolean isSecure; +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index aefdc0b8cc78..75855046b585 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -88,6 +88,7 @@ WEBIDL_FILES = [ 'ContainerBoxObject.webidl', 'ConvolverNode.webidl', 'Coordinates.webidl', + 'CreateOfferRequest.webidl', 'Crypto.webidl', 'CSPDictionaries.webidl', 'CSPReport.webidl', From 603eac64beb70ac522d9b925d27109b6570fac06 Mon Sep 17 00:00:00 2001 From: Nikhil Marathe Date: Fri, 24 Jul 2015 10:25:00 -0700 Subject: [PATCH 13/49] Bug 1187018 - Ensure feature is nulled out if it does not get added. r=khuey --HG-- extra : commitid : FdAv5R3QwMy extra : rebase_source : 2bf4d65ceabf60d506b3120776d19c31e3726965 --- dom/notification/Notification.cpp | 61 ++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index c7bca254a41a..5b8213db6c16 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -2088,11 +2088,13 @@ class CloseNotificationRunnable final : public WorkerMainThreadRunnable { Notification* mNotification; + bool mHadObserver; public: explicit CloseNotificationRunnable(Notification* aNotification) : WorkerMainThreadRunnable(aNotification->mWorkerPrivate) , mNotification(aNotification) + , mHadObserver(false) {} bool @@ -2102,26 +2104,54 @@ class CloseNotificationRunnable final // The Notify() take's responsibility of releasing the Notification. mNotification->mObserver->ForgetNotification(); mNotification->mObserver = nullptr; + mHadObserver = true; } mNotification->CloseInternal(); return true; } + + bool + HadObserver() + { + return mHadObserver; + } }; bool NotificationFeature::Notify(JSContext* aCx, Status aStatus) { - MOZ_ASSERT(aStatus >= Canceling); + if (aStatus >= Canceling) { + // CloseNotificationRunnable blocks the worker by pushing a sync event loop + // on the stack. Meanwhile, WorkerControlRunnables dispatched to the worker + // can still continue running. One of these is + // ReleaseNotificationControlRunnable that releases the notification, + // invalidating the notification and this feature. We hold this reference to + // keep the notification valid until we are done with it. + // + // An example of when the control runnable could get dispatched to the + // worker is if a Notification is created and the worker is immediately + // closed, but there is no permission to show it so that the main thread + // immediately drops the NotificationRef. In this case, this function blocks + // on the main thread, but the main thread dispatches the control runnable, + // invalidating mNotification. + nsRefPtr kungFuDeathGrip = mNotification; - // Dispatched to main thread, blocks on closing the Notification. - nsRefPtr r = - new CloseNotificationRunnable(mNotification); - r->Dispatch(aCx); + // Dispatched to main thread, blocks on closing the Notification. + nsRefPtr r = + new CloseNotificationRunnable(mNotification); + r->Dispatch(aCx); - mNotification->ReleaseObject(); - // From this point we cannot touch properties of this feature because - // ReleaseObject() may have led to the notification going away and the - // notification owns this feature! + // Only call ReleaseObject() to match the observer's NotificationRef + // ownership (since CloseNotificationRunnable asked the observer to drop the + // reference to the notification). + if (r->HadObserver()) { + mNotification->ReleaseObject(); + } + + // From this point we cannot touch properties of this feature because + // ReleaseObject() may have led to the notification going away and the + // notification owns this feature! + } return true; } @@ -2132,8 +2162,13 @@ Notification::RegisterFeature() mWorkerPrivate->AssertIsOnWorkerThread(); MOZ_ASSERT(!mFeature); mFeature = MakeUnique(this); - return mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(), - mFeature.get()); + bool added = mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(), + mFeature.get()); + if (!added) { + mFeature = nullptr; + } + + return added; } void @@ -2305,14 +2340,14 @@ Notification::CreateAndShow(nsIGlobalObject* aGlobal, // Make a structured clone of the aOptions.mData object JS::Rooted data(cx, aOptions.mData); notification->InitFromJSVal(cx, data, aRv); - if (aRv.Failed()) { + if (NS_WARN_IF(aRv.Failed())) { return nullptr; } notification->SetScope(aScope); auto ref = MakeUnique(notification); - if (!ref->Initialized()) { + if (NS_WARN_IF(!ref->Initialized())) { aRv.Throw(NS_ERROR_DOM_ABORT_ERR); return nullptr; } From 6e054174421c2f048da36af06465780858c17773 Mon Sep 17 00:00:00 2001 From: Nikhil Marathe Date: Tue, 11 Aug 2015 12:53:14 -0700 Subject: [PATCH 14/49] Bug 1193365 - Disable push debug. r=kitcambridge --HG-- extra : commitid : 9Gf6AN5z3TX extra : rebase_source : 9555cab8a9739e9a9af4fa682495e78a61fee727 --- dom/push/Push.js | 2 +- dom/push/PushClient.js | 4 +++- modules/libpref/init/all.js | 4 +--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dom/push/Push.js b/dom/push/Push.js index bbf7dcf8d7fa..01e222bc4a7b 100644 --- a/dom/push/Push.js +++ b/dom/push/Push.js @@ -5,7 +5,7 @@ "use strict"; // Don't modify this, instead set dom.push.debug. -let gDebuggingEnabled = true; +let gDebuggingEnabled = false; function debug(s) { if (gDebuggingEnabled) diff --git a/dom/push/PushClient.js b/dom/push/PushClient.js index dd03380ed5a0..c2ce2989888f 100644 --- a/dom/push/PushClient.js +++ b/dom/push/PushClient.js @@ -5,7 +5,7 @@ "use strict"; // Don't modify this, instead set dom.push.debug. -let gDebuggingEnabled = true; +let gDebuggingEnabled = false; function debug(s) { if (gDebuggingEnabled) @@ -20,6 +20,8 @@ const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); +gDebuggingEnabled = Services.prefs.getBoolPref("dom.push.debug"); + const kMessages = [ "PushService:Register:OK", "PushService:Register:KO", diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 0b64d0149b21..a61509d15eaf 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4458,9 +4458,7 @@ pref("dom.mozAlarms.enabled", false); pref("dom.push.enabled", false); -#if !defined(RELEASE_BUILD) -pref("dom.push.debug", true); -#endif +pref("dom.push.debug", false); pref("dom.push.serverURL", "wss://push.services.mozilla.com/"); pref("dom.push.userAgentID", ""); From f564deae5feca681a00910140d520652b02a9461 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 7 Aug 2015 19:27:14 -0700 Subject: [PATCH 15/49] Bug 1192466 - Prune header includes for SkiaGLGlue.h - r=bgirard --- gfx/2d/HelpersSkia.h | 75 ++-------------------------------- gfx/2d/RefPtrSkia.h | 83 ++++++++++++++++++++++++++++++++++++++ gfx/2d/moz.build | 1 + gfx/gl/SkiaGLGlue.cpp | 14 ++++++- gfx/gl/SkiaGLGlue.h | 40 +++++++++--------- gfx/thebes/gfxPlatform.cpp | 2 + 6 files changed, 122 insertions(+), 93 deletions(-) create mode 100644 gfx/2d/RefPtrSkia.h diff --git a/gfx/2d/HelpersSkia.h b/gfx/2d/HelpersSkia.h index 70233bcd7023..bade2d51e663 100644 --- a/gfx/2d/HelpersSkia.h +++ b/gfx/2d/HelpersSkia.h @@ -15,6 +15,7 @@ #endif #include "mozilla/Assertions.h" #include +#include "RefPtrSkia.h" namespace mozilla { namespace gfx { @@ -147,7 +148,7 @@ StrokeOptionsToPaint(SkPaint& aPaint, const StrokeOptions &aOptions) } SkDashPathEffect* dash = SkDashPathEffect::Create(&pattern.front(), - dashCount, + dashCount, SkFloatToScalar(aOptions.mDashOffset)); SkSafeUnref(aPaint.setPathEffect(dash)); } @@ -237,14 +238,14 @@ static inline SkColor ColorToSkColor(const Color &color, Float aAlpha) static inline SkRect RectToSkRect(const Rect& aRect) { - return SkRect::MakeXYWH(SkFloatToScalar(aRect.x), SkFloatToScalar(aRect.y), + return SkRect::MakeXYWH(SkFloatToScalar(aRect.x), SkFloatToScalar(aRect.y), SkFloatToScalar(aRect.width), SkFloatToScalar(aRect.height)); } static inline SkRect IntRectToSkRect(const IntRect& aRect) { - return SkRect::MakeXYWH(SkIntToScalar(aRect.x), SkIntToScalar(aRect.y), + return SkRect::MakeXYWH(SkIntToScalar(aRect.x), SkIntToScalar(aRect.y), SkIntToScalar(aRect.width), SkIntToScalar(aRect.height)); } @@ -289,74 +290,6 @@ ExtendModeToTileMode(ExtendMode aMode) return SkShader::kClamp_TileMode; } -// The following class was imported from Skia, which is under the -// following licence: -// -// Copyright (c) 2011 Google Inc. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -template class RefPtrSkia { -public: - RefPtrSkia() : fObj(NULL) {} - explicit RefPtrSkia(T* obj) : fObj(obj) { SkSafeRef(fObj); } - RefPtrSkia(const RefPtrSkia& o) : fObj(o.fObj) { SkSafeRef(fObj); } - ~RefPtrSkia() { SkSafeUnref(fObj); } - - RefPtrSkia& operator=(const RefPtrSkia& rp) { - SkRefCnt_SafeAssign(fObj, rp.fObj); - return *this; - } - RefPtrSkia& operator=(T* obj) { - SkRefCnt_SafeAssign(fObj, obj); - return *this; - } - - T* get() const { return fObj; } - T& operator*() const { return *fObj; } - T* operator->() const { return fObj; } - - RefPtrSkia& adopt(T* obj) { - SkSafeUnref(fObj); - fObj = obj; - return *this; - } - - typedef T* RefPtrSkia::*unspecified_bool_type; - operator unspecified_bool_type() const { - return fObj ? &RefPtrSkia::fObj : NULL; - } - -private: - T* fObj; -}; - -// End of code imported from Skia. - } // namespace gfx } // namespace mozilla diff --git a/gfx/2d/RefPtrSkia.h b/gfx/2d/RefPtrSkia.h new file mode 100644 index 000000000000..dc61d67abf44 --- /dev/null +++ b/gfx/2d/RefPtrSkia.h @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_REFPTRSKIA_H_ +#define MOZILLA_GFX_REFPTRSKIA_H_ + +namespace mozilla { +namespace gfx { + +// The following class was imported from Skia, which is under the +// following licence: +// +// Copyright (c) 2011 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +template class RefPtrSkia { +public: + RefPtrSkia() : fObj(NULL) {} + explicit RefPtrSkia(T* obj) : fObj(obj) { SkSafeRef(fObj); } + RefPtrSkia(const RefPtrSkia& o) : fObj(o.fObj) { SkSafeRef(fObj); } + ~RefPtrSkia() { SkSafeUnref(fObj); } + + RefPtrSkia& operator=(const RefPtrSkia& rp) { + SkRefCnt_SafeAssign(fObj, rp.fObj); + return *this; + } + RefPtrSkia& operator=(T* obj) { + SkRefCnt_SafeAssign(fObj, obj); + return *this; + } + + T* get() const { return fObj; } + T& operator*() const { return *fObj; } + T* operator->() const { return fObj; } + + RefPtrSkia& adopt(T* obj) { + SkSafeUnref(fObj); + fObj = obj; + return *this; + } + + typedef T* RefPtrSkia::*unspecified_bool_type; + operator unspecified_bool_type() const { + return fObj ? &RefPtrSkia::fObj : NULL; + } + +private: + T* fObj; +}; + +// End of code imported from Skia. + +} // namespace gfx +} // namespace mozilla + +#endif /* MOZILLA_GFX_REFPTRSKIA_H_ */ diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index 95f71ff9fd54..21eb5a9e3f3b 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -81,6 +81,7 @@ if CONFIG['MOZ_ENABLE_SKIA']: ] EXPORTS.mozilla.gfx += [ 'HelpersSkia.h', + 'RefPtrSkia.h', ] # Are we targeting x86 or x64? If so, build SSE2 files. diff --git a/gfx/gl/SkiaGLGlue.cpp b/gfx/gl/SkiaGLGlue.cpp index 9befec8c5ad0..1868ed4ea32a 100755 --- a/gfx/gl/SkiaGLGlue.cpp +++ b/gfx/gl/SkiaGLGlue.cpp @@ -872,7 +872,7 @@ static GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context) i->fFunctions.fDeleteVertexArrays = glDeleteVertexArrays_mozilla; i->fFunctions.fGenVertexArrays = glGenVertexArrays_mozilla; - // Desktop GL + // Desktop GL i->fFunctions.fGetTexLevelParameteriv = glGetTexLevelParameteriv_mozilla; i->fFunctions.fDrawBuffer = glDrawBuffer_mozilla; i->fFunctions.fReadBuffer = glReadBuffer_mozilla; @@ -899,3 +899,15 @@ SkiaGLGlue::SkiaGLGlue(GLContext* context) mGrGLInterface->fCallbackData = reinterpret_cast(this); mGrContext.adopt(GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)mGrGLInterface.get())); } + +SkiaGLGlue::~SkiaGLGlue() +{ + /* + * These members have inter-dependencies, but do not keep each other alive, so + * destruction order is very important here: mGrContext uses mGrGLInterface, and + * through it, uses mGLContext + */ + mGrContext = nullptr; + mGrGLInterface = nullptr; + mGLContext = nullptr; +} diff --git a/gfx/gl/SkiaGLGlue.h b/gfx/gl/SkiaGLGlue.h index 7278886df546..c7ef5a5eee0e 100755 --- a/gfx/gl/SkiaGLGlue.h +++ b/gfx/gl/SkiaGLGlue.h @@ -3,18 +3,22 @@ * 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/RefPtr.h" +#ifndef SKIA_GL_GLUE_H_ +#define SKIA_GL_GLUE_H_ #ifdef USE_SKIA_GPU -#include "GLContext.h" -#include "skia/include/gpu/gl/GrGLInterface.h" -#include "skia/include/gpu/GrContext.h" -#include "mozilla/gfx/HelpersSkia.h" +#include "mozilla/gfx/RefPtrSkia.h" +#include "mozilla/RefPtr.h" + +struct GrGLInterface; +class GrContext; namespace mozilla { namespace gl { +class GLContext; + class SkiaGLGlue : public GenericAtomicRefCounted { public: @@ -24,27 +28,18 @@ public: GrContext* GetGrContext() const { return mGrContext.get(); } protected: - virtual ~SkiaGLGlue() { - /* - * These members have inter-dependencies, but do not keep each other alive, so - * destruction order is very important here: mGrContext uses mGrGLInterface, and - * through it, uses mGLContext - */ - mGrContext = nullptr; - mGrGLInterface = nullptr; - mGLContext = nullptr; - } + virtual ~SkiaGLGlue(); private: RefPtr mGLContext; - mozilla::gfx::RefPtrSkia mGrGLInterface; - mozilla::gfx::RefPtrSkia mGrContext; + gfx::RefPtrSkia mGrGLInterface; + gfx::RefPtrSkia mGrContext; }; } // namespace gl } // namespace mozilla -#else +#else // USE_SKIA_GPU class GrContext; @@ -60,7 +55,10 @@ public: GLContext* GetGLContext() const { return nullptr; } GrContext* GetGrContext() const { return nullptr; } }; -} -} -#endif +} // namespace gl +} // namespace mozilla + +#endif // USE_SKIA_GPU + +#endif // SKIA_GL_GLUE_H_ diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 33eb20783fd6..dc5824606ef1 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -93,6 +93,8 @@ #ifdef USE_SKIA #include "skia/include/core/SkGraphics.h" # ifdef USE_SKIA_GPU +# include "skia/include/gpu/GrContext.h" +# include "skia/include/gpu/gl/GrGLInterface.h" # include "SkiaGLGlue.h" # endif #endif From 2654a75663ff2f44b935afd1b52cb16c89dae8ec Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 7 Aug 2015 19:29:53 -0700 Subject: [PATCH 16/49] Bug 1192472 - Only do supplemental isArray check if WorkAroundDriverBugs. - r=kamidphish --- dom/canvas/WebGLProgram.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/canvas/WebGLProgram.cpp b/dom/canvas/WebGLProgram.cpp index 73c05c26d9fd..6295baadfe18 100644 --- a/dom/canvas/WebGLProgram.cpp +++ b/dom/canvas/WebGLProgram.cpp @@ -171,7 +171,7 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl) // Uniforms - const bool needsCheckForArrays = true; + const bool needsCheckForArrays = gl->WorkAroundDriverBugs(); GLuint numActiveUniforms = 0; gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORMS, From 3b0a318c705cfcc56988d5b3045f32d06cae054f Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Wed, 1 Jul 2015 12:27:43 -0400 Subject: [PATCH 17/49] Bug 1192230 - clean up reference-counting in xpcom/; r=erahm --- xpcom/glue/nsArrayEnumerator.cpp | 17 +++++------------ xpcom/glue/nsEnumeratorUtils.cpp | 9 +++------ xpcom/io/nsAppFileLocationProvider.cpp | 6 ++---- xpcom/io/nsDirectoryService.cpp | 22 +++++++++------------- xpcom/io/nsInputStreamTee.cpp | 2 +- xpcom/io/nsLocalFileWin.cpp | 16 ++++++---------- xpcom/io/nsMultiplexInputStream.cpp | 8 ++------ xpcom/io/nsScriptableInputStream.cpp | 7 ++----- xpcom/io/nsStorageStream.cpp | 12 ++++-------- xpcom/io/nsStringStream.cpp | 19 ++++++------------- xpcom/io/nsUnicharInputStream.cpp | 6 +++--- 11 files changed, 43 insertions(+), 81 deletions(-) diff --git a/xpcom/glue/nsArrayEnumerator.cpp b/xpcom/glue/nsArrayEnumerator.cpp index 6873b16522b9..7457bde42d53 100644 --- a/xpcom/glue/nsArrayEnumerator.cpp +++ b/xpcom/glue/nsArrayEnumerator.cpp @@ -13,6 +13,7 @@ #include "nsCOMArray.h" #include "nsCOMPtr.h" +#include "mozilla/nsRefPtr.h" class nsSimpleArrayEnumerator final : public nsISimpleEnumerator { @@ -91,12 +92,8 @@ nsSimpleArrayEnumerator::GetNext(nsISupports** aResult) nsresult NS_NewArrayEnumerator(nsISimpleEnumerator** aResult, nsIArray* aArray) { - nsSimpleArrayEnumerator* enumer = new nsSimpleArrayEnumerator(aArray); - if (!enumer) { - return NS_ERROR_OUT_OF_MEMORY; - } - - NS_ADDREF(*aResult = enumer); + nsRefPtr enumer = new nsSimpleArrayEnumerator(aArray); + enumer.forget(aResult); return NS_OK; } @@ -210,11 +207,7 @@ nsresult NS_NewArrayEnumerator(nsISimpleEnumerator** aResult, const nsCOMArray_base& aArray) { - nsCOMArrayEnumerator* enumerator = new (aArray) nsCOMArrayEnumerator(); - if (!enumerator) { - return NS_ERROR_OUT_OF_MEMORY; - } - - NS_ADDREF(*aResult = enumerator); + nsRefPtr enumerator = new (aArray) nsCOMArrayEnumerator(); + enumerator.forget(aResult); return NS_OK; } diff --git a/xpcom/glue/nsEnumeratorUtils.cpp b/xpcom/glue/nsEnumeratorUtils.cpp index 37601831c140..9dcc4747cf63 100644 --- a/xpcom/glue/nsEnumeratorUtils.cpp +++ b/xpcom/glue/nsEnumeratorUtils.cpp @@ -12,6 +12,7 @@ #include "nsIStringEnumerator.h" #include "nsCOMPtr.h" +#include "mozilla/nsRefPtr.h" class EmptyEnumeratorImpl : public nsISimpleEnumerator @@ -163,12 +164,8 @@ nsresult NS_NewSingletonEnumerator(nsISimpleEnumerator** aResult, nsISupports* aSingleton) { - nsSingletonEnumerator* enumer = new nsSingletonEnumerator(aSingleton); - if (!enumer) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aResult = enumer; - NS_ADDREF(*aResult); + nsRefPtr enumer = new nsSingletonEnumerator(aSingleton); + enumer.forget(aResult); return NS_OK; } diff --git a/xpcom/io/nsAppFileLocationProvider.cpp b/xpcom/io/nsAppFileLocationProvider.cpp index 540f53fb471b..3d9a38eb5378 100644 --- a/xpcom/io/nsAppFileLocationProvider.cpp +++ b/xpcom/io/nsAppFileLocationProvider.cpp @@ -348,8 +348,7 @@ nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile, return rv; } - *aLocalFile = localDir; - NS_ADDREF(*aLocalFile); + localDir.forget(aLocalFile); return rv; } @@ -395,8 +394,7 @@ nsAppFileLocationProvider::GetDefaultUserProfileRoot(nsIFile** aLocalFile, } #endif - *aLocalFile = localDir; - NS_ADDREF(*aLocalFile); + localDir.forget(aLocalFile); return rv; } diff --git a/xpcom/io/nsDirectoryService.cpp b/xpcom/io/nsDirectoryService.cpp index c2abd140aa71..96e026ac77f2 100644 --- a/xpcom/io/nsDirectoryService.cpp +++ b/xpcom/io/nsDirectoryService.cpp @@ -76,18 +76,16 @@ nsDirectoryService::GetCurrentProcessDirectory(nsIFile** aFile) } if (dirService) { - nsCOMPtr aLocalFile; + nsCOMPtr localFile; dirService->Get(NS_XPCOM_INIT_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile), - getter_AddRefs(aLocalFile)); - if (aLocalFile) { - *aFile = aLocalFile; - NS_ADDREF(*aFile); + getter_AddRefs(localFile)); + if (localFile) { + localFile.forget(aFile); return NS_OK; } } - nsLocalFile* localFile = new nsLocalFile; - NS_ADDREF(localFile); + nsRefPtr localFile = new nsLocalFile; #ifdef XP_WIN wchar_t buf[MAX_PATH + 1]; @@ -101,7 +99,7 @@ nsDirectoryService::GetCurrentProcessDirectory(nsIFile** aFile) } localFile->InitWithPath(nsDependentString(buf)); - *aFile = localFile; + localFile.forget(aFile); return NS_OK; } @@ -125,7 +123,7 @@ nsDirectoryService::GetCurrentProcessDirectory(nsIFile** aFile) #endif rv = localFile->InitWithNativePath(nsDependentCString(buffer)); if (NS_SUCCEEDED(rv)) { - *aFile = localFile; + localFile.forget(aFile); } } CFRelease(parentURL); @@ -167,7 +165,7 @@ nsDirectoryService::GetCurrentProcessDirectory(nsIFile** aFile) if (moz5 && *moz5) { if (realpath(moz5, buf)) { localFile->InitWithNativePath(nsDependentCString(buf)); - *aFile = localFile; + localFile.forget(aFile); return NS_OK; } } @@ -184,14 +182,12 @@ nsDirectoryService::GetCurrentProcessDirectory(nsIFile** aFile) // Fall back to current directory. if (getcwd(buf, sizeof(buf))) { localFile->InitWithNativePath(nsDependentCString(buf)); - *aFile = localFile; + localFile.forget(aFile); return NS_OK; } #endif - NS_RELEASE(localFile); - NS_ERROR("unable to get current process directory"); return NS_ERROR_FAILURE; } // GetCurrentProcessDirectory() diff --git a/xpcom/io/nsInputStreamTee.cpp b/xpcom/io/nsInputStreamTee.cpp index 28fceb509e35..c31318913b55 100644 --- a/xpcom/io/nsInputStreamTee.cpp +++ b/xpcom/io/nsInputStreamTee.cpp @@ -358,7 +358,7 @@ NS_NewInputStreamTeeAsync(nsIInputStream** aResult, return rv; } - NS_ADDREF(*aResult = tee); + tee.forget(aResult); return rv; } diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index 3110773aa1e0..62ff8ce8d104 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -1179,8 +1179,8 @@ NS_IMETHODIMP nsLocalFile::Clone(nsIFile** aFile) { // Just copy-construct ourselves - *aFile = new nsLocalFile(*this); - NS_ADDREF(*aFile); + nsRefPtr file = new nsLocalFile(*this); + file.forget(aFile); return NS_OK; } @@ -3214,14 +3214,12 @@ nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator** aEntries) *aEntries = nullptr; if (mWorkingPath.EqualsLiteral("\\\\.")) { - nsDriveEnumerator* drives = new nsDriveEnumerator; - NS_ADDREF(drives); + nsRefPtr drives = new nsDriveEnumerator; rv = drives->Init(); if (NS_FAILED(rv)) { - NS_RELEASE(drives); return rv; } - *aEntries = drives; + drives.forget(aEntries); return NS_OK; } @@ -3360,20 +3358,18 @@ nsLocalFile::Launch() nsresult NS_NewLocalFile(const nsAString& aPath, bool aFollowLinks, nsIFile** aResult) { - nsLocalFile* file = new nsLocalFile(); - NS_ADDREF(file); + nsRefPtr file = new nsLocalFile(); file->SetFollowLinks(aFollowLinks); if (!aPath.IsEmpty()) { nsresult rv = file->InitWithPath(aPath); if (NS_FAILED(rv)) { - NS_RELEASE(file); return rv; } } - *aResult = file; + file.forget(aResult); return NS_OK; } diff --git a/xpcom/io/nsMultiplexInputStream.cpp b/xpcom/io/nsMultiplexInputStream.cpp index 5926458d492f..4b61d5108cae 100644 --- a/xpcom/io/nsMultiplexInputStream.cpp +++ b/xpcom/io/nsMultiplexInputStream.cpp @@ -696,13 +696,9 @@ nsMultiplexInputStreamConstructor(nsISupports* aOuter, return NS_ERROR_NO_AGGREGATION; } - nsMultiplexInputStream* inst = new nsMultiplexInputStream(); + nsRefPtr inst = new nsMultiplexInputStream(); - NS_ADDREF(inst); - nsresult rv = inst->QueryInterface(aIID, aResult); - NS_RELEASE(inst); - - return rv; + return inst->QueryInterface(aIID, aResult); } void diff --git a/xpcom/io/nsScriptableInputStream.cpp b/xpcom/io/nsScriptableInputStream.cpp index c0e7c5b72e0a..7fdbb711545e 100644 --- a/xpcom/io/nsScriptableInputStream.cpp +++ b/xpcom/io/nsScriptableInputStream.cpp @@ -129,9 +129,6 @@ nsScriptableInputStream::Create(nsISupports* aOuter, REFNSIID aIID, return NS_ERROR_NO_AGGREGATION; } - nsScriptableInputStream* sis = new nsScriptableInputStream(); - NS_ADDREF(sis); - nsresult rv = sis->QueryInterface(aIID, aResult); - NS_RELEASE(sis); - return rv; + nsRefPtr sis = new nsScriptableInputStream(); + return sis->QueryInterface(aIID, aResult); } diff --git a/xpcom/io/nsStorageStream.cpp b/xpcom/io/nsStorageStream.cpp index f982130af250..2ff6f38d555d 100644 --- a/xpcom/io/nsStorageStream.cpp +++ b/xpcom/io/nsStorageStream.cpp @@ -400,17 +400,15 @@ nsStorageStream::NewInputStream(int32_t aStartingOffset, return NS_ERROR_NOT_INITIALIZED; } - nsStorageInputStream* inputStream = + nsRefPtr inputStream = new nsStorageInputStream(this, mSegmentSize); - NS_ADDREF(inputStream); nsresult rv = inputStream->Seek(aStartingOffset); if (NS_FAILED(rv)) { - NS_RELEASE(inputStream); return rv; } - *aInputStream = inputStream; + inputStream.forget(aInputStream); return NS_OK; } @@ -625,14 +623,12 @@ nsresult NS_NewStorageStream(uint32_t aSegmentSize, uint32_t aMaxSize, nsIStorageStream** aResult) { - nsStorageStream* storageStream = new nsStorageStream(); - NS_ADDREF(storageStream); + nsRefPtr storageStream = new nsStorageStream(); nsresult rv = storageStream->Init(aSegmentSize, aMaxSize); if (NS_FAILED(rv)) { - NS_RELEASE(storageStream); return rv; } - *aResult = storageStream; + storageStream.forget(aResult); return NS_OK; } diff --git a/xpcom/io/nsStringStream.cpp b/xpcom/io/nsStringStream.cpp index 3735eda3bf13..80aa0edeb57f 100644 --- a/xpcom/io/nsStringStream.cpp +++ b/xpcom/io/nsStringStream.cpp @@ -380,8 +380,7 @@ NS_NewByteInputStream(nsIInputStream** aStreamResult, { NS_PRECONDITION(aStreamResult, "null out ptr"); - nsStringInputStream* stream = new nsStringInputStream(); - NS_ADDREF(stream); + nsRefPtr stream = new nsStringInputStream(); nsresult rv; switch (aAssignment) { @@ -400,11 +399,10 @@ NS_NewByteInputStream(nsIInputStream** aStreamResult, } if (NS_FAILED(rv)) { - NS_RELEASE(stream); return rv; } - *aStreamResult = stream; + stream.forget(aStreamResult); return NS_OK; } @@ -422,12 +420,11 @@ NS_NewCStringInputStream(nsIInputStream** aStreamResult, { NS_PRECONDITION(aStreamResult, "null out ptr"); - nsStringInputStream* stream = new nsStringInputStream(); - NS_ADDREF(stream); + nsRefPtr stream = new nsStringInputStream(); stream->SetData(aStringToRead); - *aStreamResult = stream; + stream.forget(aStreamResult); return NS_OK; } @@ -442,10 +439,6 @@ nsStringInputStreamConstructor(nsISupports* aOuter, REFNSIID aIID, return NS_ERROR_NO_AGGREGATION; } - nsStringInputStream* inst = new nsStringInputStream(); - NS_ADDREF(inst); - nsresult rv = inst->QueryInterface(aIID, aResult); - NS_RELEASE(inst); - - return rv; + nsRefPtr inst = new nsStringInputStream(); + return inst->QueryInterface(aIID, aResult); } diff --git a/xpcom/io/nsUnicharInputStream.cpp b/xpcom/io/nsUnicharInputStream.cpp index 02bfc983c00a..47d9d06f15c7 100644 --- a/xpcom/io/nsUnicharInputStream.cpp +++ b/xpcom/io/nsUnicharInputStream.cpp @@ -412,9 +412,9 @@ NS_IMETHODIMP nsSimpleUnicharStreamFactory::CreateInstanceFromString(const nsAString& aString, nsIUnicharInputStream** aResult) { - StringUnicharInputStream* it = new StringUnicharInputStream(aString); + nsRefPtr it = new StringUnicharInputStream(aString); - NS_ADDREF(*aResult = it); + it.forget(aResult); return NS_OK; } @@ -432,7 +432,7 @@ nsSimpleUnicharStreamFactory::CreateInstanceFromUTF8Stream( return rv; } - NS_ADDREF(*aResult = it); + it.forget(aResult); return NS_OK; } From 8f318ea9507a497da70d191f7e033a76d813c4e2 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Wed, 1 Jul 2015 13:10:53 -0400 Subject: [PATCH 18/49] Bug 1193021 - clean up reference-counting in security/; r=keeler --- security/manager/ssl/nsCertPicker.cpp | 12 ++---------- security/manager/ssl/nsNSSASN1Object.cpp | 7 +++---- security/manager/ssl/nsNSSCertHelper.cpp | 15 +++++---------- security/manager/ssl/nsNSSCertificate.cpp | 14 +++++--------- security/manager/ssl/nsNSSCertificateDB.cpp | 8 +++----- security/manager/ssl/nsPK11TokenDB.cpp | 8 ++++---- security/manager/ssl/nsPKCS11Slot.cpp | 18 ++++++------------ 7 files changed, 28 insertions(+), 54 deletions(-) diff --git a/security/manager/ssl/nsCertPicker.cpp b/security/manager/ssl/nsCertPicker.cpp index ad6d9f28f9a6..417a3c9e8a88 100644 --- a/security/manager/ssl/nsCertPicker.cpp +++ b/security/manager/ssl/nsCertPicker.cpp @@ -163,21 +163,13 @@ NS_IMETHODIMP nsCertPicker::PickByUsage(nsIInterfaceRequestor *ctx, ++i, node = CERT_LIST_NEXT(node)) { if (i == selectedIndex) { - nsNSSCertificate *cert = nsNSSCertificate::Create(node->cert); + nsRefPtr cert = nsNSSCertificate::Create(node->cert); if (!cert) { rv = NS_ERROR_OUT_OF_MEMORY; break; } - nsIX509Cert *x509 = 0; - nsresult rv = cert->QueryInterface(NS_GET_IID(nsIX509Cert), (void**)&x509); - if (NS_FAILED(rv)) { - break; - } - - NS_ADDREF(x509); - *_retval = x509; - NS_RELEASE(cert); + cert.forget(_retval); break; } } diff --git a/security/manager/ssl/nsNSSASN1Object.cpp b/security/manager/ssl/nsNSSASN1Object.cpp index e1c22f58d9ba..d118e78246e1 100644 --- a/security/manager/ssl/nsNSSASN1Object.cpp +++ b/security/manager/ssl/nsNSSASN1Object.cpp @@ -196,12 +196,11 @@ CreateFromDER(unsigned char *data, sequence->GetASN1Objects(getter_AddRefs(elements)); nsCOMPtr asn1Obj = do_QueryElementAt(elements, 0); - *retval = asn1Obj; - if (!*retval) + if (!asn1Obj) { return NS_ERROR_FAILURE; + } - NS_ADDREF(*retval); - + asn1Obj.forget(retval); } return rv; } diff --git a/security/manager/ssl/nsNSSCertHelper.cpp b/security/manager/ssl/nsNSSCertHelper.cpp index fe15c9e0f71b..13e230d08a7a 100644 --- a/security/manager/ssl/nsNSSCertHelper.cpp +++ b/security/manager/ssl/nsNSSCertHelper.cpp @@ -130,8 +130,7 @@ ProcessVersion(SECItem *versionItem, if (NS_FAILED(rv)) return rv; - *retItem = printableItem; - NS_ADDREF(*retItem); + printableItem.forget(retItem); return NS_OK; } @@ -158,8 +157,7 @@ ProcessSerialNumberDER(SECItem *serialItem, return NS_ERROR_OUT_OF_MEMORY; rv = printableItem->SetDisplayValue(NS_ConvertASCIItoUTF16(serialNumber)); - *retItem = printableItem; - NS_ADDREF(*retItem); + printableItem.forget(retItem); return rv; } @@ -1610,8 +1608,7 @@ ProcessSingleExtension(CERTCertExtension *extension, text.Append(extvalue); extensionItem->SetDisplayValue(text); - *retExtension = extensionItem; - NS_ADDREF(*retExtension); + extensionItem.forget(retExtension); return NS_OK; } @@ -1656,8 +1653,7 @@ ProcessSECAlgorithmID(SECAlgorithmID *algID, } printableItem->SetDisplayValue(text); } - *retSequence = sequence; - NS_ADDREF(*retSequence); + sequence.forget(retSequence); return NS_OK; } @@ -2012,8 +2008,7 @@ nsNSSCertificate::CreateTBSCertificateASN1Struct(nsIASN1Sequence **retSequence, if (NS_FAILED(rv)) return rv; } - *retSequence = sequence; - NS_ADDREF(*retSequence); + sequence.forget(retSequence); return NS_OK; } diff --git a/security/manager/ssl/nsNSSCertificate.cpp b/security/manager/ssl/nsNSSCertificate.cpp index 2a10bb32c603..075022926e1c 100644 --- a/security/manager/ssl/nsNSSCertificate.cpp +++ b/security/manager/ssl/nsNSSCertificate.cpp @@ -787,8 +787,7 @@ nsNSSCertificate::GetIssuer(nsIX509Cert** aIssuer) if (!cert) { return NS_ERROR_UNEXPECTED; } - *aIssuer = cert; - NS_ADDREF(*aIssuer); + cert.forget(aIssuer); return NS_OK; } @@ -1262,10 +1261,9 @@ nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity) return NS_ERROR_NOT_AVAILABLE; NS_ENSURE_ARG(aValidity); - nsX509CertValidity* validity = new nsX509CertValidity(mCert.get()); + nsRefPtr validity = new nsX509CertValidity(mCert.get()); - NS_ADDREF(validity); - *aValidity = static_cast(validity); + validity.forget(aValidity); return NS_OK; } @@ -1723,8 +1721,7 @@ nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval) nsCOMPtr enumerator = new nsNSSCertListEnumerator(mCertList.get(), locker); - *_retval = enumerator; - NS_ADDREF(*_retval); + enumerator.forget(_retval); return NS_OK; } @@ -1853,8 +1850,7 @@ nsNSSCertListEnumerator::GetNext(nsISupports** _retval) return NS_ERROR_OUT_OF_MEMORY; } - *_retval = nssCert; - NS_ADDREF(*_retval); + nssCert.forget(_retval); CERT_RemoveCertListNode(node); return NS_OK; diff --git a/security/manager/ssl/nsNSSCertificateDB.cpp b/security/manager/ssl/nsNSSCertificateDB.cpp index f975c4d0b07a..93371f25b34d 100644 --- a/security/manager/ssl/nsNSSCertificateDB.cpp +++ b/security/manager/ssl/nsNSSCertificateDB.cpp @@ -1385,12 +1385,11 @@ nsNSSCertificateDB::FindCertByEmailAddress(nsISupports *aToken, const char *aEma } // node now contains the first valid certificate with correct usage - nsNSSCertificate *nssCert = nsNSSCertificate::Create(node->cert); + nsRefPtr nssCert = nsNSSCertificate::Create(node->cert); if (!nssCert) return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(nssCert); - *_retval = static_cast(nssCert); + nssCert.forget(_retval); return NS_OK; } @@ -1695,8 +1694,7 @@ nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval) // (returns an empty list) nssCertList = new nsNSSCertList(certList, locker); - *_retval = nssCertList; - NS_ADDREF(*_retval); + nssCertList.forget(_retval); return NS_OK; } diff --git a/security/manager/ssl/nsPK11TokenDB.cpp b/security/manager/ssl/nsPK11TokenDB.cpp index fa25e2ea6790..ca769eba82b9 100644 --- a/security/manager/ssl/nsPK11TokenDB.cpp +++ b/security/manager/ssl/nsPK11TokenDB.cpp @@ -424,8 +424,7 @@ NS_IMETHODIMP nsPK11TokenDB::GetInternalKeyToken(nsIPK11Token **_retval) if (!slot) { rv = NS_ERROR_FAILURE; goto done; } token = new nsPK11Token(slot); - *_retval = token; - NS_ADDREF(*_retval); + token.forget(_retval); done: if (slot) PK11_FreeSlot(slot); @@ -438,12 +437,13 @@ FindTokenByName(const char16_t* tokenName, nsIPK11Token **_retval) nsNSSShutDownPreventionLock locker; nsresult rv = NS_OK; PK11SlotInfo *slot = 0; + nsCOMPtr token; NS_ConvertUTF16toUTF8 aUtf8TokenName(tokenName); slot = PK11_FindSlotByName(const_cast(aUtf8TokenName.get())); if (!slot) { rv = NS_ERROR_FAILURE; goto done; } - *_retval = new nsPK11Token(slot); - NS_ADDREF(*_retval); + token = new nsPK11Token(slot); + token.forget(_retval); done: if (slot) PK11_FreeSlot(slot); diff --git a/security/manager/ssl/nsPKCS11Slot.cpp b/security/manager/ssl/nsPKCS11Slot.cpp index 48e1c539e0fc..8a3cf672bc94 100644 --- a/security/manager/ssl/nsPKCS11Slot.cpp +++ b/security/manager/ssl/nsPKCS11Slot.cpp @@ -169,8 +169,7 @@ nsPKCS11Slot::GetToken(nsIPK11Token **_retval) return NS_ERROR_NOT_AVAILABLE; nsCOMPtr token = new nsPK11Token(mSlot); - *_retval = token; - NS_ADDREF(*_retval); + token.forget(_retval); return NS_OK; } @@ -319,8 +318,7 @@ nsPKCS11Module::FindSlotByName(const char16_t *aName, free(asciiname); nsCOMPtr slot = new nsPKCS11Slot(slotinfo); PK11_FreeSlot(slotinfo); - *_retval = slot; - NS_ADDREF(*_retval); + slot.forget(_retval); return NS_OK; } @@ -372,8 +370,7 @@ nsPKCS11ModuleDB::GetInternal(nsIPKCS11Module **_retval) SECMOD_CreateModule(nullptr, SECMOD_INT_NAME, nullptr, SECMOD_INT_FLAGS); nsCOMPtr module = new nsPKCS11Module(nssMod); SECMOD_DestroyModule(nssMod); - *_retval = module; - NS_ADDREF(*_retval); + module.forget(_retval); return NS_OK; } @@ -385,8 +382,7 @@ nsPKCS11ModuleDB::GetInternalFIPS(nsIPKCS11Module **_retval) SECMOD_CreateModule(nullptr, SECMOD_FIPS_NAME, nullptr, SECMOD_FIPS_FLAGS); nsCOMPtr module = new nsPKCS11Module(nssMod); SECMOD_DestroyModule(nssMod); - *_retval = module; - NS_ADDREF(*_retval); + module.forget(_retval); return NS_OK; } @@ -402,8 +398,7 @@ nsPKCS11ModuleDB::FindModuleByName(const char16_t *aName, return NS_ERROR_FAILURE; nsCOMPtr module = new nsPKCS11Module(mod); SECMOD_DestroyModule(mod); - *_retval = module; - NS_ADDREF(*_retval); + module.forget(_retval); return NS_OK; } @@ -422,8 +417,7 @@ nsPKCS11ModuleDB::FindSlotByName(const char16_t *aName, return NS_ERROR_FAILURE; nsCOMPtr slot = new nsPKCS11Slot(slotinfo); PK11_FreeSlot(slotinfo); - *_retval = slot; - NS_ADDREF(*_retval); + slot.forget(_retval); return NS_OK; } From 1bcbb7e6e87d8b813728bef5c9d2bcfacd09fd0c Mon Sep 17 00:00:00 2001 From: Milan Sreckovic Date: Tue, 11 Aug 2015 14:07:49 -0700 Subject: [PATCH 19/49] Bug 1130195: Don't immediately crash if we can't allocate image. Carry r=bas --- gfx/2d/DrawTargetD2D1.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gfx/2d/DrawTargetD2D1.cpp b/gfx/2d/DrawTargetD2D1.cpp index 99335efe868a..4b327dda8eb1 100644 --- a/gfx/2d/DrawTargetD2D1.cpp +++ b/gfx/2d/DrawTargetD2D1.cpp @@ -1116,9 +1116,7 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern) HRESULT hr = mDC->CreateBitmap(D2DIntSize(mSize), D2D1::BitmapProperties(D2DPixelFormat(mFormat)), byRef(tmpBitmap)); if (FAILED(hr)) { gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(mSize))) << "[D2D1.1] 5CreateBitmap failure " << mSize << " Code: " << hexa(hr) << " format " << (int)mFormat; - // For now, crash in this scenario; this should happen because tmpBitmap is - // null and CopyFromBitmap call below dereferences it. - // return; + return; } // This flush is important since the copy method will not know about the context drawing to the surface. From d9b56568b1c45cc92b5faa21f9fe105e14351062 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 5 Aug 2015 11:36:05 -0400 Subject: [PATCH 20/49] Bug 1136414: Removed SRGB8_EXT from list of color renderable formats. r=jgilbert --- dom/canvas/WebGLFramebuffer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dom/canvas/WebGLFramebuffer.cpp b/dom/canvas/WebGLFramebuffer.cpp index 65513b5d80fc..a5f8452cfef4 100644 --- a/dom/canvas/WebGLFramebuffer.cpp +++ b/dom/canvas/WebGLFramebuffer.cpp @@ -268,7 +268,6 @@ WebGLContext::IsFormatValidForFB(GLenum sizedFormat) const case LOCAL_GL_RGBA4: return true; - case LOCAL_GL_SRGB8: case LOCAL_GL_SRGB8_ALPHA8_EXT: return IsExtensionEnabled(WebGLExtensionID::EXT_sRGB); From 83c418c74057176bd893951e299e1b6e0783912f Mon Sep 17 00:00:00 2001 From: Muhsin Ali Steiman Date: Tue, 11 Aug 2015 14:12:06 -0700 Subject: [PATCH 21/49] Bug 1186723 - Make BytecodeEmitter::emitDupAt take a reasonable offset r=arai --- js/src/frontend/BytecodeEmitter.cpp | 28 +++++++++++++--------------- js/src/frontend/BytecodeEmitter.h | 14 +++----------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 91272169dab6..5874cf2ca1ab 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -345,12 +345,10 @@ BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn) } bool -BytecodeEmitter::emitDupAt(unsigned slot) +BytecodeEmitter::emitDupAt(unsigned slotFromTop) { - MOZ_ASSERT(slot < unsigned(stackDepth)); + MOZ_ASSERT(slotFromTop < unsigned(stackDepth)); - // The slot's position on the operand stack, measured from the top. - unsigned slotFromTop = stackDepth - 1 - slot; if (slotFromTop >= JS_BIT(24)) { reportError(nullptr, JSMSG_TOO_MANY_LOCALS); return false; @@ -2787,7 +2785,7 @@ BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts) return false; // We need another |this| on top, also - if (!emitDupAt(this->stackDepth - 1 - 1)) + if (!emitDupAt(1)) return false; } @@ -2898,11 +2896,11 @@ BytecodeEmitter::emitSuperElemIncDec(ParseNode* pn) // There's no such thing as JSOP_DUP3, so we have to be creative. // Note that pushing things again is no fewer JSOps. - if (!emitDupAt(this->stackDepth - 1 - 2)) // KEY THIS OBJ KEY + if (!emitDupAt(2)) // KEY THIS OBJ KEY return false; - if (!emitDupAt(this->stackDepth - 1 - 2)) // KEY THIS OBJ KEY THIS + if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS return false; - if (!emitDupAt(this->stackDepth - 1 - 2)) // KEY THIS OBJ KEY THIS OBJ + if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS OBJ return false; if (!emitElemOpBase(JSOP_GETELEM_SUPER)) // KEY THIS OBJ V return false; @@ -4465,11 +4463,11 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs) return false; break; case PNK_SUPERELEM: - if (!emitDupAt(this->stackDepth - 1 - 2)) + if (!emitDupAt(2)) return false; - if (!emitDupAt(this->stackDepth - 1 - 2)) + if (!emitDupAt(2)) return false; - if (!emitDupAt(this->stackDepth - 1 - 2)) + if (!emitDupAt(2)) return false; if (!emitElemOpBase(JSOP_GETELEM_SUPER)) return false; @@ -5370,7 +5368,7 @@ BytecodeEmitter::emitForOf(StmtType type, ParseNode* pn, ptrdiff_t top) if (!emit1(JSOP_DUP)) // ITER ITER return false; } else { - if (!emitDupAt(this->stackDepth - 1 - 2)) // ITER ARR I ITER + if (!emitDupAt(2)) // ITER ARR I ITER return false; } if (!emitIteratorNext(forHead)) // ... RESULT @@ -6720,7 +6718,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn) if (isNewOp) { // Repush the callee as new.target - if (!emitDupAt(this->stackDepth - 1 - (argc + 1))) + if (!emitDupAt(argc + 1)) return false; } } else { @@ -6728,7 +6726,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn) return false; if (isNewOp) { - if (!emitDupAt(this->stackDepth - 1 - 2)) + if (!emitDupAt(2)) return false; } } @@ -7869,7 +7867,7 @@ BytecodeEmitter::emitTree(ParseNode* pn) */ if (!emitTree(pn->pn_kid)) return false; - if (!emitDupAt(arrayCompDepth)) + if (!emitDupAt(this->stackDepth - 1 - arrayCompDepth)) return false; if (!emit1(JSOP_ARRAYPUSH)) return false; diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index b150eb3d5940..d0df5c9b969c 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -373,17 +373,9 @@ struct BytecodeEmitter // Emit three bytecodes, an opcode with two bytes of immediate operands. bool emit3(JSOp op, jsbytecode op1, jsbytecode op2); - // Dup the var in operand stack slot "slot". The first item on the operand - // stack is one slot past the last fixed slot. The last (most recent) item is - // slot bce->stackDepth - 1. - // - // The instruction that is written (JSOP_DUPAT) switches the depth around so - // that it is addressed from the sp instead of from the fp. This is useful when - // you don't know the size of the fixed stack segment (nfixed), as is the case - // when compiling scripts (because each statement is parsed and compiled - // separately, but they all together form one script with one fixed stack - // frame). - bool emitDupAt(unsigned slot); + // Helper to emit JSOP_DUPAT. The argument is the value's depth on the + // JS stack, as measured from the top. + bool emitDupAt(unsigned slotFromTop); // Emit a bytecode followed by an uint16 immediate operand stored in // big-endian order. From 5755b5bc07fbbb3da28885b0ac45896fdb0b01f1 Mon Sep 17 00:00:00 2001 From: Petr Jasicek Date: Tue, 11 Aug 2015 14:12:44 -0700 Subject: [PATCH 22/49] Bug 1192243 - Fix Gtk3 crash reporter's ScrolledWindow and width. r=karlt --- .../client/crashreporter_linux.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/toolkit/crashreporter/client/crashreporter_linux.cpp b/toolkit/crashreporter/client/crashreporter_linux.cpp index c7a7bb356dc0..6e7ccce4013d 100644 --- a/toolkit/crashreporter/client/crashreporter_linux.cpp +++ b/toolkit/crashreporter/client/crashreporter_linux.cpp @@ -14,6 +14,8 @@ #include "crashreporter.h" #include "crashreporter_gtk_common.h" +#define LABEL_MAX_CHAR_WIDTH 48 + using std::string; using std::vector; @@ -183,9 +185,12 @@ static void ViewReportClicked(GtkButton* button, GtkWidget* scrolled = gtk_scrolled_window_new(0, 0); gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(dialog)), scrolled); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), - GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN); +#if (MOZ_WIDGET_GTK >= 3) + gtk_widget_set_vexpand(scrolled, TRUE); +#endif GtkWidget* viewReportTextView = gtk_text_view_new(); gtk_container_add(GTK_CONTAINER(scrolled), viewReportTextView); @@ -412,7 +417,11 @@ bool UIShowCrashUI(const StringTable& files, gtk_label_new(gStrings[ST_CRASHREPORTERDESCRIPTION].c_str()); gtk_box_pack_start(GTK_BOX(vbox), descriptionLabel, TRUE, TRUE, 0); // force the label to line wrap +#if (MOZ_WIDGET_GTK == 2) gtk_widget_set_size_request(descriptionLabel, 400, -1); +#else + gtk_label_set_max_width_chars(GTK_LABEL(descriptionLabel), LABEL_MAX_CHAR_WIDTH); +#endif gtk_label_set_line_wrap(GTK_LABEL(descriptionLabel), TRUE); gtk_label_set_selectable(GTK_LABEL(descriptionLabel), TRUE); gtk_misc_set_alignment(GTK_MISC(descriptionLabel), 0, 0.5); @@ -456,6 +465,9 @@ bool UIShowCrashUI(const StringTable& files, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN); +#if (MOZ_WIDGET_GTK >= 3) + gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled), 100); +#endif gCommentTextLabel = gtk_label_new(gStrings[ST_COMMENTGRAYTEXT].c_str()); gCommentText = gtk_text_view_new(); @@ -514,7 +526,11 @@ bool UIShowCrashUI(const StringTable& files, gtk_label_new(gStrings[ST_REPORTPRESUBMIT].c_str()); gtk_box_pack_start(GTK_BOX(progressBox), gProgressLabel, TRUE, TRUE, 0); // force the label to line wrap +#if (MOZ_WIDGET_GTK == 2) gtk_widget_set_size_request(gProgressLabel, 400, -1); +#else + gtk_label_set_max_width_chars(GTK_LABEL(gProgressLabel), LABEL_MAX_CHAR_WIDTH); +#endif gtk_label_set_line_wrap(GTK_LABEL(gProgressLabel), TRUE); GtkWidget* buttonBox = gtk_hbutton_box_new(); From 09f58572fafd59a6f28fd6a454c2a1532df63f78 Mon Sep 17 00:00:00 2001 From: "Alpha A." Date: Mon, 3 Aug 2015 18:48:34 +0200 Subject: [PATCH 23/49] Bug 1086627 - Rename ThenableResolverTask to PromiseResolveThenableJob to more closely match Promise spec. r=nsm --HG-- extra : commitid : 70Le0IGETaD extra : rebase_source : ef42276c4125f91d69c271cb19319c9d995f1826 --- dom/promise/Promise.cpp | 50 ++++++++++++++++++++--------------------- dom/promise/Promise.h | 4 ++-- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index a1a5e3635d2b..6d8c68d16d59 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -174,32 +174,32 @@ GetPromise(JSContext* aCx, JS::Handle aFunc) // Runnable to resolve thenables. // Equivalent to the specification's ResolvePromiseViaThenableTask. -class ThenableResolverTask final : public nsRunnable +class PromiseResolveThenableJob final : public nsRunnable { public: - ThenableResolverTask(Promise* aPromise, - JS::Handle aThenable, - PromiseInit* aThen) + PromiseResolveThenableJob(Promise* aPromise, + JS::Handle aThenable, + PromiseInit* aThen) : mPromise(aPromise) , mThenable(CycleCollectedJSRuntime::Get()->Runtime(), aThenable) , mThen(aThen) { MOZ_ASSERT(aPromise); - MOZ_COUNT_CTOR(ThenableResolverTask); + MOZ_COUNT_CTOR(PromiseResolveThenableJob); } virtual - ~ThenableResolverTask() + ~PromiseResolveThenableJob() { - NS_ASSERT_OWNINGTHREAD(ThenableResolverTask); - MOZ_COUNT_DTOR(ThenableResolverTask); + NS_ASSERT_OWNINGTHREAD(PromiseResolveThenableJob); + MOZ_COUNT_DTOR(PromiseResolveThenableJob); } protected: NS_IMETHOD Run() override { - NS_ASSERT_OWNINGTHREAD(ThenableResolverTask); + NS_ASSERT_OWNINGTHREAD(PromiseResolveThenableJob); ThreadsafeAutoJSContext cx; JS::Rooted wrapper(cx, mPromise->GetWrapper()); MOZ_ASSERT(wrapper); // It was preserved! @@ -275,16 +275,16 @@ private: NS_DECL_OWNINGTHREAD; }; -// Fast version of ThenableResolverTask for use in the cases when we know we're +// Fast version of PromiseResolveThenableJob for use in the cases when we know we're // calling the canonical Promise.prototype.then on an actual DOM Promise. In // that case we can just bypass the jumping into and out of JS and call // AppendCallbacks on that promise directly. -class FastThenableResolverTask final : public nsRunnable +class FastPromiseResolveThenableJob final : public nsRunnable { public: - FastThenableResolverTask(PromiseCallback* aResolveCallback, - PromiseCallback* aRejectCallback, - Promise* aNextPromise) + FastPromiseResolveThenableJob(PromiseCallback* aResolveCallback, + PromiseCallback* aRejectCallback, + Promise* aNextPromise) : mResolveCallback(aResolveCallback) , mRejectCallback(aRejectCallback) , mNextPromise(aNextPromise) @@ -292,21 +292,21 @@ public: MOZ_ASSERT(aResolveCallback); MOZ_ASSERT(aRejectCallback); MOZ_ASSERT(aNextPromise); - MOZ_COUNT_CTOR(FastThenableResolverTask); + MOZ_COUNT_CTOR(FastPromiseResolveThenableJob); } virtual - ~FastThenableResolverTask() + ~FastPromiseResolveThenableJob() { - NS_ASSERT_OWNINGTHREAD(FastThenableResolverTask); - MOZ_COUNT_DTOR(FastThenableResolverTask); + NS_ASSERT_OWNINGTHREAD(FastPromiseResolveThenableJob); + MOZ_COUNT_DTOR(FastPromiseResolveThenableJob); } protected: NS_IMETHOD Run() override { - NS_ASSERT_OWNINGTHREAD(FastThenableResolverTask); + NS_ASSERT_OWNINGTHREAD(FastPromiseResolveThenableJob); mNextPromise->AppendCallbacks(mResolveCallback, mRejectCallback); return NS_OK; } @@ -1299,8 +1299,8 @@ Promise::ResolveInternal(JSContext* aCx, Promise* nextPromise; if (PromiseBinding::IsThenMethod(thenObj) && NS_SUCCEEDED(UNWRAP_OBJECT(Promise, valueObj, nextPromise))) { - // If we were taking the codepath that involves ThenableResolverTask and - // PromiseInit below, then eventually, in ThenableResolverTask::Run, we + // If we were taking the codepath that involves PromiseResolveThenableJob and + // PromiseInit below, then eventually, in PromiseResolveThenableJob::Run, we // would create some JSFunctions in the compartment of // this->GetWrapper() and pass them to the PromiseInit. So by the time // we'd see the resolution value it would be wrapped into the @@ -1310,16 +1310,16 @@ Promise::ResolveInternal(JSContext* aCx, JS::Rooted glob(aCx, GlobalJSObject()); nsRefPtr resolveCb = new ResolvePromiseCallback(this, glob); nsRefPtr rejectCb = new RejectPromiseCallback(this, glob); - nsRefPtr task = - new FastThenableResolverTask(resolveCb, rejectCb, nextPromise); + nsRefPtr task = + new FastPromiseResolveThenableJob(resolveCb, rejectCb, nextPromise); DispatchToMicroTask(task); return; } nsRefPtr thenCallback = new PromiseInit(nullptr, thenObj, mozilla::dom::GetIncumbentGlobal()); - nsRefPtr task = - new ThenableResolverTask(this, valueObj, thenCallback); + nsRefPtr task = + new PromiseResolveThenableJob(this, valueObj, thenCallback); DispatchToMicroTask(task); return; } diff --git a/dom/promise/Promise.h b/dom/promise/Promise.h index 302fe2622b3d..f7028a7bdd41 100644 --- a/dom/promise/Promise.h +++ b/dom/promise/Promise.h @@ -85,8 +85,8 @@ class Promise : public nsISupports, friend class PromiseWorkerProxyRunnable; friend class RejectPromiseCallback; friend class ResolvePromiseCallback; - friend class ThenableResolverTask; - friend class FastThenableResolverTask; + friend class PromiseResolveThenableJob; + friend class FastPromiseResolveThenableJob; friend class WrapperPromiseCallback; public: From b44082538cd6acd7093a32161d3d822c901b682e Mon Sep 17 00:00:00 2001 From: "Alpha A." Date: Thu, 6 Aug 2015 17:18:30 +0200 Subject: [PATCH 24/49] Bug 1086627 - Rename Promise constructs to more closely match the specification. r=nsm,jst --HG-- extra : commitid : 86J3tVySqhI extra : rebase_source : cccb777a893cc44c2edece078e5861aa25f3f52b extra : amend_source : 02c64f4e5ba42d2aa77776826af80927bd231f00 --- dom/promise/Promise.cpp | 53 ++++++++++++++++++++------------------- dom/promise/Promise.h | 6 ++--- dom/webidl/Promise.webidl | 2 -- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 6d8c68d16d59..73faadc38a02 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -47,33 +47,33 @@ Atomic gIDGenerator(0); using namespace workers; // This class processes the promise's callbacks with promise's result. -class PromiseCallbackTask final : public nsRunnable +class PromiseReactionJob final : public nsRunnable { public: - PromiseCallbackTask(Promise* aPromise, - PromiseCallback* aCallback, - const JS::Value& aValue) + PromiseReactionJob(Promise* aPromise, + PromiseCallback* aCallback, + const JS::Value& aValue) : mPromise(aPromise) , mCallback(aCallback) , mValue(CycleCollectedJSRuntime::Get()->Runtime(), aValue) { MOZ_ASSERT(aPromise); MOZ_ASSERT(aCallback); - MOZ_COUNT_CTOR(PromiseCallbackTask); + MOZ_COUNT_CTOR(PromiseReactionJob); } virtual - ~PromiseCallbackTask() + ~PromiseReactionJob() { - NS_ASSERT_OWNINGTHREAD(PromiseCallbackTask); - MOZ_COUNT_DTOR(PromiseCallbackTask); + NS_ASSERT_OWNINGTHREAD(PromiseReactionJob); + MOZ_COUNT_DTOR(PromiseReactionJob); } protected: NS_IMETHOD Run() override { - NS_ASSERT_OWNINGTHREAD(PromiseCallbackTask); + NS_ASSERT_OWNINGTHREAD(PromiseReactionJob); ThreadsafeAutoJSContext cx; JS::Rooted wrapper(cx, mPromise->GetWrapper()); MOZ_ASSERT(wrapper); // It was preserved! @@ -822,7 +822,7 @@ Promise::Catch(JSContext* aCx, AnyCallback* aRejectCallback, ErrorResult& aRv) /** * The CountdownHolder class encapsulates Promise.all countdown functions and * the countdown holder parts of the Promises spec. It maintains the result - * array and AllResolveHandlers use SetValue() to set the array indices. + * array and AllResolveElementFunctions use SetValue() to set the array indices. */ class CountdownHolder final : public nsISupports { @@ -910,17 +910,18 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CountdownHolder) NS_IMPL_CYCLE_COLLECTION_UNLINK_END /** - * An AllResolveHandler is the per-promise part of the Promise.all() algorithm. + * An AllResolveElementFunction is the per-promise + * part of the Promise.all() algorithm. * Every Promise in the handler is handed an instance of this as a resolution * handler and it sets the relevant index in the CountdownHolder. */ -class AllResolveHandler final : public PromiseNativeHandler +class AllResolveElementFunction final : public PromiseNativeHandler { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS(AllResolveHandler) + NS_DECL_CYCLE_COLLECTION_CLASS(AllResolveElementFunction) - AllResolveHandler(CountdownHolder* aHolder, uint32_t aIndex) + AllResolveElementFunction(CountdownHolder* aHolder, uint32_t aIndex) : mCountdownHolder(aHolder), mIndex(aIndex) { MOZ_ASSERT(aHolder); @@ -936,11 +937,11 @@ public: RejectedCallback(JSContext* aCx, JS::Handle aValue) override { // Should never be attached to Promise as a reject handler. - MOZ_ASSERT(false, "AllResolveHandler should never be attached to a Promise's reject handler!"); + MOZ_CRASH("AllResolveElementFunction should never be attached to a Promise's reject handler!"); } private: - ~AllResolveHandler() + ~AllResolveElementFunction() { } @@ -948,14 +949,14 @@ private: uint32_t mIndex; }; -NS_IMPL_CYCLE_COLLECTING_ADDREF(AllResolveHandler) -NS_IMPL_CYCLE_COLLECTING_RELEASE(AllResolveHandler) +NS_IMPL_CYCLE_COLLECTING_ADDREF(AllResolveElementFunction) +NS_IMPL_CYCLE_COLLECTING_RELEASE(AllResolveElementFunction) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AllResolveHandler) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AllResolveElementFunction) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION(AllResolveHandler, mCountdownHolder) +NS_IMPL_CYCLE_COLLECTION(AllResolveElementFunction, mCountdownHolder) /* static */ already_AddRefed Promise::All(const GlobalObject& aGlobal, @@ -1019,7 +1020,7 @@ Promise::All(const GlobalObject& aGlobal, for (uint32_t i = 0; i < aPromiseList.Length(); ++i) { nsRefPtr resolveHandler = - new AllResolveHandler(holder, i); + new AllResolveElementFunction(holder, i); nsRefPtr resolveCb = new NativePromiseCallback(resolveHandler, Resolved); @@ -1132,7 +1133,7 @@ Promise::AppendCallbacks(PromiseCallback* aResolveCallback, // callbacks with promise's result. If promise's state is rejected, queue a // task to process our reject callbacks with promise's result. if (mState != Pending) { - EnqueueCallbackTasks(); + TriggerPromiseReactions(); } } @@ -1387,7 +1388,7 @@ Promise::Settle(JS::Handle aValue, PromiseState aState) } #endif // defined(DOM_PROMISE_DEPRECATED_REPORTING) - EnqueueCallbackTasks(); + TriggerPromiseReactions(); } void @@ -1405,7 +1406,7 @@ Promise::MaybeSettle(JS::Handle aValue, } void -Promise::EnqueueCallbackTasks() +Promise::TriggerPromiseReactions() { nsTArray> callbacks; callbacks.SwapElements(mState == Resolved ? mResolveCallbacks @@ -1414,8 +1415,8 @@ Promise::EnqueueCallbackTasks() mRejectCallbacks.Clear(); for (uint32_t i = 0; i < callbacks.Length(); ++i) { - nsRefPtr task = - new PromiseCallbackTask(this, callbacks[i], mResult); + nsRefPtr task = + new PromiseReactionJob(this, callbacks[i], mResult); DispatchToMicroTask(task); } } diff --git a/dom/promise/Promise.h b/dom/promise/Promise.h index f7028a7bdd41..437183c19da5 100644 --- a/dom/promise/Promise.h +++ b/dom/promise/Promise.h @@ -75,7 +75,7 @@ class Promise : public nsISupports, public SupportsWeakPtr { friend class NativePromiseCallback; - friend class PromiseCallbackTask; + friend class PromiseReactionJob; friend class PromiseResolverTask; friend class PromiseTask; #if defined(DOM_PROMISE_DEPRECATED_REPORTING) @@ -274,8 +274,8 @@ private: // This method enqueues promise's resolve/reject callbacks with promise's // result. It's executed when the resolver.resolve() or resolver.reject() is // called or when the promise already has a result and new callbacks are - // appended by then(), catch() or done(). - void EnqueueCallbackTasks(); + // appended by then() or catch(). + void TriggerPromiseReactions(); void Settle(JS::Handle aValue, Promise::PromiseState aState); void MaybeSettle(JS::Handle aValue, Promise::PromiseState aState); diff --git a/dom/webidl/Promise.webidl b/dom/webidl/Promise.webidl index a98bca780c93..69a768e8cbcd 100644 --- a/dom/webidl/Promise.webidl +++ b/dom/webidl/Promise.webidl @@ -20,8 +20,6 @@ callback AnyCallback = any (any value); Exposed=(Window,Worker,System)] // Need to escape "Promise" so it's treated as an identifier. interface _Promise { - // TODO bug 875289 - static Promise fulfill(any value); - // Disable the static methods when the interface object is supposed to be // disabled, just in case some code decides to walk over to .constructor from // the proto of a promise object or someone screws up and manages to create a From f6fed1c3867ca9d61f64b4b876a931c0de730c01 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Fri, 7 Aug 2015 16:05:19 -0400 Subject: [PATCH 25/49] Bug 1191412 - Fix logic and text for the WillChange warning. r=roc --HG-- extra : commitid : LL1q53ZpGCQ extra : rebase_source : 342e0bf923ec556b7abd9f7275f7d5b20400663c --- dom/base/nsDocumentWarningList.h | 2 +- dom/locales/en-US/chrome/dom/dom.properties | 4 ++-- layout/base/nsDisplayList.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dom/base/nsDocumentWarningList.h b/dom/base/nsDocumentWarningList.h index 943c19eb1b60..26cb33d2158f 100644 --- a/dom/base/nsDocumentWarningList.h +++ b/dom/base/nsDocumentWarningList.h @@ -10,4 +10,4 @@ * designed to be used as input to the C preprocessor *only*. */ -DOCUMENT_WARNING(WillChangeOverBudgetIgnored) +DOCUMENT_WARNING(IgnoringWillChangeOverBudget) diff --git a/dom/locales/en-US/chrome/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties index 0ae2f0d2ac94..2377e8c0f7b4 100644 --- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -155,8 +155,8 @@ ImportXULIntoContentWarning=Importing XUL nodes into a content document is depre XMLDocumentLoadPrincipalMismatch=Use of document.load forbidden on Documents that come from other Windows. Only the Window in which a Document was created is allowed to call .load on that Document. Preferably, use XMLHttpRequest instead. # LOCALIZATION NOTE: Do not translate "IndexedDB". IndexedDBTransactionAbortNavigation=An IndexedDB transaction that was not yet complete has been aborted due to page navigation. -# LOCALIZATION NOTE: Do not translate Will-change, %1$S,%2$S,%3$S are numbers. -WillChangeOverBudgetIgnoredWarning=Will-change memory consumption is too high. Surface area covers %1$S px, budget is the document surface area multiplied by %2$S (%3$S px). Occurences of will-change over the budget will be ignored. +# LOCALIZATION NOTE: Do not translate Will-change, %1$S,%2$S are numbers. +IgnoringWillChangeOverBudgetWarning=Will-change memory consumption is too high. Budget limit is the document surface area multiplied by %1$S (%2$S px). Occurrences of will-change over the budget will be ignored. # LOCALIZATION NOTE: Do not translate "ServiceWorker". HittingMaxWorkersPerDomain=A ServiceWorker could not be started immediately because other documents in the same origin are already using the maximum number of workers. The ServiceWorker is now queued and will be started after some of the other workers have completed. # LOCALIZATION NOTE: Do no translate "setVelocity", "PannerNode", "AudioListener", "speedOfSound" and "dopplerFactor" diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 2d89d3afce51..51ca42b5ed5e 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -1230,7 +1230,7 @@ nsDisplayListBuilder::IsInWillChangeBudget(nsIFrame* aFrame, const nsSize& aSize) { bool onBudget = AddToWillChangeBudget(aFrame, aSize); - if (onBudget) { + if (!onBudget) { nsString usageStr; usageStr.AppendInt(GetWillChangeCost(aFrame, aSize)); @@ -1243,9 +1243,9 @@ nsDisplayListBuilder::IsInWillChangeBudget(nsIFrame* aFrame, nsPresContext::AppUnitsToIntCSSPixels(area.height); limitStr.AppendInt(budgetLimit); - const char16_t* params[] = { usageStr.get(), multiplierStr.get(), limitStr.get() }; + const char16_t* params[] = { multiplierStr.get(), limitStr.get() }; aFrame->PresContext()->Document()->WarnOnceAbout( - nsIDocument::eWillChangeOverBudgetIgnored, false, + nsIDocument::eIgnoringWillChangeOverBudget, false, params, ArrayLength(params)); } return onBudget; From b489e23bcaad3743e4afe0edaf4debe0d18ee288 Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Wed, 12 Aug 2015 00:43:48 +0200 Subject: [PATCH 26/49] Bug 1172701 - Make GetSubresourceURI normalize the path for packaged resources r=mcmanus --- netwerk/protocol/http/PackagedAppService.cpp | 11 +- .../unit/test_packaged_app_service_paths.js | 127 ++++++++++++++++++ netwerk/test/unit/xpcshell.ini | 1 + 3 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 netwerk/test/unit/test_packaged_app_service_paths.js diff --git a/netwerk/protocol/http/PackagedAppService.cpp b/netwerk/protocol/http/PackagedAppService.cpp index d62d93c633fc..d4d5fc136086 100644 --- a/netwerk/protocol/http/PackagedAppService.cpp +++ b/netwerk/protocol/http/PackagedAppService.cpp @@ -412,8 +412,15 @@ PackagedAppService::PackagedAppDownloader::GetSubresourceURI(nsIRequest * aReque path += PACKAGED_APP_TOKEN; - // TODO: make sure the path is normalized - if (StringBeginsWith(contentLocation, NS_LITERAL_CSTRING("/"))) { + { + // We use this temp URI to generate a path that is relative + // to the package URI and not to the root of the domain. + nsCOMPtr tempURI; + NS_NewURI(getter_AddRefs(tempURI), "http://temp-domain.local/"); + tempURI->SetPath(contentLocation); + // The path is now normalized. + tempURI->GetPath(contentLocation); + // Remove the leading slash. contentLocation = Substring(contentLocation, 1); } diff --git a/netwerk/test/unit/test_packaged_app_service_paths.js b/netwerk/test/unit/test_packaged_app_service_paths.js new file mode 100644 index 000000000000..306676ccc6c3 --- /dev/null +++ b/netwerk/test/unit/test_packaged_app_service_paths.js @@ -0,0 +1,127 @@ +Cu.import('resource://gre/modules/LoadContextInfo.jsm'); +Cu.import("resource://testing-common/httpd.js"); +Cu.import("resource://gre/modules/Services.jsm"); + +var gRequestNo = 0; +function packagedAppContentHandler(metadata, response) +{ + response.setHeader("Content-Type", 'application/package'); + var body = testData.getData(); + response.bodyOutputStream.write(body, body.length); + gRequestNo++; +} + +function getPrincipal(url) { + let uri = createURI(url); + return Components.classes["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager) + .getNoAppCodebasePrincipal(uri); +} + +var subresourcePaths = [ + [ "/index.html", "index.html" ], + [ "index.html", "index.html" ], + [ "/../../index.html", "index.html" ], + [ "../../index.html", "index.html" ], + [ "/hello/./.././index.html", "index.html" ], + [ "hello/./.././index.html", "index.html" ], + [ "../hello/index.html", "hello/index.html" ], + [ "/../hello/index.html", "hello/index.html" ], + [ "/./././index.html", "index.html" ], +] + +var content = " Test "; + +// The package content +// getData formats it as described at http://www.w3.org/TR/web-packaging/#streamable-package-format +var testData = { + token : "gc0pJq0M:08jU534c0p", + getData: function() { + var str = ""; + + str += "--" + this.token + "\r\n"; + str += "Content-Location: " + subresourcePaths[gRequestNo][0] + "\r\n"; + str += "Content-Type: text/html" + "\r\n"; + str += "\r\n"; + + str += content + "\r\n"; + str += "--" + this.token + "--"; + + return str; + } +} + +XPCOMUtils.defineLazyGetter(this, "uri", function() { + return "http://localhost:" + httpserver.identity.primaryPort; +}); + +// The active http server initialized in run_test +var httpserver = null; +// The packaged app service initialized in run_test +var paservice = null; +// This variable is set before getResource is called. The listener uses this variable +// to check the correct resource path for the returned entry +var packagePath = null; + +function run_test() +{ + // setup test + httpserver = new HttpServer(); + httpserver.registerPrefixHandler("/package/", packagedAppContentHandler); + httpserver.start(-1); + + paservice = Cc["@mozilla.org/network/packaged-app-service;1"] + .getService(Ci.nsIPackagedAppService); + + var testuri = createURI("http://localhost/"); + + add_test(continueTest); + // run tests + run_next_test(); +} + +// A listener we use to check the proper cache entry is returned by the service +function packagedResourceListener(path, content) { + this.path = path; + this.content = content; +} + +packagedResourceListener.prototype = { + QueryInterface: function (iid) { + if (iid.equals(Ci.nsICacheEntryOpenCallback) || + iid.equals(Ci.nsISupports)) + return this; + throw Cr.NS_ERROR_NO_INTERFACE; + }, + onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; }, + onCacheEntryAvailable: function (entry, isnew, appcache, status) { + equal(status, Cr.NS_OK, "status is NS_OK"); + ok(!!entry, "Needs to have an entry"); + equal(entry.key, uri + packagePath + "!//" + this.path, "Check entry has correct name"); + var inputStream = entry.openInputStream(0); + pumpReadStream(inputStream, (read) => { + inputStream.close(); + equal(read, this.content); // not using do_check_eq since logger will fail for the 1/4MB string + continueTest(); + }); + } +}; + +var gGenerator = test_paths(); +function continueTest() { + try { + gGenerator.next(); + } catch (e if e instanceof StopIteration) { + run_next_test(); + } +} +function test_paths() { + for (var i in subresourcePaths) { + packagePath = "/package/" + i; + dump("Iteration " + i + "\n"); + paservice.getResource(getPrincipal(uri + packagePath + "!//" + subresourcePaths[i][1]), 0, + LoadContextInfo.default, + new packagedResourceListener(subresourcePaths[i][1], content)); + yield undefined; + } +} diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index f35f5e5bc0d1..9413a28a3240 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -326,3 +326,4 @@ skip-if = os == "android" [test_inhibit_caching.js] [test_dns_disable_ipv4.js] [test_dns_disable_ipv6.js] +[test_packaged_app_service_paths.js] From 41fb0b2b5aa724aa2d3810b1b9138f78e4750aaf Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 11 Aug 2015 15:59:04 -0700 Subject: [PATCH 27/49] Backed out changeset 24ee4a5af7e8 (bug 1136414) for test_conformance__extensions__ext-sRGB.html failures --- dom/canvas/WebGLFramebuffer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dom/canvas/WebGLFramebuffer.cpp b/dom/canvas/WebGLFramebuffer.cpp index a5f8452cfef4..65513b5d80fc 100644 --- a/dom/canvas/WebGLFramebuffer.cpp +++ b/dom/canvas/WebGLFramebuffer.cpp @@ -268,6 +268,7 @@ WebGLContext::IsFormatValidForFB(GLenum sizedFormat) const case LOCAL_GL_RGBA4: return true; + case LOCAL_GL_SRGB8: case LOCAL_GL_SRGB8_ALPHA8_EXT: return IsExtensionEnabled(WebGLExtensionID::EXT_sRGB); From de72ab688b5e7df58a00913daf787ed5238d00b7 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Wed, 5 Aug 2015 11:02:00 -0700 Subject: [PATCH 28/49] Bug 1191529 - Remove JSIdArray and AutoIdArray and replace with Rooted; r=mccr8, r=jonco * * * imported patch 2_remove_AutoIdArray_gk --HG-- extra : rebase_source : f4492f209248c7ae4b74d7d0345c51fa893167da --- dom/bindings/Codegen.py | 4 +- dom/geolocation/nsGeolocationSettings.cpp | 4 +- dom/plugins/base/nsJSNPRuntime.cpp | 4 +- js/ipc/JavaScriptShared.cpp | 4 +- js/public/TracingAPI.h | 58 ++++++++++++--------- js/src/NamespaceImports.h | 12 ++--- js/src/ctypes/CTypes.cpp | 8 +-- js/src/gc/RootMarking.cpp | 13 ----- js/src/jsapi.cpp | 34 +++---------- js/src/jsapi.h | 62 +---------------------- js/src/jsatom.h | 10 ---- js/src/jsiter.cpp | 19 ------- js/src/jsiter.h | 3 -- js/src/jspubtd.h | 2 - js/src/shell/js.cpp | 4 +- js/xpconnect/src/XPCComponents.cpp | 4 +- js/xpconnect/src/XPCWrappedJSClass.cpp | 4 +- widget/android/NativeJSContainer.cpp | 5 +- 18 files changed, 69 insertions(+), 185 deletions(-) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 5747bff374a8..c43079f568da 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -4516,8 +4516,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, ${mozMapType} &mozMap = ${mozMapRef}; JS::Rooted mozMapObj(cx, &$${val}.toObject()); - JS::AutoIdArray ids(cx, JS_Enumerate(cx, mozMapObj)); - if (!ids) { + JS::Rooted ids(cx, JS::IdVector(cx)); + if (!JS_Enumerate(cx, mozMapObj, &ids)) { $*{exceptionCode} } JS::Rooted propNameValue(cx); diff --git a/dom/geolocation/nsGeolocationSettings.cpp b/dom/geolocation/nsGeolocationSettings.cpp index f8a0ac19a27a..cbc335294bb7 100644 --- a/dom/geolocation/nsGeolocationSettings.cpp +++ b/dom/geolocation/nsGeolocationSettings.cpp @@ -245,10 +245,10 @@ nsGeolocationSettings::HandleGeolocationPerOriginSettingsChange(const JS::Value& AutoEntryScript aes(global, "geolocation.app_settings enumeration"); aes.TakeOwnershipOfErrorReporting(); JSContext *cx = aes.cx(); - JS::AutoIdArray ids(cx, JS_Enumerate(cx, obj)); + JS::Rooted ids(cx, JS::IdVector(cx)); // if we get no ids then the exception list is empty and we can return here. - if (!ids) { + if (!JS_Enumerate(cx, obj, &ids)) { return; } diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index 50b3069610b8..7357ca63035c 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -1032,8 +1032,8 @@ nsJSObjWrapper::NP_Enumerate(NPObject *npobj, NPIdentifier **idarray, JS::Rooted jsobj(cx, npjsobj->mJSObj); JSAutoCompartment ac(cx, jsobj); - JS::AutoIdArray ida(cx, JS_Enumerate(cx, jsobj)); - if (!ida) { + JS::Rooted ida(cx, JS::IdVector(cx)); + if (!JS_Enumerate(cx, jsobj, &ida)) { return false; } diff --git a/js/ipc/JavaScriptShared.cpp b/js/ipc/JavaScriptShared.cpp index 0cf825ce71ef..729f48f155be 100644 --- a/js/ipc/JavaScriptShared.cpp +++ b/js/ipc/JavaScriptShared.cpp @@ -729,8 +729,8 @@ JavaScriptShared::Wrap(JSContext* cx, HandleObject aObj, InfallibleTArray ids(cx, IdVector(cx)); + if (!JS_Enumerate(cx, aObj, &ids)) return false; RootedId id(cx); diff --git a/js/public/TracingAPI.h b/js/public/TracingAPI.h index e9ee438eedd1..280cf18fec76 100644 --- a/js/public/TracingAPI.h +++ b/js/public/TracingAPI.h @@ -259,31 +259,6 @@ JSTracer::asCallbackTracer() return static_cast(this); } -namespace js { - -// Automates static dispatch for tracing for TraceableContainers. -template struct DefaultTracer; - -// The default for POD, non-pointer types is to do nothing. -template -struct DefaultTracer::value && - mozilla::IsPod::value>::Type> { - static void trace(JSTracer* trc, T* t, const char* name) { - MOZ_ASSERT(mozilla::IsPod::value); - MOZ_ASSERT(!mozilla::IsPointer::value); - } -}; - -// The default for non-pod (e.g. struct) types is to call the trace method. -template -struct DefaultTracer::value>::Type> { - static void trace(JSTracer* trc, T* t, const char* name) { - t->trace(trc); - } -}; - -} // namespace js - // The JS_Call*Tracer family of functions traces the given GC thing reference. // This performs the tracing action configured on the given JSTracer: // typically calling the JSTracer::callback or marking the thing as live. @@ -366,4 +341,37 @@ extern JS_PUBLIC_API(void) JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing, JS::TraceKind kind, bool includeDetails); +namespace js { + +// Automates static dispatch for tracing for TraceableContainers. +template struct DefaultTracer; + +// The default for POD, non-pointer types is to do nothing. +template +struct DefaultTracer::value && + mozilla::IsPod::value>::Type> { + static void trace(JSTracer* trc, T* t, const char* name) { + MOZ_ASSERT(mozilla::IsPod::value); + MOZ_ASSERT(!mozilla::IsPointer::value); + } +}; + +// The default for non-pod (e.g. struct) types is to call the trace method. +template +struct DefaultTracer::value>::Type> { + static void trace(JSTracer* trc, T* t, const char* name) { + t->trace(trc); + } +}; + +template <> +struct DefaultTracer +{ + static void trace(JSTracer* trc, jsid* id, const char* name) { + JS_CallUnbarrieredIdTracer(trc, id, name); + } +}; + +} // namespace js + #endif /* js_TracingAPI_h */ diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h index 3319e137818f..c6a962340927 100644 --- a/js/src/NamespaceImports.h +++ b/js/src/NamespaceImports.h @@ -36,7 +36,9 @@ typedef AutoVectorRooter AutoIdVector; typedef AutoVectorRooter AutoObjectVector; typedef AutoVectorRooter AutoVector; -class AutoIdArray; +using ValueVector = js::TraceableVector; +using IdVector = js::TraceableVector; +using ScriptVector = js::TraceableVector; template class AutoVectorRooter; template class AutoHashMapRooter; @@ -82,11 +84,9 @@ typedef AutoVectorRooter AutoIdVector; typedef AutoVectorRooter AutoObjectVector; typedef AutoVectorRooter AutoScriptVector; -using ValueVector = TraceableVector; -using IdVector = TraceableVector; -using ScriptVector = TraceableVector; - -using JS::AutoIdArray; +using JS::ValueVector; +using JS::IdVector; +using JS::ScriptVector; using JS::AutoHashMapRooter; using JS::AutoHashSetRooter; diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index e4c0874857e9..924eb15a302d 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -3261,8 +3261,8 @@ ImplicitConvert(JSContext* cx, if (val.isObject() && !sourceData) { // Enumerate the properties of the object; if they match the struct // specification, convert the fields. - AutoIdArray props(cx, JS_Enumerate(cx, valObj)); - if (!props) + Rooted props(cx, IdVector(cx)); + if (!JS_Enumerate(cx, valObj, &props)) return false; // Convert into an intermediate, in case of failure. @@ -5343,8 +5343,8 @@ ExtractStructField(JSContext* cx, Value val, MutableHandleObject typeObj) } RootedObject obj(cx, &val.toObject()); - AutoIdArray props(cx, JS_Enumerate(cx, obj)); - if (!props) + Rooted props(cx, IdVector(cx)); + if (!JS_Enumerate(cx, obj, &props)) return nullptr; // make sure we have one, and only one, property diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index aa9466746a3d..299812cb341a 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -82,13 +82,6 @@ MarkExactStackRoots(JSRuntime* rt, JSTracer* trc) MarkExactStackRootsAcrossTypes(&rt->mainThread, trc); } -void -JS::AutoIdArray::trace(JSTracer* trc) -{ - MOZ_ASSERT(tag_ == IDARRAY); - TraceRange(trc, idArray->length, idArray->begin(), "JSAutoIdArray.idArray"); -} - inline void AutoGCRooter::trace(JSTracer* trc) { @@ -97,12 +90,6 @@ AutoGCRooter::trace(JSTracer* trc) frontend::MarkParser(trc, this); return; - case IDARRAY: { - JSIdArray* ida = static_cast(this)->idArray; - TraceRange(trc, ida->length, ida->begin(), "JS::AutoIdArray.idArray"); - return; - } - case VALVECTOR: { AutoValueVector::VectorImpl& vector = static_cast(this)->vector; TraceRootRange(trc, vector.length(), vector.begin(), "JS::AutoValueVector.vector"); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 0c304e848fcc..4e2a7046a905 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1765,25 +1765,6 @@ JS_SetNativeStackQuota(JSRuntime* rt, size_t systemCodeStackSize, size_t trusted /************************************************************************/ -JS_PUBLIC_API(int) -JS_IdArrayLength(JSContext* cx, JSIdArray* ida) -{ - return ida->length; -} - -JS_PUBLIC_API(jsid) -JS_IdArrayGet(JSContext* cx, JSIdArray* ida, unsigned index) -{ - MOZ_ASSERT(index < unsigned(ida->length)); - return ida->vector[index]; -} - -JS_PUBLIC_API(void) -JS_DestroyIdArray(JSContext* cx, JSIdArray* ida) -{ - cx->runtime()->defaultFreeOp()->free_(ida); -} - JS_PUBLIC_API(bool) JS_ValueToId(JSContext* cx, HandleValue value, MutableHandleId idp) { @@ -3166,18 +3147,19 @@ JS_SetAllNonReservedSlotsToUndefined(JSContext* cx, JSObject* objArg) obj->as().setSlot(i, UndefinedValue()); } -JS_PUBLIC_API(JSIdArray*) -JS_Enumerate(JSContext* cx, HandleObject obj) +JS_PUBLIC_API(bool) +JS_Enumerate(JSContext* cx, HandleObject obj, JS::MutableHandle props) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); + MOZ_ASSERT(props.empty()); - AutoIdVector props(cx); - JSIdArray* ida; - if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida)) - return nullptr; - return ida; + AutoIdVector ids(cx); + if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &ids)) + return false; + + return props.append(ids.begin(), ids.end()); } JS_PUBLIC_API(Value) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index feb7773a98e4..7efdbce59bc7 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1867,64 +1867,6 @@ JS_SetNativeStackQuota(JSRuntime* cx, size_t systemCodeStackSize, /************************************************************************/ -extern JS_PUBLIC_API(int) -JS_IdArrayLength(JSContext* cx, JSIdArray* ida); - -extern JS_PUBLIC_API(jsid) -JS_IdArrayGet(JSContext* cx, JSIdArray* ida, unsigned index); - -extern JS_PUBLIC_API(void) -JS_DestroyIdArray(JSContext* cx, JSIdArray* ida); - -namespace JS { - -class AutoIdArray : private AutoGCRooter -{ - public: - AutoIdArray(JSContext* cx, JSIdArray* ida - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, IDARRAY), context(cx), idArray(ida) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - ~AutoIdArray() { - if (idArray) - JS_DestroyIdArray(context, idArray); - } - bool operator!() const { - return !idArray; - } - jsid operator[](size_t i) const { - MOZ_ASSERT(idArray); - return JS_IdArrayGet(context, idArray, unsigned(i)); - } - size_t length() const { - return JS_IdArrayLength(context, idArray); - } - - friend void AutoGCRooter::trace(JSTracer* trc); - - JSIdArray* steal() { - JSIdArray* copy = idArray; - idArray = nullptr; - return copy; - } - - protected: - inline void trace(JSTracer* trc); - - private: - JSContext* context; - JSIdArray* idArray; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER - - /* No copy or assignment semantics. */ - AutoIdArray(AutoIdArray& ida) = delete; - void operator=(AutoIdArray& ida) = delete; -}; - -} /* namespace JS */ - extern JS_PUBLIC_API(bool) JS_ValueToId(JSContext* cx, JS::HandleValue v, JS::MutableHandleId idp); @@ -3151,8 +3093,8 @@ JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length); extern JS_PUBLIC_API(void) JS_ReleaseMappedArrayBufferContents(void* contents, size_t length); -extern JS_PUBLIC_API(JSIdArray*) -JS_Enumerate(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API(bool) +JS_Enumerate(JSContext* cx, JS::HandleObject obj, JS::MutableHandle props); extern JS_PUBLIC_API(JS::Value) JS_GetReservedSlot(JSObject* obj, uint32_t index); diff --git a/js/src/jsatom.h b/js/src/jsatom.h index 460574fe00bc..6fce99f5ccf5 100644 --- a/js/src/jsatom.h +++ b/js/src/jsatom.h @@ -19,16 +19,6 @@ class JSAtom; class JSAutoByteString; -struct JSIdArray { - int length; - js::HeapId vector[1]; /* actually, length jsid words */ - - js::HeapId* begin() { return vector; } - const js::HeapId* begin() const { return vector; } - js::HeapId* end() { return vector + length; } - const js::HeapId* end() const { return vector + length; } -}; - namespace js { JS_STATIC_ASSERT(sizeof(HashNumber) == 4); diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 46b129ead6ad..9c55fe06383c 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -395,25 +395,6 @@ Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags, AutoIdVector* props) return true; } -bool -js::VectorToIdArray(JSContext* cx, AutoIdVector& props, JSIdArray** idap) -{ - JS_STATIC_ASSERT(sizeof(JSIdArray) > sizeof(jsid)); - size_t len = props.length(); - size_t idsz = len * sizeof(jsid); - size_t sz = (sizeof(JSIdArray) - sizeof(jsid)) + idsz; - JSIdArray* ida = reinterpret_cast(cx->zone()->pod_malloc(sz)); - if (!ida) - return false; - - ida->length = static_cast(len); - jsid* v = props.begin(); - for (int i = 0; i < ida->length; i++) - ida->vector[i].init(v[i]); - *idap = ida; - return true; -} - JS_FRIEND_API(bool) js::GetPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVector* props) { diff --git a/js/src/jsiter.h b/js/src/jsiter.h index 244eeea5c13c..1ed88bbc1efc 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -146,9 +146,6 @@ class StringIteratorObject : public JSObject static const Class class_; }; -bool -VectorToIdArray(JSContext* cx, AutoIdVector& props, JSIdArray** idap); - bool GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleObject objp); diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index 7a22a92cdf03..c27f01bb4f5c 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -93,7 +93,6 @@ struct JSCrossCompartmentCall; class JSErrorReport; struct JSExceptionState; struct JSFunctionSpec; -struct JSIdArray; struct JSLocaleCallbacks; struct JSObjectMap; struct JSPrincipals; @@ -218,7 +217,6 @@ class JS_PUBLIC_API(AutoGCRooter) enum { VALARRAY = -2, /* js::AutoValueArray */ PARSER = -3, /* js::frontend::Parser */ - IDARRAY = -6, /* js::AutoIdArray */ VALVECTOR = -10, /* js::AutoValueVector */ IDVECTOR = -11, /* js::AutoIdVector */ OBJVECTOR = -14, /* js::AutoObjectVector */ diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 88b6b6d6e6a2..7b3037f8dbd3 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4954,8 +4954,8 @@ Help(JSContext* cx, unsigned argc, Value* vp) RootedObject obj(cx); if (args.length() == 0) { RootedObject global(cx, JS::CurrentGlobalOrNull(cx)); - AutoIdArray ida(cx, JS_Enumerate(cx, global)); - if (!ida) + Rooted ida(cx, IdVector(cx)); + if (!JS_Enumerate(cx, global, &ida)) return false; for (size_t i = 0; i < ida.length(); i++) { diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 511a6eebcca4..3093304e2799 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -2836,8 +2836,8 @@ nsXPCComponents_Utils::MakeObjectPropsNormal(HandleValue vobj, JSContext* cx) RootedObject obj(cx, js::UncheckedUnwrap(&vobj.toObject())); JSAutoCompartment ac(cx, obj); - AutoIdArray ida(cx, JS_Enumerate(cx, obj)); - if (!ida) + Rooted ida(cx, IdVector(cx)); + if (!JS_Enumerate(cx, obj, &ida)) return NS_ERROR_FAILURE; RootedId id(cx); diff --git a/js/xpconnect/src/XPCWrappedJSClass.cpp b/js/xpconnect/src/XPCWrappedJSClass.cpp index 20ff5d16ee3b..96fb02854168 100644 --- a/js/xpconnect/src/XPCWrappedJSClass.cpp +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp @@ -357,8 +357,8 @@ nsXPCWrappedJSClass::BuildPropertyEnumerator(XPCCallContext& ccx, if (!scriptEval.StartEvaluating(aJSObj)) return NS_ERROR_FAILURE; - AutoIdArray idArray(cx, JS_Enumerate(cx, aJSObj)); - if (!idArray) + Rooted idArray(cx, IdVector(cx)); + if (!JS_Enumerate(cx, aJSObj, &idArray)) return NS_ERROR_FAILURE; nsCOMArray propertyArray(idArray.length()); diff --git a/widget/android/NativeJSContainer.cpp b/widget/android/NativeJSContainer.cpp index b6e2d2091b5c..ea773a34a5fa 100644 --- a/widget/android/NativeJSContainer.cpp +++ b/widget/android/NativeJSContainer.cpp @@ -262,9 +262,8 @@ class NativeJSContainerImpl final sdk::Bundle::LocalRef BundleFromValue(const JS::HandleObject obj) { - const JS::AutoIdArray ids(mJSContext, - JS_Enumerate(mJSContext, obj)); - if (!CheckJSCall(!!ids)) { + JS::Rooted ids(mJSContext, JS::IdVector(mJSContext)); + if (!CheckJSCall(JS_Enumerate(mJSContext, obj, &ids))) { return nullptr; } From 8599c008e3491ca2939d5672cd8979abed0d58ba Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Mon, 10 Aug 2015 09:26:29 -0700 Subject: [PATCH 29/49] Bug 1191543 - Remove AutoNameVector and replace with Rooted; r=jonco --HG-- extra : rebase_source : 930e012ad7a2930e6261559cd58e19a34e342323 --- js/src/asmjs/AsmJSLink.cpp | 2 +- js/src/frontend/BytecodeCompiler.cpp | 12 +++++++----- js/src/frontend/BytecodeCompiler.h | 7 ++++--- js/src/frontend/Parser.cpp | 3 ++- js/src/frontend/Parser.h | 2 +- js/src/gc/RootMarking.cpp | 6 ------ js/src/jsapi.cpp | 2 +- js/src/jsfun.cpp | 2 +- js/src/jspubtd.h | 1 - js/src/vm/String.h | 18 +----------------- 10 files changed, 18 insertions(+), 37 deletions(-) diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp index 35ed81a13c94..65c3c5d69269 100644 --- a/js/src/asmjs/AsmJSLink.cpp +++ b/js/src/asmjs/AsmJSLink.cpp @@ -846,7 +846,7 @@ HandleDynamicLinkFailure(JSContext* cx, CallArgs args, AsmJSModule& module, Hand if (!fun) return false; - AutoNameVector formals(cx); + Rooted formals(cx, PropertyNameVector(cx)); if (!formals.reserve(3)) return false; diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index f526af73a871..fcaa81cb3c89 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -57,7 +57,7 @@ class MOZ_STACK_CLASS BytecodeCompiler void setSourceArgumentsNotIncluded(); JSScript* compileScript(HandleObject scopeChain, HandleScript evalCaller); - bool compileFunctionBody(MutableHandleFunction fun, const AutoNameVector& formals, + bool compileFunctionBody(MutableHandleFunction fun, Handle formals, GeneratorKind generatorKind); private: @@ -644,7 +644,8 @@ BytecodeCompiler::compileScript(HandleObject scopeChain, HandleScript evalCaller } bool -BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun, const AutoNameVector& formals, +BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun, + Handle formals, GeneratorKind generatorKind) { MOZ_ASSERT(fun); @@ -824,7 +825,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha // handler attribute in an HTML tag, or in a Function() constructor. static bool CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, - const AutoNameVector& formals, SourceBufferHolder& srcBuf, + Handle formals, SourceBufferHolder& srcBuf, Handle enclosingStaticScope, GeneratorKind generatorKind) { MOZ_ASSERT(!options.isRunOnce); @@ -841,7 +842,7 @@ CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyComp bool frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, - const AutoNameVector& formals, JS::SourceBufferHolder& srcBuf, + Handle formals, JS::SourceBufferHolder& srcBuf, Handle enclosingStaticScope) { return CompileFunctionBody(cx, fun, options, formals, srcBuf, @@ -850,7 +851,8 @@ frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, bool frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun, - const ReadOnlyCompileOptions& options, const AutoNameVector& formals, + const ReadOnlyCompileOptions& options, + Handle formals, JS::SourceBufferHolder& srcBuf) { return CompileFunctionBody(cx, fun, options, formals, srcBuf, nullptr, StarGenerator); diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index e22797b37409..6cb1a3b8409a 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -9,11 +9,12 @@ #include "NamespaceImports.h" +#include "vm/String.h" + class JSLinearString; namespace js { -class AutoNameVector; class LazyScript; class LifoAlloc; class ScriptSourceObject; @@ -39,12 +40,12 @@ CompileLazyFunction(JSContext* cx, Handle lazy, const char16_t* cha bool CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, - const AutoNameVector& formals, JS::SourceBufferHolder& srcBuf, + Handle formals, JS::SourceBufferHolder& srcBuf, Handle enclosingStaticScope); bool CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, - const AutoNameVector& formals, JS::SourceBufferHolder& srcBuf); + Handle formals, JS::SourceBufferHolder& srcBuf); ScriptSourceObject* CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options); diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 4108f6981b74..d682af7beddf 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -799,7 +799,8 @@ Parser::checkStrictBinding(PropertyName* name, Node pn) template <> ParseNode* -Parser::standaloneFunctionBody(HandleFunction fun, const AutoNameVector& formals, +Parser::standaloneFunctionBody(HandleFunction fun, + Handle formals, GeneratorKind generatorKind, Directives inheritedDirectives, Directives* newDirectives, diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 8bc4b48f4a06..2d4e20cf84a8 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -544,7 +544,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter // Parse a function, given only its body. Used for the Function and // Generator constructors. - Node standaloneFunctionBody(HandleFunction fun, const AutoNameVector& formals, + Node standaloneFunctionBody(HandleFunction fun, Handle formals, GeneratorKind generatorKind, Directives inheritedDirectives, Directives* newDirectives, HandleObject enclosingStaticScope); diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 299812cb341a..25355c0577b9 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -108,12 +108,6 @@ AutoGCRooter::trace(JSTracer* trc) return; } - case NAMEVECTOR: { - AutoNameVector::VectorImpl& vector = static_cast(this)->vector; - TraceRootRange(trc, vector.length(), vector.begin(), "js::AutoNameVector.vector"); - return; - } - case VALARRAY: { /* * We don't know the template size parameter, but we can safely treat it diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 4e2a7046a905..451cf4ac1322 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4234,7 +4234,7 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, return false; } - AutoNameVector formals(cx); + Rooted formals(cx, PropertyNameVector(cx)); for (unsigned i = 0; i < nargs; i++) { RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i]))); if (!argAtom || !formals.append(argAtom->asPropertyName())) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 74fa6fe96ae8..3f0dd2cb2df2 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1704,7 +1704,7 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener } AutoKeepAtoms keepAtoms(cx->perThreadData); - AutoNameVector formals(cx); + Rooted formals(cx, PropertyNameVector(cx)); bool hasRest = false; diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index c27f01bb4f5c..0cc334d73693 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -221,7 +221,6 @@ class JS_PUBLIC_API(AutoGCRooter) IDVECTOR = -11, /* js::AutoIdVector */ OBJVECTOR = -14, /* js::AutoObjectVector */ SCRIPTVECTOR =-16, /* js::AutoScriptVector */ - NAMEVECTOR = -17, /* js::AutoNameVector */ IONMASM = -19, /* js::jit::MacroAssembler */ WRAPVECTOR = -20, /* js::AutoWrapperVector */ WRAPPER = -21, /* js::AutoWrapperRooter */ diff --git a/js/src/vm/String.h b/js/src/vm/String.h index 3ffd1805c229..922a6b9d3360 100644 --- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -1132,23 +1132,7 @@ NameToId(PropertyName* name) return NON_INTEGER_ATOM_TO_JSID(name); } -class AutoNameVector : public JS::AutoVectorRooterBase -{ - typedef AutoVectorRooterBase BaseType; - public: - explicit AutoNameVector(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoVectorRooterBase(cx, NAMEVECTOR) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - HandlePropertyName operator[](size_t i) const { - return HandlePropertyName::fromMarkedLocation(&begin()[i]); - } - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; +using PropertyNameVector = js::TraceableVector; template void From 38ebbe2248ab4125cc7bbd273ade7b86a1f6bc14 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Tue, 11 Aug 2015 12:19:52 +1000 Subject: [PATCH 30/49] Bug 1193019 - Rename CSSFontFaceLoadEvent to FontFaceSetLoadEvent. r=khuey --HG-- rename : dom/webidl/CSSFontFaceLoadEvent.webidl => dom/webidl/FontFaceSetLoadEvent.webidl --- .../test/test_all_synthetic_events.html | 8 +++--- .../mochitest/general/test_interfaces.html | 4 +-- ...ent.webidl => FontFaceSetLoadEvent.webidl} | 6 ++--- dom/webidl/moz.build | 2 +- layout/style/FontFaceSet.cpp | 10 +++---- layout/style/FontFaceSet.h | 2 +- layout/style/test/test_font_loading_api.html | 26 +++++++++---------- 7 files changed, 29 insertions(+), 29 deletions(-) rename dom/webidl/{CSSFontFaceLoadEvent.webidl => FontFaceSetLoadEvent.webidl} (81%) diff --git a/dom/events/test/test_all_synthetic_events.html b/dom/events/test/test_all_synthetic_events.html index 2700a9f1a3a9..64ec28d86354 100644 --- a/dom/events/test/test_all_synthetic_events.html +++ b/dom/events/test/test_all_synthetic_events.html @@ -134,10 +134,6 @@ const kEventConstructors = { return e; }, }, - CSSFontFaceLoadEvent: { create: function (aName, aProps) { - return new CSSFontFaceLoadEvent(aName, aProps); - }, - }, CustomEvent: { create: function (aName, aProps) { return new CustomEvent(aName, aProps); }, @@ -211,6 +207,10 @@ const kEventConstructors = { return new FocusEvent(aName, aProps); }, }, + FontFaceSetLoadEvent: { create: function (aName, aProps) { + return new FontFaceSetLoadEvent(aName, aProps); + }, + }, GamepadEvent: { create: function (aName, aProps) { return new GamepadEvent(aName, aProps); }, diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 40078a507ad1..568ba0f5d652 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -311,8 +311,6 @@ var interfaceNamesInGlobalScope = "CSSConditionRule", // IMPORTANT: Do not change this list without review from a DOM peer! "CSSCounterStyleRule", -// IMPORTANT: Do not change this list without review from a DOM peer! - "CSSFontFaceLoadEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "CSSFontFaceRule", // IMPORTANT: Do not change this list without review from a DOM peer! @@ -471,6 +469,8 @@ var interfaceNamesInGlobalScope = "FontFace", // IMPORTANT: Do not change this list without review from a DOM peer! "FontFaceSet", +// IMPORTANT: Do not change this list without review from a DOM peer! + "FontFaceSetLoadEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "GainNode", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/webidl/CSSFontFaceLoadEvent.webidl b/dom/webidl/FontFaceSetLoadEvent.webidl similarity index 81% rename from dom/webidl/CSSFontFaceLoadEvent.webidl rename to dom/webidl/FontFaceSetLoadEvent.webidl index 0227639b1c9a..6090d194eedb 100644 --- a/dom/webidl/CSSFontFaceLoadEvent.webidl +++ b/dom/webidl/FontFaceSetLoadEvent.webidl @@ -10,12 +10,12 @@ * liability, trademark and document use rules apply. */ -dictionary CSSFontFaceLoadEventInit : EventInit { +dictionary FontFaceSetLoadEventInit : EventInit { sequence fontfaces = []; }; -[Constructor(DOMString type, optional CSSFontFaceLoadEventInit eventInitDict), +[Constructor(DOMString type, optional FontFaceSetLoadEventInit eventInitDict), Pref="layout.css.font-loading-api.enabled"] -interface CSSFontFaceLoadEvent : Event { +interface FontFaceSetLoadEvent : Event { [Cached, Constant] readonly attribute sequence fontfaces; }; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 75855046b585..394798e2fb74 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -751,7 +751,6 @@ GENERATED_EVENTS_WEBIDL_FILES = [ 'CaretStateChangedEvent.webidl', 'CFStateChangeEvent.webidl', 'CloseEvent.webidl', - 'CSSFontFaceLoadEvent.webidl', 'DataErrorEvent.webidl', 'DataStoreChangeEvent.webidl', 'DeviceLightEvent.webidl', @@ -763,6 +762,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [ 'DownloadEvent.webidl', 'ErrorEvent.webidl', 'ExternalAppEvent.webidl', + 'FontFaceSetLoadEvent.webidl', 'HashChangeEvent.webidl', 'IccChangeEvent.webidl', 'ImageCaptureErrorEvent.webidl', diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index d1f17500832b..4c00e756d4f8 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -9,10 +9,10 @@ #include "gfxFontConstants.h" #include "mozilla/css/Declaration.h" #include "mozilla/css/Loader.h" -#include "mozilla/dom/CSSFontFaceLoadEvent.h" -#include "mozilla/dom/CSSFontFaceLoadEventBinding.h" #include "mozilla/dom/FontFaceSetBinding.h" #include "mozilla/dom/FontFaceSetIterator.h" +#include "mozilla/dom/FontFaceSetLoadEvent.h" +#include "mozilla/dom/FontFaceSetLoadEventBinding.h" #include "mozilla/dom/Promise.h" #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/Logging.h" @@ -1624,7 +1624,7 @@ FontFaceSet::DispatchLoadingFinishedEvent( const nsAString& aType, const nsTArray& aFontFaces) { - CSSFontFaceLoadEventInit init; + FontFaceSetLoadEventInit init; init.mBubbles = false; init.mCancelable = false; OwningNonNull* elements = @@ -1633,8 +1633,8 @@ FontFaceSet::DispatchLoadingFinishedEvent( for (size_t i = 0; i < aFontFaces.Length(); i++) { elements[i] = aFontFaces[i]; } - nsRefPtr event = - CSSFontFaceLoadEvent::Constructor(this, aType, init); + nsRefPtr event = + FontFaceSetLoadEvent::Constructor(this, aType, init); (new AsyncEventDispatcher(this, event))->RunDOMEventWhenSafe(); } diff --git a/layout/style/FontFaceSet.h b/layout/style/FontFaceSet.h index 86b9e1d9527a..0a79f5908ec1 100644 --- a/layout/style/FontFaceSet.h +++ b/layout/style/FontFaceSet.h @@ -215,7 +215,7 @@ private: void CheckLoadingFinishedAfterDelay(); /** - * Dispatches a CSSFontFaceLoadEvent to this object. + * Dispatches a FontFaceSetLoadEvent to this object. */ void DispatchLoadingFinishedEvent( const nsAString& aType, diff --git a/layout/style/test/test_font_loading_api.html b/layout/style/test/test_font_loading_api.html index 2ec9339b27c3..a1f37d67d12a 100644 --- a/layout/style/test/test_font_loading_api.html +++ b/layout/style/test/test_font_loading_api.html @@ -184,9 +184,9 @@ function runTest() { ok(window.FontFace, "FontFace interface object should be present (TEST 1)"); is(Object.getPrototypeOf(FontFace.prototype), Object.prototype, "FontFace should inherit from Object (TEST 1)"); - // (TEST 2) Some miscellaneous tests for CSSFontFaceLoadEvent. - ok(window.CSSFontFaceLoadEvent, "CSSFontFaceLoadEvent interface object should be present (TEST 2)"); - is(Object.getPrototypeOf(CSSFontFaceLoadEvent.prototype), Event.prototype, "CSSFontFaceLoadEvent should inherit from Event (TEST 2)"); + // (TEST 2) Some miscellaneous tests for FontFaceSetLoadEvent. + ok(window.FontFaceSetLoadEvent, "FontFaceSetLoadEvent interface object should be present (TEST 2)"); + is(Object.getPrototypeOf(FontFaceSetLoadEvent.prototype), Event.prototype, "FontFaceSetLoadEvent should inherit from Event (TEST 2)"); }).then(function() { @@ -651,15 +651,15 @@ function runTest() { } var doneListener = function(aEvent) { - is(Object.getPrototypeOf(aEvent), win.CSSFontFaceLoadEvent.prototype, "loadingdone event should be a CSSFontFaceLoadEvent object (TEST 27) (" + win + ")"); - is(aEvent.fontfaces.length, 0, "the CSSFontFaceLoadEvent should have an empty fontfaces array (TEST 27) (" + win + ")"); + is(Object.getPrototypeOf(aEvent), win.FontFaceSetLoadEvent.prototype, "loadingdone event should be a FontFaceSetLoadEvent object (TEST 27) (" + win + ")"); + is(aEvent.fontfaces.length, 0, "the FontFaceSetLoadEvent should have an empty fontfaces array (TEST 27) (" + win + ")"); loadingdoneDispatched = true; check(); }; doc.fonts.addEventListener("loadingdone", doneListener); doc.fonts.onloadingdone = function(aEvent) { - is(Object.getPrototypeOf(aEvent), win.CSSFontFaceLoadEvent.prototype, "loadingdone event should be a CSSFontFaceLoadEvent object (TEST 27) (" + win + ")"); - is(aEvent.fontfaces.length, 0, "the CSSFontFaceLoadEvent should have an empty fontfaces array (TEST 27) (" + win + ")"); + is(Object.getPrototypeOf(aEvent), win.FontFaceSetLoadEvent.prototype, "loadingdone event should be a FontFaceSetLoadEvent object (TEST 27) (" + win + ")"); + is(aEvent.fontfaces.length, 0, "the FontFaceSetLoadEvent should have an empty fontfaces array (TEST 27) (" + win + ")"); onloadingdoneTriggered = true; check(); }; @@ -783,14 +783,14 @@ function runTest() { }; doc.fonts.addEventListener("loadingdone", doneListener); doc.fonts.onloadingdone = function(aEvent) { - is(Object.getPrototypeOf(aEvent), win.CSSFontFaceLoadEvent.prototype, "loadingdone event should be a CSSFontFaceLoadEvent object (TEST 29) (" + win + ")"); - is(aEvent.fontfaces.length, 0, "the CSSFontFaceLoadEvent should have an empty fontfaces array (TEST 29) (" + win + ")"); + is(Object.getPrototypeOf(aEvent), win.FontFaceSetLoadEvent.prototype, "loadingdone event should be a FontFaceSetLoadEvent object (TEST 29) (" + win + ")"); + is(aEvent.fontfaces.length, 0, "the FontFaceSetLoadEvent should have an empty fontfaces array (TEST 29) (" + win + ")"); onloadingdoneTriggered = true; check(); }; var errorListener = function(aEvent) { - is(Object.getPrototypeOf(aEvent), win.CSSFontFaceLoadEvent.prototype, "loadingerror event should be a CSSFontFaceLoadEvent object (TEST 29) (" + win + ")"); - is(aEvent.fontfaces[0], face, "the CSSFontFaceLoadEvent should have a fontfaces array with the FontFace in it (TEST 29) (" + win + ")"); + is(Object.getPrototypeOf(aEvent), win.FontFaceSetLoadEvent.prototype, "loadingerror event should be a FontFaceSetLoadEvent object (TEST 29) (" + win + ")"); + is(aEvent.fontfaces[0], face, "the FontFaceSetLoadEvent should have a fontfaces array with the FontFace in it (TEST 29) (" + win + ")"); loadingerrorDispatched = true; check(); } @@ -848,7 +848,7 @@ function runTest() { }; doc.fonts.addEventListener("loadingdone", doneListener); doc.fonts.onloadingdone = function(aEvent) { - is(aEvent.fontfaces[0], face, "the CSSFontFaceLoadEvent should have a fontfaces array with the FontFace in it (TEST 30) (" + win + ")"); + is(aEvent.fontfaces[0], face, "the FontFaceSetLoadEvent should have a fontfaces array with the FontFace in it (TEST 30) (" + win + ")"); onloadingdoneTriggered = true; check(); }; @@ -899,7 +899,7 @@ function runTest() { }; doc.fonts.addEventListener("loadingdone", doneListener); doc.fonts.onloadingdone = function(aEvent) { - is(aEvent.fontfaces[0], face, "the CSSFontFaceLoadEvent should have a fontfaces array with the FontFace in it (TEST 31) (" + win + ")"); + is(aEvent.fontfaces[0], face, "the FontFaceSetLoadEvent should have a fontfaces array with the FontFace in it (TEST 31) (" + win + ")"); onloadingdoneTriggered = true; check(); }; From 1a31ede1e0cdb412e1ca0cca5ae1751c8565b505 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 10 Aug 2015 22:45:49 -0400 Subject: [PATCH 31/49] Bug 1193085 - Always remove the soundplaying state when starting a new top-level load; r=jaws --- browser/base/content/tabbrowser.xml | 5 +++ .../test/general/browser_audioTabIcon.js | 35 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 0f19f1864ee7..f1ce7e45f359 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -682,6 +682,11 @@ // If the browser is loading it must not be crashed anymore this.mTab.removeAttribute("crashed"); + // If the browser was playing audio, we should remove the playing state. + if (this.mTab.hasAttribute("soundplaying")) { + this.mTab.removeAttribute("soundplaying"); + this.mTabBrowser._tabAttrModified(this.mTab, ["soundplaying"]); + } // If the browser was previously muted, we should restore the muted state. if (this.mTab.hasAttribute("muted")) { this.mTab.linkedBrowser.mute(); diff --git a/browser/base/content/test/general/browser_audioTabIcon.js b/browser/base/content/test/general/browser_audioTabIcon.js index 625cc10c4ab9..016faf2b99a9 100644 --- a/browser/base/content/test/general/browser_audioTabIcon.js +++ b/browser/base/content/test/general/browser_audioTabIcon.js @@ -227,6 +227,39 @@ function* test_click_on_pinned_tab_after_mute() { }, test_on_browser); } +// This test only does something useful in e10s! +function* test_cross_process_load() { + function* test_on_browser(browser) { + let tab = gBrowser.getTabForBrowser(browser); + + // Start playback. + yield ContentTask.spawn(browser, {}, function* () { + let audio = content.document.querySelector("audio"); + audio.play(); + }); + + // Wait for playback to start. + yield wait_for_tab_playing_event(tab, true); + + let soundPlayingStoppedPromise = BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, + event => event.detail.changed.indexOf("soundplaying") >= 0 + ); + + // Go to a different process. + browser.loadURI("about:"); + yield BrowserTestUtils.browserLoaded(browser); + + yield soundPlayingStoppedPromise; + + ok(!tab.hasAttribute("soundplaying"), "Tab should not be playing sound any more"); + } + + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: PAGE + }, test_on_browser); +} + function* test_on_browser(browser) { let tab = gBrowser.getTabForBrowser(browser); @@ -269,3 +302,5 @@ add_task(function* test_page() { url: PAGE }, test_on_browser); }); + +add_task(test_cross_process_load); From 01622f82f43698dbc771c56b298878d8d6f4dff2 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 10 Aug 2015 23:40:05 -0400 Subject: [PATCH 32/49] Bug 1193134 - Run test_click_on_pinned_tab_after_mute independently; r=jaws This way the function runs after all of the tabs from the previous function have been closed, and since this test is independent, it would be better for it to be isolated. --- browser/base/content/test/general/browser_audioTabIcon.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser/base/content/test/general/browser_audioTabIcon.js b/browser/base/content/test/general/browser_audioTabIcon.js index 016faf2b99a9..39f6e2c165a3 100644 --- a/browser/base/content/test/general/browser_audioTabIcon.js +++ b/browser/base/content/test/general/browser_audioTabIcon.js @@ -281,8 +281,6 @@ function* test_on_browser(browser) { }, () => test_on_browser(browser)); } else { yield test_browser_swapping(tab, browser); - - yield test_click_on_pinned_tab_after_mute(); } } @@ -303,4 +301,6 @@ add_task(function* test_page() { }, test_on_browser); }); +add_task(test_click_on_pinned_tab_after_mute); + add_task(test_cross_process_load); From 752016181a07ecd6ea7bb46cf367a5e48a1de883 Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Fri, 3 Jul 2015 10:14:28 +1000 Subject: [PATCH 33/49] Bug 1170842 - Part 1: Sort out ARB_framebuffer_object symbol queries. r=jgilbert Obsolete old patch. Had to resort to using GLFeature detection to look for (EXT/OES)_framebuffer_object. I feel like this sucks. Replace long list of && with ||. Grr. --- gfx/gl/GLContext.cpp | 156 ++++++++++++++++++++++++----------- gfx/gl/GLContext.h | 14 ++++ gfx/gl/GLContextFeatures.cpp | 29 +++++-- gfx/gl/GLContextSymbols.h | 2 + 4 files changed, 147 insertions(+), 54 deletions(-) diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 309542f17084..7decc391a056 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -57,9 +57,11 @@ unsigned GLContext::sCurrentGLContextTLS = -1; uint32_t GLContext::sDebugMode = 0; - -#define MAX_SYMBOL_LENGTH 128 -#define MAX_SYMBOL_NAMES 5 +// If adding defines, don't forget to undefine symbols. See #undef block below. +#define CORE_SYMBOL(x) { (PRFuncPtr*) &mSymbols.f##x, { #x, nullptr } } +#define CORE_EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, { #x, #x #y, #x #z, nullptr } } +#define EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, { #x #y, #x #z, nullptr } } +#define EXT_SYMBOL3(x,y,z,w) { (PRFuncPtr*) &mSymbols.f##x, { #x #y, #x #z, #x #w, nullptr } } #define END_SYMBOLS { nullptr, { nullptr } } // should match the order of GLExtensions, and be null-terminated. @@ -74,6 +76,7 @@ static const char *sExtensionNames[] = { "GL_ANGLE_texture_compression_dxt5", "GL_ANGLE_timer_query", "GL_APPLE_client_storage", + "GL_APPLE_framebuffer_multisample", "GL_APPLE_texture_range", "GL_APPLE_vertex_array_object", "GL_ARB_ES2_compatibility", @@ -85,6 +88,7 @@ static const char *sExtensionNames[] = { "GL_ARB_draw_instanced", "GL_ARB_framebuffer_object", "GL_ARB_framebuffer_sRGB", + "GL_ARB_geometry_shader4", "GL_ARB_half_float_pixel", "GL_ARB_instanced_arrays", "GL_ARB_invalidate_subdata", @@ -120,6 +124,7 @@ static const char *sExtensionNames[] = { "GL_EXT_framebuffer_object", "GL_EXT_framebuffer_sRGB", "GL_EXT_gpu_shader4", + "GL_EXT_multisampled_render_to_texture", "GL_EXT_occlusion_query_boolean", "GL_EXT_packed_depth_stencil", "GL_EXT_read_format_bgra", @@ -143,6 +148,8 @@ static const char *sExtensionNames[] = { "GL_KHR_debug", "GL_NV_draw_instanced", "GL_NV_fence", + "GL_NV_framebuffer_blit", + "GL_NV_geometry_program4", "GL_NV_half_float", "GL_NV_instanced_arrays", "GL_NV_transform_feedback", @@ -155,6 +162,7 @@ static const char *sExtensionNames[] = { "GL_OES_depth32", "GL_OES_depth_texture", "GL_OES_element_index_uint", + "GL_OES_framebuffer_object", "GL_OES_packed_depth_stencil", "GL_OES_rgb8_rgba8", "GL_OES_standard_derivatives", @@ -476,31 +484,16 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) { (PRFuncPtr*) &mSymbols.fGetShaderSource, { "GetShaderSource", nullptr } }, { (PRFuncPtr*) &mSymbols.fShaderSource, { "ShaderSource", nullptr } }, { (PRFuncPtr*) &mSymbols.fVertexAttribPointer, { "VertexAttribPointer", nullptr } }, - { (PRFuncPtr*) &mSymbols.fBindFramebuffer, { "BindFramebuffer", "BindFramebufferEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fBindRenderbuffer, { "BindRenderbuffer", "BindRenderbufferEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fCheckFramebufferStatus, { "CheckFramebufferStatus", "CheckFramebufferStatusEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fFramebufferRenderbuffer, { "FramebufferRenderbuffer", "FramebufferRenderbufferEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fFramebufferTexture2D, { "FramebufferTexture2D", "FramebufferTexture2DEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fGenerateMipmap, { "GenerateMipmap", "GenerateMipmapEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fGetFramebufferAttachmentParameteriv, { "GetFramebufferAttachmentParameteriv", "GetFramebufferAttachmentParameterivEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fGetRenderbufferParameteriv, { "GetRenderbufferParameteriv", "GetRenderbufferParameterivEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fIsFramebuffer, { "IsFramebuffer", "IsFramebufferEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fIsRenderbuffer, { "IsRenderbuffer", "IsRenderbufferEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fRenderbufferStorage, { "RenderbufferStorage", "RenderbufferStorageEXT", nullptr } }, { (PRFuncPtr*) &mSymbols.fGenBuffers, { "GenBuffers", "GenBuffersARB", nullptr } }, { (PRFuncPtr*) &mSymbols.fGenTextures, { "GenTextures", nullptr } }, { (PRFuncPtr*) &mSymbols.fCreateProgram, { "CreateProgram", "CreateProgramARB", nullptr } }, { (PRFuncPtr*) &mSymbols.fCreateShader, { "CreateShader", "CreateShaderARB", nullptr } }, - { (PRFuncPtr*) &mSymbols.fGenFramebuffers, { "GenFramebuffers", "GenFramebuffersEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fGenRenderbuffers, { "GenRenderbuffers", "GenRenderbuffersEXT", nullptr } }, { (PRFuncPtr*) &mSymbols.fDeleteBuffers, { "DeleteBuffers", "DeleteBuffersARB", nullptr } }, { (PRFuncPtr*) &mSymbols.fDeleteTextures, { "DeleteTextures", "DeleteTexturesARB", nullptr } }, { (PRFuncPtr*) &mSymbols.fDeleteProgram, { "DeleteProgram", "DeleteProgramARB", nullptr } }, { (PRFuncPtr*) &mSymbols.fDeleteShader, { "DeleteShader", "DeleteShaderARB", nullptr } }, - { (PRFuncPtr*) &mSymbols.fDeleteFramebuffers, { "DeleteFramebuffers", "DeleteFramebuffersEXT", nullptr } }, - { (PRFuncPtr*) &mSymbols.fDeleteRenderbuffers, { "DeleteRenderbuffers", "DeleteRenderbuffersEXT", nullptr } }, END_SYMBOLS @@ -751,48 +744,107 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) } } - // Check for aux symbols based on extensions - if (IsSupported(GLFeature::framebuffer_blit)) - { + // Check for ARB_framebuffer_objects + if (IsSupported(GLFeature::framebuffer_object)) { + // https://www.opengl.org/registry/specs/ARB/framebuffer_object.txt SymLoadStruct coreSymbols[] = { - { (PRFuncPtr*) &mSymbols.fBlitFramebuffer, { "BlitFramebuffer", nullptr } }, + CORE_SYMBOL(IsRenderbuffer), + CORE_SYMBOL(BindRenderbuffer), + CORE_SYMBOL(DeleteRenderbuffers), + CORE_SYMBOL(GenRenderbuffers), + CORE_SYMBOL(RenderbufferStorage), + CORE_SYMBOL(RenderbufferStorageMultisample), + CORE_SYMBOL(GetRenderbufferParameteriv), + CORE_SYMBOL(IsFramebuffer), + CORE_SYMBOL(BindFramebuffer), + CORE_SYMBOL(DeleteFramebuffers), + CORE_SYMBOL(GenFramebuffers), + CORE_SYMBOL(CheckFramebufferStatus), + CORE_SYMBOL(FramebufferTexture2D), + CORE_SYMBOL(FramebufferTextureLayer), + CORE_SYMBOL(FramebufferRenderbuffer), + CORE_SYMBOL(GetFramebufferAttachmentParameteriv), + CORE_SYMBOL(BlitFramebuffer), + CORE_SYMBOL(GenerateMipmap), END_SYMBOLS }; - SymLoadStruct extSymbols[] = { - { (PRFuncPtr*) &mSymbols.fBlitFramebuffer, { "BlitFramebufferEXT", "BlitFramebufferANGLE", nullptr } }, - END_SYMBOLS - }; - - bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::framebuffer_blit); - - if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) { - NS_ERROR("GL supports framebuffer_blit without supplying glBlitFramebuffer"); - - MarkUnsupported(GLFeature::framebuffer_blit); - ClearSymbols(coreSymbols); + if (!LoadSymbols(coreSymbols, trygl, prefix)) { + NS_ERROR("GL supports framebuffer_object without supplying its functions."); + MarkUnsupported(GLFeature::framebuffer_object); } } - if (IsSupported(GLFeature::framebuffer_multisample)) - { - SymLoadStruct coreSymbols[] = { - { (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample, { "RenderbufferStorageMultisample", nullptr } }, - END_SYMBOLS - }; + if (!IsSupported(GLFeature::framebuffer_object)) { - SymLoadStruct extSymbols[] = { - { (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample, { "RenderbufferStorageMultisampleEXT", "RenderbufferStorageMultisampleANGLE", nullptr } }, - END_SYMBOLS - }; + // Check for aux symbols based on extensions + if (IsSupported(GLFeature::framebuffer_object_EXT_OES)) + { + SymLoadStruct extSymbols[] = { + CORE_EXT_SYMBOL2(IsRenderbuffer, EXT, OES), + CORE_EXT_SYMBOL2(BindRenderbuffer, EXT, OES), + CORE_EXT_SYMBOL2(DeleteRenderbuffers, EXT, OES), + CORE_EXT_SYMBOL2(GenRenderbuffers, EXT, OES), + CORE_EXT_SYMBOL2(RenderbufferStorage, EXT, OES), + CORE_EXT_SYMBOL2(GetRenderbufferParameteriv, EXT, OES), + CORE_EXT_SYMBOL2(IsFramebuffer, EXT, OES), + CORE_EXT_SYMBOL2(BindFramebuffer, EXT, OES), + CORE_EXT_SYMBOL2(DeleteFramebuffers, EXT, OES), + CORE_EXT_SYMBOL2(GenFramebuffers, EXT, OES), + CORE_EXT_SYMBOL2(CheckFramebufferStatus, EXT, OES), + CORE_EXT_SYMBOL2(FramebufferTexture2D, EXT, OES), + CORE_EXT_SYMBOL2(FramebufferRenderbuffer, EXT, OES), + CORE_EXT_SYMBOL2(GetFramebufferAttachmentParameteriv, EXT, OES), + CORE_EXT_SYMBOL2(GenerateMipmap, EXT, OES), + END_SYMBOLS + }; - bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::framebuffer_multisample); + if (!LoadSymbols(extSymbols, trygl, prefix)) { + NS_ERROR("GL supports framebuffer_object without supplying its functions."); + } + } - if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) { - NS_ERROR("GL supports framebuffer_multisample without supplying glRenderbufferStorageMultisample"); + if (IsExtensionSupported(GLContext::ANGLE_framebuffer_blit) || + IsExtensionSupported(GLContext::EXT_framebuffer_blit) || + IsExtensionSupported(GLContext::NV_framebuffer_blit)) - MarkUnsupported(GLFeature::framebuffer_multisample); - ClearSymbols(coreSymbols); + { + SymLoadStruct extSymbols[] = { + EXT_SYMBOL3(BlitFramebuffer, ANGLE, EXT, NV), + END_SYMBOLS + }; + + if (!LoadSymbols(extSymbols, trygl, prefix)) { + NS_ERROR("GL supports framebuffer_blit without supplying its functions."); + } + } + + if (IsExtensionSupported(GLContext::ANGLE_framebuffer_multisample) || + IsExtensionSupported(GLContext::APPLE_framebuffer_multisample) || + IsExtensionSupported(GLContext::EXT_framebuffer_multisample) || + IsExtensionSupported(GLContext::EXT_multisampled_render_to_texture)) + { + SymLoadStruct extSymbols[] = { + EXT_SYMBOL3(RenderbufferStorageMultisample, ANGLE, APPLE, EXT), + END_SYMBOLS + }; + + if (!LoadSymbols(extSymbols, trygl, prefix)) { + NS_ERROR("GL supports framebuffer_multisample without supplying its functions."); + } + } + + if (IsExtensionSupported(GLContext::ARB_geometry_shader4) || + IsExtensionSupported(GLContext::NV_geometry_program4)) + { + SymLoadStruct extSymbols[] = { + EXT_SYMBOL2(FramebufferTextureLayer, ARB, EXT), + END_SYMBOLS + }; + + if (!LoadSymbols(extSymbols, trygl, prefix)) { + NS_ERROR("GL supports geometry_shader4 withot supplying its functions."); + } } } @@ -1581,6 +1633,12 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) return mInitialized; } +#undef CORE_SYMBOL +#undef CORE_EXT_SYMBOL2 +#undef EXT_SYMBOL2 +#undef EXT_SYMBOL3 +#undef END_SYMBOLS + void GLContext::DebugCallback(GLenum source, GLenum type, diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index a73ce3abed32..cf7ae7aa7b59 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -97,6 +97,7 @@ enum class GLFeature { framebuffer_blit, framebuffer_multisample, framebuffer_object, + framebuffer_object_EXT_OES, get_integer_indexed, get_integer64_indexed, get_query_object_i64v, @@ -385,6 +386,7 @@ public: ANGLE_texture_compression_dxt5, ANGLE_timer_query, APPLE_client_storage, + APPLE_framebuffer_multisample, APPLE_texture_range, APPLE_vertex_array_object, ARB_ES2_compatibility, @@ -396,6 +398,7 @@ public: ARB_draw_instanced, ARB_framebuffer_object, ARB_framebuffer_sRGB, + ARB_geometry_shader4, ARB_half_float_pixel, ARB_instanced_arrays, ARB_invalidate_subdata, @@ -431,6 +434,7 @@ public: EXT_framebuffer_object, EXT_framebuffer_sRGB, EXT_gpu_shader4, + EXT_multisampled_render_to_texture, EXT_occlusion_query_boolean, EXT_packed_depth_stencil, EXT_read_format_bgra, @@ -454,6 +458,8 @@ public: KHR_debug, NV_draw_instanced, NV_fence, + NV_framebuffer_blit, + NV_geometry_program4, NV_half_float, NV_instanced_arrays, NV_transform_feedback, @@ -466,6 +472,7 @@ public: OES_depth32, OES_depth_texture, OES_element_index_uint, + OES_framebuffer_object, OES_packed_depth_stencil, OES_rgb8_rgba8, OES_standard_derivatives, @@ -1944,6 +1951,13 @@ public: AFTER_GL_CALL; } + void fFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fFramebufferTextureLayer); + mSymbols.fFramebufferTextureLayer(target, attachment, texture, level, layer); + AFTER_GL_CALL; + } + void fGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* value) { BEFORE_GL_CALL; mSymbols.fGetFramebufferAttachmentParameteriv(target, attachment, pname, value); diff --git a/gfx/gl/GLContextFeatures.cpp b/gfx/gl/GLContextFeatures.cpp index fefba7e38839..4428b9faf044 100644 --- a/gfx/gl/GLContextFeatures.cpp +++ b/gfx/gl/GLContextFeatures.cpp @@ -210,34 +210,53 @@ static const FeatureInfo sFeatureInfoArr[] = { } }, { + // Check for just the blit framebuffer blit part of + // ARB_framebuffer_object "framebuffer_blit", GLVersion::GL3, GLESVersion::ES3, - GLContext::Extension_None, + GLContext::ARB_framebuffer_object, { - GLContext::EXT_framebuffer_blit, GLContext::ANGLE_framebuffer_blit, + GLContext::EXT_framebuffer_blit, + GLContext::NV_framebuffer_blit, GLContext::Extensions_End } }, { + // Check for just the multisample renderbuffer part of + // ARB_framebuffer_object "framebuffer_multisample", GLVersion::GL3, GLESVersion::ES3, - GLContext::Extension_None, + GLContext::ARB_framebuffer_object, { - GLContext::EXT_framebuffer_multisample, GLContext::ANGLE_framebuffer_multisample, + GLContext::APPLE_framebuffer_multisample, + GLContext::EXT_framebuffer_multisample, + GLContext::EXT_multisampled_render_to_texture, GLContext::Extensions_End } }, { + // ARB_framebuffer_object support "framebuffer_object", GLVersion::GL3, - GLESVersion::ES2, + GLESVersion::ES3, GLContext::ARB_framebuffer_object, + { + GLContext::Extensions_End + } + }, + { + // EXT_framebuffer_object/OES_framebuffer_object support + "framebuffer_object_EXT_OES", + GLVersion::GL3, + GLESVersion::ES2, + GLContext::Extension_None, { GLContext::EXT_framebuffer_object, + GLContext::OES_framebuffer_object, GLContext::Extensions_End } }, diff --git a/gfx/gl/GLContextSymbols.h b/gfx/gl/GLContextSymbols.h index 9a5b9d8a5cc5..0e98204fd286 100644 --- a/gfx/gl/GLContextSymbols.h +++ b/gfx/gl/GLContextSymbols.h @@ -329,6 +329,8 @@ struct GLContextSymbols PFNGLFRAMEBUFFERRENDERBUFFER fFramebufferRenderbuffer; typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERTEXTURE2D) (GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint texture, GLint level); PFNGLFRAMEBUFFERTEXTURE2D fFramebufferTexture2D; + typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); + PFNGLFRAMEBUFFERTEXTURELAYERPROC fFramebufferTextureLayer; typedef void (GLAPIENTRY * PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIV) (GLenum target, GLenum attachment, GLenum pname, GLint* value); PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIV fGetFramebufferAttachmentParameteriv; typedef void (GLAPIENTRY * PFNGLGETRENDERBUFFERPARAMETERIV) (GLenum target, GLenum pname, GLint* value); From 18084ad811400d37a82ee4074ce86c9bcfcaa9d2 Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Fri, 3 Jul 2015 10:16:09 +1000 Subject: [PATCH 34/49] Bug 1170842 - Part 2: Wrangle glGetInternalformativ symbols. r=jgilbert --- gfx/gl/GLContext.cpp | 15 +++++++++++++++ gfx/gl/GLContext.h | 13 +++++++++++++ gfx/gl/GLContextFeatures.cpp | 9 +++++++++ gfx/gl/GLContextSymbols.h | 4 ++++ 4 files changed, 41 insertions(+) diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 7decc391a056..dff172ba8619 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -91,6 +91,7 @@ static const char *sExtensionNames[] = { "GL_ARB_geometry_shader4", "GL_ARB_half_float_pixel", "GL_ARB_instanced_arrays", + "GL_ARB_internalformat_query", "GL_ARB_invalidate_subdata", "GL_ARB_map_buffer_range", "GL_ARB_occlusion_query2", @@ -1462,6 +1463,20 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) } } + if (IsSupported(GLFeature::internalformat_query)) { + SymLoadStruct coreSymbols[] = { + CORE_SYMBOL(GetInternalformativ), + END_SYMBOLS + }; + + if (!LoadSymbols(&coreSymbols[0], trygl, prefix)) { + NS_ERROR("GL supports internalformat query without supplying its functions."); + + MarkUnsupported(GLFeature::internalformat_query); + ClearSymbols(coreSymbols); + } + } + if (IsSupported(GLFeature::invalidate_framebuffer)) { SymLoadStruct invSymbols[] = { { (PRFuncPtr *) &mSymbols.fInvalidateFramebuffer, { "InvalidateFramebuffer", nullptr } }, diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index cf7ae7aa7b59..0f23d13e7184 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -106,6 +106,7 @@ enum class GLFeature { gpu_shader4, instanced_arrays, instanced_non_arrays, + internalformat_query, invalidate_framebuffer, map_buffer_range, occlusion_query, @@ -401,6 +402,7 @@ public: ARB_geometry_shader4, ARB_half_float_pixel, ARB_instanced_arrays, + ARB_internalformat_query, ARB_invalidate_subdata, ARB_map_buffer_range, ARB_occlusion_query2, @@ -2532,6 +2534,17 @@ public: AFTER_GL_CALL; } +// ----------------------------------------------------------------------------- +// Feature internalformat_query +public: + void fGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) { + BEFORE_GL_CALL; + ASSERT_SYMBOL_PRESENT(fGetInternalformativ); + mSymbols.fGetInternalformativ(target, internalformat, pname, bufSize, params); + AFTER_GL_CALL; + } + + // ----------------------------------------------------------------------------- // Package XXX_query_counter /** diff --git a/gfx/gl/GLContextFeatures.cpp b/gfx/gl/GLContextFeatures.cpp index 4428b9faf044..780a9950169a 100644 --- a/gfx/gl/GLContextFeatures.cpp +++ b/gfx/gl/GLContextFeatures.cpp @@ -351,6 +351,15 @@ static const FeatureInfo sFeatureInfoArr[] = { * has no such restriction. */ }, + { + "internalformat_query", + GLVersion::GL4_2, + GLESVersion::ES3, + GLContext::ARB_internalformat_query, + { + GLContext::Extensions_End + } + }, { "invalidate_framebuffer", GLVersion::GL4_3, diff --git a/gfx/gl/GLContextSymbols.h b/gfx/gl/GLContextSymbols.h index 0e98204fd286..a3469e09242f 100644 --- a/gfx/gl/GLContextSymbols.h +++ b/gfx/gl/GLContextSymbols.h @@ -489,6 +489,10 @@ struct GLContextSymbols typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBDIVISOR) (GLuint index, GLuint divisor); PFNGLVERTEXATTRIBDIVISOR fVertexAttribDivisor; + // ARB_internalformat_query + typedef void (GLAPIENTRY * PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params); + PFNGLGETINTERNALFORMATIVPROC fGetInternalformativ; + // ARB_transform_feedback2 / OpenGL 4.0 / OpenGL ES 3.0 typedef void (GLAPIENTRY * PFNGLBINDBUFFERBASE) (GLenum target, GLuint index, GLuint buffer); PFNGLBINDBUFFERBASE fBindBufferBase; From 5b4913acf0afb2415096997bc233e6deb589b66a Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Fri, 3 Jul 2015 11:54:07 +1000 Subject: [PATCH 35/49] Bug 1170842 - Part 3: Implement GetInternalformatParameter. r=jgilbert, r=smaug --- dom/canvas/WebGL2Context.h | 11 +++- dom/canvas/WebGL2ContextFramebuffers.cpp | 15 ------ dom/canvas/WebGL2ContextRenderbuffers.cpp | 66 +++++++++++++++++++++++ dom/canvas/moz.build | 1 + dom/webidl/WebGL2RenderingContext.webidl | 5 +- 5 files changed, 79 insertions(+), 19 deletions(-) create mode 100644 dom/canvas/WebGL2ContextRenderbuffers.cpp diff --git a/dom/canvas/WebGL2Context.h b/dom/canvas/WebGL2Context.h index fe4ddab7cbe3..045cbb11b40a 100644 --- a/dom/canvas/WebGL2Context.h +++ b/dom/canvas/WebGL2Context.h @@ -55,13 +55,20 @@ public: void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); - void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); - void GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat, GLenum pname, JS::MutableHandleValue retval); + void FramebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture* texture, GLint level, GLint layer); void InvalidateFramebuffer(GLenum target, const dom::Sequence& attachments, ErrorResult& rv); void InvalidateSubFramebuffer (GLenum target, const dom::Sequence& attachments, GLint x, GLint y, GLsizei width, GLsizei height, ErrorResult& rv); void ReadBuffer(GLenum mode); + + + // ------------------------------------------------------------------------- + // Renderbuffer objects - WebGL2ContextRenderbuffers.cpp + + void GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat, + GLenum pname, JS::MutableHandleValue retval, + ErrorResult& rv); void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); diff --git a/dom/canvas/WebGL2ContextFramebuffers.cpp b/dom/canvas/WebGL2ContextFramebuffers.cpp index a50071e089bb..ab09fc1eb9a3 100644 --- a/dom/canvas/WebGL2ContextFramebuffers.cpp +++ b/dom/canvas/WebGL2ContextFramebuffers.cpp @@ -336,12 +336,6 @@ WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint GenerateWarning("framebufferTextureLayer: Not Implemented."); } -void -WebGL2Context::GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat, GLenum pname, JS::MutableHandleValue retval) -{ - GenerateWarning("getInternalformatParameter: Not Implemented."); -} - // Map attachments intended for the default buffer, to attachments for a non- // default buffer. static bool @@ -536,13 +530,4 @@ WebGL2Context::ReadBuffer(GLenum mode) gl->Screen()->SetReadBuffer(mode); } -void -WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples, - GLenum internalFormat, - GLsizei width, GLsizei height) -{ - RenderbufferStorage_base("renderbufferStorageMultisample", target, samples, - internalFormat, width, height); -} - } // namespace mozilla diff --git a/dom/canvas/WebGL2ContextRenderbuffers.cpp b/dom/canvas/WebGL2ContextRenderbuffers.cpp new file mode 100644 index 000000000000..7ad686414a3a --- /dev/null +++ b/dom/canvas/WebGL2ContextRenderbuffers.cpp @@ -0,0 +1,66 @@ +/* -*- 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 "WebGL2Context.h" + +#include "GLContext.h" +#include "WebGLContextUtils.h" + +namespace mozilla { + +void +WebGL2Context::GetInternalformatParameter(JSContext* cx, GLenum target, + GLenum internalformat, GLenum pname, + JS::MutableHandleValue retval, + ErrorResult& rv) +{ + if (IsContextLost()) + return; + + if (target != LOCAL_GL_RENDERBUFFER) { + return ErrorInvalidEnumInfo("getInternalfomratParameter: target must be " + "RENDERBUFFER. Was:", target); + } + + // GL_INVALID_ENUM is generated if internalformat is not color-, + // depth-, or stencil-renderable. + // TODO: When format table queries lands. + + if (pname != LOCAL_GL_SAMPLES) { + return ErrorInvalidEnumInfo("getInternalformatParameter: pname must be SAMPLES. " + "Was:", pname); + } + + GLint* samples = nullptr; + GLint sampleCount = 0; + gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat, + LOCAL_GL_NUM_SAMPLE_COUNTS, 1, &sampleCount); + if (sampleCount > 0) { + samples = new GLint[sampleCount]; + gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat, LOCAL_GL_SAMPLES, + sampleCount, samples); + } + + JSObject* obj = dom::Int32Array::Create(cx, this, sampleCount, samples); + if (!obj) { + rv = NS_ERROR_OUT_OF_MEMORY; + } + + delete[] samples; + + retval.setObjectOrNull(obj); +} + +void +WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples, + GLenum internalFormat, + GLsizei width, GLsizei height) +{ + RenderbufferStorage_base("renderbufferStorageMultisample", target, samples, + internalFormat, width, height); +} + +} // namespace mozilla diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build index 57984a648eb5..c859d726e986 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -60,6 +60,7 @@ UNIFIED_SOURCES += [ 'WebGL2ContextMRTs.cpp', 'WebGL2ContextPrograms.cpp', 'WebGL2ContextQueries.cpp', + 'WebGL2ContextRenderbuffers.cpp', 'WebGL2ContextSamplers.cpp', 'WebGL2ContextState.cpp', 'WebGL2ContextSync.cpp', diff --git a/dom/webidl/WebGL2RenderingContext.webidl b/dom/webidl/WebGL2RenderingContext.webidl index 30e4c9e16a7f..3be96123809f 100644 --- a/dom/webidl/WebGL2RenderingContext.webidl +++ b/dom/webidl/WebGL2RenderingContext.webidl @@ -323,8 +323,7 @@ interface WebGL2RenderingContext : WebGLRenderingContext /* Framebuffer objects */ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); - void framebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); - any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname); + void framebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture? texture, GLint level, GLint layer); [Throws] void invalidateFramebuffer(GLenum target, sequence attachments); @@ -336,6 +335,8 @@ interface WebGL2RenderingContext : WebGLRenderingContext void readBuffer(GLenum src); /* Renderbuffer objects */ + [Throws] + any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname); void renderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); /* Texture objects */ From 14d3e07d65ea239ce50863311923e575e5c779d8 Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Fri, 3 Jul 2015 11:55:43 +1000 Subject: [PATCH 36/49] Bug 1170842 - Part 4: Implement FramebufferTextureLayer. r=jgilbert --- dom/canvas/WebGL2Context.cpp | 13 +++- dom/canvas/WebGL2Context.h | 6 ++ dom/canvas/WebGL2ContextFramebuffers.cpp | 88 +++++++++++++++++++++++- dom/canvas/WebGLContext.cpp | 2 + dom/canvas/WebGLContext.h | 2 + dom/canvas/WebGLFramebuffer.cpp | 70 ++++++++++++++++--- dom/canvas/WebGLFramebuffer.h | 11 ++- 7 files changed, 175 insertions(+), 17 deletions(-) diff --git a/dom/canvas/WebGL2Context.cpp b/dom/canvas/WebGL2Context.cpp index 0532eb001d1f..0a0b0edf34a5 100644 --- a/dom/canvas/WebGL2Context.cpp +++ b/dom/canvas/WebGL2Context.cpp @@ -79,8 +79,7 @@ static const gl::GLFeature kRequiredFeatures[] = { gl::GLFeature::element_index_uint, gl::GLFeature::frag_color_float, gl::GLFeature::frag_depth, - gl::GLFeature::framebuffer_blit, - gl::GLFeature::framebuffer_multisample, + gl::GLFeature::framebuffer_object, gl::GLFeature::get_integer_indexed, gl::GLFeature::get_integer64_indexed, gl::GLFeature::gpu_shader4, @@ -165,6 +164,16 @@ WebGLContext::InitWebGL2() gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS, &mGLMaxUniformBufferBindings); + if (MinCapabilityMode()) { + mGLMax3DTextureSize = MINVALUE_GL_MAX_3D_TEXTURE_SIZE; + mGLMaxArrayTextureLayers = MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS; + } else { + gl->fGetIntegerv(LOCAL_GL_MAX_3D_TEXTURE_SIZE, + (GLint*) &mGLMax3DTextureSize); + gl->fGetIntegerv(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS, + (GLint*) &mGLMaxArrayTextureLayers); + } + mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs); mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings); diff --git a/dom/canvas/WebGL2Context.h b/dom/canvas/WebGL2Context.h index 045cbb11b40a..4fe61423e5b7 100644 --- a/dom/canvas/WebGL2Context.h +++ b/dom/canvas/WebGL2Context.h @@ -8,6 +8,12 @@ #include "WebGLContext.h" +/* + * Minimum value constants define in 6.2 State Tables of OpenGL ES - 3.0.4 + */ +#define MINVALUE_GL_MAX_3D_TEXTURE_SIZE 256 +#define MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS 256 + namespace mozilla { class ErrorResult; diff --git a/dom/canvas/WebGL2ContextFramebuffers.cpp b/dom/canvas/WebGL2ContextFramebuffers.cpp index ab09fc1eb9a3..62d330f2a254 100644 --- a/dom/canvas/WebGL2ContextFramebuffers.cpp +++ b/dom/canvas/WebGL2ContextFramebuffers.cpp @@ -330,10 +330,92 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY mask, filter); } -void -WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) +static bool +ValidateTextureLayerAttachment(GLenum attachment) { - GenerateWarning("framebufferTextureLayer: Not Implemented."); + if (LOCAL_GL_COLOR_ATTACHMENT0 < attachment && + attachment <= LOCAL_GL_COLOR_ATTACHMENT15) + { + return true; + } + + switch (attachment) { + case LOCAL_GL_DEPTH_ATTACHMENT: + case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT: + case LOCAL_GL_STENCIL_ATTACHMENT: + return true; + } + + return false; +} + +void +WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment, + WebGLTexture* texture, GLint level, GLint layer) +{ + if (IsContextLost()) + return; + + if (!ValidateFramebufferTarget(target, "framebufferTextureLayer")) + return; + + if (!ValidateTextureLayerAttachment(attachment)) + return ErrorInvalidEnumInfo("framebufferTextureLayer: attachment:", attachment); + + if (texture) { + if (texture->IsDeleted()) { + return ErrorInvalidValue("framebufferTextureLayer: texture must be a valid " + "texture object."); + } + + if (level < 0) + return ErrorInvalidValue("framebufferTextureLayer: layer must be >= 0."); + + switch (texture->Target()) { + case LOCAL_GL_TEXTURE_3D: + if ((GLuint) layer >= mGLMax3DTextureSize) { + return ErrorInvalidValue("framebufferTextureLayer: layer must be < " + "MAX_3D_TEXTURE_SIZE"); + } + break; + + case LOCAL_GL_TEXTURE_2D_ARRAY: + if ((GLuint) layer >= mGLMaxArrayTextureLayers) { + return ErrorInvalidValue("framebufferTextureLayer: layer must be < " + "MAX_ARRAY_TEXTURE_LAYERS"); + } + break; + + default: + return ErrorInvalidOperation("framebufferTextureLayer: texture must be an " + "existing 3D texture, or a 2D texture array."); + } + } else { + return ErrorInvalidOperation("framebufferTextureLayer: texture must be an " + "existing 3D texture, or a 2D texture array."); + } + + WebGLFramebuffer* fb; + switch (target) { + case LOCAL_GL_FRAMEBUFFER: + case LOCAL_GL_DRAW_FRAMEBUFFER: + fb = mBoundDrawFramebuffer; + break; + + case LOCAL_GL_READ_FRAMEBUFFER: + fb = mBoundReadFramebuffer; + break; + + default: + MOZ_CRASH("Bad target."); + } + + if (!fb) { + return ErrorInvalidOperation("framebufferTextureLayer: cannot modify" + " framebuffer 0."); + } + + fb->FramebufferTextureLayer(attachment, texture, level, layer); } // Map attachments intended for the default buffer, to attachments for a non- diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index b3a8bdcedd4b..e30958e17ced 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -272,6 +272,8 @@ WebGLContext::WebGLContext() mGLMaxDrawBuffers = 1; mGLMaxTransformFeedbackSeparateAttribs = 0; mGLMaxUniformBufferBindings = 0; + mGLMax3DTextureSize = 0; + mGLMaxArrayTextureLayers = 0; // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13 mPixelStorePackAlignment = 4; diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 71450ab56be2..7ac0beb26d26 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -1077,6 +1077,8 @@ protected: uint32_t mGLMaxTransformFeedbackSeparateAttribs; GLuint mGLMaxUniformBufferBindings; GLsizei mGLMaxSamples; + GLuint mGLMax3DTextureSize; + GLuint mGLMaxArrayTextureLayers; public: GLuint MaxVertexAttribs() const { diff --git a/dom/canvas/WebGLFramebuffer.cpp b/dom/canvas/WebGLFramebuffer.cpp index 65513b5d80fc..34363d1b0aa9 100644 --- a/dom/canvas/WebGLFramebuffer.cpp +++ b/dom/canvas/WebGLFramebuffer.cpp @@ -121,8 +121,14 @@ UnmarkAttachment(WebGLFBAttachPoint& attachment) } void -WebGLFBAttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target, - GLint level) +WebGLFBAttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level) +{ + SetTexImageLayer(tex, target, level, 0); +} + +void +WebGLFBAttachPoint::SetTexImageLayer(WebGLTexture* tex, TexImageTarget target, + GLint level, GLint layer) { mFB->InvalidateFramebufferStatus(); @@ -132,6 +138,7 @@ WebGLFBAttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target, mRenderbufferPtr = nullptr; mTexImageTarget = target; mTexImageLevel = level; + mTexImageLayer = layer; if (tex) tex->MarkAttachment(*this); @@ -378,18 +385,44 @@ WebGLFBAttachPoint::FinalizeAttachment(gl::GLContext* gl, const GLenum imageTarget = ImageTarget().get(); const GLint mipLevel = MipLevel(); + const GLint layer = Layer(); const GLuint glName = Texture()->mGLName; - if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { - gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, - imageTarget, glName, mipLevel); - gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, - imageTarget, glName, mipLevel); - } else { - gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(), - imageTarget, glName, mipLevel); + switch (imageTarget) { + case LOCAL_GL_TEXTURE_2D: + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { + gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, + imageTarget, glName, mipLevel); + gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, + imageTarget, glName, mipLevel); + } else { + gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(), + imageTarget, glName, mipLevel); + } + break; + + case LOCAL_GL_TEXTURE_2D_ARRAY: + case LOCAL_GL_TEXTURE_3D: + if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { + gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_DEPTH_ATTACHMENT, + glName, mipLevel, layer); + gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_STENCIL_ATTACHMENT, + glName, mipLevel, layer); + } else { + gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(), + glName, mipLevel, layer); + } + break; } - return; + return ; } if (Renderbuffer()) { @@ -487,6 +520,21 @@ WebGLFramebuffer::FramebufferTexture2D(FBAttachment attachPointEnum, InvalidateFramebufferStatus(); } +void +WebGLFramebuffer::FramebufferTextureLayer(FBAttachment attachment, WebGLTexture* tex, + GLint level, GLint layer) +{ + MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this || + mContext->mBoundReadFramebuffer == this); + MOZ_ASSERT(tex); + + WebGLFBAttachPoint& attachPoint = GetAttachPoint(attachment); + TexImageTarget texImageTarget = tex->Target(); + attachPoint.SetTexImageLayer(tex, texImageTarget, level, layer); + + InvalidateFramebufferStatus(); +} + WebGLFBAttachPoint& WebGLFramebuffer::GetAttachPoint(FBAttachment attachPoint) { diff --git a/dom/canvas/WebGLFramebuffer.h b/dom/canvas/WebGLFramebuffer.h index eeae53c1c825..7e12b8f47104 100644 --- a/dom/canvas/WebGLFramebuffer.h +++ b/dom/canvas/WebGLFramebuffer.h @@ -34,6 +34,7 @@ private: WebGLRefPtr mRenderbufferPtr; FBAttachment mAttachmentPoint; TexImageTarget mTexImageTarget; + GLint mTexImageLayer; GLint mTexImageLevel; public: @@ -58,8 +59,10 @@ public: } void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level); + void SetTexImageLayer(WebGLTexture* tex, TexImageTarget target, GLint level, + GLint layer); void SetRenderbuffer(WebGLRenderbuffer* rb); - + const WebGLTexture* Texture() const { return mTexturePtr; } @@ -75,6 +78,9 @@ public: TexImageTarget ImageTarget() const { return mTexImageTarget; } + GLint Layer() const { + return mTexImageLayer; + } GLint MipLevel() const { return mTexImageLevel; } @@ -146,6 +152,9 @@ public: TexImageTarget texImageTarget, WebGLTexture* tex, GLint level); + void FramebufferTextureLayer(FBAttachment attachment, WebGLTexture* tex, GLint level, + GLint layer); + bool HasDefinedAttachments() const; bool HasIncompleteAttachments() const; bool AllImageRectsMatch() const; From b122843b65a8112456e5f6c815ae2075ede9650d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 11 Aug 2015 20:22:18 -0700 Subject: [PATCH 37/49] Remove static vars from DriverInitCrashDetection. (bug 1183910 part 1, r=mattwoodrow) --- gfx/src/DriverInitCrashDetection.cpp | 19 ++++++++----------- gfx/src/DriverInitCrashDetection.h | 5 +---- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/gfx/src/DriverInitCrashDetection.cpp b/gfx/src/DriverInitCrashDetection.cpp index b75ff6f67223..02de67a7df98 100644 --- a/gfx/src/DriverInitCrashDetection.cpp +++ b/gfx/src/DriverInitCrashDetection.cpp @@ -20,21 +20,14 @@ namespace mozilla { namespace gfx { -bool DriverInitCrashDetection::sDisableAcceleration = false; bool DriverInitCrashDetection::sEnvironmentHasBeenUpdated = false; DriverInitCrashDetection::DriverInitCrashDetection() : mIsChromeProcess(XRE_GetProcessType() == GeckoProcessType_Default) { - if (sDisableAcceleration) { - // We already disabled acceleration earlier. - return; - } - if (!mIsChromeProcess) { - // In child processes we only need to check the pref state set by the - // parent process. - sDisableAcceleration = (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered)); + // We assume the parent process already performed crash detection for + // graphics devices. return; } @@ -47,7 +40,6 @@ DriverInitCrashDetection::DriverInitCrashDetection() // This is the first time we're checking for a crash recovery, so print // a message and disable acceleration for anyone who asks for it. gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Recovered from graphics driver startup crash; acceleration disabled."; - sDisableAcceleration = true; return; } @@ -83,6 +75,12 @@ DriverInitCrashDetection::~DriverInitCrashDetection() } } +bool +DriverInitCrashDetection::DisableAcceleration() const +{ + return gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered); +} + bool DriverInitCrashDetection::InitLockFilePath() { @@ -183,7 +181,6 @@ DriverInitCrashDetection::UpdateEnvironment() // Finally, mark as changed if the status has been reset by the user. changed |= (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::None)); - mGfxInfo = nullptr; return changed; } diff --git a/gfx/src/DriverInitCrashDetection.h b/gfx/src/DriverInitCrashDetection.h index dab79c9f7c79..0484f9e7bf5f 100644 --- a/gfx/src/DriverInitCrashDetection.h +++ b/gfx/src/DriverInitCrashDetection.h @@ -34,9 +34,7 @@ public: DriverInitCrashDetection(); ~DriverInitCrashDetection(); - bool DisableAcceleration() const { - return sDisableAcceleration; - } + bool DisableAcceleration() const; // These are the values reported to Telemetry (GRAPHICS_DRIVER_STARTUP_TEST). // Values should not change; add new values to the end. @@ -60,7 +58,6 @@ private: void RecordTelemetry(TelemetryState aState); private: - static bool sDisableAcceleration; static bool sEnvironmentHasBeenUpdated; private: From e6a325e77b7f9f0d7ced2443838ecc6b5c823b22 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 11 Aug 2015 20:22:18 -0700 Subject: [PATCH 38/49] Rename DriverInitCrashDetection to DriverCrashGuard. (bug 1190281 part 2, r=mattwoodrow) --HG-- rename : gfx/src/DriverInitCrashDetection.cpp => gfx/src/DriverCrashGuard.cpp rename : gfx/src/DriverInitCrashDetection.h => gfx/src/DriverCrashGuard.h --- ...rashDetection.cpp => DriverCrashGuard.cpp} | 28 +++++++++---------- ...nitCrashDetection.h => DriverCrashGuard.h} | 12 ++++---- gfx/src/moz.build | 4 +-- gfx/thebes/gfxWindowsPlatform.cpp | 4 +-- 4 files changed, 24 insertions(+), 24 deletions(-) rename gfx/src/{DriverInitCrashDetection.cpp => DriverCrashGuard.cpp} (86%) rename gfx/src/{DriverInitCrashDetection.h => DriverCrashGuard.h} (84%) diff --git a/gfx/src/DriverInitCrashDetection.cpp b/gfx/src/DriverCrashGuard.cpp similarity index 86% rename from gfx/src/DriverInitCrashDetection.cpp rename to gfx/src/DriverCrashGuard.cpp index 02de67a7df98..65c046c64978 100644 --- a/gfx/src/DriverInitCrashDetection.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -2,7 +2,7 @@ /* 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 "DriverInitCrashDetection.h" +#include "DriverCrashGuard.h" #include "gfxPrefs.h" #include "nsAppDirectoryServiceDefs.h" #include "nsDirectoryServiceUtils.h" @@ -20,9 +20,9 @@ namespace mozilla { namespace gfx { -bool DriverInitCrashDetection::sEnvironmentHasBeenUpdated = false; +bool DriverCrashGuard::sEnvironmentHasBeenUpdated = false; -DriverInitCrashDetection::DriverInitCrashDetection() +DriverCrashGuard::DriverCrashGuard() : mIsChromeProcess(XRE_GetProcessType() == GeckoProcessType_Default) { if (!mIsChromeProcess) { @@ -56,7 +56,7 @@ DriverInitCrashDetection::DriverInitCrashDetection() RecordTelemetry(TelemetryState::Okay); } -DriverInitCrashDetection::~DriverInitCrashDetection() +DriverCrashGuard::~DriverCrashGuard() { if (mLockFile) { mLockFile->Remove(false); @@ -76,13 +76,13 @@ DriverInitCrashDetection::~DriverInitCrashDetection() } bool -DriverInitCrashDetection::DisableAcceleration() const +DriverCrashGuard::DisableAcceleration() const { return gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered); } bool -DriverInitCrashDetection::InitLockFilePath() +DriverCrashGuard::InitLockFilePath() { NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(mLockFile)); if (!mLockFile) { @@ -95,7 +95,7 @@ DriverInitCrashDetection::InitLockFilePath() } void -DriverInitCrashDetection::AllowDriverInitAttempt() +DriverCrashGuard::AllowDriverInitAttempt() { // Create a temporary tombstone/lockfile. FILE* fp; @@ -120,7 +120,7 @@ DriverInitCrashDetection::AllowDriverInitAttempt() } bool -DriverInitCrashDetection::RecoverFromDriverInitCrash() +DriverCrashGuard::RecoverFromDriverInitCrash() { bool exists; if (mLockFile && @@ -147,7 +147,7 @@ DriverInitCrashDetection::RecoverFromDriverInitCrash() } bool -DriverInitCrashDetection::UpdateEnvironment() +DriverCrashGuard::UpdateEnvironment() { mGfxInfo = services::GetGfxInfo(); @@ -185,7 +185,7 @@ DriverInitCrashDetection::UpdateEnvironment() } bool -DriverInitCrashDetection::FeatureEnabled(int aFeature) +DriverCrashGuard::FeatureEnabled(int aFeature) { int32_t status; if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, &status))) { @@ -195,7 +195,7 @@ DriverInitCrashDetection::FeatureEnabled(int aFeature) } bool -DriverInitCrashDetection::CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue) +DriverCrashGuard::CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue) { bool oldValue; if (NS_SUCCEEDED(Preferences::GetBool(aPrefName, &oldValue)) && @@ -208,7 +208,7 @@ DriverInitCrashDetection::CheckAndUpdateBoolPref(const char* aPrefName, bool aCu } bool -DriverInitCrashDetection::CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue) +DriverCrashGuard::CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue) { nsAdoptingString oldValue = Preferences::GetString(aPrefName); if (oldValue == aCurrentValue) { @@ -219,7 +219,7 @@ DriverInitCrashDetection::CheckAndUpdatePref(const char* aPrefName, const nsAStr } void -DriverInitCrashDetection::FlushPreferences() +DriverCrashGuard::FlushPreferences() { if (nsIPrefService* prefService = Preferences::GetService()) { prefService->SavePrefFile(nullptr); @@ -227,7 +227,7 @@ DriverInitCrashDetection::FlushPreferences() } void -DriverInitCrashDetection::RecordTelemetry(TelemetryState aState) +DriverCrashGuard::RecordTelemetry(TelemetryState aState) { // Since we run this in each child process, we only want the initial results // from the chrome process. diff --git a/gfx/src/DriverInitCrashDetection.h b/gfx/src/DriverCrashGuard.h similarity index 84% rename from gfx/src/DriverInitCrashDetection.h rename to gfx/src/DriverCrashGuard.h index 0484f9e7bf5f..5d3cbed1fdfe 100644 --- a/gfx/src/DriverInitCrashDetection.h +++ b/gfx/src/DriverCrashGuard.h @@ -2,8 +2,8 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef gfx_src_DriverInitCrashDetection_h__ -#define gfx_src_DriverInitCrashDetection_h__ +#ifndef gfx_src_DriverCrashGuard_h__ +#define gfx_src_DriverCrashGuard_h__ #include "gfxCore.h" #include "nsCOMPtr.h" @@ -28,11 +28,11 @@ enum class DriverInitStatus Recovered }; -class DriverInitCrashDetection +class DriverCrashGuard { public: - DriverInitCrashDetection(); - ~DriverInitCrashDetection(); + DriverCrashGuard(); + ~DriverCrashGuard(); bool DisableAcceleration() const; @@ -69,5 +69,5 @@ private: } // namespace gfx } // namespace mozilla -#endif // gfx_src_DriverInitCrashDetection_h__ +#endif // gfx_src_DriverCrashGuard_h__ diff --git a/gfx/src/moz.build b/gfx/src/moz.build index 3d26b88016c5..dcff37790751 100644 --- a/gfx/src/moz.build +++ b/gfx/src/moz.build @@ -14,7 +14,7 @@ XPIDL_MODULE = 'gfx' DEFINES['MOZ_APP_VERSION'] = '"%s"' % CONFIG['MOZ_APP_VERSION'] EXPORTS += [ - 'DriverInitCrashDetection.h', + 'DriverCrashGuard.h', 'FilterSupport.h', 'gfxCore.h', 'gfxCrashReporterUtils.h', @@ -54,7 +54,7 @@ if CONFIG['MOZ_X11']: ] UNIFIED_SOURCES += [ - 'DriverInitCrashDetection.cpp', + 'DriverCrashGuard.cpp', 'FilterSupport.cpp', 'gfxCrashReporterUtils.cpp', 'gfxTelemetry.cpp', diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index ddd226613721..c321b0ec3eb0 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -73,7 +73,7 @@ #include "gfxPrefs.h" #include "VsyncSource.h" -#include "DriverInitCrashDetection.h" +#include "DriverCrashGuard.h" #include "mozilla/dom/ContentParent.h" using namespace mozilla; @@ -2183,7 +2183,7 @@ gfxWindowsPlatform::InitializeDevices() // If we previously crashed initializing devices, bail out now. This is // effectively a parent-process only check, since the content process // cannot create a lock file. - DriverInitCrashDetection detectCrashes; + DriverCrashGuard detectCrashes; if (detectCrashes.DisableAcceleration()) { mAcceleration = FeatureStatus::Blocked; return; From 129b167e20a56e4ad067ec8cfcdb991b30265440 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 11 Aug 2015 20:22:18 -0700 Subject: [PATCH 39/49] Make DriverCrashGuard initialization lazy. (bug 1190281 part 3, r=mattwoodrow) --- gfx/src/DriverCrashGuard.cpp | 22 ++++++++++++++++++++-- gfx/src/DriverCrashGuard.h | 14 +++++++++++++- gfx/thebes/gfxWindowsPlatform.cpp | 2 +- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/gfx/src/DriverCrashGuard.cpp b/gfx/src/DriverCrashGuard.cpp index 65c046c64978..f8a436fe7eaf 100644 --- a/gfx/src/DriverCrashGuard.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -23,7 +23,24 @@ namespace gfx { bool DriverCrashGuard::sEnvironmentHasBeenUpdated = false; DriverCrashGuard::DriverCrashGuard() - : mIsChromeProcess(XRE_GetProcessType() == GeckoProcessType_Default) + : mInitialized(false) + , mIsChromeProcess(XRE_GetProcessType() == GeckoProcessType_Default) +{ +} + +void +DriverCrashGuard::InitializeIfNeeded() +{ + if (mInitialized) { + return; + } + + mInitialized = true; + Initialize(); +} + +void +DriverCrashGuard::Initialize() { if (!mIsChromeProcess) { // We assume the parent process already performed crash detection for @@ -76,8 +93,9 @@ DriverCrashGuard::~DriverCrashGuard() } bool -DriverCrashGuard::DisableAcceleration() const +DriverCrashGuard::Crashed() { + InitializeIfNeeded(); return gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered); } diff --git a/gfx/src/DriverCrashGuard.h b/gfx/src/DriverCrashGuard.h index 5d3cbed1fdfe..6ea99b1ff898 100644 --- a/gfx/src/DriverCrashGuard.h +++ b/gfx/src/DriverCrashGuard.h @@ -28,13 +28,22 @@ enum class DriverInitStatus Recovered }; +// DriverCrashGuard is used to detect crashes at graphics driver callsites. +// +// If the graphics environment is unrecognized or has changed since the last +// session, the crash guard will activate and will detect any crashes within +// the scope of the guard object. +// +// If a callsite has a previously encountered crash, and the environment has +// not changed since the last session, then the guard will set a status flag +// indicating that the driver should not be used. class DriverCrashGuard { public: DriverCrashGuard(); ~DriverCrashGuard(); - bool DisableAcceleration() const; + bool Crashed(); // These are the values reported to Telemetry (GRAPHICS_DRIVER_STARTUP_TEST). // Values should not change; add new values to the end. @@ -46,6 +55,8 @@ public: }; private: + void InitializeIfNeeded(); + void Initialize(); bool InitLockFilePath(); bool UpdateEnvironment(); bool CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue); @@ -61,6 +72,7 @@ private: static bool sEnvironmentHasBeenUpdated; private: + bool mInitialized; bool mIsChromeProcess; nsCOMPtr mGfxInfo; nsCOMPtr mLockFile; diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index c321b0ec3eb0..126016837b50 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -2184,7 +2184,7 @@ gfxWindowsPlatform::InitializeDevices() // effectively a parent-process only check, since the content process // cannot create a lock file. DriverCrashGuard detectCrashes; - if (detectCrashes.DisableAcceleration()) { + if (detectCrashes.Crashed()) { mAcceleration = FeatureStatus::Blocked; return; } From be8aa250bf467a2f64259d444cbbf65b8d5f873b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 11 Aug 2015 20:22:19 -0700 Subject: [PATCH 40/49] Pull D3D11 logic out of DriverCrashGuard. (bug 1190281 part 4, r=mattwoodrow) --- gfx/src/DriverCrashGuard.cpp | 107 +++++++++++++++++++++--------- gfx/src/DriverCrashGuard.h | 39 +++++++---- gfx/thebes/gfxWindowsPlatform.cpp | 2 +- 3 files changed, 104 insertions(+), 44 deletions(-) diff --git a/gfx/src/DriverCrashGuard.cpp b/gfx/src/DriverCrashGuard.cpp index f8a436fe7eaf..eb82fd8af33e 100644 --- a/gfx/src/DriverCrashGuard.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -20,8 +20,6 @@ namespace mozilla { namespace gfx { -bool DriverCrashGuard::sEnvironmentHasBeenUpdated = false; - DriverCrashGuard::DriverCrashGuard() : mInitialized(false) , mIsChromeProcess(XRE_GetProcessType() == GeckoProcessType_Default) @@ -42,12 +40,6 @@ DriverCrashGuard::InitializeIfNeeded() void DriverCrashGuard::Initialize() { - if (!mIsChromeProcess) { - // We assume the parent process already performed crash detection for - // graphics devices. - return; - } - if (!InitLockFilePath()) { gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Failed to create the graphics startup lockfile."; return; @@ -60,13 +52,11 @@ DriverCrashGuard::Initialize() return; } - if (UpdateEnvironment() || sEnvironmentHasBeenUpdated) { + if (PrepareToGuard()) { // Something in the environment changed, *or* a previous instance of this - // class already updated the environment. Allow a fresh attempt at driver - // acceleration. This doesn't mean the previous attempt failed, it just - // means we want to detect whether the new environment crashes. + // class already updated the environment in this session. Enable the + // guard. AllowDriverInitAttempt(); - sEnvironmentHasBeenUpdated = true; return; } @@ -164,12 +154,28 @@ DriverCrashGuard::RecoverFromDriverInitCrash() return false; } +// Return true if the caller should proceed to guard for crashes. False if +// the environment has not changed. bool -DriverCrashGuard::UpdateEnvironment() +DriverCrashGuard::PrepareToGuard() { - mGfxInfo = services::GetGfxInfo(); + static bool sBaseInfoChanged = false; + static bool sBaseInfoChecked = false; + if (!sBaseInfoChecked) { + sBaseInfoChecked = true; + sBaseInfoChanged = UpdateBaseEnvironment(); + } + + // Always update the full environment, even if the base info didn't change. + return UpdateEnvironment() || sBaseInfoChanged; +} + +bool +DriverCrashGuard::UpdateBaseEnvironment() +{ bool changed = false; + mGfxInfo = services::GetGfxInfo(); if (mGfxInfo) { nsString value; @@ -178,27 +184,11 @@ DriverCrashGuard::UpdateEnvironment() changed |= CheckAndUpdatePref("gfx.driver-init.driverVersion", value); mGfxInfo->GetAdapterDeviceID(value); changed |= CheckAndUpdatePref("gfx.driver-init.deviceID", value); - - // Feature status. -#if defined(XP_WIN) - bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() || - (!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D)); - changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d2d", d2dEnabled); - - bool d3d11Enabled = !gfxPrefs::LayersPreferD3D9(); - if (!FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) { - d3d11Enabled = false; - } - changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d3d11", d3d11Enabled); -#endif } // Firefox properties. changed |= CheckAndUpdatePref("gfx.driver-init.appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION)); - // Finally, mark as changed if the status has been reset by the user. - changed |= (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::None)); - return changed; } @@ -246,6 +236,61 @@ DriverCrashGuard::FlushPreferences() void DriverCrashGuard::RecordTelemetry(TelemetryState aState) +{ + // No default telemetry handling yet. +} + +D3D11LayersCrashGuard::D3D11LayersCrashGuard() +{ +} + +void +D3D11LayersCrashGuard::Initialize() +{ + if (!mIsChromeProcess) { + // We assume the parent process already performed crash detection for + // graphics devices. + return; + } + + DriverCrashGuard::Initialize(); +} + +bool +D3D11LayersCrashGuard::UpdateEnvironment() +{ + static bool checked = false; + static bool changed = false; + + if (checked) { + return changed; + } + + checked = true; + + if (mGfxInfo) { + // Feature status. +#if defined(XP_WIN) + bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() || + (!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D)); + changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d2d", d2dEnabled); + + bool d3d11Enabled = !gfxPrefs::LayersPreferD3D9(); + if (!FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) { + d3d11Enabled = false; + } + changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d3d11", d3d11Enabled); +#endif + } + + // Finally, mark as changed if the status has been reset by the user. + changed |= (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::None)); + + return changed; +} + +void +D3D11LayersCrashGuard::RecordTelemetry(TelemetryState aState) { // Since we run this in each child process, we only want the initial results // from the chrome process. diff --git a/gfx/src/DriverCrashGuard.h b/gfx/src/DriverCrashGuard.h index 6ea99b1ff898..6abb8aa3e7be 100644 --- a/gfx/src/DriverCrashGuard.h +++ b/gfx/src/DriverCrashGuard.h @@ -54,28 +54,43 @@ public: AccelerationDisabled = 3 }; -private: - void InitializeIfNeeded(); - void Initialize(); - bool InitLockFilePath(); - bool UpdateEnvironment(); +protected: + virtual void RecordTelemetry(TelemetryState aState); + virtual bool UpdateEnvironment() = 0; + virtual void Initialize() = 0; + + // Helper functions. + bool FeatureEnabled(int aFeature); bool CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue); bool CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue); - bool FeatureEnabled(int aFeature); + +private: + void InitializeIfNeeded(); + bool InitLockFilePath(); void AllowDriverInitAttempt(); bool RecoverFromDriverInitCrash(); void FlushPreferences(); - - void RecordTelemetry(TelemetryState aState); - -private: - static bool sEnvironmentHasBeenUpdated; + bool PrepareToGuard(); + bool UpdateBaseEnvironment(); private: bool mInitialized; + nsCOMPtr mLockFile; + +protected: bool mIsChromeProcess; nsCOMPtr mGfxInfo; - nsCOMPtr mLockFile; +}; + +class D3D11LayersCrashGuard final : public DriverCrashGuard +{ + public: + D3D11LayersCrashGuard(); + + protected: + void Initialize() override; + bool UpdateEnvironment() override; + void RecordTelemetry(TelemetryState aState) override; }; } // namespace gfx diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 126016837b50..cf19a6b4d489 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -2183,7 +2183,7 @@ gfxWindowsPlatform::InitializeDevices() // If we previously crashed initializing devices, bail out now. This is // effectively a parent-process only check, since the content process // cannot create a lock file. - DriverCrashGuard detectCrashes; + D3D11LayersCrashGuard detectCrashes; if (detectCrashes.Crashed()) { mAcceleration = FeatureStatus::Blocked; return; From fc56b993a8552384fcf2cf55d6271f5ec7fa9147 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 11 Aug 2015 20:22:19 -0700 Subject: [PATCH 41/49] Move telemetry recording into D3D11LayersCrashGuard. (bug 1190281 part 5, r=mattwoodrow) --- gfx/src/DriverCrashGuard.cpp | 58 +++++++++++++++++++----------------- gfx/src/DriverCrashGuard.h | 11 +++++-- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/gfx/src/DriverCrashGuard.cpp b/gfx/src/DriverCrashGuard.cpp index eb82fd8af33e..aa61b401359a 100644 --- a/gfx/src/DriverCrashGuard.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -46,9 +46,6 @@ DriverCrashGuard::Initialize() } if (RecoverFromDriverInitCrash()) { - // This is the first time we're checking for a crash recovery, so print - // a message and disable acceleration for anyone who asks for it. - gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Recovered from graphics driver startup crash; acceleration disabled."; return; } @@ -57,10 +54,7 @@ DriverCrashGuard::Initialize() // class already updated the environment in this session. Enable the // guard. AllowDriverInitAttempt(); - return; } - - RecordTelemetry(TelemetryState::Okay); } DriverCrashGuard::~DriverCrashGuard() @@ -117,10 +111,6 @@ DriverCrashGuard::AllowDriverInitAttempt() // Flush preferences, so if we crash, we don't think the environment has changed again. FlushPreferences(); - // If we crash, we'll just lose this. Not a big deal, next startup we'll - // record the failure. - RecordTelemetry(TelemetryState::EnvironmentChanged); - #ifdef MOZ_CRASHREPORTER CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"), NS_LITERAL_CSTRING("1")); @@ -142,13 +132,12 @@ DriverCrashGuard::RecoverFromDriverInitCrash() gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Recovered)); UpdateEnvironment(); FlushPreferences(); - RecordTelemetry(TelemetryState::RecoveredFromCrash); + LogCrashRecovery(); return true; } if (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered)) { - // If we get here, we crashed in the current environment and have already - // disabled acceleration. - RecordTelemetry(TelemetryState::AccelerationDisabled); + // If we get here, we crashed in a previous session. + LogFeatureDisabled(); return true; } return false; @@ -168,7 +157,9 @@ DriverCrashGuard::PrepareToGuard() } // Always update the full environment, even if the base info didn't change. - return UpdateEnvironment() || sBaseInfoChanged; + return UpdateEnvironment() || + sBaseInfoChanged || + gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::None); } bool @@ -234,12 +225,6 @@ DriverCrashGuard::FlushPreferences() } } -void -DriverCrashGuard::RecordTelemetry(TelemetryState aState) -{ - // No default telemetry handling yet. -} - D3D11LayersCrashGuard::D3D11LayersCrashGuard() { } @@ -254,6 +239,10 @@ D3D11LayersCrashGuard::Initialize() } DriverCrashGuard::Initialize(); + + // If no telemetry states have been recorded, this will set the state to okay. + // Otherwise, it will have no effect. + RecordTelemetry(TelemetryState::Okay); } bool @@ -283,18 +272,33 @@ D3D11LayersCrashGuard::UpdateEnvironment() #endif } - // Finally, mark as changed if the status has been reset by the user. - changed |= (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::None)); + if (!changed) { + return false; + } - return changed; + RecordTelemetry(TelemetryState::EnvironmentChanged); + return true; +} + +void +D3D11LayersCrashGuard::LogCrashRecovery() +{ + RecordTelemetry(TelemetryState::RecoveredFromCrash); + gfxCriticalError(CriticalLog::DefaultOptions(false)) << "D3D11 layers just crashed; D3D11 will be disabled."; +} + +void +D3D11LayersCrashGuard::LogFeatureDisabled() +{ + RecordTelemetry(TelemetryState::FeatureDisabled); + gfxCriticalError(CriticalLog::DefaultOptions(false)) << "D3D11 layers disabled due to a prior crash."; } void D3D11LayersCrashGuard::RecordTelemetry(TelemetryState aState) { - // Since we run this in each child process, we only want the initial results - // from the chrome process. - if (XRE_GetProcessType() != GeckoProcessType_Default) { + // D3D11LayersCrashGuard is a no-op in the child process. + if (!XRE_IsParentProcess()) { return; } diff --git a/gfx/src/DriverCrashGuard.h b/gfx/src/DriverCrashGuard.h index 6abb8aa3e7be..10503a1e7973 100644 --- a/gfx/src/DriverCrashGuard.h +++ b/gfx/src/DriverCrashGuard.h @@ -51,13 +51,14 @@ public: Okay = 0, EnvironmentChanged = 1, RecoveredFromCrash = 2, - AccelerationDisabled = 3 + FeatureDisabled = 3 }; protected: - virtual void RecordTelemetry(TelemetryState aState); virtual bool UpdateEnvironment() = 0; virtual void Initialize() = 0; + virtual void LogCrashRecovery() = 0; + virtual void LogFeatureDisabled() = 0; // Helper functions. bool FeatureEnabled(int aFeature); @@ -90,7 +91,11 @@ class D3D11LayersCrashGuard final : public DriverCrashGuard protected: void Initialize() override; bool UpdateEnvironment() override; - void RecordTelemetry(TelemetryState aState) override; + void LogCrashRecovery() override; + void LogFeatureDisabled() override; + + private: + void RecordTelemetry(TelemetryState aState); }; } // namespace gfx From 2a7763cd1dd7427dc2da370e3eac795660d15a44 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 11 Aug 2015 20:22:19 -0700 Subject: [PATCH 42/49] Factor prefs out of DriverCrashGuard. (bug 1190281 part 6, r=mattwoodrow) --- gfx/src/DriverCrashGuard.cpp | 64 ++++++++++++++++++++++++++---------- gfx/src/DriverCrashGuard.h | 20 ++++++++--- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/gfx/src/DriverCrashGuard.cpp b/gfx/src/DriverCrashGuard.cpp index aa61b401359a..cd3a0724c2e1 100644 --- a/gfx/src/DriverCrashGuard.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -20,10 +20,22 @@ namespace mozilla { namespace gfx { -DriverCrashGuard::DriverCrashGuard() - : mInitialized(false) - , mIsChromeProcess(XRE_GetProcessType() == GeckoProcessType_Default) +static const size_t NUM_CRASH_GUARD_TYPES = size_t(CrashGuardType::NUM_TYPES); +static const char* sCrashGuardNames[NUM_CRASH_GUARD_TYPES] = { + "d3d11layers", +}; + +DriverCrashGuard::DriverCrashGuard(CrashGuardType aType) + : mType(aType) + , mInitialized(false) { + MOZ_ASSERT(mType < CrashGuardType::NUM_TYPES); + + mStatusPref.Assign("gfx.driver-init.status."); + mStatusPref.Append(sCrashGuardNames[size_t(mType)]); + + mGuardFilename.Assign(sCrashGuardNames[size_t(mType)]); + mGuardFilename.Append(".guard"); } void @@ -59,14 +71,14 @@ DriverCrashGuard::Initialize() DriverCrashGuard::~DriverCrashGuard() { - if (mLockFile) { - mLockFile->Remove(false); + if (mGuardFile) { + mGuardFile->Remove(false); } - if (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Attempting)) { + if (GetStatus() == DriverInitStatus::Attempting) { // If we attempted to initialize the driver, and got this far without // crashing, assume everything is okay. - gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Okay)); + SetStatus(DriverInitStatus::Okay); #ifdef MOZ_CRASHREPORTER // Remove the crash report annotation. @@ -86,11 +98,12 @@ DriverCrashGuard::Crashed() bool DriverCrashGuard::InitLockFilePath() { - NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(mLockFile)); - if (!mLockFile) { + NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(mGuardFile)); + if (!mGuardFile) { return false; } - if (!NS_SUCCEEDED(mLockFile->AppendNative(NS_LITERAL_CSTRING("gfxinit.lock")))) { + + if (!NS_SUCCEEDED(mGuardFile->AppendNative(mGuardFilename))) { return false; } return true; @@ -101,12 +114,12 @@ DriverCrashGuard::AllowDriverInitAttempt() { // Create a temporary tombstone/lockfile. FILE* fp; - if (!NS_SUCCEEDED(mLockFile->OpenANSIFileDesc("w", &fp))) { + if (!NS_SUCCEEDED(mGuardFile->OpenANSIFileDesc("w", &fp))) { return; } fclose(fp); - gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Attempting)); + SetStatus(DriverInitStatus::Attempting); // Flush preferences, so if we crash, we don't think the environment has changed again. FlushPreferences(); @@ -121,21 +134,22 @@ bool DriverCrashGuard::RecoverFromDriverInitCrash() { bool exists; - if (mLockFile && - NS_SUCCEEDED(mLockFile->Exists(&exists)) && + if (mGuardFile && + NS_SUCCEEDED(mGuardFile->Exists(&exists)) && exists) { // If we get here, we've just recovered from a crash. Disable acceleration // until the environment changes. Since we may have crashed before // preferences we're flushed, we cache the environment again, then flush // preferences so child processes can start right away. - gfxPrefs::SetDriverInitStatus(int32_t(DriverInitStatus::Recovered)); + SetStatus(DriverInitStatus::Recovered); + UpdateBaseEnvironment(); UpdateEnvironment(); FlushPreferences(); LogCrashRecovery(); return true; } - if (gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered)) { + if (GetStatus() == DriverInitStatus::Recovered) { // If we get here, we crashed in a previous session. LogFeatureDisabled(); return true; @@ -180,6 +194,9 @@ DriverCrashGuard::UpdateBaseEnvironment() // Firefox properties. changed |= CheckAndUpdatePref("gfx.driver-init.appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION)); + // Finally, mark as changed if the status has been reset by the user. + changed |= (GetStatus() == DriverInitStatus::None); + return changed; } @@ -217,6 +234,18 @@ DriverCrashGuard::CheckAndUpdatePref(const char* aPrefName, const nsAString& aCu return true; } +DriverInitStatus +DriverCrashGuard::GetStatus() const +{ + return (DriverInitStatus)Preferences::GetInt(mStatusPref.get(), 0); +} + +void +DriverCrashGuard::SetStatus(DriverInitStatus aStatus) +{ + Preferences::SetInt(mStatusPref.get(), int32_t(aStatus)); +} + void DriverCrashGuard::FlushPreferences() { @@ -226,13 +255,14 @@ DriverCrashGuard::FlushPreferences() } D3D11LayersCrashGuard::D3D11LayersCrashGuard() + : DriverCrashGuard(CrashGuardType::D3D11Layers) { } void D3D11LayersCrashGuard::Initialize() { - if (!mIsChromeProcess) { + if (!XRE_IsParentProcess()) { // We assume the parent process already performed crash detection for // graphics devices. return; diff --git a/gfx/src/DriverCrashGuard.h b/gfx/src/DriverCrashGuard.h index 10503a1e7973..bb6c2f342983 100644 --- a/gfx/src/DriverCrashGuard.h +++ b/gfx/src/DriverCrashGuard.h @@ -9,6 +9,7 @@ #include "nsCOMPtr.h" #include "nsIGfxInfo.h" #include "nsIFile.h" +#include "nsString.h" namespace mozilla { namespace gfx { @@ -28,6 +29,13 @@ enum class DriverInitStatus Recovered }; +enum class CrashGuardType : uint32_t +{ + D3D11Layers, + + NUM_TYPES +}; + // DriverCrashGuard is used to detect crashes at graphics driver callsites. // // If the graphics environment is unrecognized or has changed since the last @@ -40,7 +48,7 @@ enum class DriverInitStatus class DriverCrashGuard { public: - DriverCrashGuard(); + DriverCrashGuard(CrashGuardType aType); ~DriverCrashGuard(); bool Crashed(); @@ -55,8 +63,8 @@ public: }; protected: + virtual void Initialize(); virtual bool UpdateEnvironment() = 0; - virtual void Initialize() = 0; virtual void LogCrashRecovery() = 0; virtual void LogFeatureDisabled() = 0; @@ -73,13 +81,17 @@ private: void FlushPreferences(); bool PrepareToGuard(); bool UpdateBaseEnvironment(); + DriverInitStatus GetStatus() const; + void SetStatus(DriverInitStatus aStatus); private: + CrashGuardType mType; bool mInitialized; - nsCOMPtr mLockFile; + nsCOMPtr mGuardFile; protected: - bool mIsChromeProcess; + nsCString mStatusPref; + nsCString mGuardFilename; nsCOMPtr mGfxInfo; }; From 99f7e49fd885f2c1a6d1b33c2686900e77da9a3c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 11 Aug 2015 20:22:20 -0700 Subject: [PATCH 43/49] Allow DriverCrashGuard to be used in content processes. (bug 1190281 part 7, r=mattwoodrow) --- dom/ipc/ContentParent.cpp | 37 ++++++ dom/ipc/ContentParent.h | 5 + dom/ipc/PContent.ipdl | 4 + gfx/src/DriverCrashGuard.cpp | 243 ++++++++++++++++++++++++----------- gfx/src/DriverCrashGuard.h | 44 +++++-- gfx/src/moz.build | 6 + gfx/thebes/gfxPrefs.h | 3 - 7 files changed, 249 insertions(+), 93 deletions(-) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 79309ad2d37e..a536af5082fd 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -2081,6 +2081,10 @@ ContentParent::ActorDestroy(ActorDestroyReason why) SEND_SHUTDOWN_MESSAGE)); } cpm->RemoveContentProcess(this->ChildID()); + + if (mDriverCrashGuard) { + mDriverCrashGuard->NotifyCrashed(); + } } void @@ -5178,6 +5182,39 @@ ContentParent::RecvGetGraphicsDeviceInitData(DeviceInitData* aOut) return true; } +bool +ContentParent::RecvBeginDriverCrashGuard(const uint32_t& aGuardType, bool* aOutCrashed) +{ + // Only one driver crash guard should be active at a time, per-process. + MOZ_ASSERT(!mDriverCrashGuard); + + UniquePtr guard; + switch (gfx::CrashGuardType(aGuardType)) { + case gfx::CrashGuardType::D3D11Layers: + guard = MakeUnique(this); + break; + default: + MOZ_ASSERT_UNREACHABLE("unknown crash guard type"); + return false; + } + + if (guard->Crashed()) { + *aOutCrashed = true; + return true; + } + + *aOutCrashed = false; + mDriverCrashGuard = Move(guard); + return true; +} + +bool +ContentParent::RecvEndDriverCrashGuard(const uint32_t& aGuardType) +{ + mDriverCrashGuard = nullptr; + return true; +} + } // namespace dom } // namespace mozilla diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 332bfd042783..3472462357e4 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -25,6 +25,7 @@ #include "nsIDOMGeoPositionCallback.h" #include "nsIDOMGeoPositionErrorCallback.h" #include "PermissionMessageUtils.h" +#include "DriverCrashGuard.h" #define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown") @@ -814,6 +815,8 @@ private: virtual bool RecvGetGraphicsFeatureStatus(const int32_t& aFeature, int32_t* aStatus, bool* aSuccess) override; + virtual bool RecvBeginDriverCrashGuard(const uint32_t& aGuardType, bool* aOutCrashed) override; + virtual bool RecvEndDriverCrashGuard(const uint32_t& aGuardType) override; virtual bool RecvAddIdleObserver(const uint64_t& observerId, const uint32_t& aIdleTimeInS) override; @@ -954,6 +957,8 @@ private: nsRefPtr mGatherer; #endif nsCString mProfile; + + UniquePtr mDriverCrashGuard; }; } // namespace dom diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 29ab5cedda2e..33f8762693b1 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -933,6 +933,10 @@ parent: sync GetGraphicsFeatureStatus(int32_t aFeature) returns (int32_t aStatus, bool aSuccess); + // Driver crash guards. aGuardType must be a member of CrashGuardType. + sync BeginDriverCrashGuard(uint32_t aGuardType) returns (bool crashDetected); + sync EndDriverCrashGuard(uint32_t aGuardType); + AddIdleObserver(uint64_t observerId, uint32_t idleTimeInS); RemoveIdleObserver(uint64_t observerId, uint32_t idleTimeInS); diff --git a/gfx/src/DriverCrashGuard.cpp b/gfx/src/DriverCrashGuard.cpp index cd3a0724c2e1..b2524a774fa3 100644 --- a/gfx/src/DriverCrashGuard.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -16,6 +16,7 @@ #include "mozilla/Telemetry.h" #include "mozilla/Services.h" #include "mozilla/gfx/Logging.h" +#include "mozilla/dom/ContentChild.h" namespace mozilla { namespace gfx { @@ -25,17 +26,17 @@ static const char* sCrashGuardNames[NUM_CRASH_GUARD_TYPES] = { "d3d11layers", }; -DriverCrashGuard::DriverCrashGuard(CrashGuardType aType) +DriverCrashGuard::DriverCrashGuard(CrashGuardType aType, dom::ContentParent* aContentParent) : mType(aType) + , mMode(aContentParent ? Mode::Proxy : Mode::Normal) , mInitialized(false) + , mGuardActivated(false) + , mCrashDetected(false) { MOZ_ASSERT(mType < CrashGuardType::NUM_TYPES); - mStatusPref.Assign("gfx.driver-init.status."); + mStatusPref.Assign("gfx.crash-guard.status."); mStatusPref.Append(sCrashGuardNames[size_t(mType)]); - - mGuardFilename.Assign(sCrashGuardNames[size_t(mType)]); - mGuardFilename.Append(".guard"); } void @@ -52,120 +53,191 @@ DriverCrashGuard::InitializeIfNeeded() void DriverCrashGuard::Initialize() { - if (!InitLockFilePath()) { - gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Failed to create the graphics startup lockfile."; + if (XRE_IsContentProcess()) { + // Ask the parent whether or not activating the guard is okay. The parent + // won't bother if it detected a crash. + dom::ContentChild* cc = dom::ContentChild::GetSingleton(); + cc->SendBeginDriverCrashGuard(uint32_t(mType), &mCrashDetected); + if (mCrashDetected) { + LogFeatureDisabled(); + return; + } + + ActivateGuard(); return; } - if (RecoverFromDriverInitCrash()) { + // Always check whether or not the lock file exists. For example, we could + // have crashed creating a D3D9 device in the parent process, and on restart + // are now requesting one in the child process. We catch everything here. + if (RecoverFromCrash()) { + mCrashDetected = true; return; } - if (PrepareToGuard()) { - // Something in the environment changed, *or* a previous instance of this - // class already updated the environment in this session. Enable the - // guard. - AllowDriverInitAttempt(); + // If the environment has changed, we always activate the guard. In the + // parent process this performs main-thread disk I/O. Child process guards + // only incur an IPC cost, so if we're proxying for a child process, we + // play it safe and activate the guard as long as we don't expect it to + // crash. + if (CheckOrRefreshEnvironment() || + (mMode == Mode::Proxy && GetStatus() != DriverInitStatus::Crashed)) + { + ActivateGuard(); + return; + } + + // If we got here and our status is "crashed", then the environment has not + // updated and we do not want to attempt to use the driver again. + if (GetStatus() == DriverInitStatus::Crashed) { + mCrashDetected = true; + LogFeatureDisabled(); } } DriverCrashGuard::~DriverCrashGuard() { - if (mGuardFile) { - mGuardFile->Remove(false); + if (!mGuardActivated) { + return; } - if (GetStatus() == DriverInitStatus::Attempting) { - // If we attempted to initialize the driver, and got this far without - // crashing, assume everything is okay. - SetStatus(DriverInitStatus::Okay); + if (XRE_IsParentProcess()) { + if (mGuardFile) { + mGuardFile->Remove(false); + } + + // If during our initialization, no other process encountered a crash, we + // proceed to mark the status as okay. + if (GetStatus() != DriverInitStatus::Crashed) { + SetStatus(DriverInitStatus::Okay); + } + } else { + dom::ContentChild::GetSingleton()->SendEndDriverCrashGuard(uint32_t(mType)); + } #ifdef MOZ_CRASHREPORTER - // Remove the crash report annotation. - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"), - NS_LITERAL_CSTRING("")); + // Remove the crash report annotation. + CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"), + NS_LITERAL_CSTRING("")); #endif - } } bool DriverCrashGuard::Crashed() { InitializeIfNeeded(); - return gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::Recovered); + + // Note, we read mCrashDetected instead of GetStatus(), since in child + // processes we're not guaranteed that the prefs have been synced in + // time. + return mCrashDetected; } -bool -DriverCrashGuard::InitLockFilePath() +nsCOMPtr +DriverCrashGuard::GetGuardFile() { - NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(mGuardFile)); - if (!mGuardFile) { - return false; - } + MOZ_ASSERT(XRE_IsParentProcess()); - if (!NS_SUCCEEDED(mGuardFile->AppendNative(mGuardFilename))) { - return false; + nsCString filename; + filename.Assign(sCrashGuardNames[size_t(mType)]); + filename.Append(".guard"); + + nsCOMPtr file; + NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(file)); + if (!file) { + return nullptr; } - return true; + if (!NS_SUCCEEDED(file->AppendNative(filename))) { + return nullptr; + } + return file; } void -DriverCrashGuard::AllowDriverInitAttempt() +DriverCrashGuard::ActivateGuard() { - // Create a temporary tombstone/lockfile. - FILE* fp; - if (!NS_SUCCEEDED(mGuardFile->OpenANSIFileDesc("w", &fp))) { + MOZ_ASSERT(XRE_IsParentProcess()); + + mGuardActivated = true; + +#ifdef MOZ_CRASHREPORTER + // Anotate crash reports only if we're a real guard. Otherwise, we could + // attribute a random parent process crash to a graphics problem in a child + // process. + if (mMode != Mode::Proxy) { + CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"), + NS_LITERAL_CSTRING("1")); + } +#endif + + // If we're in the content process, the rest of the guarding is handled + // in the parent. + if (XRE_IsContentProcess()) { return; } - fclose(fp); SetStatus(DriverInitStatus::Attempting); - // Flush preferences, so if we crash, we don't think the environment has changed again. - FlushPreferences(); + if (mMode != Mode::Proxy) { + // In parent process guards, we use two tombstones to detect crashes: a + // preferences and a zero-byte file on the filesystem. + FlushPreferences(); -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"), - NS_LITERAL_CSTRING("1")); -#endif + // Create a temporary tombstone/lockfile. + FILE* fp = nullptr; + mGuardFile = GetGuardFile(); + if (!mGuardFile || !NS_SUCCEEDED(mGuardFile->OpenANSIFileDesc("w", &fp))) { + return; + } + fclose(fp); + } +} + +void +DriverCrashGuard::NotifyCrashed() +{ + CheckOrRefreshEnvironment(); + SetStatus(DriverInitStatus::Crashed); + FlushPreferences(); + LogCrashRecovery(); } bool -DriverCrashGuard::RecoverFromDriverInitCrash() +DriverCrashGuard::RecoverFromCrash() { + MOZ_ASSERT(XRE_IsParentProcess()); + + nsCOMPtr file = GetGuardFile(); bool exists; - if (mGuardFile && - NS_SUCCEEDED(mGuardFile->Exists(&exists)) && - exists) + if ((file && + NS_SUCCEEDED(file->Exists(&exists)) && + exists) || + (GetStatus() == DriverInitStatus::Attempting)) { // If we get here, we've just recovered from a crash. Disable acceleration - // until the environment changes. Since we may have crashed before - // preferences we're flushed, we cache the environment again, then flush - // preferences so child processes can start right away. - SetStatus(DriverInitStatus::Recovered); - UpdateBaseEnvironment(); - UpdateEnvironment(); - FlushPreferences(); - LogCrashRecovery(); - return true; - } - if (GetStatus() == DriverInitStatus::Recovered) { - // If we get here, we crashed in a previous session. - LogFeatureDisabled(); + // until the environment changes. + if (file) { + file->Remove(false); + } + NotifyCrashed(); return true; } return false; } // Return true if the caller should proceed to guard for crashes. False if -// the environment has not changed. +// the environment has not changed. We persist the "changed" status across +// calls, so that after an environment changes, all guards for the new +// session are activated rather than just the first. bool -DriverCrashGuard::PrepareToGuard() +DriverCrashGuard::CheckOrRefreshEnvironment() { + // Our result can be cached statically since we don't check live prefs. static bool sBaseInfoChanged = false; static bool sBaseInfoChecked = false; if (!sBaseInfoChecked) { + // None of the prefs we care about, so we cache the result statically. sBaseInfoChecked = true; sBaseInfoChanged = UpdateBaseEnvironment(); } @@ -173,7 +245,7 @@ DriverCrashGuard::PrepareToGuard() // Always update the full environment, even if the base info didn't change. return UpdateEnvironment() || sBaseInfoChanged || - gfxPrefs::DriverInitStatus() == int32_t(DriverInitStatus::None); + GetStatus() == DriverInitStatus::Unknown; } bool @@ -186,16 +258,13 @@ DriverCrashGuard::UpdateBaseEnvironment() // Driver properties. mGfxInfo->GetAdapterDriverVersion(value); - changed |= CheckAndUpdatePref("gfx.driver-init.driverVersion", value); + changed |= CheckAndUpdatePref("driverVersion", value); mGfxInfo->GetAdapterDeviceID(value); - changed |= CheckAndUpdatePref("gfx.driver-init.deviceID", value); + changed |= CheckAndUpdatePref("deviceID", value); } // Firefox properties. - changed |= CheckAndUpdatePref("gfx.driver-init.appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION)); - - // Finally, mark as changed if the status has been reset by the user. - changed |= (GetStatus() == DriverInitStatus::None); + changed |= CheckAndUpdatePref("appVersion", NS_LITERAL_STRING(MOZ_APP_VERSION)); return changed; } @@ -213,27 +282,40 @@ DriverCrashGuard::FeatureEnabled(int aFeature) bool DriverCrashGuard::CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue) { + std::string pref = GetFullPrefName(aPrefName); + bool oldValue; - if (NS_SUCCEEDED(Preferences::GetBool(aPrefName, &oldValue)) && + if (NS_SUCCEEDED(Preferences::GetBool(pref.c_str(), &oldValue)) && oldValue == aCurrentValue) { return false; } - Preferences::SetBool(aPrefName, aCurrentValue); + Preferences::SetBool(pref.c_str(), aCurrentValue); return true; } bool DriverCrashGuard::CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue) { - nsAdoptingString oldValue = Preferences::GetString(aPrefName); + std::string pref = GetFullPrefName(aPrefName); + + nsAdoptingString oldValue = Preferences::GetString(pref.c_str()); if (oldValue == aCurrentValue) { return false; } - Preferences::SetString(aPrefName, aCurrentValue); + Preferences::SetString(pref.c_str(), aCurrentValue); return true; } +std::string +DriverCrashGuard::GetFullPrefName(const char* aPref) +{ + return std::string("gfx.crash-guard.") + + std::string(sCrashGuardNames[uint32_t(mType)]) + + std::string(".") + + std::string(aPref); +} + DriverInitStatus DriverCrashGuard::GetStatus() const { @@ -243,19 +325,23 @@ DriverCrashGuard::GetStatus() const void DriverCrashGuard::SetStatus(DriverInitStatus aStatus) { + MOZ_ASSERT(XRE_IsParentProcess()); + Preferences::SetInt(mStatusPref.get(), int32_t(aStatus)); } void DriverCrashGuard::FlushPreferences() { + MOZ_ASSERT(XRE_IsParentProcess()); + if (nsIPrefService* prefService = Preferences::GetService()) { prefService->SavePrefFile(nullptr); } } -D3D11LayersCrashGuard::D3D11LayersCrashGuard() - : DriverCrashGuard(CrashGuardType::D3D11Layers) +D3D11LayersCrashGuard::D3D11LayersCrashGuard(dom::ContentParent* aContentParent) + : DriverCrashGuard(CrashGuardType::D3D11Layers, aContentParent) { } @@ -278,6 +364,7 @@ D3D11LayersCrashGuard::Initialize() bool D3D11LayersCrashGuard::UpdateEnvironment() { + // Our result can be cached statically since we don't check live prefs. static bool checked = false; static bool changed = false; @@ -292,13 +379,13 @@ D3D11LayersCrashGuard::UpdateEnvironment() #if defined(XP_WIN) bool d2dEnabled = gfxPrefs::Direct2DForceEnabled() || (!gfxPrefs::Direct2DDisabled() && FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT2D)); - changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d2d", d2dEnabled); + changed |= CheckAndUpdateBoolPref("feature-d2d", d2dEnabled); bool d3d11Enabled = !gfxPrefs::LayersPreferD3D9(); if (!FeatureEnabled(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) { d3d11Enabled = false; } - changed |= CheckAndUpdateBoolPref("gfx.driver-init.feature-d3d11", d3d11Enabled); + changed |= CheckAndUpdateBoolPref("feature-d3d11", d3d11Enabled); #endif } diff --git a/gfx/src/DriverCrashGuard.h b/gfx/src/DriverCrashGuard.h index bb6c2f342983..24f565a02221 100644 --- a/gfx/src/DriverCrashGuard.h +++ b/gfx/src/DriverCrashGuard.h @@ -10,14 +10,20 @@ #include "nsIGfxInfo.h" #include "nsIFile.h" #include "nsString.h" +#include namespace mozilla { + +namespace dom { +class ContentParent; +} // namespace dom + namespace gfx { enum class DriverInitStatus { // Drivers have not been initialized yet. - None, + Unknown, // We're attempting to initialize drivers. Attempting, @@ -26,13 +32,12 @@ enum class DriverInitStatus Okay, // We crashed during driver initialization, and have restarted. - Recovered + Crashed }; enum class CrashGuardType : uint32_t { D3D11Layers, - NUM_TYPES }; @@ -48,10 +53,11 @@ enum class CrashGuardType : uint32_t class DriverCrashGuard { public: - DriverCrashGuard(CrashGuardType aType); - ~DriverCrashGuard(); + DriverCrashGuard(CrashGuardType aType, dom::ContentParent* aContentParent); + virtual ~DriverCrashGuard(); bool Crashed(); + void NotifyCrashed(); // These are the values reported to Telemetry (GRAPHICS_DRIVER_STARTUP_TEST). // Values should not change; add new values to the end. @@ -62,6 +68,14 @@ public: FeatureDisabled = 3 }; + enum class Mode { + // Normal operation. + Normal, + + // Acting as a proxy between the parent and child process. + Proxy + }; + protected: virtual void Initialize(); virtual bool UpdateEnvironment() = 0; @@ -72,33 +86,39 @@ protected: bool FeatureEnabled(int aFeature); bool CheckAndUpdatePref(const char* aPrefName, const nsAString& aCurrentValue); bool CheckAndUpdateBoolPref(const char* aPrefName, bool aCurrentValue); + std::string GetFullPrefName(const char* aPref); private: + // Either process. void InitializeIfNeeded(); - bool InitLockFilePath(); - void AllowDriverInitAttempt(); - bool RecoverFromDriverInitCrash(); - void FlushPreferences(); - bool PrepareToGuard(); + bool CheckOrRefreshEnvironment(); bool UpdateBaseEnvironment(); DriverInitStatus GetStatus() const; + + // Parent process only. + nsCOMPtr GetGuardFile(); + bool RecoverFromCrash(); + void ActivateGuard(); + void FlushPreferences(); void SetStatus(DriverInitStatus aStatus); private: CrashGuardType mType; + Mode mMode; bool mInitialized; + bool mGuardActivated; + bool mCrashDetected; nsCOMPtr mGuardFile; protected: nsCString mStatusPref; - nsCString mGuardFilename; nsCOMPtr mGfxInfo; }; class D3D11LayersCrashGuard final : public DriverCrashGuard { public: - D3D11LayersCrashGuard(); + explicit D3D11LayersCrashGuard(dom::ContentParent* aContentParent = nullptr); protected: void Initialize() override; diff --git a/gfx/src/moz.build b/gfx/src/moz.build index dcff37790751..ea1ff8cb4cae 100644 --- a/gfx/src/moz.build +++ b/gfx/src/moz.build @@ -77,6 +77,12 @@ SOURCES += [ FAIL_ON_WARNINGS = True +include('/ipc/chromium/chromium-config.mozbuild') + +LOCAL_INCLUDES += [ + '/dom/ipc', # for ContentChild.h +] + FINAL_LIBRARY = 'xul' CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS'] diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 7b1b8f875cee..dde41004fd40 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -232,9 +232,6 @@ private: DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled", Direct2DForceEnabled, bool, false); DECL_GFX_PREF(Live, "gfx.direct2d.use1_1", Direct2DUse1_1, bool, false); DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false); - // This should be set to values in the DriverInitStatus enumeration found in - // DriverInitCrashDetection.h. - DECL_GFX_PREF(Live, "gfx.driver-init.status", DriverInitStatus, int32_t, 0); DECL_GFX_PREF(Once, "gfx.font_rendering.directwrite.enabled", DirectWriteFontRenderingEnabled, bool, false); DECL_GFX_PREF(Live, "gfx.gralloc.fence-with-readpixels", GrallocFenceWithReadPixels, bool, false); DECL_GFX_PREF(Live, "gfx.layerscope.enabled", LayerScopeEnabled, bool, false); From 2704e2ce1838c47cadf7e382e5f9c62d25294b17 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 11 Aug 2015 20:22:20 -0700 Subject: [PATCH 44/49] Add a crash guard for DXVA2D3D9. (bug 1190281 part 8, r=mattwoodrow) --- dom/ipc/ContentParent.cpp | 3 +++ dom/media/platforms/wmf/DXVA2Manager.cpp | 7 +++++++ gfx/src/DriverCrashGuard.cpp | 25 ++++++++++++++++++++++++ gfx/src/DriverCrashGuard.h | 12 ++++++++++++ 4 files changed, 47 insertions(+) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index a536af5082fd..1bef008771ad 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -5193,6 +5193,9 @@ ContentParent::RecvBeginDriverCrashGuard(const uint32_t& aGuardType, bool* aOutC case gfx::CrashGuardType::D3D11Layers: guard = MakeUnique(this); break; + case gfx::CrashGuardType::D3D9Video: + guard = MakeUnique(this); + break; default: MOZ_ASSERT_UNREACHABLE("unknown crash guard type"); return false; diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index 05abc6aa256a..7d3e4a7ea190 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -14,6 +14,7 @@ #include "mozilla/Preferences.h" #include "mfapi.h" #include "MFTDecoder.h" +#include "DriverCrashGuard.h" const CLSID CLSID_VideoProcessorMFT = { @@ -90,6 +91,12 @@ D3D9DXVA2Manager::Init() { MOZ_ASSERT(NS_IsMainThread()); + gfx::D3D9VideoCrashGuard crashGuard; + if (crashGuard.Crashed()) { + NS_WARNING("DXVA2D3D9 crash detected"); + return E_FAIL; + } + // Create D3D9Ex. HMODULE d3d9lib = LoadLibraryW(L"d3d9.dll"); NS_ENSURE_TRUE(d3d9lib, E_FAIL); diff --git a/gfx/src/DriverCrashGuard.cpp b/gfx/src/DriverCrashGuard.cpp index b2524a774fa3..448fb1e300ba 100644 --- a/gfx/src/DriverCrashGuard.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -24,6 +24,7 @@ namespace gfx { static const size_t NUM_CRASH_GUARD_TYPES = size_t(CrashGuardType::NUM_TYPES); static const char* sCrashGuardNames[NUM_CRASH_GUARD_TYPES] = { "d3d11layers", + "d3d9video", }; DriverCrashGuard::DriverCrashGuard(CrashGuardType aType, dom::ContentParent* aContentParent) @@ -430,5 +431,29 @@ D3D11LayersCrashGuard::RecordTelemetry(TelemetryState aState) sTelemetryStateRecorded = true; } +D3D9VideoCrashGuard::D3D9VideoCrashGuard(dom::ContentParent* aContentParent) + : DriverCrashGuard(CrashGuardType::D3D9Video, aContentParent) +{ +} + +bool +D3D9VideoCrashGuard::UpdateEnvironment() +{ + // We don't care about any extra preferences here. + return false; +} + +void +D3D9VideoCrashGuard::LogCrashRecovery() +{ + gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DXVA2D3D9 just crashed; hardware video will be disabled."; +} + +void +D3D9VideoCrashGuard::LogFeatureDisabled() +{ + gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DXVA2D3D9 video decoding is disabled due to a previous crash."; +} + } // namespace gfx } // namespace mozilla diff --git a/gfx/src/DriverCrashGuard.h b/gfx/src/DriverCrashGuard.h index 24f565a02221..3d48c7f3912a 100644 --- a/gfx/src/DriverCrashGuard.h +++ b/gfx/src/DriverCrashGuard.h @@ -38,6 +38,7 @@ enum class DriverInitStatus enum class CrashGuardType : uint32_t { D3D11Layers, + D3D9Video, NUM_TYPES }; @@ -130,6 +131,17 @@ class D3D11LayersCrashGuard final : public DriverCrashGuard void RecordTelemetry(TelemetryState aState); }; +class D3D9VideoCrashGuard final : public DriverCrashGuard +{ + public: + explicit D3D9VideoCrashGuard(dom::ContentParent* aContentParent = nullptr); + + protected: + bool UpdateEnvironment() override; + void LogCrashRecovery() override; + void LogFeatureDisabled() override; +}; + } // namespace gfx } // namespace mozilla From 5b76d8f3b7d9a4a6c2714a29107f1b396ecbdf45 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 23 Jul 2015 02:37:26 -0700 Subject: [PATCH 45/49] Bug 1181443 (part 3, attempt 2) - Remove nsTHashtable::EnumerateEntries(), which is no longer used. r=froydnj. --HG-- extra : rebase_source : 232b65e93556a311efaf1f2e0b1aee0449b3838d --- xpcom/glue/nsBaseHashtable.h | 11 ++++++++ xpcom/glue/nsTHashtable.h | 50 ------------------------------------ 2 files changed, 11 insertions(+), 50 deletions(-) diff --git a/xpcom/glue/nsBaseHashtable.h b/xpcom/glue/nsBaseHashtable.h index 8d14b0057928..58c5acb6d3d3 100644 --- a/xpcom/glue/nsBaseHashtable.h +++ b/xpcom/glue/nsBaseHashtable.h @@ -13,6 +13,17 @@ #include "prlock.h" #include "nsDebug.h" +// These are the codes returned by |EnumReadFunction| and |EnumFunction|, which +// control the behavior of EnumerateRead() and Enumerate(). The PLD/PL_D prefix +// is because they originated in PLDHashTable, but that class no longer uses +// them. +enum PLDHashOperator +{ + PL_DHASH_NEXT = 0, // enumerator says continue + PL_DHASH_STOP = 1, // enumerator says stop + PL_DHASH_REMOVE = 2 // enumerator says remove +}; + template class nsBaseHashtable; // forward declaration diff --git a/xpcom/glue/nsTHashtable.h b/xpcom/glue/nsTHashtable.h index f79a2f379951..c2c5a4a6b723 100644 --- a/xpcom/glue/nsTHashtable.h +++ b/xpcom/glue/nsTHashtable.h @@ -72,16 +72,6 @@ * @author "Benjamin Smedberg " */ -// These are the codes returned by |Enumerator| functions, which control -// EnumerateEntry()'s behavior. The PLD/PL_D prefix is because they originated -// in PLDHashTable, but that class no longer uses them. -enum PLDHashOperator -{ - PL_DHASH_NEXT = 0, // enumerator says continue - PL_DHASH_STOP = 1, // enumerator says stop - PL_DHASH_REMOVE = 2 // enumerator says remove -}; - template class MOZ_NEEDS_NO_VTABLE_TYPE nsTHashtable { @@ -189,46 +179,6 @@ public: PL_DHashTableRawRemove(&mTable, aEntry); } - /** - * client must provide an Enumerator function for - * EnumerateEntries - * @param aEntry the entry being enumerated - * @param userArg passed unchanged from EnumerateEntries - * @return combination of flags - * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink , - * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink , - * @link PLDHashOperator::PL_DHASH_REMOVE PL_DHASH_REMOVE @endlink - */ - typedef PLDHashOperator (*Enumerator)(EntryType* aEntry, void* userArg); - - /** - * Enumerate all the entries of the function. If any entries are removed via - * a PL_DHASH_REMOVE return value from |aEnumFunc|, the table may be shrunk - * at the end. Use RawRemoveEntry() instead if you wish to remove an entry - * without possibly shrinking the table. - * WARNING: this function is deprecated. Please use Iterator instead. - * @param enumFunc the Enumerator function to call - * @param userArg a pointer to pass to the - * Enumerator function - * @return the number of entries actually enumerated - */ - uint32_t EnumerateEntries(Enumerator aEnumFunc, void* aUserArg) - { - uint32_t n = 0; - for (auto iter = mTable.Iter(); !iter.Done(); iter.Next()) { - auto entry = static_cast(iter.Get()); - PLDHashOperator op = aEnumFunc(entry, aUserArg); - n++; - if (op & PL_DHASH_REMOVE) { - iter.Remove(); - } - if (op & PL_DHASH_STOP) { - break; - } - } - return n; - } - // This is an iterator that also allows entry removal. Example usage: // // for (auto iter = table.Iter(); !iter.Done(); iter.Next()) { From fa7e35025b0f182b6c414cd8ddc96305120b1c27 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Tue, 11 Aug 2015 16:03:30 -0400 Subject: [PATCH 46/49] Bug 1188543 - Make sure finishTabSwitch is always called on layers ready. r=blassey --HG-- extra : commitid : LyakUEHyEQT --- browser/base/content/tabbrowser.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index f1ce7e45f359..3ecc40f37ab7 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -3371,6 +3371,8 @@ let tab = this.tabbrowser.getTabForBrowser(browser); this.setTabState(tab, this.STATE_LOADED); + this.finishTabSwitch(); + if (this.loadingTab === tab) { clearTimeout(this.loadTimer); this.loadTimer = null; From 3c08b48c3aec87da40241ef7a043e4adc24f4779 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Tue, 11 Aug 2015 23:50:28 -0700 Subject: [PATCH 47/49] Bug 1193125 - Avoid corrupting image data in test_fetch_event.html. r=bkelly --- .../test/serviceworkers/fetch_event_worker.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/dom/workers/test/serviceworkers/fetch_event_worker.js b/dom/workers/test/serviceworkers/fetch_event_worker.js index 4d219b9ac954..33c8f9ed6c33 100644 --- a/dom/workers/test/serviceworkers/fetch_event_worker.js +++ b/dom/workers/test/serviceworkers/fetch_event_worker.js @@ -97,12 +97,20 @@ onfetch = function(ev) { } else if (ev.request.url.includes("nonexistent_image.gif")) { + var imageAsBinaryString = atob("R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs"); + var imageLength = imageAsBinaryString.length; + + // If we just pass |imageAsBinaryString| to the Response constructor, an + // encoding conversion occurs that corrupts the image. Instead, we need to + // convert it to a typed array. + // typed array. + var imageAsArray = new Uint8Array(imageLength); + for (var i = 0; i < imageLength; ++i) { + imageAsArray[i] = imageAsBinaryString.charCodeAt(i); + } + ev.respondWith(Promise.resolve( - new Response(atob("R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs"), { - headers: { - "Content-Type": "image/gif" - } - }) + new Response(imageAsArray, { headers: { "Content-Type": "image/gif" } }) )); } From 65cf06375b361cb407da79f3a2e3612da4edebbe Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Tue, 11 Aug 2015 23:50:31 -0700 Subject: [PATCH 48/49] Bug 1192356 (Part 1) - Take advantage of mozilla::Tie() in SurfaceCache.cpp. r=dholbert --- image/SurfaceCache.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/image/SurfaceCache.cpp b/image/SurfaceCache.cpp index 32448d42c132..71baee875788 100644 --- a/image/SurfaceCache.cpp +++ b/image/SurfaceCache.cpp @@ -19,6 +19,7 @@ #include "mozilla/Pair.h" #include "mozilla/RefPtr.h" #include "mozilla/StaticPtr.h" +#include "mozilla/Tuple.h" #include "nsIMemoryReporter.h" #include "gfx2DGlue.h" #include "gfxPattern.h" // Workaround for flaw in bug 921753 part 2. @@ -661,11 +662,8 @@ public: DrawableFrameRef ref; MatchType matchType = MatchType::NOT_FOUND; while (true) { - // XXX(seth): This code is begging for std::tie. See bug 1184385. - Pair, MatchType> lookupResult = + Tie(surface, matchType) = cache->LookupBestMatch(aSurfaceKey, aAlternateFlags); - surface = lookupResult.first(); - matchType = lookupResult.second(); if (!surface) { return LookupResult(matchType); // Lookup in the per-image cache missed. From b388f51c026eb7663e47f4e72ac25b668ef3b7ad Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Tue, 11 Aug 2015 23:50:33 -0700 Subject: [PATCH 49/49] Bug 1192356 (Part 2) - Take advantage of mozilla::Tie() in RasterImage.cpp. r=tn --- image/RasterImage.cpp | 45 ++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index df9e64e7e229..da062530a912 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -41,6 +41,7 @@ #include #include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" +#include "mozilla/Tuple.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/gfx/Scale.h" @@ -744,17 +745,20 @@ RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags) MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aContainer); - auto result = GetFrameInternal(FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY); - if (!result.second()) { + DrawResult drawResult; + RefPtr surface; + Tie(drawResult, surface) = + GetFrameInternal(FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY); + if (!surface) { // The OS threw out some or all of our buffer. We'll need to wait for the // redecode (which was automatically triggered by GetFrame) to complete. - return MakePair(result.first(), nsRefPtr()); + return MakePair(drawResult, nsRefPtr()); } CairoImage::Data cairoData; GetWidth(&cairoData.mSize.width); GetHeight(&cairoData.mSize.height); - cairoData.mSourceSurface = result.second(); + cairoData.mSourceSurface = surface; nsRefPtr image = aContainer->CreateImage(ImageFormat::CAIRO_SURFACE); @@ -762,7 +766,7 @@ RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags) static_cast(image.get())->SetData(cairoData); - return MakePair(result.first(), Move(image)); + return MakePair(drawResult, Move(image)); } NS_IMETHODIMP_(bool) @@ -814,18 +818,19 @@ RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags) // We need a new ImageContainer, so create one. container = LayerManager::CreateImageContainer(); - auto result = GetCurrentImage(container, aFlags); - if (!result.second()) { - // We couldn't get an Image. + DrawResult drawResult; + nsRefPtr image; + Tie(drawResult, image) = GetCurrentImage(container, aFlags); + if (!image) { return nullptr; } - // |result.second()| holds a reference to a SourceSurface which in turn holds - // a lock on the current frame's VolatileBuffer, ensuring that it doesn't get - // freed as long as the layer system keeps this ImageContainer alive. - container->SetCurrentImageInTransaction(result.second()); + // |image| holds a reference to a SourceSurface which in turn holds a lock on + // the current frame's VolatileBuffer, ensuring that it doesn't get freed as + // long as the layer system keeps this ImageContainer alive. + container->SetCurrentImageInTransaction(image); - mLastImageContainerDrawResult = result.first(); + mLastImageContainerDrawResult = drawResult; mImageContainer = container; return container.forget(); @@ -841,16 +846,16 @@ RasterImage::UpdateImageContainer() return; } - auto result = GetCurrentImage(container, FLAG_NONE); - if (!result.second()) { - // We couldn't get an Image. + DrawResult drawResult; + nsRefPtr image; + Tie(drawResult, image) = GetCurrentImage(container, FLAG_NONE); + if (!image) { return; } - mLastImageContainerDrawResult = result.first(); - nsAutoTArray imageList; - imageList.AppendElement( - ImageContainer::NonOwningImage(result.second())); + mLastImageContainerDrawResult = drawResult; + nsAutoTArray imageList; + imageList.AppendElement(ImageContainer::NonOwningImage(image)); container->SetCurrentImages(imageList); }