MozReview-Commit-ID: BYGylgZSbUu
This commit is contained in:
Wes Kocher 2017-06-20 18:31:42 -07:00
Родитель bee0bbe92b c0e1236f1a
Коммит 47a595548e
697 изменённых файлов: 40867 добавлений и 51783 удалений

Просмотреть файл

@ -35,9 +35,9 @@
^js/src/ctypes/libffi/.*
^js/src/dtoa.c.*
^js/src/jit/arm64/vixl/.*
^media/ffvpx/.*
^media/gmp-clearkey/0.1/openaes/.*
^media/kiss_fft/.*
^media/ffvpx/.*
^media/libav/.*
^media/libcubeb/.*
^media/libjpeg/.*
@ -58,25 +58,48 @@
^media/openmax_dl/.*
^media/pocketsphinx/.*
^media/sphinxbase/.*
^media/webrtc/trunk/.*
^media/webrtc/signaling/src/sdp/sipcc/.*
^media/webrtc/trunk/.*
^mfbt/decimal/.*
^mfbt/double-conversion/source/.*
^mfbt/lz4.*
^mobile/android/geckoview/src/thirdparty/.*
^mobile/android/thirdparty/.*
^modules/brotli/.*
^modules/fdlibm/.*
^modules/freetype2/.*
^modules/libbz2/.*
^modules/libmar/.*
^modules/woff2/.*
^modules/zlib/.*
^netwerk/sctp/src/.*
^netwerk/srtp/src/.*
^nsprpub/.*
^other-licenses/.*
^parser/expat/.*
^security/nss/.*
^security/sandbox/chromium/.*
^testing/gtest/gmock/.*
^testing/gtest/gtest/.*
^testing/talos/talos/tests/dromaeo/.*
^third_party/aom/.*
^third_party/python/blessings/.*
^third_party/python/configobj/.*
^third_party/python/futures/.*
^third_party/python/jsmin/.*
^third_party/python/mock-*/.*
^third_party/python/psutil/.*
^third_party/python/py/.*
^third_party/python/pyasn1/.*
^third_party/python/pyasn1-modules/.*
^third_party/python/PyECC/.*
^third_party/python/pytest/.*
^third_party/python/pytoml/.*
^third_party/python/pyyaml/.*
^third_party/python/redo/.*
^third_party/python/requests/.*
^third_party/python/rsa/.*
^third_party/python/which/.*
^toolkit/components/jsoncpp/.*
^toolkit/components/protobuf/.*
^toolkit/crashreporter/google-breakpad/.*

Просмотреть файл

@ -2344,6 +2344,11 @@
<infoURL>https://get.adobe.com/reader/</infoURL>
<versionRange maxVersion="15.006.30244" minVersion="15.006" severity="0" vulnerabilitystatus="1"/>
</pluginItem>
<pluginItem blockID="41bf48ab-7e0c-4349-8e3f-6890311b2f83">
<match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
<versionRange maxVersion="25.0.0.171" minVersion="25.0.0.163" severity="0" vulnerabilitystatus="1"/>
</pluginItem>
<pluginItem blockID="43b45ad8-a373-42c1-89c6-64e2746885e5">
<match exp="(nppdf32\.dll)|(AdobePDFViewerNPAPI\.plugin)" name="filename"/>
<infoURL>https://get.adobe.com/reader/</infoURL>
@ -2653,6 +2658,11 @@
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
<versionRange maxVersion="25.0.0.163" minVersion="25.0.0.127" severity="0" vulnerabilitystatus="1"/>
</pluginItem>
<pluginItem blockID="91543128-a6f1-40ea-8766-57c54aebd0c7" os="Linux">
<match exp="libflashplayer\.so" name="filename"/>
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
<versionRange maxVersion="25.0.0.171" minVersion="25.0.0.163" severity="0" vulnerabilitystatus="1"/>
</pluginItem>
<pluginItem blockID="p34">
<match exp="[Nn][Pp][Jj][Pp][Ii]1[56]0_[0-9]+\.[Dd][Ll][Ll]" name="filename"/>
<versionRange>

Просмотреть файл

@ -68,7 +68,6 @@ var SidebarUI = {
enumerator.getNext();
if (!enumerator.hasMoreElements()) {
document.persist("sidebar-box", "sidebarcommand");
document.persist("sidebar-box", "checked");
document.persist("sidebar-box", "width");
document.persist("sidebar-title", "value");
}

Просмотреть файл

@ -12,7 +12,6 @@
--lwt-additional-images: none;
--lwt-background-alignment: right top;
--lwt-background-tiling: no-repeat;
--lwt-toolbar-color: inherit;
}
:root:-moz-lwtheme {
@ -26,11 +25,6 @@
background-repeat: var(--lwt-background-tiling) !important;
}
#navigator-toolbox > toolbar,
findbar {
background: var(--lwt-toolbar-color) !important;
}
#main-window:not([chromehidden~="toolbar"]) {
%ifdef XP_MACOSX
min-width: 335px;

Просмотреть файл

@ -5,15 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
Components.utils.import("resource://gre/modules/LoginManagerContextMenu.jsm");
Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SpellCheckHelper",
"resource://gre/modules/InlineSpellChecker.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
"resource://gre/modules/LoginHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContextMenu",
"resource://gre/modules/LoginManagerContextMenu.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
@ -146,7 +148,9 @@ nsContextMenu.prototype = {
InlineSpellCheckerUI.clearSuggestionsFromMenu();
InlineSpellCheckerUI.clearDictionaryListFromMenu();
InlineSpellCheckerUI.uninit();
LoginManagerContextMenu.clearLoginsFromMenu(document);
if (Cu.isModuleLoaded("resource://gre/modules/LoginManagerContextMenu.jsm")) {
LoginManagerContextMenu.clearLoginsFromMenu(document);
}
// This handler self-deletes, only run it if it is still there:
if (this._onPopupHiding) {

Просмотреть файл

@ -5643,6 +5643,16 @@
return;
let browser = event.originalTarget;
// Preloaded browsers do not actually have any tabs. If one crashes,
// it should be released and removed.
if (browser === this._preloadedBrowser) {
// Calling _getPreloadedBrowser is necessary to actually consume the preloaded browser
let preloaded = this._getPreloadedBrowser();
preloaded.remove();
return;
}
let icon = browser.mIconURL;
let tab = this.getTabForBrowser(browser);

Просмотреть файл

@ -90,7 +90,11 @@ const startupPhases = {
// We are at this phase once we are ready to handle user events.
// Anything loaded at this phase or before gets in the way of the user
// interacting with the first browser window.
"before handling user events": {},
"before handling user events": {blacklist: {
modules: new Set([
"resource://gre/modules/LoginManagerContextMenu.jsm",
]),
}},
};
function test() {

Просмотреть файл

@ -1716,7 +1716,7 @@ BrowserGlue.prototype = {
// eslint-disable-next-line complexity
_migrateUI: function BG__migrateUI() {
const UI_VERSION = 47;
const UI_VERSION = 48;
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
let currentUIVersion;
@ -2046,6 +2046,14 @@ BrowserGlue.prototype = {
}
}
if (currentUIVersion < 48) {
// Bug 1372954 - the checked value was persisted but the attribute removal wouldn't
// be persisted (Bug 15232). Turns out we can just not persist the value in this case.
// The situation was only happening for a few nightlies in 56, so this migration can
// be removed in version 58.
xulStore.removeValue(BROWSER_DOCURL, "sidebar-box", "checked");
}
// Update the migration version.
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
},

Просмотреть файл

@ -2,9 +2,12 @@
tags = resistfingerprinting
support-files =
file_dummy.html
file_navigator.html
file_navigatorWorker.js
file_workerPerformance.js
head.js
[browser_navigator.js]
[browser_performanceAPI.js]
[browser_roundedWindow_dialogWindow.js]
[browser_roundedWindow_newWindow.js]

Просмотреть файл

@ -0,0 +1,122 @@
/**
* Bug 1333651 - A test case for making sure the navigator object has been
* spoofed/disabled correctly.
*/
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
const TEST_PATH = "http://example.net/browser/browser/" +
"components/resistfingerprinting/test/browser/"
var spoofedUserAgent;
const SPOOFED_APPNAME = "Netscape";
const SPOOFED_APPVERSION = "5.0 (Windows)";
const SPOOFED_PLATFORM = "Win32";
const SPOOFED_OSCPU = "Windows NT 6.1";
const SPOOFED_BUILDID = "20100101";
const SPOOFED_HW_CONCURRENCY = 2;
const CONST_APPCODENAME = "Mozilla";
const CONST_PRODUCT = "Gecko";
const CONST_PRODUCTSUB = "20100101";
const CONST_VENDOR = "";
const CONST_VENDORSUB = "";
async function testNavigator() {
// Open a tab to collect result.
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser, TEST_PATH + "file_navigator.html");
let result = await ContentTask.spawn(tab.linkedBrowser, null, function() {
return content.document.getElementById("result").innerHTML;
});
result = JSON.parse(result);
is(result.appName, SPOOFED_APPNAME, "Navigator.appName is correctly spoofed.");
is(result.appVersion, SPOOFED_APPVERSION, "Navigator.appVersion is correctly spoofed.");
is(result.platform, SPOOFED_PLATFORM, "Navigator.platform is correctly spoofed.");
is(result.userAgent, spoofedUserAgent, "Navigator.userAgent is correctly spoofed.");
is(result.mimeTypesLength, 0, "Navigator.mimeTypes has a length of 0.");
is(result.pluginsLength, 0, "Navigator.plugins has a length of 0.");
is(result.oscpu, SPOOFED_OSCPU, "Navigator.oscpu is correctly spoofed.");
is(result.buildID, SPOOFED_BUILDID, "Navigator.buildID is correctly spoofed.");
is(result.hardwareConcurrency, SPOOFED_HW_CONCURRENCY, "Navigator.hardwareConcurrency is correctly spoofed.")
is(result.appCodeName, CONST_APPCODENAME, "Navigator.appCodeName reports correct constant value.");
is(result.product, CONST_PRODUCT, "Navigator.product reports correct constant value.");
is(result.productSub, CONST_PRODUCTSUB, "Navigator.productSub reports correct constant value.");
is(result.vendor, CONST_VENDOR, "Navigator.vendor reports correct constant value.");
is(result.vendorSub, CONST_VENDORSUB, "Navigator.vendorSub reports correct constant value.");
await BrowserTestUtils.removeTab(tab);
}
async function testWorkerNavigator() {
// Open a tab to collect result from worker.
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser, TEST_PATH + "file_dummy.html");
let result = await ContentTask.spawn(tab.linkedBrowser, null, async function() {
let worker = new content.SharedWorker("file_navigatorWorker.js", "WorkerNavigatorTest");
let res = await new Promise(resolve => {
worker.port.onmessage = function(e) {
resolve(e.data);
};
});
return res;
});
result = JSON.parse(result);
is(result.appName, SPOOFED_APPNAME, "Navigator.appName is correctly spoofed.");
is(result.appVersion, SPOOFED_APPVERSION, "Navigator.appVersion is correctly spoofed.");
is(result.platform, SPOOFED_PLATFORM, "Navigator.platform is correctly spoofed.");
is(result.userAgent, spoofedUserAgent, "Navigator.userAgent is correctly spoofed.");
is(result.hardwareConcurrency, SPOOFED_HW_CONCURRENCY, "Navigator.hardwareConcurrency is correctly spoofed.")
is(result.appCodeName, CONST_APPCODENAME, "Navigator.appCodeName reports correct constant value.");
is(result.product, CONST_PRODUCT, "Navigator.product reports correct constant value.");
await BrowserTestUtils.removeTab(tab);
}
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({"set":
[["privacy.resistFingerprinting", true]]
});
let appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
let appVersion = parseInt(appInfo.version);
let spoofedVersion = appVersion - (appVersion % 10);
spoofedUserAgent = `Mozilla/5.0 (Windows NT 6.1; rv:${spoofedVersion}.0) Gecko/20100101 Firefox/${spoofedVersion}.0`;
});
add_task(async function runNavigatorTest() {
await testNavigator();
});
add_task(async function runWorkerNavigatorTest() {
await testWorkerNavigator();
});
// This tests that 'general.*.override' should not override spoofed values.
add_task(async function runOverrideTest() {
await SpecialPowers.pushPrefEnv({"set":
[
["general.appname.override", "appName overridden"],
["general.appversion.override", "appVersion overridden"],
["general.platform.override", "platform overridden"],
["general.useragent.override", "userAgent overridden"],
["general.oscpu.override", "oscpu overridden"],
["general.buildID.override", "buildID overridden"],
]
});
await testNavigator();
await testWorkerNavigator();
});

Просмотреть файл

@ -6,7 +6,7 @@
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
const TEST_DOMAIN = "http://example.net/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistFingerprinting/test/browser/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistfingerprinting/test/browser/";
let gMaxAvailWidth;
let gMaxAvailHeight;

Просмотреть файл

@ -7,7 +7,7 @@
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
const TEST_DOMAIN = "http://example.net/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistFingerprinting/test/browser/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistfingerprinting/test/browser/";
let gMaxAvailWidth;
let gMaxAvailHeight;

Просмотреть файл

@ -7,7 +7,7 @@
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
const TEST_DOMAIN = "http://example.net/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistFingerprinting/test/browser/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistfingerprinting/test/browser/";
let gMaxAvailWidth;
let gMaxAvailHeight;

Просмотреть файл

@ -7,7 +7,7 @@
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
const TEST_DOMAIN = "http://example.net/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistFingerprinting/test/browser/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistfingerprinting/test/browser/";
let gMaxAvailWidth;
let gMaxAvailHeight;

Просмотреть файл

@ -7,7 +7,7 @@
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
const TEST_DOMAIN = "http://example.net/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistFingerprinting/test/browser/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistfingerprinting/test/browser/";
let gMaxAvailWidth;
let gMaxAvailHeight;

Просмотреть файл

@ -7,7 +7,7 @@
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
const TEST_DOMAIN = "http://example.net/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistFingerprinting/test/browser/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistfingerprinting/test/browser/";
let gMaxAvailWidth;
let gMaxAvailHeight;

Просмотреть файл

@ -7,7 +7,7 @@
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
const TEST_DOMAIN = "http://example.net/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistFingerprinting/test/browser/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistfingerprinting/test/browser/";
let gMaxAvailWidth;
let gMaxAvailHeight;

Просмотреть файл

@ -4,7 +4,7 @@
*/
const TEST_DOMAIN = "http://example.net/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistFingerprinting/test/browser/";
const TEST_PATH = TEST_DOMAIN + "browser/browser/components/resistfingerprinting/test/browser/";
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({"set":

Просмотреть файл

@ -0,0 +1,33 @@
<html>
<head>
<title>Test page for navigator object</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
<script>
// This page will collect information from the navigator object and store
// the result at a paragraph in the page.
function collect() {
let result = {};
result["appCodeName"] = navigator.appCodeName;
result["appName"] = navigator.appName;
result["appVersion"] = navigator.appVersion;
result["platform"] = navigator.platform;
result["userAgent"] = navigator.userAgent;
result["product"] = navigator.product;
result["productSub"] = navigator.productSub;
result["vendor"] = navigator.vendor;
result["vendorSub"] = navigator.vendorSub;
result["mimeTypesLength"] = navigator.mimeTypes.length;
result["pluginsLength"] = navigator.plugins.length;
result["oscpu"] = navigator.oscpu;
result["buildID"] = navigator.buildID;
result["hardwareConcurrency"] = navigator.hardwareConcurrency;
document.getElementById("result").innerHTML = JSON.stringify(result);
}
</script>
</head>
<body onload="collect();">
<p id="result"></p>
</body>
</html>

Просмотреть файл

@ -0,0 +1,19 @@
/* eslint-env worker */
onconnect = function(e) {
let port = e.ports[0];
let navigatorObj = self.navigator;
let result = {};
result["appCodeName"] = navigatorObj.appCodeName;
result["appName"] = navigatorObj.appName;
result["appVersion"] = navigatorObj.appVersion;
result["platform"] = navigatorObj.platform;
result["userAgent"] = navigatorObj.userAgent;
result["product"] = navigatorObj.product;
result["hardwareConcurrency"] = navigatorObj.hardwareConcurrency;
port.postMessage(JSON.stringify(result));
port.start();
};

Просмотреть файл

@ -11,7 +11,7 @@ async function calcMaximumAvailSize(aChromeWidth, aChromeHeight) {
let chromeUIWidth;
let chromeUIHeight;
let testPath = "http://example.net/browser/browser/" +
"components/resistFingerprinting/test/browser/"
"components/resistfingerprinting/test/browser/"
// If the chrome UI dimensions is not given, we will calculate it.
if (!aChromeWidth || !aChromeHeight) {

Просмотреть файл

@ -219,3 +219,30 @@ add_task(async function test_background_crash_multiple() {
});
});
});
// Tests that crashed preloaded tabs are removed and no unexpected errors are
// thrown.
add_task(async function test_preload_crash() {
if (!Services.prefs.getBoolPref("browser.newtab.preload")) {
return;
}
// Since new tab is only crashable for the activity-stream version,
// we need to flip the pref
await SpecialPowers.pushPrefEnv({
set: [[ "browser.newtabpage.activity-stream.enabled", true ]]
});
// Release any existing preloaded browser
let preloaded = gBrowser._getPreloadedBrowser();
if (preloaded) {
preloaded.remove();
}
// Create a fresh preloaded browser
gBrowser._createPreloadBrowser();
await BrowserTestUtils.crashBrowser(gBrowser._preloadedBrowser, false);
Assert.ok(!gBrowser._preloadedBrowser);
});

Просмотреть файл

@ -143,6 +143,10 @@ function log(message) {
// This also prevents us from handling reloads with hashes twice
let gLastSearch = null;
// Keep track of the original window we were loaded in
// so we don't handle requests for other windows.
let gOriginalWindow = null;
/**
* Since most codes are in the URL, we can handle them via
* a progress listener.
@ -151,6 +155,9 @@ var webProgressListener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
onLocationChange(aWebProgress, aRequest, aLocation, aFlags)
{
if (aWebProgress.DOMWindow && (aWebProgress.DOMWindow != gOriginalWindow)) {
return;
}
try {
if (!aWebProgress.isTopLevel ||
// Not a URL
@ -231,9 +238,9 @@ function onPageLoad(event) {
uri.spec == gLastSearch) {
return;
}
var queries = new URLSearchParams(doc.location.search);
var queries = new URLSearchParams(doc.location.search.toLowerCase());
// For Bing, QBRE form code is used for all follow-on search
if (queries.get("form") != "QBRE") {
if (queries.get("form") != "qbre") {
return;
}
if (parseCookies(doc.cookie).SRCHS == "PC=MOZI") {
@ -263,6 +270,8 @@ addEventListener("DOMContentLoaded", onPageLoad, false);
docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebProgress)
.addProgressListener(webProgressListener, Ci.nsIWebProgress.NOTIFY_LOCATION);
gOriginalWindow = content;
let gDisabled = false;
addMessageListener(kShutdownMsg, () => {

Просмотреть файл

@ -7,7 +7,7 @@
<Description about="urn:mozilla:install-manifest">
<em:id>followonsearch@mozilla.com</em:id>
<em:name>Follow-on Search Telemetry</em:name>
<em:version>0.9.0</em:version>
<em:version>0.9.1</em:version>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>

Просмотреть файл

@ -102,8 +102,12 @@ menu.subviewbutton > .menu-right:-moz-locale-dir(rtl) {
photonpanelmultiview .subviewbutton > .toolbarbutton-text,
photonpanelmultiview .subviewbutton > .toolbarbutton-icon,
photonpanelmultiview .panel-banner-item > .toolbarbutton-multiline-text {
padding: 0;
margin: 0;
}
photonpanelmultiview .subviewbutton > .toolbarbutton-icon,
photonpanelmultiview .panel-banner-item > .toolbarbutton-multiline-text {
padding: 0;
}
/* END photon adjustments */

Просмотреть файл

@ -1254,6 +1254,7 @@ photonpanelmultiview .subviewbutton:focus {
}
photonpanelmultiview .subviewbutton > .toolbarbutton-text {
padding: 0;
padding-inline-start: 24px; /* This is 16px for the icon + 8px for the padding as defined above. */
}

Просмотреть файл

@ -2,5 +2,5 @@
- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="context-fill" d="M14 6H6.5l3-3a.967.967 0 0 0 0-1.4L8.7.7a.967.967 0 0 0-1.4 0L.7 7.3a.967.967 0 0 0 0 1.4l6.6 6.6a.967.967 0 0 0 1.4 0l.8-.8a.965.965 0 0 0 0-1.4l-3-3.1H14c.6 0 1-.2 1-.8V7a.945.945 0 0 0-1-1z"/>
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M14 6H6.5l3-3a.967.967 0 0 0 0-1.4L8.7.7a.967.967 0 0 0-1.4 0L.7 7.3a.967.967 0 0 0 0 1.4l6.6 6.6a.967.967 0 0 0 1.4 0l.8-.8a.965.965 0 0 0 0-1.4l-3-3.1H14c.6 0 1-.2 1-.8V7a.945.945 0 0 0-1-1z"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 530 B

После

Ширина:  |  Высота:  |  Размер: 566 B

Просмотреть файл

@ -152,8 +152,12 @@ menu.subviewbutton > .menu-right:-moz-locale-dir(rtl) {
photonpanelmultiview .subviewbutton > .toolbarbutton-text,
photonpanelmultiview .subviewbutton > .toolbarbutton-icon,
photonpanelmultiview .panel-banner-item > .toolbarbutton-multiline-text {
padding: 0;
margin: 0;
}
photonpanelmultiview .subviewbutton > .toolbarbutton-icon,
photonpanelmultiview .panel-banner-item > .toolbarbutton-multiline-text {
padding: 0;
}
/* END photon adjustments */

Просмотреть файл

@ -322,11 +322,6 @@ OptionsPanel.prototype = {
label: "Enable new debugger frontend",
id: "devtools-new-debugger",
parentId: "debugger-options"
}, {
pref: "devtools.layoutview.enabled",
label: "Enable layout panel",
id: "devtools-layout-panel",
parentId: "inspector-options"
}];
let createPreferenceOption = ({pref, label, id}) => {

Просмотреть файл

@ -11,10 +11,8 @@ Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
this);
Services.prefs.setBoolPref("devtools.layoutview.enabled", true);
Services.prefs.setIntPref("devtools.toolbox.footer.height", 350);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.layoutview.enabled");
Services.prefs.clearUserPref("devtools.toolbox.footer.height");
});

Просмотреть файл

@ -16,11 +16,9 @@ Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-redux-head.js",
this);
Services.prefs.setBoolPref("devtools.layoutview.enabled", true);
Services.prefs.setBoolPref("devtools.promote.layoutview.showPromoteBar", false);
Services.prefs.setIntPref("devtools.toolbox.footer.height", 350);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.layoutview.enabled");
Services.prefs.clearUserPref("devtools.promote.layoutview.showPromoteBar");
Services.prefs.clearUserPref("devtools.toolbox.footer.height");
});

Просмотреть файл

@ -624,14 +624,12 @@ Inspector.prototype = {
INSPECTOR_L10N.getStr("inspector.sidebar.computedViewTitle"),
defaultTab == "computedview");
if (Services.prefs.getBoolPref("devtools.layoutview.enabled")) {
// Grid and layout panels aren't lazy-loaded as their module end up
// calling inspector.addSidebarTab
this.gridInspector = new GridInspector(this, this.panelWin);
// Grid and layout panels aren't lazy-loaded as their module end up
// calling inspector.addSidebarTab
this.gridInspector = new GridInspector(this, this.panelWin);
const LayoutView = this.browserRequire("devtools/client/inspector/layout/layout");
this.layoutview = new LayoutView(this, this.panelWin);
}
const LayoutView = this.browserRequire("devtools/client/inspector/layout/layout");
this.layoutview = new LayoutView(this, this.panelWin);
if (this.target.form.animationsActor) {
this.sidebar.addFrameTab(

Просмотреть файл

@ -114,7 +114,7 @@ function* openEyedropper(view, swatch) {
swatch.click();
yield onColorPickerReady;
let dropperButton = tooltip.doc.querySelector("#eyedropper-button");
let dropperButton = tooltip.container.querySelector("#eyedropper-button");
info("Click on the eyedropper icon");
let onOpened = tooltip.once("eyedropper-opened");

Просмотреть файл

@ -31,7 +31,7 @@ add_task(function* () {
swatchEl.click();
yield onColorPickerReady;
button = cPicker.tooltip.doc.querySelector("#eyedropper-button");
button = cPicker.tooltip.container.querySelector("#eyedropper-button");
ok(isDisabled(button), "The button is disabled in the color picker");
info("Navigate to a HTML document");
@ -55,7 +55,7 @@ add_task(function* () {
swatchEl.click();
yield onColorPickerReady;
button = cPicker.tooltip.doc.querySelector("#eyedropper-button");
button = cPicker.tooltip.container.querySelector("#eyedropper-button");
ok(!isDisabled(button), "The button is enabled in the color picker");
});

Просмотреть файл

@ -4,8 +4,6 @@
# LOCALIZATION NOTE This file contains the Layout Inspector strings.
# The Layout Inspector is a panel accessible in the Inspector sidebar.
# The Layout Inspector may need to be enabled in about:config by setting
# devtools.layoutview.enabled to true.
# LOCALIZATION NOTE (layout.cannotShowGridOutline, layout.cannotSHowGridOutline.title):
# In the case where the grid outline cannot be effectively displayed.

Просмотреть файл

@ -8,10 +8,9 @@
const { Ci } = require("chrome");
const Services = require("Services");
loader.lazyRequireGetter(this, "HarCollector", "devtools/client/netmonitor/har/har-collector", true);
loader.lazyRequireGetter(this, "HarExporter", "devtools/client/netmonitor/har/har-exporter", true);
loader.lazyRequireGetter(this, "HarUtils", "devtools/client/netmonitor/har/har-utils", true);
const { HarCollector } = require("./har-collector");
const { HarExporter } = require("./har-exporter");
const { HarUtils } = require("./har-utils");
const prefDomain = "devtools.netmonitor.har.";

Просмотреть файл

@ -8,7 +8,6 @@ const Services = require("Services");
const appInfo = Services.appinfo;
const { LocalizationHelper } = require("devtools/shared/l10n");
const { CurlUtils } = require("devtools/client/shared/curl");
const { getLongString } = require("../connector/index");
const {
getFormDataSections,
getUrlQuery,
@ -270,7 +269,7 @@ HarBuilder.prototype = {
file.requestHeaders,
file.requestHeadersFromUploadStream,
file.requestPostData,
getLongString,
this._options.getString,
).then(formDataSections => {
formDataSections.forEach(section => {
let paramsArray = parseQueryString(section);

Просмотреть файл

@ -84,15 +84,16 @@ HarCollector.prototype = {
// the page loaded.
// If some new requests appears in the meantime the promise will
// be rejected and we need to wait for responses all over again.
return this.waitForTimeout().then(() => {
this.pageLoadDeferred = this.waitForTimeout().then(() => {
// Page loaded!
}, () => {
trace.log("HarCollector.waitForResponses; NEW requests " +
"appeared during page timeout!");
// New requests executed, let's wait again.
return this.waitForResponses();
});
return this.pageLoadDeferred;
});
},
@ -112,10 +113,11 @@ HarCollector.prototype = {
trace.log("HarCollector.waitForTimeout; " + timeout);
return new Promise((resolve) => {
return new Promise((resolve, reject) => {
if (timeout <= 0) {
resolve();
}
this.pageLoadReject = reject;
this.pageLoadTimeout = setTimeout(() => {
trace.log("HarCollector.onPageLoadTimeout;");
resolve();
@ -133,9 +135,9 @@ HarCollector.prototype = {
}
// Reject the current page load promise
if (this.pageLoadDeferred) {
this.pageLoadDeferred.reject();
this.pageLoadDeferred = null;
if (this.pageLoadReject) {
this.pageLoadReject();
this.pageLoadReject = null;
}
},
@ -440,6 +442,7 @@ function waitForAll(promises) {
if (promises.length) {
return waitForAll(promises);
}
return undefined;
});
}

Просмотреть файл

@ -6,7 +6,7 @@
const Services = require("Services");
loader.lazyRequireGetter(this, "HarAutomation", "devtools/client/netmonitor/har/har-automation", true);
loader.lazyRequireGetter(this, "HarAutomation", "devtools/client/netmonitor/src/har/har-automation", true);
// Map of all created overlays. There is always one instance of
// an overlay per Toolbox instance (i.e. one per browser tab).

Просмотреть файл

@ -68,9 +68,6 @@ pref("devtools.inspector.colorWidget.enabled", false);
// Enable the Font Inspector
pref("devtools.fontinspector.enabled", true);
// Enable the Layout View
pref("devtools.layoutview.enabled", false);
// Counter to promote the inspector layout view.
// @remove after release 56 (See Bug 1355747)
pref("devtools.promote.layoutview", 1);

Просмотреть файл

@ -143,7 +143,12 @@ TableWidget.prototype = {
*/
set selectedRow(id) {
for (let column of this.columns.values()) {
column.selectRow(id[this.uniqueId] || id);
if (id) {
column.selectRow(id[this.uniqueId] || id);
} else {
column.selectedRow = null;
column.selectRow(null);
}
}
},
@ -853,7 +858,8 @@ TableWidget.prototype = {
column.remove(item);
column.updateZebra();
}
if (this.items.size == 0) {
if (this.items.size === 0) {
this.selectedRow = null;
this.tbody.setAttribute("empty", "empty");
}
@ -896,6 +902,8 @@ TableWidget.prototype = {
this.tbody.setAttribute("empty", "empty");
this.setPlaceholderText(this.emptyText);
this.selectedRow = null;
this.emit(EVENTS.TABLE_CLEARED, this);
},
@ -1247,15 +1255,16 @@ Column.prototype = {
*/
selectRowAt: function (index) {
if (this.selectedRow != null) {
this.cells[this.items[this.selectedRow]].toggleClass("theme-selected");
}
if (index < 0) {
this.selectedRow = null;
return;
this.cells[this.items[this.selectedRow]].classList.remove("theme-selected");
}
let cell = this.cells[index];
cell.toggleClass("theme-selected");
this.selectedRow = cell.id;
if (cell) {
cell.classList.add("theme-selected");
this.selectedRow = cell.id;
} else {
this.selectedRow = null;
}
},
/**
@ -1419,7 +1428,6 @@ Column.prototype = {
this.cells = [];
this.items = {};
this._itemsDirty = false;
this.selectedRow = null;
while (this.header.nextSibling) {
this.header.nextSibling.remove();
}
@ -1450,7 +1458,7 @@ Column.prototype = {
}
if (this.selectedRow) {
this.cells[this.items[this.selectedRow]].toggleClass("theme-selected");
this.cells[this.items[this.selectedRow]].classList.remove("theme-selected");
}
this.items = {};
// Otherwise, just use the sorted array passed to update the cells value.
@ -1460,7 +1468,7 @@ Column.prototype = {
this.cells[i].id = item[this.uniqueId];
});
if (this.selectedRow) {
this.cells[this.items[this.selectedRow]].toggleClass("theme-selected");
this.cells[this.items[this.selectedRow]].classList.add("theme-selected");
}
this._itemsDirty = false;
this.updateZebra();
@ -1474,7 +1482,9 @@ Column.prototype = {
if (!cell.hidden) {
i++;
}
cell.toggleClass("even", !(i % 2));
let even = !(i % 2);
cell.classList.toggle("even", even);
}
},
@ -1610,8 +1620,8 @@ Cell.prototype = {
return this._value;
},
toggleClass: function (className, condition) {
this.label.classList.toggle(className, condition);
get classList() {
return this.label.classList;
},
/**

Просмотреть файл

@ -26,7 +26,7 @@ add_task(function* () {
for (let i = 0; i < UPDATE_COUNT; i++) {
info(`Performing update #${i}`);
updates.push(gUI.once("sidebar-updated"));
gUI.displayObjectSidebar();
gUI.updateObjectSidebar();
}
yield promise.all(updates);

Просмотреть файл

@ -113,8 +113,8 @@ function StorageUI(front, target, panelWin, toolbox) {
cellContextMenuId: "storage-table-popup"
});
this.displayObjectSidebar = this.displayObjectSidebar.bind(this);
this.table.on(TableWidget.EVENTS.ROW_SELECTED, this.displayObjectSidebar);
this.updateObjectSidebar = this.updateObjectSidebar.bind(this);
this.table.on(TableWidget.EVENTS.ROW_SELECTED, this.updateObjectSidebar);
this.handleScrollEnd = this.handleScrollEnd.bind(this);
this.table.on(TableWidget.EVENTS.SCROLL_END, this.handleScrollEnd);
@ -216,7 +216,7 @@ StorageUI.prototype = {
},
destroy: function () {
this.table.off(TableWidget.EVENTS.ROW_SELECTED, this.displayObjectSidebar);
this.table.off(TableWidget.EVENTS.ROW_SELECTED, this.updateObjectSidebar);
this.table.off(TableWidget.EVENTS.SCROLL_END, this.handleScrollEnd);
this.table.off(TableWidget.EVENTS.CELL_EDIT, this.editItem);
this.table.destroy();
@ -319,17 +319,16 @@ StorageUI.prototype = {
* being removed was selected.
*/
removeItemFromTable: function (name) {
if (this.table.isSelected(name)) {
if (this.table.isSelected(name) && this.table.items.size > 1) {
if (this.table.selectedIndex == 0) {
this.table.selectNextRow();
} else {
this.table.selectPreviousRow();
}
this.table.remove(name);
this.displayObjectSidebar();
} else {
this.table.remove(name);
}
this.table.remove(name);
this.updateObjectSidebar();
},
/**
@ -666,21 +665,25 @@ StorageUI.prototype = {
* Populates the selected entry from the table in the sidebar for a more
* detailed view.
*/
displayObjectSidebar: Task.async(function* () {
updateObjectSidebar: Task.async(function* () {
let item = this.table.selectedRow;
if (!item) {
// Make sure that sidebar is hidden and return
this.sidebar.hidden = true;
this.updateSidebarToggleButton();
return;
}
let value;
// Get the string value (async action) and the update the UI synchronously.
let value;
if (item.name && item.valueActor) {
if (item && item.name && item.valueActor) {
value = yield item.valueActor.string();
}
// Bail if the selectedRow is no longer selected, the item doesn't exist or the state
// changed in another way during the above yield.
if (this.table.items.size === 0 ||
!item ||
!this.table.selectedRow ||
item.uniqueKey !== this.table.selectedRow.uniqueKey) {
this.hideSidebar();
return;
}
// Start updating the UI. Everything is sync beyond this point.
if (this.sidebarToggledOpen === null || this.sidebarToggledOpen === true) {
this.sidebar.hidden = false;
@ -979,7 +982,7 @@ StorageUI.prototype = {
case REASON.UPDATE:
this.table.update(item);
if (item == this.table.selectedRow && !this.sidebar.hidden) {
this.displayObjectSidebar();
this.updateObjectSidebar();
}
break;
}

Просмотреть файл

@ -8,8 +8,6 @@
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const EventEmitter = require("devtools/shared/event-emitter");
const promise = require("promise");
const defer = require("devtools/shared/defer");
const {LongStringClient} = require("devtools/shared/client/main");
/**
@ -686,31 +684,28 @@ WebConsoleClient.prototype = {
*/
getString: function (stringGrip) {
// Make sure this is a long string.
if (typeof stringGrip != "object" || stringGrip.type != "longString") {
if (typeof stringGrip !== "object" || stringGrip.type !== "longString") {
// Go home string, you're drunk.
return promise.resolve(stringGrip);
return Promise.resolve(stringGrip);
}
// Fetch the long string only once.
if (stringGrip._fullText) {
return stringGrip._fullText.promise;
return stringGrip._fullText;
}
let deferred = stringGrip._fullText = defer();
let { initial, length } = stringGrip;
let longStringClient = this.longString(stringGrip);
return new Promise((resolve, reject) => {
let { initial, length } = stringGrip;
let longStringClient = this.longString(stringGrip);
longStringClient.substring(initial.length, length, response => {
if (response.error) {
DevToolsUtils.reportException("getString",
response.error + ": " + response.message);
deferred.reject(response);
return;
}
deferred.resolve(initial + response.substring);
longStringClient.substring(initial.length, length, response => {
if (response.error) {
DevToolsUtils.reportException("getString",
response.error + ": " + response.message);
reject(response);
}
resolve(initial + response.substring);
});
});
return deferred.promise;
}
};

Просмотреть файл

@ -349,7 +349,7 @@ KeyframeEffectReadOnly::DoUpdateProperties(StyleType* aStyle)
}
mProperties = Move(properties);
UpadateEffectSet();
UpdateEffectSet();
for (AnimationProperty& property : mProperties) {
property.mIsRunningOnCompositor =
@ -961,7 +961,7 @@ KeyframeEffectReadOnly::UpdateTargetRegistration()
EffectSet* effectSet =
EffectSet::GetOrCreateEffectSet(mTarget->mElement, mTarget->mPseudoType);
effectSet->AddEffect(*this);
UpadateEffectSet(effectSet);
UpdateEffectSet(effectSet);
} else {
UnregisterTarget();
}
@ -1832,7 +1832,7 @@ KeyframeEffectReadOnly::ContainsAnimatedScale(const nsIFrame* aFrame) const
}
void
KeyframeEffectReadOnly::UpadateEffectSet(EffectSet* aEffectSet) const
KeyframeEffectReadOnly::UpdateEffectSet(EffectSet* aEffectSet) const
{
EffectSet* effectSet =
aEffectSet ? aEffectSet

Просмотреть файл

@ -464,7 +464,7 @@ private:
static const TimeDuration OverflowRegionRefreshInterval();
void UpadateEffectSet(mozilla::EffectSet* aEffectSet = nullptr) const;
void UpdateEffectSet(mozilla::EffectSet* aEffectSet = nullptr) const;
// FIXME: This flag will be removed in bug 1324966.
bool mIsComposingStyle = false;

Просмотреть файл

@ -370,35 +370,8 @@ AllChildrenIterator::Seek(nsIContent* aChildToFind)
void
AllChildrenIterator::AppendNativeAnonymousChildren()
{
if (nsIFrame* primaryFrame = mOriginalContent->GetPrimaryFrame()) {
// NAC created by the element's primary frame.
AppendNativeAnonymousChildrenFromFrame(primaryFrame);
// NAC created by any other non-primary frames for the element.
AutoTArray<nsIFrame::OwnedAnonBox,8> ownedAnonBoxes;
primaryFrame->AppendOwnedAnonBoxes(ownedAnonBoxes);
for (nsIFrame::OwnedAnonBox& box : ownedAnonBoxes) {
MOZ_ASSERT(box.mAnonBoxFrame->GetContent() == mOriginalContent);
AppendNativeAnonymousChildrenFromFrame(box.mAnonBoxFrame);
}
}
// The root scroll frame is not the primary frame of the root element.
// Detect and handle this case.
if (!(mFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) &&
mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
mOriginalContent->OwnerDoc(), mAnonKids);
}
}
void
AllChildrenIterator::AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame)
{
nsIAnonymousContentCreator* ac = do_QueryFrame(aFrame);
if (ac) {
ac->AppendAnonymousContentTo(mAnonKids, mFlags);
}
nsContentUtils::AppendNativeAnonymousChildren(
mOriginalContent, mAnonKids, mFlags);
}
nsIContent*
@ -542,7 +515,6 @@ StyleChildrenIterator::IsNeeded(const Element* aElement)
return false;
}
nsIContent*
StyleChildrenIterator::GetNextChild()
{

Просмотреть файл

@ -231,8 +231,6 @@ public:
private:
// Helpers.
void AppendNativeAnonymousChildren();
void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame);
const nsIContent* mOriginalContent;
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index

Просмотреть файл

@ -1815,15 +1815,16 @@ _elementName::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult, \
return rv; \
}
#define NS_IMPL_ELEMENT_CLONE_WITH_INIT(_elementName) \
#define EXPAND(...) __VA_ARGS__
#define NS_IMPL_ELEMENT_CLONE_WITH_INIT_HELPER(_elementName, extra_args_) \
nsresult \
_elementName::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult, \
bool aPreallocateChildren) const \
{ \
*aResult = nullptr; \
already_AddRefed<mozilla::dom::NodeInfo> ni = \
RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget(); \
_elementName *it = new _elementName(ni); \
RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget(); \
_elementName *it = new _elementName(ni EXPAND extra_args_); \
if (!it) { \
return NS_ERROR_OUT_OF_MEMORY; \
} \
@ -1841,6 +1842,11 @@ _elementName::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult, \
return rv; \
}
#define NS_IMPL_ELEMENT_CLONE_WITH_INIT(_elementName) \
NS_IMPL_ELEMENT_CLONE_WITH_INIT_HELPER(_elementName, ())
#define NS_IMPL_ELEMENT_CLONE_WITH_INIT_AND_PARSER(_elementName) \
NS_IMPL_ELEMENT_CLONE_WITH_INIT_HELPER(_elementName, (, NOT_FROM_PARSER))
/**
* A macro to implement the getter and setter for a given string
* valued content property. The method uses the generic GetAttr and

Просмотреть файл

@ -61,6 +61,7 @@
#include "nsIPermissionManager.h"
#include "nsMimeTypes.h"
#include "nsNetUtil.h"
#include "nsRFPService.h"
#include "nsStringStream.h"
#include "nsComponentManagerUtils.h"
#include "nsIStringStream.h"
@ -465,6 +466,13 @@ Navigator::GetOscpu(nsAString& aOSCPU, CallerType aCallerType,
ErrorResult& aRv) const
{
if (aCallerType != CallerType::System) {
// If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h
// for details about spoofed values.
if (nsContentUtils::ShouldResistFingerprinting()) {
aOSCPU.AssignLiteral(SPOOFED_OSCPU);
return;
}
const nsAdoptingString& override =
Preferences::GetString("general.oscpu.override");
@ -517,7 +525,7 @@ NS_IMETHODIMP
Navigator::GetProductSub(nsAString& aProductSub)
{
// Legacy build ID hardcoded for backward compatibility (bug 776376)
aProductSub.AssignLiteral("20100101");
aProductSub.AssignLiteral(LEGACY_BUILD_ID);
return NS_OK;
}
@ -639,6 +647,12 @@ Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType,
ErrorResult& aRv) const
{
if (aCallerType != CallerType::System) {
// If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h
// for details about spoofed values.
if (nsContentUtils::ShouldResistFingerprinting()) {
aBuildID.AssignLiteral(LEGACY_BUILD_ID);
return;
}
const nsAdoptingString& override =
Preferences::GetString("general.buildID.override");
@ -1769,6 +1783,12 @@ Navigator::GetPlatform(nsAString& aPlatform, bool aUsePrefOverriddenValue)
MOZ_ASSERT(NS_IsMainThread());
if (aUsePrefOverriddenValue) {
// If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h
// for details about spoofed values.
if (nsContentUtils::ShouldResistFingerprinting()) {
aPlatform.AssignLiteral(SPOOFED_PLATFORM);
return NS_OK;
}
const nsAdoptingString& override =
mozilla::Preferences::GetString("general.platform.override");
@ -1814,6 +1834,12 @@ Navigator::GetAppVersion(nsAString& aAppVersion, bool aUsePrefOverriddenValue)
MOZ_ASSERT(NS_IsMainThread());
if (aUsePrefOverriddenValue) {
// If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h
// for details about spoofed values.
if (nsContentUtils::ShouldResistFingerprinting()) {
aAppVersion.AssignLiteral(SPOOFED_APPVERSION);
return NS_OK;
}
const nsAdoptingString& override =
mozilla::Preferences::GetString("general.appversion.override");
@ -1851,6 +1877,13 @@ Navigator::AppName(nsAString& aAppName, bool aUsePrefOverriddenValue)
MOZ_ASSERT(NS_IsMainThread());
if (aUsePrefOverriddenValue) {
// If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h
// for details about spoofed values.
if (nsContentUtils::ShouldResistFingerprinting()) {
aAppName.AssignLiteral(SPOOFED_APPNAME);
return;
}
const nsAdoptingString& override =
mozilla::Preferences::GetString("general.appname.override");
@ -1876,7 +1909,10 @@ Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow,
{
MOZ_ASSERT(NS_IsMainThread());
if (!aIsCallerChrome) {
// We will skip the override and pass to httpHandler to get spoofed userAgent
// when 'privacy.resistFingerprinting' is true.
if (!aIsCallerChrome &&
!nsContentUtils::ShouldResistFingerprinting()) {
const nsAdoptingString& override =
mozilla::Preferences::GetString("general.useragent.override");
@ -1901,7 +1937,11 @@ Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow,
CopyASCIItoUTF16(ua, aUserAgent);
if (!aWindow) {
// When the caller is content, we will always return spoofed userAgent and
// ignore the User-Agent header from the document channel when
// 'privacy.resistFingerprinting' is true.
if (!aWindow ||
(nsContentUtils::ShouldResistFingerprinting() && !aIsCallerChrome)) {
return NS_OK;
}

Просмотреть файл

@ -10243,6 +10243,45 @@ nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
}
}
static void
AppendNativeAnonymousChildrenFromFrame(
nsIFrame* aFrame,
nsTArray<nsIContent*>& aKids,
uint32_t aFlags)
{
if (nsIAnonymousContentCreator* ac = do_QueryFrame(aFrame)) {
ac->AppendAnonymousContentTo(aKids, aFlags);
}
}
/* static */ void
nsContentUtils::AppendNativeAnonymousChildren(
const nsIContent* aContent,
nsTArray<nsIContent*>& aKids,
uint32_t aFlags)
{
if (nsIFrame* primaryFrame = aContent->GetPrimaryFrame()) {
// NAC created by the element's primary frame.
AppendNativeAnonymousChildrenFromFrame(primaryFrame, aKids, aFlags);
// NAC created by any other non-primary frames for the element.
AutoTArray<nsIFrame::OwnedAnonBox, 8> ownedAnonBoxes;
primaryFrame->AppendOwnedAnonBoxes(ownedAnonBoxes);
for (nsIFrame::OwnedAnonBox& box : ownedAnonBoxes) {
MOZ_ASSERT(box.mAnonBoxFrame->GetContent() == aContent);
AppendNativeAnonymousChildrenFromFrame(box.mAnonBoxFrame, aKids, aFlags);
}
}
// The root scroll frame is not the primary frame of the root element.
// Detect and handle this case.
if (!(aFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) &&
aContent == aContent->OwnerDoc()->GetRootElement()) {
AppendDocumentLevelNativeAnonymousContentTo(aContent->OwnerDoc(), aKids);
}
}
/* static */ void
nsContentUtils::GetContentPolicyTypeForUIImageLoading(nsIContent* aLoadingNode,
nsIPrincipal** aLoadingPrincipal,

Просмотреть файл

@ -2931,6 +2931,16 @@ public:
nsIDocument* aDocument,
nsTArray<nsIContent*>& aElements);
/**
* Appends all native anonymous content subtree roots generated by `aContent`
* to `aKids`.
*
* See `AllChildrenIterator` for the description of the `aFlags` parameter.
*/
static void AppendNativeAnonymousChildren(const nsIContent* aContent,
nsTArray<nsIContent*>& aKids,
uint32_t aFlags);
/**
* Returns the content policy type that should be used for loading images
* for displaying in the UI. The sources of such images can be <xul:image>,

Просмотреть файл

@ -244,6 +244,14 @@ public:
return IsInNativeAnonymousSubtree() || (!IsInShadowTree() && GetBindingParent() != nullptr);
}
/*
* Return true if this node is the shadow root of an use-element shadow tree.
*/
bool IsRootOfUseElementShadowTree() const {
return GetParent() && GetParent()->IsSVGElement(nsGkAtoms::use) &&
IsRootOfAnonymousSubtree();
}
/**
* Return true iff this node is in an HTML document (in the HTML5 sense of
* the term, i.e. not in an XHTML/XML document).

Просмотреть файл

@ -87,6 +87,7 @@
#include "nsCycleCollectionNoteRootCallback.h"
#include "GeckoProfiler.h"
#include "mozilla/IdleTaskRunner.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -120,7 +121,7 @@ const size_t gStackSize = 8192;
#define NS_CC_SKIPPABLE_DELAY 250 // ms
// ForgetSkippable is usually fast, so we can use small budgets.
// This isn't a real budget but a hint to CollectorRunner whether there
// This isn't a real budget but a hint to IdleTaskRunner whether there
// is enough time to call ForgetSkippable.
static const int64_t kForgetSkippableSliceDuration = 2;
@ -149,16 +150,14 @@ static const uint32_t kMaxICCDuration = 2000; // ms
// Large value used to specify that a script should run essentially forever
#define NS_UNLIMITED_SCRIPT_RUNTIME (0x40000000LL << 32)
class CollectorRunner;
// if you add statics here, add them to the list in StartupJSEnvironment
static nsITimer *sGCTimer;
static nsITimer *sShrinkingGCTimer;
static StaticRefPtr<CollectorRunner> sCCRunner;
static StaticRefPtr<CollectorRunner> sICCRunner;
static StaticRefPtr<IdleTaskRunner> sCCRunner;
static StaticRefPtr<IdleTaskRunner> sICCRunner;
static nsITimer *sFullGCTimer;
static StaticRefPtr<CollectorRunner> sInterSliceGCRunner;
static StaticRefPtr<IdleTaskRunner> sInterSliceGCRunner;
static TimeStamp sLastCCEndTime;
@ -228,183 +227,6 @@ static int32_t sExpensiveCollectorPokes = 0;
static const int32_t kPokesBetweenExpensiveCollectorTriggers = 5;
static TimeDuration sGCUnnotifiedTotalTime;
// Return true if some meaningful work was done.
typedef bool (*CollectorRunnerCallback) (TimeStamp aDeadline, void* aData);
// Repeating callback runner for CC and GC.
class CollectorRunner final : public IdleRunnable
{
public:
static already_AddRefed<CollectorRunner>
Create(CollectorRunnerCallback aCallback, uint32_t aDelay,
int64_t aBudget, bool aRepeating, void* aData = nullptr)
{
if (sShuttingDown) {
return nullptr;
}
RefPtr<CollectorRunner> runner =
new CollectorRunner(aCallback, aDelay, aBudget, aRepeating, aData);
runner->Schedule(false); // Initial scheduling shouldn't use idle dispatch.
return runner.forget();
}
NS_IMETHOD Run() override
{
if (!mCallback) {
return NS_OK;
}
// Deadline is null when called from timer.
bool deadLineWasNull = mDeadline.IsNull();
bool didRun = false;
if (deadLineWasNull || ((TimeStamp::Now() + mBudget) < mDeadline)) {
CancelTimer();
didRun = mCallback(mDeadline, mData);
}
if (mCallback && (mRepeating || !didRun)) {
// If we didn't do meaningful work, don't schedule using immediate
// idle dispatch, since that could lead to a loop until the idle
// period ends.
Schedule(didRun);
}
return NS_OK;
}
static void
TimedOut(nsITimer* aTimer, void* aClosure)
{
RefPtr<CollectorRunner> runnable = static_cast<CollectorRunner*>(aClosure);
runnable->Run();
}
void SetDeadline(mozilla::TimeStamp aDeadline) override
{
mDeadline = aDeadline;
};
void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override
{
if (mTimerActive) {
return;
}
mTarget = aTarget;
if (!mTimer) {
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
} else {
mTimer->Cancel();
}
if (mTimer) {
mTimer->SetTarget(mTarget);
mTimer->InitWithFuncCallback(TimedOut, this, aDelay,
nsITimer::TYPE_ONE_SHOT);
mTimerActive = true;
}
}
nsresult Cancel() override
{
CancelTimer();
mTimer = nullptr;
mScheduleTimer = nullptr;
mCallback = nullptr;
return NS_OK;
}
static void
ScheduleTimedOut(nsITimer* aTimer, void* aClosure)
{
RefPtr<CollectorRunner> runnable = static_cast<CollectorRunner*>(aClosure);
runnable->Schedule(true);
}
void Schedule(bool aAllowIdleDispatch)
{
if (!mCallback) {
return;
}
if (sShuttingDown) {
Cancel();
return;
}
mDeadline = TimeStamp();
TimeStamp now = TimeStamp::Now();
TimeStamp hint = nsRefreshDriver::GetIdleDeadlineHint(now);
if (hint != now) {
// RefreshDriver is ticking, let it schedule the idle dispatch.
nsRefreshDriver::DispatchIdleRunnableAfterTick(this, mDelay);
// Ensure we get called at some point, even if RefreshDriver is stopped.
SetTimer(mDelay, mTarget);
} else {
// RefreshDriver doesn't seem to be running.
if (aAllowIdleDispatch) {
nsCOMPtr<nsIRunnable> runnable = this;
NS_IdleDispatchToCurrentThread(runnable.forget(), mDelay);
SetTimer(mDelay, mTarget);
} else {
if (!mScheduleTimer) {
mScheduleTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
if (!mScheduleTimer) {
return;
}
} else {
mScheduleTimer->Cancel();
}
// We weren't allowed to do idle dispatch immediately, do it after a
// short timeout.
mScheduleTimer->InitWithFuncCallback(ScheduleTimedOut, this, 16,
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY);
}
}
}
private:
explicit CollectorRunner(CollectorRunnerCallback aCallback,
uint32_t aDelay, int64_t aBudget,
bool aRepeating, void* aData)
: mCallback(aCallback), mDelay(aDelay)
, mBudget(TimeDuration::FromMilliseconds(aBudget))
, mRepeating(aRepeating), mTimerActive(false), mData(aData)
{
}
~CollectorRunner()
{
CancelTimer();
}
void CancelTimer()
{
nsRefreshDriver::CancelIdleRunnable(this);
if (mTimer) {
mTimer->Cancel();
}
if (mScheduleTimer) {
mScheduleTimer->Cancel();
}
mTimerActive = false;
}
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsITimer> mScheduleTimer;
nsCOMPtr<nsIEventTarget> mTarget;
CollectorRunnerCallback mCallback;
uint32_t mDelay;
TimeStamp mDeadline;
TimeDuration mBudget;
bool mRepeating;
bool mTimerActive;
void* mData;
};
static const char*
ProcessNameForCollectorLog()
{
@ -1780,7 +1602,7 @@ nsJSContext::GetMaxCCSliceTimeSinceClear()
}
static bool
ICCRunnerFired(TimeStamp aDeadline, void* aData)
ICCRunnerFired(TimeStamp aDeadline)
{
if (sDidShutdown) {
return false;
@ -1821,8 +1643,8 @@ nsJSContext::BeginCycleCollectionCallback()
// Create an ICC timer even if ICC is globally disabled, because we could be manually triggering
// an incremental collection, and we want to be sure to finish it.
sICCRunner = CollectorRunner::Create(ICCRunnerFired, kICCIntersliceDelay,
kIdleICCSliceBudget, true);
sICCRunner = IdleTaskRunner::Create(ICCRunnerFired, kICCIntersliceDelay,
kIdleICCSliceBudget, true, []{ return sShuttingDown; });
}
static_assert(NS_GC_DELAY > kMaxICCDuration, "A max duration ICC shouldn't reduce GC delay to 0");
@ -2034,11 +1856,9 @@ GCTimerFired(nsITimer *aTimer, void *aClosure)
{
nsJSContext::KillGCTimer();
// Now start the actual GC after initial timer has fired.
sInterSliceGCRunner = CollectorRunner::Create(InterSliceGCRunnerFired,
NS_INTERSLICE_GC_DELAY,
sActiveIntersliceGCBudget,
false,
aClosure);
sInterSliceGCRunner = IdleTaskRunner::Create([aClosure](TimeStamp aDeadline) {
return InterSliceGCRunnerFired(aDeadline, aClosure);
}, NS_INTERSLICE_GC_DELAY, sActiveIntersliceGCBudget, false, []{ return sShuttingDown; });
}
// static
@ -2062,7 +1882,7 @@ ShouldTriggerCC(uint32_t aSuspected)
}
static bool
CCRunnerFired(TimeStamp aDeadline, void* aData)
CCRunnerFired(TimeStamp aDeadline)
{
if (sDidShutdown) {
return false;
@ -2214,13 +2034,13 @@ nsJSContext::RunNextCollectorTimer()
if (sCCRunner) {
if (ReadyToTriggerExpensiveCollectorTimer()) {
CCRunnerFired(TimeStamp(), nullptr);
CCRunnerFired(TimeStamp());
}
return;
}
if (sICCRunner) {
ICCRunnerFired(TimeStamp(), nullptr);
ICCRunnerFired(TimeStamp());
return;
}
}
@ -2327,8 +2147,9 @@ nsJSContext::MaybePokeCC()
nsCycleCollector_dispatchDeferredDeletion();
sCCRunner =
CollectorRunner::Create(CCRunnerFired, NS_CC_SKIPPABLE_DELAY,
kForgetSkippableSliceDuration, true);
IdleTaskRunner::Create(CCRunnerFired, NS_CC_SKIPPABLE_DELAY,
kForgetSkippableSliceDuration, true,
[]{ return sShuttingDown; });
}
}
@ -2508,8 +2329,9 @@ DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, const JS::GCDescrip
nsJSContext::KillInterSliceGCRunner();
if (!sShuttingDown && !aDesc.isComplete_) {
sInterSliceGCRunner =
CollectorRunner::Create(InterSliceGCRunnerFired, NS_INTERSLICE_GC_DELAY,
sActiveIntersliceGCBudget, false);
IdleTaskRunner::Create([](TimeStamp aDeadline) {
return InterSliceGCRunnerFired(aDeadline, nullptr);
}, NS_INTERSLICE_GC_DELAY, sActiveIntersliceGCBudget, false, []{ return sShuttingDown; });
}
if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {

7
dom/cache/Connection.cpp поставляемый
Просмотреть файл

@ -62,6 +62,13 @@ Connection::AsyncClose(mozIStorageCompletionCallback*)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
Connection::SpinningSynchronousClose()
{
// not supported
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
Connection::AsyncClone(bool, mozIStorageCompletionCallback*)
{

Просмотреть файл

@ -24,6 +24,7 @@ NS_IMPL_ISUPPORTS(MediaShutdownManager, nsIAsyncShutdownBlocker)
MediaShutdownManager::MediaShutdownManager()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(sInitPhase == NotInited);
}
MediaShutdownManager::~MediaShutdownManager()
@ -35,11 +36,17 @@ MediaShutdownManager::~MediaShutdownManager()
// may interfere with our shutdown listener.
StaticRefPtr<MediaShutdownManager> MediaShutdownManager::sInstance;
MediaShutdownManager::InitPhase MediaShutdownManager::sInitPhase = MediaShutdownManager::NotInited;
MediaShutdownManager&
MediaShutdownManager::Instance()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(sInstance);
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
if (!sInstance) {
MOZ_CRASH_UNSAFE_PRINTF("sInstance is null. sInitPhase=%d", int(sInitPhase));
}
#endif
return *sInstance;
}
@ -65,32 +72,34 @@ void
MediaShutdownManager::InitStatics()
{
MOZ_ASSERT(NS_IsMainThread());
static bool sInitDone = false;
if (sInitDone) {
if (sInitPhase != NotInited) {
return;
}
sInitDone = true;
sInstance = new MediaShutdownManager();
MOZ_DIAGNOSTIC_ASSERT(sInstance);
nsresult rv = GetShutdownBarrier()->AddBlocker(
sInstance, NS_LITERAL_STRING(__FILE__), __LINE__,
NS_LITERAL_STRING("MediaShutdownManager shutdown"));
if (NS_FAILED(rv)) {
LOGW("Failed to add shutdown blocker! rv=%x", uint32_t(rv));
sInstance->mError = rv;
sInitPhase = InitFailed;
return;
}
sInitPhase = InitSucceeded;
}
void
MediaShutdownManager::RemoveBlocker()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mIsDoingXPCOMShutDown);
MOZ_DIAGNOSTIC_ASSERT(sInitPhase == XPCOMShutdownStarted);
MOZ_ASSERT(mDecoders.Count() == 0);
GetShutdownBarrier()->RemoveBlocker(this);
// Clear our singleton reference. This will probably delete
// this instance, so don't deref |this| clearing sInstance.
sInitPhase = XPCOMShutdownEnded;
sInstance = nullptr;
DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() end."));
}
@ -99,10 +108,10 @@ nsresult
MediaShutdownManager::Register(MediaDecoder* aDecoder)
{
MOZ_ASSERT(NS_IsMainThread());
if (NS_FAILED(mError)) {
if (sInitPhase == InitFailed) {
return NS_ERROR_NOT_INITIALIZED;
}
if (mIsDoingXPCOMShutDown) {
if (sInitPhase == XPCOMShutdownStarted) {
return NS_ERROR_ABORT;
}
// Don't call Register() after you've Unregistered() all the decoders,
@ -122,7 +131,7 @@ MediaShutdownManager::Unregister(MediaDecoder* aDecoder)
return;
}
mDecoders.RemoveEntry(aDecoder);
if (mIsDoingXPCOMShutDown && mDecoders.Count() == 0) {
if (sInitPhase == XPCOMShutdownStarted && mDecoders.Count() == 0) {
RemoveBlocker();
}
}
@ -144,12 +153,13 @@ NS_IMETHODIMP
MediaShutdownManager::BlockShutdown(nsIAsyncShutdownClient*)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(sInstance);
MOZ_DIAGNOSTIC_ASSERT(sInitPhase == InitSucceeded);
MOZ_DIAGNOSTIC_ASSERT(sInstance);
DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() start..."));
// Set this flag to ensure no Register() is allowed when Shutdown() begins.
mIsDoingXPCOMShutDown = true;
sInitPhase = XPCOMShutdownStarted;
auto oldCount = mDecoders.Count();
if (oldCount == 0) {

Просмотреть файл

@ -70,6 +70,16 @@ public:
void Unregister(MediaDecoder* aDecoder);
private:
enum InitPhase
{
NotInited,
InitSucceeded,
InitFailed,
XPCOMShutdownStarted,
XPCOMShutdownEnded
};
static InitPhase sInitPhase;
MediaShutdownManager();
virtual ~MediaShutdownManager();
@ -81,9 +91,6 @@ private:
// in their Shutdown() method, so we'll drop the reference naturally when
// we're shutting down (in the non xpcom-shutdown case).
nsTHashtable<nsRefPtrHashKey<MediaDecoder>> mDecoders;
bool mIsDoingXPCOMShutDown = false;
nsresult mError = NS_OK;
};
} // namespace mozilla

Просмотреть файл

@ -26,7 +26,6 @@
namespace mozilla {
namespace dom {
using base::Thread;
using namespace ipc;
using namespace layers;
using namespace gfx;

Просмотреть файл

@ -10,7 +10,7 @@ load 493915-1.html
load 495794-1.html
load 576612-1.html
load 752784-1.html
skip-if(webrender) load 789075-1.html # bug 1366502 comment 42
skip-if(Android) skip-if(webrender) load 789075-1.html # bug 1366502 comment 42, bug 1374405
skip-if(Android&&AndroidVersion=='22') HTTP load 795892-1.html # bug 1358718
load 844563.html
load 846612.html

Просмотреть файл

@ -4,43 +4,26 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdint.h>
#include "mozilla/ArrayUtils.h"
#include "mozilla/ContentEvents.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/Likely.h"
#include "nsGkAtoms.h"
#include "nsLayoutUtils.h"
#include "nsLayoutStylesheetCache.h"
#include "DOMSVGNumber.h"
#include "DOMSVGLength.h"
#include "nsSVGAngle.h"
#include "nsCOMPtr.h"
#include "nsIPresShell.h"
#include "nsContentUtils.h"
#include "nsIDocument.h"
#include "mozilla/dom/SVGMatrix.h"
#include "DOMSVGPoint.h"
#include "nsIFrame.h"
#include "nsFrameSelection.h"
#include "nsISVGSVGFrame.h" //XXX
#include "mozilla/dom/SVGRect.h"
#include "nsError.h"
#include "nsSVGDisplayableFrame.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "mozilla/dom/SVGSVGElementBinding.h"
#include "nsSVGUtils.h"
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/SVGViewElement.h"
#include "nsStyleUtil.h"
#include "SVGContentUtils.h"
#include "mozilla/EventDispatcher.h"
#include "nsSMILTimeContainer.h"
#include "DOMSVGLength.h"
#include "DOMSVGNumber.h"
#include "DOMSVGPoint.h"
#include "nsLayoutStylesheetCache.h"
#include "nsSVGAngle.h"
#include "nsFrameSelection.h"
#include "nsIFrame.h"
#include "nsISVGSVGFrame.h"
#include "nsSMILAnimationController.h"
#include "nsSMILTypes.h"
#include "nsSMILTimeContainer.h"
#include "nsSVGDisplayableFrame.h"
#include "nsSVGUtils.h"
#include "SVGAngle.h"
#include <algorithm>
#include "prtime.h"
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT_CHECK_PARSER(SVG)
@ -49,13 +32,19 @@ using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
class SVGAnimatedLength;
nsSVGEnumMapping SVGSVGElement::sZoomAndPanMap[] = {
{&nsGkAtoms::disable, SVG_ZOOMANDPAN_DISABLE},
{&nsGkAtoms::magnify, SVG_ZOOMANDPAN_MAGNIFY},
{nullptr, 0}
};
JSObject*
SVGSVGElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
nsSVGElement::EnumInfo SVGSVGElement::sEnumInfo[1] =
{
return SVGSVGElementBinding::Wrap(aCx, this, aGivenProto);
}
{ &nsGkAtoms::zoomAndPan,
sZoomAndPanMap,
SVG_ZOOMANDPAN_MAGNIFY
}
};
NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMSVGTranslatePoint, nsISVGPoint,
mElement)
@ -71,10 +60,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGTranslatePoint)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
SVGSVGElement::~SVGSVGElement()
{
}
DOMSVGPoint*
DOMSVGTranslatePoint::Copy()
{
@ -111,36 +96,12 @@ DOMSVGTranslatePoint::MatrixTransform(SVGMatrix& matrix)
return point.forget();
}
SVGView::SVGView()
JSObject*
SVGSVGElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
mZoomAndPan.Init(SVGSVGElement::ZOOMANDPAN,
SVG_ZOOMANDPAN_MAGNIFY);
mViewBox.Init();
mPreserveAspectRatio.Init();
return SVGSVGElementBinding::Wrap(aCx, this, aGivenProto);
}
nsSVGElement::LengthInfo SVGSVGElement::sLengthInfo[4] =
{
{ &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
{ &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
{ &nsGkAtoms::width, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X },
{ &nsGkAtoms::height, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::Y },
};
nsSVGEnumMapping SVGSVGElement::sZoomAndPanMap[] = {
{&nsGkAtoms::disable, SVG_ZOOMANDPAN_DISABLE},
{&nsGkAtoms::magnify, SVG_ZOOMANDPAN_MAGNIFY},
{nullptr, 0}
};
nsSVGElement::EnumInfo SVGSVGElement::sEnumInfo[1] =
{
{ &nsGkAtoms::zoomAndPan,
sZoomAndPanMap,
SVG_ZOOMANDPAN_MAGNIFY
}
};
//----------------------------------------------------------------------
// nsISupports methods
@ -167,14 +128,20 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(SVGSVGElement)
nsIDOMSVGElement)
NS_INTERFACE_TABLE_TAIL_INHERITING(SVGSVGElementBase)
SVGView::SVGView()
{
mZoomAndPan.Init(SVGSVGElement::ZOOMANDPAN,
SVG_ZOOMANDPAN_MAGNIFY);
mViewBox.Init();
mPreserveAspectRatio.Init();
}
//----------------------------------------------------------------------
// Implementation
SVGSVGElement::SVGSVGElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
FromParser aFromParser)
: SVGSVGElementBase(aNodeInfo),
mViewportWidth(0),
mViewportHeight(0),
mCurrentTranslate(0.0f, 0.0f),
mCurrentScale(1.0f),
mPreviousTranslate(0.0f, 0.0f),
@ -182,33 +149,18 @@ SVGSVGElement::SVGSVGElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo
mStartAnimationOnBindToTree(aFromParser == NOT_FROM_PARSER ||
aFromParser == FROM_PARSER_FRAGMENT ||
aFromParser == FROM_PARSER_XSLT),
mImageNeedsTransformInvalidation(false),
mHasChildrenOnlyTransform(false)
mImageNeedsTransformInvalidation(false)
{
}
SVGSVGElement::~SVGSVGElement()
{
}
//----------------------------------------------------------------------
// nsIDOMNode methods
// From NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSVGElement)
nsresult
SVGSVGElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const
{
*aResult = nullptr;
already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
SVGSVGElement *it = new SVGSVGElement(ni, NOT_FROM_PARSER);
nsCOMPtr<nsINode> kungFuDeathGrip = it;
nsresult rv1 = it->Init();
nsresult rv2 = const_cast<SVGSVGElement*>(this)->CopyInnerTo(it, aPreallocateChildren);
if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
kungFuDeathGrip.swap(*aResult);
}
return NS_FAILED(rv1) ? rv1 : rv2;
}
NS_IMPL_ELEMENT_CLONE_WITH_INIT_AND_PARSER(SVGSVGElement)
//----------------------------------------------------------------------
// nsIDOMSVGSVGElement methods:
@ -236,7 +188,6 @@ SVGSVGElement::Height()
{
return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
}
float
SVGSVGElement::PixelUnitToMillimeterX()
{
@ -260,7 +211,6 @@ SVGSVGElement::ScreenPixelToMillimeterY()
{
return ScreenPixelToMillimeterX();
}
bool
SVGSVGElement::UseCurrentView()
{
@ -442,38 +392,6 @@ SVGSVGElement::CreateSVGTransformFromMatrix(SVGMatrix& matrix)
return transform.forget();
}
//----------------------------------------------------------------------
already_AddRefed<SVGAnimatedRect>
SVGSVGElement::ViewBox()
{
return mViewBox.ToSVGAnimatedRect(this);
}
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
SVGSVGElement::PreserveAspectRatio()
{
return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
}
uint16_t
SVGSVGElement::ZoomAndPan()
{
return mEnumAttributes[ZOOMANDPAN].GetAnimValue();
}
void
SVGSVGElement::SetZoomAndPan(uint16_t aZoomAndPan, ErrorResult& rv)
{
if (aZoomAndPan == SVG_ZOOMANDPAN_DISABLE ||
aZoomAndPan == SVG_ZOOMANDPAN_MAGNIFY) {
mEnumAttributes[ZOOMANDPAN].SetBaseValue(aZoomAndPan, this);
return;
}
rv.ThrowRangeError<MSG_INVALID_ZOOMANDPAN_VALUE_ERROR>();
}
//----------------------------------------------------------------------
// helper method for implementing SetCurrentScale/Translate
@ -490,7 +408,7 @@ SVGSVGElement::SetCurrentScaleTranslate(float s, float x, float y)
s = CURRENT_SCALE_MIN;
else if (s > CURRENT_SCALE_MAX)
s = CURRENT_SCALE_MAX;
// IMPORTANT: If either mCurrentTranslate *or* mCurrentScale is changed then
// mPreviousTranslate_x, mPreviousTranslate_y *and* mPreviousScale must all
// be updated otherwise SVGZoomEvents will end up with invalid data. I.e. an
@ -504,7 +422,7 @@ SVGSVGElement::SetCurrentScaleTranslate(float s, float x, float y)
// remove some of this code?
mPreviousScale = mCurrentScale;
mPreviousTranslate = mCurrentTranslate;
mCurrentScale = s;
mCurrentTranslate = SVGPoint(x, y);
@ -529,6 +447,27 @@ SVGSVGElement::SetCurrentTranslate(float x, float y)
SetCurrentScaleTranslate(mCurrentScale, x, y);
}
//----------------------------------------------------------------------
// SVGZoomAndPanValues
uint16_t
SVGSVGElement::ZoomAndPan()
{
return mEnumAttributes[ZOOMANDPAN].GetAnimValue();
}
void
SVGSVGElement::SetZoomAndPan(uint16_t aZoomAndPan, ErrorResult& rv)
{
if (aZoomAndPan == SVG_ZOOMANDPAN_DISABLE ||
aZoomAndPan == SVG_ZOOMANDPAN_MAGNIFY) {
mEnumAttributes[ZOOMANDPAN].SetBaseValue(aZoomAndPan, this);
return;
}
rv.ThrowRangeError<MSG_INVALID_ZOOMANDPAN_VALUE_ERROR>();
}
//----------------------------------------------------------------------
nsSMILTimeContainer*
SVGSVGElement::GetTimedDocumentRoot()
{
@ -546,175 +485,8 @@ SVGSVGElement::GetTimedDocumentRoot()
// invalid structure
return nullptr;
}
//----------------------------------------------------------------------
// nsIContent methods
NS_IMETHODIMP_(bool)
SVGSVGElement::IsAttributeMapped(const nsIAtom* name) const
{
// We want to map the 'width' and 'height' attributes into style for
// outer-<svg>, except when the attributes aren't set (since their default
// values of '100%' can cause unexpected and undesirable behaviour for SVG
// inline in HTML). We rely on nsSVGElement::UpdateContentStyleRule() to
// prevent mapping of the default values into style (it only maps attributes
// that are set). We also rely on a check in nsSVGElement::
// UpdateContentStyleRule() to prevent us mapping the attributes when they're
// given a <length> value that is not currently recognized by the SVG
// specification.
if (!IsInner() && (name == nsGkAtoms::width || name == nsGkAtoms::height)) {
return true;
}
static const MappedAttributeEntry* const map[] = {
sColorMap,
sFEFloodMap,
sFillStrokeMap,
sFiltersMap,
sFontSpecificationMap,
sGradientStopMap,
sGraphicsMap,
sLightingEffectsMap,
sMarkersMap,
sTextContentElementsMap,
sViewportsMap
};
return FindAttributeDependence(name, map) ||
SVGSVGElementBase::IsAttributeMapped(name);
}
//----------------------------------------------------------------------
// nsIContent methods:
nsresult
SVGSVGElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
if (aVisitor.mEvent->mMessage == eSVGLoad) {
if (mTimedDocumentRoot) {
mTimedDocumentRoot->Begin();
// Set 'resample needed' flag, so that if any script calls a DOM method
// that requires up-to-date animations before our first sample callback,
// we'll force a synchronous sample.
AnimationNeedsResample();
}
}
return SVGSVGElementBase::GetEventTargetParent(aVisitor);
}
bool
SVGSVGElement::IsEventAttributeName(nsIAtom* aName)
{
/* The events in EventNameType_SVGSVG are for events that are only
applicable to outermost 'svg' elements. We don't check if we're an outer
'svg' element in case we're not inserted into the document yet, but since
the target of the events in question will always be the outermost 'svg'
element, this shouldn't cause any real problems.
*/
return nsContentUtils::IsEventAttributeName(aName,
(EventNameType_SVGGraphic | EventNameType_SVGSVG));
}
//----------------------------------------------------------------------
// nsSVGElement overrides
// Helper for GetViewBoxTransform on root <svg> node
// * aLength: internal value for our <svg> width or height attribute.
// * aViewportLength: length of the corresponding dimension of the viewport.
// * aSelf: the outermost <svg> node itself.
// NOTE: aSelf is not an ancestor viewport element, so it can't be used to
// resolve percentage lengths. (It can only be used to resolve
// 'em'/'ex'-valued units).
inline float
ComputeSynthesizedViewBoxDimension(const nsSVGLength2& aLength,
float aViewportLength,
const SVGSVGElement* aSelf)
{
if (aLength.IsPercentage()) {
return aViewportLength * aLength.GetAnimValInSpecifiedUnits() / 100.0f;
}
return aLength.GetAnimValue(const_cast<SVGSVGElement*>(aSelf));
}
//----------------------------------------------------------------------
// public helpers:
gfx::Matrix
SVGSVGElement::GetViewBoxTransform() const
{
float viewportWidth, viewportHeight;
if (IsInner()) {
SVGSVGElement *ctx = GetCtx();
viewportWidth = mLengthAttributes[ATTR_WIDTH].GetAnimValue(ctx);
viewportHeight = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(ctx);
} else {
viewportWidth = mViewportWidth;
viewportHeight = mViewportHeight;
}
if (viewportWidth <= 0.0f || viewportHeight <= 0.0f) {
return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
}
nsSVGViewBoxRect viewBox =
GetViewBoxWithSynthesis(viewportWidth, viewportHeight);
if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
}
return SVGContentUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
viewBox.x, viewBox.y,
viewBox.width, viewBox.height,
GetPreserveAspectRatioWithOverride());
}
void
SVGSVGElement::UpdateHasChildrenOnlyTransform()
{
bool hasChildrenOnlyTransform =
HasViewBoxOrSyntheticViewBox() ||
(IsRoot() && (mCurrentTranslate != SVGPoint(0.0f, 0.0f) ||
mCurrentScale != 1.0f));
mHasChildrenOnlyTransform = hasChildrenOnlyTransform;
}
void
SVGSVGElement::ChildrenOnlyTransformChanged(uint32_t aFlags)
{
// Avoid wasteful calls:
MOZ_ASSERT(!(GetPrimaryFrame()->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
"Non-display SVG frames don't maintain overflow rects");
nsChangeHint changeHint;
bool hadChildrenOnlyTransform = mHasChildrenOnlyTransform;
UpdateHasChildrenOnlyTransform();
if (hadChildrenOnlyTransform != mHasChildrenOnlyTransform) {
// Reconstruct the frame tree to handle stacking context changes:
// XXXjwatt don't do this for root-<svg> or even outer-<svg>?
changeHint = nsChangeHint_ReconstructFrame;
} else {
// We just assume the old and new transforms are different.
changeHint = nsChangeHint(nsChangeHint_UpdateOverflow |
nsChangeHint_ChildrenOnlyTransform);
}
// If we're not reconstructing the frame tree, then we only call
// PostRestyleEvent if we're not being called under reflow to avoid recursing
// to death. See bug 767056 comments 10 and 12. Since our nsSVGOuterSVGFrame
// is being reflowed we're going to invalidate and repaint its entire area
// anyway (which will include our children).
if ((changeHint & nsChangeHint_ReconstructFrame) ||
!(aFlags & eDuringReflow)) {
nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint);
}
}
// nsSVGElement
nsresult
SVGSVGElement::BindToTree(nsIDocument* aDocument,
nsIContent* aParent,
@ -742,7 +514,7 @@ SVGSVGElement::BindToTree(nsIDocument* aDocument,
}
}
nsresult rv = SVGSVGElementBase::BindToTree(aDocument, aParent,
nsresult rv = SVGGraphicsElement::BindToTree(aDocument, aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv,rv);
@ -774,7 +546,88 @@ SVGSVGElement::UnbindFromTree(bool aDeep, bool aNullParent)
mTimedDocumentRoot->SetParent(nullptr);
}
SVGSVGElementBase::UnbindFromTree(aDeep, aNullParent);
SVGGraphicsElement::UnbindFromTree(aDeep, aNullParent);
}
nsSVGAnimatedTransformList*
SVGSVGElement::GetAnimatedTransformList(uint32_t aFlags)
{
if (!(aFlags & DO_ALLOCATE) && mSVGView && mSVGView->mTransforms) {
return mSVGView->mTransforms;
}
return SVGGraphicsElement::GetAnimatedTransformList(aFlags);
}
nsresult
SVGSVGElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
if (aVisitor.mEvent->mMessage == eSVGLoad) {
if (mTimedDocumentRoot) {
mTimedDocumentRoot->Begin();
// Set 'resample needed' flag, so that if any script calls a DOM method
// that requires up-to-date animations before our first sample callback,
// we'll force a synchronous sample.
AnimationNeedsResample();
}
}
return SVGSVGElementBase::GetEventTargetParent(aVisitor);
}
bool
SVGSVGElement::IsEventAttributeName(nsIAtom* aName)
{
/* The events in EventNameType_SVGSVG are for events that are only
applicable to outermost 'svg' elements. We don't check if we're an outer
'svg' element in case we're not inserted into the document yet, but since
the target of the events in question will always be the outermost 'svg'
element, this shouldn't cause any real problems.
*/
return nsContentUtils::IsEventAttributeName(aName,
(EventNameType_SVGGraphic | EventNameType_SVGSVG));
}
//----------------------------------------------------------------------
// public helpers:
int32_t
SVGSVGElement::GetIntrinsicWidth()
{
if (mLengthAttributes[ATTR_WIDTH].IsPercentage()) {
return -1;
}
// Passing |this| as a SVGViewportElement* invokes the variant of GetAnimValue
// that uses the passed argument as the context, but that's fine since we
// know the length isn't a percentage so the context won't be used (and we
// need to pass the element to be able to resolve em/ex units).
float width = mLengthAttributes[ATTR_WIDTH].GetAnimValue(this);
return nsSVGUtils::ClampToInt(width);
}
int32_t
SVGSVGElement::GetIntrinsicHeight()
{
if (mLengthAttributes[ATTR_HEIGHT].IsPercentage()) {
return -1;
}
// Passing |this| as a SVGViewportElement* invokes the variant of GetAnimValue
// that uses the passed argument as the context, but that's fine since we
// know the length isn't a percentage so the context won't be used (and we
// need to pass the element to be able to resolve em/ex units).
float height = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(this);
return nsSVGUtils::ClampToInt(height);
}
void
SVGSVGElement::FlushImageTransformInvalidation()
{
MOZ_ASSERT(!GetParent(), "Should only be called on root node");
MOZ_ASSERT(OwnerDoc()->IsBeingUsedAsImage(),
"Should only be called on image documents");
if (mImageNeedsTransformInvalidation) {
InvalidateTransformNotifyFrame();
mImageNeedsTransformInvalidation = false;
}
}
//----------------------------------------------------------------------
@ -811,223 +664,6 @@ SVGSVGElement::InvalidateTransformNotifyFrame()
}
}
bool
SVGSVGElement::HasPreserveAspectRatio()
{
return HasAttr(kNameSpaceID_None, nsGkAtoms::preserveAspectRatio) ||
mPreserveAspectRatio.IsAnimated();
}
SVGViewElement*
SVGSVGElement::GetCurrentViewElement() const
{
if (mCurrentViewID) {
//XXXsmaug It is unclear how this should work in case we're in Shadow DOM.
nsIDocument* doc = GetUncomposedDoc();
if (doc) {
Element *element = doc->GetElementById(*mCurrentViewID);
if (element && element->IsSVGElement(nsGkAtoms::view)) {
return static_cast<SVGViewElement*>(element);
}
}
}
return nullptr;
}
nsSVGViewBoxRect
SVGSVGElement::GetViewBoxWithSynthesis(
float aViewportWidth, float aViewportHeight) const
{
// The logic here should match HasViewBoxRect().
SVGViewElement* viewElement = GetCurrentViewElement();
if (viewElement && viewElement->mViewBox.HasRect()) {
return viewElement->mViewBox.GetAnimValue();
}
if (mSVGView && mSVGView->mViewBox.HasRect()) {
return mSVGView->mViewBox.GetAnimValue();
}
if (mViewBox.HasRect()) {
return mViewBox.GetAnimValue();
}
if (ShouldSynthesizeViewBox()) {
// Special case -- fake a viewBox, using height & width attrs.
// (Use |this| as context, since if we get here, we're outermost <svg>.)
return nsSVGViewBoxRect(0, 0,
ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_WIDTH],
mViewportWidth, this),
ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_HEIGHT],
mViewportHeight, this));
}
// No viewBox attribute, so we shouldn't auto-scale. This is equivalent
// to having a viewBox that exactly matches our viewport size.
return nsSVGViewBoxRect(0, 0, aViewportWidth, aViewportHeight);
}
SVGPreserveAspectRatio
SVGSVGElement::GetPreserveAspectRatioWithOverride() const
{
nsIDocument* doc = GetUncomposedDoc();
if (doc && doc->IsBeingUsedAsImage()) {
const SVGPreserveAspectRatio *pAROverridePtr = GetPreserveAspectRatioProperty();
if (pAROverridePtr) {
return *pAROverridePtr;
}
}
SVGViewElement* viewElement = GetCurrentViewElement();
// This check is equivalent to "!HasViewBoxRect() && ShouldSynthesizeViewBox()".
// We're just holding onto the viewElement that HasViewBoxRect() would look up,
// so that we don't have to look it up again later.
if (!((viewElement && viewElement->mViewBox.HasRect()) ||
(mSVGView && mSVGView->mViewBox.HasRect()) ||
mViewBox.HasRect()) &&
ShouldSynthesizeViewBox()) {
// If we're synthesizing a viewBox, use preserveAspectRatio="none";
return SVGPreserveAspectRatio(SVG_PRESERVEASPECTRATIO_NONE, SVG_MEETORSLICE_SLICE);
}
if (viewElement && viewElement->mPreserveAspectRatio.IsExplicitlySet()) {
return viewElement->mPreserveAspectRatio.GetAnimValue();
}
if (mSVGView && mSVGView->mPreserveAspectRatio.IsExplicitlySet()) {
return mSVGView->mPreserveAspectRatio.GetAnimValue();
}
return mPreserveAspectRatio.GetAnimValue();
}
//----------------------------------------------------------------------
// SVGSVGElement
float
SVGSVGElement::GetLength(uint8_t aCtxType)
{
float h, w;
SVGViewElement* viewElement = GetCurrentViewElement();
const nsSVGViewBoxRect* viewbox = nullptr;
// The logic here should match HasViewBoxRect().
if (viewElement && viewElement->mViewBox.HasRect()) {
viewbox = &viewElement->mViewBox.GetAnimValue();
} else if (mSVGView && mSVGView->mViewBox.HasRect()) {
viewbox = &mSVGView->mViewBox.GetAnimValue();
} else if (mViewBox.HasRect()) {
viewbox = &mViewBox.GetAnimValue();
}
if (viewbox) {
w = viewbox->width;
h = viewbox->height;
} else if (IsInner()) {
SVGSVGElement *ctx = GetCtx();
w = mLengthAttributes[ATTR_WIDTH].GetAnimValue(ctx);
h = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(ctx);
} else if (ShouldSynthesizeViewBox()) {
w = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_WIDTH],
mViewportWidth, this);
h = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_HEIGHT],
mViewportHeight, this);
} else {
w = mViewportWidth;
h = mViewportHeight;
}
w = std::max(w, 0.0f);
h = std::max(h, 0.0f);
switch (aCtxType) {
case SVGContentUtils::X:
return w;
case SVGContentUtils::Y:
return h;
case SVGContentUtils::XY:
return float(SVGContentUtils::ComputeNormalizedHypotenuse(w, h));
}
return 0;
}
//----------------------------------------------------------------------
// nsSVGElement methods
/* virtual */ gfxMatrix
SVGSVGElement::PrependLocalTransformsTo(const gfxMatrix& aMatrix,
SVGTransformTypes aWhich) const
{
// 'transform' attribute (or an override from a fragment identifier):
gfxMatrix userToParent;
if (aWhich == eUserSpaceToParent || aWhich == eAllTransforms) {
userToParent = GetUserToParentTransform(mAnimateMotionTransform,
mSVGView && mSVGView->mTransforms
? mSVGView->mTransforms
: mTransforms);
if (aWhich == eUserSpaceToParent) {
return userToParent * aMatrix;
}
}
gfxMatrix childToUser;
if (IsInner()) {
float x, y;
const_cast<SVGSVGElement*>(this)->GetAnimatedLengthValues(&x, &y, nullptr);
childToUser = ThebesMatrix(GetViewBoxTransform().PostTranslate(x, y));
} else if (IsRoot()) {
childToUser = ThebesMatrix(GetViewBoxTransform()
.PostScale(mCurrentScale, mCurrentScale)
.PostTranslate(mCurrentTranslate.GetX(),
mCurrentTranslate.GetY()));
} else {
// outer-<svg>, but inline in some other content:
childToUser = ThebesMatrix(GetViewBoxTransform());
}
if (aWhich == eAllTransforms) {
return childToUser * userToParent * aMatrix;
}
MOZ_ASSERT(aWhich == eChildToUserSpace, "Unknown TransformTypes");
// The following may look broken because pre-multiplying our eChildToUserSpace
// transform with another matrix without including our eUserSpaceToParent
// transform between the two wouldn't make sense. We don't expect that to
// ever happen though. We get here either when the identity matrix has been
// passed because our caller just wants our eChildToUserSpace transform, or
// when our eUserSpaceToParent transform has already been multiplied into the
// matrix that our caller passes (such as when we're called from PaintSVG).
return childToUser * aMatrix;
}
nsSVGAnimatedTransformList*
SVGSVGElement::GetAnimatedTransformList(uint32_t aFlags)
{
if (!(aFlags & DO_ALLOCATE) && mSVGView && mSVGView->mTransforms) {
return mSVGView->mTransforms;
}
return SVGSVGElementBase::GetAnimatedTransformList(aFlags);
}
/* virtual */ bool
SVGSVGElement::HasValidDimensions() const
{
return !IsInner() ||
((!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
(!mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() ||
mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0));
}
nsSVGElement::LengthAttributesInfo
SVGSVGElement::GetLengthInfo()
{
return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
ArrayLength(sLengthInfo));
}
nsSVGElement::EnumAttributesInfo
SVGSVGElement::GetEnumInfo()
{
@ -1035,74 +671,6 @@ SVGSVGElement::GetEnumInfo()
ArrayLength(sEnumInfo));
}
nsSVGViewBox*
SVGSVGElement::GetViewBox()
{
return &mViewBox;
}
SVGAnimatedPreserveAspectRatio *
SVGSVGElement::GetPreserveAspectRatio()
{
return &mPreserveAspectRatio;
}
bool
SVGSVGElement::HasViewBoxRect() const
{
SVGViewElement* viewElement = GetCurrentViewElement();
if ((viewElement && viewElement->mViewBox.HasRect()) ||
(mSVGView && mSVGView->mViewBox.HasRect())) {
return true;
}
return mViewBox.HasRect();
}
bool
SVGSVGElement::ShouldSynthesizeViewBox() const
{
MOZ_ASSERT(!HasViewBoxRect(), "Should only be called if we lack a viewBox");
return IsRoot() && OwnerDoc()->IsBeingUsedAsImage();
}
bool
SVGSVGElement::SetPreserveAspectRatioProperty(const SVGPreserveAspectRatio& aPAR)
{
SVGPreserveAspectRatio* pAROverridePtr = new SVGPreserveAspectRatio(aPAR);
nsresult rv = SetProperty(nsGkAtoms::overridePreserveAspectRatio,
pAROverridePtr,
nsINode::DeleteProperty<SVGPreserveAspectRatio>,
true);
MOZ_ASSERT(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
"Setting override value when it's already set...?");
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
// property-insertion failed (e.g. OOM in property-table code)
delete pAROverridePtr;
return false;
}
return true;
}
const SVGPreserveAspectRatio*
SVGSVGElement::GetPreserveAspectRatioProperty() const
{
void* valPtr = GetProperty(nsGkAtoms::overridePreserveAspectRatio);
if (valPtr) {
return static_cast<SVGPreserveAspectRatio*>(valPtr);
}
return nullptr;
}
bool
SVGSVGElement::ClearPreserveAspectRatioProperty()
{
void* valPtr = UnsetProperty(nsGkAtoms::overridePreserveAspectRatio);
delete static_cast<SVGPreserveAspectRatio*>(valPtr);
return valPtr;
}
void
SVGSVGElement::
SetImageOverridePreserveAspectRatio(const SVGPreserveAspectRatio& aPAR)
@ -1149,45 +717,112 @@ SVGSVGElement::ClearImageOverridePreserveAspectRatio()
}
}
void
SVGSVGElement::FlushImageTransformInvalidation()
bool
SVGSVGElement::SetPreserveAspectRatioProperty(const SVGPreserveAspectRatio& aPAR)
{
MOZ_ASSERT(!GetParent(), "Should only be called on root node");
MOZ_ASSERT(OwnerDoc()->IsBeingUsedAsImage(),
"Should only be called on image documents");
SVGPreserveAspectRatio* pAROverridePtr = new SVGPreserveAspectRatio(aPAR);
nsresult rv = SetProperty(nsGkAtoms::overridePreserveAspectRatio,
pAROverridePtr,
nsINode::DeleteProperty<SVGPreserveAspectRatio>,
true);
MOZ_ASSERT(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
"Setting override value when it's already set...?");
if (mImageNeedsTransformInvalidation) {
InvalidateTransformNotifyFrame();
mImageNeedsTransformInvalidation = false;
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
// property-insertion failed (e.g. OOM in property-table code)
delete pAROverridePtr;
return false;
}
return true;
}
int32_t
SVGSVGElement::GetIntrinsicWidth()
const SVGPreserveAspectRatio*
SVGSVGElement::GetPreserveAspectRatioProperty() const
{
if (mLengthAttributes[ATTR_WIDTH].IsPercentage()) {
return -1;
void* valPtr = GetProperty(nsGkAtoms::overridePreserveAspectRatio);
if (valPtr) {
return static_cast<SVGPreserveAspectRatio*>(valPtr);
}
// Passing |this| as a SVGSVGElement* invokes the variant of GetAnimValue
// that uses the passed argument as the context, but that's fine since we
// know the length isn't a percentage so the context won't be used (and we
// need to pass the element to be able to resolve em/ex units).
float width = mLengthAttributes[ATTR_WIDTH].GetAnimValue(this);
return nsSVGUtils::ClampToInt(width);
return nullptr;
}
int32_t
SVGSVGElement::GetIntrinsicHeight()
bool
SVGSVGElement::ClearPreserveAspectRatioProperty()
{
if (mLengthAttributes[ATTR_HEIGHT].IsPercentage()) {
return -1;
void* valPtr = UnsetProperty(nsGkAtoms::overridePreserveAspectRatio);
delete static_cast<SVGPreserveAspectRatio*>(valPtr);
return valPtr;
}
SVGPreserveAspectRatio
SVGSVGElement::GetPreserveAspectRatioWithOverride() const
{
nsIDocument* doc = GetUncomposedDoc();
if (doc && doc->IsBeingUsedAsImage()) {
const SVGPreserveAspectRatio *pAROverridePtr = GetPreserveAspectRatioProperty();
if (pAROverridePtr) {
return *pAROverridePtr;
}
}
// Passing |this| as a SVGSVGElement* invokes the variant of GetAnimValue
// that uses the passed argument as the context, but that's fine since we
// know the length isn't a percentage so the context won't be used (and we
// need to pass the element to be able to resolve em/ex units).
float height = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(this);
return nsSVGUtils::ClampToInt(height);
SVGViewElement* viewElement = GetCurrentViewElement();
// This check is equivalent to "!HasViewBoxRect() && ShouldSynthesizeViewBox()".
// We're just holding onto the viewElement that HasViewBoxRect() would look up,
// so that we don't have to look it up again later.
if (!((viewElement && viewElement->mViewBox.HasRect()) ||
(mSVGView && mSVGView->mViewBox.HasRect()) ||
mViewBox.HasRect()) &&
ShouldSynthesizeViewBox()) {
// If we're synthesizing a viewBox, use preserveAspectRatio="none";
return SVGPreserveAspectRatio(SVG_PRESERVEASPECTRATIO_NONE, SVG_MEETORSLICE_SLICE);
}
if (viewElement && viewElement->mPreserveAspectRatio.IsExplicitlySet()) {
return viewElement->mPreserveAspectRatio.GetAnimValue();
}
if (mSVGView && mSVGView->mPreserveAspectRatio.IsExplicitlySet()) {
return mSVGView->mPreserveAspectRatio.GetAnimValue();
}
return mPreserveAspectRatio.GetAnimValue();
}
SVGViewElement*
SVGSVGElement::GetCurrentViewElement() const
{
if (mCurrentViewID) {
//XXXsmaug It is unclear how this should work in case we're in Shadow DOM.
nsIDocument* doc = GetUncomposedDoc();
if (doc) {
Element *element = doc->GetElementById(*mCurrentViewID);
if (element && element->IsSVGElement(nsGkAtoms::view)) {
return static_cast<SVGViewElement*>(element);
}
}
}
return nullptr;
}
const nsSVGViewBox&
SVGSVGElement::GetViewBoxInternal() const
{
SVGViewElement* viewElement = GetCurrentViewElement();
if (viewElement && viewElement->mViewBox.HasRect()) {
return viewElement->mViewBox;
} else if (mSVGView && mSVGView->mViewBox.HasRect()) {
return mSVGView->mViewBox;
}
return mViewBox;
}
nsSVGAnimatedTransformList*
SVGSVGElement::GetTransformInternal() const
{
return (mSVGView && mSVGView->mTransforms)
? mSVGView->mTransforms: mTransforms;
}
} // namespace dom

Просмотреть файл

@ -7,50 +7,41 @@
#ifndef mozilla_dom_SVGSVGElement_h
#define mozilla_dom_SVGSVGElement_h
#include "mozilla/dom/FromParser.h"
#include "nsAutoPtr.h"
#include "nsIContentInlines.h"
#include "nsISVGPoint.h"
#include "nsSVGEnum.h"
#include "nsSVGLength2.h"
#include "SVGGraphicsElement.h"
#include "SVGImageContext.h"
#include "nsSVGViewBox.h"
#include "SVGPreserveAspectRatio.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "mozilla/Attributes.h"
#include "SVGViewportElement.h"
nsresult NS_NewSVGSVGElement(nsIContent **aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser);
class nsSMILTimeContainer;
class nsSVGOuterSVGFrame;
class nsSVGInnerSVGFrame;
namespace mozilla {
class AutoPreserveAspectRatioOverride;
class AutoSVGTimeSetRestore;
class DOMSVGAnimatedPreserveAspectRatio;
class AutoSVGViewHandler;
class SVGFragmentIdentifier;
class EventChainPreVisitor;
class DOMSVGLength;
class DOMSVGNumber;
class EventChainPreVisitor;
class SVGFragmentIdentifier;
class AutoSVGViewHandler;
namespace dom {
class SVGAngle;
class SVGAnimatedRect;
class SVGMatrix;
class SVGTransform;
class SVGViewElement;
class SVGIRect;
class SVGSVGElement;
// Stores svgView arguments of SVG fragment identifiers.
class SVGView {
public:
SVGView();
nsSVGEnum mZoomAndPan;
nsSVGViewBox mViewBox;
SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
nsAutoPtr<nsSVGAnimatedTransformList> mTransforms;
};
class DOMSVGTranslatePoint final : public nsISVGPoint {
public:
DOMSVGTranslatePoint(SVGPoint* aPt, SVGSVGElement *aElement)
DOMSVGTranslatePoint(SVGPoint* aPt, SVGSVGElement* aElement)
: nsISVGPoint(aPt, true), mElement(aElement) {}
explicit DOMSVGTranslatePoint(DOMSVGTranslatePoint* aPt)
@ -76,45 +67,17 @@ private:
~DOMSVGTranslatePoint() {}
};
class svgFloatSize {
public:
svgFloatSize(float aWidth, float aHeight)
: width(aWidth)
, height(aHeight)
{}
bool operator!=(const svgFloatSize& rhs) {
return width != rhs.width || height != rhs.height;
}
float width;
float height;
};
// Stores svgView arguments of SVG fragment identifiers.
class SVGView {
friend class mozilla::AutoSVGViewHandler;
friend class mozilla::dom::SVGSVGElement;
public:
SVGView();
private:
nsSVGEnum mZoomAndPan;
nsSVGViewBox mViewBox;
SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
nsAutoPtr<nsSVGAnimatedTransformList> mTransforms;
};
typedef SVGGraphicsElement SVGSVGElementBase;
typedef SVGViewportElement SVGSVGElementBase;
class SVGSVGElement final : public SVGSVGElementBase
{
friend class ::nsSVGOuterSVGFrame;
friend class ::nsSVGInnerSVGFrame;
friend class mozilla::AutoPreserveAspectRatioOverride;
friend class mozilla::AutoSVGTimeSetRestore;
friend class mozilla::dom::SVGView;
friend class mozilla::SVGFragmentIdentifier;
friend class mozilla::AutoSVGViewHandler;
friend class mozilla::AutoPreserveAspectRatioOverride;
friend class mozilla::dom::SVGView;
protected:
SVGSVGElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
FromParser aFromParser);
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
@ -139,124 +102,15 @@ public:
*/
void SetCurrentScaleTranslate(float s, float x, float y);
/**
* Retrieve the value of currentScale and currentTranslate.
*/
const SVGPoint& GetCurrentTranslate() { return mCurrentTranslate; }
float GetCurrentScale() { return mCurrentScale; }
/**
* Retrieve the value of currentScale, currentTranslate.x or
* currentTranslate.y prior to the last change made to any one of them.
*/
const SVGPoint& GetPreviousTranslate() { return mPreviousTranslate; }
float GetPreviousScale() { return mPreviousScale; }
nsSMILTimeContainer* GetTimedDocumentRoot();
// nsIContent interface
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
virtual nsresult GetEventTargetParent(
EventChainPreVisitor& aVisitor) override;
virtual bool IsEventAttributeName(nsIAtom* aName) override;
// nsSVGElement specializations:
virtual gfxMatrix PrependLocalTransformsTo(
const gfxMatrix &aMatrix,
SVGTransformTypes aWhich = eAllTransforms) const override;
virtual nsSVGAnimatedTransformList*
GetAnimatedTransformList(uint32_t aFlags = 0) override;
virtual bool HasValidDimensions() const override;
// SVGSVGElement methods:
float GetLength(uint8_t mCtxType);
// public helpers:
/**
* Returns -1 if the width/height is a percentage, else returns the user unit
* length clamped to fit in a int32_t.
* XXX see bug 1112533 comment 3 - we should fix drawImage so that we can
* change these methods to make zero the error flag for percentages.
*/
int32_t GetIntrinsicWidth();
int32_t GetIntrinsicHeight();
/**
* Returns true if this element has a base/anim value for its "viewBox"
* attribute that defines a viewBox rectangle with finite values, or
* if there is a view element overriding this element's viewBox and it
* has a valid viewBox.
*
* Note that this does not check whether we need to synthesize a viewBox,
* so you must call ShouldSynthesizeViewBox() if you need to check that too.
*
* Note also that this method does not pay attention to whether the width or
* height values of the viewBox rect are positive!
*/
bool HasViewBoxRect() const;
/**
* Returns true if we should synthesize a viewBox for ourselves (that is, if
* we're the root element in an image document, and we're not currently being
* painted for an <svg:image> element).
*
* Only call this method if HasViewBoxRect() returns false.
*/
bool ShouldSynthesizeViewBox() const;
bool HasViewBoxOrSyntheticViewBox() const {
return HasViewBoxRect() || ShouldSynthesizeViewBox();
}
gfx::Matrix GetViewBoxTransform() const;
bool HasChildrenOnlyTransform() const {
return mHasChildrenOnlyTransform;
}
void UpdateHasChildrenOnlyTransform();
enum ChildrenOnlyTransformChangedFlags {
eDuringReflow = 1
};
/**
* This method notifies the style system that the overflow rects of our
* immediate childrens' frames need to be updated. It is called by our own
* frame when changes (e.g. to currentScale) cause our children-only
* transform to change.
*
* The reason we have this method instead of overriding
* GetAttributeChangeHint is because we need to act on non-attribute (e.g.
* currentScale) changes in addition to attribute (e.g. viewBox) changes.
*/
void ChildrenOnlyTransformChanged(uint32_t aFlags = 0);
// This services any pending notifications for the transform on on this root
// <svg> node needing to be recalculated. (Only applicable in
// SVG-as-an-image documents.)
virtual void FlushImageTransformInvalidation();
// nsINode methods:
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;
// Returns true IFF our attributes are currently overridden by a <view>
// element and that element's ID matches the passed-in string.
bool IsOverriddenBy(const nsAString &aViewID) const {
return mCurrentViewID && mCurrentViewID->Equals(aViewID);
}
svgFloatSize GetViewportSize() const {
return svgFloatSize(mViewportWidth, mViewportHeight);
}
void SetViewportSize(const svgFloatSize& aSize) {
mViewportWidth = aSize.width;
mViewportHeight = aSize.height;
}
// WebIDL
already_AddRefed<SVGAnimatedLength> X();
already_AddRefed<SVGAnimatedLength> Y();
@ -290,54 +144,62 @@ public:
already_AddRefed<SVGTransform> CreateSVGTransform();
already_AddRefed<SVGTransform> CreateSVGTransformFromMatrix(SVGMatrix& matrix);
using nsINode::GetElementById; // This does what we want
already_AddRefed<SVGAnimatedRect> ViewBox();
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
uint16_t ZoomAndPan();
void SetZoomAndPan(uint16_t aZoomAndPan, ErrorResult& rv);
virtual nsSVGViewBox* GetViewBox() override;
private:
// nsSVGElement overrides
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
virtual nsSVGAnimatedTransformList*
GetAnimatedTransformList(uint32_t aFlags = 0) override;
// SVGSVGElement methods:
// Returns true IFF our attributes are currently overridden by a <view>
// element and that element's ID matches the passed-in string.
bool IsOverriddenBy(const nsAString &aViewID) const {
return mCurrentViewID && mCurrentViewID->Equals(aViewID);
}
nsSMILTimeContainer* GetTimedDocumentRoot();
// public helpers:
/**
* Returns -1 if the width/height is a percentage, else returns the user unit
* length clamped to fit in a int32_t.
* XXX see bug 1112533 comment 3 - we should fix drawImage so that we can
* change these methods to make zero the error flag for percentages.
*/
int32_t GetIntrinsicWidth();
int32_t GetIntrinsicHeight();
// This services any pending notifications for the transform on on this root
// <svg> node needing to be recalculated. (Only applicable in
// SVG-as-an-image documents.)
virtual void FlushImageTransformInvalidation();
svgFloatSize GetViewportSize() const {
return svgFloatSize(mViewportWidth, mViewportHeight);
}
void SetViewportSize(const svgFloatSize& aSize) {
mViewportWidth = aSize.width;
mViewportHeight = aSize.height;
}
private:
// SVGViewportElement methods:
virtual SVGViewElement* GetCurrentViewElement() const;
virtual SVGPreserveAspectRatio GetPreserveAspectRatioWithOverride() const override;
// implementation helpers:
SVGViewElement* GetCurrentViewElement() const;
// Methods for <image> elements to override my "PreserveAspectRatio" value.
// These are private so that only our friends
// (AutoPreserveAspectRatioOverride in particular) have access.
void SetImageOverridePreserveAspectRatio(const SVGPreserveAspectRatio& aPAR);
void ClearImageOverridePreserveAspectRatio();
// Set/Clear properties to hold old version of preserveAspectRatio
// when it's being overridden by an <image> element that we are inside of.
bool SetPreserveAspectRatioProperty(const SVGPreserveAspectRatio& aPAR);
const SVGPreserveAspectRatio* GetPreserveAspectRatioProperty() const;
bool ClearPreserveAspectRatioProperty();
bool IsRoot() const {
NS_ASSERTION((IsInUncomposedDoc() && !GetParent()) ==
(OwnerDoc() && (OwnerDoc()->GetRootElement() == this)),
"Can't determine if we're root");
return IsInUncomposedDoc() && !GetParent();
}
/**
* Returns true if this is an SVG <svg> element that is the child of
* another non-foreignObject SVG element.
*/
bool IsInner() const {
const nsIContent *parent = GetFlattenedTreeParent();
return parent && parent->IsSVGElement() &&
!parent->IsSVGElement(nsGkAtoms::foreignObject);
}
/*
/*
* While binding to the tree we need to determine if we will be the outermost
* <svg> element _before_ the children are bound (as they want to know what
* timed document root to register with) and therefore _before_ our parent is
@ -357,24 +219,25 @@ private:
// - a SMIL-animated value for the preserveAspectRatio attribute
bool HasPreserveAspectRatio();
/**
* Returns the explicit viewBox rect, if specified, or else a synthesized
* viewBox, if appropriate, or else a viewBox matching the dimensions of the
* SVG viewport.
*/
nsSVGViewBoxRect GetViewBoxWithSynthesis(
float aViewportWidth, float aViewportHeight) const;
/**
* Returns the explicit or default preserveAspectRatio, unless we're
* synthesizing a viewBox, in which case it returns the "none" value.
*/
SVGPreserveAspectRatio GetPreserveAspectRatioWithOverride() const;
// Methods for <image> elements to override my "PreserveAspectRatio" value.
// These are private so that only our friends
// (AutoPreserveAspectRatioOverride in particular) have access.
void SetImageOverridePreserveAspectRatio(const SVGPreserveAspectRatio& aPAR);
void ClearImageOverridePreserveAspectRatio();
virtual LengthAttributesInfo GetLengthInfo() override;
// Set/Clear properties to hold old version of preserveAspectRatio
// when it's being overridden by an <image> element that we are inside of.
bool SetPreserveAspectRatioProperty(const SVGPreserveAspectRatio& aPAR);
const SVGPreserveAspectRatio* GetPreserveAspectRatioProperty() const;
bool ClearPreserveAspectRatioProperty();
enum { ATTR_X, ATTR_Y, ATTR_WIDTH, ATTR_HEIGHT };
nsSVGLength2 mLengthAttributes[4];
static LengthInfo sLengthInfo[4];
virtual SVGPoint GetCurrentTranslate() const override
{ return mCurrentTranslate; }
virtual float GetCurrentScale() const override
{ return mCurrentScale; }
virtual const nsSVGViewBox& GetViewBoxInternal() const override;
virtual nsSVGAnimatedTransformList* GetTransformInternal() const override;
virtual EnumAttributesInfo GetEnumInfo() override;
@ -383,26 +246,6 @@ private:
static nsSVGEnumMapping sZoomAndPanMap[];
static EnumInfo sEnumInfo[1];
virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio() override;
nsSVGViewBox mViewBox;
SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
// mCurrentViewID and mSVGView are mutually exclusive; we can have
// at most one non-null.
nsAutoPtr<nsString> mCurrentViewID;
nsAutoPtr<SVGView> mSVGView;
// The size of the rectangular SVG viewport into which we render. This is
// not (necessarily) the same as the content area. See:
//
// http://www.w3.org/TR/SVG11/coords.html#ViewportSpace
//
// XXXjwatt Currently only used for outer <svg>, but maybe we could use -1 to
// flag this as an inner <svg> to save the overhead of GetCtx calls?
// XXXjwatt our frame should probably reset these when it's destroyed.
float mViewportWidth, mViewportHeight;
// The time container for animations within this SVG document fragment. Set
// for all outermost <svg> elements (not nested <svg> elements).
nsAutoPtr<nsSMILTimeContainer> mTimedDocumentRoot;
@ -420,48 +263,17 @@ private:
// created by script or promoted from inner <svg> to outermost <svg> we need
// to manually kick off animation when they are bound to the tree.
bool mStartAnimationOnBindToTree;
bool mImageNeedsTransformInvalidation;
bool mHasChildrenOnlyTransform;
// mCurrentViewID and mSVGView are mutually exclusive; we can have
// at most one non-null.
nsAutoPtr<nsString> mCurrentViewID;
nsAutoPtr<SVGView> mSVGView;
};
} // namespace dom
class MOZ_RAII AutoPreserveAspectRatioOverride
{
public:
AutoPreserveAspectRatioOverride(const Maybe<SVGImageContext>& aSVGContext,
dom::SVGSVGElement* aRootElem
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mRootElem(aRootElem)
, mDidOverride(false)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
MOZ_ASSERT(mRootElem, "No SVG node to manage?");
if (aSVGContext.isSome() &&
aSVGContext->GetPreserveAspectRatio().isSome()) {
// Override preserveAspectRatio in our helper document.
// XXXdholbert We should technically be overriding the helper doc's clip
// and overflow properties here, too. See bug 272288 comment 36.
mRootElem->SetImageOverridePreserveAspectRatio(
*aSVGContext->GetPreserveAspectRatio());
mDidOverride = true;
}
}
~AutoPreserveAspectRatioOverride()
{
if (mDidOverride) {
mRootElem->ClearImageOverridePreserveAspectRatio();
}
}
private:
const RefPtr<dom::SVGSVGElement> mRootElem;
bool mDidOverride;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class MOZ_RAII AutoSVGTimeSetRestore
{
public:
@ -486,6 +298,42 @@ private:
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class MOZ_RAII AutoPreserveAspectRatioOverride
{
public:
AutoPreserveAspectRatioOverride(const Maybe<SVGImageContext>& aSVGContext,
dom::SVGSVGElement* aRootElem
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mRootElem(aRootElem)
, mDidOverride(false)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
MOZ_ASSERT(mRootElem, "No SVG/Symbol node to manage?");
if (aSVGContext.isSome() &&
aSVGContext->GetPreserveAspectRatio().isSome()) {
// Override preserveAspectRatio in our helper document.
// XXXdholbert We should technically be overriding the helper doc's clip
// and overflow properties here, too. See bug 272288 comment 36.
mRootElem->SetImageOverridePreserveAspectRatio(
*aSVGContext->GetPreserveAspectRatio());
mDidOverride = true;
}
}
~AutoPreserveAspectRatioOverride()
{
if (mDidOverride) {
mRootElem->ClearImageOverridePreserveAspectRatio();
}
}
private:
const RefPtr<dom::SVGSVGElement> mRootElem;
bool mDidOverride;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
} // namespace mozilla
#endif // SVGSVGElement_h

Просмотреть файл

@ -42,44 +42,6 @@ SVGSymbolElement::~SVGSymbolElement()
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSymbolElement)
//----------------------------------------------------------------------
already_AddRefed<SVGAnimatedRect>
SVGSymbolElement::ViewBox()
{
return mViewBox.ToSVGAnimatedRect(this);
}
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
SVGSymbolElement::PreserveAspectRatio()
{
return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
}
//----------------------------------------------------------------------
// nsIContent methods
NS_IMETHODIMP_(bool)
SVGSymbolElement::IsAttributeMapped(const nsIAtom* name) const
{
static const MappedAttributeEntry* const map[] = {
sColorMap,
sFEFloodMap,
sFillStrokeMap,
sFiltersMap,
sFontSpecificationMap,
sGradientStopMap,
sGraphicsMap,
sLightingEffectsMap,
sMarkersMap,
sTextContentElementsMap,
sViewportsMap
};
return FindAttributeDependence(name, map) ||
SVGSymbolElementBase::IsAttributeMapped(name);
}
//----------------------------------------------------------------------
// SVGTests methods
@ -89,21 +51,5 @@ SVGSymbolElement::IsInChromeDoc() const
return nsContentUtils::IsChromeDoc(OwnerDoc());
}
//----------------------------------------------------------------------
// nsSVGElement methods
nsSVGViewBox *
SVGSymbolElement::GetViewBox()
{
return &mViewBox;
}
SVGAnimatedPreserveAspectRatio *
SVGSymbolElement::GetPreserveAspectRatio()
{
return &mPreserveAspectRatio;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -7,10 +7,7 @@
#ifndef mozilla_dom_SVGSymbolElement_h
#define mozilla_dom_SVGSymbolElement_h
#include "mozilla/dom/SVGTests.h"
#include "nsSVGElement.h"
#include "nsSVGViewBox.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "SVGViewportElement.h"
nsresult NS_NewSVGSymbolElement(nsIContent **aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
@ -18,10 +15,9 @@ nsresult NS_NewSVGSymbolElement(nsIContent **aResult,
namespace mozilla {
namespace dom {
typedef nsSVGElement SVGSymbolElementBase;
typedef SVGViewportElement SVGSymbolElementBase;
class SVGSymbolElement final : public SVGSymbolElementBase,
public SVGTests
class SVGSymbolElement final : public SVGSymbolElementBase
{
protected:
friend nsresult (::NS_NewSVGSymbolElement(nsIContent **aResult,
@ -32,28 +28,13 @@ protected:
public:
// interfaces:
NS_DECL_ISUPPORTS_INHERITED
// nsIContent interface
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;
// WebIDL
already_AddRefed<SVGAnimatedRect> ViewBox();
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
// SVGTests
bool IsInChromeDoc() const override;
protected:
virtual nsSVGViewBox *GetViewBox() override;
virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio() override;
nsSVGViewBox mViewBox;
SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
};
} // namespace dom

Просмотреть файл

@ -275,51 +275,6 @@ SVGUseElement::CreateAnonymousContent()
if (!newcontent)
return nullptr;
if (newcontent->IsSVGElement(nsGkAtoms::symbol)) {
nsIDocument *document = GetComposedDoc();
if (!document)
return nullptr;
nsNodeInfoManager *nodeInfoManager = document->NodeInfoManager();
if (!nodeInfoManager)
return nullptr;
RefPtr<mozilla::dom::NodeInfo> nodeInfo;
nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::svg, nullptr,
kNameSpaceID_SVG,
nsIDOMNode::ELEMENT_NODE);
nsCOMPtr<nsIContent> svgNode;
NS_NewSVGSVGElement(getter_AddRefs(svgNode), nodeInfo.forget(),
NOT_FROM_PARSER);
if (!svgNode)
return nullptr;
// copy attributes
BorrowedAttrInfo info;
uint32_t i;
for (i = 0; (info = newcontent->GetAttrInfoAt(i)); i++) {
nsAutoString value;
int32_t nsID = info.mName->NamespaceID();
nsIAtom* lname = info.mName->LocalName();
info.mValue->ToString(value);
svgNode->SetAttr(nsID, lname, info.mName->GetPrefix(), value, false);
}
// move the children over
uint32_t num = newcontent->GetChildCount();
for (i = 0; i < num; i++) {
nsCOMPtr<nsIContent> child = newcontent->GetFirstChild();
newcontent->RemoveChildAt(0, false);
svgNode->InsertChildAt(child, i, true);
}
newcontent = svgNode;
}
if (newcontent->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol)) {
nsSVGElement *newElement = static_cast<nsSVGElement*>(newcontent.get());

Просмотреть файл

@ -28,13 +28,14 @@ namespace mozilla {
class SVGFragmentIdentifier;
namespace dom {
class SVGSVGElement;
class SVGViewportElement;
class SVGViewElement : public SVGViewElementBase
{
protected:
friend class mozilla::SVGFragmentIdentifier;
friend class SVGSVGElement;
friend class SVGViewportElement;
friend class ::nsSVGOuterSVGFrame;
explicit SVGViewElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
friend nsresult (::NS_NewSVGViewElement(nsIContent **aResult,

Просмотреть файл

@ -0,0 +1,374 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdint.h>
#include "mozilla/ArrayUtils.h"
#include "mozilla/ContentEvents.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/Likely.h"
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/SVGViewportElement.h"
#include "mozilla/dom/SVGViewElement.h"
#include "DOMSVGLength.h"
#include "DOMSVGPoint.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsFrameSelection.h"
#include "nsError.h"
#include "nsGkAtoms.h"
#include "nsIDocument.h"
#include "nsIFrame.h"
#include "nsIPresShell.h"
#include "nsISVGSVGFrame.h" //XXX
#include "nsLayoutUtils.h"
#include "nsStyleUtil.h"
#include "nsSMILTypes.h"
#include "SVGContentUtils.h"
#include <algorithm>
#include "prtime.h"
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
nsSVGElement::LengthInfo SVGViewportElement::sLengthInfo[4] =
{
{ &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
{ &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
{ &nsGkAtoms::width, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X },
{ &nsGkAtoms::height, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::Y },
};
//----------------------------------------------------------------------
// Implementation
SVGViewportElement::SVGViewportElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: SVGGraphicsElement(aNodeInfo),
mViewportWidth(0),
mViewportHeight(0),
mHasChildrenOnlyTransform(false)
{
}
SVGViewportElement::~SVGViewportElement()
{
}
//----------------------------------------------------------------------
already_AddRefed<SVGAnimatedRect>
SVGViewportElement::ViewBox()
{
return mViewBox.ToSVGAnimatedRect(this);
}
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
SVGViewportElement::PreserveAspectRatio()
{
return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
}
//----------------------------------------------------------------------
// nsIContent methods
NS_IMETHODIMP_(bool)
SVGViewportElement::IsAttributeMapped(const nsIAtom* name) const
{
// We want to map the 'width' and 'height' attributes into style for
// outer-<svg>, except when the attributes aren't set (since their default
// values of '100%' can cause unexpected and undesirable behaviour for SVG
// inline in HTML). We rely on nsSVGElement::UpdateContentStyleRule() to
// prevent mapping of the default values into style (it only maps attributes
// that are set). We also rely on a check in nsSVGElement::
// UpdateContentStyleRule() to prevent us mapping the attributes when they're
// given a <length> value that is not currently recognized by the SVG
// specification.
if (!IsInner() && (name == nsGkAtoms::width || name == nsGkAtoms::height)) {
return true;
}
static const MappedAttributeEntry* const map[] = {
sColorMap,
sFEFloodMap,
sFillStrokeMap,
sFiltersMap,
sFontSpecificationMap,
sGradientStopMap,
sGraphicsMap,
sLightingEffectsMap,
sMarkersMap,
sTextContentElementsMap,
sViewportsMap
};
return FindAttributeDependence(name, map) ||
SVGGraphicsElement::IsAttributeMapped(name);
}
//----------------------------------------------------------------------
// nsSVGElement overrides
// Helper for GetViewBoxTransform on root <svg> node
// * aLength: internal value for our <svg> width or height attribute.
// * aViewportLength: length of the corresponding dimension of the viewport.
// * aSelf: the outermost <svg> node itself.
// NOTE: aSelf is not an ancestor viewport element, so it can't be used to
// resolve percentage lengths. (It can only be used to resolve
// 'em'/'ex'-valued units).
inline float
ComputeSynthesizedViewBoxDimension(const nsSVGLength2& aLength,
float aViewportLength,
const SVGViewportElement* aSelf)
{
if (aLength.IsPercentage()) {
return aViewportLength * aLength.GetAnimValInSpecifiedUnits() / 100.0f;
}
return aLength.GetAnimValue(const_cast<SVGViewportElement*>(aSelf));
}
//----------------------------------------------------------------------
// public helpers:
void
SVGViewportElement::UpdateHasChildrenOnlyTransform()
{
bool hasChildrenOnlyTransform =
HasViewBoxOrSyntheticViewBox() ||
(IsRoot() && (GetCurrentTranslate() != SVGPoint(0.0f, 0.0f) ||
GetCurrentScale() != 1.0f));
mHasChildrenOnlyTransform = hasChildrenOnlyTransform;
}
void
SVGViewportElement::ChildrenOnlyTransformChanged(uint32_t aFlags)
{
// Avoid wasteful calls:
MOZ_ASSERT(!(GetPrimaryFrame()->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
"Non-display SVG frames don't maintain overflow rects");
nsChangeHint changeHint;
bool hadChildrenOnlyTransform = mHasChildrenOnlyTransform;
UpdateHasChildrenOnlyTransform();
if (hadChildrenOnlyTransform != mHasChildrenOnlyTransform) {
// Reconstruct the frame tree to handle stacking context changes:
// XXXjwatt don't do this for root-<svg> or even outer-<svg>?
changeHint = nsChangeHint_ReconstructFrame;
} else {
// We just assume the old and new transforms are different.
changeHint = nsChangeHint(nsChangeHint_UpdateOverflow |
nsChangeHint_ChildrenOnlyTransform);
}
// If we're not reconstructing the frame tree, then we only call
// PostRestyleEvent if we're not being called under reflow to avoid recursing
// to death. See bug 767056 comments 10 and 12. Since our nsSVGOuterSVGFrame
// is being reflowed we're going to invalidate and repaint its entire area
// anyway (which will include our children).
if ((changeHint & nsChangeHint_ReconstructFrame) ||
!(aFlags & eDuringReflow)) {
nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint);
}
}
gfx::Matrix
SVGViewportElement::GetViewBoxTransform() const
{
float viewportWidth, viewportHeight;
if (IsInner()) {
SVGViewportElement *ctx = GetCtx();
viewportWidth = mLengthAttributes[ATTR_WIDTH].GetAnimValue(ctx);
viewportHeight = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(ctx);
} else {
viewportWidth = mViewportWidth;
viewportHeight = mViewportHeight;
}
if (viewportWidth <= 0.0f || viewportHeight <= 0.0f) {
return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
}
nsSVGViewBoxRect viewBox =
GetViewBoxWithSynthesis(viewportWidth, viewportHeight);
if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
}
return SVGContentUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
viewBox.x, viewBox.y,
viewBox.width, viewBox.height,
GetPreserveAspectRatioWithOverride());
}
//----------------------------------------------------------------------
// SVGViewportElement
float
SVGViewportElement::GetLength(uint8_t aCtxType)
{
const nsSVGViewBoxRect* viewbox =
GetViewBoxInternal().HasRect() ? &GetViewBoxInternal().GetAnimValue()
: nullptr;
float h, w;
if (viewbox) {
w = viewbox->width;
h = viewbox->height;
} else if (IsInner()) {
SVGViewportElement *ctx = GetCtx();
w = mLengthAttributes[ATTR_WIDTH].GetAnimValue(ctx);
h = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(ctx);
} else if (ShouldSynthesizeViewBox()) {
w = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_WIDTH],
mViewportWidth, this);
h = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_HEIGHT],
mViewportHeight, this);
} else {
w = mViewportWidth;
h = mViewportHeight;
}
w = std::max(w, 0.0f);
h = std::max(h, 0.0f);
switch (aCtxType) {
case SVGContentUtils::X:
return w;
case SVGContentUtils::Y:
return h;
case SVGContentUtils::XY:
return float(SVGContentUtils::ComputeNormalizedHypotenuse(w, h));
}
return 0;
}
//----------------------------------------------------------------------
// nsSVGElement methods
/* virtual */ gfxMatrix
SVGViewportElement::PrependLocalTransformsTo(const gfxMatrix& aMatrix,
SVGTransformTypes aWhich) const
{
// 'transform' attribute (or an override from a fragment identifier):
gfxMatrix userToParent;
if (aWhich == eUserSpaceToParent || aWhich == eAllTransforms) {
userToParent = GetUserToParentTransform(mAnimateMotionTransform,
GetTransformInternal());
if (aWhich == eUserSpaceToParent) {
return userToParent * aMatrix;
}
}
gfxMatrix childToUser;
if (IsInner()) {
float x, y;
const_cast<SVGViewportElement*>(this)->GetAnimatedLengthValues(&x, &y, nullptr);
childToUser = ThebesMatrix(GetViewBoxTransform().PostTranslate(x, y));
} else if (IsRoot()) {
SVGPoint translate = GetCurrentTranslate();
float scale = GetCurrentScale();
childToUser = ThebesMatrix(GetViewBoxTransform()
.PostScale(scale, scale)
.PostTranslate(translate.GetX(),
translate.GetY()));
} else {
// outer-<svg>, but inline in some other content:
childToUser = ThebesMatrix(GetViewBoxTransform());
}
if (aWhich == eAllTransforms) {
return childToUser * userToParent * aMatrix;
}
MOZ_ASSERT(aWhich == eChildToUserSpace, "Unknown TransformTypes");
// The following may look broken because pre-multiplying our eChildToUserSpace
// transform with another matrix without including our eUserSpaceToParent
// transform between the two wouldn't make sense. We don't expect that to
// ever happen though. We get here either when the identity matrix has been
// passed because our caller just wants our eChildToUserSpace transform, or
// when our eUserSpaceToParent transform has already been multiplied into the
// matrix that our caller passes (such as when we're called from PaintSVG).
return childToUser * aMatrix;
}
/* virtual */ bool
SVGViewportElement::HasValidDimensions() const
{
return !IsInner() ||
((!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
(!mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() ||
mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0));
}
nsSVGViewBox*
SVGViewportElement::GetViewBox()
{
return &mViewBox;
}
SVGAnimatedPreserveAspectRatio *
SVGViewportElement::GetPreserveAspectRatio()
{
return &mPreserveAspectRatio;
}
bool
SVGViewportElement::ShouldSynthesizeViewBox() const
{
MOZ_ASSERT(!HasViewBoxRect(), "Should only be called if we lack a viewBox");
return IsRoot() && OwnerDoc()->IsBeingUsedAsImage();
}
//----------------------------------------------------------------------
// implementation helpers
nsSVGViewBoxRect
SVGViewportElement::GetViewBoxWithSynthesis(
float aViewportWidth, float aViewportHeight) const
{
if (GetViewBoxInternal().HasRect()) {
return GetViewBoxInternal().GetAnimValue();
}
if (ShouldSynthesizeViewBox()) {
// Special case -- fake a viewBox, using height & width attrs.
// (Use |this| as context, since if we get here, we're outermost <svg>.)
return nsSVGViewBoxRect(0, 0,
ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_WIDTH],
mViewportWidth, this),
ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_HEIGHT],
mViewportHeight, this));
}
// No viewBox attribute, so we shouldn't auto-scale. This is equivalent
// to having a viewBox that exactly matches our viewport size.
return nsSVGViewBoxRect(0, 0, aViewportWidth, aViewportHeight);
}
nsSVGElement::LengthAttributesInfo
SVGViewportElement::GetLengthInfo()
{
return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
ArrayLength(sLengthInfo));
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,212 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_SVGViewportElement_h
#define mozilla_dom_SVGViewportElement_h
#include "mozilla/dom/FromParser.h"
#include "nsAutoPtr.h"
#include "nsIContentInlines.h"
#include "nsISVGPoint.h"
#include "nsSVGEnum.h"
#include "nsSVGLength2.h"
#include "SVGGraphicsElement.h"
#include "SVGImageContext.h"
#include "nsSVGViewBox.h"
#include "SVGPreserveAspectRatio.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "mozilla/Attributes.h"
class nsSVGOuterSVGFrame;
class nsSVGViewportFrame;
namespace mozilla {
class AutoPreserveAspectRatioOverride;
class DOMSVGAnimatedPreserveAspectRatio;
namespace dom {
class SVGAnimatedRect;
class SVGTransform;
class SVGViewElement;
class SVGViewportElement;
class svgFloatSize {
public:
svgFloatSize(float aWidth, float aHeight)
: width(aWidth)
, height(aHeight)
{}
bool operator!=(const svgFloatSize& rhs) {
return width != rhs.width || height != rhs.height;
}
float width;
float height;
};
class SVGViewportElement : public SVGGraphicsElement
{
friend class ::nsSVGOuterSVGFrame;
friend class ::nsSVGViewportFrame;
protected:
SVGViewportElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
~SVGViewportElement();
public:
// nsIContent interface
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
// nsSVGElement specializations:
virtual gfxMatrix PrependLocalTransformsTo(
const gfxMatrix &aMatrix,
SVGTransformTypes aWhich = eAllTransforms) const override;
virtual bool HasValidDimensions() const override;
// SVGViewportElement methods:
float GetLength(uint8_t mCtxType);
// public helpers:
/**
* Returns true if this element has a base/anim value for its "viewBox"
* attribute that defines a viewBox rectangle with finite values, or
* if there is a view element overriding this element's viewBox and it
* has a valid viewBox.
*
* Note that this does not check whether we need to synthesize a viewBox,
* so you must call ShouldSynthesizeViewBox() if you need to chck that too.
*
* Note also that this method does not pay attention to whether the width or
* height values of the viewBox rect are positive!
*/
bool HasViewBoxRect() const {
return GetViewBoxInternal().HasRect();
}
/**
* Returns true if we should synthesize a viewBox for ourselves (that is, if
* we're the root element in an image document, and we're not currently being
* painted for an <svg:image> element).
*
* Only call this method if HasViewBoxRect() returns false.
*/
bool ShouldSynthesizeViewBox() const;
bool HasViewBoxOrSyntheticViewBox() const {
return HasViewBoxRect() || ShouldSynthesizeViewBox();
}
bool HasChildrenOnlyTransform() const {
return mHasChildrenOnlyTransform;
}
void UpdateHasChildrenOnlyTransform();
enum ChildrenOnlyTransformChangedFlags {
eDuringReflow = 1
};
/**
* This method notifies the style system that the overflow rects of our
* immediate childrens' frames need to be updated. It is called by our own
* frame when changes (e.g. to currentScale) cause our children-only
* transform to change.
*
* The reason we have this method instead of overriding
* GetAttributeChangeHint is because we need to act on non-attribute (e.g.
* currentScale) changes in addition to attribute (e.g. viewBox) changes.
*/
void ChildrenOnlyTransformChanged(uint32_t aFlags = 0);
gfx::Matrix GetViewBoxTransform() const;
// WebIDL
already_AddRefed<SVGAnimatedRect> ViewBox();
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
virtual nsSVGViewBox* GetViewBox() override;
protected:
// implementation helpers:
bool IsRoot() const {
NS_ASSERTION((IsInUncomposedDoc() && !GetParent()) ==
(OwnerDoc() && (OwnerDoc()->GetRootElement() == this)),
"Can't determine if we're root");
return IsInUncomposedDoc() && !GetParent();
}
/**
* Returns true if either this is an SVG <svg> element that is the child of
* another non-foreignObject SVG element, or this is a SVG <symbol> element
* this is the root of a use-element shadow tree.
*/
bool IsInner() const {
const nsIContent *parent = GetFlattenedTreeParent();
return parent && parent->IsSVGElement() &&
!parent->IsSVGElement(nsGkAtoms::foreignObject);
}
/**
* Returns the explicit or default preserveAspectRatio, unless we're
* synthesizing a viewBox, in which case it returns the "none" value.
*/
virtual SVGPreserveAspectRatio GetPreserveAspectRatioWithOverride() const {
return mPreserveAspectRatio.GetAnimValue();
}
/**
* Returns the explicit viewBox rect, if specified, or else a synthesized
* viewBox, if appropriate, or else a viewBox matching the dimensions of the
* SVG viewport.
*/
nsSVGViewBoxRect GetViewBoxWithSynthesis(
float aViewportWidth, float aViewportHeight) const;
/**
* Retrieve the value of currentScale and currentTranslate.
*/
virtual SVGPoint GetCurrentTranslate() const
{ return SVGPoint(0.0f, 0.0f); }
virtual float GetCurrentScale() const
{ return 1.0f; }
enum { ATTR_X, ATTR_Y, ATTR_WIDTH, ATTR_HEIGHT };
nsSVGLength2 mLengthAttributes[4];
static LengthInfo sLengthInfo[4];
virtual LengthAttributesInfo GetLengthInfo() override;
virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio() override;
virtual const nsSVGViewBox& GetViewBoxInternal() const { return mViewBox; }
virtual nsSVGAnimatedTransformList* GetTransformInternal() const {
return mTransforms;
}
nsSVGViewBox mViewBox;
SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
// The size of the rectangular SVG viewport into which we render. This is
// not (necessarily) the same as the content area. See:
//
// http://www.w3.org/TR/SVG11/coords.html#ViewportSpace
//
// XXXjwatt Currently only used for outer <svg>, but maybe we could use -1 to
// flag this as an inner <svg> to save the overhead of GetCtx calls?
// XXXjwatt our frame should probably reset these when it's destroyed.
float mViewportWidth, mViewportHeight;
bool mHasChildrenOnlyTransform;
};
} // namespace dom
} // namespace mozilla
#endif // SVGViewportElement_h

Просмотреть файл

@ -102,6 +102,7 @@ EXPORTS.mozilla.dom += [
'SVGTSpanElement.h',
'SVGUseElement.h',
'SVGViewElement.h',
'SVGViewportElement.h',
]
UNIFIED_SOURCES += [
@ -248,6 +249,7 @@ UNIFIED_SOURCES += [
'SVGUseElement.cpp',
'SVGViewBoxSMILType.cpp',
'SVGViewElement.cpp',
'SVGViewportElement.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/dom/network/Connection.h"
#include "nsProxyRelease.h"
#include "nsRFPService.h"
#include "RuntimeService.h"
#include "nsIDocument.h"
@ -79,9 +80,13 @@ WorkerNavigator::GetAppName(nsString& aAppName, CallerType aCallerType) const
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
if (!mProperties.mAppNameOverridden.IsEmpty() &&
if ((!mProperties.mAppNameOverridden.IsEmpty() ||
workerPrivate->ResistFingerprintingEnabled()) &&
!workerPrivate->UsesSystemPrincipal()) {
aAppName = mProperties.mAppNameOverridden;
// We will spoof this value when 'privacy.resistFingerprinting' is true.
// See nsRFPService.h for spoofed value.
aAppName = workerPrivate->ResistFingerprintingEnabled() ?
NS_LITERAL_STRING(SPOOFED_APPNAME) : mProperties.mAppNameOverridden;
} else {
aAppName = mProperties.mAppName;
}
@ -94,9 +99,13 @@ WorkerNavigator::GetAppVersion(nsString& aAppVersion, CallerType aCallerType,
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
if (!mProperties.mAppVersionOverridden.IsEmpty() &&
if ((!mProperties.mAppVersionOverridden.IsEmpty() ||
workerPrivate->ResistFingerprintingEnabled()) &&
!workerPrivate->UsesSystemPrincipal()) {
aAppVersion = mProperties.mAppVersionOverridden;
// We will spoof this value when 'privacy.resistFingerprinting' is true.
// See nsRFPService.h for spoofed value.
aAppVersion = workerPrivate->ResistFingerprintingEnabled() ?
NS_LITERAL_STRING(SPOOFED_APPVERSION) : mProperties.mAppVersionOverridden;
} else {
aAppVersion = mProperties.mAppVersion;
}
@ -109,9 +118,13 @@ WorkerNavigator::GetPlatform(nsString& aPlatform, CallerType aCallerType,
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
if (!mProperties.mPlatformOverridden.IsEmpty() &&
if ((!mProperties.mPlatformOverridden.IsEmpty() ||
workerPrivate->ResistFingerprintingEnabled()) &&
!workerPrivate->UsesSystemPrincipal()) {
aPlatform = mProperties.mPlatformOverridden;
// We will spoof this value when 'privacy.resistFingerprinting' is true.
// See nsRFPService.h for spoofed value.
aPlatform = workerPrivate->ResistFingerprintingEnabled() ?
NS_LITERAL_STRING(SPOOFED_PLATFORM) : mProperties.mPlatformOverridden;
} else {
aPlatform = mProperties.mPlatform;
}

Просмотреть файл

@ -25,6 +25,7 @@
#include "nsError.h"
#include "nsGkAtoms.h"
#include "nsIContent.h"
#include "nsIDocumentEncoder.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNode.h"
#include "nsIDOMNodeFilter.h"
@ -296,7 +297,7 @@ TextEditRules::WillDoAction(Selection* aSelection,
return WillRemoveTextProperty(aSelection, aCancel, aHandled);
case EditAction::outputText:
return WillOutputText(aSelection, info->outputFormat, info->outString,
aCancel, aHandled);
info->flags, aCancel, aHandled);
case EditAction::insertElement:
// i had thought this would be html rules only. but we put pre elements
// into plaintext mail when doing quoting for reply! doh!
@ -1186,11 +1187,13 @@ nsresult
TextEditRules::WillOutputText(Selection* aSelection,
const nsAString* aOutputFormat,
nsAString* aOutString,
uint32_t aFlags,
bool* aCancel,
bool* aHandled)
{
// null selection ok
if (!aOutString || !aOutputFormat || !aCancel || !aHandled) {
if (NS_WARN_IF(!aOutString) || NS_WARN_IF(!aOutputFormat) ||
NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
return NS_ERROR_NULL_POINTER;
}
@ -1198,17 +1201,100 @@ TextEditRules::WillOutputText(Selection* aSelection,
*aCancel = false;
*aHandled = false;
if (aOutputFormat->LowerCaseEqualsLiteral("text/plain")) {
// Only use these rules for plain text output.
if (IsPasswordEditor()) {
*aOutString = mPasswordText;
*aHandled = true;
} else if (mBogusNode) {
// This means there's no content, so output null string.
aOutString->Truncate();
*aHandled = true;
}
if (!aOutputFormat->LowerCaseEqualsLiteral("text/plain")) {
return NS_OK;
}
// XXX Looks like that even if it's password field, we need to use the
// expensive path if the caller requests some complicated handling.
// However, changing the behavior for password field might cause
// security issue. So, be careful when you touch here.
if (IsPasswordEditor()) {
*aOutString = mPasswordText;
*aHandled = true;
return NS_OK;
}
// If there is a bogus node, there's no content. So output empty string.
if (mBogusNode) {
aOutString->Truncate();
*aHandled = true;
return NS_OK;
}
// If it's necessary to check selection range or the editor wraps hard,
// we need some complicated handling. In such case, we need to use the
// expensive path.
// XXX Anything else what we cannot return plain text simply?
if (aFlags & nsIDocumentEncoder::OutputSelectionOnly ||
aFlags & nsIDocumentEncoder::OutputWrap) {
return NS_OK;
}
// If it's neither <input type="text"> nor <textarea>, e.g., an HTML editor
// which is in plaintext mode (e.g., plaintext email composer on Thunderbird),
// it should be handled by the expensive path.
if (NS_WARN_IF(!mTextEditor) || mTextEditor->AsHTMLEditor()) {
return NS_OK;
}
RefPtr<Element> root = mTextEditor->GetRoot();
if (!root) { // Don't warn it, this is possible, e.g., 997805.html
aOutString->Truncate();
*aHandled = true;
return NS_OK;
}
nsIContent* firstChild = root->GetFirstChild();
if (!firstChild) {
aOutString->Truncate();
*aHandled = true;
return NS_OK;
}
// If it's an <input type="text"> element, the DOM tree should be:
// <div class="anonymous-div">
// #text
// </div>
//
// If it's a <textarea> element, the DOM tree should be:
// <div class="anonymous-div">
// #text (if there is)
// <br type="_moz">
// <scrollbar orient="horizontal">
// ...
// </div>
Text* text = firstChild->GetAsText();
nsIContent* firstChildExceptText =
text ? firstChild->GetNextSibling() : firstChild;
// If the DOM tree is unexpected, fall back to the expensive path.
bool isInput = IsSingleLineEditor();
bool isTextarea = !isInput;
if (NS_WARN_IF(isInput && firstChildExceptText) ||
NS_WARN_IF(isTextarea && !firstChildExceptText) ||
NS_WARN_IF(isTextarea &&
!TextEditUtils::IsMozBR(firstChildExceptText) &&
!firstChildExceptText->IsXULElement(nsGkAtoms::scrollbar))) {
return NS_OK;
}
// If there is no text node in the expected DOM tree, we can say that it's
// just empty.
if (!text) {
aOutString->Truncate();
*aHandled = true;
return NS_OK;
}
// Otherwise, the text is the value.
nsresult rv = text->GetData(*aOutString);
if (NS_WARN_IF(NS_FAILED(rv))) {
// Fall back to the expensive path if it fails.
return NS_OK;
}
*aHandled = true;
return NS_OK;
}

Просмотреть файл

@ -171,6 +171,7 @@ protected:
nsresult WillOutputText(Selection* aSelection,
const nsAString* aInFormat,
nsAString* aOutText,
uint32_t aFlags,
bool* aOutCancel,
bool* aHandled);
@ -261,6 +262,8 @@ protected:
friend class AutoLockRulesSniffing;
};
// TODO: This class (almost struct, though) is ugly and its size isn't
// optimized. Should be refined later.
class TextRulesInfo final : public RulesInfo
{
public:
@ -270,6 +273,7 @@ public:
, outString(nullptr)
, outputFormat(nullptr)
, maxLength(-1)
, flags(0)
, collapsedAction(nsIEditor::eNext)
, stripWrappers(nsIEditor::eStrip)
, bOrdered(false)
@ -285,6 +289,9 @@ public:
const nsAString* outputFormat;
int32_t maxLength;
// EditAction::outputText
uint32_t flags;
// EditAction::deleteSelection
nsIEditor::EDirection collapsedAction;
nsIEditor::EStripWrappers stripWrappers;

Просмотреть файл

@ -1313,6 +1313,7 @@ TextEditor::OutputToString(const nsAString& aFormatType,
nsString resultString;
TextRulesInfo ruleInfo(EditAction::outputText);
ruleInfo.outString = &resultString;
ruleInfo.flags = aFlags;
// XXX Struct should store a nsAReadable*
nsAutoString str(aFormatType);
ruleInfo.outputFormat = &str;

Просмотреть файл

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<script type="application/javascript">
let form = document.createElement('form');
let input1 = document.createElement('input');
let input2 = document.createElement('input');
document.documentElement.appendChild(form);
document.documentElement.appendChild(input1);
form.appendChild(input2);
form.contentEditable = true
input1.focus();
let range = document.createRange();
range.selectNode(input2);
window.getSelection().addRange(range);
document.execCommand("italic", false, null);
</script>
</head>
<body></body>
</html>

Просмотреть файл

@ -72,6 +72,7 @@ load 1272490.html
load 1317704.html
load 1317718.html
load 1324505.html
needs-focus load 1343918.html
load 1348851.html
load 1350772.html
load 1366176.html

Просмотреть файл

@ -13,10 +13,6 @@ function GetPermissionsFile(profile)
return file;
}
function run_test() {
run_next_test();
}
add_task(function* test() {
/* Create and set up the permissions database */
let profile = do_get_profile();
@ -59,7 +55,11 @@ add_task(function* test() {
stmtInsert.bindByName("appId", appId);
stmtInsert.bindByName("isInBrowserElement", isInBrowserElement);
stmtInsert.execute();
try {
stmtInsert.execute();
} finally {
stmtInsert.reset();
}
return {
id: thisId,
@ -199,8 +199,12 @@ add_task(function* test() {
// The moz_hosts table should still exist but be empty
let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts");
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), 0);
try {
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), 0);
} finally {
mozHostsCount.finalize();
}
db.close();
}

Просмотреть файл

@ -42,10 +42,6 @@ function GetPermissionsFile(profile)
* Done nsINavHistoryService code
*/
function run_test() {
run_next_test();
}
add_task(function test() {
/* Create and set up the permissions database */
let profile = do_get_profile();
@ -96,7 +92,11 @@ add_task(function test() {
stmtInsert.bindByName("appId", appId);
stmtInsert.bindByName("isInBrowserElement", isInBrowserElement);
stmtInsert.execute();
try {
stmtInsert.execute();
} finally {
stmtInsert.reset();
}
return {
id: thisId,
@ -216,8 +216,12 @@ add_task(function test() {
// The moz_hosts table should still exist but be empty
let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts");
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), 0);
try {
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), 0);
} finally {
mozHostsCount.finalize();
}
db.close();
}

Просмотреть файл

@ -13,10 +13,6 @@ function GetPermissionsFile(profile)
return file;
}
function run_test() {
run_next_test();
}
add_task(function* test() {
/* Create and set up the permissions database */
let profile = do_get_profile();
@ -81,7 +77,11 @@ add_task(function* test() {
stmt5Insert.bindByName("expireTime", expireTime);
stmt5Insert.bindByName("modificationTime", modificationTime);
stmt5Insert.execute();
try {
stmt5Insert.execute();
} finally {
stmt5Insert.reset();
}
return {
id: thisId,
@ -107,7 +107,11 @@ add_task(function* test() {
stmtInsert.bindByName("appId", appId);
stmtInsert.bindByName("isInBrowserElement", isInBrowserElement);
stmtInsert.execute();
try {
stmtInsert.execute();
} finally {
stmtInsert.reset();
}
return {
id: thisId,
@ -151,6 +155,7 @@ add_task(function* test() {
];
// CLose the db connection
stmt5Insert.finalize();
stmtInsert.finalize();
db.close();
stmtInsert = null;
@ -253,31 +258,42 @@ add_task(function* test() {
// The moz_hosts table should still exist but be empty
let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts");
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), 0);
try {
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), 0);
} finally {
mozHostsCount.finalize();
}
// Check that the moz_perms_v6 table contains the backup of the entry we created
let mozPermsV6Stmt = db.createStatement("SELECT " +
"origin, type, permission, expireType, expireTime, modificationTime " +
"FROM moz_perms_v6 WHERE id = :id");
// Check that the moz_hosts table still contains the correct values.
created5.forEach((it) => {
mozPermsV6Stmt.reset();
mozPermsV6Stmt.bindByName("id", it.id);
mozPermsV6Stmt.executeStep();
do_check_eq(mozPermsV6Stmt.getUTF8String(0), it.origin);
do_check_eq(mozPermsV6Stmt.getUTF8String(1), it.type);
do_check_eq(mozPermsV6Stmt.getInt64(2), it.permission);
do_check_eq(mozPermsV6Stmt.getInt64(3), it.expireType);
do_check_eq(mozPermsV6Stmt.getInt64(4), it.expireTime);
do_check_eq(mozPermsV6Stmt.getInt64(5), it.modificationTime);
});
try {
// Check that the moz_hosts table still contains the correct values.
created5.forEach((it) => {
mozPermsV6Stmt.reset();
mozPermsV6Stmt.bindByName("id", it.id);
mozPermsV6Stmt.executeStep();
do_check_eq(mozPermsV6Stmt.getUTF8String(0), it.origin);
do_check_eq(mozPermsV6Stmt.getUTF8String(1), it.type);
do_check_eq(mozPermsV6Stmt.getInt64(2), it.permission);
do_check_eq(mozPermsV6Stmt.getInt64(3), it.expireType);
do_check_eq(mozPermsV6Stmt.getInt64(4), it.expireTime);
do_check_eq(mozPermsV6Stmt.getInt64(5), it.modificationTime);
});
} finally {
mozPermsV6Stmt.finalize();
}
// Check that there are the right number of values
let mozPermsV6Count = db.createStatement("SELECT count(*) FROM moz_perms_v6");
mozPermsV6Count.executeStep();
do_check_eq(mozPermsV6Count.getInt64(0), created5.length);
try {
mozPermsV6Count.executeStep();
do_check_eq(mozPermsV6Count.getInt64(0), created5.length);
} finally {
mozPermsV6Count.finalize();
}
db.close();
}

Просмотреть файл

@ -13,10 +13,6 @@ function GetPermissionsFile(profile)
return file;
}
function run_test() {
run_next_test();
}
add_task(function test() {
/* Create and set up the permissions database */
let profile = do_get_profile();
@ -58,7 +54,11 @@ add_task(function test() {
stmt5Insert.bindByName("expireTime", expireTime);
stmt5Insert.bindByName("modificationTime", modificationTime);
stmt5Insert.execute();
try {
stmt5Insert.execute();
} finally {
stmt5Insert.reset();
}
return {
id: thisId,
@ -142,26 +142,33 @@ add_task(function test() {
"host, type, permission, expireType, expireTime, " +
"modificationTime, appId, isInBrowserElement " +
"FROM moz_hosts WHERE id = :id");
// Check that the moz_hosts table still contains the correct values.
created4.forEach((it) => {
mozHostsStmt.reset();
mozHostsStmt.bindByName("id", it.id);
mozHostsStmt.executeStep();
do_check_eq(mozHostsStmt.getUTF8String(0), it.host);
do_check_eq(mozHostsStmt.getUTF8String(1), it.type);
do_check_eq(mozHostsStmt.getInt64(2), it.permission);
do_check_eq(mozHostsStmt.getInt64(3), it.expireType);
do_check_eq(mozHostsStmt.getInt64(4), it.expireTime);
do_check_eq(mozHostsStmt.getInt64(5), it.modificationTime);
do_check_eq(mozHostsStmt.getInt64(6), it.appId);
do_check_eq(mozHostsStmt.getInt64(7), it.isInBrowserElement);
});
try {
// Check that the moz_hosts table still contains the correct values.
created4.forEach((it) => {
mozHostsStmt.reset();
mozHostsStmt.bindByName("id", it.id);
mozHostsStmt.executeStep();
do_check_eq(mozHostsStmt.getUTF8String(0), it.host);
do_check_eq(mozHostsStmt.getUTF8String(1), it.type);
do_check_eq(mozHostsStmt.getInt64(2), it.permission);
do_check_eq(mozHostsStmt.getInt64(3), it.expireType);
do_check_eq(mozHostsStmt.getInt64(4), it.expireTime);
do_check_eq(mozHostsStmt.getInt64(5), it.modificationTime);
do_check_eq(mozHostsStmt.getInt64(6), it.appId);
do_check_eq(mozHostsStmt.getInt64(7), it.isInBrowserElement);
});
} finally {
mozHostsStmt.finalize();
}
// Check that there are the right number of values
let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts");
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), created4.length);
try {
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), created4.length);
} finally {
mozHostsCount.finalize();
}
db.close();
}

Просмотреть файл

@ -13,10 +13,6 @@ function GetPermissionsFile(profile)
return file;
}
function run_test() {
run_next_test();
}
add_task(function* test() {
/* Create and set up the permissions database */
let profile = do_get_profile();
@ -81,7 +77,11 @@ add_task(function* test() {
stmt6Insert.bindByName("expireTime", expireTime);
stmt6Insert.bindByName("modificationTime", modificationTime);
stmt6Insert.execute();
try {
stmt6Insert.execute();
} finally {
stmt6Insert.reset();
}
return {
id: thisId,
@ -107,7 +107,11 @@ add_task(function* test() {
stmtInsert.bindByName("appId", appId);
stmtInsert.bindByName("isInBrowserElement", isInBrowserElement);
stmtInsert.execute();
try {
stmtInsert.execute();
} finally {
stmtInsert.reset();
}
return {
id: thisId,
@ -151,6 +155,7 @@ add_task(function* test() {
];
// CLose the db connection
stmt6Insert.finalize();
stmtInsert.finalize();
db.close();
stmtInsert = null;
@ -253,31 +258,42 @@ add_task(function* test() {
// The moz_hosts table should still exist but be empty
let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts");
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), 0);
try {
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), 0);
} finally {
mozHostsCount.finalize();
}
// Check that the moz_perms_v6 table contains the backup of the entry we created
let mozPermsV6Stmt = db.createStatement("SELECT " +
"origin, type, permission, expireType, expireTime, modificationTime " +
"FROM moz_perms_v6 WHERE id = :id");
// Check that the moz_hosts table still contains the correct values.
created6.forEach((it) => {
mozPermsV6Stmt.reset();
mozPermsV6Stmt.bindByName("id", it.id);
mozPermsV6Stmt.executeStep();
do_check_eq(mozPermsV6Stmt.getUTF8String(0), it.origin);
do_check_eq(mozPermsV6Stmt.getUTF8String(1), it.type);
do_check_eq(mozPermsV6Stmt.getInt64(2), it.permission);
do_check_eq(mozPermsV6Stmt.getInt64(3), it.expireType);
do_check_eq(mozPermsV6Stmt.getInt64(4), it.expireTime);
do_check_eq(mozPermsV6Stmt.getInt64(5), it.modificationTime);
});
try {
// Check that the moz_hosts table still contains the correct values.
created6.forEach((it) => {
mozPermsV6Stmt.reset();
mozPermsV6Stmt.bindByName("id", it.id);
mozPermsV6Stmt.executeStep();
do_check_eq(mozPermsV6Stmt.getUTF8String(0), it.origin);
do_check_eq(mozPermsV6Stmt.getUTF8String(1), it.type);
do_check_eq(mozPermsV6Stmt.getInt64(2), it.permission);
do_check_eq(mozPermsV6Stmt.getInt64(3), it.expireType);
do_check_eq(mozPermsV6Stmt.getInt64(4), it.expireTime);
do_check_eq(mozPermsV6Stmt.getInt64(5), it.modificationTime);
});
} finally {
mozPermsV6Stmt.finalize();
}
// Check that there are the right number of values
let mozPermsV6Count = db.createStatement("SELECT count(*) FROM moz_perms_v6");
mozPermsV6Count.executeStep();
do_check_eq(mozPermsV6Count.getInt64(0), created6.length);
try {
mozPermsV6Count.executeStep();
do_check_eq(mozPermsV6Count.getInt64(0), created6.length);
} finally {
mozPermsV6Count.finalize();
}
db.close();
}

Просмотреть файл

@ -13,10 +13,6 @@ function GetPermissionsFile(profile)
return file;
}
function run_test() {
run_next_test();
}
add_task(function test() {
/* Create and set up the permissions database */
let profile = do_get_profile();
@ -58,7 +54,11 @@ add_task(function test() {
stmt6Insert.bindByName("expireTime", expireTime);
stmt6Insert.bindByName("modificationTime", modificationTime);
stmt6Insert.execute();
try {
stmt6Insert.execute();
} finally {
stmt6Insert.reset();
}
return {
id: thisId,
@ -136,26 +136,33 @@ add_task(function test() {
"host, type, permission, expireType, expireTime, " +
"modificationTime, appId, isInBrowserElement " +
"FROM moz_hosts WHERE id = :id");
// Check that the moz_hosts table still contains the correct values.
created4.forEach((it) => {
mozHostsStmt.reset();
mozHostsStmt.bindByName("id", it.id);
mozHostsStmt.executeStep();
do_check_eq(mozHostsStmt.getUTF8String(0), it.host);
do_check_eq(mozHostsStmt.getUTF8String(1), it.type);
do_check_eq(mozHostsStmt.getInt64(2), it.permission);
do_check_eq(mozHostsStmt.getInt64(3), it.expireType);
do_check_eq(mozHostsStmt.getInt64(4), it.expireTime);
do_check_eq(mozHostsStmt.getInt64(5), it.modificationTime);
do_check_eq(mozHostsStmt.getInt64(6), it.appId);
do_check_eq(mozHostsStmt.getInt64(7), it.isInBrowserElement);
});
try {
// Check that the moz_hosts table still contains the correct values.
created4.forEach((it) => {
mozHostsStmt.reset();
mozHostsStmt.bindByName("id", it.id);
mozHostsStmt.executeStep();
do_check_eq(mozHostsStmt.getUTF8String(0), it.host);
do_check_eq(mozHostsStmt.getUTF8String(1), it.type);
do_check_eq(mozHostsStmt.getInt64(2), it.permission);
do_check_eq(mozHostsStmt.getInt64(3), it.expireType);
do_check_eq(mozHostsStmt.getInt64(4), it.expireTime);
do_check_eq(mozHostsStmt.getInt64(5), it.modificationTime);
do_check_eq(mozHostsStmt.getInt64(6), it.appId);
do_check_eq(mozHostsStmt.getInt64(7), it.isInBrowserElement);
});
} finally {
mozHostsStmt.finalize();
}
// Check that there are the right number of values
let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts");
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), created4.length);
try {
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), created4.length);
} finally {
mozHostsCount.finalize();
}
db.close();
}

Просмотреть файл

@ -13,10 +13,6 @@ function GetPermissionsFile(profile)
return file;
}
function run_test() {
run_next_test();
}
add_task(function* test() {
/* Create and set up the permissions database */
let profile = do_get_profile();
@ -86,7 +82,11 @@ add_task(function* test() {
stmt6Insert.bindByName("expireTime", expireTime);
stmt6Insert.bindByName("modificationTime", modificationTime);
stmt6Insert.execute();
try {
stmt6Insert.execute();
} finally {
stmt6Insert.reset();
}
return {
id: thisId,
@ -112,7 +112,11 @@ add_task(function* test() {
stmtInsert.bindByName("appId", appId);
stmtInsert.bindByName("isInBrowserElement", isInBrowserElement);
stmtInsert.execute();
try {
stmtInsert.execute();
} finally {
stmtInsert.reset();
}
return {
id: thisId,
@ -161,6 +165,7 @@ add_task(function* test() {
];
// CLose the db connection
stmt6Insert.finalize();
stmtInsert.finalize();
db.close();
stmtInsert = null;
@ -233,13 +238,21 @@ add_task(function* test() {
// The moz_hosts table should still exist but be empty
let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts");
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), 0);
try {
mozHostsCount.executeStep();
do_check_eq(mozHostsCount.getInt64(0), 0);
} finally {
mozHostsCount.finalize();
}
// Check that there are the right number of values in the permissions database
let mozPermsCount = db.createStatement("SELECT count(*) FROM moz_perms");
mozPermsCount.executeStep();
do_check_eq(mozPermsCount.getInt64(0), expected.length);
try {
mozPermsCount.executeStep();
do_check_eq(mozPermsCount.getInt64(0), expected.length);
} finally {
mozPermsCount.finalize();
}
db.close();
}

Просмотреть файл

@ -79,4 +79,4 @@ to make sure that mozjs_sys also has its Cargo.lock file updated if needed, henc
the need to run the cargo update command in js/src as well. Hopefully this will
be resolved soon.
Latest Commit: 6752684fcc7402b0a5480e0b9f73152b2f9ed1e5
Latest Commit: 1d6348023a4a4fdd89dce038640c5da906005acc

Просмотреть файл

@ -216,7 +216,6 @@ struct ParamTraits<WrBuiltDisplayListDescriptor>
static void
Write(Message* aMsg, const WrBuiltDisplayListDescriptor& aParam)
{
WriteParam(aMsg, aParam.display_list_items_size);
WriteParam(aMsg, aParam.builder_start_time);
WriteParam(aMsg, aParam.builder_finish_time);
}
@ -224,8 +223,7 @@ struct ParamTraits<WrBuiltDisplayListDescriptor>
static bool
Read(const Message* aMsg, PickleIterator* aIter, WrBuiltDisplayListDescriptor* aResult)
{
return ReadParam(aMsg, aIter, &aResult->display_list_items_size)
&& ReadParam(aMsg, aIter, &aResult->builder_start_time)
return ReadParam(aMsg, aIter, &aResult->builder_start_time)
&& ReadParam(aMsg, aIter, &aResult->builder_finish_time);
}
};

Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "webrender"
version = "0.40.0"
version = "0.43.0"
authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
license = "MPL-2.0"
repository = "https://github.com/servo/webrender"
@ -13,36 +13,36 @@ profiler = ["thread_profiler/thread_profiler"]
webgl = ["offscreen_gl_context", "webrender_traits/webgl"]
[dependencies]
app_units = "0.4"
bincode = "1.0.0-alpha6"
app_units = "0.5"
bincode = "0.8"
bit-set = "0.4"
byteorder = "1.0"
euclid = "0.14.4"
euclid = "0.15"
fnv = "1.0"
gleam = "0.4.3"
lazy_static = "0.2"
log = "0.3"
num-traits = "0.1.32"
offscreen_gl_context = {version = "0.9.0", features = ["serde", "osmesa"], optional = true}
offscreen_gl_context = {version = "0.11", features = ["serde", "osmesa"], optional = true}
time = "0.1"
rayon = "0.8"
webrender_traits = {path = "../webrender_traits"}
bitflags = "0.7"
gamma-lut = "0.2"
thread_profiler = "0.1.1"
plane-split = "0.5"
plane-split = "0.6"
[dev-dependencies]
angle = {git = "https://github.com/servo/angle", branch = "servo"}
rand = "0.3" # for the benchmarks
servo-glutin = "0.10.1" # for the example apps
servo-glutin = "0.11" # for the example apps
[target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies]
freetype = { version = "0.2", default-features = false }
[target.'cfg(target_os = "windows")'.dependencies]
dwrote = "0.3"
dwrote = "0.4"
[target.'cfg(target_os = "macos")'.dependencies]
core-graphics = "0.7.0"
core-text = "4.0"
core-graphics = "0.8.0"
core-text = { version = "5.0.1", features = ["lion"] }

Просмотреть файл

@ -77,7 +77,7 @@ fn render_blob(
let tc = if tile_checker { 0 } else { (1 - checker) * 40 };
match descriptor.format {
wt::ImageFormat::RGBA8 => {
wt::ImageFormat::BGRA8 => {
texels.push(color.b * checker + tc);
texels.push(color.g * checker + tc);
texels.push(color.r * checker + tc);
@ -221,7 +221,7 @@ fn body(api: &wt::RenderApi,
let blob_img1 = api.generate_image_key();
api.add_image(
blob_img1,
wt::ImageDescriptor::new(500, 500, wt::ImageFormat::RGBA8, true),
wt::ImageDescriptor::new(500, 500, wt::ImageFormat::BGRA8, true),
wt::ImageData::new_blob_image(serialize_blob(wt::ColorU::new(50, 50, 150, 255))),
Some(128),
);
@ -229,7 +229,7 @@ fn body(api: &wt::RenderApi,
let blob_img2 = api.generate_image_key();
api.add_image(
blob_img2,
wt::ImageDescriptor::new(200, 200, wt::ImageFormat::RGBA8, true),
wt::ImageDescriptor::new(200, 200, wt::ImageFormat::BGRA8, true),
wt::ImageData::new_blob_image(serialize_blob(wt::ColorU::new(50, 150, 50, 255))),
None,
);

Просмотреть файл

@ -0,0 +1,132 @@
/* 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/. */
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate webrender_traits;
#[macro_use]
extern crate lazy_static;
#[path="common/boilerplate.rs"]
mod boilerplate;
use boilerplate::HandyDandyRectBuilder;
use std::sync::Mutex;
use webrender_traits::*;
fn body(_api: &RenderApi,
builder: &mut DisplayListBuilder,
pipeline_id: &PipelineId,
layout_size: &LayoutSize)
{
let bounds = LayoutRect::new(LayoutPoint::zero(), *layout_size);
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
bounds,
None,
TransformStyle::Flat,
None,
webrender_traits::MixBlendMode::Normal,
Vec::new());
let outer_scroll_frame_rect = (100, 100).to(600, 400);
let token = builder.push_clip_region(&outer_scroll_frame_rect, vec![], None);
builder.push_rect(outer_scroll_frame_rect,
token, ColorF::new(1.0, 1.0, 1.0, 1.0));
let token = builder.push_clip_region(&outer_scroll_frame_rect, vec![], None);
let nested_clip_id = builder.define_clip((100, 100).to(1000, 1000), token, None);
builder.push_clip_id(nested_clip_id);
let mut builder2 = webrender_traits::DisplayListBuilder::new(*pipeline_id, *layout_size);
let mut builder3 = webrender_traits::DisplayListBuilder::new(*pipeline_id, *layout_size);
let rect = (110, 110).to(210, 210);
let token = builder3.push_clip_region(&rect, vec![], None);
builder3.push_rect(rect, token, ColorF::new(0.0, 1.0, 0.0, 1.0));
// A fixed position rectangle should be fixed to the reference frame that starts
// in the outer display list.
builder3.push_stacking_context(webrender_traits::ScrollPolicy::Fixed,
(220, 110).to(320, 210),
None,
TransformStyle::Flat,
None,
webrender_traits::MixBlendMode::Normal,
Vec::new());
let rect = (0, 0).to(100, 100);
let token = builder3.push_clip_region(&rect, vec![], None);
builder3.push_rect(rect, token, ColorF::new(0.0, 1.0, 0.0, 1.0));
builder3.pop_stacking_context();
// Now we push an inner scroll frame that should have the same id as the outer one,
// but the WebRender nested display list replacement code should convert it into
// a unique ClipId.
let inner_scroll_frame_rect = (330, 110).to(530, 360);
let token = builder3.push_clip_region(&inner_scroll_frame_rect, vec![], None);
builder3.push_rect(inner_scroll_frame_rect, token, ColorF::new(1.0, 0.0, 1.0, 0.5));
let token = builder3.push_clip_region(&inner_scroll_frame_rect, vec![], None);
let inner_nested_clip_id = builder3.define_clip((330, 110).to(2000, 2000), token, None);
builder3.push_clip_id(inner_nested_clip_id);
let rect = (340, 120).to(440, 220);
let token = builder3.push_clip_region(&rect, vec![], None);
builder3.push_rect(rect, token, ColorF::new(0.0, 1.0, 0.0, 1.0));
builder3.pop_clip_id();
let (_, _, built_list) = builder3.finalize();
builder2.push_nested_display_list(&built_list);
let (_, _, built_list) = builder2.finalize();
builder.push_nested_display_list(&built_list);
builder.pop_clip_id();
builder.pop_stacking_context();
}
lazy_static! {
static ref CURSOR_POSITION: Mutex<WorldPoint> = Mutex::new(WorldPoint::zero());
}
fn event_handler(event: &glutin::Event,
api: &RenderApi)
{
match *event {
glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(key)) => {
let offset = match key {
glutin::VirtualKeyCode::Down => (0.0, -10.0),
glutin::VirtualKeyCode::Up => (0.0, 10.0),
glutin::VirtualKeyCode::Right => (-10.0, 0.0),
glutin::VirtualKeyCode::Left => (10.0, 0.0),
_ => return,
};
api.scroll(ScrollLocation::Delta(LayoutVector2D::new(offset.0, offset.1)),
*CURSOR_POSITION.lock().unwrap(),
ScrollEventPhase::Start);
}
glutin::Event::MouseMoved(x, y) => {
*CURSOR_POSITION.lock().unwrap() = WorldPoint::new(x as f32, y as f32);
}
glutin::Event::MouseWheel(delta, _, event_cursor_position) => {
if let Some((x, y)) = event_cursor_position {
*CURSOR_POSITION.lock().unwrap() = WorldPoint::new(x as f32, y as f32);
}
const LINE_HEIGHT: f32 = 38.0;
let (dx, dy) = match delta {
glutin::MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
glutin::MouseScrollDelta::PixelDelta(dx, dy) => (dx, dy),
};
api.scroll(ScrollLocation::Delta(LayoutVector2D::new(dx, dy)),
*CURSOR_POSITION.lock().unwrap(),
ScrollEventPhase::Start);
}
_ => ()
}
}
fn main() {
boilerplate::main_wrapper(body, event_handler, None);
}

Просмотреть файл

@ -15,12 +15,14 @@ in int aClipRenderTaskIndex;
in int aClipLayerIndex;
in int aClipDataIndex;
in int aClipSegmentIndex;
in int aClipResourceAddress;
struct CacheClipInstance {
int render_task_index;
int layer_index;
int data_index;
int segment_index;
int resource_address;
};
CacheClipInstance fetch_clip_item(int index) {
@ -30,6 +32,7 @@ CacheClipInstance fetch_clip_item(int index) {
cci.layer_index = aClipLayerIndex;
cci.data_index = aClipDataIndex;
cci.segment_index = aClipSegmentIndex;
cci.resource_address = aClipResourceAddress;
return cci;
}

Просмотреть файл

@ -4,14 +4,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
struct ImageMaskData {
RectWithSize uv_rect;
RectWithSize local_rect;
};
ImageMaskData fetch_mask_data(int index) {
vec4 data[2] = fetch_data_2(index);
return ImageMaskData(RectWithSize(data[0].xy, data[0].zw),
RectWithSize(data[1].xy, data[1].zw));
return ImageMaskData(RectWithSize(data[0].xy, data[0].zw));
}
void main(void) {
@ -20,6 +18,7 @@ void main(void) {
Layer layer = fetch_layer(cci.layer_index);
ImageMaskData mask = fetch_mask_data(cci.data_index);
RectWithSize local_rect = mask.local_rect;
ImageResource res = fetch_image_resource(cci.resource_address);
ClipVertexInfo vi = write_clip_tile_vertex(local_rect,
layer,
@ -30,8 +29,8 @@ void main(void) {
vClipMaskUv = vec3((vPos.xy / vPos.z - local_rect.p0) / local_rect.size, 0.0);
vec2 texture_size = vec2(textureSize(sColor0, 0));
vClipMaskUvRect = vec4(mask.uv_rect.p0, mask.uv_rect.size) / texture_size.xyxy;
vClipMaskUvRect = vec4(res.uv_rect.xy, res.uv_rect.zw - res.uv_rect.xy) / texture_size.xyxy;
// applying a half-texel offset to the UV boundaries to prevent linear samples from the outside
vec4 inner_rect = vec4(mask.uv_rect.p0, mask.uv_rect.p0 + mask.uv_rect.size);
vec4 inner_rect = vec4(res.uv_rect.xy, res.uv_rect.zw);
vClipMaskUvInnerRect = (inner_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy;
}

Просмотреть файл

@ -12,15 +12,16 @@ void main(void) {
TextRun text = fetch_text_run(prim.specific_prim_address);
int glyph_index = prim.user_data0;
int resource_address = prim.user_data1;
int resource_address = prim.user_data2;
Glyph glyph = fetch_glyph(prim.specific_prim_address, glyph_index);
ResourceRect res = fetch_resource_rect(resource_address + glyph_index);
GlyphResource res = fetch_glyph_resource(resource_address);
// Glyphs size is already in device-pixels.
// The render task origin is in device-pixels. Offset that by
// the glyph offset, relative to its primitive bounding rect.
vec2 size = res.uv_rect.zw - res.uv_rect.xy;
vec2 origin = prim.task.screen_space_origin + uDevicePixelRatio * (glyph.offset - prim.local_rect.p0);
vec2 local_pos = glyph.offset + vec2(res.offset.x, -res.offset.y) / uDevicePixelRatio;
vec2 origin = prim.task.screen_space_origin + uDevicePixelRatio * (local_pos - prim.local_rect.p0);
vec4 local_rect = vec4(origin, size);
vec2 texture_size = vec2(textureSize(sColor0, 0));

Просмотреть файл

@ -10,7 +10,16 @@
#else
precision mediump sampler2DArray;
#endif
// Sampler default precision is lowp on mobile GPUs.
// This causes RGBA32F texture data to be clamped to 16 bit floats on some GPUs (e.g. Mali-T880).
// Define highp precision macro to allow lossless FLOAT texture sampling.
#define HIGHP_SAMPLER_FLOAT highp
#else
#define HIGHP_SAMPLER_FLOAT
#endif
#else
#define HIGHP_SAMPLER_FLOAT
#endif
#define PST_TOP_LEFT 0
@ -80,17 +89,8 @@ vec2 clamp_rect(vec2 point, RectWithSize rect) {
return clamp(point, rect.p0, rect.p0 + rect.size);
}
vec2 clamp_rect(vec2 point, RectWithEndpoint rect) {
return clamp(point, rect.p0, rect.p1);
}
// Clamp 2 points at once.
vec4 clamp_rect(vec4 points, RectWithSize rect) {
return clamp(points, rect.p0.xyxy, rect.p0.xyxy + rect.size.xyxy);
}
RectWithSize intersect_rect(RectWithSize a, RectWithSize b) {
vec4 p = clamp_rect(vec4(a.p0, a.p0 + a.size), b);
vec4 p = clamp(vec4(a.p0, a.p0 + a.size), b.p0.xyxy, b.p0.xyxy + b.size.xyxy);
return RectWithSize(p.xy, max(vec2(0.0), p.zw - p.xy));
}
@ -118,7 +118,7 @@ ivec2 get_resource_cache_uv(int address) {
address / WR_MAX_VERTEX_TEXTURE_WIDTH);
}
uniform sampler2D sResourceCache;
uniform HIGHP_SAMPLER_FLOAT sampler2D sResourceCache;
vec4[2] fetch_from_resource_cache_2(int address) {
ivec2 uv = get_resource_cache_uv(address);
@ -137,12 +137,10 @@ vec4[2] fetch_from_resource_cache_2(int address) {
#define VECS_PER_GRADIENT 3
#define VECS_PER_GRADIENT_STOP 2
uniform sampler2D sLayers;
uniform sampler2D sRenderTasks;
uniform HIGHP_SAMPLER_FLOAT sampler2D sLayers;
uniform HIGHP_SAMPLER_FLOAT sampler2D sRenderTasks;
uniform sampler2D sData16;
uniform sampler2D sData32;
uniform sampler2D sResourceRects;
uniform HIGHP_SAMPLER_FLOAT sampler2D sData32;
// Instanced attributes
in ivec4 aData0;
@ -154,11 +152,6 @@ in ivec4 aData1;
// https://github.com/servo/servo/issues/13953
#define get_fetch_uv(i, vpi) ivec2(vpi * (i % (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi)), i / (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi))
vec4 fetch_data_1(int index) {
ivec2 uv = get_fetch_uv(index, 1);
return texelFetch(sData16, uv, 0);
}
vec4[2] fetch_data_2(int index) {
ivec2 uv = get_fetch_uv(index, 2);
return vec4[2](
@ -455,6 +448,7 @@ struct PrimitiveInstance {
int z;
int user_data0;
int user_data1;
int user_data2;
};
PrimitiveInstance fetch_prim_instance() {
@ -468,6 +462,7 @@ PrimitiveInstance fetch_prim_instance() {
pi.z = aData1.x;
pi.user_data0 = aData1.y;
pi.user_data1 = aData1.z;
pi.user_data2 = aData1.w;
return pi;
}
@ -504,6 +499,7 @@ struct Primitive {
int specific_prim_address;
int user_data0;
int user_data1;
int user_data2;
float z;
};
@ -523,6 +519,7 @@ Primitive load_primitive() {
prim.specific_prim_address = pi.specific_prim_address;
prim.user_data0 = pi.user_data0;
prim.user_data1 = pi.user_data1;
prim.user_data2 = pi.user_data2;
prim.z = float(pi.z);
return prim;
@ -571,6 +568,35 @@ vec4 get_layer_pos(vec2 pos, Layer layer) {
return untransform(pos, n, a, layer.inv_transform);
}
// Compute a snapping offset in world space (adjusted to pixel ratio),
// given local position on the layer and a snap rectangle.
vec2 compute_snap_offset(vec2 local_pos,
RectWithSize local_clip_rect,
Layer layer,
RectWithSize snap_rect) {
// Ensure that the snap rect is at *least* one device pixel in size.
// TODO(gw): It's not clear to me that this is "correct". Specifically,
// how should it interact with sub-pixel snap rects when there
// is a layer transform with scale present? But it does fix
// the test cases we have in Servo that are failing without it
// and seem better than not having this at all.
snap_rect.size = max(snap_rect.size, vec2(1.0 / uDevicePixelRatio));
// Transform the snap corners to the world space.
vec4 world_snap_p0 = layer.transform * vec4(snap_rect.p0, 0.0, 1.0);
vec4 world_snap_p1 = layer.transform * vec4(snap_rect.p0 + snap_rect.size, 0.0, 1.0);
// Snap bounds in world coordinates, adjusted for pixel ratio. XY = top left, ZW = bottom right
vec4 world_snap = uDevicePixelRatio * vec4(world_snap_p0.xy, world_snap_p1.xy) /
vec4(world_snap_p0.ww, world_snap_p1.ww);
/// World offsets applied to the corners of the snap rectangle.
vec4 snap_offsets = floor(world_snap + 0.5) - world_snap;
/// Compute the position of this vertex inside the snap rectangle.
vec2 normalized_snap_pos = (local_pos - snap_rect.p0) / snap_rect.size;
/// Compute the actual world offset for this vertex needed to make it snap.
return mix(snap_offsets.xy, snap_offsets.zw, normalized_snap_pos);
}
struct VertexInfo {
vec2 local_pos;
vec2 screen_pos;
@ -581,38 +607,32 @@ VertexInfo write_vertex(RectWithSize instance_rect,
float z,
Layer layer,
AlphaBatchTask task,
vec2 snap_ref) {
RectWithSize snap_rect) {
// Select the corner of the local rect that we are processing.
vec2 local_pos = instance_rect.p0 + instance_rect.size * aPosition.xy;
// xy = top left corner of the local rect, zw = position of current vertex.
vec4 local_p0_pos = vec4(snap_ref, local_pos);
// Clamp to the two local clip rects.
local_p0_pos = clamp_rect(local_p0_pos, local_clip_rect);
local_p0_pos = clamp_rect(local_p0_pos, layer.local_clip_rect);
vec2 clamped_local_pos = clamp_rect(clamp_rect(local_pos, local_clip_rect),
layer.local_clip_rect);
// Transform the top corner and current vertex to world space.
vec4 world_p0 = layer.transform * vec4(local_p0_pos.xy, 0.0, 1.0);
world_p0.xyz /= world_p0.w;
vec4 world_pos = layer.transform * vec4(local_p0_pos.zw, 0.0, 1.0);
world_pos.xyz /= world_pos.w;
/// Compute the snapping offset.
vec2 snap_offset = compute_snap_offset(clamped_local_pos, local_clip_rect, layer, snap_rect);
// Convert the world positions to device pixel space. xy=top left corner. zw=current vertex.
vec4 device_p0_pos = vec4(world_p0.xy, world_pos.xy) * uDevicePixelRatio;
// Transform the current vertex to the world cpace.
vec4 world_pos = layer.transform * vec4(clamped_local_pos, 0.0, 1.0);
// Calculate the distance to snap the vertex by (snap top left corner).
vec2 snap_delta = device_p0_pos.xy - floor(device_p0_pos.xy + 0.5);
// Convert the world positions to device pixel space.
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;
// Apply offsets for the render task to get correct screen location.
vec2 final_pos = device_p0_pos.zw -
snap_delta -
vec2 final_pos = device_pos + snap_offset -
task.screen_space_origin +
task.render_target_origin;
gl_Position = uTransform * vec4(final_pos, z, 1.0);
VertexInfo vi = VertexInfo(local_p0_pos.zw, device_p0_pos.zw);
VertexInfo vi = VertexInfo(clamped_local_pos, device_pos);
return vi;
}
@ -647,7 +667,7 @@ TransformVertexInfo write_transform_vertex(RectWithSize instance_rect,
float z,
Layer layer,
AlphaBatchTask task,
vec2 snap_ref) {
RectWithSize snap_rect) {
RectWithEndpoint local_rect = to_rect_with_endpoint(instance_rect);
vec2 current_local_pos, prev_local_pos, next_local_pos;
@ -706,14 +726,14 @@ TransformVertexInfo write_transform_vertex(RectWithSize instance_rect,
adjusted_next_p0,
adjusted_next_p1);
// Calculate the snap amount based on the first vertex as a reference point.
vec4 world_p0 = layer.transform * vec4(snap_ref, 0.0, 1.0);
vec2 device_p0 = uDevicePixelRatio * world_p0.xy / world_p0.w;
vec2 snap_delta = device_p0 - floor(device_p0 + 0.5);
vec4 layer_pos = get_layer_pos(device_pos / uDevicePixelRatio, layer);
/// Compute the snapping offset.
vec2 snap_offset = compute_snap_offset(layer_pos.xy / layer_pos.w,
local_clip_rect, layer, snap_rect);
// Apply offsets for the render task to get correct screen location.
vec2 final_pos = device_pos -
snap_delta -
vec2 final_pos = device_pos + snap_offset -
task.screen_space_origin +
task.render_target_origin;
@ -721,25 +741,28 @@ TransformVertexInfo write_transform_vertex(RectWithSize instance_rect,
vLocalBounds = vec4(local_rect.p0, local_rect.p1);
vec4 layer_pos = get_layer_pos(device_pos / uDevicePixelRatio, layer);
return TransformVertexInfo(layer_pos.xyw, device_pos);
}
#endif //WR_FEATURE_TRANSFORM
struct ResourceRect {
struct GlyphResource {
vec4 uv_rect;
vec2 offset;
};
GlyphResource fetch_glyph_resource(int address) {
vec4 data[2] = fetch_from_resource_cache_2(address);
return GlyphResource(data[0], data[1].xy);
}
struct ImageResource {
vec4 uv_rect;
};
ResourceRect fetch_resource_rect(int index) {
ResourceRect rect;
ivec2 uv = get_fetch_uv(index, 1);
rect.uv_rect = texelFetchOffset(sResourceRects, uv, 0, ivec2(0, 0));
return rect;
ImageResource fetch_image_resource(int address) {
vec4 data = fetch_from_resource_cache_1(address);
return ImageResource(data);
}
struct Rectangle {
@ -763,11 +786,12 @@ TextRun fetch_text_run(int address) {
struct Image {
vec4 stretch_size_and_tile_spacing; // Size of the actual image and amount of space between
// tiled instances of this image.
vec4 sub_rect; // If negative, ignored.
};
Image fetch_image(int address) {
vec4 data = fetch_from_resource_cache_1(address);
return Image(data);
vec4 data[2] = fetch_from_resource_cache_2(address);
return Image(data[0], data[1]);
}
struct YuvImage {

Просмотреть файл

@ -12,7 +12,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
vPos = vi.local_pos - prim.local_rect.p0;

Просмотреть файл

@ -271,14 +271,14 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
#else
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
#endif
vLocalPos = vi.local_pos;

Просмотреть файл

@ -184,14 +184,14 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
#else
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
#endif
vLocalPos = vi.local_pos;

Просмотреть файл

@ -15,7 +15,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
RenderTaskData child_task = fetch_render_task(prim.user_data1);
vUv.z = child_task.data1.x;

Просмотреть файл

@ -14,7 +14,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
RenderTaskData child_task = fetch_render_task(prim.user_data1);
vUv.z = child_task.data1.x;

Просмотреть файл

@ -66,7 +66,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
vLocalPos = vi.local_pos;
vec2 f = (vi.local_pos.xy - prim.local_rect.p0) / prim.local_rect.size;
#else
@ -75,7 +75,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
vec2 f = (vi.local_pos - segment_rect.p0) / segment_rect.size;
vPos = vi.local_pos;

Просмотреть файл

@ -6,7 +6,7 @@
void main(void) {
Primitive prim = load_primitive();
Image image = fetch_image(prim.specific_prim_address);
ResourceRect res = fetch_resource_rect(prim.user_data0);
ImageResource res = fetch_image_resource(prim.user_data0);
#ifdef WR_FEATURE_TRANSFORM
TransformVertexInfo vi = write_transform_vertex(prim.local_rect,
@ -14,7 +14,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
vLocalPos = vi.local_pos;
#else
VertexInfo vi = write_vertex(prim.local_rect,
@ -22,7 +22,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
vLocalPos = vi.local_pos - prim.local_rect.p0;
#endif
@ -36,9 +36,19 @@ void main(void) {
vec2 texture_size_normalization_factor = vec2(textureSize(sColor0, 0));
#endif
vec2 uv0, uv1;
if (image.sub_rect.x < 0.0) {
uv0 = res.uv_rect.xy;
uv1 = res.uv_rect.zw;
} else {
uv0 = res.uv_rect.xy + image.sub_rect.xy;
uv1 = res.uv_rect.xy + image.sub_rect.zw;
}
// vUv will contain how many times this image has wrapped around the image size.
vec2 st0 = res.uv_rect.xy / texture_size_normalization_factor;
vec2 st1 = res.uv_rect.zw / texture_size_normalization_factor;
vec2 st0 = uv0 / texture_size_normalization_factor;
vec2 st1 = uv1 / texture_size_normalization_factor;
vTextureSize = st1 - st0;
vTextureOffset = st0;

Просмотреть файл

@ -12,7 +12,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
vPos = vi.local_pos - prim.local_rect.p0;

Просмотреть файл

@ -13,7 +13,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
vLocalPos = vi.local_pos;
#else
VertexInfo vi = write_vertex(prim.local_rect,
@ -21,7 +21,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
prim.local_rect.p0);
prim.local_rect);
#endif
#ifdef WR_FEATURE_CLIP

Просмотреть файл

@ -8,11 +8,13 @@ void main(void) {
TextRun text = fetch_text_run(prim.specific_prim_address);
int glyph_index = prim.user_data0;
int resource_address = prim.user_data1;
int resource_address = prim.user_data2;
Glyph glyph = fetch_glyph(prim.specific_prim_address, glyph_index);
ResourceRect res = fetch_resource_rect(resource_address + glyph_index);
GlyphResource res = fetch_glyph_resource(resource_address);
RectWithSize local_rect = RectWithSize(glyph.offset,
vec2 local_pos = glyph.offset + vec2(res.offset.x, -res.offset.y) / uDevicePixelRatio;
RectWithSize local_rect = RectWithSize(local_pos,
(res.uv_rect.zw - res.uv_rect.xy) / uDevicePixelRatio);
#ifdef WR_FEATURE_TRANSFORM
@ -21,7 +23,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
local_rect.p0);
local_rect);
vLocalPos = vi.local_pos;
vec2 f = (vi.local_pos.xy / vi.local_pos.z - local_rect.p0) / local_rect.size;
#else
@ -30,7 +32,7 @@ void main(void) {
prim.z,
prim.layer,
prim.task,
local_rect.p0);
local_rect);
vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
#endif

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше