зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound, a=merge
MozReview-Commit-ID: BYGylgZSbUu
This commit is contained in:
Коммит
47a595548e
|
@ -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())) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче