import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1196391, part 3 - Make argument count assertions fatal in js::ExpandErrorArgumentsVA(). r=Waldo (8233c0afac) - minor cleanup (1da0b2c3e9) - Bug 1191765: Make Debugger.Object.prototype.getScript properly recognize functions without scripts. r=fitzgen (3e2753577f) - Bug 1165807 - display WeakSet and WeakMap contents in console; r=bz,fitzgen (d8f70d8e6a) - Bug 1226024 - Expose the root of the dominator tree to JavaScript; r=bz,sfink x # Please enter the commit message for your changes. Lines starting (1949832288) - Bug 1220702 - Part 1: Replace callback() and newNode() with variadic templates. What could go wrong? r=Waldo. (80e1b40871) - Bug 1220702 - Part 2: Fix the .method property of certain FunctionDeclaration nodes. r=Waldo. (47f244a6e0) - Bug 1220702 - Part 3: Distinguish ES6 generators from legacy generators in Reflect.parse() output. r=Waldo. (362bb8ea4b) - bit of Bug 1180017 - Fix up the badly-horked backout and re-land. (f4f92ff88c) - Bug 1155303 - Add telemetry for async DeferredFinalize max pause. r=smaug (3ddc7b8856) - Bug 1174796 - Make sure ReleaseNow releases everything. r=smaug (5065aa1f52) - Bug 1191918 - Remove printf debugging r=me (48e95e425e) - update some tests (26ae4a8050) - Bug 1218643 - correct a DOM test. r=smaug " (75c6302bbb) - space (26dfeca131) - Bug 1166805 part 1 - refactor common tests for whether an animated list mirrors the base version of the list into methods. r=dholbert (e538b90e00) - Bug 1166805 part 2 - Call SetCapacity before calling DOMSVGXXXList::MaybeInsertNullInAnimValListAt, to prevent fallible InsertElementAt calls from failing r=dholbert (918397681f) - Bug 1092125 - Part 1 - Add non-scaling-stroke support to nsSVGPathGeometryElement::GetGeometryBounds (except line). r=jwatt (19ee6f9517) - Bug 1092125 - part 2 - add non-scaling-stroke support to SVGLineElement::GetGeometryBounds. r=jwatt (2c84b88ff1) - Bug 1140080 - ensure we only create stop frames for gradients. r=dholbert (636db91975) - Bug 1182496 - Don't create frames for SVG <text> descendants with failing conditional processing attributes. r=dholbert (4e976c1587) - Bug 1149542 - Part 3: Crashtest. r=dholbert (cde5ca0f57) - Bug 1209525 - Protect GetGeometryBounds from a singular non-scaling-stroke transform. r=longsonr (2cd1f2e0a4) - Bug 325427 - Add crashtest. (98ab5e6907) - Bug 803562 - force -moz-appearance: none on foreignObject elements. r=dbaron (0ba37f76ad) - Bug 950324 - Add crashtest. (6e2f7bc4c2) - Bug 1178159 - Ignore stroke-linecap:"square" on circle and ellipse. r=longsonr (42f4a9a71c) - Bug 1187770 - work around draw targets that don't display zero-length lines. r=longsonr (a612616ecb) - Bug 1222812 - add a null check in case there is no old style. r=dholbert (6a883edea2) - Bug 958160 - Compute bounds in transformed space instead of user space in GetCoveredRegion. r=longsonr (d020a10c56) - Bug 1224061: Followup to fix b2g bustage r=me CLOSED TREE (1dc2693955) - Bug 1173573 - Fix possible crash initializing sessionstorage. r=honzab (c6c77ccf7d) - Bug 536509 - Update localStorage to use common StorageAllowedForWindow logic, r=ehsan (825ee71ff3) - Bug 606655 - delete cookies UI option AskMeEveryTime and its related comments and tests. r=mak (828dfe54a5) - Bug 1194052 - Append to redirectchain before asyncopen() is called (r=sicking,mayhemer) (bb051ceb94) - Bug 1145503 - TP exceptions added while in Private Browsing mode persist beyond the Private Browsing session. r=ehsan Import url-classifier and private browsing modules. (4492b2de09) - Bug 1138979 - Pref to turn TP on when in Private Browsing mode. r=mmc , r=ehsan (5078eaa914) - Bug 1168635 - Extend nsITLSServerSocket to customize cipher suites. r=keeler (185a551640) - Bug 1165423 - WebRTC Fix DTLS handshake by expanding UDP buffer. r=rjesup (1f207e03ee) - Bug 1219939 - make nsTemporaryFileInputStream nsISeekableStream, r=jduell (f2a5ddfbf2) - Bug 1125816 - Parse FTP directory listings of Windows CE and WEC7 FTP Server r=jduell (4137b29d21) - Bug 1171016 - Initialize the linelen variable at its declaration in ParseFTPList.cpp. r=mcmanus (2a3960897d) - Bug 1197313 - remove PR_snprintf calls in netwerk/; r=froydnj (005da76d31) - Bug 1219910 - make gSocketThread a relaxed atomic variable; r=mcmanus (620d299605) - Bug 1222867 - part 1 - return already_AddRefed from WebSocketEventService::CreateFrameIfNeeded; r=mcmanus (0eee829a08) - Bug 1222867 - part 2 - be smarter about transferring ownership of WebSocketFrame; r=mcmanus (4a9fd71798) - Bug 1211001 - constant ASSERTION: nsITimer->SetDelay() called when the one-shot timer is not set up, r=mcmanus (451c903cbe) - Bug 1130822 - properly decode arbitrarily aligned data for non-tier1 platforms. r=mcmanus (bcb99913dc) - Bug 1204731 - telemetry for peer h2 goaway r=hurley (d6748682b4) - Bug 1205810 - telemetry for local h2 goaway code r=hurley (e142625588) - bug 1194818 - h2 header priority handling r=hurley (51766fff44) - bug 1194820 - h2 push promise padding handling r=hurley (560ee1f480) - bug 1208114 - fix h2 connect tunnels r=hurley (d17f920c31) - Bug 1213060 (part 1) - Properly handle discarding padding in Http2Session::OnWriteSegment. r=mcmanus (2cce4ac006) - Bug 1213060 (part 2) - Re-add state assertion in Http2Session::OnWriteSegment. r=mcmanus (6b1c030780) - fix build (39845819f6) - Bug 1214076 - allow TokenServerClient errors to be JSON.stringify'd. r=rnewman (ab6085fa97) - Bug 1220007 P1 Allow ConsoleReportCollectors to flush to another collector. r=bz (a97b2c5a57) - Bug 1220007 P2 Make InterceptedChannel's collect logs locally and only flush to nsIChannel on main thread r=bz (85b77c5a44) - Bug 867407 - Fix cloning of file URIs with search query strings (r=sworkman) (da6fd51c15) - Bug 1220728 Clear pending exceptions if string conversion fails in SWintercept error handling. r=bz (b188c34862) - Bug 1147913 - Change NS_SOCKETTRANSPORTSERVICE_CONTRACTID to NS_STREAMTRANSPORTSERVICE_CONTRACTID in RespondWithHandler::ResolvedCallback. r=ehsan (5b443e88ab) - fix namespace (562ed51caa) - Bug 1206060 - Show pinning status at about:cache. r=michal (75ed53663f) - Bug 1032254 - Generic way to pin reasource in the HTTP cache, r=michal (eeb860f8e3) - Bug 1211504. Remove unused member from RefLayer. (fab6bae915)
@@ -721,6 +721,7 @@
|
||||
@RESPATH@/components/nsUrlClassifierHashCompleter.js
|
||||
@RESPATH@/components/nsUrlClassifierListManager.js
|
||||
@RESPATH@/components/nsUrlClassifierLib.js
|
||||
@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
|
||||
@RESPATH@/components/url-classifier.xpt
|
||||
|
||||
; GNOME hooks
|
||||
|
||||
@@ -650,6 +650,20 @@
|
||||
@RESPATH@/browser/modules/*
|
||||
@RESPATH@/modules/*
|
||||
|
||||
; Safe Browsing
|
||||
#ifdef MOZ_URL_CLASSIFIER
|
||||
@RESPATH@/components/nsURLClassifier.manifest
|
||||
@RESPATH@/components/nsUrlClassifierHashCompleter.js
|
||||
@RESPATH@/components/nsUrlClassifierListManager.js
|
||||
@RESPATH@/components/nsUrlClassifierLib.js
|
||||
@RESPATH@/components/url-classifier.xpt
|
||||
#endif
|
||||
|
||||
; Private Browsing
|
||||
@RESPATH@/components/privatebrowsing.xpt
|
||||
@RESPATH@/components/PrivateBrowsing.manifest
|
||||
@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
|
||||
|
||||
; ANGLE GLES-on-D3D rendering library
|
||||
#ifdef MOZ_ANGLE_RENDERER
|
||||
@BINPATH@/libEGL.dll
|
||||
|
||||
@@ -18,7 +18,7 @@ function f2(stdlib, foreign, buffer) {
|
||||
}
|
||||
if (this.jsFuns)
|
||||
ok(jsFuns.isAsmJSModule(f2), "f2 is an asm.js module");
|
||||
var i32 = new Int32Array(1024);
|
||||
var i32 = new Int32Array(16384); // Smallest allowed buffer size is 64KBy
|
||||
for (var i = 0; i < i32.length; i++)
|
||||
i32[i] = i;
|
||||
var f2Main = f2(this, null, i32.buffer);
|
||||
|
||||
@@ -70,4 +70,5 @@ private:
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,6 +30,26 @@ ThreadSafeChromeUtils::NondeterministicGetWeakMapKeys(GlobalObject& aGlobal,
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ThreadSafeChromeUtils::NondeterministicGetWeakSetKeys(GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aSet,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!aSet.isObject()) {
|
||||
aRetval.setUndefined();
|
||||
} else {
|
||||
JSContext* cx = aGlobal.Context();
|
||||
JS::Rooted<JSObject*> objRet(cx);
|
||||
JS::Rooted<JSObject*> setObj(cx, &aSet.toObject());
|
||||
if (!JS_NondeterministicGetWeakSetKeys(cx, setObj, &objRet)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
} else {
|
||||
aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
|
||||
const dom::OriginAttributesDictionary& aAttrs,
|
||||
|
||||
@@ -38,6 +38,11 @@ public:
|
||||
JS::Handle<JS::Value> aMap,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static void NondeterministicGetWeakSetKeys(GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aSet,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
ErrorResult& aRv);
|
||||
};
|
||||
|
||||
class ChromeUtils : public ThreadSafeChromeUtils
|
||||
|
||||
@@ -79,6 +79,27 @@ ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ConsoleReportCollector::FlushConsoleReports(nsIConsoleReportCollector* aCollector)
|
||||
{
|
||||
MOZ_ASSERT(aCollector);
|
||||
|
||||
nsTArray<PendingReport> reports;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mPendingReports.SwapElements(reports);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < reports.Length(); ++i) {
|
||||
PendingReport& report = reports[i];
|
||||
aCollector->AddConsoleReport(report.mErrorFlags, report.mCategory,
|
||||
report.mPropertiesFile, report.mSourceFileURI,
|
||||
report.mLineNumber, report.mColumnNumber,
|
||||
report.mMessageName, report.mStringParams);
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleReportCollector::~ConsoleReportCollector()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ public:
|
||||
void
|
||||
FlushConsoleReports(nsIDocument* aDocument) override;
|
||||
|
||||
void
|
||||
FlushConsoleReports(nsIConsoleReportCollector* aCollector) override;
|
||||
|
||||
private:
|
||||
~ConsoleReportCollector();
|
||||
|
||||
|
||||
@@ -10688,13 +10688,6 @@ nsGlobalWindow::GetLocalStorage(ErrorResult& aError)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If the document has the sandboxed origin flag set
|
||||
// don't allow access to localStorage.
|
||||
if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
|
||||
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsString documentURI;
|
||||
if (mDoc) {
|
||||
mDoc->GetDocumentURI(documentURI);
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
aLineNumber, aColumnNumber, aMessageName, params);
|
||||
}
|
||||
|
||||
// Flush all pending reports to the console.
|
||||
// Flush all pending reports to the console. Main thread only.
|
||||
//
|
||||
// aDocument An optional document representing where to flush the
|
||||
// reports. If provided, then the corresponding window's
|
||||
@@ -74,6 +74,14 @@ public:
|
||||
// go to the browser console.
|
||||
virtual void
|
||||
FlushConsoleReports(nsIDocument* aDocument) = 0;
|
||||
|
||||
// Flush all pending reports to another collector. May be called from any
|
||||
// thread.
|
||||
//
|
||||
// aCollector A required collector object that will effectively take
|
||||
// ownership of our currently console reports.
|
||||
virtual void
|
||||
FlushConsoleReports(nsIConsoleReportCollector* aCollector) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIConsoleReportCollector, NS_NSICONSOLEREPORTCOLLECTOR_IID)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
var ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageBroadcaster);
|
||||
ppmm.QueryInterface(Ci.nsIProcessScriptLoader);
|
||||
|
||||
@@ -18,7 +18,7 @@ function processScript() {
|
||||
});
|
||||
sendSyncMessage("ProcessTest:Loaded");
|
||||
}
|
||||
let processScriptURL = "data:,(" + processScript.toString() + ")()";
|
||||
var processScriptURL = "data:,(" + processScript.toString() + ")()";
|
||||
|
||||
function initTestScript() {
|
||||
let init = initialProcessData;
|
||||
@@ -29,9 +29,9 @@ function initTestScript() {
|
||||
|
||||
sendAsyncMessage("ProcessTest:InitGood", init.test456.get("hi"));
|
||||
}
|
||||
let initTestScriptURL = "data:,(" + initTestScript.toString() + ")()";
|
||||
var initTestScriptURL = "data:,(" + initTestScript.toString() + ")()";
|
||||
|
||||
let checkProcess = Task.async(function*(mm) {
|
||||
var checkProcess = Task.async(function*(mm) {
|
||||
let { target } = yield promiseMessage(mm, "ProcessTest:Loaded");
|
||||
target.sendAsyncMessage("ProcessTest:Reply");
|
||||
yield promiseMessage(target, "ProcessTest:Finished");
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { interfaces: Ci, classes: Cc, utils: Cu } = Components;
|
||||
var { interfaces: Ci, classes: Cc, utils: Cu } = Components;
|
||||
const { addObserver, removeObserver } = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
const { openWindow } = Cc["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
|
||||
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
var {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
|
||||
const gHttpTestRoot = "http://example.com/browser/dom/base/test/";
|
||||
|
||||
/**
|
||||
* Enable local telemetry recording for the duration of the tests.
|
||||
*/
|
||||
let gOldContentCanRecord = false;
|
||||
var gOldContentCanRecord = false;
|
||||
add_task(function* test_initialize() {
|
||||
gOldContentCanRecord = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function () {
|
||||
let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
@@ -112,7 +112,7 @@ function grabHistogramsFromContent(browser, use_counter_middlefix) {
|
||||
});
|
||||
}
|
||||
|
||||
let check_use_counter_iframe = Task.async(function* (file, use_counter_middlefix, check_documents=true) {
|
||||
var check_use_counter_iframe = Task.async(function* (file, use_counter_middlefix, check_documents=true) {
|
||||
info("checking " + file + " with histogram " + use_counter_middlefix);
|
||||
|
||||
let newTab = gBrowser.addTab( "about:blank");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
Cu.importGlobalProperties(["File"]);
|
||||
|
||||
let testFile = Cc["@mozilla.org/file/directory_service;1"]
|
||||
var testFile = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
.get("ProfD", Ci.nsIFile);
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
<!DOCTYPE html>
|
||||
<audio src="audio.ogg" autoplay="true" loop>
|
||||
<!DOCTYPE html>
|
||||
<audio src="audio.ogg" autoplay="true" loop>
|
||||
|
||||
@@ -4,9 +4,3 @@
|
||||
<iframe id="frame" src="about:robots"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<iframe id="frame" src="about:robots"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cr = Components.results;
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
var Cr = Components.results;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
Cu.importGlobalProperties(["File"]);
|
||||
|
||||
var fileNum = 1;
|
||||
|
||||
@@ -142,10 +142,7 @@ BatteryManager::UpdateFromBatteryInfo(const hal::BatteryInformation& aBatteryInf
|
||||
if (!nsContentUtils::IsChromeDoc(doc) &&
|
||||
status != nsIPrincipal::APP_STATUS_CERTIFIED)
|
||||
{
|
||||
mLevel = 0.292f;
|
||||
printf_stderr("SNORP: battery level before rounding: %lf\n", mLevel);
|
||||
mLevel = lround(mLevel * 10.0) / 10.0;
|
||||
printf_stderr("SNORP: battery level after rounding: %lf\n", mLevel);
|
||||
}
|
||||
|
||||
mCharging = aBatteryInfo.charging();
|
||||
|
||||
@@ -18,3 +18,6 @@ include('/ipc/chromium/chromium-config.mozbuild')
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wshadow']
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = null;
|
||||
var battery = null;
|
||||
|
||||
function verifyInitialState() {
|
||||
window.navigator.getBattery().then(function (b) {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = null;
|
||||
let fromStatus = "charging";
|
||||
let fromCharging = true;
|
||||
var battery = null;
|
||||
var fromStatus = "charging";
|
||||
var fromCharging = true;
|
||||
|
||||
function verifyInitialState() {
|
||||
window.navigator.getBattery().then(function (b) {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = null;
|
||||
let fromStatus = "discharging";
|
||||
let fromCharging = false;
|
||||
var battery = null;
|
||||
var fromStatus = "discharging";
|
||||
var fromCharging = false;
|
||||
|
||||
function verifyInitialState() {
|
||||
window.navigator.getBattery().then(function (b) {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = window.navigator.battery;
|
||||
let fromStatus = "full";
|
||||
let fromCharging = true;
|
||||
var battery = window.navigator.battery;
|
||||
var fromStatus = "full";
|
||||
var fromCharging = true;
|
||||
|
||||
function verifyInitialState() {
|
||||
window.navigator.getBattery().then(function (b) {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = window.navigator.battery;
|
||||
let fromStatus = "not-charging";
|
||||
let fromCharging = false;
|
||||
var battery = window.navigator.battery;
|
||||
var fromStatus = "not-charging";
|
||||
var fromCharging = false;
|
||||
|
||||
function verifyInitialState() {
|
||||
window.navigator.getBattery().then(function (b) {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = window.navigator.battery;
|
||||
let fromStatus = "unknown";
|
||||
let fromCharging = false;
|
||||
var battery = window.navigator.battery;
|
||||
var fromStatus = "unknown";
|
||||
var fromCharging = false;
|
||||
|
||||
function verifyInitialState() {
|
||||
window.navigator.getBattery().then(function (b) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = window.navigator.battery;
|
||||
var battery = window.navigator.battery;
|
||||
|
||||
function verifyInitialState() {
|
||||
ok(battery, "battery");
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = window.navigator.battery;
|
||||
let fromStatus = "charging";
|
||||
let fromCharging = true;
|
||||
var battery = window.navigator.battery;
|
||||
var fromStatus = "charging";
|
||||
var fromCharging = true;
|
||||
|
||||
function verifyInitialState() {
|
||||
ok(battery, "battery");
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = window.navigator.battery;
|
||||
let fromStatus = "discharging";
|
||||
let fromCharging = false;
|
||||
var battery = window.navigator.battery;
|
||||
var fromStatus = "discharging";
|
||||
var fromCharging = false;
|
||||
|
||||
function verifyInitialState() {
|
||||
ok(battery, "battery");
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = window.navigator.battery;
|
||||
let fromStatus = "full";
|
||||
let fromCharging = true;
|
||||
var battery = window.navigator.battery;
|
||||
var fromStatus = "full";
|
||||
var fromCharging = true;
|
||||
|
||||
function verifyInitialState() {
|
||||
ok(battery, "battery");
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = window.navigator.battery;
|
||||
let fromStatus = "not-charging";
|
||||
let fromCharging = false;
|
||||
var battery = window.navigator.battery;
|
||||
var fromStatus = "not-charging";
|
||||
var fromCharging = false;
|
||||
|
||||
function verifyInitialState() {
|
||||
ok(battery, "battery");
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
let battery = window.navigator.battery;
|
||||
let fromStatus = "unknown";
|
||||
let fromCharging = false;
|
||||
var battery = window.navigator.battery;
|
||||
var fromStatus = "unknown";
|
||||
var fromCharging = false;
|
||||
|
||||
function verifyInitialState() {
|
||||
ok(battery, "battery");
|
||||
@@ -1662,8 +1662,7 @@ BluetoothAdapter::DispatchEmptyEvent(const nsAString& aType)
|
||||
{
|
||||
RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
|
||||
|
||||
nsresult rv = event->InitEvent(aType, false, false);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
event->InitEvent(aType, false, false);
|
||||
|
||||
DispatchTrustedEvent(event);
|
||||
}
|
||||
|
||||
@@ -90,13 +90,7 @@ SpeakerManager::DispatchSimpleEvent(const nsAString& aStr)
|
||||
}
|
||||
|
||||
RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
|
||||
rv = event->InitEvent(aStr, false, false);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to init the error event!!!");
|
||||
return;
|
||||
}
|
||||
|
||||
event->InitEvent(aStr, false, false);
|
||||
event->SetTrusted(true);
|
||||
|
||||
rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsICookiePermission.h"
|
||||
#include "nsICookieService.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
#include "mozilla/dom/StorageBinding.h"
|
||||
#include "mozilla/dom/StorageEvent.h"
|
||||
#include "mozilla/dom/StorageEventBinding.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/EnumSet.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
@@ -71,7 +71,7 @@ DOMStorage::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
uint32_t
|
||||
DOMStorage::GetLength(ErrorResult& aRv)
|
||||
{
|
||||
if (!CanUseStorage(mWindow, this)) {
|
||||
if (!CanUseStorage(nullptr, this)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return 0;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ DOMStorage::GetLength(ErrorResult& aRv)
|
||||
void
|
||||
DOMStorage::Key(uint32_t aIndex, nsAString& aResult, ErrorResult& aRv)
|
||||
{
|
||||
if (!CanUseStorage(mWindow, this)) {
|
||||
if (!CanUseStorage(nullptr, this)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
@@ -95,7 +95,7 @@ DOMStorage::Key(uint32_t aIndex, nsAString& aResult, ErrorResult& aRv)
|
||||
void
|
||||
DOMStorage::GetItem(const nsAString& aKey, nsAString& aResult, ErrorResult& aRv)
|
||||
{
|
||||
if (!CanUseStorage(mWindow, this)) {
|
||||
if (!CanUseStorage(nullptr, this)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
@@ -107,7 +107,7 @@ void
|
||||
DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!CanUseStorage(mWindow, this)) {
|
||||
if (!CanUseStorage(nullptr, this)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
@@ -140,7 +140,7 @@ DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData,
|
||||
void
|
||||
DOMStorage::RemoveItem(const nsAString& aKey, ErrorResult& aRv)
|
||||
{
|
||||
if (!CanUseStorage(mWindow, this)) {
|
||||
if (!CanUseStorage(nullptr, this)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
@@ -159,7 +159,7 @@ DOMStorage::RemoveItem(const nsAString& aKey, ErrorResult& aRv)
|
||||
void
|
||||
DOMStorage::Clear(ErrorResult& aRv)
|
||||
{
|
||||
if (!CanUseStorage(mWindow, this)) {
|
||||
if (!CanUseStorage(nullptr, this)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
@@ -232,80 +232,35 @@ DOMStorage::BroadcastChangeNotification(const nsSubstring& aKey,
|
||||
|
||||
static const char kPermissionType[] = "cookie";
|
||||
static const char kStorageEnabled[] = "dom.storage.enabled";
|
||||
static const char kCookiesBehavior[] = "network.cookie.cookieBehavior";
|
||||
static const char kCookiesLifetimePolicy[] = "network.cookie.lifetimePolicy";
|
||||
|
||||
// static, public
|
||||
bool
|
||||
DOMStorage::CanUseStorage(nsIDOMWindow* aWindow, DOMStorage* aStorage)
|
||||
DOMStorage::CanUseStorage(nsPIDOMWindow* aWindow, DOMStorage* aStorage)
|
||||
{
|
||||
// This method is responsible for correct setting of mIsSessionOnly.
|
||||
// It doesn't work with mIsPrivate flag at all, since it is checked
|
||||
// regardless mIsSessionOnly flag in DOMStorageCache code.
|
||||
if (aStorage) {
|
||||
aStorage->mIsSessionOnly = false;
|
||||
}
|
||||
|
||||
if (!mozilla::Preferences::GetBool(kStorageEnabled)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// chrome can always use aStorage regardless of permission preferences
|
||||
nsCOMPtr<nsIPrincipal> subjectPrincipal =
|
||||
nsContentUtils::SubjectPrincipal();
|
||||
if (nsContentUtils::IsSystemPrincipal(subjectPrincipal)) {
|
||||
return true;
|
||||
nsContentUtils::StorageAccess access = nsContentUtils::StorageAccess::eDeny;
|
||||
if (aWindow) {
|
||||
access = nsContentUtils::StorageAllowedForWindow(aWindow);
|
||||
} else if (aStorage) {
|
||||
access = nsContentUtils::StorageAllowedForPrincipal(aStorage->mPrincipal);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
services::GetPermissionManager();
|
||||
if (!permissionManager) {
|
||||
if (access == nsContentUtils::StorageAccess::eDeny) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t perm;
|
||||
permissionManager->TestPermissionFromPrincipal(subjectPrincipal,
|
||||
kPermissionType, &perm);
|
||||
|
||||
if (perm == nsIPermissionManager::DENY_ACTION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (perm == nsICookiePermission::ACCESS_SESSION) {
|
||||
if (aStorage) {
|
||||
aStorage->mIsSessionOnly = true;
|
||||
}
|
||||
} else if (perm != nsIPermissionManager::ALLOW_ACTION) {
|
||||
uint32_t cookieBehavior = Preferences::GetUint(kCookiesBehavior);
|
||||
uint32_t lifetimePolicy = Preferences::GetUint(kCookiesLifetimePolicy);
|
||||
|
||||
// Can't use DOM storage when policy is set to "reject always".
|
||||
if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reject storage from 3rd party embedded content.
|
||||
// If we don't have a window, then we can assume that the content is not
|
||||
// originated from a 3rd party, because storage was not obtained through
|
||||
// the window object.
|
||||
if (aWindow && cookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID);
|
||||
MOZ_ASSERT(thirdPartyUtil);
|
||||
|
||||
bool thirdPartyWindow = false;
|
||||
if (NS_SUCCEEDED(thirdPartyUtil->IsThirdPartyWindow(
|
||||
aWindow, nullptr, &thirdPartyWindow)) && thirdPartyWindow) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (lifetimePolicy == nsICookieService::ACCEPT_SESSION && aStorage) {
|
||||
aStorage->mIsSessionOnly = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (aStorage) {
|
||||
aStorage->mIsSessionOnly = access <= nsContentUtils::StorageAccess::eSessionScoped;
|
||||
|
||||
nsCOMPtr<nsIPrincipal> subjectPrincipal =
|
||||
nsContentUtils::SubjectPrincipal();
|
||||
return aStorage->CanAccess(subjectPrincipal);
|
||||
}
|
||||
|
||||
@@ -343,7 +298,7 @@ DOMStorage::CanAccess(nsIPrincipal* aPrincipal)
|
||||
void
|
||||
DOMStorage::GetSupportedNames(unsigned, nsTArray<nsString>& aKeys)
|
||||
{
|
||||
if (!CanUseStorage(mWindow, this)) {
|
||||
if (!CanUseStorage(nullptr, this)) {
|
||||
// return just an empty array
|
||||
aKeys.Clear();
|
||||
return;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsIDOMWindow;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -115,13 +116,14 @@ public:
|
||||
|
||||
void Clear(ErrorResult& aRv);
|
||||
|
||||
// This method checks whether the caller can use storage.
|
||||
// The method checks whether the caller can use a storage.
|
||||
// CanUseStorage is called before any DOM initiated operation
|
||||
// on storage is about to happen and ensures that the storage's
|
||||
// on a storage is about to happen and ensures that the storage's
|
||||
// session-only flag is properly set according the current settings.
|
||||
// It is an optimization, since the privileges check and session-only
|
||||
// state determination are complex and share code (goes hand in hand).
|
||||
static bool CanUseStorage(nsIDOMWindow* aWindow, DOMStorage* aStorage = nullptr);
|
||||
// It is an optimization since the privileges check and session only
|
||||
// state determination are complex and share the code (comes hand in
|
||||
// hand together).
|
||||
static bool CanUseStorage(nsPIDOMWindow* aWindow, DOMStorage* aStorage = nullptr);
|
||||
|
||||
bool IsPrivate() const { return mIsPrivate; }
|
||||
bool IsSessionOnly() const { return mIsSessionOnly; }
|
||||
|
||||
@@ -778,8 +778,11 @@ DOMStorageCache::StartDatabase()
|
||||
|
||||
sDatabase = db.forget();
|
||||
} else {
|
||||
// Use DOMLocalStorageManager::Ensure in case we're called from
|
||||
// DOMSessionStorageManager's initializer and we haven't yet initialized the
|
||||
// local storage manager.
|
||||
RefPtr<DOMStorageDBChild> db = new DOMStorageDBChild(
|
||||
DOMLocalStorageManager::Self());
|
||||
DOMLocalStorageManager::Ensure());
|
||||
|
||||
nsresult rv = db->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
|
||||
@@ -598,6 +598,21 @@ DOMLocalStorageManager::~DOMLocalStorageManager()
|
||||
sSelf = nullptr;
|
||||
}
|
||||
|
||||
DOMLocalStorageManager*
|
||||
DOMLocalStorageManager::Ensure()
|
||||
{
|
||||
if (sSelf) {
|
||||
return sSelf;
|
||||
}
|
||||
|
||||
// Cause sSelf to be populated.
|
||||
nsCOMPtr<nsIDOMStorageManager> initializer =
|
||||
do_GetService("@mozilla.org/dom/localStorage-manager;1");
|
||||
MOZ_ASSERT(sSelf, "Didn't initialize?");
|
||||
|
||||
return sSelf;
|
||||
}
|
||||
|
||||
// DOMSessionStorageManager
|
||||
|
||||
DOMSessionStorageManager::DOMSessionStorageManager()
|
||||
|
||||
@@ -125,6 +125,9 @@ public:
|
||||
// Global getter of localStorage manager service
|
||||
static DOMLocalStorageManager* Self() { return sSelf; }
|
||||
|
||||
// Like Self, but creates an instance if we're not yet initialized.
|
||||
static DOMLocalStorageManager* Ensure();
|
||||
|
||||
private:
|
||||
static DOMLocalStorageManager* sSelf;
|
||||
};
|
||||
|
||||
@@ -31,3 +31,6 @@ LOCAL_INCLUDES += [
|
||||
|
||||
if CONFIG['ENABLE_TESTS']:
|
||||
DEFINES['DOM_STORAGE_TESTS'] = True
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wshadow']
|
||||
|
||||
@@ -260,6 +260,13 @@ DOMSVGLengthList::InsertItemBefore(DOMSVGLength& newItem,
|
||||
error.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
if (AnimListMirrorsBaseList()) {
|
||||
if (!mAList->mAnimVal->mItems.SetCapacity(
|
||||
mAList->mAnimVal->mItems.Length() + 1, fallible)) {
|
||||
error.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AutoChangeLengthListNotifier notifier(this);
|
||||
// Now that we know we're inserting, keep animVal list in sync as necessary.
|
||||
@@ -370,16 +377,15 @@ DOMSVGLengthList::MaybeInsertNullInAnimValListAt(uint32_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
|
||||
|
||||
DOMSVGLengthList* animVal = mAList->mAnimVal;
|
||||
|
||||
if (!animVal || mAList->IsAnimating()) {
|
||||
// No animVal list wrapper, or animVal not a clone of baseVal
|
||||
if (!AnimListMirrorsBaseList()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOMSVGLengthList* animVal = mAList->mAnimVal;
|
||||
|
||||
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
|
||||
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
|
||||
"animVal list not in sync!");
|
||||
|
||||
MOZ_ALWAYS_TRUE(animVal->mItems.InsertElementAt(aIndex, nullptr, fallible));
|
||||
|
||||
UpdateListIndicesFromIndex(animVal->mItems, aIndex + 1);
|
||||
@@ -390,15 +396,15 @@ DOMSVGLengthList::MaybeRemoveItemFromAnimValListAt(uint32_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
|
||||
|
||||
if (!AnimListMirrorsBaseList()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This needs to be a strong reference; otherwise, the RemovingFromList call
|
||||
// below might drop the last reference to animVal before we're done with it.
|
||||
RefPtr<DOMSVGLengthList> animVal = mAList->mAnimVal;
|
||||
|
||||
if (!animVal || mAList->IsAnimating()) {
|
||||
// No animVal list wrapper, or animVal not a clone of baseVal
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
|
||||
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
|
||||
"animVal list not in sync!");
|
||||
|
||||
|
||||
@@ -98,6 +98,12 @@ public:
|
||||
bool IsAnimating() const {
|
||||
return mAList->IsAnimating();
|
||||
}
|
||||
/**
|
||||
* Returns true if there is an animated list mirroring the base list.
|
||||
*/
|
||||
bool AnimListMirrorsBaseList() const {
|
||||
return mAList->mAnimVal && !mAList->IsAnimating();
|
||||
}
|
||||
|
||||
uint32_t NumberOfItems() const
|
||||
{
|
||||
|
||||
@@ -244,6 +244,13 @@ DOMSVGNumberList::InsertItemBefore(DOMSVGNumber& aItem,
|
||||
error.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
if (AnimListMirrorsBaseList()) {
|
||||
if (!mAList->mAnimVal->mItems.SetCapacity(
|
||||
mAList->mAnimVal->mItems.Length() + 1, fallible)) {
|
||||
error.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AutoChangeNumberListNotifier notifier(this);
|
||||
// Now that we know we're inserting, keep animVal list in sync as necessary.
|
||||
@@ -349,16 +356,15 @@ DOMSVGNumberList::MaybeInsertNullInAnimValListAt(uint32_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
|
||||
|
||||
DOMSVGNumberList* animVal = mAList->mAnimVal;
|
||||
|
||||
if (!animVal || mAList->IsAnimating()) {
|
||||
// No animVal list wrapper, or animVal not a clone of baseVal
|
||||
if (!AnimListMirrorsBaseList()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOMSVGNumberList* animVal = mAList->mAnimVal;
|
||||
|
||||
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
|
||||
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
|
||||
"animVal list not in sync!");
|
||||
|
||||
MOZ_ALWAYS_TRUE(animVal->mItems.InsertElementAt(aIndex, nullptr, fallible));
|
||||
|
||||
UpdateListIndicesFromIndex(animVal->mItems, aIndex + 1);
|
||||
@@ -369,15 +375,15 @@ DOMSVGNumberList::MaybeRemoveItemFromAnimValListAt(uint32_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
|
||||
|
||||
if (!AnimListMirrorsBaseList()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This needs to be a strong reference; otherwise, the RemovingFromList call
|
||||
// below might drop the last reference to animVal before we're done with it.
|
||||
RefPtr<DOMSVGNumberList> animVal = mAList->mAnimVal;
|
||||
|
||||
if (!animVal || mAList->IsAnimating()) {
|
||||
// No animVal list wrapper, or animVal not a clone of baseVal
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
|
||||
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
|
||||
"animVal list not in sync!");
|
||||
|
||||
|
||||
@@ -98,6 +98,12 @@ public:
|
||||
bool IsAnimating() const {
|
||||
return mAList->IsAnimating();
|
||||
}
|
||||
/**
|
||||
* Returns true if there is an animated list mirroring the base list.
|
||||
*/
|
||||
bool AnimListMirrorsBaseList() const {
|
||||
return mAList->mAnimVal && !mAList->IsAnimating();
|
||||
}
|
||||
|
||||
uint32_t NumberOfItems() const
|
||||
{
|
||||
|
||||
@@ -242,6 +242,13 @@ DOMSVGPathSegList::AttrIsAnimating() const
|
||||
return InternalAList().IsAnimating();
|
||||
}
|
||||
|
||||
bool
|
||||
DOMSVGPathSegList::AnimListMirrorsBaseList() const
|
||||
{
|
||||
return GetDOMWrapperIfExists(InternalAList().GetAnimValKey()) &&
|
||||
!AttrIsAnimating();
|
||||
}
|
||||
|
||||
SVGPathData&
|
||||
DOMSVGPathSegList::InternalList() const
|
||||
{
|
||||
@@ -375,6 +382,15 @@ DOMSVGPathSegList::InsertItemBefore(DOMSVGPathSeg& aNewItem,
|
||||
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
if (AnimListMirrorsBaseList()) {
|
||||
DOMSVGPathSegList *animVal =
|
||||
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
|
||||
if (!animVal->mItems.SetCapacity(
|
||||
animVal->mItems.Length() + 1, fallible)) {
|
||||
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AutoChangePathSegListNotifier notifier(this);
|
||||
// Now that we know we're inserting, keep animVal list in sync as necessary.
|
||||
@@ -526,22 +542,17 @@ DOMSVGPathSegList::
|
||||
{
|
||||
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
|
||||
|
||||
if (AttrIsAnimating()) {
|
||||
// animVal not a clone of baseVal
|
||||
if (!AnimListMirrorsBaseList()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The anim val list is in sync with the base val list
|
||||
DOMSVGPathSegList *animVal =
|
||||
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
|
||||
if (!animVal) {
|
||||
// No animVal list wrapper
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
|
||||
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
|
||||
"animVal list not in sync!");
|
||||
|
||||
MOZ_ALWAYS_TRUE(animVal->mItems.InsertElementAt(aIndex,
|
||||
ItemProxy(nullptr,
|
||||
aInternalIndex),
|
||||
@@ -557,8 +568,7 @@ DOMSVGPathSegList::
|
||||
{
|
||||
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
|
||||
|
||||
if (AttrIsAnimating()) {
|
||||
// animVal not a clone of baseVal
|
||||
if (!AnimListMirrorsBaseList()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -566,11 +576,8 @@ DOMSVGPathSegList::
|
||||
// below might drop the last reference to animVal before we're done with it.
|
||||
RefPtr<DOMSVGPathSegList> animVal =
|
||||
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
|
||||
if (!animVal) {
|
||||
// No animVal list wrapper
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
|
||||
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
|
||||
"animVal list not in sync!");
|
||||
|
||||
|
||||
@@ -128,6 +128,10 @@ public:
|
||||
* not simply a mirror of our baseVal).
|
||||
*/
|
||||
bool AttrIsAnimating() const;
|
||||
/**
|
||||
* Returns true if there is an animated list mirroring the base list.
|
||||
*/
|
||||
bool AnimListMirrorsBaseList() const;
|
||||
|
||||
uint32_t NumberOfItems() const
|
||||
{
|
||||
|
||||
@@ -185,6 +185,13 @@ DOMSVGPointList::AttrIsAnimating() const
|
||||
return InternalAList().IsAnimating();
|
||||
}
|
||||
|
||||
bool
|
||||
DOMSVGPointList::AnimListMirrorsBaseList() const
|
||||
{
|
||||
return GetDOMWrapperIfExists(InternalAList().GetAnimValKey()) &&
|
||||
!AttrIsAnimating();
|
||||
}
|
||||
|
||||
SVGPointList&
|
||||
DOMSVGPointList::InternalList() const
|
||||
{
|
||||
@@ -311,6 +318,15 @@ DOMSVGPointList::InsertItemBefore(nsISVGPoint& aNewItem, uint32_t aIndex,
|
||||
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
if (AnimListMirrorsBaseList()) {
|
||||
DOMSVGPointList *animVal =
|
||||
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
|
||||
if (!animVal->mItems.SetCapacity(
|
||||
animVal->mItems.Length() + 1, fallible)) {
|
||||
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AutoChangePointListNotifier notifier(this);
|
||||
// Now that we know we're inserting, keep animVal list in sync as necessary.
|
||||
@@ -417,22 +433,17 @@ DOMSVGPointList::MaybeInsertNullInAnimValListAt(uint32_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
|
||||
|
||||
if (AttrIsAnimating()) {
|
||||
// animVal not a clone of baseVal
|
||||
if (!AnimListMirrorsBaseList()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The anim val list is in sync with the base val list
|
||||
DOMSVGPointList *animVal =
|
||||
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
|
||||
if (!animVal) {
|
||||
// No animVal list wrapper
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
|
||||
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
|
||||
"animVal list not in sync!");
|
||||
|
||||
MOZ_ALWAYS_TRUE(animVal->mItems.InsertElementAt(aIndex, nullptr, fallible));
|
||||
|
||||
UpdateListIndicesFromIndex(animVal->mItems, aIndex + 1);
|
||||
@@ -443,8 +454,7 @@ DOMSVGPointList::MaybeRemoveItemFromAnimValListAt(uint32_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
|
||||
|
||||
if (AttrIsAnimating()) {
|
||||
// animVal not a clone of baseVal
|
||||
if (!AnimListMirrorsBaseList()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -452,11 +462,8 @@ DOMSVGPointList::MaybeRemoveItemFromAnimValListAt(uint32_t aIndex)
|
||||
// below might drop the last reference to animVal before we're done with it.
|
||||
RefPtr<DOMSVGPointList> animVal =
|
||||
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
|
||||
if (!animVal) {
|
||||
// No animVal list wrapper
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
|
||||
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
|
||||
"animVal list not in sync!");
|
||||
|
||||
|
||||
@@ -130,6 +130,10 @@ public:
|
||||
* not simply a mirror of our baseVal).
|
||||
*/
|
||||
bool AttrIsAnimating() const;
|
||||
/**
|
||||
* Returns true if there is an animated list mirroring the base list.
|
||||
*/
|
||||
bool AnimListMirrorsBaseList() const;
|
||||
|
||||
uint32_t NumberOfItems() const
|
||||
{
|
||||
|
||||
@@ -252,6 +252,13 @@ DOMSVGTransformList::InsertItemBefore(SVGTransform& newItem,
|
||||
error.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
if (AnimListMirrorsBaseList()) {
|
||||
if (!mAList->mAnimVal->mItems.SetCapacity(
|
||||
mAList->mAnimVal->mItems.Length() + 1, fallible)) {
|
||||
error.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AutoChangeTransformListNotifier notifier(this);
|
||||
// Now that we know we're inserting, keep animVal list in sync as necessary.
|
||||
@@ -396,16 +403,15 @@ DOMSVGTransformList::MaybeInsertNullInAnimValListAt(uint32_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
|
||||
|
||||
DOMSVGTransformList* animVal = mAList->mAnimVal;
|
||||
|
||||
if (!animVal || mAList->IsAnimating()) {
|
||||
// No animVal list wrapper, or animVal not a clone of baseVal
|
||||
if (!AnimListMirrorsBaseList()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOMSVGTransformList* animVal = mAList->mAnimVal;
|
||||
|
||||
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
|
||||
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
|
||||
"animVal list not in sync!");
|
||||
|
||||
MOZ_ALWAYS_TRUE(animVal->mItems.InsertElementAt(aIndex, nullptr, fallible));
|
||||
|
||||
UpdateListIndicesFromIndex(animVal->mItems, aIndex + 1);
|
||||
@@ -416,15 +422,15 @@ DOMSVGTransformList::MaybeRemoveItemFromAnimValListAt(uint32_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
|
||||
|
||||
if (!AnimListMirrorsBaseList()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This needs to be a strong reference; otherwise, the RemovingFromList call
|
||||
// below might drop the last reference to animVal before we're done with it.
|
||||
RefPtr<DOMSVGTransformList> animVal = mAList->mAnimVal;
|
||||
|
||||
if (!animVal || mAList->IsAnimating()) {
|
||||
// No animVal list wrapper, or animVal not a clone of baseVal
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
|
||||
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
|
||||
"animVal list not in sync!");
|
||||
|
||||
|
||||
@@ -91,6 +91,12 @@ public:
|
||||
bool IsAnimating() const {
|
||||
return mAList->IsAnimating();
|
||||
}
|
||||
/**
|
||||
* Returns true if there is an animated list mirroring the base list.
|
||||
*/
|
||||
bool AnimListMirrorsBaseList() const {
|
||||
return mAList->mAnimVal && !mAList->IsAnimating();
|
||||
}
|
||||
|
||||
uint32_t NumberOfItems() const
|
||||
{
|
||||
|
||||
@@ -83,26 +83,39 @@ SVGCircleElement::GetLengthInfo()
|
||||
// nsSVGPathGeometryElement methods
|
||||
|
||||
bool
|
||||
SVGCircleElement::GetGeometryBounds(
|
||||
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
|
||||
SVGCircleElement::GetGeometryBounds(Rect* aBounds,
|
||||
const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace)
|
||||
{
|
||||
float x, y, r;
|
||||
GetAnimatedLengthValues(&x, &y, &r, nullptr);
|
||||
|
||||
if (r <= 0.f) {
|
||||
// Rendering of the element is disabled
|
||||
*aBounds = Rect(aTransform * Point(x, y), Size());
|
||||
*aBounds = Rect(aToBoundsSpace * Point(x, y), Size());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aTransform.IsRectilinear()) {
|
||||
if (aToBoundsSpace.IsRectilinear()) {
|
||||
// Optimize the case where we can treat the circle as a rectangle and
|
||||
// still get tight bounds.
|
||||
if (aStrokeOptions.mLineWidth > 0.f) {
|
||||
if (aToNonScalingStrokeSpace) {
|
||||
if (aToNonScalingStrokeSpace->IsRectilinear()) {
|
||||
MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
|
||||
Rect userBounds(x - r, y - r, 2 * r, 2 * r);
|
||||
SVGContentUtils::RectilinearGetStrokeBounds(
|
||||
userBounds, aToBoundsSpace, *aToNonScalingStrokeSpace,
|
||||
aStrokeOptions.mLineWidth, aBounds);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
r += aStrokeOptions.mLineWidth / 2.f;
|
||||
}
|
||||
Rect rect(x - r, y - r, 2 * r, 2 * r);
|
||||
*aBounds = aTransform.TransformBounds(rect);
|
||||
*aBounds = aToBoundsSpace.TransformBounds(rect);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ public:
|
||||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aTransform) override;
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
|
||||
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
@@ -219,16 +219,21 @@ SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
|
||||
break;
|
||||
}
|
||||
|
||||
switch (styleSVG->mStrokeLinecap) {
|
||||
case NS_STYLE_STROKE_LINECAP_BUTT:
|
||||
if (ShapeTypeHasNoCorners(aElement)) {
|
||||
aStrokeOptions->mLineCap = CapStyle::BUTT;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINECAP_ROUND:
|
||||
aStrokeOptions->mLineCap = CapStyle::ROUND;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINECAP_SQUARE:
|
||||
aStrokeOptions->mLineCap = CapStyle::SQUARE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
switch (styleSVG->mStrokeLinecap) {
|
||||
case NS_STYLE_STROKE_LINECAP_BUTT:
|
||||
aStrokeOptions->mLineCap = CapStyle::BUTT;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINECAP_ROUND:
|
||||
aStrokeOptions->mLineCap = CapStyle::ROUND;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINECAP_SQUARE:
|
||||
aStrokeOptions->mLineCap = CapStyle::SQUARE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,6 +463,45 @@ SVGContentUtils::GetCTM(nsSVGElement *aElement, bool aScreenCTM)
|
||||
return GetCTMInternal(aElement, aScreenCTM, false);
|
||||
}
|
||||
|
||||
void
|
||||
SVGContentUtils::RectilinearGetStrokeBounds(const Rect& aRect,
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix& aToNonScalingStrokeSpace,
|
||||
float aStrokeWidth,
|
||||
Rect* aBounds)
|
||||
{
|
||||
MOZ_ASSERT(aToBoundsSpace.IsRectilinear(),
|
||||
"aToBoundsSpace must be rectilinear");
|
||||
MOZ_ASSERT(aToNonScalingStrokeSpace.IsRectilinear(),
|
||||
"aToNonScalingStrokeSpace must be rectilinear");
|
||||
|
||||
Matrix nonScalingToSource = aToNonScalingStrokeSpace.Inverse();
|
||||
Matrix nonScalingToBounds = nonScalingToSource * aToBoundsSpace;
|
||||
|
||||
*aBounds = aToBoundsSpace.TransformBounds(aRect);
|
||||
|
||||
// Compute the amounts dx and dy that nonScalingToBounds scales a half-width
|
||||
// stroke in the x and y directions, and then inflate aBounds by those amounts
|
||||
// so that when aBounds is transformed back to non-scaling-stroke space
|
||||
// it will map onto the correct stroked bounds.
|
||||
|
||||
Float dx = 0.0f;
|
||||
Float dy = 0.0f;
|
||||
// nonScalingToBounds is rectilinear, so either _12 and _21 are zero or _11
|
||||
// and _22 are zero, and in each case the non-zero entries (from among _11,
|
||||
// _12, _21, _22) simply scale the stroke width in the x and y directions.
|
||||
if (FuzzyEqual(nonScalingToBounds._12, 0) &&
|
||||
FuzzyEqual(nonScalingToBounds._21, 0)) {
|
||||
dx = (aStrokeWidth / 2.0f) * std::abs(nonScalingToBounds._11);
|
||||
dy = (aStrokeWidth / 2.0f) * std::abs(nonScalingToBounds._22);
|
||||
} else {
|
||||
dx = (aStrokeWidth / 2.0f) * std::abs(nonScalingToBounds._21);
|
||||
dy = (aStrokeWidth / 2.0f) * std::abs(nonScalingToBounds._12);
|
||||
}
|
||||
|
||||
aBounds->Inflate(dx, dy);
|
||||
}
|
||||
|
||||
double
|
||||
SVGContentUtils::ComputeNormalizedHypotenuse(double aWidth, double aHeight)
|
||||
{
|
||||
@@ -807,3 +851,9 @@ SVGContentUtils::GetPath(const nsAString& aPathString)
|
||||
|
||||
return pathData.BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 1);
|
||||
}
|
||||
|
||||
bool
|
||||
SVGContentUtils::ShapeTypeHasNoCorners(const nsIContent* aContent) {
|
||||
return aContent && aContent->IsAnyOfSVGElements(nsGkAtoms::circle,
|
||||
nsGkAtoms::ellipse);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ class Matrix;
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#define SVG_ZERO_LENGTH_PATH_FIX_FACTOR 512
|
||||
|
||||
inline bool
|
||||
IsSVGWhitespace(char aChar)
|
||||
{
|
||||
@@ -61,6 +63,8 @@ class SVGContentUtils
|
||||
{
|
||||
public:
|
||||
typedef mozilla::gfx::Float Float;
|
||||
typedef mozilla::gfx::Matrix Matrix;
|
||||
typedef mozilla::gfx::Rect Rect;
|
||||
typedef mozilla::gfx::StrokeOptions StrokeOptions;
|
||||
typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
|
||||
typedef mozilla::SVGPreserveAspectRatio SVGPreserveAspectRatio;
|
||||
@@ -178,7 +182,23 @@ public:
|
||||
const char16_t **aParams,
|
||||
uint32_t aParamsLength);
|
||||
|
||||
static mozilla::gfx::Matrix GetCTM(nsSVGElement *aElement, bool aScreenCTM);
|
||||
static Matrix GetCTM(nsSVGElement *aElement, bool aScreenCTM);
|
||||
|
||||
/**
|
||||
* Gets the tight bounds-space stroke bounds of the non-scaling-stroked rect
|
||||
* aRect.
|
||||
* @param aToBoundsSpace transforms from source space to the space aBounds
|
||||
* should be computed in. Must be rectilinear.
|
||||
* @param aToNonScalingStrokeSpace transforms from source
|
||||
* space to the space in which non-scaling stroke should be applied.
|
||||
* Must be rectilinear.
|
||||
*/
|
||||
static void
|
||||
RectilinearGetStrokeBounds(const Rect& aRect,
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix& aToNonScalingStrokeSpace,
|
||||
float aStrokeWidth,
|
||||
Rect* aBounds);
|
||||
|
||||
/**
|
||||
* Check if this is one of the SVG elements that SVG 1.1 Full says
|
||||
@@ -203,13 +223,13 @@ public:
|
||||
|
||||
/* Generate a viewbox to viewport tranformation matrix */
|
||||
|
||||
static mozilla::gfx::Matrix
|
||||
static Matrix
|
||||
GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
|
||||
float aViewboxX, float aViewboxY,
|
||||
float aViewboxWidth, float aViewboxHeight,
|
||||
const SVGAnimatedPreserveAspectRatio &aPreserveAspectRatio);
|
||||
|
||||
static mozilla::gfx::Matrix
|
||||
static Matrix
|
||||
GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
|
||||
float aViewboxX, float aViewboxY,
|
||||
float aViewboxWidth, float aViewboxHeight,
|
||||
@@ -323,6 +343,12 @@ public:
|
||||
*/
|
||||
static already_AddRefed<mozilla::gfx::Path>
|
||||
GetPath(const nsAString& aPathString);
|
||||
|
||||
/**
|
||||
* Returns true if aContent is one of the elements whose stroke is guaranteed
|
||||
* to have no corners: circle or ellipse
|
||||
*/
|
||||
static bool ShapeTypeHasNoCorners(const nsIContent* aContent);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -94,27 +94,40 @@ SVGEllipseElement::GetLengthInfo()
|
||||
// nsSVGPathGeometryElement methods
|
||||
|
||||
bool
|
||||
SVGEllipseElement::GetGeometryBounds(
|
||||
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
|
||||
SVGEllipseElement::GetGeometryBounds(Rect* aBounds,
|
||||
const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace)
|
||||
{
|
||||
float x, y, rx, ry;
|
||||
GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
|
||||
|
||||
if (rx <= 0.f || ry <= 0.f) {
|
||||
// Rendering of the element is disabled
|
||||
*aBounds = Rect(aTransform * Point(x, y), Size());
|
||||
*aBounds = Rect(aToBoundsSpace * Point(x, y), Size());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aTransform.IsRectilinear()) {
|
||||
if (aToBoundsSpace.IsRectilinear()) {
|
||||
// Optimize the case where we can treat the ellipse as a rectangle and
|
||||
// still get tight bounds.
|
||||
if (aStrokeOptions.mLineWidth > 0.f) {
|
||||
if (aToNonScalingStrokeSpace) {
|
||||
if (aToNonScalingStrokeSpace->IsRectilinear()) {
|
||||
MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
|
||||
Rect userBounds(x - rx, y - ry, 2 * rx, 2 * ry);
|
||||
SVGContentUtils::RectilinearGetStrokeBounds(
|
||||
userBounds, aToBoundsSpace, *aToNonScalingStrokeSpace,
|
||||
aStrokeOptions.mLineWidth, aBounds);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
rx += aStrokeOptions.mLineWidth / 2.f;
|
||||
ry += aStrokeOptions.mLineWidth / 2.f;
|
||||
}
|
||||
Rect rect(x - rx, y - ry, 2 * rx, 2 * ry);
|
||||
*aBounds = aTransform.TransformBounds(rect);
|
||||
*aBounds = aToBoundsSpace.TransformBounds(rect);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ public:
|
||||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aTransform) override;
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
|
||||
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
@@ -226,8 +226,10 @@ SVGImageElement::IsAttributeMapped(const nsIAtom* name) const
|
||||
/* For the purposes of the update/invalidation logic pretend to
|
||||
be a rectangle. */
|
||||
bool
|
||||
SVGImageElement::GetGeometryBounds(
|
||||
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
|
||||
SVGImageElement::GetGeometryBounds(Rect* aBounds,
|
||||
const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace)
|
||||
{
|
||||
Rect rect;
|
||||
GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width,
|
||||
@@ -238,7 +240,7 @@ SVGImageElement::GetGeometryBounds(
|
||||
rect.SetEmpty(); // Make sure width/height are zero and not negative
|
||||
}
|
||||
|
||||
*aBounds = aTransform.TransformBounds(rect);
|
||||
*aBounds = aToBoundsSpace.TransformBounds(rect);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@ public:
|
||||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aTransform) override;
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
|
||||
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
|
||||
|
||||
// nsSVGSVGElement methods:
|
||||
|
||||
@@ -37,6 +37,23 @@ SVGLineElement::SVGLineElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeIn
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SVGLineElement::MaybeAdjustForZeroLength(float aX1, float aY1,
|
||||
float& aX2, float aY2)
|
||||
{
|
||||
if (aX1 == aX2 && aY1 == aY2) {
|
||||
SVGContentUtils::AutoStrokeOptions strokeOptions;
|
||||
SVGContentUtils::GetStrokeOptions(&strokeOptions, this, nullptr, nullptr,
|
||||
SVGContentUtils::eIgnoreStrokeDashing);
|
||||
|
||||
if (strokeOptions.mLineCap != CapStyle::BUTT) {
|
||||
float tinyLength =
|
||||
strokeOptions.mLineWidth / SVG_ZERO_LENGTH_PATH_FIX_FACTOR;
|
||||
aX2 += tinyLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMNode methods
|
||||
|
||||
@@ -112,6 +129,8 @@ SVGLineElement::GetAsSimplePath(SimplePath* aSimplePath)
|
||||
{
|
||||
float x1, y1, x2, y2;
|
||||
GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
|
||||
|
||||
MaybeAdjustForZeroLength(x1, y1, x2, y2);
|
||||
aSimplePath->SetLine(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
@@ -121,6 +140,7 @@ SVGLineElement::BuildPath(PathBuilder* aBuilder)
|
||||
float x1, y1, x2, y2;
|
||||
GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
|
||||
|
||||
MaybeAdjustForZeroLength(x1, y1, x2, y2);
|
||||
aBuilder->MoveTo(Point(x1, y1));
|
||||
aBuilder->LineTo(Point(x2, y2));
|
||||
|
||||
@@ -128,33 +148,68 @@ SVGLineElement::BuildPath(PathBuilder* aBuilder)
|
||||
}
|
||||
|
||||
bool
|
||||
SVGLineElement::GetGeometryBounds(
|
||||
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
|
||||
SVGLineElement::GetGeometryBounds(Rect* aBounds,
|
||||
const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace)
|
||||
{
|
||||
float x1, y1, x2, y2;
|
||||
GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
|
||||
|
||||
if (aStrokeOptions.mLineWidth <= 0) {
|
||||
*aBounds = Rect(aTransform * Point(x1, y1), Size());
|
||||
aBounds->ExpandToEnclose(aTransform * Point(x2, y2));
|
||||
*aBounds = Rect(aToBoundsSpace * Point(x1, y1), Size());
|
||||
aBounds->ExpandToEnclose(aToBoundsSpace * Point(x2, y2));
|
||||
return true;
|
||||
}
|
||||
|
||||
// transform from non-scaling-stroke space to the space in which we compute
|
||||
// bounds
|
||||
Matrix nonScalingToBounds;
|
||||
if (aToNonScalingStrokeSpace) {
|
||||
MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
|
||||
Matrix nonScalingToUser = aToNonScalingStrokeSpace->Inverse();
|
||||
nonScalingToBounds = nonScalingToUser * aToBoundsSpace;
|
||||
}
|
||||
|
||||
if (aStrokeOptions.mLineCap == CapStyle::ROUND) {
|
||||
if (!aTransform.IsRectilinear()) {
|
||||
if (!aToBoundsSpace.IsRectilinear() ||
|
||||
(aToNonScalingStrokeSpace &&
|
||||
!aToNonScalingStrokeSpace->IsRectilinear())) {
|
||||
// TODO: handle this case.
|
||||
return false;
|
||||
}
|
||||
Rect bounds(Point(x1, y1), Size());
|
||||
bounds.ExpandToEnclose(Point(x2, y2));
|
||||
bounds.Inflate(aStrokeOptions.mLineWidth / 2.f);
|
||||
*aBounds = aTransform.TransformBounds(bounds);
|
||||
if (aToNonScalingStrokeSpace) {
|
||||
bounds = aToNonScalingStrokeSpace->TransformBounds(bounds);
|
||||
bounds.Inflate(aStrokeOptions.mLineWidth / 2.f);
|
||||
*aBounds = nonScalingToBounds.TransformBounds(bounds);
|
||||
} else {
|
||||
bounds.Inflate(aStrokeOptions.mLineWidth / 2.f);
|
||||
*aBounds = aToBoundsSpace.TransformBounds(bounds);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle butt and square linecap, normal and non-scaling stroke cases
|
||||
// together: start with endpoints (x1, y1), (x2, y2) in the stroke space,
|
||||
// compute the four corners of the stroked line, transform the corners to
|
||||
// bounds space, and compute bounds there.
|
||||
|
||||
if (aToNonScalingStrokeSpace) {
|
||||
Point nonScalingSpaceP1, nonScalingSpaceP2;
|
||||
nonScalingSpaceP1 = *aToNonScalingStrokeSpace * Point(x1, y1);
|
||||
nonScalingSpaceP2 = *aToNonScalingStrokeSpace * Point(x2, y2);
|
||||
x1 = nonScalingSpaceP1.x;
|
||||
y1 = nonScalingSpaceP1.y;
|
||||
x2 = nonScalingSpaceP2.x;
|
||||
y2 = nonScalingSpaceP2.y;
|
||||
}
|
||||
|
||||
Float length = Float(NS_hypot(x2 - x1, y2 - y1));
|
||||
Float xDelta;
|
||||
Float yDelta;
|
||||
Point points[4];
|
||||
|
||||
if (aStrokeOptions.mLineCap == CapStyle::BUTT) {
|
||||
if (length == 0.f) {
|
||||
@@ -164,27 +219,37 @@ SVGLineElement::GetGeometryBounds(
|
||||
xDelta = ratio * (y2 - y1);
|
||||
yDelta = ratio * (x2 - x1);
|
||||
}
|
||||
points[0] = Point(x1 - xDelta, y1 + yDelta);
|
||||
points[1] = Point(x1 + xDelta, y1 - yDelta);
|
||||
points[2] = Point(x2 + xDelta, y2 - yDelta);
|
||||
points[3] = Point(x2 - xDelta, y2 + yDelta);
|
||||
} else {
|
||||
MOZ_ASSERT(aStrokeOptions.mLineCap == CapStyle::SQUARE);
|
||||
if (length == 0.f) {
|
||||
xDelta = yDelta = aStrokeOptions.mLineWidth / 2.f;
|
||||
points[0] = Point(x1 - xDelta, y1 + yDelta);
|
||||
points[1] = Point(x1 - xDelta, y1 - yDelta);
|
||||
points[2] = Point(x1 + xDelta, y1 - yDelta);
|
||||
points[3] = Point(x1 + xDelta, y1 + yDelta);
|
||||
} else {
|
||||
Float ratio = aStrokeOptions.mLineWidth / 2.f / length;
|
||||
xDelta = yDelta = ratio * (fabs(y2 - y1) + fabs(x2 - x1));
|
||||
yDelta = ratio * (x2 - x1);
|
||||
xDelta = ratio * (y2 - y1);
|
||||
points[0] = Point(x1 - yDelta - xDelta, y1 - xDelta + yDelta);
|
||||
points[1] = Point(x1 - yDelta + xDelta, y1 - xDelta - yDelta);
|
||||
points[2] = Point(x2 + yDelta + xDelta, y2 + xDelta - yDelta);
|
||||
points[3] = Point(x2 + yDelta - xDelta, y2 + xDelta + yDelta);
|
||||
}
|
||||
}
|
||||
|
||||
Point points[4];
|
||||
const Matrix& toBoundsSpace = aToNonScalingStrokeSpace ?
|
||||
nonScalingToBounds : aToBoundsSpace;
|
||||
|
||||
points[0] = Point(x1 - xDelta, y1 - yDelta);
|
||||
points[1] = Point(x1 + xDelta, y1 + yDelta);
|
||||
points[2] = Point(x2 + xDelta, y2 + yDelta);
|
||||
points[3] = Point(x2 - xDelta, y2 - yDelta);
|
||||
|
||||
*aBounds = Rect(aTransform * points[0], Size());
|
||||
*aBounds = Rect(toBoundsSpace * points[0], Size());
|
||||
for (uint32_t i = 1; i < 4; ++i) {
|
||||
aBounds->ExpandToEnclose(aTransform * points[i]);
|
||||
aBounds->ExpandToEnclose(toBoundsSpace * points[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ protected:
|
||||
virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
friend nsresult (::NS_NewSVGLineElement(nsIContent **aResult,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
|
||||
// If the input line has length zero and linecaps aren't butt, adjust |aX2| by
|
||||
// a tiny amount to a barely-nonzero-length line that all of our draw targets
|
||||
// will render
|
||||
void MaybeAdjustForZeroLength(float aX1, float aY1, float& aX2, float aY2);
|
||||
|
||||
public:
|
||||
// nsIContent interface
|
||||
@@ -36,7 +40,8 @@ public:
|
||||
virtual void GetAsSimplePath(SimplePath* aSimplePath) override;
|
||||
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
|
||||
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aTransform) override;
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
|
||||
|
||||
@@ -255,7 +255,7 @@ ApproximateZeroLengthSubpathSquareCaps(PathBuilder* aPB,
|
||||
// line is rather arbitrary, other than being chosen to meet the requirements
|
||||
// described in the comment above.
|
||||
|
||||
Float tinyLength = aStrokeWidth / 512;
|
||||
Float tinyLength = aStrokeWidth / SVG_ZERO_LENGTH_PATH_FIX_FACTOR;
|
||||
|
||||
aPB->LineTo(aPoint + Point(tinyLength, 0));
|
||||
aPB->MoveTo(aPoint);
|
||||
|
||||
@@ -112,8 +112,10 @@ SVGRectElement::GetLengthInfo()
|
||||
// nsSVGPathGeometryElement methods
|
||||
|
||||
bool
|
||||
SVGRectElement::GetGeometryBounds(
|
||||
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
|
||||
SVGRectElement::GetGeometryBounds(Rect* aBounds,
|
||||
const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace)
|
||||
{
|
||||
Rect rect;
|
||||
Float rx, ry;
|
||||
@@ -124,11 +126,11 @@ SVGRectElement::GetGeometryBounds(
|
||||
// Rendering of the element disabled
|
||||
rect.SetEmpty(); // Make sure width/height are zero and not negative
|
||||
// We still want the x/y position from 'rect'
|
||||
*aBounds = aTransform.TransformBounds(rect);
|
||||
*aBounds = aToBoundsSpace.TransformBounds(rect);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!aTransform.IsRectilinear()) {
|
||||
if (!aToBoundsSpace.IsRectilinear()) {
|
||||
// We can't ignore the radii in this case if we want tight bounds
|
||||
rx = std::max(rx, 0.0f);
|
||||
ry = std::max(ry, 0.0f);
|
||||
@@ -139,10 +141,29 @@ SVGRectElement::GetGeometryBounds(
|
||||
}
|
||||
|
||||
if (aStrokeOptions.mLineWidth > 0.f) {
|
||||
if (aToNonScalingStrokeSpace) {
|
||||
if (aToNonScalingStrokeSpace->IsRectilinear()) {
|
||||
MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
|
||||
rect = aToNonScalingStrokeSpace->TransformBounds(rect);
|
||||
// Note that, in principle, an author could cause the corners of the
|
||||
// rect to be beveled by specifying stroke-linejoin or setting
|
||||
// stroke-miterlimit to be less than sqrt(2). In that very unlikely
|
||||
// event the bounds that we calculate here may be too big if
|
||||
// aToBoundsSpace is non-rectilinear. This is likely to be so rare it's
|
||||
// not worth handling though.
|
||||
rect.Inflate(aStrokeOptions.mLineWidth / 2.f);
|
||||
Matrix nonScalingToBounds =
|
||||
aToNonScalingStrokeSpace->Inverse() * aToBoundsSpace;
|
||||
*aBounds = nonScalingToBounds.TransformBounds(rect);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// The "beveled" comment above applies here too
|
||||
rect.Inflate(aStrokeOptions.mLineWidth / 2.f);
|
||||
}
|
||||
|
||||
*aBounds = aTransform.TransformBounds(rect);
|
||||
*aBounds = aToBoundsSpace.TransformBounds(rect);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ public:
|
||||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aTransform) override;
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
|
||||
virtual void GetAsSimplePath(SimplePath* aSimplePath) override;
|
||||
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder = nullptr) override;
|
||||
|
||||
|
||||
@@ -76,9 +76,21 @@ public:
|
||||
* GetStrokedBounds on it. It also helps us avoid rounding error for simple
|
||||
* shapes and simple transforms where the Moz2D Path backends can fail to
|
||||
* produce the clean integer bounds that content authors expect in some cases.
|
||||
*
|
||||
* If |aToNonScalingStrokeSpace| is non-null then |aBounds|, which is computed
|
||||
* in bounds space, has the property that it's the smallest (axis-aligned)
|
||||
* rectangular bound containing the image of this shape as stroked in
|
||||
* non-scaling-stroke space. (When all transforms involved are rectilinear
|
||||
* the bounds of the image of |aBounds| in non-scaling-stroke space will be
|
||||
* tight, but if there are non-rectilinear transforms involved then that may
|
||||
* be impossible and this method will return false).
|
||||
*
|
||||
* If |aToNonScalingStrokeSpace| is non-null then |*aToNonScalingStrokeSpace|
|
||||
* must be non-singular.
|
||||
*/
|
||||
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aTransform) {
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace = nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,8 +122,10 @@ nsSVGPolyElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGPolyElement::GetGeometryBounds(
|
||||
Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aTransform)
|
||||
nsSVGPolyElement::GetGeometryBounds(Rect* aBounds,
|
||||
const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace)
|
||||
{
|
||||
const SVGPointList &points = mPoints.GetAnimValue();
|
||||
|
||||
@@ -133,23 +135,23 @@ nsSVGPolyElement::GetGeometryBounds(
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aStrokeOptions.mLineWidth > 0) {
|
||||
// We don't handle stroke-miterlimit etc. yet
|
||||
if (aStrokeOptions.mLineWidth > 0 || aToNonScalingStrokeSpace) {
|
||||
// We don't handle non-scaling-stroke or stroke-miterlimit etc. yet
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aTransform.IsRectilinear()) {
|
||||
if (aToBoundsSpace.IsRectilinear()) {
|
||||
// We can avoid transforming each point and just transform the result.
|
||||
// Important for large point lists.
|
||||
Rect bounds(points[0], Size());
|
||||
for (uint32_t i = 1; i < points.Length(); ++i) {
|
||||
bounds.ExpandToEnclose(points[i]);
|
||||
}
|
||||
*aBounds = aTransform.TransformBounds(bounds);
|
||||
*aBounds = aToBoundsSpace.TransformBounds(bounds);
|
||||
} else {
|
||||
*aBounds = Rect(aTransform * points[0], Size());
|
||||
*aBounds = Rect(aToBoundsSpace * points[0], Size());
|
||||
for (uint32_t i = 1; i < points.Length(); ++i) {
|
||||
aBounds->ExpandToEnclose(aTransform * points[i]);
|
||||
aBounds->ExpandToEnclose(aToBoundsSpace * points[i]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -47,7 +47,8 @@ public:
|
||||
virtual bool IsMarkable() override { return true; }
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) override;
|
||||
virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aTransform) override;
|
||||
const Matrix& aToBoundsSpace,
|
||||
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
|
||||
|
||||
// WebIDL
|
||||
already_AddRefed<mozilla::DOMSVGPointList> Points();
|
||||
|
||||
@@ -39,5 +39,37 @@ text { font: 20px monospace; }
|
||||
<rect x="100" y="100" width="50" height="50" fill="pink"/>
|
||||
<text x="200" y="200"/>
|
||||
</g>
|
||||
<circle id="nonScalingStrokedCircle1" cx="0" cy="0" r="10"
|
||||
transform="translate(45 130) scale(3 -2)"
|
||||
fill="none" stroke="gray" stroke-width="10"
|
||||
vector-effect="non-scaling-stroke"/>
|
||||
<ellipse id="nonScalingStrokedEllipse1" cx="20" cy="-10" rx="5" ry="5"
|
||||
transform="matrix(0 3 -2 0 0 0)"
|
||||
fill="none" stroke="steelblue" stroke-width="10"
|
||||
vector-effect="non-scaling-stroke" />
|
||||
<line id="nonScalingStrokedLine1" x1="120" y1="5" x2="120" y2="10"
|
||||
transform="scale(2 3)"
|
||||
stroke-width="10" stroke-linecap="round" stroke="orange"
|
||||
vector-effect="non-scaling-stroke" />
|
||||
<line id="nonScalingStrokedLine2" x1="130" y1="5" x2="140" y2="5"
|
||||
transform="rotate(45 260 15) scale(2 3)"
|
||||
stroke-width="10" stroke-linecap="square" stroke="crimson"
|
||||
vector-effect="non-scaling-stroke" />
|
||||
<line id="nonScalingStrokedLine3" x1="140" y1="5" x2="150" y2="5"
|
||||
transform="rotate(45 280 15) scale(2 3)"
|
||||
stroke-width="10" stroke-linecap="butt" stroke="indigo"
|
||||
vector-effect="non-scaling-stroke" />
|
||||
|
||||
<marker id="marker1" markerWidth="100" markerHeight="100"
|
||||
refX="0" refY="50" markerUnits="userSpaceOnUse">
|
||||
<line x1="0" y1="50" x2="50" y2="100" stroke="aqua" stroke-width="20"
|
||||
transform="rotate(-45 0 50)" />
|
||||
</marker>
|
||||
<line id="shapeWithMarker1" x1="160" y1="130" x2="170" y2="130"
|
||||
stroke="black" stroke-width="3" marker-end="url(#marker1)"/>
|
||||
|
||||
<line id="rotatedLine1" x1="160" y1="150" x2="180" y2="170"
|
||||
stroke="darkmagenta" stroke-width="10"
|
||||
transform="rotate(-45 160 150)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 3.6 KiB |
@@ -159,13 +159,10 @@ function runTest()
|
||||
is(rect3aBounds.width, 108, "rect3a.getBoundingClientRect().width");
|
||||
is(rect3aBounds.height, 108, "rect3a.getBoundingClientRect().height");
|
||||
|
||||
// Our PathExtentsToMaxStrokeExtents implementation considers the stroke
|
||||
// width to be sqrt(2)*stroke-width in case the rect is rotated 45 degrees,
|
||||
// so unfortunately we get slightly large results currently. Bug 1092125.
|
||||
isWithAbsTolerance(rect3bBounds.left, 198, 1, "rect3b.getBoundingClientRect().left");
|
||||
isWithAbsTolerance(rect3bBounds.top, 198, 1, "rect3b.getBoundingClientRect().top");
|
||||
isWithAbsTolerance(rect3bBounds.width, 54, 2, "rect3b.getBoundingClientRect().width");
|
||||
isWithAbsTolerance(rect3bBounds.height, 54, 2, "rect3b.getBoundingClientRect().height");
|
||||
isWithAbsTolerance(rect3bBounds.left, 198, 0.1, "rect3b.getBoundingClientRect().left");
|
||||
isWithAbsTolerance(rect3bBounds.top, 198, 0.1, "rect3b.getBoundingClientRect().top");
|
||||
isWithAbsTolerance(rect3bBounds.width, 54, 0.1, "rect3b.getBoundingClientRect().width");
|
||||
isWithAbsTolerance(rect3bBounds.height, 54, 0.1, "rect3b.getBoundingClientRect().height");
|
||||
|
||||
rect = new Rect(350 - 108 * sin45, 150 - 108 * sin45, 108 * sin45 * 2, 108 * sin45 * 2);
|
||||
isWithAbsTolerance(rect4aBounds.left, rect.left, 0.1, "rect4a.getBoundingClientRect().left");
|
||||
@@ -203,6 +200,89 @@ function runTest()
|
||||
is(gBounds.width, 50, "g2.getBoundingClientRect().width");
|
||||
is(gBounds.height, 50, "g2.getBoundingClientRect().height");
|
||||
|
||||
var nonScalingStrokedCircle1Bounds =
|
||||
doc.getElementById("nonScalingStrokedCircle1").getBoundingClientRect();
|
||||
isWithAbsTolerance(nonScalingStrokedCircle1Bounds.left, 10, 0.15,
|
||||
"nonScalingStrokedCircle1.getBoundingClientRect().left");
|
||||
isWithAbsTolerance(nonScalingStrokedCircle1Bounds.top, 105, 0.15,
|
||||
"nonScalingStrokedCircle1.getBoundingClientRect().top");
|
||||
isWithAbsTolerance(nonScalingStrokedCircle1Bounds.width, 70, 0.15,
|
||||
"nonScalingStrokedCircle1.getBoundingClientRect().width");
|
||||
isWithAbsTolerance(nonScalingStrokedCircle1Bounds.height, 50, 0.15,
|
||||
"nonScalingStrokedCircle1.getBoundingClientRect().height");
|
||||
|
||||
var nonScalingStrokedEllipse1Bounds =
|
||||
doc.getElementById("nonScalingStrokedEllipse1").getBoundingClientRect();
|
||||
isWithAbsTolerance(nonScalingStrokedEllipse1Bounds.left, 5, 0.15,
|
||||
"nonScalingStrokedEllipse1.getBoundingClientRect().left");
|
||||
isWithAbsTolerance(nonScalingStrokedEllipse1Bounds.top, 40, 0.15,
|
||||
"nonScalingStrokedEllipse1.getBoundingClientRect().top");
|
||||
isWithAbsTolerance(nonScalingStrokedEllipse1Bounds.width, 30, 0.15,
|
||||
"nonScalingStrokedEllipse1.getBoundingClientRect().width");
|
||||
isWithAbsTolerance(nonScalingStrokedEllipse1Bounds.height, 40, 0.15,
|
||||
"nonScalingStrokedEllipse1.getBoundingClientRect().height");
|
||||
|
||||
var nonScalingStrokedLine1Bounds =
|
||||
doc.getElementById("nonScalingStrokedLine1").getBoundingClientRect();
|
||||
isWithAbsTolerance(nonScalingStrokedLine1Bounds.left, 235, 0.1,
|
||||
"nonScalingStrokedLine1.getBoundingClientRect().left");
|
||||
isWithAbsTolerance(nonScalingStrokedLine1Bounds.top, 10, 0.1,
|
||||
"nonScalingStrokedLine1.getBoundingClientRect().top");
|
||||
isWithAbsTolerance(nonScalingStrokedLine1Bounds.width, 10, 0.1,
|
||||
"nonScalingStrokedLine1.getBoundingClientRect().width");
|
||||
isWithAbsTolerance(nonScalingStrokedLine1Bounds.height, 25, 0.1,
|
||||
"nonScalingStrokedLine1.getBoundingClientRect().height");
|
||||
|
||||
var nonScalingStrokedLine2Bounds =
|
||||
doc.getElementById("nonScalingStrokedLine2").getBoundingClientRect();
|
||||
var capDelta = 5/Math.SQRT2 + 5/Math.SQRT2;
|
||||
rect = new Rect(260 - capDelta, 15 - capDelta, 20/Math.SQRT2 + 2 * capDelta,
|
||||
20/Math.SQRT2 + 2 * capDelta);
|
||||
isWithAbsTolerance(nonScalingStrokedLine2Bounds.left, rect.left, 0.1,
|
||||
"nonScalingStrokedLine2.getBoundingClientRect().left");
|
||||
isWithAbsTolerance(nonScalingStrokedLine2Bounds.top, rect.top, 0.1,
|
||||
"nonScalingStrokedLine2.getBoundingClientRect().top");
|
||||
isWithAbsTolerance(nonScalingStrokedLine2Bounds.width, rect.width, 0.15,
|
||||
"nonScalingStrokedLine2.getBoundingClientRect().width");
|
||||
isWithAbsTolerance(nonScalingStrokedLine2Bounds.height, rect.height, 0.15,
|
||||
"nonScalingStrokedLine2.getBoundingClientRect().height");
|
||||
|
||||
var nonScalingStrokedLine3Bounds =
|
||||
doc.getElementById("nonScalingStrokedLine3").getBoundingClientRect();
|
||||
var capDelta = 5/Math.SQRT2;
|
||||
rect = new Rect(280 - capDelta, 15 - capDelta, 20/Math.SQRT2 + 2 * capDelta,
|
||||
20/Math.SQRT2 + 2 * capDelta);
|
||||
isWithAbsTolerance(nonScalingStrokedLine3Bounds.left, rect.left, 0.1,
|
||||
"nonScalingStrokedLine3.getBoundingClientRect().left");
|
||||
isWithAbsTolerance(nonScalingStrokedLine3Bounds.top, rect.top, 0.1,
|
||||
"nonScalingStrokedLine3.getBoundingClientRect().top");
|
||||
isWithAbsTolerance(nonScalingStrokedLine3Bounds.width, rect.width, 0.1,
|
||||
"nonScalingStrokedLine3.getBoundingClientRect().width");
|
||||
isWithAbsTolerance(nonScalingStrokedLine3Bounds.height, rect.height, 0.1,
|
||||
"nonScalingStrokedLine3.getBoundingClientRect().height");
|
||||
|
||||
var shapeWithMarker1Bounds =
|
||||
doc.getElementById("shapeWithMarker1").getBoundingClientRect();
|
||||
isWithAbsTolerance(shapeWithMarker1Bounds.left, 160, 0.1,
|
||||
"shapeWithMarker1Bounds.left");
|
||||
isWithAbsTolerance(shapeWithMarker1Bounds.top, 120, 0.1,
|
||||
"shapeWithMarker1Bounds.top");
|
||||
isWithAbsTolerance(shapeWithMarker1Bounds.width, 10 + Math.SQRT2 * 50, 0.1,
|
||||
"shapeWithMarker1Bounds.width");
|
||||
isWithAbsTolerance(shapeWithMarker1Bounds.height, 20, 0.1,
|
||||
"shapeWithMarker1Bounds.height");
|
||||
|
||||
var rotatedLine1Bounds =
|
||||
doc.getElementById("rotatedLine1").getBoundingClientRect();
|
||||
isWithAbsTolerance(rotatedLine1Bounds.left, 160, 0.1,
|
||||
"rotatedLine1Bounds.left");
|
||||
isWithAbsTolerance(rotatedLine1Bounds.top, 145, 0.1,
|
||||
"rotatedLine1Bounds.top");
|
||||
isWithAbsTolerance(rotatedLine1Bounds.width, Math.SQRT2 * 20, 0.1,
|
||||
"rotatedLine1Bounds.width");
|
||||
isWithAbsTolerance(rotatedLine1Bounds.height, 10, 0.1,
|
||||
"rotatedLine1Bounds.height");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ function finishTest()
|
||||
{
|
||||
try {
|
||||
localStorage.clear();
|
||||
} catch(e) {}
|
||||
} catch (e) {}
|
||||
postMsg("done");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -27,21 +27,6 @@ function test1() {
|
||||
is(ex.name, "SecurityError");
|
||||
}
|
||||
|
||||
// Set cookies behavior to "ask every time".
|
||||
SpecialPowers.pushPrefEnv({"set": [["network.cookie.lifetimePolicy", 1]],
|
||||
"clear": [["network.cookie.cookieBehavior"]]},
|
||||
test2);
|
||||
}
|
||||
|
||||
function test2() {
|
||||
try {
|
||||
localStorage.setItem("contentkey", "test-value");
|
||||
ok(false, "Setting localStorageItem should throw a security exception");
|
||||
}
|
||||
catch(ex) {
|
||||
is(ex.name, "SecurityError");
|
||||
}
|
||||
|
||||
// Set cookies behavior to "reject 3rd party"
|
||||
SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 1]],
|
||||
"clear": [["network.cookie.lifetimePolicy"]]},
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
typedef unsigned long long NodeId;
|
||||
|
||||
/**
|
||||
* In a directed graph with a root node `R`, a node `A` is said to "dominate" a
|
||||
* node `B` iff every path from `R` to `B` contains `A`. A node `A` is said to
|
||||
@@ -37,5 +39,10 @@
|
||||
*/
|
||||
[ChromeOnly, Exposed=(Window,System,Worker)]
|
||||
interface DominatorTree {
|
||||
|
||||
/**
|
||||
* The `NodeId` for the root of the dominator tree. This is a "meta-root" in
|
||||
* that it has an edge to each GC root in the heap snapshot this dominator
|
||||
* tree was created from.
|
||||
*/
|
||||
readonly attribute NodeId root;
|
||||
};
|
||||
|
||||
@@ -43,6 +43,18 @@ interface ThreadSafeChromeUtils {
|
||||
*/
|
||||
[Throws, NewObject]
|
||||
static any nondeterministicGetWeakMapKeys(any map);
|
||||
|
||||
/**
|
||||
* Return the keys in a weak set. This operation is
|
||||
* non-deterministic because it is affected by the scheduling of the
|
||||
* garbage collector and the cycle collector.
|
||||
*
|
||||
* @param aSet weak set or other JavaScript value
|
||||
* @returns If aSet is a weak set object, return the keys of the weak
|
||||
* set as an array. Otherwise, return undefined.
|
||||
*/
|
||||
[Throws, NewObject]
|
||||
static any nondeterministicGetWeakSetKeys(any aSet);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -115,10 +115,7 @@ AsyncLog(nsIInterceptedChannel *aInterceptedChannel,
|
||||
const nsACString& aMessageName, const nsTArray<nsString>& aParams)
|
||||
{
|
||||
MOZ_ASSERT(aInterceptedChannel);
|
||||
// Since the intercepted channel is kept alive and paused while handling
|
||||
// the FetchEvent, we are guaranteed the reporter is stable on the worker
|
||||
// thread.
|
||||
nsIConsoleReportCollector* reporter =
|
||||
nsCOMPtr<nsIConsoleReportCollector> reporter =
|
||||
aInterceptedChannel->GetConsoleReportCollector();
|
||||
if (reporter) {
|
||||
reporter->AddConsoleReport(nsIScriptError::errorFlag,
|
||||
@@ -398,8 +395,8 @@ ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||
else if(NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException))) {
|
||||
|
||||
nsAutoString filename;
|
||||
if (NS_SUCCEEDED(domException->GetFilename(filename)) &&
|
||||
!filename.IsEmpty()) {
|
||||
domException->GetFilename(filename);
|
||||
if (!filename.IsEmpty()) {
|
||||
CopyUTF16toUTF8(filename, aSourceSpecOut);
|
||||
*aLineOut = domException->LineNumber();
|
||||
*aColumnOut = domException->ColumnNumber();
|
||||
@@ -421,6 +418,8 @@ ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||
nsAutoJSString jsString;
|
||||
if (jsString.init(aCx, aValue)) {
|
||||
aMessageOut = jsString;
|
||||
} else {
|
||||
JS_ClearPendingException(aCx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -618,7 +617,7 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(!stsThread)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
// values for mCookiesLifetimePolicy
|
||||
// 0 == accept normally
|
||||
// 1 == ask before accepting -- obsolete, treated as ACCEPT_NORMALLY
|
||||
// 1 == ask before accepting, no more supported, treated like ACCEPT_NORMALLY (Bug 606655).
|
||||
// 2 == downgrade to session
|
||||
// 3 == limit lifetime to N days
|
||||
static const uint32_t ACCEPT_NORMALLY = 0;
|
||||
|
||||
@@ -2533,7 +2533,6 @@ protected:
|
||||
|
||||
virtual void DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent) override;
|
||||
|
||||
Layer* mTempReferent;
|
||||
// 0 is a special value that means "no ID".
|
||||
uint64_t mId;
|
||||
};
|
||||
|
||||
@@ -546,6 +546,13 @@ class JS_EXPORT_API(DominatorTree)
|
||||
mozilla::Move(*maybeDominatedSets)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root node for this dominator tree.
|
||||
*/
|
||||
const Node& root() const {
|
||||
return postOrder[postOrder.length() - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the immediate dominator of the given `node`. If `node` was not
|
||||
* reachable from the `root` that this dominator tree was constructed from,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -32,6 +33,7 @@ using namespace js::frontend;
|
||||
using JS::AutoValueArray;
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::DebugOnly;
|
||||
using mozilla::Forward;
|
||||
|
||||
enum class ParseTarget
|
||||
{
|
||||
@@ -220,6 +222,13 @@ GetPropertyDefault(JSContext* cx, HandleObject obj, HandleId id, HandleValue def
|
||||
return GetProperty(cx, obj, obj, id, result);
|
||||
}
|
||||
|
||||
enum class GeneratorStyle
|
||||
{
|
||||
None,
|
||||
Legacy,
|
||||
ES6
|
||||
};
|
||||
|
||||
/*
|
||||
* Builder class that constructs JavaScript AST node objects. See:
|
||||
*
|
||||
@@ -296,123 +305,43 @@ class NodeBuilder
|
||||
}
|
||||
|
||||
private:
|
||||
bool callback(HandleValue fun, TokenPos* pos, MutableHandleValue dst) {
|
||||
template <size_t N>
|
||||
bool callbackHelper(HandleValue fun, AutoValueArray<N>& args, size_t i,
|
||||
TokenPos* pos, MutableHandleValue dst)
|
||||
{
|
||||
// The end of the implementation of callback(). All arguments except
|
||||
// loc have already been stored in range [0, i) or args.
|
||||
MOZ_ASSERT(i == N - 1);
|
||||
if (saveLoc) {
|
||||
RootedValue loc(cx);
|
||||
if (!newNodeLoc(pos, &loc))
|
||||
return false;
|
||||
AutoValueArray<1> argv(cx);
|
||||
argv[0].set(loc);
|
||||
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
|
||||
args[i++].set(loc);
|
||||
}
|
||||
|
||||
AutoValueArray<1> argv(cx);
|
||||
argv[0].setNull(); /* no zero-length arrays allowed! */
|
||||
return Invoke(cx, userv, fun, 0, argv.begin(), dst);
|
||||
return Invoke(cx, userv, fun, N, args.begin(), dst);
|
||||
}
|
||||
|
||||
bool callback(HandleValue fun, HandleValue v1, TokenPos* pos, MutableHandleValue dst) {
|
||||
if (saveLoc) {
|
||||
RootedValue loc(cx);
|
||||
if (!newNodeLoc(pos, &loc))
|
||||
return false;
|
||||
AutoValueArray<2> argv(cx);
|
||||
argv[0].set(v1);
|
||||
argv[1].set(loc);
|
||||
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
|
||||
}
|
||||
|
||||
AutoValueArray<1> argv(cx);
|
||||
argv[0].set(v1);
|
||||
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
|
||||
// Helper function for callback(). Note that all Arguments must be types
|
||||
// that convert to HandleValue, so this is not really as template-y as it
|
||||
// seems, just variadic.
|
||||
template <size_t N, typename... Arguments>
|
||||
bool callbackHelper(HandleValue fun, AutoValueArray<N>& args, size_t i,
|
||||
HandleValue head, Arguments&&... tail)
|
||||
{
|
||||
// Recursive loop to store the arguments in the array. This eventually
|
||||
// bottoms out in a call to the non-template callbackHelper() above.
|
||||
args[i].set(head);
|
||||
return callbackHelper(fun, args, i + 1, Forward<Arguments>(tail)...);
|
||||
}
|
||||
|
||||
bool callback(HandleValue fun, HandleValue v1, HandleValue v2, TokenPos* pos,
|
||||
MutableHandleValue dst) {
|
||||
if (saveLoc) {
|
||||
RootedValue loc(cx);
|
||||
if (!newNodeLoc(pos, &loc))
|
||||
return false;
|
||||
AutoValueArray<3> argv(cx);
|
||||
argv[0].set(v1);
|
||||
argv[1].set(v2);
|
||||
argv[2].set(loc);
|
||||
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
|
||||
}
|
||||
|
||||
AutoValueArray<2> argv(cx);
|
||||
argv[0].set(v1);
|
||||
argv[1].set(v2);
|
||||
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
|
||||
}
|
||||
|
||||
bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, TokenPos* pos,
|
||||
MutableHandleValue dst) {
|
||||
if (saveLoc) {
|
||||
RootedValue loc(cx);
|
||||
if (!newNodeLoc(pos, &loc))
|
||||
return false;
|
||||
AutoValueArray<4> argv(cx);
|
||||
argv[0].set(v1);
|
||||
argv[1].set(v2);
|
||||
argv[2].set(v3);
|
||||
argv[3].set(loc);
|
||||
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
|
||||
}
|
||||
|
||||
AutoValueArray<3> argv(cx);
|
||||
argv[0].set(v1);
|
||||
argv[1].set(v2);
|
||||
argv[2].set(v3);
|
||||
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
|
||||
}
|
||||
|
||||
bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, HandleValue v4,
|
||||
TokenPos* pos, MutableHandleValue dst) {
|
||||
if (saveLoc) {
|
||||
RootedValue loc(cx);
|
||||
if (!newNodeLoc(pos, &loc))
|
||||
return false;
|
||||
AutoValueArray<5> argv(cx);
|
||||
argv[0].set(v1);
|
||||
argv[1].set(v2);
|
||||
argv[2].set(v3);
|
||||
argv[3].set(v4);
|
||||
argv[4].set(loc);
|
||||
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
|
||||
}
|
||||
|
||||
AutoValueArray<4> argv(cx);
|
||||
argv[0].set(v1);
|
||||
argv[1].set(v2);
|
||||
argv[2].set(v3);
|
||||
argv[3].set(v4);
|
||||
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
|
||||
}
|
||||
|
||||
bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, HandleValue v4,
|
||||
HandleValue v5, TokenPos* pos, MutableHandleValue dst) {
|
||||
if (saveLoc) {
|
||||
RootedValue loc(cx);
|
||||
if (!newNodeLoc(pos, &loc))
|
||||
return false;
|
||||
AutoValueArray<6> argv(cx);
|
||||
argv[0].set(v1);
|
||||
argv[1].set(v2);
|
||||
argv[2].set(v3);
|
||||
argv[3].set(v4);
|
||||
argv[4].set(v5);
|
||||
argv[5].set(loc);
|
||||
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
|
||||
}
|
||||
|
||||
AutoValueArray<5> argv(cx);
|
||||
argv[0].set(v1);
|
||||
argv[1].set(v2);
|
||||
argv[2].set(v3);
|
||||
argv[3].set(v4);
|
||||
argv[4].set(v5);
|
||||
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
|
||||
// Invoke a user-defined callback. The actual signature is:
|
||||
//
|
||||
// bool callback(HandleValue fun, HandleValue... args, TokenPos* pos,
|
||||
// MutableHandleValue dst);
|
||||
template <typename... Arguments>
|
||||
bool callback(HandleValue fun, Arguments&&... args) {
|
||||
AutoValueArray<sizeof...(args) - 1> argv(cx);
|
||||
return callbackHelper(fun, argv, 0, Forward<Arguments>(args)...);
|
||||
}
|
||||
|
||||
// WARNING: Returning a Handle is non-standard, but it works in this case
|
||||
@@ -447,117 +376,39 @@ class NodeBuilder
|
||||
|
||||
bool newArray(NodeVector& elts, MutableHandleValue dst);
|
||||
|
||||
bool newNode(ASTType type, TokenPos* pos, MutableHandleObject dst);
|
||||
bool createNode(ASTType type, TokenPos* pos, MutableHandleObject dst);
|
||||
|
||||
bool newNode(ASTType type, TokenPos* pos, MutableHandleValue dst) {
|
||||
RootedObject node(cx);
|
||||
return newNode(type, pos, &node) &&
|
||||
setResult(node, dst);
|
||||
bool newNodeHelper(HandleObject obj, MutableHandleValue dst) {
|
||||
// The end of the implementation of newNode().
|
||||
MOZ_ASSERT(obj);
|
||||
dst.setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newNode(ASTType type, TokenPos* pos,
|
||||
const char* childName, HandleValue child,
|
||||
MutableHandleValue dst) {
|
||||
RootedObject node(cx);
|
||||
return newNode(type, pos, &node) &&
|
||||
setProperty(node, childName, child) &&
|
||||
setResult(node, dst);
|
||||
template <typename... Arguments>
|
||||
bool newNodeHelper(HandleObject obj, const char *name, HandleValue value,
|
||||
Arguments&&... rest)
|
||||
{
|
||||
// Recursive loop to define properties. Note that the newNodeHelper()
|
||||
// call below passes two fewer arguments than we received, as we omit
|
||||
// `name` and `value`. This eventually bottoms out in a call to the
|
||||
// non-template newNodeHelper() above.
|
||||
return defineProperty(obj, name, value)
|
||||
&& newNodeHelper(obj, Forward<Arguments>(rest)...);
|
||||
}
|
||||
|
||||
bool newNode(ASTType type, TokenPos* pos,
|
||||
const char* childName1, HandleValue child1,
|
||||
const char* childName2, HandleValue child2,
|
||||
MutableHandleValue dst) {
|
||||
// Create a node object with "type" and "loc" properties, as well as zero
|
||||
// or more properties passed in as arguments. The signature is really more
|
||||
// like:
|
||||
//
|
||||
// bool newNode(ASTType type, TokenPos* pos,
|
||||
// {const char *name0, HandleValue value0,}...
|
||||
// MutableHandleValue dst);
|
||||
template <typename... Arguments>
|
||||
bool newNode(ASTType type, TokenPos* pos, Arguments&&... args) {
|
||||
RootedObject node(cx);
|
||||
return newNode(type, pos, &node) &&
|
||||
setProperty(node, childName1, child1) &&
|
||||
setProperty(node, childName2, child2) &&
|
||||
setResult(node, dst);
|
||||
}
|
||||
|
||||
bool newNode(ASTType type, TokenPos* pos,
|
||||
const char* childName1, HandleValue child1,
|
||||
const char* childName2, HandleValue child2,
|
||||
const char* childName3, HandleValue child3,
|
||||
MutableHandleValue dst) {
|
||||
RootedObject node(cx);
|
||||
return newNode(type, pos, &node) &&
|
||||
setProperty(node, childName1, child1) &&
|
||||
setProperty(node, childName2, child2) &&
|
||||
setProperty(node, childName3, child3) &&
|
||||
setResult(node, dst);
|
||||
}
|
||||
|
||||
bool newNode(ASTType type, TokenPos* pos,
|
||||
const char* childName1, HandleValue child1,
|
||||
const char* childName2, HandleValue child2,
|
||||
const char* childName3, HandleValue child3,
|
||||
const char* childName4, HandleValue child4,
|
||||
MutableHandleValue dst) {
|
||||
RootedObject node(cx);
|
||||
return newNode(type, pos, &node) &&
|
||||
setProperty(node, childName1, child1) &&
|
||||
setProperty(node, childName2, child2) &&
|
||||
setProperty(node, childName3, child3) &&
|
||||
setProperty(node, childName4, child4) &&
|
||||
setResult(node, dst);
|
||||
}
|
||||
|
||||
bool newNode(ASTType type, TokenPos* pos,
|
||||
const char* childName1, HandleValue child1,
|
||||
const char* childName2, HandleValue child2,
|
||||
const char* childName3, HandleValue child3,
|
||||
const char* childName4, HandleValue child4,
|
||||
const char* childName5, HandleValue child5,
|
||||
MutableHandleValue dst) {
|
||||
RootedObject node(cx);
|
||||
return newNode(type, pos, &node) &&
|
||||
setProperty(node, childName1, child1) &&
|
||||
setProperty(node, childName2, child2) &&
|
||||
setProperty(node, childName3, child3) &&
|
||||
setProperty(node, childName4, child4) &&
|
||||
setProperty(node, childName5, child5) &&
|
||||
setResult(node, dst);
|
||||
}
|
||||
|
||||
bool newNode(ASTType type, TokenPos* pos,
|
||||
const char* childName1, HandleValue child1,
|
||||
const char* childName2, HandleValue child2,
|
||||
const char* childName3, HandleValue child3,
|
||||
const char* childName4, HandleValue child4,
|
||||
const char* childName5, HandleValue child5,
|
||||
const char* childName6, HandleValue child6,
|
||||
MutableHandleValue dst) {
|
||||
RootedObject node(cx);
|
||||
return newNode(type, pos, &node) &&
|
||||
setProperty(node, childName1, child1) &&
|
||||
setProperty(node, childName2, child2) &&
|
||||
setProperty(node, childName3, child3) &&
|
||||
setProperty(node, childName4, child4) &&
|
||||
setProperty(node, childName5, child5) &&
|
||||
setProperty(node, childName6, child6) &&
|
||||
setResult(node, dst);
|
||||
}
|
||||
|
||||
bool newNode(ASTType type, TokenPos* pos,
|
||||
const char* childName1, HandleValue child1,
|
||||
const char* childName2, HandleValue child2,
|
||||
const char* childName3, HandleValue child3,
|
||||
const char* childName4, HandleValue child4,
|
||||
const char* childName5, HandleValue child5,
|
||||
const char* childName6, HandleValue child6,
|
||||
const char* childName7, HandleValue child7,
|
||||
MutableHandleValue dst) {
|
||||
RootedObject node(cx);
|
||||
return newNode(type, pos, &node) &&
|
||||
setProperty(node, childName1, child1) &&
|
||||
setProperty(node, childName2, child2) &&
|
||||
setProperty(node, childName3, child3) &&
|
||||
setProperty(node, childName4, child4) &&
|
||||
setProperty(node, childName5, child5) &&
|
||||
setProperty(node, childName6, child6) &&
|
||||
setProperty(node, childName7, child7) &&
|
||||
setResult(node, dst);
|
||||
return createNode(type, pos, &node) &&
|
||||
newNodeHelper(node, Forward<Arguments>(args)...);
|
||||
}
|
||||
|
||||
bool listNode(ASTType type, const char* propName, NodeVector& elts, TokenPos* pos,
|
||||
@@ -573,7 +424,7 @@ class NodeBuilder
|
||||
return newNode(type, pos, propName, array, dst);
|
||||
}
|
||||
|
||||
bool setProperty(HandleObject obj, const char* name, HandleValue val) {
|
||||
bool defineProperty(HandleObject obj, const char* name, HandleValue val) {
|
||||
MOZ_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
|
||||
|
||||
/*
|
||||
@@ -592,12 +443,6 @@ class NodeBuilder
|
||||
|
||||
bool setNodeLoc(HandleObject node, TokenPos* pos);
|
||||
|
||||
bool setResult(HandleObject obj, MutableHandleValue dst) {
|
||||
MOZ_ASSERT(obj);
|
||||
dst.setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
/*
|
||||
* All of the public builder methods take as their last two
|
||||
@@ -620,8 +465,8 @@ class NodeBuilder
|
||||
|
||||
bool function(ASTType type, TokenPos* pos,
|
||||
HandleValue id, NodeVector& args, NodeVector& defaults,
|
||||
HandleValue body, HandleValue rest, bool isGenerator, bool isExpression,
|
||||
MutableHandleValue dst);
|
||||
HandleValue body, HandleValue rest, GeneratorStyle generatorStyle,
|
||||
bool isExpression, MutableHandleValue dst);
|
||||
|
||||
bool variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos,
|
||||
MutableHandleValue dst);
|
||||
@@ -788,7 +633,7 @@ class NodeBuilder
|
||||
} /* anonymous namespace */
|
||||
|
||||
bool
|
||||
NodeBuilder::newNode(ASTType type, TokenPos* pos, MutableHandleObject dst)
|
||||
NodeBuilder::createNode(ASTType type, TokenPos* pos, MutableHandleObject dst)
|
||||
{
|
||||
MOZ_ASSERT(type > AST_ERROR && type < AST_LIMIT);
|
||||
|
||||
@@ -797,7 +642,7 @@ NodeBuilder::newNode(ASTType type, TokenPos* pos, MutableHandleObject dst)
|
||||
if (!node ||
|
||||
!setNodeLoc(node, pos) ||
|
||||
!atomValue(nodeTypeNames[type], &tv) ||
|
||||
!setProperty(node, "type", tv)) {
|
||||
!defineProperty(node, "type", tv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -859,28 +704,28 @@ NodeBuilder::newNodeLoc(TokenPos* pos, MutableHandleValue dst)
|
||||
if (!newObject(&to))
|
||||
return false;
|
||||
val.setObject(*to);
|
||||
if (!setProperty(loc, "start", val))
|
||||
if (!defineProperty(loc, "start", val))
|
||||
return false;
|
||||
val.setNumber(startLineNum);
|
||||
if (!setProperty(to, "line", val))
|
||||
if (!defineProperty(to, "line", val))
|
||||
return false;
|
||||
val.setNumber(startColumnIndex);
|
||||
if (!setProperty(to, "column", val))
|
||||
if (!defineProperty(to, "column", val))
|
||||
return false;
|
||||
|
||||
if (!newObject(&to))
|
||||
return false;
|
||||
val.setObject(*to);
|
||||
if (!setProperty(loc, "end", val))
|
||||
if (!defineProperty(loc, "end", val))
|
||||
return false;
|
||||
val.setNumber(endLineNum);
|
||||
if (!setProperty(to, "line", val))
|
||||
if (!defineProperty(to, "line", val))
|
||||
return false;
|
||||
val.setNumber(endColumnIndex);
|
||||
if (!setProperty(to, "column", val))
|
||||
if (!defineProperty(to, "column", val))
|
||||
return false;
|
||||
|
||||
if (!setProperty(loc, "source", srcval))
|
||||
if (!defineProperty(loc, "source", srcval))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -891,13 +736,13 @@ NodeBuilder::setNodeLoc(HandleObject node, TokenPos* pos)
|
||||
{
|
||||
if (!saveLoc) {
|
||||
RootedValue nullVal(cx, NullValue());
|
||||
setProperty(node, "loc", nullVal);
|
||||
defineProperty(node, "loc", nullVal);
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedValue loc(cx);
|
||||
return newNodeLoc(pos, &loc) &&
|
||||
setProperty(node, "loc", loc);
|
||||
defineProperty(node, "loc", loc);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -1757,7 +1602,7 @@ bool
|
||||
NodeBuilder::function(ASTType type, TokenPos* pos,
|
||||
HandleValue id, NodeVector& args, NodeVector& defaults,
|
||||
HandleValue body, HandleValue rest,
|
||||
bool isGenerator, bool isExpression,
|
||||
GeneratorStyle generatorStyle, bool isExpression,
|
||||
MutableHandleValue dst)
|
||||
{
|
||||
RootedValue array(cx), defarray(cx);
|
||||
@@ -1766,6 +1611,7 @@ NodeBuilder::function(ASTType type, TokenPos* pos,
|
||||
if (!newArray(defaults, &defarray))
|
||||
return false;
|
||||
|
||||
bool isGenerator = generatorStyle != GeneratorStyle::None;
|
||||
RootedValue isGeneratorVal(cx, BooleanValue(isGenerator));
|
||||
RootedValue isExpressionVal(cx, BooleanValue(isExpression));
|
||||
|
||||
@@ -1774,6 +1620,27 @@ NodeBuilder::function(ASTType type, TokenPos* pos,
|
||||
return callback(cb, opt(id), array, body, isGeneratorVal, isExpressionVal, pos, dst);
|
||||
}
|
||||
|
||||
if (isGenerator) {
|
||||
// Distinguish ES6 generators from legacy generators.
|
||||
RootedValue styleVal(cx);
|
||||
JSAtom* styleStr = generatorStyle == GeneratorStyle::ES6
|
||||
? Atomize(cx, "es6", 3)
|
||||
: Atomize(cx, "legacy", 6);
|
||||
if (!styleStr)
|
||||
return false;
|
||||
styleVal.setString(styleStr);
|
||||
return newNode(type, pos,
|
||||
"id", id,
|
||||
"params", array,
|
||||
"defaults", defarray,
|
||||
"body", body,
|
||||
"rest", rest,
|
||||
"generator", isGeneratorVal,
|
||||
"style", styleVal,
|
||||
"expression", isExpressionVal,
|
||||
dst);
|
||||
}
|
||||
|
||||
return newNode(type, pos,
|
||||
"id", id,
|
||||
"params", array,
|
||||
@@ -3395,7 +3262,9 @@ ASTSerializer::property(ParseNode* pn, MutableHandleValue dst)
|
||||
}
|
||||
|
||||
bool isShorthand = pn->isKind(PNK_SHORTHAND);
|
||||
bool isMethod = pn->pn_right->isKind(PNK_FUNCTION) && kind == PROP_INIT;
|
||||
bool isMethod =
|
||||
pn->pn_right->isKind(PNK_FUNCTION) &&
|
||||
pn->pn_right->pn_funbox->function()->kind() == JSFunction::Method;
|
||||
RootedValue key(cx), val(cx);
|
||||
return propertyName(pn->pn_left, &key) &&
|
||||
expression(pn->pn_right, &val) &&
|
||||
@@ -3567,8 +3436,12 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
|
||||
{
|
||||
RootedFunction func(cx, pn->pn_funbox->function());
|
||||
|
||||
// FIXME: Provide more information (legacy generator vs star generator).
|
||||
bool isGenerator = pn->pn_funbox->isGenerator();
|
||||
GeneratorStyle generatorStyle =
|
||||
pn->pn_funbox->isGenerator()
|
||||
? (pn->pn_funbox->isLegacyGenerator()
|
||||
? GeneratorStyle::Legacy
|
||||
: GeneratorStyle::ES6)
|
||||
: GeneratorStyle::None;
|
||||
|
||||
bool isExpression =
|
||||
#if JS_HAS_EXPR_CLOSURES
|
||||
@@ -3592,7 +3465,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
|
||||
rest.setNull();
|
||||
return functionArgsAndBody(pn->pn_body, args, defaults, &body, &rest) &&
|
||||
builder.function(type, &pn->pn_pos, id, args, defaults, body,
|
||||
rest, isGenerator, isExpression, dst);
|
||||
rest, generatorStyle, isExpression, dst);
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -156,3 +156,21 @@ js::InitWeakSetClass(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
return WeakSetObject::initClass(cx, obj);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
JS_NondeterministicGetWeakSetKeys(JSContext* cx, HandleObject objArg, MutableHandleObject ret)
|
||||
{
|
||||
RootedObject obj(cx, objArg);
|
||||
obj = UncheckedUnwrap(obj);
|
||||
if (!obj || !obj->is<WeakSetObject>()) {
|
||||
ret.set(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
Rooted<WeakSetObject*> weakset(cx, &obj->as<WeakSetObject>());
|
||||
if (!weakset)
|
||||
return false;
|
||||
|
||||
RootedObject map(cx, &weakset->getReservedSlot(WEAKSET_MAP_SLOT).toObject());
|
||||
return JS_NondeterministicGetWeakMapKeys(cx, map, ret);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ class Common(object):
|
||||
# the template member holds the referent directly.
|
||||
handle = False
|
||||
|
||||
# If True, we should strip typedefs from our referent type. (Rooted<T>
|
||||
# uses template magic that gives the referent a noisy type.)
|
||||
strip_typedefs = False
|
||||
|
||||
# Initialize a pretty-printer for |value|, using |cache|.
|
||||
#
|
||||
# If given, |content_printer| is a pretty-printer constructor to use for
|
||||
@@ -42,6 +46,8 @@ class Common(object):
|
||||
ptr = self.value[self.member]
|
||||
if self.handle:
|
||||
ptr = ptr.dereference()
|
||||
if self.strip_typedefs:
|
||||
ptr = ptr.cast(ptr.type.strip_typedefs())
|
||||
if self.content_printer:
|
||||
return self.content_printer(ptr, self.cache).to_string()
|
||||
else:
|
||||
@@ -53,7 +59,7 @@ class Common(object):
|
||||
|
||||
@template_pretty_printer("JS::Rooted")
|
||||
class Rooted(Common):
|
||||
pass
|
||||
strip_typedefs = True
|
||||
|
||||
@template_pretty_printer("JS::Handle")
|
||||
class Handle(Common):
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
function test(stdlib, foreign) {
|
||||
"use asm"
|
||||
function f(y) {
|
||||
y = +y;
|
||||
}
|
||||
return f;
|
||||
};
|
||||
var g = newGlobal();
|
||||
g.parent = this;
|
||||
g.eval(`
|
||||
var dbg = new Debugger();
|
||||
var parentw = dbg.addDebuggee(parent);
|
||||
var testw = parentw.makeDebuggeeValue(parent.test);
|
||||
var scriptw = testw.script;
|
||||
`);
|
||||
@@ -223,9 +223,8 @@ ReportError(JSContext* cx, const char* message, JSErrorReport* reportp,
|
||||
}
|
||||
|
||||
if (cx->options().autoJSAPIOwnsErrorReporting() || JS_IsRunning(cx)) {
|
||||
if (ErrorToException(cx, message, reportp, callback, userRef)) {
|
||||
if (ErrorToException(cx, message, reportp, callback, userRef))
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The AutoJSAPI error reporter only allows warnings to be reported so
|
||||
@@ -233,7 +232,6 @@ ReportError(JSContext* cx, const char* message, JSErrorReport* reportp,
|
||||
*/
|
||||
if (cx->options().autoJSAPIOwnsErrorReporting() && !JSREPORT_IS_WARNING(reportp->flags))
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -587,7 +585,7 @@ js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback,
|
||||
size_t totalArgsLength = 0;
|
||||
size_t argLengths[JS::MaxNumErrorArguments]; /* only {0} thru {9} supported */
|
||||
argCount = efs->argCount;
|
||||
MOZ_ASSERT(argCount <= JS::MaxNumErrorArguments);
|
||||
MOZ_RELEASE_ASSERT(argCount <= JS::MaxNumErrorArguments);
|
||||
if (argCount > 0) {
|
||||
/*
|
||||
* Gather the arguments into an array, and accumulate
|
||||
@@ -654,7 +652,7 @@ js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback,
|
||||
if (*fmt == '{') {
|
||||
if (isdigit(fmt[1])) {
|
||||
int d = JS7_UNDEC(fmt[1]);
|
||||
MOZ_ASSERT(d < argCount);
|
||||
MOZ_RELEASE_ASSERT(d < argCount);
|
||||
js_strncpy(out, reportp->messageArgs[d],
|
||||
argLengths[d]);
|
||||
out += argLengths[d];
|
||||
@@ -824,7 +822,7 @@ js::CallErrorReporter(JSContext* cx, const char* message, JSErrorReport* reportp
|
||||
}
|
||||
|
||||
bool
|
||||
js::ReportIsNotDefined(JSContext *cx, HandleId id)
|
||||
js::ReportIsNotDefined(JSContext* cx, HandleId id)
|
||||
{
|
||||
JSAutoByteString printable;
|
||||
if (ValueToPrintable(cx, IdToValue(id), &printable))
|
||||
@@ -833,7 +831,7 @@ js::ReportIsNotDefined(JSContext *cx, HandleId id)
|
||||
}
|
||||
|
||||
bool
|
||||
js::ReportIsNotDefined(JSContext *cx, HandlePropertyName name)
|
||||
js::ReportIsNotDefined(JSContext* cx, HandlePropertyName name)
|
||||
{
|
||||
RootedId id(cx, NameToId(name));
|
||||
return ReportIsNotDefined(cx, id);
|
||||
@@ -841,7 +839,7 @@ js::ReportIsNotDefined(JSContext *cx, HandlePropertyName name)
|
||||
|
||||
bool
|
||||
js::ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v,
|
||||
HandleString fallback)
|
||||
HandleString fallback)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
@@ -896,8 +894,9 @@ js::ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNum
|
||||
int spindex, HandleValue v, HandleString fallback,
|
||||
const char* arg1, const char* arg2)
|
||||
{
|
||||
bool ok;
|
||||
UniquePtr<char[], JS::FreePolicy> bytes;
|
||||
bool ok;
|
||||
|
||||
MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
|
||||
MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
|
||||
bytes = DecompileValueGenerator(cx, spindex, v, fallback);
|
||||
@@ -906,7 +905,6 @@ js::ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNum
|
||||
|
||||
ok = JS_ReportErrorFlagsAndNumber(cx, flags, GetErrorMessage,
|
||||
nullptr, errorNumber, bytes.get(), arg1, arg2);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,9 @@ JS_GetCustomIteratorCount(JSContext* cx);
|
||||
extern JS_FRIEND_API(bool)
|
||||
JS_NondeterministicGetWeakMapKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret);
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
JS_NondeterministicGetWeakSetKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret);
|
||||
|
||||
// Raw JSScript* because this needs to be callable from a signal handler.
|
||||
extern JS_FRIEND_API(unsigned)
|
||||
JS_PCToLineNumber(JSScript* script, jsbytecode* pc, unsigned* columnp = nullptr);
|
||||
|
||||
@@ -38,13 +38,14 @@ function funDecl(id, params, body, defaults=[], rest=null) {
|
||||
rest: rest,
|
||||
generator: false });
|
||||
}
|
||||
function genFunDecl(id, params, body) {
|
||||
function genFunDecl(style, id, params, body) {
|
||||
return Pattern({ type: "FunctionDeclaration",
|
||||
id: id,
|
||||
params: params,
|
||||
defaults: [],
|
||||
body: body,
|
||||
generator: true });
|
||||
generator: true,
|
||||
style: style });
|
||||
}
|
||||
function varDecl(decls) {
|
||||
return Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" });
|
||||
@@ -157,12 +158,13 @@ function funExpr(id, args, body, gen) {
|
||||
body: body,
|
||||
generator: false });
|
||||
}
|
||||
function genFunExpr(id, args, body) {
|
||||
function genFunExpr(style, id, args, body) {
|
||||
return Pattern({ type: "FunctionExpression",
|
||||
id: id,
|
||||
params: args,
|
||||
body: body,
|
||||
generator: true });
|
||||
generator: true,
|
||||
style: style });
|
||||
}
|
||||
function arrowExpr(args, body) {
|
||||
return Pattern({ type: "ArrowFunctionExpression",
|
||||
|
||||
@@ -41,8 +41,7 @@ assertGlobalExpr("({ x: y })", 13, { objectExpression: () => 13 });
|
||||
assertGlobalExpr("this", 14, { thisExpression: () => 14 });
|
||||
assertGlobalExpr("[x for (x in y)]", 17, { comprehensionExpression: () => 17 });
|
||||
assertGlobalExpr("(x for (x in y))", 18, { generatorExpression: () => 18 });
|
||||
assertGlobalExpr("(function() { yield 42 })", genFunExpr(null, [], blockStmt([exprStmt(19)])), { yieldExpression: () => 19 });
|
||||
assertGlobalExpr("(let (x) x)", 20, { letExpression: () => 20 });
|
||||
assertGlobalExpr("(function() { yield 42 })", genFunExpr("legacy", null, [], blockStmt([exprStmt(19)])), { yieldExpression: () => 19 });
|
||||
|
||||
assertGlobalStmt("switch (x) { case y: }", switchStmt(ident("x"), [1]), { switchCase: () => 1 });
|
||||
assertGlobalStmt("try { } catch (e) { }", 2, { tryStatement: (b, g, u, f) => u, catchClause: () => 2 });
|
||||
|
||||
@@ -14,10 +14,11 @@ function testClasses() {
|
||||
function methodFun(id, kind, generator, args, body = []) {
|
||||
assertEq(generator && kind === "method", generator);
|
||||
assertEq(typeof id === 'string' || id === null, true);
|
||||
let idN = typeof id === 'string' ? ident(id): null;
|
||||
let methodMaker = generator ? genFunExpr : funExpr;
|
||||
let idN = typeof id === 'string' ? ident(id) : null;
|
||||
let methodName = kind !== "method" ? null : idN;
|
||||
return methodMaker(methodName, args.map(ident), blockStmt(body));
|
||||
return generator
|
||||
? genFunExpr("es6", methodName, args.map(ident), blockStmt(body))
|
||||
: funExpr(methodName, args.map(ident), blockStmt(body));
|
||||
}
|
||||
|
||||
function simpleMethod(id, kind, generator, args=[], isStatic=false) {
|
||||
|
||||
@@ -31,6 +31,15 @@ assertExpr("b = { set [meth](a) { } }", aExpr("=", ident("b"),
|
||||
objExpr([{ key: computedName(ident("meth")), value: funExpr(null, [ident("a")],
|
||||
blockStmt([])), method: false, kind: "set"}])));
|
||||
|
||||
// Bug 1220702 - If it's not written as a method, `.method` should be false.
|
||||
assertExpr("({[x]: function () {}})",
|
||||
objExpr([{
|
||||
key: computedName(ident("x")),
|
||||
value: funExpr(null, [], blockStmt([])),
|
||||
method: false,
|
||||
kind: "init"
|
||||
}]));
|
||||
|
||||
}
|
||||
|
||||
runtest(test);
|
||||
|
||||
@@ -3,10 +3,14 @@ function test() {
|
||||
|
||||
// generators
|
||||
|
||||
assertDecl("function gen(x) { yield }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
|
||||
assertExpr("(function(x) { yield })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
|
||||
assertDecl("function gen(x) { yield 42 }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
|
||||
assertExpr("(function(x) { yield 42 })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
|
||||
assertDecl("function gen(x) { yield }", genFunDecl("legacy", ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
|
||||
assertExpr("(function(x) { yield })", genFunExpr("legacy", null, [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
|
||||
assertDecl("function gen(x) { yield 42 }", genFunDecl("legacy", ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
|
||||
assertExpr("(function(x) { yield 42 })", genFunExpr("legacy", null, [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
|
||||
|
||||
assertDecl("function* gen() {}", genFunDecl("es6", ident("gen"), [], blockStmt([])));
|
||||
assertExpr("(function*() {})", genFunExpr("es6", null, [], blockStmt([])));
|
||||
assertExpr("(function* gen() {})", genFunExpr("es6", ident("gen"), [], blockStmt([])));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ assertExpr("b = { a() { } }", aExpr("=", ident("b"),
|
||||
true}])));
|
||||
|
||||
assertExpr("b = { *a() { } }", aExpr("=", ident("b"),
|
||||
objExpr([{ key: ident("a"), value: genFunExpr(ident("a"), [], blockStmt([])), method:
|
||||
objExpr([{ key: ident("a"), value: genFunExpr("es6", ident("a"), [], blockStmt([])), method:
|
||||
true}])));
|
||||
|
||||
// Method definitions without braces
|
||||
@@ -28,9 +28,9 @@ assertExpr("({ set x(v) { return 42 } })",
|
||||
|
||||
// Bug 1073809 - Getter/setter syntax with generators
|
||||
assertExpr("({*get() { }})", objExpr([{ type: "Property", key: ident("get"), method: true,
|
||||
value: genFunExpr(ident("get"), [], blockStmt([]))}]));
|
||||
value: genFunExpr("es6", ident("get"), [], blockStmt([]))}]));
|
||||
assertExpr("({*set() { }})", objExpr([{ type: "Property", key: ident("set"), method: true,
|
||||
value: genFunExpr(ident("set"), [], blockStmt([]))}]));
|
||||
value: genFunExpr("es6", ident("set"), [], blockStmt([]))}]));
|
||||
assertError("({*get foo() { }})", SyntaxError);
|
||||
assertError("({*set foo() { }})", SyntaxError);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ function testNewTarget() {
|
||||
assertError("(() => new.target))", SyntaxError);
|
||||
|
||||
// valid in generators, too!
|
||||
assertStmt("function *foo() { new.target; }", genFunDecl(ident("foo"), [],
|
||||
assertStmt("function *foo() { new.target; }", genFunDecl("es6", ident("foo"), [],
|
||||
blockStmt([exprStmt(newTarget())])));
|
||||
|
||||
// new.target is a member expression. You should be able to call, invoke, or
|
||||
|
||||
@@ -7099,7 +7099,7 @@ DebuggerObject_getScript(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
RootedFunction fun(cx, &obj->as<JSFunction>());
|
||||
if (fun->isBuiltin()) {
|
||||
if (!fun->isInterpreted()) {
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/* 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/. */
|
||||
|
||||
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=1165807 */
|
||||
|
||||
function run_test()
|
||||
{
|
||||
var bunnies = new String("bunnies");
|
||||
var lizards = new String("lizards");
|
||||
|
||||
var weakset = new WeakSet([bunnies, lizards]);
|
||||
var weakmap = new WeakMap();
|
||||
weakmap.set(bunnies, 23);
|
||||
weakmap.set(lizards, "oh no");
|
||||
|
||||
var keys = ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(bunnies);
|
||||
equal(keys, undefined, "test nondeterministicGetWeakMapKeys on non-WeakMap");
|
||||
|
||||
keys = ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(weakmap);
|
||||
equal(keys.length, 2, "length of nondeterministicGetWeakMapKeys");
|
||||
equal(weakmap.get(bunnies), 23, "check bunnies in weakmap");
|
||||
equal(weakmap.get(lizards), "oh no", "check lizards in weakmap");
|
||||
|
||||
keys = ThreadSafeChromeUtils.nondeterministicGetWeakSetKeys(bunnies);
|
||||
equal(keys, undefined, "test nondeterministicGetWeakSetKeys on non-WeakMap");
|
||||
|
||||
keys = ThreadSafeChromeUtils.nondeterministicGetWeakSetKeys(weakset);
|
||||
equal(keys.length, 2, "length of nondeterministicGetWeakSetKeys");
|
||||
ok(weakset.has(bunnies), "check bunnies in weakset");
|
||||
ok(weakset.has(lizards), "check lizards in weakset");
|
||||
|
||||
bunnies = null;
|
||||
keys = null;
|
||||
|
||||
Components.utils.forceGC();
|
||||
|
||||
keys = ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(weakmap);
|
||||
equal(keys.length, 1, "length of nondeterministicGetWeakMapKeys after GC");
|
||||
equal(weakmap.get(lizards), "oh no", "check lizards still in weakmap");
|
||||
|
||||
keys = ThreadSafeChromeUtils.nondeterministicGetWeakSetKeys(weakset);
|
||||
equal(keys.length, 1, "length of nondeterministicGetWeakSetKeys after GC");
|
||||
ok(weakset.has(lizards), "check lizards still in weakset");
|
||||
}
|
||||
@@ -126,6 +126,7 @@ head = head_watchdog.js
|
||||
head = head_watchdog.js
|
||||
[test_watchdog_hibernate.js]
|
||||
head = head_watchdog.js
|
||||
[test_weak_keys.js]
|
||||
[test_writeToGlobalPrototype.js]
|
||||
[test_xpcwn_tamperproof.js]
|
||||
[test_xrayed_iterator.js]
|
||||
|
||||
@@ -5200,9 +5200,31 @@ nsCSSFrameConstructor::FindSVGData(Element* aElement,
|
||||
// Elements with failing conditional processing attributes never get
|
||||
// rendered. Note that this is not where we select which frame in a
|
||||
// <switch> to render! That happens in nsSVGSwitchFrame::PaintSVG.
|
||||
if (aIsWithinSVGText) {
|
||||
// SVGTextFrame doesn't handle conditional processing attributes,
|
||||
// so don't create frames for descendants of <text> with failing
|
||||
// attributes. We need frames not to be created so that text layout
|
||||
// is correct.
|
||||
return &sSuppressData;
|
||||
}
|
||||
// If we're not inside <text>, create an nsSVGContainerFrame (which is a
|
||||
// frame that doesn't render) so that paint servers can still be referenced,
|
||||
// even if they live inside an element with failing conditional processing
|
||||
// attributes.
|
||||
return &sContainerData;
|
||||
}
|
||||
|
||||
// Ensure that a stop frame is a child of a gradient and that gradients
|
||||
// can only have stop children.
|
||||
bool parentIsGradient = aParentFrame &&
|
||||
(aParentFrame->GetType() == nsGkAtoms::svgLinearGradientFrame ||
|
||||
aParentFrame->GetType() == nsGkAtoms::svgRadialGradientFrame);
|
||||
bool stop = (aTag == nsGkAtoms::stop);
|
||||
if ((parentIsGradient && !stop) ||
|
||||
(!parentIsGradient && stop)) {
|
||||
return &sSuppressData;
|
||||
}
|
||||
|
||||
// Prevent bad frame types being children of filters or parents of filter
|
||||
// primitives. If aParentFrame is null, we know that the frame that will
|
||||
// be created will be an nsInlineFrame, so it can never be a filter.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="100">
|
||||
<text x="10" y="20">
|
||||
<tspan fill="green">This text should display.</tspan>
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 164 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="100">
|
||||
<text x="10" y="20">
|
||||
<tspan systemLanguage="xx" fill="red">This text shouldn't display.</tspan>
|
||||
<tspan fill="green">This text should display.</tspan>
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 243 B |
@@ -51,6 +51,7 @@ fuzzy-if(/^Windows\x20NT\x206\.[12]/.test(http.oscpu),1,5) fuzzy-if(azureQuartz,
|
||||
== conditions-06.svg pass.svg
|
||||
== conditions-07.svg pass.svg
|
||||
== conditions-08.svg conditions-08-ref.svg
|
||||
== conditions-09.svg conditions-09-ref.svg
|
||||
== currentColor-01.svg pass.svg
|
||||
== currentColor-02.svg pass.svg
|
||||
== currentColor-03.svg pass.svg
|
||||
@@ -290,6 +291,7 @@ fuzzy-if(cocoaWidget,4,15982) fuzzy-if(winWidget,4,92) == radialGradient-basic-0
|
||||
== rootElement-null-01.svg pass.svg
|
||||
== script-empty-01.svg pass.svg
|
||||
== selector-01.svg pass.svg
|
||||
== stroke-linecap-circle-ellipse-01.svg stroke-linecap-circle-ellipse-01-ref.svg
|
||||
== stroke-width-percentage-01.svg pass.svg
|
||||
== stroke-width-percentage-02a.svg stroke-width-percentage-02-ref.svg
|
||||
== stroke-width-percentage-02b.svg stroke-width-percentage-02-ref.svg
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Reference to test that stroke-linecap:"square" is ignored on circles and ellipses</title>
|
||||
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1178159 -->
|
||||
|
||||
<circle cx="300" cy="300" r="200" stroke="black" fill="none"
|
||||
stroke-width="80"/>
|
||||
|
||||
<ellipse cx="300" cy="750" rx="150" ry="100" fill="none"
|
||||
stroke="blue" stroke-width="80"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 528 B |
@@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Test that stroke-linecap:"square" is ignored on circles and ellipses</title>
|
||||
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1178159 -->
|
||||
|
||||
<circle cx="300" cy="300" r="200" stroke="black" fill="none"
|
||||
stroke-width="80" stroke-linecap="square"/>
|
||||
|
||||
<ellipse cx="300" cy="750" rx="150" ry="100" fill="none"
|
||||
stroke="blue" stroke-width="80" stroke-linecap="square"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 563 B |
@@ -6,11 +6,12 @@
|
||||
|
||||
<title>Test 'stroke-linecap: round' with zero length path segments</title>
|
||||
|
||||
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=1075399 -->
|
||||
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=1075399 for paths and
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1187770 for lines -->
|
||||
|
||||
<style>
|
||||
|
||||
path {
|
||||
path, line {
|
||||
stroke-width: 20px;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
@@ -20,7 +21,7 @@ circle {
|
||||
}
|
||||
|
||||
/* expect lime circles to cover red circles */
|
||||
path.circles-expected {
|
||||
path.circles-expected, line.circles-expected {
|
||||
stroke: lime;
|
||||
}
|
||||
|
||||
@@ -158,4 +159,11 @@ path.coverer {
|
||||
<circle cy="80" r="8"/>
|
||||
<path class="circles-expected" d="M0,0v81" stroke-dasharray="0" />
|
||||
</g>
|
||||
|
||||
<!-- Column 6: test zero-length line -->
|
||||
<g transform="translate(625, 25)">
|
||||
<circle cy="0" r="8" />
|
||||
<line class="circles-expected" x1="0" y1="0" x2="0" y2="0" />
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.3 KiB |
@@ -6,13 +6,15 @@
|
||||
|
||||
<title>Test invalidation for 'stroke-linecap: round' with zero length path segments</title>
|
||||
|
||||
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=1075399 -->
|
||||
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=1075399 for path and
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1187770 for line -->
|
||||
|
||||
<script>
|
||||
|
||||
function run()
|
||||
{
|
||||
document.getElementById('path').setAttribute('stroke-linecap', 'butt');
|
||||
document.getElementById('line').setAttribute('stroke-linecap', 'butt');
|
||||
document.documentElement.removeAttribute('class');
|
||||
}
|
||||
|
||||
@@ -24,5 +26,7 @@ window.addEventListener("MozReftestInvalidate", run, false);
|
||||
|
||||
<path id="path" stroke="red" stroke-width="200" stroke-linecap="round"
|
||||
d="M100,100 L100,100"/>
|
||||
<line id="line" stroke="red" stroke-width="200" stroke-linecap="round"
|
||||
x1="300" y1="300" x2="300" y2="300"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 751 B After Width: | Height: | Size: 1.0 KiB |