mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
8c47612fee
@ -63,17 +63,16 @@ add_task(function* test() {
|
||||
});
|
||||
}
|
||||
|
||||
// make sure we have received a message
|
||||
yield ContentTask.spawn(receiver.browser, channelName,
|
||||
function* (name) {
|
||||
yield content.window.testPromise.then(function() {});
|
||||
}
|
||||
);
|
||||
|
||||
// Since sender1 sends before sender2, if the title is exactly
|
||||
// sender2's message, sender1's message must've been blocked
|
||||
is(receiver.browser.contentDocument.title, sender2.message,
|
||||
"should only receive messages from the same user context");
|
||||
yield ContentTask.spawn(receiver.browser, sender2.message,
|
||||
function* (message) {
|
||||
yield content.window.testPromise.then(function() {
|
||||
is(content.document.title, message,
|
||||
"should only receive messages from the same user context");
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
gBrowser.removeTab(sender1.tab);
|
||||
gBrowser.removeTab(sender2.tab);
|
||||
|
@ -35,7 +35,6 @@ support-files =
|
||||
[browser_ext_contextMenus_urlPatterns.js]
|
||||
[browser_ext_currentWindow.js]
|
||||
[browser_ext_getViews.js]
|
||||
[browser_ext_history.js]
|
||||
[browser_ext_incognito_popup.js]
|
||||
[browser_ext_lastError.js]
|
||||
[browser_ext_optionsPage_privileges.js]
|
||||
|
@ -1,3 +1,7 @@
|
||||
{
|
||||
"extends": "../../../../../testing/xpcshell/xpcshell.eslintrc",
|
||||
|
||||
"globals": {
|
||||
"browser": false,
|
||||
},
|
||||
}
|
||||
|
@ -2,12 +2,24 @@
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
/* exported createHttpServer */
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Extension",
|
||||
"resource://gre/modules/Extension.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData",
|
||||
"resource://gre/modules/Extension.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
|
||||
"resource://gre/modules/ExtensionManagement.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionTestUtils",
|
||||
"resource://testing-common/ExtensionXPCShellUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
|
||||
"resource://testing-common/httpd.js");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
|
||||
@ -15,36 +27,29 @@ XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
/* exported normalizeManifest */
|
||||
ExtensionTestUtils.init(this);
|
||||
|
||||
let BASE_MANIFEST = {
|
||||
"applications": {"gecko": {"id": "test@web.ext"}},
|
||||
|
||||
"manifest_version": 2,
|
||||
/**
|
||||
* Creates a new HttpServer for testing, and begins listening on the
|
||||
* specified port. Automatically shuts down the server when the test
|
||||
* unit ends.
|
||||
*
|
||||
* @param {integer} [port]
|
||||
* The port to listen on. If omitted, listen on a random
|
||||
* port. The latter is the preferred behavior.
|
||||
*
|
||||
* @returns {HttpServer}
|
||||
*/
|
||||
function createHttpServer(port = -1) {
|
||||
let server = new HttpServer();
|
||||
server.start(port);
|
||||
|
||||
"name": "name",
|
||||
"version": "0",
|
||||
};
|
||||
do_register_cleanup(() => {
|
||||
return new Promise(resolve => {
|
||||
server.stop(resolve);
|
||||
});
|
||||
});
|
||||
|
||||
function* normalizeManifest(manifest, baseManifest = BASE_MANIFEST) {
|
||||
const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
|
||||
yield Management.lazyInit();
|
||||
|
||||
let errors = [];
|
||||
let context = {
|
||||
url: null,
|
||||
|
||||
logError: error => {
|
||||
errors.push(error);
|
||||
},
|
||||
|
||||
preprocessors: {},
|
||||
};
|
||||
|
||||
manifest = Object.assign({}, baseManifest, manifest);
|
||||
|
||||
let normalized = Schemas.normalize(manifest, "manifest.WebExtensionManifest", context);
|
||||
normalized.errors = errors;
|
||||
|
||||
return normalized;
|
||||
return server;
|
||||
}
|
||||
|
@ -1,16 +1,5 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
function backgroundScript() {
|
||||
@ -276,13 +265,13 @@ function backgroundScript() {
|
||||
return browser.bookmarks.search("Menu Item");
|
||||
}).then(results => {
|
||||
browser.test.assertEq(1, results.length, "Expected number of results returned for menu item search");
|
||||
checkBookmark({title: "Menu Item", url: "http://menu.org/", index: 3, parentId: bookmarkGuids.menuGuid}, results[0]);
|
||||
checkBookmark({title: "Menu Item", url: "http://menu.org/", index: 0, parentId: bookmarkGuids.menuGuid}, results[0]);
|
||||
|
||||
// finds toolbar items
|
||||
return browser.bookmarks.search("Toolbar Item");
|
||||
}).then(results => {
|
||||
browser.test.assertEq(1, results.length, "Expected number of results returned for toolbar item search");
|
||||
checkBookmark({title: "Toolbar Item", url: "http://toolbar.org/", index: 2, parentId: bookmarkGuids.toolbarGuid}, results[0]);
|
||||
checkBookmark({title: "Toolbar Item", url: "http://toolbar.org/", index: 0, parentId: bookmarkGuids.toolbarGuid}, results[0]);
|
||||
|
||||
// finds folders
|
||||
return browser.bookmarks.search("Mozilla Folder");
|
||||
@ -389,7 +378,7 @@ function backgroundScript() {
|
||||
return browser.bookmarks.move(corporationBookmark.id, {parentId: bookmarkGuids.menuGuid});
|
||||
}).then(result => {
|
||||
browser.test.assertEq(bookmarkGuids.menuGuid, result.parentId, "Bookmark has the expected parent");
|
||||
browser.test.assertEq(childCount + 1, result.index, "Bookmark has the expected index");
|
||||
browser.test.assertEq(childCount, result.index, "Bookmark has the expected index");
|
||||
|
||||
return browser.bookmarks.move(corporationBookmark.id, {index: 1});
|
||||
}).then(result => {
|
||||
@ -490,8 +479,3 @@ add_task(function* test_contentscript() {
|
||||
yield extension.awaitFinish("bookmarks");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -85,14 +85,14 @@ add_task(function* test_delete() {
|
||||
}
|
||||
|
||||
yield PlacesUtils.history.insertMany(visits);
|
||||
is(yield PlacesTestUtils.visitsInDB(visits[0].url), 5, "5 visits for uri found in history database");
|
||||
equal((yield PlacesTestUtils.visitsInDB(visits[0].url)), 5, "5 visits for uri found in history database");
|
||||
|
||||
let testUrl = visits[2].url;
|
||||
ok(yield PlacesTestUtils.isPageInDB(testUrl), "expected url found in history database");
|
||||
ok((yield PlacesTestUtils.isPageInDB(testUrl)), "expected url found in history database");
|
||||
|
||||
extension.sendMessage("delete-url", testUrl);
|
||||
yield extension.awaitMessage("url-deleted");
|
||||
is(yield PlacesTestUtils.isPageInDB(testUrl), false, "expected url not found in history database");
|
||||
equal((yield PlacesTestUtils.isPageInDB(testUrl)), false, "expected url not found in history database");
|
||||
|
||||
// delete 3 of the 5 visits for url 1
|
||||
let filter = {
|
||||
@ -103,10 +103,10 @@ add_task(function* test_delete() {
|
||||
extension.sendMessage("delete-range", filter);
|
||||
let removedUrls = yield extension.awaitMessage("range-deleted");
|
||||
ok(!removedUrls.includes(visits[0].url), `${visits[0].url} not received by onVisitRemoved`);
|
||||
ok(yield PlacesTestUtils.isPageInDB(visits[0].url), "expected uri found in history database");
|
||||
is(yield PlacesTestUtils.visitsInDB(visits[0].url), 2, "2 visits for uri found in history database");
|
||||
ok(yield PlacesTestUtils.isPageInDB(visits[1].url), "expected uri found in history database");
|
||||
is(yield PlacesTestUtils.visitsInDB(visits[1].url), 1, "1 visit for uri found in history database");
|
||||
ok((yield PlacesTestUtils.isPageInDB(visits[0].url)), "expected uri found in history database");
|
||||
equal((yield PlacesTestUtils.visitsInDB(visits[0].url)), 2, "2 visits for uri found in history database");
|
||||
ok((yield PlacesTestUtils.isPageInDB(visits[1].url)), "expected uri found in history database");
|
||||
equal((yield PlacesTestUtils.visitsInDB(visits[1].url)), 1, "1 visit for uri found in history database");
|
||||
|
||||
// delete the rest of the visits for url 1, and the visit for url 2
|
||||
filter.startTime = visits[0].visits[0].date;
|
||||
@ -115,18 +115,18 @@ add_task(function* test_delete() {
|
||||
extension.sendMessage("delete-range", filter);
|
||||
yield extension.awaitMessage("range-deleted");
|
||||
|
||||
is(yield PlacesTestUtils.isPageInDB(visits[0].url), false, "expected uri not found in history database");
|
||||
is(yield PlacesTestUtils.visitsInDB(visits[0].url), 0, "0 visits for uri found in history database");
|
||||
is(yield PlacesTestUtils.isPageInDB(visits[1].url), false, "expected uri not found in history database");
|
||||
is(yield PlacesTestUtils.visitsInDB(visits[1].url), 0, "0 visits for uri found in history database");
|
||||
equal((yield PlacesTestUtils.isPageInDB(visits[0].url)), false, "expected uri not found in history database");
|
||||
equal((yield PlacesTestUtils.visitsInDB(visits[0].url)), 0, "0 visits for uri found in history database");
|
||||
equal((yield PlacesTestUtils.isPageInDB(visits[1].url)), false, "expected uri not found in history database");
|
||||
equal((yield PlacesTestUtils.visitsInDB(visits[1].url)), 0, "0 visits for uri found in history database");
|
||||
|
||||
ok(yield PlacesTestUtils.isPageInDB(visits[3].url), "expected uri found in history database");
|
||||
ok((yield PlacesTestUtils.isPageInDB(visits[3].url)), "expected uri found in history database");
|
||||
|
||||
extension.sendMessage("delete-all");
|
||||
[historyClearedCount, removedUrls] = yield extension.awaitMessage("history-cleared");
|
||||
is(PlacesUtils.history.hasHistoryEntries, false, "history is empty");
|
||||
is(historyClearedCount, 2, "onVisitRemoved called for each clearing of history");
|
||||
is(removedUrls.length, 3, "onVisitRemoved called the expected number of times");
|
||||
equal(PlacesUtils.history.hasHistoryEntries, false, "history is empty");
|
||||
equal(historyClearedCount, 2, "onVisitRemoved called for each clearing of history");
|
||||
equal(removedUrls.length, 3, "onVisitRemoved called the expected number of times");
|
||||
for (let i = 1; i < 3; ++i) {
|
||||
let url = visits[i].url;
|
||||
ok(removedUrls.includes(url), `${url} received by onVisitRemoved`);
|
||||
@ -215,9 +215,9 @@ add_task(function* test_search() {
|
||||
|
||||
function checkResult(results, url, expectedCount) {
|
||||
let result = findResult(url, results);
|
||||
isnot(result, null, `history.search result was found for ${url}`);
|
||||
is(result.visitCount, expectedCount, `history.search reports ${expectedCount} visit(s)`);
|
||||
is(result.title, `test visit for ${url}`, "title for search result is correct");
|
||||
notEqual(result, null, `history.search result was found for ${url}`);
|
||||
equal(result.visitCount, expectedCount, `history.search reports ${expectedCount} visit(s)`);
|
||||
equal(result.title, `test visit for ${url}`, "title for search result is correct");
|
||||
}
|
||||
|
||||
yield extension.startup();
|
||||
@ -229,21 +229,21 @@ add_task(function* test_search() {
|
||||
extension.sendMessage("check-history");
|
||||
|
||||
let results = yield extension.awaitMessage("empty-search");
|
||||
is(results.length, 3, "history.search with empty text returned 3 results");
|
||||
equal(results.length, 3, "history.search with empty text returned 3 results");
|
||||
checkResult(results, SINGLE_VISIT_URL, 1);
|
||||
checkResult(results, DOUBLE_VISIT_URL, 2);
|
||||
checkResult(results, MOZILLA_VISIT_URL, 1);
|
||||
|
||||
results = yield extension.awaitMessage("text-search");
|
||||
is(results.length, 1, "history.search with specific text returned 1 result");
|
||||
equal(results.length, 1, "history.search with specific text returned 1 result");
|
||||
checkResult(results, MOZILLA_VISIT_URL, 1);
|
||||
|
||||
results = yield extension.awaitMessage("max-results-search");
|
||||
is(results.length, 1, "history.search with maxResults returned 1 result");
|
||||
equal(results.length, 1, "history.search with maxResults returned 1 result");
|
||||
checkResult(results, DOUBLE_VISIT_URL, 2);
|
||||
|
||||
results = yield extension.awaitMessage("date-range-search");
|
||||
is(results.length, 2, "history.search with a date range returned 2 result");
|
||||
equal(results.length, 2, "history.search with a date range returned 2 result");
|
||||
checkResult(results, DOUBLE_VISIT_URL, 2);
|
||||
checkResult(results, SINGLE_VISIT_URL, 1);
|
||||
|
||||
@ -300,11 +300,11 @@ add_task(function* test_add_url() {
|
||||
];
|
||||
|
||||
function* checkUrl(results) {
|
||||
ok(yield PlacesTestUtils.isPageInDB(results.details.url), `${results.details.url} found in history database`);
|
||||
ok((yield PlacesTestUtils.isPageInDB(results.details.url)), `${results.details.url} found in history database`);
|
||||
ok(PlacesUtils.isValidGuid(results.result.id), "URL was added with a valid id");
|
||||
is(results.result.title, results.details.title, "URL was added with the correct title");
|
||||
equal(results.result.title, results.details.title, "URL was added with the correct title");
|
||||
if (results.details.visitTime) {
|
||||
is(results.result.lastVisitTime,
|
||||
equal(results.result.lastVisitTime,
|
||||
Number(ExtensionUtils.normalizeTime(results.details.visitTime)),
|
||||
"URL was added with the correct date");
|
||||
}
|
||||
@ -458,12 +458,12 @@ add_task(function* test_on_visited() {
|
||||
function checkOnVisitedData(index, expected) {
|
||||
let onVisited = onVisitedData[index];
|
||||
ok(PlacesUtils.isValidGuid(onVisited.id), "onVisited received a valid id");
|
||||
is(onVisited.url, expected.url, "onVisited received the expected url");
|
||||
equal(onVisited.url, expected.url, "onVisited received the expected url");
|
||||
// Title will be blank until bug 1287928 lands
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1287928
|
||||
is(onVisited.title, "", "onVisited received a blank title");
|
||||
is(onVisited.lastVisitTime, expected.time, "onVisited received the expected time");
|
||||
is(onVisited.visitCount, expected.visitCount, "onVisited received the expected visitCount");
|
||||
equal(onVisited.title, "", "onVisited received a blank title");
|
||||
equal(onVisited.lastVisitTime, expected.time, "onVisited received the expected time");
|
||||
equal(onVisited.visitCount, expected.visitCount, "onVisited received the expected visitCount");
|
||||
}
|
||||
|
||||
let expected = {
|
@ -4,7 +4,7 @@
|
||||
|
||||
|
||||
add_task(function* test_manifest_commands() {
|
||||
let normalized = yield normalizeManifest({
|
||||
let normalized = yield ExtensionTestUtils.normalizeManifest({
|
||||
"commands": {
|
||||
"toggle-feature": {
|
||||
"suggested_key": {"default": "Shifty+Y"},
|
||||
|
@ -3,4 +3,6 @@ head = head.js
|
||||
tail =
|
||||
firefox-appdir = browser
|
||||
|
||||
[test_ext_bookmarks.js]
|
||||
[test_ext_history.js]
|
||||
[test_ext_manifest_commands.js]
|
||||
|
@ -108,37 +108,9 @@ this.ContentLinkHandler = {
|
||||
}
|
||||
sizeHistogramTypes.add(sizesType);
|
||||
|
||||
if (uri.scheme == 'blob') {
|
||||
// Blob URLs don't work cross process, work around this by sending as a data uri
|
||||
let channel = NetUtil.newChannel({
|
||||
uri: uri,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE,
|
||||
loadUsingSystemPrincipal: true
|
||||
});
|
||||
let listener = {
|
||||
encoded: "",
|
||||
bis: null,
|
||||
onStartRequest: function(aRequest, aContext) {
|
||||
this.bis = Components.classes["@mozilla.org/binaryinputstream;1"]
|
||||
.createInstance(Components.interfaces.nsIBinaryInputStream);
|
||||
},
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
let spec = "data:" + channel.contentType + ";base64," + this.encoded;
|
||||
chromeGlobal.sendAsyncMessage(
|
||||
"Link:SetIcon",
|
||||
{url: spec, loadingPrincipal: link.ownerDocument.nodePrincipal});
|
||||
},
|
||||
onDataAvailable: function(request, context, inputStream, offset, count) {
|
||||
this.bis.setInputStream(inputStream);
|
||||
this.encoded += btoa(this.bis.readBytes(this.bis.available()));
|
||||
}
|
||||
}
|
||||
channel.asyncOpen2(listener);
|
||||
} else {
|
||||
chromeGlobal.sendAsyncMessage(
|
||||
"Link:SetIcon",
|
||||
{url: uri.spec, loadingPrincipal: link.ownerDocument.nodePrincipal});
|
||||
}
|
||||
chromeGlobal.sendAsyncMessage(
|
||||
"Link:SetIcon",
|
||||
{url: uri.spec, loadingPrincipal: link.ownerDocument.nodePrincipal});
|
||||
iconAdded = true;
|
||||
break;
|
||||
case "search":
|
||||
|
@ -2425,7 +2425,8 @@ nsDocument::FillStyleSet(StyleSetHandle aStyleSet)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NS_ERROR("stylo: nsStyleSheetService doesn't handle ServoStyleSheets yet");
|
||||
NS_WARNING("stylo: Not yet checking nsStyleSheetService for Servo-backed "
|
||||
"documents. See bug 1290224");
|
||||
}
|
||||
|
||||
AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet],
|
||||
@ -13350,7 +13351,8 @@ nsIDocument::FlushUserFontSet()
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
NS_ERROR("stylo: ServoStyleSets cannot handle @font-face rules yet");
|
||||
NS_WARNING("stylo: ServoStyleSets cannot handle @font-face rules yet. "
|
||||
"See bug 1290237.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -13439,6 +13441,10 @@ nsIDocument::UpdateStyleBackendType()
|
||||
{
|
||||
MOZ_ASSERT(mStyleBackendType == StyleBackendType(0),
|
||||
"no need to call UpdateStyleBackendType now");
|
||||
|
||||
// Assume Gecko by default.
|
||||
mStyleBackendType = StyleBackendType::Gecko;
|
||||
|
||||
#ifdef MOZ_STYLO
|
||||
// XXX For now we use a Servo-backed style set only for (X)HTML documents
|
||||
// in content docshells. This should let us avoid implementing XUL-specific
|
||||
@ -13447,15 +13453,11 @@ nsIDocument::UpdateStyleBackendType()
|
||||
// document before we have a pres shell (i.e. before we make the decision
|
||||
// here about whether to use a Gecko- or Servo-backed style system), so
|
||||
// we avoid Servo-backed style sets for SVG documents.
|
||||
NS_ASSERTION(mDocumentContainer, "stylo: calling UpdateStyleBackendType "
|
||||
"before we have a docshell");
|
||||
mStyleBackendType =
|
||||
nsLayoutUtils::SupportsServoStyleBackend(this) &&
|
||||
mDocumentContainer ?
|
||||
StyleBackendType::Servo :
|
||||
StyleBackendType::Gecko;
|
||||
#else
|
||||
mStyleBackendType = StyleBackendType::Gecko;
|
||||
if (!mDocumentContainer) {
|
||||
NS_WARNING("stylo: No docshell yet, assuming Gecko style system");
|
||||
} else if (nsLayoutUtils::SupportsServoStyleBackend(this)) {
|
||||
mStyleBackendType = StyleBackendType::Servo;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,8 @@ NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeTypeArray,
|
||||
mWindow,
|
||||
mMimeTypes)
|
||||
mMimeTypes,
|
||||
mCTPMimeTypes)
|
||||
|
||||
nsMimeTypeArray::nsMimeTypeArray(nsPIDOMWindowInner* aWindow)
|
||||
: mWindow(aWindow)
|
||||
@ -57,6 +58,7 @@ void
|
||||
nsMimeTypeArray::Refresh()
|
||||
{
|
||||
mMimeTypes.Clear();
|
||||
mCTPMimeTypes.Clear();
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner*
|
||||
@ -133,6 +135,10 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
aFound = true;
|
||||
return mimeType;
|
||||
}
|
||||
nsMimeType* hiddenType = FindMimeType(mCTPMimeTypes, lowerName);
|
||||
if (hiddenType) {
|
||||
nsPluginArray::NotifyHiddenPluginTouched(hiddenType->GetEnabledPlugin());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@ -180,6 +186,7 @@ nsMimeTypeArray::EnsurePluginMimeTypes()
|
||||
}
|
||||
|
||||
pluginArray->GetMimeTypes(mMimeTypes);
|
||||
pluginArray->GetCTPMimeTypes(mCTPMimeTypes);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsMimeType, AddRef)
|
||||
|
@ -48,6 +48,7 @@ protected:
|
||||
// mMimeTypes contains MIME types handled by plugins or by an OS
|
||||
// PreferredApplicationHandler.
|
||||
nsTArray<RefPtr<nsMimeType> > mMimeTypes;
|
||||
nsTArray<RefPtr<nsMimeType> > mCTPMimeTypes;
|
||||
};
|
||||
|
||||
class nsMimeType final : public nsWrapperCache
|
||||
|
@ -114,6 +114,24 @@ nsPluginArray::GetMimeTypes(nsTArray<RefPtr<nsMimeType>>& aMimeTypes)
|
||||
aMimeTypes.Sort();
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginArray::GetCTPMimeTypes(nsTArray<RefPtr<nsMimeType>>& aMimeTypes)
|
||||
{
|
||||
aMimeTypes.Clear();
|
||||
|
||||
if (!AllowPlugins()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnsurePlugins();
|
||||
|
||||
GetPluginMimeTypes(mCTPPlugins, aMimeTypes);
|
||||
|
||||
// Alphabetize the enumeration order of non-hidden MIME types to reduce
|
||||
// fingerprintable entropy based on plugins' installation file times.
|
||||
aMimeTypes.Sort();
|
||||
}
|
||||
|
||||
nsPluginElement*
|
||||
nsPluginArray::Item(uint32_t aIndex)
|
||||
{
|
||||
@ -236,21 +254,26 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
if (!aFound) {
|
||||
nsPluginElement* hiddenPlugin = FindPlugin(mCTPPlugins, aName);
|
||||
if (hiddenPlugin) {
|
||||
HiddenPluginEventInit init;
|
||||
init.mTag = hiddenPlugin->PluginTag();
|
||||
nsCOMPtr<nsIDocument> doc = hiddenPlugin->GetParentObject()->GetDoc();
|
||||
RefPtr<HiddenPluginEvent> event =
|
||||
HiddenPluginEvent::Constructor(doc, NS_LITERAL_STRING("HiddenPlugin"), init);
|
||||
event->SetTarget(doc);
|
||||
event->SetTrusted(true);
|
||||
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
|
||||
bool dummy;
|
||||
doc->DispatchEvent(event, &dummy);
|
||||
NotifyHiddenPluginTouched(hiddenPlugin);
|
||||
}
|
||||
}
|
||||
return plugin;
|
||||
}
|
||||
|
||||
void nsPluginArray::NotifyHiddenPluginTouched(nsPluginElement* aHiddenElement)
|
||||
{
|
||||
HiddenPluginEventInit init;
|
||||
init.mTag = aHiddenElement->PluginTag();
|
||||
nsCOMPtr<nsIDocument> doc = aHiddenElement->GetParentObject()->GetDoc();
|
||||
RefPtr<HiddenPluginEvent> event =
|
||||
HiddenPluginEvent::Constructor(doc, NS_LITERAL_STRING("HiddenPlugin"), init);
|
||||
event->SetTarget(doc);
|
||||
event->SetTrusted(true);
|
||||
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
|
||||
bool dummy;
|
||||
doc->DispatchEvent(event, &dummy);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsPluginArray::Length()
|
||||
{
|
||||
|
@ -41,6 +41,9 @@ public:
|
||||
void Invalidate();
|
||||
|
||||
void GetMimeTypes(nsTArray<RefPtr<nsMimeType>>& aMimeTypes);
|
||||
void GetCTPMimeTypes(nsTArray<RefPtr<nsMimeType>>& aMimeTypes);
|
||||
|
||||
static void NotifyHiddenPluginTouched(nsPluginElement* aElement);
|
||||
|
||||
// PluginArray WebIDL methods
|
||||
|
||||
|
@ -346,16 +346,10 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribs[index].stride);
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE:
|
||||
if (!mBoundVertexArray->mAttribs[index].enabled)
|
||||
return JS::Int32Value(4);
|
||||
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribs[index].size);
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE:
|
||||
if (!mBoundVertexArray->mAttribs[index].enabled)
|
||||
return JS::NumberValue(uint32_t(LOCAL_GL_FLOAT));
|
||||
|
||||
return JS::NumberValue(uint32_t(mBoundVertexArray->mAttribs[index].type));
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribs[index].type);
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER:
|
||||
if (IsWebGL2())
|
||||
|
@ -262,6 +262,9 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
||||
bytes = view.DataAllowShared();
|
||||
byteCount = view.LengthAllowShared();
|
||||
}
|
||||
} else if (isSubImage) {
|
||||
mContext->ErrorInvalidValue("%s: `pixels` must not be null.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool isClientData = true;
|
||||
|
9
dom/canvas/crashtests/1284356-1.html
Normal file
9
dom/canvas/crashtests/1284356-1.html
Normal file
@ -0,0 +1,9 @@
|
||||
<canvas id='i0'></canvas>
|
||||
<script>
|
||||
var c=document.getElementById('i0').getContext('2d');
|
||||
c.lineWidth=194.622602174;
|
||||
c.miterLimit=270.273509738;
|
||||
c.transform(0,0,0,0,0,0);
|
||||
c.globalCompositeOperation='soft-light';
|
||||
c.strokeText('a',200,273,722);
|
||||
</script>
|
8
dom/canvas/crashtests/1284578-1.html
Normal file
8
dom/canvas/crashtests/1284578-1.html
Normal file
@ -0,0 +1,8 @@
|
||||
<canvas id='i0'></canvas>
|
||||
<script>
|
||||
var c=document.getElementById('i0').getContext('2d');
|
||||
c.bezierCurveTo(157,351,351,44,946,701);
|
||||
c.quadraticCurveTo(260,-9007199254740991,945,145);
|
||||
c.translate(-9007199254740991,239);
|
||||
c.isPointInPath(988,439);
|
||||
</script>
|
8
dom/canvas/crashtests/1287652-1.html
Normal file
8
dom/canvas/crashtests/1287652-1.html
Normal file
@ -0,0 +1,8 @@
|
||||
<canvas id='i0'></canvas>
|
||||
<script>
|
||||
var c=document.getElementById('i0').getContext('2d');
|
||||
var g=c.createLinearGradient(59,9,38.89,-75.51);
|
||||
c.fillStyle=g;
|
||||
c.globalAlpha=0.62;
|
||||
c.fillText('a',0,24,30);
|
||||
</script>
|
@ -29,6 +29,9 @@ skip-if(azureCairo) load 1229983-1.html
|
||||
load 1229932-1.html
|
||||
load 1244850-1.html
|
||||
load 1246775-1.html
|
||||
load 1284356-1.html
|
||||
load 1284578-1.html
|
||||
skip-if(d2d) load 1287515-1.html
|
||||
load 1287652-1.html
|
||||
load 1288872-1.html
|
||||
|
||||
|
@ -5838,7 +5838,6 @@ skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.
|
||||
[generated/test_2_conformance__textures__misc__tex-image-with-invalid-data.html]
|
||||
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
|
||||
[generated/test_2_conformance__textures__misc__tex-sub-image-2d-bad-args.html]
|
||||
fail-if = (os == 'mac') || (os == 'win')
|
||||
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
|
||||
[generated/test_2_conformance__textures__misc__tex-sub-image-2d.html]
|
||||
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
|
||||
@ -6722,7 +6721,6 @@ skip-if = (os == 'android')
|
||||
skip-if = (os == 'android')
|
||||
[generated/test_conformance__textures__misc__tex-input-validation.html]
|
||||
[generated/test_conformance__textures__misc__tex-sub-image-2d-bad-args.html]
|
||||
fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
|
||||
[generated/test_conformance__textures__misc__tex-sub-image-2d.html]
|
||||
[generated/test_conformance__textures__misc__texparameter-test.html]
|
||||
[generated/test_conformance__textures__misc__texture-active-bind-2.html]
|
||||
|
@ -148,8 +148,6 @@ fail-if = (os == 'mac')
|
||||
fail-if = (os == 'mac') || (os == 'win')
|
||||
[generated/test_2_conformance2__glsl3__forbidden-operators.html]
|
||||
fail-if = (os == 'mac') || (os == 'win')
|
||||
[generated/test_conformance__textures__misc__tex-sub-image-2d-bad-args.html]
|
||||
fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
|
||||
[generated/test_2_conformance2__vertex_arrays__vertex-array-object.html]
|
||||
fail-if = (os == 'mac') || (os == 'win')
|
||||
[generated/test_2_conformance__rendering__negative-one-index.html]
|
||||
@ -160,8 +158,6 @@ fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
|
||||
fail-if = (os == 'mac') || (os == 'win')
|
||||
[generated/test_conformance__attribs__gl-vertexattribpointer.html]
|
||||
fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
|
||||
[generated/test_2_conformance__textures__misc__tex-sub-image-2d-bad-args.html]
|
||||
fail-if = (os == 'mac') || (os == 'win')
|
||||
[generated/test_conformance__ogles__GL__biuDepthRange__biuDepthRange_001_to_002.html]
|
||||
fail-if = (os == 'android') || (os == 'linux')
|
||||
[generated/test_conformance__ogles__GL__gl_FragCoord__gl_FragCoord_001_to_003.html]
|
||||
|
@ -2365,22 +2365,6 @@ HTMLInputElement::GetValueIfStepped(int32_t aStep,
|
||||
value += step * Decimal(aStep);
|
||||
}
|
||||
|
||||
// For date inputs, the value can hold a string that is not a day. We do not
|
||||
// want to round it, as it might result in a step mismatch. Instead we want to
|
||||
// clamp to the next valid value.
|
||||
if (mType == NS_FORM_INPUT_DATE &&
|
||||
NS_floorModulo(Decimal(value - GetStepBase()), GetStepScaleFactor()) != Decimal(0)) {
|
||||
MOZ_ASSERT(GetStep() > Decimal(0));
|
||||
Decimal validStep = EuclidLCM<Decimal>(GetStep().floor(),
|
||||
GetStepScaleFactor().floor());
|
||||
if (aStep > 0) {
|
||||
value -= NS_floorModulo(value - GetStepBase(), validStep);
|
||||
value += validStep;
|
||||
} else if (aStep < 0) {
|
||||
value -= NS_floorModulo(value - GetStepBase(), validStep);
|
||||
}
|
||||
}
|
||||
|
||||
if (value < minimum) {
|
||||
value = minimum;
|
||||
deltaFromStep = NS_floorModulo(value - stepBase, step);
|
||||
@ -6903,6 +6887,11 @@ HTMLInputElement::GetStep() const
|
||||
step = GetDefaultStep();
|
||||
}
|
||||
|
||||
// For input type=date, we round the step value to have a rounded day.
|
||||
if (mType == NS_FORM_INPUT_DATE) {
|
||||
step = std::max(step.round(), Decimal(1));
|
||||
}
|
||||
|
||||
return step * GetStepScaleFactor();
|
||||
}
|
||||
|
||||
@ -7506,16 +7495,6 @@ HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
|
||||
Decimal step = GetStep();
|
||||
MOZ_ASSERT(step != kStepAny && step > Decimal(0));
|
||||
|
||||
// In case this is a date and the step is not an integer, we don't want to
|
||||
// display the dates corresponding to the truncated timestamps of valueLow
|
||||
// and valueHigh because they might suffer from a step mismatch as well.
|
||||
// Instead we want the timestamps to correspond to a rounded day. That is,
|
||||
// we want a multiple of the step scale factor (1 day) as well as of step.
|
||||
if (mType == NS_FORM_INPUT_DATE) {
|
||||
step = EuclidLCM<Decimal>(step.floor(),
|
||||
GetStepScaleFactor().floor());
|
||||
}
|
||||
|
||||
Decimal stepBase = GetStepBase();
|
||||
|
||||
Decimal valueLow = value - NS_floorModulo(value - stepBase, step);
|
||||
|
@ -76,6 +76,7 @@ static constexpr const nsAttrValue::EnumTable* kKindTableInvalidValueDefault = &
|
||||
/** HTMLTrackElement */
|
||||
HTMLTrackElement::HTMLTrackElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
, mLoadResourceDispatched(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -182,9 +183,46 @@ HTMLTrackElement::ParseAttribute(int32_t aNamespaceID,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLTrackElement::SetSrc(const nsAString& aSrc, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aError);
|
||||
uint16_t oldReadyState = ReadyState();
|
||||
SetReadyState(TextTrackReadyState::NotLoaded);
|
||||
if (!mMediaParent) {
|
||||
return;
|
||||
}
|
||||
if (mTrack && (oldReadyState != TextTrackReadyState::NotLoaded)) {
|
||||
// Remove all the cues in MediaElement.
|
||||
mMediaParent->RemoveTextTrack(mTrack);
|
||||
// Recreate mTrack.
|
||||
CreateTextTrack();
|
||||
}
|
||||
// Stop WebVTTListener.
|
||||
mListener = nullptr;
|
||||
if (mChannel) {
|
||||
mChannel->Cancel(NS_BINDING_ABORTED);
|
||||
mChannel = nullptr;
|
||||
}
|
||||
|
||||
DispatchLoadResource();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLTrackElement::DispatchLoadResource()
|
||||
{
|
||||
if (!mLoadResourceDispatched) {
|
||||
RefPtr<Runnable> r = NewRunnableMethod(this, &HTMLTrackElement::LoadResource);
|
||||
nsContentUtils::RunInStableState(r.forget());
|
||||
mLoadResourceDispatched = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLTrackElement::LoadResource()
|
||||
{
|
||||
mLoadResourceDispatched = false;
|
||||
|
||||
// Find our 'src' url
|
||||
nsAutoString src;
|
||||
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
|
||||
@ -258,8 +296,7 @@ HTMLTrackElement::BindToTree(nsIDocument* aDocument,
|
||||
if (!mTrack) {
|
||||
CreateTextTrack();
|
||||
}
|
||||
RefPtr<Runnable> r = NewRunnableMethod(this, &HTMLTrackElement::LoadResource);
|
||||
nsContentUtils::RunInStableState(r.forget());
|
||||
DispatchLoadResource();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -46,10 +46,8 @@ public:
|
||||
{
|
||||
GetHTMLURIAttr(nsGkAtoms::src, aSrc);
|
||||
}
|
||||
void SetSrc(const nsAString& aSrc, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aError);
|
||||
}
|
||||
|
||||
void SetSrc(const nsAString& aSrc, ErrorResult& aError);
|
||||
|
||||
void GetSrclang(DOMString& aSrclang) const
|
||||
{
|
||||
@ -134,6 +132,10 @@ protected:
|
||||
RefPtr<WebVTTListener> mListener;
|
||||
|
||||
void CreateTextTrack();
|
||||
|
||||
private:
|
||||
void DispatchLoadResource();
|
||||
bool mLoadResourceDispatched;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -185,7 +185,7 @@ for (var test of data) {
|
||||
input.min = '2009-02-01';
|
||||
input.step = '1.1';
|
||||
input.value = '2009-02-02';
|
||||
checkValidity(input, false, apply, { low: "2009-02-01", high: "2009-02-12" });
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
// Without any step attribute the date is valid
|
||||
input.removeAttribute('step');
|
||||
@ -203,21 +203,21 @@ for (var test of data) {
|
||||
|
||||
input.step = '0.9';
|
||||
input.value = '1951-01-02';
|
||||
checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-10" });
|
||||
|
||||
input.value = '1951-01-10'
|
||||
is(input.step, '0.9', "check that step value is unchanged");
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '0.5';
|
||||
input.step = '0.4';
|
||||
input.value = '1951-01-02';
|
||||
is(input.step, '0.4', "check that step value is unchanged");
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '1.5';
|
||||
input.value = '1951-01-03';
|
||||
checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-04" });
|
||||
input.value = '1951-01-02';
|
||||
is(input.step, '1.5', "check that step value is unchanged");
|
||||
checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-03" });
|
||||
|
||||
input.value = '1951-01-08';
|
||||
checkValidity(input, false, apply, { low: "1951-01-07", high: "1951-01-10" });
|
||||
checkValidity(input, false, apply, { low: "1951-01-07", high: "1951-01-09" });
|
||||
|
||||
input.step = '3000';
|
||||
input.min= '1968-01-01';
|
||||
@ -236,26 +236,26 @@ for (var test of data) {
|
||||
input.value = '1992-08-22';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '1.1';
|
||||
input.step = '2.1';
|
||||
input.min = '1991-01-01';
|
||||
input.value = '1991-01-01';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.value = '1991-01-02';
|
||||
checkValidity(input, false, apply, { low: "1991-01-01", high: "1991-01-12" });
|
||||
checkValidity(input, false, apply, { low: "1991-01-01", high: "1991-01-03" });
|
||||
|
||||
input.value = '1991-01-12';
|
||||
input.value = '1991-01-03';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '1.1';
|
||||
input.step = '2.1';
|
||||
input.min = '1969-12-20';
|
||||
input.value = '1969-12-20';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.value = '1969-12-21';
|
||||
checkValidity(input, false, apply, { low: "1969-12-20", high: "1969-12-31" });
|
||||
checkValidity(input, false, apply, { low: "1969-12-20", high: "1969-12-22" });
|
||||
|
||||
input.value = '1969-12-31';
|
||||
input.value = '1969-12-22';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
break;
|
||||
|
@ -271,12 +271,12 @@ function checkStepDown()
|
||||
[ '2012-01-03', '0.5', null, null, null, '2012-01-02', false ],
|
||||
[ '2012-01-02', '0.5', null, null, null, '2012-01-01', false ],
|
||||
[ '2012-01-01', '2', null, null, null, '2011-12-30', false ],
|
||||
[ '2012-01-02', '0.25',null, null, 4, '2012-01-01', false ],
|
||||
[ '2012-01-15', '1.1', '2012-01-01', null, 1, '2012-01-12', false ],
|
||||
[ '2012-01-12', '1.1', '2012-01-01', null, 2, '2012-01-01', false ],
|
||||
[ '2012-01-23', '1.1', '2012-01-01', null, 10, '2012-01-12', false ],
|
||||
[ '2012-01-23', '1.1', '2012-01-01', null, 11, '2012-01-01', false ],
|
||||
[ '1968-01-12', '1.1', '1968-01-01', null, 8, '1968-01-01', false ],
|
||||
[ '2012-01-02', '0.25',null, null, 4, '2011-12-29', false ],
|
||||
[ '2012-01-15', '1.1', '2012-01-01', null, 1, '2012-01-14', false ],
|
||||
[ '2012-01-12', '1.1', '2012-01-01', null, 2, '2012-01-10', false ],
|
||||
[ '2012-01-23', '1.1', '2012-01-01', null, 10, '2012-01-13', false ],
|
||||
[ '2012-01-23', '1.1', '2012-01-01', null, 11, '2012-01-12', false ],
|
||||
[ '1968-01-12', '1.1', '1968-01-01', null, 8, '1968-01-04', false ],
|
||||
// step = 0 isn't allowed (-> step = 1).
|
||||
[ '2012-01-02', '0', null, null, null, '2012-01-01', false ],
|
||||
// step < 0 isn't allowed (-> step = 1).
|
||||
@ -588,14 +588,13 @@ function checkStepUp()
|
||||
[ '2012-01-01', null, null, null, 1.9, '2012-01-02', false ],
|
||||
// With step values.
|
||||
[ '2012-01-01', '0.5', null, null, null, '2012-01-02', false ],
|
||||
[ '2012-01-01', '0.5', null, null, null, '2012-01-02', false ],
|
||||
[ '2012-01-01', '2', null, null, null, '2012-01-03', false ],
|
||||
[ '2012-01-01', '0.25', null, null, 4, '2012-01-02', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 1, '2012-01-12', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 2, '2012-01-12', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 10, '2012-01-12', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 11, '2012-01-23', false ],
|
||||
[ '1968-01-01', '1.1', '1968-01-01', null, 8, '1968-01-12', false ],
|
||||
[ '2012-01-01', '0.25', null, null, 4, '2012-01-05', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 1, '2012-01-02', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 2, '2012-01-03', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 10, '2012-01-11', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 11, '2012-01-12', false ],
|
||||
[ '1968-01-01', '1.1', '1968-01-01', null, 8, '1968-01-09', false ],
|
||||
// step = 0 isn't allowed (-> step = 1).
|
||||
[ '2012-01-01', '0', null, null, null, '2012-01-02', false ],
|
||||
// step < 0 isn't allowed (-> step = 1).
|
||||
|
@ -856,6 +856,8 @@ tags = webvtt
|
||||
[test_timeupdate_small_files.html]
|
||||
[test_trackelementevent.html]
|
||||
tags = webvtt
|
||||
[test_trackelementsrc.html]
|
||||
tags = webvtt
|
||||
[test_trackevent.html]
|
||||
tags = webvtt
|
||||
[test_unseekable.html]
|
||||
|
55
dom/media/test/test_trackelementsrc.html
Normal file
55
dom/media/test/test_trackelementsrc.html
Normal file
@ -0,0 +1,55 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1281418 - Change the src attribue for TrackElement.</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true],
|
||||
["media.webvtt.regions.enabled", true]]}, function() {
|
||||
|
||||
var video = document.createElement("video");
|
||||
video.src = "seek.webm";
|
||||
video.preload = "metadata";
|
||||
var trackElement = document.createElement("track");
|
||||
trackElement.src = "basic.vtt";
|
||||
trackElement.default = true;
|
||||
|
||||
document.getElementById("content").appendChild(video);
|
||||
video.appendChild(trackElement);
|
||||
|
||||
video.addEventListener("loadedmetadata", function metadata() {
|
||||
if (trackElement.readyState <= 1) {
|
||||
return setTimeout(metadata, 0);
|
||||
}
|
||||
is(video.textTracks.length, 1, "Length should be 1.");
|
||||
is(video.textTracks[0].cues.length, 6, "Cue length should be 6.");
|
||||
|
||||
trackElement.src = "sequential.vtt";
|
||||
trackElement.track.mode = "showing";
|
||||
video.play();
|
||||
});
|
||||
|
||||
video.addEventListener("ended", function end() {
|
||||
is(trackElement.readyState, 2, "readyState should be 2.")
|
||||
is(video.textTracks.length, 1, "Length should be 1.");
|
||||
is(video.textTracks[0].cues.length, 3, "Cue length should be 3.");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -21,7 +21,9 @@ addEventListener('fetch', function(evt) {
|
||||
evt.respondWith(registration.unregister().then(function() {
|
||||
return new Response('service worker generated download', {
|
||||
headers: {
|
||||
'Content-Disposition': 'attachment; filename="fake_download.bin"'
|
||||
'Content-Disposition': 'attachment; filename="fake_download.bin"',
|
||||
// fake encoding header that should have no effect
|
||||
'Content-Encoding': 'gzip',
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
@ -34,9 +34,12 @@ namespace image {
|
||||
static LazyLogModule sPNGLog("PNGDecoder");
|
||||
static LazyLogModule sPNGDecoderAccountingLog("PNGDecoderAccounting");
|
||||
|
||||
// Limit image dimensions (bug #251381, #591822, and #967656)
|
||||
#ifndef MOZ_PNG_MAX_DIMENSION
|
||||
# define MOZ_PNG_MAX_DIMENSION 32767
|
||||
// limit image dimensions (bug #251381, #591822, #967656, and #1283961)
|
||||
#ifndef MOZ_PNG_MAX_WIDTH
|
||||
# define MOZ_PNG_MAX_WIDTH 0x7fffffff // Unlimited
|
||||
#endif
|
||||
#ifndef MOZ_PNG_MAX_HEIGHT
|
||||
# define MOZ_PNG_MAX_HEIGHT 0x7fffffff // Unlimited
|
||||
#endif
|
||||
|
||||
nsPNGDecoder::AnimFrameInfo::AnimFrameInfo()
|
||||
@ -323,6 +326,7 @@ nsPNGDecoder::InitInternal()
|
||||
#endif
|
||||
|
||||
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
|
||||
png_set_user_limits(mPNG, MOZ_PNG_MAX_WIDTH, MOZ_PNG_MAX_HEIGHT);
|
||||
if (mCMSMode != eCMSMode_Off) {
|
||||
png_set_chunk_malloc_max(mPNG, 4000000L);
|
||||
}
|
||||
@ -557,11 +561,6 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
|
||||
&interlace_type, &compression_type, &filter_type);
|
||||
|
||||
// Are we too big?
|
||||
if (width > MOZ_PNG_MAX_DIMENSION || height > MOZ_PNG_MAX_DIMENSION) {
|
||||
png_longjmp(decoder->mPNG, 1);
|
||||
}
|
||||
|
||||
const IntRect frameRect(0, 0, width, height);
|
||||
|
||||
// Post our size to the superclass
|
||||
|
@ -990,7 +990,7 @@ function ArrayConcat(arg1) {
|
||||
if (n + len > MAX_NUMERIC_INDEX)
|
||||
ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
|
||||
|
||||
if (IsPackedArray(E)) {
|
||||
if (IsPackedArray(A) && IsPackedArray(E)) {
|
||||
// Step 5.c.i, 5.c.iv, and 5.c.iv.5.
|
||||
for (k = 0; k < len; k++) {
|
||||
// Steps 5.c.iv.1-3.
|
||||
|
@ -1792,8 +1792,11 @@ InitDateTimeFormatClass(JSContext* cx, HandleObject Intl, Handle<GlobalObject*>
|
||||
// is enabled, also add it.
|
||||
if (cx->compartment()->creationOptions().experimentalDateTimeFormatFormatToPartsEnabled()) {
|
||||
RootedValue ftp(cx);
|
||||
if (!GlobalObject::getIntrinsicValue(cx, cx->global(),
|
||||
cx->names().DateTimeFormatFormatToParts, &ftp))
|
||||
HandlePropertyName name = cx->names().formatToParts;
|
||||
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(),
|
||||
cx->names().DateTimeFormatFormatToParts,
|
||||
name,
|
||||
0, &ftp))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1559,6 +1559,15 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto, uint8_t* resul
|
||||
return true;
|
||||
}
|
||||
|
||||
JSNative unicodeGetter;
|
||||
if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().unicode), &unicodeGetter))
|
||||
return false;
|
||||
|
||||
if (unicodeGetter != regexp_unicode) {
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if @@match, @@search, and exec are own data properties,
|
||||
// those values should be tested in selfhosted JS.
|
||||
bool has = false;
|
||||
|
@ -579,6 +579,7 @@ function IsRegExpSplitOptimizable(rx, C) {
|
||||
// If RegExpPrototypeOptimizable succeeds, `RegExpProto.exec` is guaranteed
|
||||
// to be a data property.
|
||||
return RegExpPrototypeOptimizable(RegExpProto) &&
|
||||
RegExpInstanceOptimizable(rx, RegExpProto) &&
|
||||
RegExpProto.exec === RegExp_prototype_Exec;
|
||||
}
|
||||
|
||||
@ -603,7 +604,8 @@ function RegExpSplit(string, limit) {
|
||||
// Steps 6-7.
|
||||
var unicodeMatching = callFunction(std_String_includes, flags, "u");
|
||||
|
||||
var optimizable = IsRegExpSplitOptimizable(rx, C);
|
||||
var optimizable = IsRegExpSplitOptimizable(rx, C) &&
|
||||
(limit === undefined || typeof limit == "number");
|
||||
var splitter;
|
||||
if (optimizable) {
|
||||
// Steps 8-9 (skipped).
|
||||
|
@ -864,23 +864,7 @@ GCState(JSContext* cx, unsigned argc, Value* vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* state;
|
||||
gc::State globalState = cx->runtime()->gc.state();
|
||||
if (globalState == gc::NO_INCREMENTAL)
|
||||
state = "none";
|
||||
else if (globalState == gc::MARK)
|
||||
state = "mark";
|
||||
else if (globalState == gc::SWEEP)
|
||||
state = "sweep";
|
||||
else if (globalState == gc::FINALIZE)
|
||||
state = "finalize";
|
||||
else if (globalState == gc::COMPACT)
|
||||
state = "compact";
|
||||
else if (globalState == gc::DECOMMIT)
|
||||
state = "decommit";
|
||||
else
|
||||
MOZ_CRASH("Unobserveable global GC state");
|
||||
|
||||
const char* state = StateName(cx->runtime()->gc.state());
|
||||
JSString* str = JS_NewStringCopyZ(cx, state);
|
||||
if (!str)
|
||||
return false;
|
||||
|
@ -689,8 +689,8 @@ class GCRuntime
|
||||
public:
|
||||
// Internal public interface
|
||||
State state() const { return incrementalState; }
|
||||
bool isHeapCompacting() const { return state() == COMPACT; }
|
||||
bool isForegroundSweeping() const { return state() == SWEEP; }
|
||||
bool isHeapCompacting() const { return state() == State::Compact; }
|
||||
bool isForegroundSweeping() const { return state() == State::Sweep; }
|
||||
bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); }
|
||||
void waitBackgroundSweepEnd() { helperState.waitBackgroundSweepEnd(); }
|
||||
void waitBackgroundSweepOrAllocEnd() {
|
||||
@ -766,7 +766,7 @@ class GCRuntime
|
||||
void disallowIncrementalGC() { incrementalAllowed = false; }
|
||||
|
||||
bool isIncrementalGCEnabled() const { return mode == JSGC_MODE_INCREMENTAL && incrementalAllowed; }
|
||||
bool isIncrementalGCInProgress() const { return state() != NO_INCREMENTAL; }
|
||||
bool isIncrementalGCInProgress() const { return state() != State::NotActive; }
|
||||
|
||||
bool isGenerationalGCEnabled() const { return generationalDisabled == 0; }
|
||||
void disableGenerationalGC();
|
||||
|
@ -346,8 +346,8 @@ static void
|
||||
AssertRootMarkingPhase(JSTracer* trc)
|
||||
{
|
||||
MOZ_ASSERT_IF(trc->isMarkingTracer(),
|
||||
trc->runtime()->gc.state() == NO_INCREMENTAL ||
|
||||
trc->runtime()->gc.state() == MARK_ROOTS);
|
||||
trc->runtime()->gc.state() == State::NotActive ||
|
||||
trc->runtime()->gc.state() == State::MarkRoots);
|
||||
}
|
||||
|
||||
|
||||
@ -1945,7 +1945,7 @@ bool
|
||||
GCMarker::markDelayedChildren(SliceBudget& budget)
|
||||
{
|
||||
GCRuntime& gc = runtime()->gc;
|
||||
gcstats::AutoPhase ap(gc.stats, gc.state() == MARK, gcstats::PHASE_MARK_DELAYED);
|
||||
gcstats::AutoPhase ap(gc.stats, gc.state() == State::Mark, gcstats::PHASE_MARK_DELAYED);
|
||||
|
||||
MOZ_ASSERT(unmarkedArenaStackTop);
|
||||
do {
|
||||
@ -2439,7 +2439,7 @@ CheckIsMarkedThing(T* thingp)
|
||||
JSRuntime* rt = (*thingp)->runtimeFromAnyThread();
|
||||
MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(*thingp),
|
||||
CurrentThreadCanAccessRuntime(rt) ||
|
||||
(rt->isHeapCollecting() && rt->gc.state() == SWEEP));
|
||||
(rt->isHeapCollecting() && rt->gc.state() == State::Sweep));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -253,7 +253,7 @@ struct Statistics
|
||||
double startTimestamp, size_t startFaults, gc::State initialState)
|
||||
: budget(budget), reason(reason),
|
||||
initialState(initialState),
|
||||
finalState(gc::NO_INCREMENTAL),
|
||||
finalState(gc::State::NotActive),
|
||||
resetReason(nullptr),
|
||||
start(start), startTimestamp(startTimestamp),
|
||||
startFaults(startFaults)
|
||||
|
@ -203,7 +203,7 @@ gc::GCRuntime::startVerifyPreBarriers()
|
||||
/* Create the root node. */
|
||||
trc->curnode = MakeNode(trc, nullptr, JS::TraceKind(0));
|
||||
|
||||
incrementalState = MARK_ROOTS;
|
||||
incrementalState = State::MarkRoots;
|
||||
|
||||
/* Make all the roots be edges emanating from the root node. */
|
||||
markRuntime(trc, TraceRuntime, prep.session().lock);
|
||||
@ -230,7 +230,7 @@ gc::GCRuntime::startVerifyPreBarriers()
|
||||
}
|
||||
|
||||
verifyPreData = trc;
|
||||
incrementalState = MARK;
|
||||
incrementalState = State::Mark;
|
||||
marker.start();
|
||||
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
@ -244,7 +244,7 @@ gc::GCRuntime::startVerifyPreBarriers()
|
||||
return;
|
||||
|
||||
oom:
|
||||
incrementalState = NO_INCREMENTAL;
|
||||
incrementalState = State::NotActive;
|
||||
js_delete(trc);
|
||||
verifyPreData = nullptr;
|
||||
}
|
||||
@ -342,7 +342,7 @@ gc::GCRuntime::endVerifyPreBarriers()
|
||||
number++;
|
||||
|
||||
verifyPreData = nullptr;
|
||||
incrementalState = NO_INCREMENTAL;
|
||||
incrementalState = State::NotActive;
|
||||
|
||||
if (!compartmentCreated && IsIncrementalGCSafe(rt)) {
|
||||
CheckEdgeTracer cetrc(rt);
|
||||
|
@ -286,13 +286,6 @@ GetCaseIndependentLetters(char16_t character,
|
||||
for (size_t i = 0; i < choices_length; i++) {
|
||||
char16_t c = choices[i];
|
||||
|
||||
// The standard requires that non-ASCII characters cannot have ASCII
|
||||
// character codes in their equivalence class, even though this
|
||||
// situation occurs multiple times in the unicode tables.
|
||||
static const unsigned kMaxAsciiCharCode = 127;
|
||||
if (!unicode && character > kMaxAsciiCharCode && c <= kMaxAsciiCharCode)
|
||||
continue;
|
||||
|
||||
// Skip characters that can't appear in one byte strings.
|
||||
if (!unicode && ascii_subject && c > kMaxOneByteCharCode)
|
||||
continue;
|
||||
@ -332,10 +325,40 @@ GetCaseIndependentLetters(char16_t character,
|
||||
choices, ArrayLength(choices), letters);
|
||||
}
|
||||
|
||||
char16_t upper = unicode::ToUpperCase(character);
|
||||
unicode::CodepointsWithSameUpperCase others(character);
|
||||
char16_t other1 = others.other1();
|
||||
char16_t other2 = others.other2();
|
||||
char16_t other3 = others.other3();
|
||||
|
||||
// ES 2017 draft 996af87b7072b3c3dd2b1def856c66f456102215 21.2.4.2
|
||||
// step 3.g.
|
||||
// The standard requires that non-ASCII characters cannot have ASCII
|
||||
// character codes in their equivalence class, even though this
|
||||
// situation occurs multiple times in the unicode tables.
|
||||
static const unsigned kMaxAsciiCharCode = 127;
|
||||
if (upper <= kMaxAsciiCharCode) {
|
||||
if (character > kMaxAsciiCharCode) {
|
||||
// If Canonicalize(character) == character, all other characters
|
||||
// should be ignored.
|
||||
return GetCaseIndependentLetters(character, ascii_subject, unicode,
|
||||
&character, 1, letters);
|
||||
}
|
||||
|
||||
if (other1 > kMaxAsciiCharCode)
|
||||
other1 = character;
|
||||
if (other2 > kMaxAsciiCharCode)
|
||||
other2 = character;
|
||||
if (other3 > kMaxAsciiCharCode)
|
||||
other3 = character;
|
||||
}
|
||||
|
||||
const char16_t choices[] = {
|
||||
character,
|
||||
unicode::ToLowerCase(character),
|
||||
unicode::ToUpperCase(character)
|
||||
upper,
|
||||
other1,
|
||||
other2,
|
||||
other3
|
||||
};
|
||||
return GetCaseIndependentLetters(character, ascii_subject, unicode,
|
||||
choices, ArrayLength(choices), letters);
|
||||
|
@ -17,12 +17,12 @@ var g = newGlobal();
|
||||
|
||||
// Start an off thread compilation that will not run until GC has finished
|
||||
if ("gcstate" in this)
|
||||
assertEq(gcstate(), "mark");
|
||||
assertEq(gcstate(), "Mark");
|
||||
g.offThreadCompileScript('23;', {});
|
||||
|
||||
// Wait for the compilation to finish, which must finish the GC first
|
||||
assertEq(23, g.runOffThreadScript());
|
||||
if ("gcstate" in this)
|
||||
assertEq(gcstate(), "none");
|
||||
assertEq(gcstate(), "NotActive");
|
||||
|
||||
print("done");
|
||||
|
@ -27,7 +27,7 @@ function testAbort(zoneCount, objectCount, sliceCount, abortState)
|
||||
|
||||
var didAbort = false;
|
||||
startgc(sliceCount, "shrinking");
|
||||
while (gcstate() !== "none") {
|
||||
while (gcstate() !== "NotActive") {
|
||||
var state = gcstate();
|
||||
if (state == abortState) {
|
||||
abortgc();
|
||||
@ -38,7 +38,7 @@ function testAbort(zoneCount, objectCount, sliceCount, abortState)
|
||||
gcslice(sliceCount);
|
||||
}
|
||||
|
||||
assertEq(gcstate(), "none");
|
||||
assertEq(gcstate(), "NotActive");
|
||||
if (abortState)
|
||||
assertEq(didAbort, true);
|
||||
|
||||
@ -47,6 +47,8 @@ function testAbort(zoneCount, objectCount, sliceCount, abortState)
|
||||
|
||||
gczeal(0);
|
||||
testAbort(10, 10000, 10000);
|
||||
testAbort(10, 10000, 10000, "mark");
|
||||
testAbort(10, 10000, 10000, "sweep");
|
||||
testAbort(10, 10000, 10000, "compact");
|
||||
testAbort(10, 10000, 10000, "Mark");
|
||||
testAbort(10, 10000, 10000, "Sweep");
|
||||
testAbort(10, 10000, 10000, "Compact");
|
||||
// Note: we do not yield automatically before Finalize or Decommit, as they yield internally.
|
||||
// Thus, we may not witness an incremental state in this phase and cannot test it explicitly.
|
||||
|
@ -27,11 +27,11 @@ function testCompacting(zoneCount, objectCount, sliceCount)
|
||||
}
|
||||
|
||||
// Finish any alloc-triggered incremental GC
|
||||
if (gcstate() !== "none")
|
||||
if (gcstate() !== "NotActive")
|
||||
gc();
|
||||
|
||||
startgc(sliceCount, "shrinking");
|
||||
while (gcstate() !== "none") {
|
||||
while (gcstate() !== "NotActive") {
|
||||
gcslice(sliceCount);
|
||||
}
|
||||
|
||||
|
@ -6,26 +6,26 @@ gczeal(0);
|
||||
|
||||
// Non-incremental GC.
|
||||
gc();
|
||||
assertEq(gcstate(), "none");
|
||||
assertEq(gcstate(), "NotActive");
|
||||
|
||||
// Incremental GC in minimal slice. Note that finalization always uses zero-
|
||||
// sized slices while background finalization is on-going, so we need to loop.
|
||||
gcslice(1000000);
|
||||
while (gcstate() == "finalize") { gcslice(1); }
|
||||
while (gcstate() == "decommit") { gcslice(1); }
|
||||
assertEq(gcstate(), "none");
|
||||
while (gcstate() == "Finalize") { gcslice(1); }
|
||||
while (gcstate() == "Decommit") { gcslice(1); }
|
||||
assertEq(gcstate(), "NotActive");
|
||||
|
||||
// Incremental GC in multiple slices: if marking takes more than one slice,
|
||||
// we yield before we start sweeping.
|
||||
gczeal(0);
|
||||
gcslice(1);
|
||||
assertEq(gcstate(), "mark");
|
||||
assertEq(gcstate(), "Mark");
|
||||
gcslice(1000000);
|
||||
assertEq(gcstate(), "mark");
|
||||
assertEq(gcstate(), "Mark");
|
||||
gcslice(1000000);
|
||||
while (gcstate() == "finalize") { gcslice(1); }
|
||||
while (gcstate() == "decommit") { gcslice(1); }
|
||||
assertEq(gcstate(), "none");
|
||||
while (gcstate() == "Finalize") { gcslice(1); }
|
||||
while (gcstate() == "Decommit") { gcslice(1); }
|
||||
assertEq(gcstate(), "NotActive");
|
||||
|
||||
// Zeal mode 8: Incremental GC in two main slices:
|
||||
// 1) mark roots
|
||||
@ -33,11 +33,11 @@ assertEq(gcstate(), "none");
|
||||
// *) finalize.
|
||||
gczeal(8, 0);
|
||||
gcslice(1);
|
||||
assertEq(gcstate(), "mark");
|
||||
assertEq(gcstate(), "Mark");
|
||||
gcslice(1);
|
||||
while (gcstate() == "finalize") { gcslice(1); }
|
||||
while (gcstate() == "decommit") { gcslice(1); }
|
||||
assertEq(gcstate(), "none");
|
||||
while (gcstate() == "Finalize") { gcslice(1); }
|
||||
while (gcstate() == "Decommit") { gcslice(1); }
|
||||
assertEq(gcstate(), "NotActive");
|
||||
|
||||
// Zeal mode 9: Incremental GC in two main slices:
|
||||
// 1) mark roots and marking
|
||||
@ -45,19 +45,19 @@ assertEq(gcstate(), "none");
|
||||
// *) finalize.
|
||||
gczeal(9, 0);
|
||||
gcslice(1);
|
||||
assertEq(gcstate(), "mark");
|
||||
assertEq(gcstate(), "Mark");
|
||||
gcslice(1);
|
||||
while (gcstate() == "finalize") { gcslice(1); }
|
||||
while (gcstate() == "decommit") { gcslice(1); }
|
||||
assertEq(gcstate(), "none");
|
||||
while (gcstate() == "Finalize") { gcslice(1); }
|
||||
while (gcstate() == "Decommit") { gcslice(1); }
|
||||
assertEq(gcstate(), "NotActive");
|
||||
|
||||
// Zeal mode 10: Incremental GC in multiple slices (always yeilds before
|
||||
// sweeping). This test uses long slices to prove that this zeal mode yields
|
||||
// in sweeping, where normal IGC (above) does not.
|
||||
gczeal(10, 0);
|
||||
gcslice(1000000);
|
||||
assertEq(gcstate(), "sweep");
|
||||
assertEq(gcstate(), "Sweep");
|
||||
gcslice(1000000);
|
||||
while (gcstate() == "finalize") { gcslice(1); }
|
||||
while (gcstate() == "decommit") { gcslice(1); }
|
||||
assertEq(gcstate(), "none");
|
||||
while (gcstate() == "Finalize") { gcslice(1); }
|
||||
while (gcstate() == "Decommit") { gcslice(1); }
|
||||
assertEq(gcstate(), "NotActive");
|
||||
|
@ -1502,11 +1502,9 @@ Simulator::exclusiveMonitorClear()
|
||||
}
|
||||
|
||||
int
|
||||
Simulator::readW(int32_t addr, SimInstruction* instr)
|
||||
Simulator::readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f)
|
||||
{
|
||||
// The regexp engine emits unaligned loads, so we don't check for them here
|
||||
// like most of the other methods do.
|
||||
if ((addr & 3) == 0 || !HasAlignmentFault()) {
|
||||
if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) {
|
||||
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
|
||||
return *ptr;
|
||||
}
|
||||
@ -1527,9 +1525,9 @@ Simulator::readW(int32_t addr, SimInstruction* instr)
|
||||
}
|
||||
|
||||
void
|
||||
Simulator::writeW(int32_t addr, int value, SimInstruction* instr)
|
||||
Simulator::writeW(int32_t addr, int value, SimInstruction* instr, UnalignedPolicy f)
|
||||
{
|
||||
if ((addr & 3) == 0 || !HasAlignmentFault()) {
|
||||
if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) {
|
||||
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
|
||||
*ptr = value;
|
||||
return;
|
||||
@ -1592,10 +1590,10 @@ Simulator::writeExW(int32_t addr, int value, SimInstruction* instr)
|
||||
return 1;
|
||||
int32_t old = compareExchangeRelaxed(ptr, expected, int32_t(value));
|
||||
return old != expected;
|
||||
} else {
|
||||
printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
uint16_t
|
||||
@ -1607,6 +1605,15 @@ Simulator::readHU(int32_t addr, SimInstruction* instr)
|
||||
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
// See comments in readW.
|
||||
if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
||||
char* ptr = reinterpret_cast<char*>(addr);
|
||||
uint16_t value;
|
||||
memcpy(&value, ptr, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
return 0;
|
||||
@ -1619,6 +1626,15 @@ Simulator::readH(int32_t addr, SimInstruction* instr)
|
||||
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
// See comments in readW.
|
||||
if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
||||
char* ptr = reinterpret_cast<char*>(addr);
|
||||
int16_t value;
|
||||
memcpy(&value, ptr, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
printf("Unaligned signed halfword read at 0x%08x\n", addr);
|
||||
MOZ_CRASH();
|
||||
return 0;
|
||||
@ -1630,10 +1646,18 @@ Simulator::writeH(int32_t addr, uint16_t value, SimInstruction* instr)
|
||||
if ((addr & 1) == 0 || !HasAlignmentFault()) {
|
||||
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
|
||||
*ptr = value;
|
||||
} else {
|
||||
printf("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
return;
|
||||
}
|
||||
|
||||
// See the comments above in readW.
|
||||
if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
||||
char* ptr = reinterpret_cast<char*>(addr);
|
||||
memcpy(ptr, &value, sizeof(value));
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1642,10 +1666,18 @@ Simulator::writeH(int32_t addr, int16_t value, SimInstruction* instr)
|
||||
if ((addr & 1) == 0 || !HasAlignmentFault()) {
|
||||
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
|
||||
*ptr = value;
|
||||
} else {
|
||||
printf("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
return;
|
||||
}
|
||||
|
||||
// See the comments above in readW.
|
||||
if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
||||
char* ptr = reinterpret_cast<char*>(addr);
|
||||
memcpy(ptr, &value, sizeof(value));
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
uint16_t
|
||||
@ -3194,9 +3226,9 @@ Simulator::decodeType2(SimInstruction* instr)
|
||||
}
|
||||
} else {
|
||||
if (instr->hasL())
|
||||
set_register(rd, readW(addr, instr));
|
||||
set_register(rd, readW(addr, instr, AllowUnaligned));
|
||||
else
|
||||
writeW(addr, get_register(rd), instr);
|
||||
writeW(addr, get_register(rd), instr, AllowUnaligned);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3461,9 +3493,9 @@ Simulator::decodeType3(SimInstruction* instr)
|
||||
}
|
||||
} else {
|
||||
if (instr->hasL())
|
||||
set_register(rd, readW(addr, instr));
|
||||
set_register(rd, readW(addr, instr, AllowUnaligned));
|
||||
else
|
||||
writeW(addr, get_register(rd), instr);
|
||||
writeW(addr, get_register(rd), instr, AllowUnaligned);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4288,8 +4320,10 @@ Simulator::decodeSpecialCondition(SimInstruction* instr)
|
||||
while (r < regs) {
|
||||
uint32_t data[2];
|
||||
get_d_register(Vd + r, data);
|
||||
writeW(address, data[0], instr);
|
||||
writeW(address + 4, data[1], instr);
|
||||
// TODO: We should AllowUnaligned here only if the alignment attribute of
|
||||
// the instruction calls for default alignment.
|
||||
writeW(address, data[0], instr, AllowUnaligned);
|
||||
writeW(address + 4, data[1], instr, AllowUnaligned);
|
||||
address += 8;
|
||||
r++;
|
||||
}
|
||||
@ -4327,8 +4361,10 @@ Simulator::decodeSpecialCondition(SimInstruction* instr)
|
||||
int r = 0;
|
||||
while (r < regs) {
|
||||
uint32_t data[2];
|
||||
data[0] = readW(address, instr);
|
||||
data[1] = readW(address + 4, instr);
|
||||
// TODO: We should AllowUnaligned here only if the alignment attribute of
|
||||
// the instruction calls for default alignment.
|
||||
data[0] = readW(address, instr, AllowUnaligned);
|
||||
data[1] = readW(address + 4, instr, AllowUnaligned);
|
||||
set_d_register(Vd + r, data);
|
||||
address += 8;
|
||||
r++;
|
||||
|
@ -204,6 +204,20 @@ class Simulator
|
||||
end_sim_pc = -2
|
||||
};
|
||||
|
||||
// ForbidUnaligned means "always fault on unaligned access".
|
||||
//
|
||||
// AllowUnaligned means "allow the unaligned access if other conditions are
|
||||
// met". The "other conditions" vary with the instruction: For all
|
||||
// instructions the base condition is !HasAlignmentFault(), ie, the chip is
|
||||
// configured to allow unaligned accesses. For instructions like VLD1
|
||||
// there is an additional constraint that the alignment attribute in the
|
||||
// instruction must be set to "default alignment".
|
||||
|
||||
enum UnalignedPolicy {
|
||||
ForbidUnaligned,
|
||||
AllowUnaligned
|
||||
};
|
||||
|
||||
bool init();
|
||||
|
||||
// Checks if the current instruction should be executed based on its
|
||||
@ -261,8 +275,8 @@ class Simulator
|
||||
inline uint16_t readExHU(int32_t addr, SimInstruction* instr);
|
||||
inline int32_t writeExH(int32_t addr, uint16_t value, SimInstruction* instr);
|
||||
|
||||
inline int readW(int32_t addr, SimInstruction* instr);
|
||||
inline void writeW(int32_t addr, int value, SimInstruction* instr);
|
||||
inline int readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f = ForbidUnaligned);
|
||||
inline void writeW(int32_t addr, int value, SimInstruction* instr, UnalignedPolicy f = ForbidUnaligned);
|
||||
|
||||
inline int readExW(int32_t addr, SimInstruction* instr);
|
||||
inline int writeExW(int32_t addr, int value, SimInstruction* instr);
|
||||
|
@ -85,6 +85,7 @@ static constexpr Register ABINonArgReturnReg1 = { Registers::invalid_reg };
|
||||
|
||||
static constexpr Register WasmTableCallPtrReg = { Registers::invalid_reg };
|
||||
static constexpr Register WasmTableCallSigReg = { Registers::invalid_reg };
|
||||
static constexpr Register WasmTlsReg = { Registers::invalid_reg };
|
||||
|
||||
static constexpr uint32_t ABIStackAlignment = 4;
|
||||
static constexpr uint32_t CodeAlignment = 4;
|
||||
|
@ -44,6 +44,7 @@ UNIFIED_SOURCES += [
|
||||
'testGCExactRooting.cpp',
|
||||
'testGCFinalizeCallback.cpp',
|
||||
'testGCHeapPostBarriers.cpp',
|
||||
'testGCHooks.cpp',
|
||||
'testGCMarking.cpp',
|
||||
'testGCOutOfMemory.cpp',
|
||||
'testGCStoreBufferRemoval.cpp',
|
||||
|
@ -103,7 +103,7 @@ BEGIN_TEST(testGCFinalizeCallback)
|
||||
JS::PrepareForFullGC(cx);
|
||||
js::SliceBudget budget(js::WorkBudget(1));
|
||||
cx->gc.startDebugGC(GC_NORMAL, budget);
|
||||
CHECK(cx->gc.state() == js::gc::MARK);
|
||||
CHECK(cx->gc.state() == js::gc::State::Mark);
|
||||
CHECK(cx->gc.isFullGc());
|
||||
|
||||
JS::RootedObject global4(cx, createTestGlobal());
|
||||
|
36
js/src/jsapi-tests/testGCHooks.cpp
Normal file
36
js/src/jsapi-tests/testGCHooks.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "js/GCAPI.h"
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
static unsigned gSliceCallbackCount = 0;
|
||||
|
||||
static void
|
||||
NonIncrementalGCSliceCallback(JSContext* cx, JS::GCProgress progress, const JS::GCDescription& desc)
|
||||
{
|
||||
++gSliceCallbackCount;
|
||||
MOZ_RELEASE_ASSERT(progress == JS::GC_CYCLE_BEGIN || progress == JS::GC_CYCLE_END);
|
||||
MOZ_RELEASE_ASSERT(desc.isCompartment_ == false);
|
||||
MOZ_RELEASE_ASSERT(desc.invocationKind_ == GC_NORMAL);
|
||||
MOZ_RELEASE_ASSERT(desc.reason_ == JS::gcreason::API);
|
||||
if (progress == JS::GC_CYCLE_END) {
|
||||
mozilla::UniquePtr<char16_t> summary(desc.formatSummaryMessage(cx));
|
||||
mozilla::UniquePtr<char16_t> message(desc.formatSliceMessage(cx));
|
||||
mozilla::UniquePtr<char16_t> json(desc.formatJSON(cx, 0));
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_TEST(testGCSliceCallback)
|
||||
{
|
||||
JS::SetGCSliceCallback(cx, NonIncrementalGCSliceCallback);
|
||||
JS_GC(cx);
|
||||
JS::SetGCSliceCallback(cx, nullptr);
|
||||
CHECK(gSliceCallbackCount == 2);
|
||||
return true;
|
||||
}
|
||||
END_TEST(testGCSliceCallback)
|
127
js/src/jsgc.cpp
127
js/src/jsgc.cpp
@ -53,46 +53,49 @@
|
||||
* The collector proceeds through the following states, the current state being
|
||||
* held in JSRuntime::gcIncrementalState:
|
||||
*
|
||||
* - MARK_ROOTS - marks the stack and other roots
|
||||
* - MARK - incrementally marks reachable things
|
||||
* - SWEEP - sweeps zones in groups and continues marking unswept zones
|
||||
* - MarkRoots - marks the stack and other roots
|
||||
* - Mark - incrementally marks reachable things
|
||||
* - Sweep - sweeps zones in groups and continues marking unswept zones
|
||||
* - Finalize - performs background finalization, concurrent with mutator
|
||||
* - Compact - incrementally compacts by zone
|
||||
* - Decommit - performs background decommit and chunk removal
|
||||
*
|
||||
* The MARK_ROOTS activity always takes place in the first slice. The next two
|
||||
* The MarkRoots activity always takes place in the first slice. The next two
|
||||
* states can take place over one or more slices.
|
||||
*
|
||||
* In other words an incremental collection proceeds like this:
|
||||
*
|
||||
* Slice 1: MARK_ROOTS: Roots pushed onto the mark stack.
|
||||
* MARK: The mark stack is processed by popping an element,
|
||||
* Slice 1: MarkRoots: Roots pushed onto the mark stack.
|
||||
* Mark: The mark stack is processed by popping an element,
|
||||
* marking it, and pushing its children.
|
||||
*
|
||||
* ... JS code runs ...
|
||||
*
|
||||
* Slice 2: MARK: More mark stack processing.
|
||||
* Slice 2: Mark: More mark stack processing.
|
||||
*
|
||||
* ... JS code runs ...
|
||||
*
|
||||
* Slice n-1: MARK: More mark stack processing.
|
||||
* Slice n-1: Mark: More mark stack processing.
|
||||
*
|
||||
* ... JS code runs ...
|
||||
*
|
||||
* Slice n: MARK: Mark stack is completely drained.
|
||||
* SWEEP: Select first group of zones to sweep and sweep them.
|
||||
* Slice n: Mark: Mark stack is completely drained.
|
||||
* Sweep: Select first group of zones to sweep and sweep them.
|
||||
*
|
||||
* ... JS code runs ...
|
||||
*
|
||||
* Slice n+1: SWEEP: Mark objects in unswept zones that were newly
|
||||
* Slice n+1: Sweep: Mark objects in unswept zones that were newly
|
||||
* identified as alive (see below). Then sweep more zone
|
||||
* groups.
|
||||
*
|
||||
* ... JS code runs ...
|
||||
*
|
||||
* Slice n+2: SWEEP: Mark objects in unswept zones that were newly
|
||||
* Slice n+2: Sweep: Mark objects in unswept zones that were newly
|
||||
* identified as alive. Then sweep more zone groups.
|
||||
*
|
||||
* ... JS code runs ...
|
||||
*
|
||||
* Slice m: SWEEP: Sweeping is finished, and background sweeping
|
||||
* Slice m: Sweep: Sweeping is finished, and background sweeping
|
||||
* started on the helper thread.
|
||||
*
|
||||
* ... JS code runs, remaining sweeping done on background thread ...
|
||||
@ -141,7 +144,7 @@
|
||||
*
|
||||
* The order of sweeping is restricted by cross compartment pointers - for
|
||||
* example say that object |a| from zone A points to object |b| in zone B and
|
||||
* neither object was marked when we transitioned to the SWEEP phase. Imagine we
|
||||
* neither object was marked when we transitioned to the Sweep phase. Imagine we
|
||||
* sweep B first and then return to the mutator. It's possible that the mutator
|
||||
* could cause |a| to become alive through a read barrier (perhaps it was a
|
||||
* shape that was accessed via a shape table). Then we would need to mark |b|,
|
||||
@ -822,7 +825,7 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
|
||||
#ifdef DEBUG
|
||||
disableStrictProxyCheckingCount(0),
|
||||
#endif
|
||||
incrementalState(gc::NO_INCREMENTAL),
|
||||
incrementalState(gc::State::NotActive),
|
||||
lastMarkSlice(false),
|
||||
sweepOnBackgroundThread(false),
|
||||
foundBlackGrayEdges(false),
|
||||
@ -4176,7 +4179,7 @@ js::gc::MarkingValidator::nonIncrementalMark(AutoLockForExclusiveAccess& lock)
|
||||
|
||||
/* Re-do all the marking, but non-incrementally. */
|
||||
js::gc::State state = gc->incrementalState;
|
||||
gc->incrementalState = MARK_ROOTS;
|
||||
gc->incrementalState = State::MarkRoots;
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(gc->stats, gcstats::PHASE_MARK);
|
||||
@ -4196,12 +4199,12 @@ js::gc::MarkingValidator::nonIncrementalMark(AutoLockForExclusiveAccess& lock)
|
||||
|
||||
gc->markRuntime(gcmarker, GCRuntime::MarkRuntime, lock);
|
||||
|
||||
gc->incrementalState = MARK;
|
||||
gc->incrementalState = State::Mark;
|
||||
auto unlimited = SliceBudget::unlimited();
|
||||
MOZ_RELEASE_ASSERT(gc->marker.drainMarkStack(unlimited));
|
||||
}
|
||||
|
||||
gc->incrementalState = SWEEP;
|
||||
gc->incrementalState = State::Sweep;
|
||||
{
|
||||
gcstats::AutoPhase ap1(gc->stats, gcstats::PHASE_SWEEP);
|
||||
gcstats::AutoPhase ap2(gc->stats, gcstats::PHASE_SWEEP_MARK);
|
||||
@ -5621,10 +5624,14 @@ void
|
||||
GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lock)
|
||||
{
|
||||
switch (incrementalState) {
|
||||
case NO_INCREMENTAL:
|
||||
case State::NotActive:
|
||||
return;
|
||||
|
||||
case MARK: {
|
||||
case State::MarkRoots:
|
||||
MOZ_CRASH("resetIncrementalGC did not expect MarkRoots state");
|
||||
break;
|
||||
|
||||
case State::Mark: {
|
||||
/* Cancel any ongoing marking. */
|
||||
marker.reset();
|
||||
marker.stop();
|
||||
@ -5641,14 +5648,14 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo
|
||||
|
||||
blocksToFreeAfterSweeping.freeAll();
|
||||
|
||||
incrementalState = NO_INCREMENTAL;
|
||||
incrementalState = State::NotActive;
|
||||
|
||||
MOZ_ASSERT(!marker.shouldCheckCompartments());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SWEEP: {
|
||||
case State::Sweep: {
|
||||
marker.reset();
|
||||
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
|
||||
@ -5673,7 +5680,7 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo
|
||||
break;
|
||||
}
|
||||
|
||||
case FINALIZE: {
|
||||
case State::Finalize: {
|
||||
{
|
||||
gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
|
||||
rt->gc.waitBackgroundSweepOrAllocEnd();
|
||||
@ -5690,7 +5697,7 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo
|
||||
break;
|
||||
}
|
||||
|
||||
case COMPACT: {
|
||||
case State::Compact: {
|
||||
bool wasCompacting = isCompacting;
|
||||
|
||||
isCompacting = true;
|
||||
@ -5704,14 +5711,11 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo
|
||||
break;
|
||||
}
|
||||
|
||||
case DECOMMIT: {
|
||||
case State::Decommit: {
|
||||
auto unlimited = SliceBudget::unlimited();
|
||||
incrementalCollectSlice(unlimited, JS::gcreason::RESET, lock);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Invalid incremental GC state");
|
||||
}
|
||||
|
||||
stats.reset(reason);
|
||||
@ -5724,7 +5728,7 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo
|
||||
MOZ_ASSERT(!zone->isOnList());
|
||||
}
|
||||
MOZ_ASSERT(zonesToMaybeCompact.isEmpty());
|
||||
MOZ_ASSERT(incrementalState == NO_INCREMENTAL);
|
||||
MOZ_ASSERT(incrementalState == State::NotActive);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -5843,33 +5847,33 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
||||
}
|
||||
|
||||
switch (incrementalState) {
|
||||
case NO_INCREMENTAL:
|
||||
case State::NotActive:
|
||||
initialReason = reason;
|
||||
cleanUpEverything = ShouldCleanUpEverything(reason, invocationKind);
|
||||
isCompacting = shouldCompact();
|
||||
lastMarkSlice = false;
|
||||
|
||||
incrementalState = MARK_ROOTS;
|
||||
incrementalState = State::MarkRoots;
|
||||
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case MARK_ROOTS:
|
||||
case State::MarkRoots:
|
||||
if (!beginMarkPhase(reason, lock)) {
|
||||
incrementalState = NO_INCREMENTAL;
|
||||
incrementalState = State::NotActive;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!destroyingRuntime)
|
||||
pushZealSelectedObjects();
|
||||
|
||||
incrementalState = MARK;
|
||||
incrementalState = State::Mark;
|
||||
|
||||
if (isIncremental && useZeal && hasZealMode(ZealMode::IncrementalRootsThenFinish))
|
||||
break;
|
||||
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case MARK:
|
||||
case State::Mark:
|
||||
AutoGCRooter::traceAllWrappers(&marker);
|
||||
|
||||
/* If we needed delayed marking for gray roots, then collect until done. */
|
||||
@ -5884,19 +5888,19 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
||||
MOZ_ASSERT(marker.isDrained());
|
||||
|
||||
if (!lastMarkSlice && isIncremental && useZeal &&
|
||||
((initialState == MARK && !hasZealMode(ZealMode::IncrementalRootsThenFinish)) ||
|
||||
((initialState == State::Mark && !hasZealMode(ZealMode::IncrementalRootsThenFinish)) ||
|
||||
hasZealMode(ZealMode::IncrementalMarkAllThenFinish)))
|
||||
{
|
||||
/*
|
||||
* Yield with the aim of starting the sweep in the next
|
||||
* slice. We will need to mark anything new on the stack
|
||||
* when we resume, so we stay in MARK state.
|
||||
* when we resume, so we stay in Mark state.
|
||||
*/
|
||||
lastMarkSlice = true;
|
||||
break;
|
||||
}
|
||||
|
||||
incrementalState = SWEEP;
|
||||
incrementalState = State::Sweep;
|
||||
|
||||
/*
|
||||
* This runs to completion, but we don't continue if the budget is
|
||||
@ -5915,13 +5919,13 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
||||
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case SWEEP:
|
||||
case State::Sweep:
|
||||
if (sweepPhase(budget, lock) == NotFinished)
|
||||
break;
|
||||
|
||||
endSweepPhase(destroyingRuntime, lock);
|
||||
|
||||
incrementalState = FINALIZE;
|
||||
incrementalState = State::Finalize;
|
||||
|
||||
/* Yield before compacting since it is not incremental. */
|
||||
if (isCompacting && isIncremental)
|
||||
@ -5929,7 +5933,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
||||
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case FINALIZE:
|
||||
case State::Finalize:
|
||||
{
|
||||
gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
|
||||
|
||||
@ -5955,11 +5959,11 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!startedCompacting);
|
||||
incrementalState = COMPACT;
|
||||
incrementalState = State::Compact;
|
||||
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case COMPACT:
|
||||
case State::Compact:
|
||||
if (isCompacting) {
|
||||
if (!startedCompacting)
|
||||
beginCompactPhase();
|
||||
@ -5971,11 +5975,11 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
||||
}
|
||||
|
||||
startDecommit();
|
||||
incrementalState = DECOMMIT;
|
||||
incrementalState = State::Decommit;
|
||||
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case DECOMMIT:
|
||||
case State::Decommit:
|
||||
{
|
||||
gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
|
||||
|
||||
@ -5987,11 +5991,8 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
||||
}
|
||||
|
||||
finishCollection(reason);
|
||||
incrementalState = NO_INCREMENTAL;
|
||||
incrementalState = State::NotActive;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("unexpected GC incrementalState");
|
||||
}
|
||||
}
|
||||
|
||||
@ -6154,7 +6155,7 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
|
||||
}
|
||||
|
||||
/* The GC was reset, so we need a do-over. */
|
||||
if (prevState != NO_INCREMENTAL && !isIncrementalGCInProgress())
|
||||
if (prevState != State::NotActive && !isIncrementalGCInProgress())
|
||||
return true;
|
||||
|
||||
TraceMajorGCStart();
|
||||
@ -6361,7 +6362,7 @@ GCRuntime::finishGC(JS::gcreason::Reason reason)
|
||||
// compacting phase if we need to finish an ongoing incremental GC
|
||||
// non-incrementally to avoid janking the browser.
|
||||
if (!IsOOMReason(initialReason)) {
|
||||
if (incrementalState == COMPACT) {
|
||||
if (incrementalState == State::Compact) {
|
||||
abortGC();
|
||||
return;
|
||||
}
|
||||
@ -6799,8 +6800,8 @@ GCRuntime::runDebugGC()
|
||||
* or compact phases.
|
||||
*/
|
||||
if (hasZealMode(ZealMode::IncrementalMultipleSlices)) {
|
||||
if ((initialState == MARK && incrementalState == SWEEP) ||
|
||||
(initialState == SWEEP && incrementalState == COMPACT))
|
||||
if ((initialState == State::Mark && incrementalState == State::Sweep) ||
|
||||
(initialState == State::Sweep && incrementalState == State::Compact))
|
||||
{
|
||||
incrementalLimit = zealFrequency / 2;
|
||||
}
|
||||
@ -7313,7 +7314,7 @@ JS::IsIncrementalGCInProgress(JSContext* cx)
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::IsIncrementalBarrierNeeded(JSContext* cx)
|
||||
{
|
||||
return cx->gc.state() == gc::MARK && !cx->isHeapBusy();
|
||||
return cx->gc.state() == gc::State::Mark && !cx->isHeapBusy();
|
||||
}
|
||||
|
||||
struct IncrementalReferenceBarrierFunctor {
|
||||
@ -7596,18 +7597,12 @@ NewMemoryInfoObject(JSContext* cx)
|
||||
const char*
|
||||
StateName(State state)
|
||||
{
|
||||
static const char* names[] = {
|
||||
"None",
|
||||
"MarkRoots",
|
||||
"Mark",
|
||||
"Sweep",
|
||||
"Finalize",
|
||||
"Compact",
|
||||
"Decommit"
|
||||
};
|
||||
MOZ_ASSERT(ArrayLength(names) == NUM_STATES);
|
||||
MOZ_ASSERT(state < NUM_STATES);
|
||||
return names[state];
|
||||
switch(state) {
|
||||
#define MAKE_CASE(name) case State::name: return #name;
|
||||
GCSTATES(MAKE_CASE)
|
||||
#undef MAKE_CASE
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("invalide gc::State enum value");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -43,16 +43,18 @@ namespace gc {
|
||||
|
||||
struct FinalizePhase;
|
||||
|
||||
enum State {
|
||||
NO_INCREMENTAL,
|
||||
MARK_ROOTS,
|
||||
MARK,
|
||||
SWEEP,
|
||||
FINALIZE,
|
||||
COMPACT,
|
||||
DECOMMIT,
|
||||
|
||||
NUM_STATES
|
||||
#define GCSTATES(D) \
|
||||
D(NotActive) \
|
||||
D(MarkRoots) \
|
||||
D(Mark) \
|
||||
D(Sweep) \
|
||||
D(Finalize) \
|
||||
D(Compact) \
|
||||
D(Decommit)
|
||||
enum class State {
|
||||
#define MAKE_STATE(name) name,
|
||||
GCSTATES(MAKE_STATE)
|
||||
#undef MAKE_STATE
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -528,6 +528,7 @@ dnl Android libstdc++, placed here so it can use MOZ_ARCH
|
||||
dnl computed above.
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ANDROID_CPU_ARCH
|
||||
MOZ_ANDROID_STLPORT
|
||||
|
||||
dnl ========================================================
|
||||
|
25
js/src/tests/ecma_6/Array/concat-proxy.js
Normal file
25
js/src/tests/ecma_6/Array/concat-proxy.js
Normal file
@ -0,0 +1,25 @@
|
||||
var BUGNUMBER = 1287520;
|
||||
var summary = 'Array.prototype.concat should check HasProperty everytime for non-dense array';
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
var a = [1, 2, 3];
|
||||
a.constructor = {
|
||||
[Symbol.species]: function(...args) {
|
||||
var p = new Proxy(new Array(...args), {
|
||||
defineProperty(target, propertyKey, receiver) {
|
||||
if (propertyKey === "0") delete a[1];
|
||||
return Reflect.defineProperty(target, propertyKey, receiver);
|
||||
}
|
||||
});
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
var p = a.concat();
|
||||
assertEq(0 in p, true);
|
||||
assertEq(1 in p, false);
|
||||
assertEq(2 in p, true);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
71
js/src/tests/ecma_6/RegExp/ignoreCase-multiple.js
Normal file
71
js/src/tests/ecma_6/RegExp/ignoreCase-multiple.js
Normal file
@ -0,0 +1,71 @@
|
||||
var BUGNUMBER = 1280046;
|
||||
var summary = "ignoreCase match should perform Canonicalize both on input and pattern.";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
// Each element [code1, upper, code2] satisfies the following condition:
|
||||
// ToUpperCase(code1) == upper
|
||||
// ToUpperCase(code2) == upper
|
||||
var pairs =
|
||||
[
|
||||
// U+00B5: MICRO SIGN
|
||||
// U+039C: GREEK CAPITAL LETTER MU
|
||||
// U+03BC: GREEK SMALL LETTER MU
|
||||
["\u00B5", "\u039C", "\u03BC"],
|
||||
// U+0345: COMBINING GREEK YPOGEGRAMMENI
|
||||
// U+0399: GREEK CAPITAL LETTER IOTA
|
||||
// U+03B9: GREEK SMALL LETTER IOTA
|
||||
["\u0345", "\u0399", "\u03B9"],
|
||||
// U+03C2: GREEK SMALL LETTER FINAL SIGMA
|
||||
// U+03A3: GREEK CAPITAL LETTER SIGMA
|
||||
// U+03C3: GREEK SMALL LETTER SIGMA
|
||||
["\u03C2", "\u03A3", "\u03C3"],
|
||||
// U+03D0: GREEK BETA SYMBOL
|
||||
// U+0392: GREEK CAPITAL LETTER BETA
|
||||
// U+03B2: GREEK SMALL LETTER BETA
|
||||
["\u03D0", "\u0392", "\u03B2"],
|
||||
// U+03D1: GREEK THETA SYMBOL
|
||||
// U+0398: GREEK CAPITAL LETTER THETA
|
||||
// U+03B8: GREEK SMALL LETTER THETA
|
||||
["\u03D1", "\u0398", "\u03B8"],
|
||||
// U+03D5: GREEK PHI SYMBOL
|
||||
// U+03A6: GREEK CAPITAL LETTER PHI
|
||||
// U+03C6: GREEK SMALL LETTER PHI
|
||||
["\u03D5", "\u03A6", "\u03C6"],
|
||||
// U+03D6: GREEK PI SYMBOL
|
||||
// U+03A0: GREEK CAPITAL LETTER PI
|
||||
// U+03C0: GREEK SMALL LETTER PI
|
||||
["\u03D6", "\u03A0", "\u03C0"],
|
||||
// U+03F0: GREEK KAPPA SYMBOL
|
||||
// U+039A: GREEK CAPITAL LETTER KAPPA
|
||||
// U+03BA: GREEK SMALL LETTER KAPPA
|
||||
["\u03F0", "\u039A", "\u03BA"],
|
||||
// U+03F1: GREEK RHO SYMBOL
|
||||
// U+03A1: GREEK CAPITAL LETTER RHO
|
||||
// U+03C1: GREEK SMALL LETTER RHO
|
||||
["\u03F1", "\u03A1", "\u03C1"],
|
||||
// U+03F5: GREEK LUNATE EPSILON SYMBOL
|
||||
// U+0395: GREEK CAPITAL LETTER EPSILON
|
||||
// U+03B5: GREEK SMALL LETTER EPSILON
|
||||
["\u03F5", "\u0395", "\u03B5"],
|
||||
// U+1E9B: LATIN SMALL LETTER LONG S WITH DOT ABOVE
|
||||
// U+1E60: LATIN CAPITAL LETTER S WITH DOT ABOVE
|
||||
// U+1E61: LATIN SMALL LETTER S WITH DOT ABOVE
|
||||
["\u1E9B", "\u1E60", "\u1E61"],
|
||||
// U+1FBE: GREEK PROSGEGRAMMENI
|
||||
// U+0399: GREEK CAPITAL LETTER IOTA
|
||||
// U+03B9: GREEK SMALL LETTER IOTA
|
||||
["\u1FBE", "\u0399", "\u03B9"],
|
||||
];
|
||||
|
||||
for (var [code1, upper, code2] of pairs) {
|
||||
assertEq(new RegExp(code1, "i").test(code2), true);
|
||||
assertEq(new RegExp(code1, "i").test(upper), true);
|
||||
assertEq(new RegExp(upper, "i").test(code1), true);
|
||||
assertEq(new RegExp(upper, "i").test(code2), true);
|
||||
assertEq(new RegExp(code2, "i").test(code1), true);
|
||||
assertEq(new RegExp(code2, "i").test(upper), true);
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
18
js/src/tests/ecma_6/RegExp/replace-global-unicode.js
Normal file
18
js/src/tests/ecma_6/RegExp/replace-global-unicode.js
Normal file
@ -0,0 +1,18 @@
|
||||
var BUGNUMBER = 1287524;
|
||||
var summary = 'RegExp.prototype[@@replace] should not use optimized path if RegExp.prototype.unicode is modified.';
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
Object.defineProperty(RegExp.prototype, "unicode", {
|
||||
get() {
|
||||
RegExp.prototype.exec = () => null;
|
||||
}
|
||||
});
|
||||
|
||||
var rx = RegExp("a", "g");
|
||||
var s = "abba";
|
||||
var r = rx[Symbol.replace](s, "c");
|
||||
assertEq(r, "abba");
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
14
js/src/tests/ecma_6/RegExp/split-limit.js
Normal file
14
js/src/tests/ecma_6/RegExp/split-limit.js
Normal file
@ -0,0 +1,14 @@
|
||||
var BUGNUMBER = 1287525;
|
||||
var summary = "RegExp.prototype[@@split] shouldn't use optimized path if limit is not number.";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
var rx = /a/;
|
||||
var r = rx[Symbol.split]("abba", {valueOf() {
|
||||
RegExp.prototype.exec = () => null;
|
||||
return 100;
|
||||
}});
|
||||
assertEq(r.length, 1);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
19
js/src/tests/ecma_6/RegExp/split-prop-access.js
Normal file
19
js/src/tests/ecma_6/RegExp/split-prop-access.js
Normal file
@ -0,0 +1,19 @@
|
||||
var BUGNUMBER = 1287525;
|
||||
var summary = 'String.prototype.split should call ToUint32(limit) before ToString(separator).';
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
var accessed = false;
|
||||
|
||||
var rx = /a/;
|
||||
Object.defineProperty(rx, Symbol.match, {
|
||||
get() {
|
||||
accessed = true;
|
||||
}
|
||||
});
|
||||
rx[Symbol.split]("abba");
|
||||
|
||||
assertEq(accessed, true);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
@ -2829,12 +2829,12 @@ Debugger::markIncomingCrossCompartmentEdges(JSTracer* trc)
|
||||
{
|
||||
JSRuntime* rt = trc->runtime();
|
||||
gc::State state = rt->gc.state();
|
||||
MOZ_ASSERT(state == gc::MARK_ROOTS || state == gc::COMPACT);
|
||||
MOZ_ASSERT(state == gc::State::MarkRoots || state == gc::State::Compact);
|
||||
|
||||
for (Debugger* dbg : rt->debuggerList) {
|
||||
Zone* zone = MaybeForwarded(dbg->object.get())->zone();
|
||||
if ((state == gc::MARK_ROOTS && !zone->isCollecting()) ||
|
||||
(state == gc::COMPACT && !zone->isGCCompacting()))
|
||||
if ((state == gc::State::MarkRoots && !zone->isCollecting()) ||
|
||||
(state == gc::State::Compact && !zone->isGCCompacting()))
|
||||
{
|
||||
dbg->markCrossCompartmentEdges(trc);
|
||||
}
|
||||
|
@ -326,6 +326,7 @@ class RegExpCompartment
|
||||
* The shape of RegExp.prototype object that satisfies following:
|
||||
* * RegExp.prototype.global getter is not modified
|
||||
* * RegExp.prototype.sticky getter is not modified
|
||||
* * RegExp.prototype.unicode getter is not modified
|
||||
* * RegExp.prototype.exec is an own data property
|
||||
* * RegExp.prototype[@@match] is an own data property
|
||||
* * RegExp.prototype[@@search] is an own data property
|
||||
|
@ -1380,8 +1380,15 @@ JSStructuredCloneWriter::transferOwnership()
|
||||
}
|
||||
|
||||
MOZ_ASSERT(point <= out.rawBuffer() + out.count());
|
||||
MOZ_ASSERT_IF(point < out.rawBuffer() + out.count(),
|
||||
uint32_t(LittleEndian::readUint64(point) >> 32) < SCTAG_TRANSFER_MAP_HEADER);
|
||||
#if DEBUG
|
||||
// Make sure there aren't any more transfer map entries after the expected
|
||||
// number we read out.
|
||||
if (point < out.rawBuffer() + out.count()) {
|
||||
uint32_t tag, data;
|
||||
SCInput::getPair(point, &tag, &data);
|
||||
MOZ_ASSERT(tag < SCTAG_TRANSFER_MAP_HEADER || tag >= SCTAG_TRANSFER_MAP_END_OF_BUILTIN_TYPES);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -772,6 +772,322 @@ const uint8_t unicode::index2[] = {
|
||||
5, 5, 5, 0, 0, 0,
|
||||
};
|
||||
|
||||
const CodepointsWithSameUpperCaseInfo unicode::js_codepoints_with_same_upper_info[] = {
|
||||
{0, 0, 0},
|
||||
{32, 0, 0},
|
||||
{32, 232, 0},
|
||||
{32, 300, 0},
|
||||
{0, 200, 0},
|
||||
{0, 268, 0},
|
||||
{0, 775, 0},
|
||||
{1, 0, 0},
|
||||
{65336, 0, 0},
|
||||
{65415, 0, 0},
|
||||
{65268, 0, 0},
|
||||
{210, 0, 0},
|
||||
{206, 0, 0},
|
||||
{205, 0, 0},
|
||||
{79, 0, 0},
|
||||
{202, 0, 0},
|
||||
{203, 0, 0},
|
||||
{207, 0, 0},
|
||||
{211, 0, 0},
|
||||
{209, 0, 0},
|
||||
{213, 0, 0},
|
||||
{214, 0, 0},
|
||||
{218, 0, 0},
|
||||
{217, 0, 0},
|
||||
{219, 0, 0},
|
||||
{1, 2, 0},
|
||||
{0, 1, 0},
|
||||
{65535, 0, 0},
|
||||
{65439, 0, 0},
|
||||
{65480, 0, 0},
|
||||
{65406, 0, 0},
|
||||
{10795, 0, 0},
|
||||
{65373, 0, 0},
|
||||
{10792, 0, 0},
|
||||
{65341, 0, 0},
|
||||
{69, 0, 0},
|
||||
{71, 0, 0},
|
||||
{0, 116, 7289},
|
||||
{38, 0, 0},
|
||||
{37, 0, 0},
|
||||
{64, 0, 0},
|
||||
{63, 0, 0},
|
||||
{32, 62, 0},
|
||||
{32, 96, 0},
|
||||
{32, 57, 0},
|
||||
{65452, 32, 7205},
|
||||
{32, 86, 0},
|
||||
{64793, 32, 0},
|
||||
{32, 54, 0},
|
||||
{32, 80, 0},
|
||||
{31, 32, 0},
|
||||
{32, 47, 0},
|
||||
{0, 30, 0},
|
||||
{0, 64, 0},
|
||||
{0, 25, 0},
|
||||
{65420, 0, 7173},
|
||||
{0, 54, 0},
|
||||
{64761, 0, 0},
|
||||
{0, 22, 0},
|
||||
{0, 48, 0},
|
||||
{0, 15, 0},
|
||||
{8, 0, 0},
|
||||
{65506, 0, 0},
|
||||
{65511, 0, 0},
|
||||
{65521, 0, 0},
|
||||
{65514, 0, 0},
|
||||
{65482, 0, 0},
|
||||
{65488, 0, 0},
|
||||
{65472, 0, 0},
|
||||
{65529, 0, 0},
|
||||
{80, 0, 0},
|
||||
{15, 0, 0},
|
||||
{48, 0, 0},
|
||||
{7264, 0, 0},
|
||||
{1, 59, 0},
|
||||
{0, 58, 0},
|
||||
{65478, 0, 0},
|
||||
{65528, 0, 0},
|
||||
{65462, 0, 0},
|
||||
{65527, 0, 0},
|
||||
{58247, 58363, 0},
|
||||
{65450, 0, 0},
|
||||
{65436, 0, 0},
|
||||
{65424, 0, 0},
|
||||
{65408, 0, 0},
|
||||
{65410, 0, 0},
|
||||
{28, 0, 0},
|
||||
{16, 0, 0},
|
||||
{26, 0, 0},
|
||||
{54793, 0, 0},
|
||||
{61722, 0, 0},
|
||||
{54809, 0, 0},
|
||||
{54756, 0, 0},
|
||||
{54787, 0, 0},
|
||||
{54753, 0, 0},
|
||||
{54754, 0, 0},
|
||||
{54721, 0, 0},
|
||||
{30204, 0, 0},
|
||||
{23256, 0, 0},
|
||||
{23228, 0, 0},
|
||||
};
|
||||
|
||||
const uint8_t unicode::codepoints_with_same_upper_index1[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, 23, 21, 24, 25,
|
||||
26, 27, 0, 0, 0, 0, 28, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 31, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 34, 21, 35,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36,
|
||||
37, 0, 38, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0,
|
||||
};
|
||||
|
||||
const uint8_t unicode::codepoints_with_same_upper_index2[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 8,
|
||||
7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7,
|
||||
0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 9, 7,
|
||||
0, 7, 0, 7, 0, 10, 0, 11, 7, 0, 7, 0, 12, 7, 0, 13, 13, 7,
|
||||
0, 0, 14, 15, 16, 7, 0, 13, 17, 0, 18, 19, 7, 0, 0, 0, 18, 20,
|
||||
0, 21, 7, 0, 7, 0, 7, 0, 22, 7, 0, 22, 0, 0, 7, 0, 22, 7,
|
||||
0, 23, 23, 7, 0, 7, 0, 24, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 25, 26, 27, 25, 26, 27, 25, 26, 27, 7, 0, 7, 0, 7, 0, 7,
|
||||
0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 25, 26, 27, 7, 0, 28, 29,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 30, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 31, 7, 0, 32, 33, 0,
|
||||
0, 7, 0, 34, 35, 36, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 39, 39, 39, 0, 40, 0, 41, 41,
|
||||
0, 1, 42, 1, 1, 43, 1, 1, 44, 45, 46, 1, 47, 1, 1, 1, 48, 49,
|
||||
0, 50, 1, 1, 51, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 52, 0,
|
||||
0, 53, 0, 0, 54, 55, 56, 0, 57, 0, 0, 0, 58, 59, 26, 27, 0, 0,
|
||||
60, 0, 0, 0, 0, 0, 0, 0, 0, 61, 62, 63, 0, 0, 0, 64, 65, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 66, 67, 0, 0, 0, 68, 0, 7, 0, 69, 7, 0,
|
||||
0, 30, 30, 30, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
|
||||
70, 70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 71, 7,
|
||||
0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
|
||||
72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
|
||||
72, 72, 72, 72, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 0, 73, 0, 0, 0, 0, 0, 73, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
74, 75, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
0, 0, 0, 0, 0, 76, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 77, 0, 77, 0, 77, 0, 77, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 78, 78, 79, 0, 80, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 81, 81, 81, 81, 79, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 77, 77, 82, 82, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 77, 77, 83, 83, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 84, 84, 85, 85, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 87,
|
||||
87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
|
||||
72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
|
||||
72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 89, 90, 91, 0,
|
||||
0, 7, 0, 7, 0, 7, 0, 92, 93, 94, 95, 0, 7, 0, 0, 7, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 96, 96, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7,
|
||||
0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
|
||||
7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7,
|
||||
0, 97, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 7, 0, 98,
|
||||
0, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 99, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
const FoldingInfo unicode::js_foldinfo[] = {
|
||||
{0, 0, 0, 0},
|
||||
{32, 0, 0, 0},
|
||||
|
@ -279,6 +279,76 @@ ToLowerCaseNonBMPTrail(char16_t lead, char16_t trail)
|
||||
return trail;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a codepoint C, CodepointsWithSameUpperCaseInfo stores three offsets
|
||||
* from C to up to three codepoints with same uppercase (no codepoint in
|
||||
* UnicodeData.txt has more than three such codepoints).
|
||||
*
|
||||
* To illustrate, consider the codepoint U+0399 GREEK CAPITAL LETTER IOTA, the
|
||||
* uppercased form of these three codepoints:
|
||||
*
|
||||
* U+03B9 GREEK SMALL LETTER IOTA
|
||||
* U+1FBE GREEK PROSGEGRAMMENI
|
||||
* U+0345 COMBINING GREEK YPOGEGRAMMENI
|
||||
*
|
||||
* For the CodepointsWithSameUpperCaseInfo corresponding to this codepoint,
|
||||
* delta{1,2,3} are 16-bit modular deltas from 0x0399 to each respective
|
||||
* codepoint:
|
||||
* uint16_t(0x03B9 - 0x0399),
|
||||
* uint16_t(0x1FBE - 0x0399),
|
||||
* uint16_t(0x0345 - 0x0399)
|
||||
* in an unimportant order.
|
||||
*
|
||||
* If there are fewer than three other codepoints, some fields are zero.
|
||||
* Consider the codepoint U+03B9 above, the other two codepoints U+1FBE and
|
||||
* U+0345 have same uppercase (U+0399 is not). For the
|
||||
* CodepointsWithSameUpperCaseInfo corresponding to this codepoint,
|
||||
* delta{1,2,3} are:
|
||||
* uint16_t(0x1FBE - 0x03B9),
|
||||
* uint16_t(0x0345 - 0x03B9),
|
||||
* uint16_t(0)
|
||||
* in an unimportant order.
|
||||
*
|
||||
* Because multiple codepoints map to a single CodepointsWithSameUpperCaseInfo,
|
||||
* a CodepointsWithSameUpperCaseInfo and its delta{1,2,3} have no meaning
|
||||
* standing alone: they have meaning only with respect to a codepoint mapping
|
||||
* to that CodepointsWithSameUpperCaseInfo.
|
||||
*/
|
||||
class CodepointsWithSameUpperCaseInfo
|
||||
{
|
||||
public:
|
||||
uint16_t delta1;
|
||||
uint16_t delta2;
|
||||
uint16_t delta3;
|
||||
};
|
||||
|
||||
extern const uint8_t codepoints_with_same_upper_index1[];
|
||||
extern const uint8_t codepoints_with_same_upper_index2[];
|
||||
extern const CodepointsWithSameUpperCaseInfo js_codepoints_with_same_upper_info[];
|
||||
|
||||
class CodepointsWithSameUpperCase
|
||||
{
|
||||
const CodepointsWithSameUpperCaseInfo& info_;
|
||||
const char16_t code_;
|
||||
|
||||
static const CodepointsWithSameUpperCaseInfo& computeInfo(char16_t code) {
|
||||
const size_t shift = 6;
|
||||
size_t index = codepoints_with_same_upper_index1[code >> shift];
|
||||
index = codepoints_with_same_upper_index2[(index << shift) + (code & ((1 << shift) - 1))];
|
||||
return js_codepoints_with_same_upper_info[index];
|
||||
}
|
||||
|
||||
public:
|
||||
explicit CodepointsWithSameUpperCase(char16_t code)
|
||||
: info_(computeInfo(code)),
|
||||
code_(code)
|
||||
{}
|
||||
|
||||
char16_t other1() const { return uint16_t(code_) + info_.delta1; }
|
||||
char16_t other2() const { return uint16_t(code_) + info_.delta2; }
|
||||
char16_t other3() const { return uint16_t(code_) + info_.delta3; }
|
||||
};
|
||||
|
||||
class FoldingInfo {
|
||||
public:
|
||||
uint16_t folding;
|
||||
|
@ -145,6 +145,11 @@ def generate_unicode_stuff(unicode_data, case_folding,
|
||||
table = [dummy]
|
||||
cache = {dummy: 0}
|
||||
index = [0] * (MAX + 1)
|
||||
same_upper_map = {}
|
||||
same_upper_dummy = (0, 0, 0)
|
||||
same_upper_table = [same_upper_dummy]
|
||||
same_upper_cache = {same_upper_dummy: 0}
|
||||
same_upper_index = [0] * (MAX + 1)
|
||||
folding_map = {}
|
||||
rev_folding_map = {}
|
||||
folding_dummy = (0, 0, 0, 0)
|
||||
@ -172,6 +177,11 @@ def generate_unicode_stuff(unicode_data, case_folding,
|
||||
|
||||
if uppercase:
|
||||
upper = int(uppercase, 16)
|
||||
|
||||
if upper not in same_upper_map:
|
||||
same_upper_map[upper] = [code]
|
||||
else:
|
||||
same_upper_map[upper].append(code)
|
||||
else:
|
||||
upper = code
|
||||
|
||||
@ -216,6 +226,36 @@ def generate_unicode_stuff(unicode_data, case_folding,
|
||||
table.append(item)
|
||||
index[code] = i
|
||||
|
||||
for code in range(0, MAX + 1):
|
||||
entry = test_table.get(code)
|
||||
|
||||
if not entry:
|
||||
continue
|
||||
|
||||
(upper, lower, name, alias) = entry
|
||||
|
||||
if upper not in same_upper_map:
|
||||
continue
|
||||
|
||||
same_upper_ds = [v - code for v in same_upper_map[upper]]
|
||||
|
||||
assert len(same_upper_ds) <= 3
|
||||
assert all([v > -65535 and v < 65535 for v in same_upper_ds])
|
||||
|
||||
same_upper = [v & 0xffff for v in same_upper_ds]
|
||||
same_upper_0 = same_upper[0] if len(same_upper) >= 1 else 0
|
||||
same_upper_1 = same_upper[1] if len(same_upper) >= 2 else 0
|
||||
same_upper_2 = same_upper[2] if len(same_upper) >= 3 else 0
|
||||
|
||||
item = (same_upper_0, same_upper_1, same_upper_2)
|
||||
|
||||
i = same_upper_cache.get(item)
|
||||
if i is None:
|
||||
assert item not in same_upper_table
|
||||
same_upper_cache[item] = i = len(same_upper_table)
|
||||
same_upper_table.append(item)
|
||||
same_upper_index[code] = i
|
||||
|
||||
for row in read_case_folding(case_folding):
|
||||
code = row[0]
|
||||
mapping = row[2]
|
||||
@ -310,7 +350,7 @@ def generate_unicode_stuff(unicode_data, case_folding,
|
||||
entry = test_table.get(code)
|
||||
|
||||
if entry:
|
||||
upper, lower, name, alias = entry
|
||||
(upper, lower, name, alias) = entry
|
||||
test_mapping.write(' [' + hex(upper) + ', ' + hex(lower) + '], /* ' +
|
||||
name + (' (' + alias + ')' if alias else '') + ' */\n')
|
||||
else:
|
||||
@ -389,6 +429,11 @@ if (typeof reportCompare === "function")
|
||||
# Don't forget to update CharInfo in Unicode.cpp if you need to change this
|
||||
assert shift == 5
|
||||
|
||||
same_upper_index1, same_upper_index2, same_upper_shift = splitbins(same_upper_index)
|
||||
|
||||
# Don't forget to update CharInfo in Unicode.cpp if you need to change this
|
||||
assert same_upper_shift == 6
|
||||
|
||||
folding_index1, folding_index2, folding_shift = splitbins(folding_index)
|
||||
|
||||
# Don't forget to update CharInfo in Unicode.cpp if you need to change this
|
||||
@ -403,6 +448,15 @@ if (typeof reportCompare === "function")
|
||||
|
||||
assert test == table[idx]
|
||||
|
||||
# verify correctness
|
||||
for char in same_upper_index:
|
||||
test = same_upper_table[same_upper_index[char]]
|
||||
|
||||
idx = same_upper_index1[char >> same_upper_shift]
|
||||
idx = same_upper_index2[(idx << same_upper_shift) + (char & ((1 << same_upper_shift) - 1))]
|
||||
|
||||
assert test == same_upper_table[idx]
|
||||
|
||||
# verify correctness
|
||||
for char in folding_index:
|
||||
test = folding_table[folding_index[char]]
|
||||
@ -497,6 +551,19 @@ if (typeof reportCompare === "function")
|
||||
dump(index2, 'index2', data_file)
|
||||
data_file.write('\n')
|
||||
|
||||
data_file.write('const CodepointsWithSameUpperCaseInfo unicode::js_codepoints_with_same_upper_info[] = {\n')
|
||||
for d in same_upper_table:
|
||||
data_file.write(' {')
|
||||
data_file.write(', '.join((str(e) for e in d)))
|
||||
data_file.write('},\n')
|
||||
data_file.write('};\n')
|
||||
data_file.write('\n')
|
||||
|
||||
dump(same_upper_index1, 'codepoints_with_same_upper_index1', data_file)
|
||||
data_file.write('\n')
|
||||
dump(same_upper_index2, 'codepoints_with_same_upper_index2', data_file)
|
||||
data_file.write('\n')
|
||||
|
||||
data_file.write('const FoldingInfo unicode::js_foldinfo[] = {\n')
|
||||
for d in folding_table:
|
||||
data_file.write(' {')
|
||||
|
@ -50,14 +50,14 @@ ServoRestyleManager::PostRestyleEvent(Element* aElement,
|
||||
void
|
||||
ServoRestyleManager::PostRestyleEventForLazyConstruction()
|
||||
{
|
||||
NS_ERROR("stylo: ServoRestyleManager::PostRestyleEventForLazyConstruction not implemented");
|
||||
NS_WARNING("stylo: ServoRestyleManager::PostRestyleEventForLazyConstruction not implemented");
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
|
||||
nsRestyleHint aRestyleHint)
|
||||
{
|
||||
NS_ERROR("stylo: ServoRestyleManager::RebuildAllStyleData not implemented");
|
||||
NS_WARNING("stylo: ServoRestyleManager::RebuildAllStyleData not implemented");
|
||||
}
|
||||
|
||||
void
|
||||
@ -166,7 +166,7 @@ ServoRestyleManager::NoteRestyleHint(Element* aElement, nsRestyleHint aHint)
|
||||
|
||||
// TODO: Handle all other nsRestyleHint values.
|
||||
if (aHint & ~(eRestyle_Self | eRestyle_Subtree | eRestyle_LaterSiblings)) {
|
||||
NS_ERROR(nsPrintfCString("stylo: Unhandled restyle hint %s",
|
||||
NS_WARNING(nsPrintfCString("stylo: Unhandled restyle hint %s",
|
||||
RestyleManagerBase::RestyleHintToString(aHint).get()).get());
|
||||
}
|
||||
}
|
||||
@ -226,14 +226,14 @@ void
|
||||
ServoRestyleManager::RestyleForInsertOrChange(Element* aContainer,
|
||||
nsIContent* aChild)
|
||||
{
|
||||
NS_ERROR("stylo: ServoRestyleManager::RestyleForInsertOrChange not implemented");
|
||||
NS_WARNING("stylo: ServoRestyleManager::RestyleForInsertOrChange not implemented");
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::RestyleForAppend(Element* aContainer,
|
||||
nsIContent* aFirstNewContent)
|
||||
{
|
||||
NS_ERROR("stylo: ServoRestyleManager::RestyleForAppend not implemented");
|
||||
NS_WARNING("stylo: ServoRestyleManager::RestyleForAppend not implemented");
|
||||
}
|
||||
|
||||
void
|
||||
@ -241,7 +241,7 @@ ServoRestyleManager::RestyleForRemove(Element* aContainer,
|
||||
nsIContent* aOldChild,
|
||||
nsIContent* aFollowingSibling)
|
||||
{
|
||||
NS_ERROR("stylo: ServoRestyleManager::RestyleForRemove not implemented");
|
||||
NS_WARNING("stylo: ServoRestyleManager::RestyleForRemove not implemented");
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -296,18 +296,10 @@ ServoRestyleManager::AttributeWillChange(Element* aElement,
|
||||
snapshot->AddAttrs(aElement);
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute, int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
NS_ERROR("stylo: ServoRestyleManager::AttributeChanged not implemented");
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServoRestyleManager::ReparentStyleContext(nsIFrame* aFrame)
|
||||
{
|
||||
NS_ERROR("stylo: ServoRestyleManager::ReparentStyleContext not implemented");
|
||||
NS_WARNING("stylo: ServoRestyleManager::ReparentStyleContext not implemented");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -62,9 +62,12 @@ public:
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aNewValue);
|
||||
|
||||
// XXXbholley: We should assert that the element is already snapshotted.
|
||||
void AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute, int32_t aModType,
|
||||
const nsAttrValue* aOldValue);
|
||||
const nsAttrValue* aOldValue) {}
|
||||
|
||||
nsresult ReparentStyleContext(nsIFrame* aFrame);
|
||||
|
||||
bool HasPendingRestyles() { return !mModifiedElements.IsEmpty(); }
|
||||
|
@ -2691,7 +2691,7 @@ nsCSSFrameConstructor::ConstructRootFrame()
|
||||
// ServoStyleSets yet.
|
||||
styleSet->AsGecko()->SetBindingManager(mDocument->BindingManager());
|
||||
} else {
|
||||
NS_ERROR("stylo: cannot get ServoStyleSheets from XBL bindings yet");
|
||||
NS_WARNING("stylo: cannot get ServoStyleSheets from XBL bindings yet. See bug 1290276.");
|
||||
}
|
||||
|
||||
// --------- BUILD VIEWPORT -----------
|
||||
|
@ -2347,7 +2347,8 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NS_ERROR("stylo: nsStyleSheetService doesn't handle ServoStyleSheets yet");
|
||||
NS_WARNING("stylo: Not yet checking nsStyleSheetService for Servo-backed "
|
||||
"documents. See bug 1290224");
|
||||
}
|
||||
|
||||
// Caller will handle calling EndUpdate, per contract.
|
||||
|
@ -1867,8 +1867,8 @@ nsPresContext::MediaFeatureValuesChanged(nsRestyleHint aRestyleHint,
|
||||
aRestyleHint |= eRestyle_Subtree;
|
||||
}
|
||||
} else {
|
||||
NS_ERROR("stylo: ServoStyleSets don't support responding to medium "
|
||||
"changes yet");
|
||||
NS_WARNING("stylo: ServoStyleSets don't support responding to medium "
|
||||
"changes yet. See bug 1290228.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4232,8 +4232,8 @@ PresShell::DocumentStatesChanged(nsIDocument* aDocument,
|
||||
// XXXheycam ServoStyleSets don't support document state selectors,
|
||||
// but these are only used in chrome documents, which we are not
|
||||
// aiming to support yet.
|
||||
NS_ERROR("stylo: ServoStyleSets cannot respond to document state "
|
||||
"changes yet");
|
||||
NS_WARNING("stylo: ServoStyleSets cannot respond to document state "
|
||||
"changes yet (only matters for chrome documents). See bug 1290285.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1294,7 +1294,7 @@ Loader::PrepareSheet(StyleSheetHandle aSheet,
|
||||
|
||||
// XXXheycam Need to set media, title, etc. on ServoStyleSheets.
|
||||
if (aSheet->IsServo()) {
|
||||
NS_ERROR("stylo: should set metadata on ServoStyleSheets");
|
||||
NS_WARNING("stylo: should set metadata on ServoStyleSheets. See bug 1290209.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1976,7 +1976,7 @@ Loader::DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
NS_ERROR("stylo: not caching ServoStyleSheet");
|
||||
NS_WARNING("stylo: Stylesheet caching not yet supported - see bug 1290218.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,7 +378,7 @@ nsRestyleHint
|
||||
ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
|
||||
EventStates aStateMask)
|
||||
{
|
||||
NS_ERROR("stylo: HasStateDependentStyle not implemented");
|
||||
NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
|
||||
return nsRestyleHint(0);
|
||||
}
|
||||
|
||||
@ -388,7 +388,7 @@ ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
|
||||
dom::Element* aPseudoElement,
|
||||
EventStates aStateMask)
|
||||
{
|
||||
NS_ERROR("stylo: HasStateDependentStyle not implemented");
|
||||
NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
|
||||
return nsRestyleHint(0);
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,12 @@ function nextPopupTest(panel)
|
||||
if ("last" in popupTests[gTestId])
|
||||
document.getElementById("popupresizer").removeAttribute("flex");
|
||||
|
||||
panel.openPopup();
|
||||
// Prevent event loop starvation as a result of popup events being
|
||||
// synchronous. See bug 1131576.
|
||||
SimpleTest.executeSoon(() => {
|
||||
// Non-chrome shells require focus to open a popup.
|
||||
SimpleTest.waitForFocus(() => { panel.openPopup() });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,9 +5,12 @@
|
||||
#ifndef PNGLCONF_H
|
||||
#define PNGLCONF_H
|
||||
|
||||
/* limit image dimensions (bug #251381, #591822, and #967656) */
|
||||
#ifndef MOZ_PNG_MAX_DIMENSION
|
||||
# define MOZ_PNG_MAX_DIMENSION 32767
|
||||
/* Limit image dimensions (bug #251381, #591822, #967656, and #1283961) */
|
||||
#ifndef MOZ_PNG_MAX_WIDTH
|
||||
# define MOZ_PNG_MAX_WIDTH 0x7fffffffL /* Unlimited */
|
||||
#endif
|
||||
#ifndef MOZ_PNG_MAX_HEIGHT
|
||||
# define MOZ_PNG_MAX_HEIGHT 0x7fffffffL /* Unlimited */
|
||||
#endif
|
||||
|
||||
#define PNG_API_RULE 0
|
||||
@ -23,8 +26,8 @@
|
||||
#define PNG_sRGB_PROFILE_CHECKS -1
|
||||
#define PNG_USER_CHUNK_CACHE_MAX 128
|
||||
#define PNG_USER_CHUNK_MALLOC_MAX 4000000L
|
||||
#define PNG_USER_HEIGHT_MAX MOZ_PNG_MAX_DIMENSION
|
||||
#define PNG_USER_WIDTH_MAX MOZ_PNG_MAX_DIMENSION
|
||||
#define PNG_USER_HEIGHT_MAX MOZ_PNG_MAX_WIDTH
|
||||
#define PNG_USER_WIDTH_MAX MOZ_PNG_MAX_HEIGHT
|
||||
#define PNG_WEIGHT_SHIFT 8
|
||||
#define PNG_ZBUF_SIZE 8192
|
||||
#define PNG_Z_DEFAULT_COMPRESSION (-1)
|
||||
|
@ -1290,6 +1290,13 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnAuthCancelled(nsISupports *aContext,
|
||||
// there are still some challenges to process, do so
|
||||
nsresult rv;
|
||||
|
||||
// Get rid of current continuationState to avoid reusing it in
|
||||
// next challenges since it is no longer relevant.
|
||||
if (mProxyAuth) {
|
||||
NS_IF_RELEASE(mProxyAuthContinuationState);
|
||||
} else {
|
||||
NS_IF_RELEASE(mAuthContinuationState);
|
||||
}
|
||||
nsAutoCString creds;
|
||||
rv = GetCredentials(mRemainingChallenges.get(), mProxyAuth, creds);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -47,12 +47,17 @@ class Introspection(MachCommandBase):
|
||||
build_vars = util.get_build_vars(make_dir, self)
|
||||
|
||||
if what.endswith('.c'):
|
||||
cc = 'CC'
|
||||
name = 'COMPILE_CFLAGS'
|
||||
else:
|
||||
cc = 'CXX'
|
||||
name = 'COMPILE_CXXFLAGS'
|
||||
|
||||
if name not in build_vars:
|
||||
return
|
||||
|
||||
# Drop the first flag since that is the pathname of the compiler.
|
||||
flags = (shell_split(build_vars[cc]) + shell_split(build_vars[name]))[1:]
|
||||
|
||||
print(' '.join(shell_quote(arg)
|
||||
for arg in util.sanitize_cflags(shell_split(build_vars[name]))))
|
||||
for arg in util.sanitize_cflags(flags)))
|
||||
|
@ -674,6 +674,11 @@ public:
|
||||
return Allow();
|
||||
#endif
|
||||
|
||||
#ifdef __NR_fadvise64_64
|
||||
case __NR_fadvise64_64:
|
||||
return Allow();
|
||||
#endif
|
||||
|
||||
case __NR_fallocate:
|
||||
return Allow();
|
||||
|
||||
|
@ -458,10 +458,6 @@ static const char contentSandboxRules[] =
|
||||
" (iokit-user-client-class \"NVDVDContextTesla\")\n"
|
||||
" (iokit-user-client-class \"Gen6DVDContext\"))\n"
|
||||
"\n"
|
||||
"; bug 1190032\n"
|
||||
" (allow file*\n"
|
||||
" (home-regex \"/Library/Caches/TemporaryItems/plugtmp.*\"))\n"
|
||||
"\n"
|
||||
"; bug 1201935\n"
|
||||
" (allow file-read*\n"
|
||||
" (home-subpath \"/Library/Caches/TemporaryItems\"))\n"
|
||||
|
@ -1,7 +1,7 @@
|
||||
$inherits:
|
||||
from: 'tasks/builds/firefox_docker_base.yml'
|
||||
task:
|
||||
workerType: spidermonkey
|
||||
workerType: dbg-linux64
|
||||
|
||||
routes:
|
||||
- 'index.buildbot.branches.{{project}}.sm-plain'
|
||||
|
@ -14,3 +14,4 @@ task:
|
||||
extra:
|
||||
treeherder:
|
||||
symbol: msan
|
||||
tier: 3
|
||||
|
@ -14,3 +14,4 @@ task:
|
||||
extra:
|
||||
treeherder:
|
||||
symbol: tsan
|
||||
tier: 3
|
||||
|
@ -29,6 +29,7 @@ task:
|
||||
/build/tooltool.py fetch -m manifest.tt &&
|
||||
tar xvfz eslint.tar.gz &&
|
||||
rm eslint.tar.gz &&
|
||||
ln -s ../eslint-plugin-mozilla node_modules &&
|
||||
cd ../../.. &&
|
||||
tools/lint/eslint/node_modules/.bin/eslint --quiet --plugin html --ext [.js,.jsm,.jsx,.xml,.html] -f tools/lint/eslint-formatter .
|
||||
|
||||
|
@ -1,8 +1,5 @@
|
||||
[form-validation-reportValidity.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
disabled:
|
||||
if debug and (os == "mac"): https://bugzilla.mozilla.org/show_bug.cgi?id=1273105
|
||||
[[INPUT in TEXT status\] suffering from being too long]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -56,6 +56,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
Cu.import("resource://gre/modules/ExtensionContent.jsm");
|
||||
Cu.import("resource://gre/modules/ExtensionManagement.jsm");
|
||||
|
||||
const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json";
|
||||
@ -326,7 +327,7 @@ class ProxyContext extends ExtensionContext {
|
||||
|
||||
function findPathInObject(obj, path) {
|
||||
for (let elt of path) {
|
||||
obj = obj[elt];
|
||||
obj = obj[elt] || undefined;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
285
toolkit/components/extensions/ExtensionXPCShellUtils.jsm
Normal file
285
toolkit/components/extensions/ExtensionXPCShellUtils.jsm
Normal file
@ -0,0 +1,285 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ExtensionTestUtils"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Extension",
|
||||
"resource://gre/modules/Extension.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
|
||||
"resource://gre/modules/Schemas.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "uuidGenerator",
|
||||
"@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
|
||||
|
||||
/* exported ExtensionTestUtils */
|
||||
|
||||
let BASE_MANIFEST = Object.freeze({
|
||||
"applications": Object.freeze({
|
||||
"gecko": Object.freeze({
|
||||
"id": "test@web.ext",
|
||||
}),
|
||||
}),
|
||||
|
||||
"manifest_version": 2,
|
||||
|
||||
"name": "name",
|
||||
"version": "0",
|
||||
});
|
||||
|
||||
class ExtensionWrapper {
|
||||
constructor(extension, testScope) {
|
||||
this.extension = extension;
|
||||
this.testScope = testScope;
|
||||
|
||||
this.state = "uninitialized";
|
||||
|
||||
this.testResolve = null;
|
||||
this.testDone = new Promise(resolve => { this.testResolve = resolve; });
|
||||
|
||||
this.messageHandler = new Map();
|
||||
this.messageAwaiter = new Map();
|
||||
|
||||
this.messageQueue = new Set();
|
||||
|
||||
this.testScope.do_register_cleanup(() => {
|
||||
if (this.messageQueue.size) {
|
||||
let names = Array.from(this.messageQueue, ([msg]) => msg);
|
||||
this.testScope.equal(JSON.stringify(names), "[]", "message queue is empty");
|
||||
}
|
||||
if (this.messageAwaiter.size) {
|
||||
let names = Array.from(this.messageAwaiter.keys());
|
||||
this.testScope.equal(JSON.stringify(names), "[]", "no tasks awaiting on messages");
|
||||
}
|
||||
});
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
extension.on("test-eq", (kind, pass, msg, expected, actual) => {
|
||||
this.testScope.ok(pass, `${msg} - Expected: ${expected}, Actual: ${actual}`);
|
||||
});
|
||||
extension.on("test-log", (kind, pass, msg) => {
|
||||
this.testScope.do_print(msg);
|
||||
});
|
||||
extension.on("test-result", (kind, pass, msg) => {
|
||||
this.testScope.ok(pass, msg);
|
||||
});
|
||||
extension.on("test-done", (kind, pass, msg, expected, actual) => {
|
||||
this.testScope.ok(pass, msg);
|
||||
this.testResolve(msg);
|
||||
});
|
||||
|
||||
extension.on("test-message", (kind, msg, ...args) => {
|
||||
let handler = this.messageHandler.get(msg);
|
||||
if (handler) {
|
||||
handler(...args);
|
||||
} else {
|
||||
this.messageQueue.add([msg, ...args]);
|
||||
this.checkMessages();
|
||||
}
|
||||
});
|
||||
/* eslint-enable mozilla/balanced-listeners */
|
||||
|
||||
this.testScope.do_register_cleanup(() => {
|
||||
if (this.state == "pending" || this.state == "running") {
|
||||
this.testScope.equal(this.state, "unloaded", "Extension left running at test shutdown");
|
||||
return this.unload();
|
||||
} else if (extension.state == "unloading") {
|
||||
this.testScope.equal(this.state, "unloaded", "Extension not fully unloaded at test shutdown");
|
||||
}
|
||||
});
|
||||
|
||||
this.testScope.do_print(`Extension loaded`);
|
||||
}
|
||||
|
||||
startup() {
|
||||
if (this.state != "uninitialized") {
|
||||
throw new Error("Extension already started");
|
||||
}
|
||||
this.state = "pending";
|
||||
|
||||
return this.extension.startup().then(
|
||||
result => {
|
||||
this.state = "running";
|
||||
|
||||
return result;
|
||||
},
|
||||
error => {
|
||||
this.state = "failed";
|
||||
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
unload() {
|
||||
if (this.state != "running") {
|
||||
throw new Error("Extension not running");
|
||||
}
|
||||
this.state = "unloading";
|
||||
|
||||
this.extension.shutdown();
|
||||
this.state = "unloaded";
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
sendMessage(...args) {
|
||||
this.extension.testMessage(...args);
|
||||
}
|
||||
|
||||
awaitFinish(msg) {
|
||||
return this.testDone.then(actual => {
|
||||
if (msg) {
|
||||
this.testScope.equal(actual, msg, "test result correct");
|
||||
}
|
||||
return actual;
|
||||
});
|
||||
}
|
||||
|
||||
checkMessages() {
|
||||
for (let message of this.messageQueue) {
|
||||
let [msg, ...args] = message;
|
||||
|
||||
let listener = this.messageAwaiter.get(msg);
|
||||
if (listener) {
|
||||
this.messageQueue.delete(message);
|
||||
this.messageAwaiter.delete(msg);
|
||||
|
||||
listener.resolve(...args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkDuplicateListeners(msg) {
|
||||
if (this.messageHandler.has(msg) || this.messageAwaiter.has(msg)) {
|
||||
throw new Error("only one message handler allowed");
|
||||
}
|
||||
}
|
||||
|
||||
awaitMessage(msg) {
|
||||
return new Promise(resolve => {
|
||||
this.checkDuplicateListeners(msg);
|
||||
|
||||
this.messageAwaiter.set(msg, {resolve});
|
||||
this.checkMessages();
|
||||
});
|
||||
}
|
||||
|
||||
onMessage(msg, callback) {
|
||||
this.checkDuplicateListeners(msg);
|
||||
this.messageHandler.set(msg, callback);
|
||||
}
|
||||
}
|
||||
|
||||
var ExtensionTestUtils = {
|
||||
BASE_MANIFEST,
|
||||
|
||||
normalizeManifest: Task.async(function* (manifest, baseManifest = BASE_MANIFEST) {
|
||||
const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
|
||||
|
||||
yield Management.lazyInit();
|
||||
|
||||
let errors = [];
|
||||
let context = {
|
||||
url: null,
|
||||
|
||||
logError: error => {
|
||||
errors.push(error);
|
||||
},
|
||||
|
||||
preprocessors: {},
|
||||
};
|
||||
|
||||
manifest = Object.assign({}, baseManifest, manifest);
|
||||
|
||||
let normalized = Schemas.normalize(manifest, "manifest.WebExtensionManifest", context);
|
||||
normalized.errors = errors;
|
||||
|
||||
return normalized;
|
||||
}),
|
||||
|
||||
currentScope: null,
|
||||
|
||||
profileDir: null,
|
||||
|
||||
init(scope) {
|
||||
this.currentScope = scope;
|
||||
|
||||
this.profileDir = scope.do_get_profile();
|
||||
|
||||
// We need to load at least one frame script into every message
|
||||
// manager to ensure that the scriptable wrapper for its global gets
|
||||
// created before we try to access it externally. If we don't, we
|
||||
// fail sanity checks on debug builds the first time we try to
|
||||
// create a wrapper, because we should never have a global without a
|
||||
// cached wrapper.
|
||||
Services.mm.loadFrameScript("data:text/javascript,//", true);
|
||||
|
||||
|
||||
let tmpD = this.profileDir.clone();
|
||||
tmpD.append("tmp");
|
||||
tmpD.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
||||
|
||||
let dirProvider = {
|
||||
getFile(prop, persistent) {
|
||||
persistent.value = false;
|
||||
if (prop == "TmpD") {
|
||||
return tmpD.clone();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]),
|
||||
};
|
||||
Services.dirsvc.registerProvider(dirProvider);
|
||||
|
||||
|
||||
scope.do_register_cleanup(() => {
|
||||
tmpD.remove(true);
|
||||
Services.dirsvc.unregisterProvider(dirProvider);
|
||||
|
||||
this.currentScope = null;
|
||||
});
|
||||
},
|
||||
|
||||
addonManagerStarted: false,
|
||||
|
||||
startAddonManager() {
|
||||
if (this.addonManagerStarted) {
|
||||
return;
|
||||
}
|
||||
this.addonManagerStarted = true;
|
||||
|
||||
let appInfo = {};
|
||||
Cu.import("resource://testing-common/AppInfo.jsm", appInfo);
|
||||
|
||||
appInfo.updateAppInfo({
|
||||
ID: "xpcshell@tests.mozilla.org",
|
||||
name: "XPCShell",
|
||||
version: "48",
|
||||
platformVersion: "48",
|
||||
});
|
||||
|
||||
|
||||
let manager = Cc["@mozilla.org/addons/integration;1"].getService(Ci.nsIObserver)
|
||||
.QueryInterface(Ci.nsITimerCallback);
|
||||
manager.observe(null, "addons-startup", null);
|
||||
},
|
||||
|
||||
loadExtension(data, id = uuidGenerator.generateUUID().number) {
|
||||
let extension = Extension.generate(id, data);
|
||||
|
||||
return new ExtensionWrapper(extension, this.currentScope);
|
||||
},
|
||||
};
|
@ -19,6 +19,10 @@ EXTRA_COMPONENTS += [
|
||||
'extensions-toolkit.manifest',
|
||||
]
|
||||
|
||||
TESTING_JS_MODULES += [
|
||||
'ExtensionXPCShellUtils.jsm',
|
||||
]
|
||||
|
||||
DIRS += ['schemas']
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
@ -2,18 +2,12 @@
|
||||
support-files =
|
||||
chrome_head.js
|
||||
head.js
|
||||
file_download.html
|
||||
file_download.txt
|
||||
interruptible.sjs
|
||||
file_sample.html
|
||||
|
||||
[test_chrome_ext_background_debug_global.html]
|
||||
skip-if = (os == 'android') # android doesn't have devtools
|
||||
[test_chrome_ext_background_page.html]
|
||||
skip-if = (toolkit == 'android') # android doesn't have devtools
|
||||
[test_chrome_ext_downloads_download.html]
|
||||
[test_chrome_ext_downloads_misc.html]
|
||||
[test_chrome_ext_downloads_search.html]
|
||||
[test_chrome_ext_eventpage_warning.html]
|
||||
[test_chrome_ext_native_messaging.html]
|
||||
skip-if = os == "android" # native messaging is not supported on android
|
||||
|
@ -1,38 +0,0 @@
|
||||
const TEST_DATA = "This is 31 bytes of sample data";
|
||||
const TOTAL_LEN = TEST_DATA.length;
|
||||
const PARTIAL_LEN = 15;
|
||||
|
||||
// A handler to let us systematically test pausing/resuming/canceling
|
||||
// of downloads. This target represents a small text file but a simple
|
||||
// GET will stall after sending part of the data, to give the test code
|
||||
// a chance to pause or do other operations on an in-progress download.
|
||||
// A resumed download (ie, a GET with a Range: header) will allow the
|
||||
// download to complete.
|
||||
function handleRequest(request, response) {
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
|
||||
if (request.hasHeader("Range")) {
|
||||
let start, end;
|
||||
let matches = request.getHeader("Range")
|
||||
.match(/^\s*bytes=(\d+)?-(\d+)?\s*$/);
|
||||
if (matches != null) {
|
||||
start = matches[1] ? parseInt(matches[1], 10) : 0;
|
||||
end = matches[2] ? pareInt(matchs[2], 10) : (TOTAL_LEN - 1);
|
||||
}
|
||||
|
||||
if (end == undefined || end >= TOTAL_LEN) {
|
||||
response.setStatusLine(request.httpVersion, 416, "Requested Range Not Satisfiable");
|
||||
response.setHeader("Content-Range", `*/${TOTAL_LEN}`, false);
|
||||
response.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
response.setStatusLine(request.httpVersion, 206, "Partial Content");
|
||||
response.setHeader("Content-Range", `${start}-${end}/${TOTAL_LEN}`, false);
|
||||
response.write(TEST_DATA.slice(start, end + 1));
|
||||
} else {
|
||||
response.processAsync();
|
||||
response.setHeader("Content-Length", `${TOTAL_LEN}`, false);
|
||||
response.write(TEST_DATA.slice(0, PARTIAL_LEN));
|
||||
}
|
||||
}
|
@ -34,12 +34,9 @@ support-files =
|
||||
file_privilege_escalation.html
|
||||
file_ext_test_api_injection.js
|
||||
file_permission_xhr.html
|
||||
file_download.txt
|
||||
|
||||
[test_ext_extension.html]
|
||||
[test_ext_inIncognitoContext_window.html]
|
||||
skip-if = os == 'android' # Android does not currently support windows.
|
||||
[test_ext_simple.html]
|
||||
[test_ext_geturl.html]
|
||||
[test_ext_background_canvas.html]
|
||||
[test_ext_content_security_policy.html]
|
||||
@ -50,13 +47,9 @@ skip-if = buildapp == 'b2g' # runat != document_idle is not supported.
|
||||
[test_ext_contentscript_devtools_metadata.html]
|
||||
[test_ext_contentscript_exporthelpers.html]
|
||||
[test_ext_contentscript_css.html]
|
||||
[test_ext_downloads.html]
|
||||
[test_ext_exclude_include_globs.html]
|
||||
[test_ext_i18n_css.html]
|
||||
[test_ext_generate.html]
|
||||
[test_ext_idle.html]
|
||||
[test_ext_localStorage.html]
|
||||
[test_ext_onmessage_removelistener.html]
|
||||
[test_ext_notifications.html]
|
||||
[test_ext_permission_xhr.html]
|
||||
skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE:
|
||||
@ -67,9 +60,7 @@ skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined
|
||||
[test_ext_runtime_connect2.html]
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android.
|
||||
[test_ext_runtime_disconnect.html]
|
||||
[test_ext_runtime_getPlatformInfo.html]
|
||||
[test_ext_runtime_id.html]
|
||||
[test_ext_runtime_sendMessage.html]
|
||||
[test_ext_sandbox_var.html]
|
||||
[test_ext_sendmessage_reply.html]
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
|
||||
@ -77,21 +68,12 @@ skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
|
||||
[test_ext_sendmessage_doublereply.html]
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
|
||||
[test_ext_storage.html]
|
||||
[test_ext_storage_content.html]
|
||||
[test_ext_storage_tab.html]
|
||||
skip-if = os == 'android' # Android does not currently support tabs.
|
||||
[test_ext_background_runtime_connect_params.html]
|
||||
[test_ext_cookies.html]
|
||||
[test_ext_bookmarks.html]
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # unimplemented api. Bug 1258975 on android.
|
||||
[test_ext_alarms.html]
|
||||
[test_ext_background_window_properties.html]
|
||||
[test_ext_background_sub_windows.html]
|
||||
[test_ext_background_api_injection.html]
|
||||
[test_ext_background_generated_url.html]
|
||||
[test_ext_background_generated_reload.html]
|
||||
[test_ext_background_generated_load_events.html]
|
||||
[test_ext_i18n.html]
|
||||
skip-if = (os == 'android') # Bug 1258975 on android.
|
||||
[test_ext_web_accessible_resources.html]
|
||||
|
@ -1,47 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test load events in _generated_background_page.html</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
|
||||
add_task(function* test_DOMContentLoaded_in_generated_background_page() {
|
||||
function backgroundScript() {
|
||||
function reportListener(event) {
|
||||
browser.test.sendMessage("eventname", event.type);
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", reportListener);
|
||||
window.addEventListener("load", reportListener);
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
background: {
|
||||
scripts: ["bg.js"],
|
||||
},
|
||||
web_accessible_resources: ["_generated_background_page.html"],
|
||||
},
|
||||
files: {
|
||||
"bg.js": `(${backgroundScript})();`,
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
is("DOMContentLoaded", yield extension.awaitMessage("eventname"));
|
||||
is("load", yield extension.awaitMessage("eventname"));
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,50 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test reload of _generated_background_page.html</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_reload_generated_background_page() {
|
||||
function backgroundScript() {
|
||||
if (location.hash !== "#firstrun") {
|
||||
browser.test.sendMessage("first run");
|
||||
location.hash = "#firstrun";
|
||||
browser.test.assertEq("#firstrun", location.hash);
|
||||
location.reload();
|
||||
} else {
|
||||
browser.test.notifyPass("second run");
|
||||
}
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
background: {
|
||||
scripts: ["bg.js"],
|
||||
},
|
||||
},
|
||||
files: {
|
||||
"bg.js": `(${backgroundScript})();`,
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
info("Waiting for first message");
|
||||
yield extension.awaitMessage("first run");
|
||||
info("Waiting for second message");
|
||||
yield extension.awaitFinish("second run");
|
||||
info("Received both messages");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,3 +1,7 @@
|
||||
{
|
||||
"extends": "../../../../../testing/xpcshell/xpcshell.eslintrc",
|
||||
|
||||
"globals": {
|
||||
"browser": false,
|
||||
},
|
||||
}
|
||||
|
@ -2,12 +2,24 @@
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
/* exported createHttpServer */
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Extension",
|
||||
"resource://gre/modules/Extension.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData",
|
||||
"resource://gre/modules/Extension.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
|
||||
"resource://gre/modules/ExtensionManagement.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionTestUtils",
|
||||
"resource://testing-common/ExtensionXPCShellUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
|
||||
"resource://testing-common/httpd.js");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
|
||||
@ -15,37 +27,28 @@ XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
/* exported normalizeManifest */
|
||||
ExtensionTestUtils.init(this);
|
||||
|
||||
let BASE_MANIFEST = {
|
||||
"applications": {"gecko": {"id": "test@web.ext"}},
|
||||
/**
|
||||
* Creates a new HttpServer for testing, and begins listening on the
|
||||
* specified port. Automatically shuts down the server when the test
|
||||
* unit ends.
|
||||
*
|
||||
* @param {integer} [port]
|
||||
* The port to listen on. If omitted, listen on a random
|
||||
* port. The latter is the preferred behavior.
|
||||
*
|
||||
* @returns {HttpServer}
|
||||
*/
|
||||
function createHttpServer(port = -1) {
|
||||
let server = new HttpServer();
|
||||
server.start(port);
|
||||
|
||||
"manifest_version": 2,
|
||||
do_register_cleanup(() => {
|
||||
return new Promise(resolve => {
|
||||
server.stop(resolve);
|
||||
});
|
||||
});
|
||||
|
||||
"name": "name",
|
||||
"version": "0",
|
||||
};
|
||||
|
||||
function* normalizeManifest(manifest, baseManifest = BASE_MANIFEST) {
|
||||
const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
|
||||
|
||||
yield Management.lazyInit();
|
||||
|
||||
let errors = [];
|
||||
let context = {
|
||||
url: null,
|
||||
|
||||
logError: error => {
|
||||
errors.push(error);
|
||||
},
|
||||
|
||||
preprocessors: {},
|
||||
};
|
||||
|
||||
manifest = Object.assign({}, baseManifest, manifest);
|
||||
|
||||
let normalized = Schemas.normalize(manifest, "manifest.WebExtensionManifest", context);
|
||||
normalized.errors = errors;
|
||||
|
||||
return normalized;
|
||||
return server;
|
||||
}
|
||||
|
@ -1,16 +1,5 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_alarm_without_permissions() {
|
||||
@ -68,37 +57,6 @@ add_task(function* test_alarm_fires() {
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_cleared_alarm_does_not_fire() {
|
||||
function backgroundScript() {
|
||||
let ALARM_NAME = "test_ext_alarms";
|
||||
|
||||
browser.alarms.onAlarm.addListener(alarm => {
|
||||
browser.test.fail("cleared alarm does not fire");
|
||||
browser.test.notifyFail("alarm-cleared");
|
||||
});
|
||||
browser.alarms.create(ALARM_NAME, {when: Date.now() + 1000});
|
||||
|
||||
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
|
||||
browser.test.assertTrue(wasCleared, "alarm was cleared");
|
||||
setTimeout(() => {
|
||||
browser.test.notifyPass("alarm-cleared");
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: `(${backgroundScript})()`,
|
||||
manifest: {
|
||||
permissions: ["alarms"],
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("alarm-cleared");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_alarm_fires_with_when() {
|
||||
function backgroundScript() {
|
||||
let ALARM_NAME = "test_ext_alarms";
|
||||
@ -191,47 +149,6 @@ add_task(function* test_alarm_get_and_clear_single_argument() {
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_periodic_alarm_fires() {
|
||||
function backgroundScript() {
|
||||
const ALARM_NAME = "test_ext_alarms";
|
||||
let count = 0;
|
||||
let timer;
|
||||
|
||||
browser.alarms.onAlarm.addListener(alarm => {
|
||||
browser.test.assertEq(alarm.name, ALARM_NAME, "alarm has the expected name");
|
||||
if (count++ === 3) {
|
||||
clearTimeout(timer);
|
||||
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
|
||||
browser.test.assertTrue(wasCleared, "alarm was cleared");
|
||||
browser.test.notifyPass("alarm-periodic");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
browser.alarms.create(ALARM_NAME, {periodInMinutes: 0.02});
|
||||
|
||||
timer = setTimeout(() => {
|
||||
browser.test.fail("alarm fired expected number of times");
|
||||
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
|
||||
browser.test.assertTrue(wasCleared, "alarm was cleared");
|
||||
});
|
||||
browser.test.notifyFail("alarm-periodic");
|
||||
}, 30000);
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: `(${backgroundScript})()`,
|
||||
manifest: {
|
||||
permissions: ["alarms"],
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("alarm-periodic");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_get_get_all_clear_all_alarms() {
|
||||
function backgroundScript() {
|
||||
const ALARM_NAME = "test_alarm";
|
||||
@ -302,49 +219,3 @@ add_task(function* test_get_get_all_clear_all_alarms() {
|
||||
]);
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_duplicate_alarm_name_replaces_alarm() {
|
||||
function backgroundScript() {
|
||||
let count = 0;
|
||||
|
||||
browser.alarms.onAlarm.addListener(alarm => {
|
||||
if (alarm.name === "master alarm") {
|
||||
browser.alarms.create("child alarm", {delayInMinutes: 0.05});
|
||||
browser.alarms.getAll().then(results => {
|
||||
browser.test.assertEq(2, results.length, "exactly two alarms exist");
|
||||
browser.test.assertEq("master alarm", results[0].name, "first alarm has the expected name");
|
||||
browser.test.assertEq("child alarm", results[1].name, "second alarm has the expected name");
|
||||
}).then(() => {
|
||||
if (count++ === 3) {
|
||||
browser.alarms.clear("master alarm").then(wasCleared => {
|
||||
return browser.alarms.clear("child alarm");
|
||||
}).then(wasCleared => {
|
||||
browser.test.notifyPass("alarm-duplicate");
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
browser.test.fail("duplicate named alarm replaced existing alarm");
|
||||
browser.test.notifyFail("alarm-duplicate");
|
||||
}
|
||||
});
|
||||
|
||||
browser.alarms.create("master alarm", {delayInMinutes: 0.025, periodInMinutes: 0.025});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: `(${backgroundScript})()`,
|
||||
manifest: {
|
||||
permissions: ["alarms"],
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("alarm-duplicate");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,33 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_cleared_alarm_does_not_fire() {
|
||||
function backgroundScript() {
|
||||
let ALARM_NAME = "test_ext_alarms";
|
||||
|
||||
browser.alarms.onAlarm.addListener(alarm => {
|
||||
browser.test.fail("cleared alarm does not fire");
|
||||
browser.test.notifyFail("alarm-cleared");
|
||||
});
|
||||
browser.alarms.create(ALARM_NAME, {when: Date.now() + 1000});
|
||||
|
||||
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
|
||||
browser.test.assertTrue(wasCleared, "alarm was cleared");
|
||||
setTimeout(() => {
|
||||
browser.test.notifyPass("alarm-cleared");
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: `(${backgroundScript})()`,
|
||||
manifest: {
|
||||
permissions: ["alarms"],
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("alarm-cleared");
|
||||
yield extension.unload();
|
||||
});
|
@ -0,0 +1,43 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_periodic_alarm_fires() {
|
||||
function backgroundScript() {
|
||||
const ALARM_NAME = "test_ext_alarms";
|
||||
let count = 0;
|
||||
let timer;
|
||||
|
||||
browser.alarms.onAlarm.addListener(alarm => {
|
||||
browser.test.assertEq(alarm.name, ALARM_NAME, "alarm has the expected name");
|
||||
if (count++ === 3) {
|
||||
clearTimeout(timer);
|
||||
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
|
||||
browser.test.assertTrue(wasCleared, "alarm was cleared");
|
||||
browser.test.notifyPass("alarm-periodic");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
browser.alarms.create(ALARM_NAME, {periodInMinutes: 0.02});
|
||||
|
||||
timer = setTimeout(() => {
|
||||
browser.test.fail("alarm fired expected number of times");
|
||||
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
|
||||
browser.test.assertTrue(wasCleared, "alarm was cleared");
|
||||
});
|
||||
browser.test.notifyFail("alarm-periodic");
|
||||
}, 30000);
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: `(${backgroundScript})()`,
|
||||
manifest: {
|
||||
permissions: ["alarms"],
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("alarm-periodic");
|
||||
yield extension.unload();
|
||||
});
|
@ -0,0 +1,45 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
|
||||
add_task(function* test_duplicate_alarm_name_replaces_alarm() {
|
||||
function backgroundScript() {
|
||||
let count = 0;
|
||||
|
||||
browser.alarms.onAlarm.addListener(alarm => {
|
||||
if (alarm.name === "master alarm") {
|
||||
browser.alarms.create("child alarm", {delayInMinutes: 0.05});
|
||||
browser.alarms.getAll().then(results => {
|
||||
browser.test.assertEq(2, results.length, "exactly two alarms exist");
|
||||
browser.test.assertEq("master alarm", results[0].name, "first alarm has the expected name");
|
||||
browser.test.assertEq("child alarm", results[1].name, "second alarm has the expected name");
|
||||
}).then(() => {
|
||||
if (count++ === 3) {
|
||||
browser.alarms.clear("master alarm").then(wasCleared => {
|
||||
return browser.alarms.clear("child alarm");
|
||||
}).then(wasCleared => {
|
||||
browser.test.notifyPass("alarm-duplicate");
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
browser.test.fail("duplicate named alarm replaced existing alarm");
|
||||
browser.test.notifyFail("alarm-duplicate");
|
||||
}
|
||||
});
|
||||
|
||||
browser.alarms.create("master alarm", {delayInMinutes: 0.025, periodInMinutes: 0.025});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: `(${backgroundScript})()`,
|
||||
manifest: {
|
||||
permissions: ["alarms"],
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("alarm-duplicate");
|
||||
yield extension.unload();
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user