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)
This commit is contained in:
2023-01-17 11:23:50 +08:00
parent 9ce925bf38
commit b808ffac2d
279 changed files with 15388 additions and 1271 deletions
+1
View File
@@ -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
+14
View File
@@ -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
+1 -1
View File
@@ -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);
+1
View File
@@ -70,4 +70,5 @@ private:
} // namespace dom
} // namespace mozilla
#endif
+20
View File
@@ -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,
+5
View File
@@ -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
+21
View File
@@ -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()
{
}
+3
View File
@@ -29,6 +29,9 @@ public:
void
FlushConsoleReports(nsIDocument* aDocument) override;
void
FlushConsoleReports(nsIConsoleReportCollector* aCollector) override;
private:
~ConsoleReportCollector();
-7
View File
@@ -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);
+9 -1
View File
@@ -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");
+1 -1
View File
@@ -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"].
+3 -3
View File
@@ -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");
+2 -2
View File
@@ -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);
-2
View File
@@ -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>
+3 -3
View File
@@ -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 -1
View File
@@ -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;
-3
View File
@@ -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();
+3
View File
@@ -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);
}
+1 -7
View File
@@ -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);
+20 -65
View File
@@ -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;
+7 -5
View File
@@ -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; }
+4 -1
View File
@@ -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)) {
+15
View File
@@ -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()
+3
View File
@@ -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;
};
+3
View File
@@ -31,3 +31,6 @@ LOCAL_INCLUDES += [
if CONFIG['ENABLE_TESTS']:
DEFINES['DOM_STORAGE_TESTS'] = True
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wshadow']
+16 -10
View File
@@ -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!");
+6
View File
@@ -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
{
+16 -10
View File
@@ -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!");
+6
View File
@@ -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
{
+20 -13
View File
@@ -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!");
+4
View File
@@ -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
{
+20 -13
View File
@@ -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!");
+4
View File
@@ -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
{
+16 -10
View File
@@ -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!");
+6
View File
@@ -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
{
+18 -5
View File
@@ -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;
}
+2 -1
View File
@@ -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;
+59 -9
View File
@@ -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);
}
+29 -3
View File
@@ -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
+18 -5
View File
@@ -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;
}
+2 -1
View File
@@ -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;
+5 -3
View File
@@ -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;
}
+2 -1
View File
@@ -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:
+81 -16
View File
@@ -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;
}
+6 -1
View File
@@ -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;
+1 -1
View File
@@ -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);
+26 -5
View File
@@ -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;
}
+2 -1
View File
@@ -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;
+13 -1
View File
@@ -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;
}
+10 -8
View File
@@ -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;
+2 -1
View File
@@ -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();
+32
View File
@@ -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

+87 -7
View File
@@ -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"]]},
+8 -1
View File
@@ -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;
};
+12
View File
@@ -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);
};
/**
+6 -7
View File
@@ -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;
}
+1 -1
View File
@@ -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;
-1
View File
@@ -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;
};
+7
View File
@@ -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,
+111 -238
View File
@@ -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
+18
View File
@@ -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);
}
+7 -1
View File
@@ -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;
`);
+8 -10
View File
@@ -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;
}
+3
View File
@@ -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
+1 -1
View File
@@ -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;
}
+45
View File
@@ -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");
}
+1
View File
@@ -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]
+22
View File
@@ -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

+6
View File
@@ -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

+2
View File
@@ -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

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