mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
6486c70d50
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="53a59364ce4f14068034c8d6fe01f4f6b9f78f23">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3a838afca295c9db32e1a3ec76d49fb7fe7fd2d2"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="39cad6c82122b964f12a66771bfbcc14fb342d9e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a838afca295c9db32e1a3ec76d49fb7fe7fd2d2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="39cad6c82122b964f12a66771bfbcc14fb342d9e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3a838afca295c9db32e1a3ec76d49fb7fe7fd2d2"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="39cad6c82122b964f12a66771bfbcc14fb342d9e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
|
||||
@ -130,7 +130,7 @@
|
||||
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
|
||||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="197cd9492b9fadaa915c5daf36ff557f8f4a8d1c"/>
|
||||
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="30d0dfa566651fea8031551e86cec6018b7bbb12"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="57b16fcb790bdf0b53b3c6435a37ccc8ca90ed36"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9f28c4faea3b2f01db227b2467b08aeba96d9bec"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="aad3e80dea67774aa51ed4e6c054856168dd180b"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="53a59364ce4f14068034c8d6fe01f4f6b9f78f23">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3a838afca295c9db32e1a3ec76d49fb7fe7fd2d2"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="39cad6c82122b964f12a66771bfbcc14fb342d9e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
@ -128,7 +128,7 @@
|
||||
<!-- Emulator specific things -->
|
||||
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="72ffdf71c68a96309212eb13d63560d66db14c9e"/>
|
||||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="c0e0019a6ec1a6199a9c7bc4ace041259f3b8512"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="5f184e4aa6ad784e20b4c5e6be24db4b9a848087"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="e4b7cd053711ece3cd5616cd4fb7f75c43bce9c0"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="694cecf256122d0cb3b6a1a4efb4b5c7401db223"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="97d63c256a047b491565d624aea1dd5f1f8593ea"/>
|
||||
<project name="platform/development" path="development" revision="5968ff4e13e0d696ad8d972281fc27ae5a12829b"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a838afca295c9db32e1a3ec76d49fb7fe7fd2d2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="39cad6c82122b964f12a66771bfbcc14fb342d9e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3a838afca295c9db32e1a3ec76d49fb7fe7fd2d2"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="39cad6c82122b964f12a66771bfbcc14fb342d9e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "d4afc0a7f72fd7793359b9575ea7c90cd54e2348",
|
||||
"revision": "6fa1c6e992e9d7169e8e6cd8c714d1983087a87c",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a838afca295c9db32e1a3ec76d49fb7fe7fd2d2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="39cad6c82122b964f12a66771bfbcc14fb342d9e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a838afca295c9db32e1a3ec76d49fb7fe7fd2d2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="39cad6c82122b964f12a66771bfbcc14fb342d9e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3a838afca295c9db32e1a3ec76d49fb7fe7fd2d2"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="39cad6c82122b964f12a66771bfbcc14fb342d9e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3a838afca295c9db32e1a3ec76d49fb7fe7fd2d2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="39cad6c82122b964f12a66771bfbcc14fb342d9e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -249,15 +249,37 @@ var tests = {
|
||||
SocialService.registerProviderListener(function providerListener(topic, origin, providers) {
|
||||
if (topic != "provider-update")
|
||||
return;
|
||||
is(origin, addonManifest.origin, "provider updated")
|
||||
// The worker will have reloaded and the current provider instance
|
||||
// disabled, removed from the provider list. We have a reference
|
||||
// here, check it is is disabled.
|
||||
is(provider.enabled, false, "old provider instance is disabled")
|
||||
is(origin, addonManifest.origin, "provider manifest updated")
|
||||
SocialService.unregisterProviderListener(providerListener);
|
||||
Services.prefs.clearUserPref("social.whitelist");
|
||||
let provider = Social._getProviderFromOrigin(origin);
|
||||
is(provider.manifest.version, 2, "manifest version is 2");
|
||||
Social.uninstallProvider(origin, function() {
|
||||
gBrowser.removeTab(tab);
|
||||
next();
|
||||
});
|
||||
|
||||
// Get the new provider instance, fetch the manifest via workerapi
|
||||
// and validate that data as well.
|
||||
let p = Social._getProviderFromOrigin(origin);
|
||||
is(p.manifest.version, 2, "manifest version is 2");
|
||||
let port = p.getWorkerPort();
|
||||
ok(port, "got a new port");
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
switch (topic) {
|
||||
case "social.manifest":
|
||||
let manifest = e.data.data;
|
||||
is(manifest.version, 2, "manifest version is 2");
|
||||
port.close();
|
||||
Social.uninstallProvider(origin, function() {
|
||||
Services.prefs.clearUserPref("social.whitelist");
|
||||
gBrowser.removeTab(tab);
|
||||
next();
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
port.postMessage({topic: "test-init"});
|
||||
port.postMessage({topic: "manifest-get"});
|
||||
|
||||
});
|
||||
|
||||
let port = provider.getWorkerPort();
|
||||
|
@ -2,7 +2,7 @@
|
||||
* 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/. */
|
||||
|
||||
let testPort, sidebarPort, apiPort;
|
||||
let testPort, sidebarPort, apiPort, updatingManifest=false;
|
||||
|
||||
onconnect = function(e) {
|
||||
let port = e.ports[0];
|
||||
@ -116,12 +116,21 @@ onconnect = function(e) {
|
||||
if (testPort)
|
||||
testPort.postMessage({topic:"got-share-data-message", result: event.data.result});
|
||||
break;
|
||||
case "manifest-get":
|
||||
apiPort.postMessage({topic: 'social.manifest-get'});
|
||||
break;
|
||||
case "worker.update":
|
||||
updatingManifest = true;
|
||||
apiPort.postMessage({topic: 'social.manifest-get'});
|
||||
break;
|
||||
case "social.manifest":
|
||||
event.data.data.version = 2;
|
||||
apiPort.postMessage({topic: 'social.manifest-set', data: event.data.data});
|
||||
if (updatingManifest) {
|
||||
updatingManifest = false;
|
||||
event.data.data.version = 2;
|
||||
apiPort.postMessage({topic: 'social.manifest-set', data: event.data.data});
|
||||
} else if (testPort) {
|
||||
testPort.postMessage({topic:"social.manifest", data: event.data.data});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1171,6 +1171,7 @@ SourceScripts.prototype = {
|
||||
// both in the editor and the breakpoints pane.
|
||||
DebuggerController.Breakpoints.updatePaneBreakpoints();
|
||||
DebuggerController.Breakpoints.updateEditorBreakpoints();
|
||||
DebuggerController.HitCounts.updateEditorHitCounts();
|
||||
|
||||
// Make sure the events listeners are up to date.
|
||||
if (DebuggerView.instrumentsPaneTab == "events-tab") {
|
||||
@ -1223,6 +1224,7 @@ SourceScripts.prototype = {
|
||||
// both in the editor and the breakpoints pane.
|
||||
DebuggerController.Breakpoints.updatePaneBreakpoints();
|
||||
DebuggerController.Breakpoints.updateEditorBreakpoints();
|
||||
DebuggerController.HitCounts.updateEditorHitCounts();
|
||||
|
||||
// Signal that sources have been added.
|
||||
window.emit(EVENTS.SOURCES_ADDED);
|
||||
@ -1488,6 +1490,7 @@ Tracer.prototype = {
|
||||
let fields = [
|
||||
"name",
|
||||
"location",
|
||||
"hitCount",
|
||||
"parameterNames",
|
||||
"depth",
|
||||
"arguments",
|
||||
@ -1521,6 +1524,7 @@ Tracer.prototype = {
|
||||
}
|
||||
|
||||
this._trace = null;
|
||||
DebuggerController.HitCounts.clear();
|
||||
aCallback(aResponse);
|
||||
});
|
||||
},
|
||||
@ -1529,6 +1533,15 @@ Tracer.prototype = {
|
||||
const tracesLength = traces.length;
|
||||
let tracesToShow;
|
||||
|
||||
// Update hit counts.
|
||||
for (let t of traces) {
|
||||
if (t.type == "enteredFrame") {
|
||||
DebuggerController.HitCounts.set(t.location, t.hitCount);
|
||||
}
|
||||
}
|
||||
DebuggerController.HitCounts.updateEditorHitCounts();
|
||||
|
||||
// Limit number of traces to be shown in the log.
|
||||
if (tracesLength > TracerView.MAX_TRACES) {
|
||||
tracesToShow = traces.slice(tracesLength - TracerView.MAX_TRACES, tracesLength);
|
||||
this._stack.splice(0, this._stack.length);
|
||||
@ -1537,6 +1550,7 @@ Tracer.prototype = {
|
||||
tracesToShow = traces;
|
||||
}
|
||||
|
||||
// Show traces in the log.
|
||||
for (let t of tracesToShow) {
|
||||
if (t.type == "enteredFrame") {
|
||||
this._onCall(t);
|
||||
@ -1544,7 +1558,6 @@ Tracer.prototype = {
|
||||
this._onReturn(t);
|
||||
}
|
||||
}
|
||||
|
||||
DebuggerView.Tracer.commit();
|
||||
},
|
||||
|
||||
@ -2224,6 +2237,84 @@ Object.defineProperty(Breakpoints.prototype, "_addedOrDisabled", {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles Tracer's hit counts.
|
||||
*/
|
||||
function HitCounts() {
|
||||
/**
|
||||
* Storage of hit counts for every location
|
||||
* hitCount = _locations[url][line][column]
|
||||
*/
|
||||
this._hitCounts = Object.create(null);
|
||||
}
|
||||
|
||||
HitCounts.prototype = {
|
||||
set: function({url, line, column}, aHitCount) {
|
||||
if (!this._hitCounts[url]) {
|
||||
this._hitCounts[url] = Object.create(null);
|
||||
}
|
||||
if (!this._hitCounts[url][line]) {
|
||||
this._hitCounts[url][line] = Object.create(null);
|
||||
}
|
||||
this._hitCounts[url][line][column] = aHitCount;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update all the hit counts in the editor view. This is invoked when the
|
||||
* selected script is changed, or when new sources are received via the
|
||||
* _onNewSource and _onSourcesAdded event listeners.
|
||||
*/
|
||||
updateEditorHitCounts: function() {
|
||||
// First, remove all hit counters.
|
||||
DebuggerView.editor.removeAllMarkers("hit-counts");
|
||||
|
||||
// Then, add new hit counts, just for the current source.
|
||||
for (let url in this._hitCounts) {
|
||||
for (let line in this._hitCounts[url]) {
|
||||
for (let column in this._hitCounts[url][line]) {
|
||||
this._updateEditorHitCount({url, line, column});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update a hit counter on a certain line.
|
||||
*/
|
||||
_updateEditorHitCount: function({url, line, column}) {
|
||||
// Editor must be initialized.
|
||||
if (!DebuggerView.editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to do anything if the counter's source is not being shown in the
|
||||
// editor.
|
||||
if (DebuggerView.Sources.selectedValue != url) {
|
||||
return;
|
||||
}
|
||||
|
||||
// There might be more counters on the same line. We need to combine them
|
||||
// into one.
|
||||
let content = Object.keys(this._hitCounts[url][line])
|
||||
.sort() // Sort by key (column).
|
||||
.map(a => this._hitCounts[url][line][a]) // Extract values.
|
||||
.map(a => a + "\u00D7") // Format hit count (e.g. 146×).
|
||||
.join("|");
|
||||
|
||||
// CodeMirror's lines are indexed from 0, while traces start from 1
|
||||
DebuggerView.editor.addContentMarker(line - 1, "hit-counts", "hit-count",
|
||||
content);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all hit couters and clear the storage
|
||||
*/
|
||||
clear: function() {
|
||||
DebuggerView.editor.removeAllMarkers("hit-counts");
|
||||
this._hitCounts = Object.create(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Localization convenience methods.
|
||||
*/
|
||||
@ -2265,6 +2356,7 @@ DebuggerController.SourceScripts = new SourceScripts();
|
||||
DebuggerController.Breakpoints = new Breakpoints();
|
||||
DebuggerController.Breakpoints.DOM = new EventListeners();
|
||||
DebuggerController.Tracer = new Tracer();
|
||||
DebuggerController.HitCounts = new HitCounts();
|
||||
|
||||
/**
|
||||
* Export some properties to the global scope for easier access.
|
||||
|
@ -221,12 +221,17 @@ let DebuggerView = {
|
||||
extraKeys[shortcut] = () => DebuggerView.Filtering[func]();
|
||||
}
|
||||
|
||||
let gutters = ["breakpoints"];
|
||||
if (Services.prefs.getBoolPref("devtools.debugger.tracer")) {
|
||||
gutters.unshift("hit-counts");
|
||||
}
|
||||
|
||||
this.editor = new Editor({
|
||||
mode: Editor.modes.text,
|
||||
readOnly: true,
|
||||
lineNumbers: true,
|
||||
showAnnotationRuler: true,
|
||||
gutters: [ "breakpoints" ],
|
||||
gutters: gutters,
|
||||
extraKeys: extraKeys,
|
||||
contextMenu: "sourceEditorContextMenu"
|
||||
});
|
||||
@ -410,6 +415,7 @@ let DebuggerView = {
|
||||
// Synchronize any other components with the currently displayed source.
|
||||
DebuggerView.Sources.selectedValue = aSource.url;
|
||||
DebuggerController.Breakpoints.updateEditorBreakpoints();
|
||||
DebuggerController.HitCounts.updateEditorHitCounts();
|
||||
|
||||
histogram.add(Date.now() - startTime);
|
||||
|
||||
|
@ -23,6 +23,7 @@ support-files =
|
||||
code_math.map
|
||||
code_math.min.js
|
||||
code_math_bogus_map.js
|
||||
code_same-line-functions.js
|
||||
code_script-switching-01.js
|
||||
code_script-switching-02.js
|
||||
code_test-editor-mode
|
||||
@ -74,6 +75,7 @@ support-files =
|
||||
doc_pretty-print-on-paused.html
|
||||
doc_random-javascript.html
|
||||
doc_recursion-stack.html
|
||||
doc_same-line-functions.html
|
||||
doc_scope-variable.html
|
||||
doc_scope-variable-2.html
|
||||
doc_scope-variable-3.html
|
||||
@ -161,6 +163,8 @@ skip-if = true # Bug 933950 (leaky test)
|
||||
[browser_dbg_function-display-name.js]
|
||||
[browser_dbg_global-method-override.js]
|
||||
[browser_dbg_globalactor.js]
|
||||
[browser_dbg_hit-counts-01.js]
|
||||
[browser_dbg_hit-counts-02.js]
|
||||
[browser_dbg_host-layout.js]
|
||||
[browser_dbg_iframes.js]
|
||||
[browser_dbg_instruments-pane-collapse.js]
|
||||
|
65
browser/devtools/debugger/test/browser_dbg_hit-counts-01.js
Normal file
65
browser/devtools/debugger/test/browser_dbg_hit-counts-01.js
Normal file
@ -0,0 +1,65 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Evaluating two functions on the same line and checking for correct hit count
|
||||
* for both of them in CodeMirror's gutter.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_same-line-functions.html";
|
||||
const CODE_URL = "code_same-line-functions.js";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gEditor;
|
||||
|
||||
function test() {
|
||||
Task.async(function* () {
|
||||
yield pushPrefs(["devtools.debugger.tracer", true]);
|
||||
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
|
||||
Task.async(function* () {
|
||||
yield waitForSourceShown(gPanel, CODE_URL);
|
||||
yield startTracing(gPanel);
|
||||
|
||||
clickButton();
|
||||
|
||||
yield waitForClientEvents(aPanel, "traces");
|
||||
|
||||
testHitCounts();
|
||||
|
||||
yield stopTracing(gPanel);
|
||||
yield popPrefs();
|
||||
yield closeDebuggerAndFinish(gPanel);
|
||||
})();
|
||||
});
|
||||
})().catch(e => {
|
||||
ok(false, "Got an error: " + e.message + "\n" + e.stack);
|
||||
});
|
||||
}
|
||||
|
||||
function clickButton() {
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
gDebuggee.document.querySelector("button"),
|
||||
gDebuggee);
|
||||
}
|
||||
|
||||
function testHitCounts() {
|
||||
let marker = gEditor.getMarker(0, 'hit-counts');
|
||||
|
||||
is(marker.innerHTML, "1\u00D7|1\u00D7",
|
||||
"Both functions should be hit only once.");
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
});
|
70
browser/devtools/debugger/test/browser_dbg_hit-counts-02.js
Normal file
70
browser/devtools/debugger/test/browser_dbg_hit-counts-02.js
Normal file
@ -0,0 +1,70 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* When tracing is stopped all hit counters should be cleared.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_same-line-functions.html";
|
||||
const CODE_URL = "code_same-line-functions.js";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gEditor;
|
||||
|
||||
function test() {
|
||||
Task.async(function* () {
|
||||
yield pushPrefs(["devtools.debugger.tracer", true]);
|
||||
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
|
||||
Task.async(function* () {
|
||||
yield waitForSourceShown(gPanel, CODE_URL);
|
||||
yield startTracing(gPanel);
|
||||
|
||||
clickButton();
|
||||
|
||||
yield waitForClientEvents(aPanel, "traces");
|
||||
|
||||
testHitCountsBeforeStopping();
|
||||
|
||||
yield stopTracing(gPanel);
|
||||
|
||||
testHitCountsAfterStopping();
|
||||
|
||||
yield popPrefs();
|
||||
yield closeDebuggerAndFinish(gPanel);
|
||||
})();
|
||||
});
|
||||
})().catch(e => {
|
||||
ok(false, "Got an error: " + e.message + "\n" + e.stack);
|
||||
});
|
||||
}
|
||||
|
||||
function clickButton() {
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
gDebuggee.document.querySelector("button"),
|
||||
gDebuggee);
|
||||
}
|
||||
|
||||
function testHitCountsBeforeStopping() {
|
||||
let marker = gEditor.getMarker(0, 'hit-counts');
|
||||
ok(marker, "A counter should exists.");
|
||||
}
|
||||
|
||||
function testHitCountsAfterStopping() {
|
||||
let marker = gEditor.getMarker(0, 'hit-counts');
|
||||
is(marker, undefined, "A counter should be cleared.");
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
});
|
@ -0,0 +1 @@
|
||||
function first() { var a = "first"; second(); function second() { var a = "second"; } }
|
15
browser/devtools/debugger/test/doc_same-line-functions.html
Normal file
15
browser/devtools/debugger/test/doc_same-line-functions.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Debugger Tracer test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="code_same-line-functions.js"></script>
|
||||
<button onclick="first()">Click me!</button>
|
||||
</body>
|
||||
</html>
|
@ -926,3 +926,14 @@ function doInterrupt(aPanel) {
|
||||
return rdpInvoke(threadClient, threadClient.interrupt);
|
||||
}
|
||||
|
||||
function pushPrefs(...aPrefs) {
|
||||
let deferred = promise.defer();
|
||||
SpecialPowers.pushPrefEnv({"set": aPrefs}, deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function popPrefs() {
|
||||
let deferred = promise.defer();
|
||||
SpecialPowers.popPrefEnv(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
@ -36,6 +36,7 @@ function test() {
|
||||
emptyText: "This is dummy empty text",
|
||||
highlightUpdated: true,
|
||||
removableColumns: true,
|
||||
firstColumn: "col4"
|
||||
});
|
||||
startTests();
|
||||
});
|
||||
@ -126,12 +127,42 @@ function populateTable() {
|
||||
function testTreeItemInsertedCorrectly() {
|
||||
is(table.tbody.children.length, 4*2 /* double because splitters */,
|
||||
"4 columns exist");
|
||||
for (let i = 0; i < 4; i++) {
|
||||
is(table.tbody.children[i*2].firstChild.children.length, 9 + 1 /* header */,
|
||||
|
||||
// Test firstColumn option and check if the nodes are inserted correctly
|
||||
is(table.tbody.children[0].firstChild.children.length, 9 + 1 /* header */,
|
||||
"Correct rows in column 4");
|
||||
is(table.tbody.children[0].firstChild.firstChild.value, "Column 4",
|
||||
"Correct column header value");
|
||||
|
||||
for (let i = 1; i < 4; i++) {
|
||||
is(table.tbody.children[i * 2].firstChild.children.length, 9 + 1 /* header */,
|
||||
"Correct rows in column " + i);
|
||||
is(table.tbody.children[i*2].firstChild.firstChild.value, "Column " + (i + 1),
|
||||
is(table.tbody.children[i * 2].firstChild.firstChild.value, "Column " + i,
|
||||
"Correct column header value");
|
||||
}
|
||||
for (let i = 1; i < 10; i++) {
|
||||
is(table.tbody.children[2].firstChild.children[i].value, "id" + i,
|
||||
"Correct value in row " + i);
|
||||
}
|
||||
|
||||
// Remove firstColumn option and reset the table
|
||||
table.clear();
|
||||
table.firstColumn = "";
|
||||
table.setColumns({
|
||||
col1: "Column 1",
|
||||
col2: "Column 2",
|
||||
col3: "Column 3",
|
||||
col4: "Column 4"
|
||||
});
|
||||
populateTable();
|
||||
|
||||
// Check if the nodes are inserted correctly without firstColumn option
|
||||
for (let i = 0; i < 4; i++) {
|
||||
is(table.tbody.children[i * 2].firstChild.children.length, 9 + 1 /* header */,
|
||||
"Correct rows in column " + i);
|
||||
is(table.tbody.children[i * 2].firstChild.firstChild.value, "Column " + (i + 1),
|
||||
"Correct column header value");
|
||||
}
|
||||
for (let i = 1; i < 10; i++) {
|
||||
is(table.tbody.firstChild.firstChild.children[i].value, "id" + i,
|
||||
"Correct value in row " + i);
|
||||
|
@ -40,6 +40,7 @@ const MAX_VISIBLE_STRING_SIZE = 100;
|
||||
* - highlightUpdated: true to highlight the changed/added row.
|
||||
* - removableColumns: Whether columns are removeable. If set to true,
|
||||
* the context menu in the headers will not appear.
|
||||
* - firstColumn: key of the first column that should appear.
|
||||
*/
|
||||
function TableWidget(node, options={}) {
|
||||
EventEmitter.decorate(this);
|
||||
@ -48,10 +49,11 @@ function TableWidget(node, options={}) {
|
||||
this.window = this.document.defaultView;
|
||||
this._parent = node;
|
||||
|
||||
let {initialColumns, emptyText, uniqueId, highlightUpdated, removableColumns} =
|
||||
options;
|
||||
let {initialColumns, emptyText, uniqueId, highlightUpdated, removableColumns,
|
||||
firstColumn} = options;
|
||||
this.emptyText = emptyText || "";
|
||||
this.uniqueId = uniqueId || "name";
|
||||
this.firstColumn = firstColumn || "";
|
||||
this.highlightUpdated = highlightUpdated || false;
|
||||
this.removableColumns = removableColumns || false;
|
||||
|
||||
@ -237,10 +239,24 @@ TableWidget.prototype = {
|
||||
sortOn = null;
|
||||
}
|
||||
|
||||
if (!(this.firstColumn in columns)) {
|
||||
this.firstColumn = null;
|
||||
}
|
||||
|
||||
if (this.firstColumn) {
|
||||
this.columns.set(this.firstColumn,
|
||||
new Column(this, this.firstColumn, columns[this.firstColumn]));
|
||||
}
|
||||
|
||||
for (let id in columns) {
|
||||
if (!sortOn) {
|
||||
sortOn = id;
|
||||
}
|
||||
|
||||
if (this.firstColumn && id == this.firstColumn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.columns.set(id, new Column(this, id, columns[id]));
|
||||
if (hiddenColumns.indexOf(id) > -1) {
|
||||
this.columns.get(id).toggleColumn();
|
||||
|
@ -7,6 +7,10 @@
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.hit-counts {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.error, .breakpoint, .debugLocation, .breakpoint-debugLocation {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
@ -17,6 +21,17 @@
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.hit-count {
|
||||
display: inline-block;
|
||||
height: 12px;
|
||||
border: solid rgba(0,0,0,0.2);
|
||||
border-width: 1px 1px 1px 0;
|
||||
border-radius: 0 3px 3px 0;
|
||||
padding: 0 3px;
|
||||
font-size: 10px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.error {
|
||||
background-image: url("chrome://browser/skin/devtools/editor-error.png");
|
||||
opacity: 0.75;
|
||||
|
@ -115,6 +115,7 @@ function hasBreakpoint(ctx, line) {
|
||||
let markers = cm.lineInfo(line).gutterMarkers;
|
||||
|
||||
return markers != null &&
|
||||
markers.breakpoints &&
|
||||
markers.breakpoints.classList.contains("breakpoint");
|
||||
}
|
||||
|
||||
|
@ -618,6 +618,32 @@ Editor.prototype = {
|
||||
cm.lineInfo(line).gutterMarkers[gutterName].classList.remove(markerClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a marker with a specified class and an HTML content to a line's
|
||||
* gutter. If another marker exists on that line, it is overwritten by a new
|
||||
* marker.
|
||||
*/
|
||||
addContentMarker: function (line, gutterName, markerClass, content) {
|
||||
let cm = editors.get(this);
|
||||
let info = cm.lineInfo(line);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
let marker = cm.getWrapperElement().ownerDocument.createElement("div");
|
||||
marker.className = markerClass;
|
||||
marker.innerHTML = content;
|
||||
cm.setGutterMarker(info.line, gutterName, marker);
|
||||
},
|
||||
|
||||
/**
|
||||
* The reverse of addContentMarker. Removes any line's markers in the
|
||||
* specified gutter.
|
||||
*/
|
||||
removeContentMarker: function (line, gutterName) {
|
||||
let cm = editors.get(this);
|
||||
cm.setGutterMarker(info.line, gutterName, null);
|
||||
},
|
||||
|
||||
getMarker: function(line, gutterName) {
|
||||
let cm = editors.get(this);
|
||||
let info = cm.lineInfo(line);
|
||||
|
@ -10,8 +10,12 @@ const {Cc, Ci, Cu} = require("chrome");
|
||||
loader.lazyImporter(this, "VariablesView", "resource:///modules/devtools/VariablesView.jsm");
|
||||
loader.lazyImporter(this, "escapeHTML", "resource:///modules/devtools/VariablesView.jsm");
|
||||
loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
|
||||
loader.lazyImporter(this, "Task","resource://gre/modules/Task.jsm");
|
||||
loader.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm");
|
||||
loader.lazyImporter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
|
||||
loader.lazyImporter(this, "ObjectClient", "resource://gre/modules/devtools/dbg-client.jsm");
|
||||
|
||||
loader.lazyRequireGetter(this, "promise");
|
||||
loader.lazyRequireGetter(this, "TableWidget", "devtools/shared/widgets/TableWidget", true);
|
||||
|
||||
const Heritage = require("sdk/core/heritage");
|
||||
const URI = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
@ -81,6 +85,7 @@ const CONSOLE_API_LEVELS_TO_SEVERITIES = {
|
||||
info: "info",
|
||||
log: "log",
|
||||
trace: "log",
|
||||
table: "log",
|
||||
debug: "log",
|
||||
dir: "log",
|
||||
group: "log",
|
||||
@ -111,6 +116,12 @@ const RE_CLEANUP_STYLES = [
|
||||
/['"(]*(?:chrome|resource|about|app|data|https?|ftp|file):+\/*/gi,
|
||||
];
|
||||
|
||||
// Maximum number of rows to display in console.table().
|
||||
const TABLE_ROW_MAX_ITEMS = 1000;
|
||||
|
||||
// Maximum number of columns to display in console.table().
|
||||
const TABLE_COLUMN_MAX_ITEMS = 10;
|
||||
|
||||
/**
|
||||
* The ConsoleOutput object is used to manage output of messages in the Web
|
||||
* Console.
|
||||
@ -1616,6 +1627,344 @@ Messages.ConsoleTrace.prototype = Heritage.extend(Messages.Simple.prototype,
|
||||
_renderRepeatNode: function() { },
|
||||
}); // Messages.ConsoleTrace.prototype
|
||||
|
||||
/**
|
||||
* The ConsoleTable message is used for console.table() calls.
|
||||
*
|
||||
* @constructor
|
||||
* @extends Messages.Extended
|
||||
* @param object packet
|
||||
* The Console API call packet received from the server.
|
||||
*/
|
||||
Messages.ConsoleTable = function(packet)
|
||||
{
|
||||
let options = {
|
||||
className: "cm-s-mozilla",
|
||||
timestamp: packet.timeStamp,
|
||||
category: "webdev",
|
||||
severity: CONSOLE_API_LEVELS_TO_SEVERITIES[packet.level],
|
||||
private: packet.private,
|
||||
filterDuplicates: false,
|
||||
location: {
|
||||
url: packet.filename,
|
||||
line: packet.lineNumber,
|
||||
},
|
||||
};
|
||||
|
||||
this._populateTableData = this._populateTableData.bind(this);
|
||||
this._renderTable = this._renderTable.bind(this);
|
||||
Messages.Extended.call(this, [this._renderTable], options);
|
||||
|
||||
this._repeatID.consoleApiLevel = packet.level;
|
||||
this._arguments = packet.arguments;
|
||||
};
|
||||
|
||||
Messages.ConsoleTable.prototype = Heritage.extend(Messages.Extended.prototype,
|
||||
{
|
||||
/**
|
||||
* Holds the arguments the content script passed to the console.table()
|
||||
* method.
|
||||
*
|
||||
* @private
|
||||
* @type array
|
||||
*/
|
||||
_arguments: null,
|
||||
|
||||
/**
|
||||
* Array of objects that holds the data to log in the table.
|
||||
*
|
||||
* @private
|
||||
* @type array
|
||||
*/
|
||||
_data: null,
|
||||
|
||||
/**
|
||||
* Key value pair of the id and display name for the columns in the table.
|
||||
* Refer to the TableWidget API.
|
||||
*
|
||||
* @private
|
||||
* @type object
|
||||
*/
|
||||
_columns: null,
|
||||
|
||||
/**
|
||||
* A promise that resolves when the table data is ready or null if invalid
|
||||
* arguments are provided.
|
||||
*
|
||||
* @private
|
||||
* @type promise|null
|
||||
*/
|
||||
_populatePromise: null,
|
||||
|
||||
init: function()
|
||||
{
|
||||
let result = Messages.Extended.prototype.init.apply(this, arguments);
|
||||
this._data = [];
|
||||
this._columns = {};
|
||||
|
||||
this._populatePromise = this._populateTableData();
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the key value pair of the id and display name for the columns in the
|
||||
* table.
|
||||
*
|
||||
* @private
|
||||
* @param array|string columns
|
||||
* Either a string or array containing the names for the columns in
|
||||
* the output table.
|
||||
*/
|
||||
_setColumns: function(columns)
|
||||
{
|
||||
if (columns.class == "Array") {
|
||||
let items = columns.preview.items;
|
||||
|
||||
for (let item of items) {
|
||||
if (typeof item == "string") {
|
||||
this._columns[item] = item;
|
||||
}
|
||||
}
|
||||
} else if (typeof columns == "string" && columns) {
|
||||
this._columns[columns] = columns;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the table data and columns from the arguments received from the
|
||||
* server.
|
||||
*
|
||||
* @return Promise|null
|
||||
* Returns a promise that resolves when the table data is ready or
|
||||
* null if the arguments are invalid.
|
||||
*/
|
||||
_populateTableData: function()
|
||||
{
|
||||
let deferred = promise.defer();
|
||||
|
||||
if (this._arguments.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let data = this._arguments[0];
|
||||
if (data.class != "Array" && data.class != "Object" &&
|
||||
data.class != "Map" && data.class != "Set") {
|
||||
return;
|
||||
}
|
||||
|
||||
let hasColumnsArg = false;
|
||||
if (this._arguments.length > 1) {
|
||||
if (data.class == "Object" || data.class == "Array") {
|
||||
this._columns["_index"] = l10n.getStr("table.index");
|
||||
} else {
|
||||
this._columns["_index"] = l10n.getStr("table.iterationIndex");
|
||||
}
|
||||
|
||||
this._setColumns(this._arguments[1]);
|
||||
hasColumnsArg = true;
|
||||
}
|
||||
|
||||
if (data.class == "Object" || data.class == "Array") {
|
||||
// Get the object properties, and parse the key and value properties into
|
||||
// the table data and columns.
|
||||
this.client = new ObjectClient(this.output.owner.jsterm.hud.proxy.client,
|
||||
data);
|
||||
this.client.getPrototypeAndProperties(aResponse => {
|
||||
let {ownProperties} = aResponse;
|
||||
let rowCount = 0;
|
||||
let columnCount = 0;
|
||||
|
||||
for (let index of Object.keys(ownProperties || {})) {
|
||||
// Avoid outputting the length property if the data argument provided
|
||||
// is an array
|
||||
if (data.class == "Array" && index == "length") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hasColumnsArg) {
|
||||
this._columns["_index"] = l10n.getStr("table.index");
|
||||
}
|
||||
|
||||
let property = ownProperties[index].value;
|
||||
let item = { _index: index };
|
||||
|
||||
if (property.class == "Object" || property.class == "Array") {
|
||||
let {preview} = property;
|
||||
let entries = property.class == "Object" ?
|
||||
preview.ownProperties : preview.items;
|
||||
|
||||
for (let key of Object.keys(entries)) {
|
||||
let value = property.class == "Object" ?
|
||||
preview.ownProperties[key].value : preview.items[key];
|
||||
|
||||
item[key] = this._renderValueGrip(value, { concise: true });
|
||||
|
||||
if (!hasColumnsArg && !(key in this._columns) &&
|
||||
(++columnCount <= TABLE_COLUMN_MAX_ITEMS)) {
|
||||
this._columns[key] = key;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Display the value for any non-object data input.
|
||||
item["_value"] = this._renderValueGrip(property, { concise: true });
|
||||
|
||||
if (!hasColumnsArg && !("_value" in this._columns)) {
|
||||
this._columns["_value"] = l10n.getStr("table.value");
|
||||
}
|
||||
}
|
||||
|
||||
this._data.push(item);
|
||||
|
||||
if (++rowCount == TABLE_ROW_MAX_ITEMS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
});
|
||||
} else if (data.class == "Map") {
|
||||
let entries = data.preview.entries;
|
||||
|
||||
if (!hasColumnsArg) {
|
||||
this._columns["_index"] = l10n.getStr("table.iterationIndex");
|
||||
this._columns["_key"] = l10n.getStr("table.key");
|
||||
this._columns["_value"] = l10n.getStr("table.value");
|
||||
}
|
||||
|
||||
let rowCount = 0;
|
||||
for (let index of Object.keys(entries || {})) {
|
||||
let [key, value] = entries[index];
|
||||
let item = {
|
||||
_index: index,
|
||||
_key: this._renderValueGrip(key, { concise: true }),
|
||||
_value: this._renderValueGrip(value, { concise: true })
|
||||
};
|
||||
|
||||
this._data.push(item);
|
||||
|
||||
if (++rowCount == TABLE_ROW_MAX_ITEMS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
} else if (data.class == "Set") {
|
||||
let entries = data.preview.items;
|
||||
|
||||
if (!hasColumnsArg) {
|
||||
this._columns["_index"] = l10n.getStr("table.iterationIndex");
|
||||
this._columns["_value"] = l10n.getStr("table.value");
|
||||
}
|
||||
|
||||
let rowCount = 0;
|
||||
for (let index of Object.keys(entries || {})) {
|
||||
let value = entries[index];
|
||||
let item = {
|
||||
_index : index,
|
||||
_value: this._renderValueGrip(value, { concise: true })
|
||||
};
|
||||
|
||||
this._data.push(item);
|
||||
|
||||
if (++rowCount == TABLE_ROW_MAX_ITEMS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
render: function()
|
||||
{
|
||||
Messages.Extended.prototype.render.apply(this, arguments);
|
||||
this.element.setAttribute("open", true);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Render the table.
|
||||
*
|
||||
* @private
|
||||
* @return DOMElement
|
||||
*/
|
||||
_renderTable: function()
|
||||
{
|
||||
let cmvar = this.document.createElementNS(XHTML_NS, "span");
|
||||
cmvar.className = "cm-variable";
|
||||
cmvar.textContent = "console";
|
||||
|
||||
let cmprop = this.document.createElementNS(XHTML_NS, "span");
|
||||
cmprop.className = "cm-property";
|
||||
cmprop.textContent = "table";
|
||||
|
||||
let title = this.document.createElementNS(XHTML_NS, "span");
|
||||
title.className = "message-body devtools-monospace";
|
||||
title.appendChild(cmvar);
|
||||
title.appendChild(this.document.createTextNode("."));
|
||||
title.appendChild(cmprop);
|
||||
title.appendChild(this.document.createTextNode("():"));
|
||||
|
||||
let repeatNode = Messages.Simple.prototype._renderRepeatNode.call(this);
|
||||
let location = Messages.Simple.prototype._renderLocation.call(this);
|
||||
if (location) {
|
||||
location.target = "jsdebugger";
|
||||
}
|
||||
|
||||
let body = this.document.createElementNS(XHTML_NS, "span");
|
||||
body.className = "message-flex-body";
|
||||
body.appendChild(title);
|
||||
if (repeatNode) {
|
||||
body.appendChild(repeatNode);
|
||||
}
|
||||
if (location) {
|
||||
body.appendChild(location);
|
||||
}
|
||||
body.appendChild(this.document.createTextNode("\n"));
|
||||
|
||||
let result = this.document.createElementNS(XHTML_NS, "div");
|
||||
result.appendChild(body);
|
||||
|
||||
if (this._populatePromise) {
|
||||
this._populatePromise.then(() => {
|
||||
if (this._data.length > 0) {
|
||||
let widget = new Widgets.Table(this, this._data, this._columns).render();
|
||||
result.appendChild(widget.element);
|
||||
}
|
||||
|
||||
result.scrollIntoView();
|
||||
this.output.owner.emit("messages-table-rendered");
|
||||
|
||||
// Release object actors
|
||||
if (Array.isArray(this._arguments)) {
|
||||
for (let arg of this._arguments) {
|
||||
if (WebConsoleUtils.isActorGrip(arg)) {
|
||||
this.output._releaseObject(arg.actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._arguments = null;
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
_renderBody: function()
|
||||
{
|
||||
let body = Messages.Simple.prototype._renderBody.apply(this, arguments);
|
||||
body.classList.remove("devtools-monospace", "message-body");
|
||||
return body;
|
||||
},
|
||||
|
||||
// no-op for the message location and .repeats elements.
|
||||
// |this._renderTable| handles customized message output.
|
||||
_renderLocation: function() { },
|
||||
_renderRepeatNode: function() { },
|
||||
}); // Messages.ConsoleTable.prototype
|
||||
|
||||
let Widgets = {};
|
||||
|
||||
/**
|
||||
@ -3012,6 +3361,63 @@ Widgets.Stacktrace.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
|
||||
}); // Widgets.Stacktrace.prototype
|
||||
|
||||
|
||||
/**
|
||||
* The table widget.
|
||||
*
|
||||
* @constructor
|
||||
* @extends Widgets.BaseWidget
|
||||
* @param object message
|
||||
* The owning message.
|
||||
* @param array data
|
||||
* Array of objects that holds the data to log in the table.
|
||||
* @param object columns
|
||||
* Object containing the key value pair of the id and display name for
|
||||
* the columns in the table.
|
||||
*/
|
||||
Widgets.Table = function(message, data, columns)
|
||||
{
|
||||
Widgets.BaseWidget.call(this, message);
|
||||
this.data = data;
|
||||
this.columns = columns;
|
||||
};
|
||||
|
||||
Widgets.Table.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
|
||||
{
|
||||
/**
|
||||
* Array of objects that holds the data to output in the table.
|
||||
* @type array
|
||||
*/
|
||||
data: null,
|
||||
|
||||
/**
|
||||
* Object containing the key value pair of the id and display name for
|
||||
* the columns in the table.
|
||||
* @type object
|
||||
*/
|
||||
columns: null,
|
||||
|
||||
render: function() {
|
||||
if (this.element) {
|
||||
return this;
|
||||
}
|
||||
|
||||
let result = this.element = this.document.createElementNS(XHTML_NS, "div");
|
||||
result.className = "consoletable devtools-monospace";
|
||||
|
||||
this.table = new TableWidget(result, {
|
||||
initialColumns: this.columns,
|
||||
uniqueId: "_index",
|
||||
firstColumn: "_index"
|
||||
});
|
||||
|
||||
for (let row of this.data) {
|
||||
this.table.push(row);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}); // Widgets.Table.prototype
|
||||
|
||||
function gSequenceId()
|
||||
{
|
||||
return gSequenceId.n++;
|
||||
|
@ -67,6 +67,7 @@ support-files =
|
||||
test-console-extras.html
|
||||
test-console-replaced-api.html
|
||||
test-console.html
|
||||
test-console-table.html
|
||||
test-console-output-02.html
|
||||
test-console-output-03.html
|
||||
test-console-output-04.html
|
||||
@ -305,6 +306,7 @@ skip-if = buildapp == 'mulet'
|
||||
[browser_webconsole_output_dom_elements_03.js]
|
||||
[browser_webconsole_output_dom_elements_04.js]
|
||||
[browser_webconsole_output_events.js]
|
||||
[browser_webconsole_output_table.js]
|
||||
[browser_console_variables_view_highlighter.js]
|
||||
[browser_webconsole_start_netmon_first.js]
|
||||
[browser_webconsole_console_trace_duplicates.js]
|
||||
|
@ -0,0 +1,158 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that console.table() works as intended.
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-table.html";
|
||||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
command: "console.table(languages1)",
|
||||
data: [
|
||||
{ _index: "0", name: "\"JavaScript\"", fileExtension: "Array[1]" },
|
||||
{ _index: "1", name: "Object", fileExtension: "\".ts\"" },
|
||||
{ _index: "2", name: "\"CoffeeScript\"", fileExtension: "\".coffee\"" }
|
||||
],
|
||||
columns: { _index: "(index)", name: "name", fileExtension: "fileExtension" }
|
||||
},
|
||||
{
|
||||
command: "console.table(languages1, 'name')",
|
||||
data: [
|
||||
{ _index: "0", name: "\"JavaScript\"", fileExtension: "Array[1]" },
|
||||
{ _index: "1", name: "Object", fileExtension: "\".ts\"" },
|
||||
{ _index: "2", name: "\"CoffeeScript\"", fileExtension: "\".coffee\"" }
|
||||
],
|
||||
columns: { _index: "(index)", name: "name" }
|
||||
},
|
||||
{
|
||||
command: "console.table(languages1, ['name'])",
|
||||
data: [
|
||||
{ _index: "0", name: "\"JavaScript\"", fileExtension: "Array[1]" },
|
||||
{ _index: "1", name: "Object", fileExtension: "\".ts\"" },
|
||||
{ _index: "2", name: "\"CoffeeScript\"", fileExtension: "\".coffee\"" }
|
||||
],
|
||||
columns: { _index: "(index)", name: "name" }
|
||||
},
|
||||
{
|
||||
command: "console.table(languages2)",
|
||||
data: [
|
||||
{ _index: "csharp", name: "\"C#\"", paradigm: "\"object-oriented\"" },
|
||||
{ _index: "fsharp", name: "\"F#\"", paradigm: "\"functional\"" }
|
||||
],
|
||||
columns: { _index: "(index)", name: "name", paradigm: "paradigm" }
|
||||
},
|
||||
{
|
||||
command: "console.table([[1, 2], [3, 4]])",
|
||||
data: [
|
||||
{ _index: "0", 0: "1", 1: "2" },
|
||||
{ _index: "1", 0: "3", 1: "4" }
|
||||
],
|
||||
columns: { _index: "(index)", 0: "0", 1: "1" }
|
||||
},
|
||||
{
|
||||
command: "console.table({a: [1, 2], b: [3, 4]})",
|
||||
data: [
|
||||
{ _index: "a", 0: "1", 1: "2" },
|
||||
{ _index: "b", 0: "3", 1: "4" }
|
||||
],
|
||||
columns: { _index: "(index)", 0: "0", 1: "1" }
|
||||
},
|
||||
{
|
||||
command: "console.table(family)",
|
||||
data: [
|
||||
{ _index: "mother", firstName: "\"Susan\"", lastName: "\"Doyle\"", age: "32" },
|
||||
{ _index: "father", firstName: "\"John\"", lastName: "\"Doyle\"", age: "33" },
|
||||
{ _index: "daughter", firstName: "\"Lily\"", lastName: "\"Doyle\"", age: "5" },
|
||||
{ _index: "son", firstName: "\"Mike\"", lastName: "\"Doyle\"", age: "8" },
|
||||
],
|
||||
columns: { _index: "(index)", firstName: "firstName", lastName: "lastName", age: "age" }
|
||||
},
|
||||
{
|
||||
command: "console.table(family, [])",
|
||||
data: [
|
||||
{ _index: "mother", firstName: "\"Susan\"", lastName: "\"Doyle\"", age: "32" },
|
||||
{ _index: "father", firstName: "\"John\"", lastName: "\"Doyle\"", age: "33" },
|
||||
{ _index: "daughter", firstName: "\"Lily\"", lastName: "\"Doyle\"", age: "5" },
|
||||
{ _index: "son", firstName: "\"Mike\"", lastName: "\"Doyle\"", age: "8" },
|
||||
],
|
||||
columns: { _index: "(index)" }
|
||||
},
|
||||
{
|
||||
command: "console.table(family, ['firstName', 'lastName'])",
|
||||
data: [
|
||||
{ _index: "mother", firstName: "\"Susan\"", lastName: "\"Doyle\"", age: "32" },
|
||||
{ _index: "father", firstName: "\"John\"", lastName: "\"Doyle\"", age: "33" },
|
||||
{ _index: "daughter", firstName: "\"Lily\"", lastName: "\"Doyle\"", age: "5" },
|
||||
{ _index: "son", firstName: "\"Mike\"", lastName: "\"Doyle\"", age: "8" },
|
||||
],
|
||||
columns: { _index: "(index)", firstName: "firstName", lastName: "lastName" }
|
||||
},
|
||||
{
|
||||
command: "console.table(mySet)",
|
||||
data: [
|
||||
{ _index: "0", _value: "1" },
|
||||
{ _index: "1", _value: "5" },
|
||||
{ _index: "2", _value: "\"some text\"" },
|
||||
{ _index: "3", _value: "null" },
|
||||
{ _index: "4", _value: "undefined" }
|
||||
],
|
||||
columns: { _index: "(iteration index)", _value: "Values" }
|
||||
},
|
||||
{
|
||||
command: "console.table(myMap)",
|
||||
data: [
|
||||
{ _index: "0", _key: "\"a string\"", _value: "\"value associated with 'a string'\"" },
|
||||
{ _index: "1", _key: "5", _value: "\"value associated with 5\"" },
|
||||
],
|
||||
columns: { _index: "(iteration index)", _key: "Key", _value: "Values" }
|
||||
}
|
||||
];
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
const {tab} = yield loadTab(TEST_URI);
|
||||
let hud = yield openConsole(tab);
|
||||
|
||||
for (let testdata of TEST_DATA) {
|
||||
hud.jsterm.clearOutput();
|
||||
|
||||
info("Executing " + testdata.command);
|
||||
|
||||
let onTableRender = once(hud.ui, "messages-table-rendered");
|
||||
hud.jsterm.execute(testdata.command);
|
||||
yield onTableRender;
|
||||
|
||||
let [result] = yield waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
name: testdata.command + " output",
|
||||
consoleTable: true
|
||||
}],
|
||||
});
|
||||
|
||||
let node = [...result.matched][0];
|
||||
ok(node, "found trace log node");
|
||||
|
||||
let obj = node._messageObject;
|
||||
ok(obj, "console.trace message object");
|
||||
|
||||
ok(obj._data, "found table data object");
|
||||
|
||||
let data = obj._data.map(entries => {
|
||||
let result = {};
|
||||
|
||||
for (let key of Object.keys(entries)) {
|
||||
result[key] = entries[key] instanceof HTMLElement ?
|
||||
entries[key].textContent : entries[key];
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
is(data.toSource(), testdata.data.toSource(), "table data is correct");
|
||||
ok(obj._columns, "found table column object");
|
||||
is(obj._columns.toSource(), testdata.columns.toSource(), "table column is correct");
|
||||
}
|
||||
});
|
@ -912,6 +912,8 @@ function openDebugger(aOptions = {})
|
||||
* message.
|
||||
* - consoleGroup: boolean, set to |true| to match a console.group()
|
||||
* message.
|
||||
* - consoleTable: boolean, set to |true| to match a console.table()
|
||||
* message.
|
||||
* - longString: boolean, set to |true} to match long strings in the
|
||||
* message.
|
||||
* - collapsible: boolean, set to |true| to match messages that can
|
||||
@ -970,6 +972,22 @@ function waitForMessages(aOptions)
|
||||
return result;
|
||||
}
|
||||
|
||||
function checkConsoleTable(aRule, aElement)
|
||||
{
|
||||
let elemText = aElement.textContent;
|
||||
let table = aRule.consoleTable;
|
||||
|
||||
if (!checkText("console.table():", elemText)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aRule.category = CATEGORY_WEBDEV;
|
||||
aRule.severity = SEVERITY_LOG;
|
||||
aRule.type = Messages.ConsoleTable;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkConsoleTrace(aRule, aElement)
|
||||
{
|
||||
let elemText = aElement.textContent;
|
||||
@ -1146,6 +1164,10 @@ function waitForMessages(aOptions)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aRule.consoleTable && !checkConsoleTable(aRule, aElement)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aRule.consoleTrace && !checkConsoleTrace(aRule, aElement)) {
|
||||
return false;
|
||||
}
|
||||
@ -1593,3 +1615,34 @@ function checkOutputForInputs(hud, inputTests)
|
||||
|
||||
return Task.spawn(runner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for eventName on target.
|
||||
* @param {Object} target An observable object that either supports on/off or
|
||||
* addEventListener/removeEventListener
|
||||
* @param {String} eventName
|
||||
* @param {Boolean} useCapture Optional, for addEventListener/removeEventListener
|
||||
* @return A promise that resolves when the event has been handled
|
||||
*/
|
||||
function once(target, eventName, useCapture=false) {
|
||||
info("Waiting for event: '" + eventName + "' on " + target + ".");
|
||||
|
||||
let deferred = promise.defer();
|
||||
|
||||
for (let [add, remove] of [
|
||||
["addEventListener", "removeEventListener"],
|
||||
["addListener", "removeListener"],
|
||||
["on", "off"]
|
||||
]) {
|
||||
if ((add in target) && (remove in target)) {
|
||||
target[add](eventName, function onEvent(...aArgs) {
|
||||
target[remove](eventName, onEvent, useCapture);
|
||||
deferred.resolve.apply(deferred, aArgs);
|
||||
}, useCapture);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,6 @@
|
||||
console.log("start");
|
||||
console.clear()
|
||||
console.dirxml()
|
||||
console.profile()
|
||||
console.profileEnd()
|
||||
console.table()
|
||||
console.log("end");
|
||||
}
|
||||
</script>
|
||||
|
52
browser/devtools/webconsole/test/test-console-table.html
Normal file
52
browser/devtools/webconsole/test/test-console-table.html
Normal file
@ -0,0 +1,52 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html dir="ltr" lang="en">
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<!--
|
||||
- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<title>Test for Bug 899753 - console.table support</title>
|
||||
<script>
|
||||
var languages1 = [
|
||||
{ name: "JavaScript", fileExtension: [".js"] },
|
||||
{ name: { a: "TypeScript" }, fileExtension: ".ts" },
|
||||
{ name: "CoffeeScript", fileExtension: ".coffee" }
|
||||
];
|
||||
|
||||
var languages2 = {
|
||||
csharp: { name: "C#", paradigm: "object-oriented" },
|
||||
fsharp: { name: "F#", paradigm: "functional" }
|
||||
};
|
||||
|
||||
function Person(firstName, lastName, age)
|
||||
{
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
var family = {};
|
||||
family.mother = new Person("Susan", "Doyle", 32);
|
||||
family.father = new Person("John", "Doyle", 33);
|
||||
family.daughter = new Person("Lily", "Doyle", 5);
|
||||
family.son = new Person("Mike", "Doyle", 8);
|
||||
|
||||
var myMap = new Map();
|
||||
|
||||
myMap.set("a string", "value associated with 'a string'");
|
||||
myMap.set(5, "value associated with 5");
|
||||
|
||||
var mySet = new Set();
|
||||
|
||||
mySet.add(1);
|
||||
mySet.add(5);
|
||||
mySet.add("some text");
|
||||
mySet.add(null);
|
||||
mySet.add(undefined);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Hello world!</p>
|
||||
</body>
|
||||
</html>
|
@ -123,6 +123,7 @@ const LEVELS = {
|
||||
info: SEVERITY_INFO,
|
||||
log: SEVERITY_LOG,
|
||||
trace: SEVERITY_LOG,
|
||||
table: SEVERITY_LOG,
|
||||
debug: SEVERITY_LOG,
|
||||
dir: SEVERITY_LOG,
|
||||
group: SEVERITY_LOG,
|
||||
@ -1212,6 +1213,11 @@ WebConsoleFrame.prototype = {
|
||||
node = msg.init(this.output).render().element;
|
||||
break;
|
||||
}
|
||||
case "table": {
|
||||
let msg = new Messages.ConsoleTable(aMessage);
|
||||
node = msg.init(this.output).render().element;
|
||||
break;
|
||||
}
|
||||
case "trace": {
|
||||
let msg = new Messages.ConsoleTrace(aMessage);
|
||||
node = msg.init(this.output).render().element;
|
||||
|
@ -250,3 +250,10 @@ messageToggleDetails=Show/hide message details.
|
||||
# example: 1 empty slot
|
||||
# example: 5 empty slots
|
||||
emptySlotLabel=#1 empty slot;#1 empty slots
|
||||
|
||||
# LOCALIZATION NOTE (table.index, table.iterationIndex, table.key, table.value):
|
||||
# the column header displayed in the console table widget.
|
||||
table.index=(index)
|
||||
table.iterationIndex=(iteration index)
|
||||
table.key=Key
|
||||
table.value=Values
|
||||
|
@ -63,6 +63,10 @@ a {
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
.message-body-wrapper .table-widget-body {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* The red bubble that shows the number of times a message is repeated */
|
||||
.message-repeats {
|
||||
-moz-user-select: none;
|
||||
@ -223,6 +227,13 @@ a {
|
||||
color: hsl(24,85%,39%);
|
||||
}
|
||||
|
||||
.theme-selected .console-string,
|
||||
.theme-selected .cm-number,
|
||||
.theme-selected .cm-variable,
|
||||
.theme-selected .kind-ArrayLike {
|
||||
color: #f5f7fa !important; /* Selection Text Color */
|
||||
}
|
||||
|
||||
.message[category=network] > .indent {
|
||||
-moz-border-end: solid #000 6px;
|
||||
}
|
||||
@ -429,6 +440,10 @@ a {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.consoletable {
|
||||
margin: 5px 0 0 0;
|
||||
}
|
||||
|
||||
.theme-light .message[severity=error] .stacktrace {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
@ -624,6 +624,7 @@ METHOD(Warn, "warn")
|
||||
METHOD(Error, "error")
|
||||
METHOD(Exception, "exception")
|
||||
METHOD(Debug, "debug")
|
||||
METHOD(Table, "table")
|
||||
|
||||
void
|
||||
Console::Trace(JSContext* aCx)
|
||||
|
@ -66,6 +66,9 @@ public:
|
||||
void
|
||||
Debug(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Table(JSContext* aCx, const Sequence<JS::Value>& aData);
|
||||
|
||||
void
|
||||
Trace(JSContext* aCx);
|
||||
|
||||
@ -111,6 +114,7 @@ private:
|
||||
MethodError,
|
||||
MethodException,
|
||||
MethodDebug,
|
||||
MethodTable,
|
||||
MethodTrace,
|
||||
MethodDir,
|
||||
MethodGroup,
|
||||
|
@ -5,8 +5,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
// On top because they include basictypes.h:
|
||||
#include "mozilla/dom/SmsFilter.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#undef GetClassName
|
||||
@ -125,7 +123,6 @@
|
||||
|
||||
#include "nsIDOMMozSmsMessage.h"
|
||||
#include "nsIDOMMozMmsMessage.h"
|
||||
#include "nsIDOMSmsFilter.h"
|
||||
#include "nsIDOMMozMobileMessageThread.h"
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
@ -348,9 +345,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
NS_DEFINE_CLASSINFO_DATA(MozMmsMessage, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(MozSmsFilter, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(MozMobileMessageThread, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
@ -422,7 +416,6 @@ static const nsConstructorFuncMapData kConstructorFuncMap[] =
|
||||
{
|
||||
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Blob, DOMMultipartFileImpl::NewBlob)
|
||||
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, DOMMultipartFileImpl::NewFile)
|
||||
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, SmsFilter::NewSmsFilter)
|
||||
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XSLTProcessor, XSLTProcessorCtor)
|
||||
};
|
||||
#undef NS_DEFINE_CONSTRUCTOR_FUNC_DATA
|
||||
@ -913,10 +906,6 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozMmsMessage)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(MozSmsFilter, nsIDOMMozSmsFilter)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsFilter)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(MozMobileMessageThread, nsIDOMMozMobileMessageThread)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozMobileMessageThread)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
@ -55,7 +55,6 @@ DOMCI_CLASS(ModalContentWindow)
|
||||
|
||||
DOMCI_CLASS(MozSmsMessage)
|
||||
DOMCI_CLASS(MozMmsMessage)
|
||||
DOMCI_CLASS(MozSmsFilter)
|
||||
DOMCI_CLASS(MozMobileMessageThread)
|
||||
|
||||
// @font-face in CSS
|
||||
|
@ -2702,12 +2702,16 @@ nsDOMWindowUtils::SetAsyncScrollOffset(nsIDOMNode* aNode,
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
FrameMetrics::ViewID viewId;
|
||||
if (!nsLayoutUtils::FindIDFor(element, &viewId)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
ShadowLayerForwarder* forwarder = layer->Manager()->AsShadowForwarder();
|
||||
if (!forwarder || !forwarder->HasShadowManager()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
forwarder->GetShadowManager()->SendSetAsyncScrollOffset(
|
||||
layer->AsShadowableLayer()->GetShadow(), aX, aY);
|
||||
layer->AsShadowableLayer()->GetShadow(), viewId, aX, aY);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
ok("console" in window, "Console exists");
|
||||
window.console.log(42);
|
||||
ok("table" in console, "Console has the 'table' method.");
|
||||
window.console = 42;
|
||||
is(window.console, 42, "Console is replacable");
|
||||
|
||||
|
@ -1990,7 +1990,6 @@ addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
|
||||
addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
|
||||
notflattened=True)
|
||||
addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
|
||||
addExternalIface('MozSmsFilter', headerFile='nsIDOMSmsFilter.h')
|
||||
addExternalIface('MozSmsMessage')
|
||||
addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject',
|
||||
notflattened=True)
|
||||
|
@ -9,7 +9,6 @@ XPIDL_SOURCES += [
|
||||
'nsIDOMMozMmsMessage.idl',
|
||||
'nsIDOMMozMobileMessageThread.idl',
|
||||
'nsIDOMMozSmsMessage.idl',
|
||||
'nsIDOMSmsFilter.idl',
|
||||
'nsIMmsService.idl',
|
||||
'nsIMobileMessageCallback.idl',
|
||||
'nsIMobileMessageCursorCallback.idl',
|
||||
|
@ -1,33 +0,0 @@
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
[scriptable, builtinclass, uuid(17890b60-0367-45c6-9729-62e5bf349b2b)]
|
||||
interface nsIDOMMozSmsFilter : nsISupports
|
||||
{
|
||||
// A date that can return null.
|
||||
[implicit_jscontext]
|
||||
attribute jsval startDate;
|
||||
|
||||
// A date that can return null.
|
||||
[implicit_jscontext]
|
||||
attribute jsval endDate;
|
||||
|
||||
// An array of DOMString that can return null.
|
||||
[implicit_jscontext]
|
||||
attribute jsval numbers;
|
||||
|
||||
// A DOMString that can return and be set to "sent", "received" or null.
|
||||
[Null(Empty)]
|
||||
attribute DOMString delivery;
|
||||
|
||||
// A read flag that can return and be set to a boolean or null.
|
||||
[implicit_jscontext]
|
||||
attribute jsval read;
|
||||
|
||||
// A thread id that can return and be set to a numeric value or null.
|
||||
[implicit_jscontext]
|
||||
attribute jsval threadId;
|
||||
};
|
@ -12,11 +12,10 @@
|
||||
%}
|
||||
|
||||
interface nsICursorContinueCallback;
|
||||
interface nsIDOMMozSmsFilter;
|
||||
interface nsIMobileMessageCallback;
|
||||
interface nsIMobileMessageCursorCallback;
|
||||
|
||||
[scriptable, uuid(8439916f-abc1-4c67-aa45-8a276a0a7855)]
|
||||
[scriptable, uuid(ead626bc-f5b4-47e1-921c-0b956c9298e0)]
|
||||
interface nsIMobileMessageDatabaseService : nsISupports
|
||||
{
|
||||
[binaryname(GetMessageMoz)]
|
||||
@ -27,7 +26,16 @@ interface nsIMobileMessageDatabaseService : nsISupports
|
||||
in uint32_t count,
|
||||
in nsIMobileMessageCallback request);
|
||||
|
||||
nsICursorContinueCallback createMessageCursor(in nsIDOMMozSmsFilter filter,
|
||||
nsICursorContinueCallback createMessageCursor(in boolean hasStartDate,
|
||||
in unsigned long long startDate,
|
||||
in boolean hasEndDate,
|
||||
in unsigned long long endDate,
|
||||
[array, size_is(numbersCount)] in wstring numbers,
|
||||
in uint32_t numbersCount,
|
||||
[Null(Null), Undefined(Null)] in DOMString delivery,
|
||||
in boolean hasRead,
|
||||
in boolean read,
|
||||
in unsigned long long threadId,
|
||||
in boolean reverse,
|
||||
in nsIMobileMessageCursorCallback callback);
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsISmsService.h"
|
||||
#include "nsServiceManagerUtils.h" // For do_GetService()
|
||||
#include "SmsFilter.h"
|
||||
|
||||
#define RECEIVED_EVENT_NAME NS_LITERAL_STRING("received")
|
||||
#define RETRIEVING_EVENT_NAME NS_LITERAL_STRING("retrieving")
|
||||
@ -367,7 +366,7 @@ MobileMessageManager::Delete(const Sequence<OwningLongOrMozSmsMessageOrMozMmsMes
|
||||
}
|
||||
|
||||
already_AddRefed<DOMCursor>
|
||||
MobileMessageManager::GetMessages(nsIDOMMozSmsFilter* aFilter,
|
||||
MobileMessageManager::GetMessages(const MobileMessageFilter& aFilter,
|
||||
bool aReverse,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@ -378,16 +377,62 @@ MobileMessageManager::GetMessages(nsIDOMMozSmsFilter* aFilter,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMMozSmsFilter> filter = aFilter;
|
||||
if (!filter) {
|
||||
filter = new SmsFilter();
|
||||
bool hasStartDate = !aFilter.mStartDate.IsNull();
|
||||
uint64_t startDate = 0;
|
||||
if (hasStartDate) {
|
||||
startDate = aFilter.mStartDate.Value();
|
||||
}
|
||||
|
||||
bool hasEndDate = !aFilter.mEndDate.IsNull();
|
||||
uint64_t endDate = 0;
|
||||
if (hasEndDate) {
|
||||
endDate = aFilter.mEndDate.Value();
|
||||
}
|
||||
|
||||
nsAutoArrayPtr<const char16_t*> ptrNumbers;
|
||||
uint32_t numbersCount = 0;
|
||||
if (!aFilter.mNumbers.IsNull() &&
|
||||
aFilter.mNumbers.Value().Length()) {
|
||||
const FallibleTArray<nsString>& numbers = aFilter.mNumbers.Value();
|
||||
uint32_t index;
|
||||
|
||||
numbersCount = numbers.Length();
|
||||
ptrNumbers = new const char16_t* [numbersCount];
|
||||
for (index = 0; index < numbersCount; index++) {
|
||||
ptrNumbers[index] = numbers[index].get();
|
||||
}
|
||||
}
|
||||
|
||||
nsString delivery;
|
||||
delivery.SetIsVoid(true);
|
||||
if (!aFilter.mDelivery.IsNull()) {
|
||||
const uint32_t index = static_cast<uint32_t>(aFilter.mDelivery.Value());
|
||||
const EnumEntry& entry =
|
||||
MobileMessageFilterDeliveryValues::strings[index];
|
||||
delivery.AssignASCII(entry.value, entry.length);
|
||||
}
|
||||
|
||||
bool hasRead = !aFilter.mRead.IsNull();
|
||||
bool read = false;
|
||||
if (hasRead) {
|
||||
read = aFilter.mRead.Value();
|
||||
}
|
||||
|
||||
uint64_t threadId = 0;
|
||||
if (!aFilter.mThreadId.IsNull()) {
|
||||
threadId = aFilter.mThreadId.Value();
|
||||
}
|
||||
|
||||
nsRefPtr<MobileMessageCursorCallback> cursorCallback =
|
||||
new MobileMessageCursorCallback();
|
||||
|
||||
nsCOMPtr<nsICursorContinueCallback> continueCallback;
|
||||
nsresult rv = dbService->CreateMessageCursor(filter, aReverse, cursorCallback,
|
||||
nsresult rv = dbService->CreateMessageCursor(hasStartDate, startDate,
|
||||
hasEndDate, endDate,
|
||||
ptrNumbers, numbersCount,
|
||||
delivery,
|
||||
hasRead, read,
|
||||
threadId,
|
||||
aReverse, cursorCallback,
|
||||
getter_AddRefs(continueCallback));
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
|
@ -14,7 +14,6 @@
|
||||
class nsISmsService;
|
||||
class nsIDOMMozSmsMessage;
|
||||
class nsIDOMMozMmsMessage;
|
||||
class nsIDOMMozSmsFilter;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -23,6 +22,7 @@ class DOMRequest;
|
||||
class DOMCursor;
|
||||
struct MmsParameters;
|
||||
struct MmsSendParameters;
|
||||
struct MobileMessageFilter;
|
||||
struct SmsSendParameters;
|
||||
|
||||
class MobileMessageManager MOZ_FINAL : public DOMEventTargetHelper
|
||||
@ -90,7 +90,7 @@ public:
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<DOMCursor>
|
||||
GetMessages(nsIDOMMozSmsFilter* aFilter,
|
||||
GetMessages(const MobileMessageFilter& aFilter,
|
||||
bool aReverse,
|
||||
ErrorResult& aRv);
|
||||
|
||||
|
@ -1,292 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "SmsFilter.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h" // For js_DateGetMsecSinceEpoch.
|
||||
#include "js/Utility.h"
|
||||
#include "mozilla/dom/mobilemessage/Constants.h" // For MessageType
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "nsDOMString.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIDOMClassInfo.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
using namespace mozilla::dom::mobilemessage;
|
||||
|
||||
DOMCI_DATA(MozSmsFilter, mozilla::dom::SmsFilter)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(SmsFilter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMMozSmsFilter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsFilter)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(SmsFilter)
|
||||
NS_IMPL_RELEASE(SmsFilter)
|
||||
|
||||
SmsFilter::SmsFilter()
|
||||
{
|
||||
mData.startDate() = 0;
|
||||
mData.endDate() = 0;
|
||||
mData.delivery() = eDeliveryState_Unknown;
|
||||
mData.read() = eReadState_Unknown;
|
||||
mData.threadId() = 0;
|
||||
}
|
||||
|
||||
SmsFilter::SmsFilter(const SmsFilterData& aData)
|
||||
: mData(aData)
|
||||
{
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
SmsFilter::NewSmsFilter(nsISupports** aSmsFilter)
|
||||
{
|
||||
NS_ADDREF(*aSmsFilter = new SmsFilter());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::GetStartDate(JSContext* aCx, JS::MutableHandle<JS::Value> aStartDate)
|
||||
{
|
||||
if (mData.startDate() == 0) {
|
||||
aStartDate.setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aStartDate.setObjectOrNull(JS_NewDateObjectMsec(aCx, mData.startDate()));
|
||||
NS_ENSURE_TRUE(aStartDate.isObject(), NS_ERROR_FAILURE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::SetStartDate(JSContext* aCx, JS::Handle<JS::Value> aStartDate)
|
||||
{
|
||||
if (aStartDate.isNull()) {
|
||||
mData.startDate() = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aStartDate.isObject()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, &aStartDate.toObject());
|
||||
if (!JS_ObjectIsDate(aCx, obj)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mData.startDate() = js_DateGetMsecSinceEpoch(obj);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::GetEndDate(JSContext* aCx, JS::MutableHandle<JS::Value> aEndDate)
|
||||
{
|
||||
if (mData.endDate() == 0) {
|
||||
aEndDate.setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aEndDate.setObjectOrNull(JS_NewDateObjectMsec(aCx, mData.endDate()));
|
||||
NS_ENSURE_TRUE(aEndDate.isObject(), NS_ERROR_FAILURE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::SetEndDate(JSContext* aCx, JS::Handle<JS::Value> aEndDate)
|
||||
{
|
||||
if (aEndDate.isNull()) {
|
||||
mData.endDate() = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aEndDate.isObject()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, &aEndDate.toObject());
|
||||
if (!JS_ObjectIsDate(aCx, obj)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mData.endDate() = js_DateGetMsecSinceEpoch(obj);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::GetNumbers(JSContext* aCx, JS::MutableHandle<JS::Value> aNumbers)
|
||||
{
|
||||
uint32_t length = mData.numbers().Length();
|
||||
|
||||
if (length == 0) {
|
||||
aNumbers.setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!ToJSValue(aCx, mData.numbers(), aNumbers)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::SetNumbers(JSContext* aCx, JS::Handle<JS::Value> aNumbers)
|
||||
{
|
||||
if (aNumbers.isNull()) {
|
||||
mData.numbers().Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aNumbers.isObject()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, &aNumbers.toObject());
|
||||
if (!JS_IsArrayObject(aCx, obj)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
uint32_t size;
|
||||
MOZ_ALWAYS_TRUE(JS_GetArrayLength(aCx, obj, &size));
|
||||
|
||||
nsTArray<nsString> numbers;
|
||||
|
||||
for (uint32_t i=0; i<size; ++i) {
|
||||
JS::Rooted<JS::Value> jsNumber(aCx);
|
||||
if (!JS_GetElement(aCx, obj, i, &jsNumber)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!jsNumber.isString()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsAutoJSString number;
|
||||
if (!number.init(aCx, jsNumber.toString())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
numbers.AppendElement(number);
|
||||
}
|
||||
|
||||
mData.numbers().Clear();
|
||||
mData.numbers().AppendElements(numbers);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::GetDelivery(nsAString& aDelivery)
|
||||
{
|
||||
switch (mData.delivery()) {
|
||||
case eDeliveryState_Received:
|
||||
aDelivery = DELIVERY_RECEIVED;
|
||||
break;
|
||||
case eDeliveryState_Sent:
|
||||
aDelivery = DELIVERY_SENT;
|
||||
break;
|
||||
case eDeliveryState_Unknown:
|
||||
SetDOMStringToNull(aDelivery);
|
||||
break;
|
||||
default:
|
||||
NS_ASSERTION(false, "We shouldn't get another delivery state!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::SetDelivery(const nsAString& aDelivery)
|
||||
{
|
||||
if (aDelivery.IsEmpty()) {
|
||||
mData.delivery() = eDeliveryState_Unknown;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aDelivery.Equals(DELIVERY_RECEIVED)) {
|
||||
mData.delivery() = eDeliveryState_Received;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aDelivery.Equals(DELIVERY_SENT)) {
|
||||
mData.delivery() = eDeliveryState_Sent;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::GetRead(JSContext* aCx, JS::MutableHandle<JS::Value> aRead)
|
||||
{
|
||||
if (mData.read() == eReadState_Unknown) {
|
||||
aRead.setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aRead.setBoolean(mData.read());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::SetRead(JSContext* aCx, JS::Handle<JS::Value> aRead)
|
||||
{
|
||||
if (aRead.isNull()) {
|
||||
mData.read() = eReadState_Unknown;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aRead.isBoolean()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mData.read() = aRead.toBoolean() ? eReadState_Read : eReadState_Unread;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::GetThreadId(JSContext* aCx, JS::MutableHandle<JS::Value> aThreadId)
|
||||
{
|
||||
if (!mData.threadId()) {
|
||||
aThreadId.setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aThreadId.setNumber(static_cast<double>(mData.threadId()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsFilter::SetThreadId(JSContext* aCx, JS::Handle<JS::Value> aThreadId)
|
||||
{
|
||||
if (aThreadId.isNull()) {
|
||||
mData.threadId() = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aThreadId.isNumber()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
double number = aThreadId.toNumber();
|
||||
uint64_t integer = static_cast<uint64_t>(number);
|
||||
if (integer == 0 || integer != number) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mData.threadId() = integer;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -1,43 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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_mobilemessage_SmsFilter_h
|
||||
#define mozilla_dom_mobilemessage_SmsFilter_h
|
||||
|
||||
#include "mozilla/dom/mobilemessage/SmsTypes.h"
|
||||
#include "nsIDOMSmsFilter.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SmsFilter MOZ_FINAL : public nsIDOMMozSmsFilter
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMMOZSMSFILTER
|
||||
|
||||
SmsFilter();
|
||||
SmsFilter(const mobilemessage::SmsFilterData& aData);
|
||||
|
||||
const mobilemessage::SmsFilterData& GetData() const;
|
||||
|
||||
static nsresult NewSmsFilter(nsISupports** aSmsFilter);
|
||||
|
||||
private:
|
||||
~SmsFilter() {}
|
||||
|
||||
mobilemessage::SmsFilterData mData;
|
||||
};
|
||||
|
||||
inline const mobilemessage::SmsFilterData&
|
||||
SmsFilter::GetData() const {
|
||||
return mData;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_mobilemessage_SmsFilter_h
|
@ -48,16 +48,7 @@ enum ReadStatus {
|
||||
eReadStatus_EndGuard
|
||||
};
|
||||
|
||||
// For {Mms,Sms}FilterData.read.
|
||||
enum ReadState {
|
||||
eReadState_Unknown = -1,
|
||||
eReadState_Unread,
|
||||
eReadState_Read,
|
||||
// This state should stay at the end.
|
||||
eReadState_EndGuard
|
||||
};
|
||||
|
||||
// For {Mms,Sms}FilterData.messageClass.
|
||||
// For {Mms,Sms}MessageData.messageClass.
|
||||
enum MessageClass {
|
||||
eMessageClass_Normal = 0,
|
||||
eMessageClass_Class0,
|
||||
@ -115,17 +106,6 @@ struct ParamTraits<mozilla::dom::mobilemessage::ReadStatus>
|
||||
mozilla::dom::mobilemessage::eReadStatus_EndGuard>
|
||||
{};
|
||||
|
||||
/**
|
||||
* Read state serializer.
|
||||
*/
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::mobilemessage::ReadState>
|
||||
: public ContiguousEnumSerializer<
|
||||
mozilla::dom::mobilemessage::ReadState,
|
||||
mozilla::dom::mobilemessage::eReadState_Unknown,
|
||||
mozilla::dom::mobilemessage::eReadState_EndGuard>
|
||||
{};
|
||||
|
||||
/**
|
||||
* Message class serializer.
|
||||
*/
|
||||
|
@ -3,7 +3,6 @@
|
||||
* 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 "SmsFilter.h"
|
||||
#include "MobileMessageDatabaseService.h"
|
||||
#include "AndroidBridge.h"
|
||||
|
||||
@ -47,7 +46,16 @@ MobileMessageDatabaseService::DeleteMessage(int32_t *aMessageIds,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileMessageDatabaseService::CreateMessageCursor(nsIDOMMozSmsFilter* aFilter,
|
||||
MobileMessageDatabaseService::CreateMessageCursor(bool aHasStartDate,
|
||||
uint64_t aStartDate,
|
||||
bool aHasEndDate,
|
||||
uint64_t aEndDate,
|
||||
const char16_t** aNumbers,
|
||||
uint32_t aNumbersCount,
|
||||
const nsAString& aDelivery,
|
||||
bool aHasRead,
|
||||
bool aRead,
|
||||
uint64_t aThreadId,
|
||||
bool aReverse,
|
||||
nsIMobileMessageCursorCallback* aCallback,
|
||||
nsICursorContinueCallback** aResult)
|
||||
|
@ -3105,25 +3105,47 @@ MobileMessageDB.prototype = {
|
||||
}, [MESSAGE_STORE_NAME, THREAD_STORE_NAME]);
|
||||
},
|
||||
|
||||
createMessageCursor: function(filter, reverse, callback) {
|
||||
createMessageCursor: function(aHasStartDate, aStartDate, aHasEndDate,
|
||||
aEndDate, aNumbers, aNumbersCount, aDelivery,
|
||||
aHasRead, aRead, aThreadId, aReverse, aCallback) {
|
||||
if (DEBUG) {
|
||||
debug("Creating a message cursor. Filters:" +
|
||||
" startDate: " + filter.startDate +
|
||||
" endDate: " + filter.endDate +
|
||||
" delivery: " + filter.delivery +
|
||||
" numbers: " + filter.numbers +
|
||||
" read: " + filter.read +
|
||||
" threadId: " + filter.threadId +
|
||||
" reverse: " + reverse);
|
||||
" startDate: " + (aHasStartDate ? aStartDate : "(null)") +
|
||||
" endDate: " + (aHasEndDate ? aEndDate : "(null)") +
|
||||
" delivery: " + aDelivery +
|
||||
" numbers: " + (aNumbersCount ? aNumbers : "(null)") +
|
||||
" read: " + (aHasRead ? aRead : "(null)") +
|
||||
" threadId: " + aThreadId +
|
||||
" reverse: " + aReverse);
|
||||
}
|
||||
|
||||
let cursor = new GetMessagesCursor(this, callback);
|
||||
let filter = {};
|
||||
if (aHasStartDate) {
|
||||
filter.startDate = aStartDate;
|
||||
}
|
||||
if (aHasEndDate) {
|
||||
filter.endDate = aEndDate;
|
||||
}
|
||||
if (aNumbersCount) {
|
||||
filter.numbers = aNumbers.slice();
|
||||
}
|
||||
if (aDelivery !== null) {
|
||||
filter.delivery = aDelivery;
|
||||
}
|
||||
if (aHasRead) {
|
||||
filter.read = aRead;
|
||||
}
|
||||
if (aThreadId) {
|
||||
filter.threadId = aThreadId;
|
||||
}
|
||||
|
||||
let cursor = new GetMessagesCursor(this, aCallback);
|
||||
|
||||
let self = this;
|
||||
self.newTxn(READ_ONLY, function(error, txn, stores) {
|
||||
let collector = cursor.collector;
|
||||
let collect = collector.collect.bind(collector);
|
||||
FilterSearcherHelper.transact(self, txn, error, filter, reverse, collect);
|
||||
FilterSearcherHelper.transact(self, txn, error, filter, aReverse, collect);
|
||||
}, [MESSAGE_STORE_NAME, PARTICIPANT_STORE_NAME]);
|
||||
|
||||
return cursor;
|
||||
@ -3311,11 +3333,11 @@ let FilterSearcherHelper = {
|
||||
filterTimestamp: function(startDate, endDate, direction, txn, collect) {
|
||||
let range = null;
|
||||
if (startDate != null && endDate != null) {
|
||||
range = IDBKeyRange.bound(startDate.getTime(), endDate.getTime());
|
||||
range = IDBKeyRange.bound(startDate, endDate);
|
||||
} else if (startDate != null) {
|
||||
range = IDBKeyRange.lowerBound(startDate.getTime());
|
||||
range = IDBKeyRange.lowerBound(startDate);
|
||||
} else if (endDate != null) {
|
||||
range = IDBKeyRange.upperBound(endDate.getTime());
|
||||
range = IDBKeyRange.upperBound(endDate);
|
||||
}
|
||||
this.filterIndex("timestamp", range, direction, txn, collect);
|
||||
},
|
||||
@ -3330,7 +3352,7 @@ let FilterSearcherHelper = {
|
||||
* @param error
|
||||
* Previous error while creating the transaction.
|
||||
* @param filter
|
||||
* A SmsFilter object.
|
||||
* A MobileMessageFilter dictionary.
|
||||
* @param reverse
|
||||
* A boolean value indicating whether we should filter message in
|
||||
* reversed order.
|
||||
@ -3368,10 +3390,10 @@ let FilterSearcherHelper = {
|
||||
// than all numeric values.
|
||||
let startDate = 0, endDate = "";
|
||||
if (filter.startDate != null) {
|
||||
startDate = filter.startDate.getTime();
|
||||
startDate = filter.startDate;
|
||||
}
|
||||
if (filter.endDate != null) {
|
||||
endDate = filter.endDate.getTime();
|
||||
endDate = filter.endDate;
|
||||
}
|
||||
|
||||
let single, intersectionCollector;
|
||||
|
@ -108,8 +108,13 @@ MobileMessageDatabaseService.prototype = {
|
||||
this.mmdb.deleteMessage(aMessageIds, aLength, aRequest);
|
||||
},
|
||||
|
||||
createMessageCursor: function(aFilter, aReverse, aCallback) {
|
||||
return this.mmdb.createMessageCursor(aFilter, aReverse, aCallback);
|
||||
createMessageCursor: function(aHasStartDate, aStartDate, aHasEndDate,
|
||||
aEndDate, aNumbers, aNumbersCount, aDelivery,
|
||||
aHasRead, aRead, aThreadId, aReverse, aCallback) {
|
||||
return this.mmdb.createMessageCursor(aHasStartDate, aStartDate, aHasEndDate,
|
||||
aEndDate, aNumbers, aNumbersCount,
|
||||
aDelivery, aHasRead, aRead, aThreadId,
|
||||
aReverse, aCallback);
|
||||
},
|
||||
|
||||
markMessageRead: function(aMessageId, aValue, aSendReadReport, aRequest) {
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/dom/mobilemessage/SmsChild.h"
|
||||
#include "SmsMessage.h"
|
||||
#include "SmsFilter.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "mozilla/dom/MozMobileMessageManagerBinding.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
@ -220,13 +219,40 @@ SmsIPCService::DeleteMessage(int32_t *aMessageIds, uint32_t aSize,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsIPCService::CreateMessageCursor(nsIDOMMozSmsFilter* aFilter,
|
||||
SmsIPCService::CreateMessageCursor(bool aHasStartDate,
|
||||
uint64_t aStartDate,
|
||||
bool aHasEndDate,
|
||||
uint64_t aEndDate,
|
||||
const char16_t** aNumbers,
|
||||
uint32_t aNumbersCount,
|
||||
const nsAString& aDelivery,
|
||||
bool aHasRead,
|
||||
bool aRead,
|
||||
uint64_t aThreadId,
|
||||
bool aReverse,
|
||||
nsIMobileMessageCursorCallback* aCursorCallback,
|
||||
nsICursorContinueCallback** aResult)
|
||||
{
|
||||
const SmsFilterData& data =
|
||||
SmsFilterData(static_cast<SmsFilter*>(aFilter)->GetData());
|
||||
SmsFilterData data;
|
||||
|
||||
data.hasStartDate() = aHasStartDate;
|
||||
data.startDate() = aStartDate;
|
||||
data.hasEndDate() = aHasEndDate;
|
||||
data.startDate() = aEndDate;
|
||||
|
||||
if (aNumbersCount && aNumbers) {
|
||||
nsTArray<nsString>& numbers = data.numbers();
|
||||
uint32_t index;
|
||||
|
||||
for (index = 0; index < aNumbersCount; index++) {
|
||||
numbers.AppendElement(aNumbers[index]);
|
||||
}
|
||||
}
|
||||
|
||||
data.delivery() = aDelivery;
|
||||
data.hasRead() = aHasRead;
|
||||
data.read() = aRead;
|
||||
data.threadId() = aThreadId;
|
||||
|
||||
return SendCursorRequest(CreateMessageCursorRequest(data, aReverse),
|
||||
aCursorCallback, aResult);
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "SmsMessage.h"
|
||||
#include "MmsMessage.h"
|
||||
#include "nsIMobileMessageDatabaseService.h"
|
||||
#include "SmsFilter.h"
|
||||
#include "MobileMessageThread.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "mozilla/dom/ipc/Blob.h"
|
||||
@ -774,10 +773,31 @@ MobileMessageCursorParent::DoRequest(const CreateMessageCursorRequest& aRequest)
|
||||
nsCOMPtr<nsIMobileMessageDatabaseService> dbService =
|
||||
do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID);
|
||||
if (dbService) {
|
||||
nsCOMPtr<nsIDOMMozSmsFilter> filter = new SmsFilter(aRequest.filter());
|
||||
bool reverse = aRequest.reverse();
|
||||
const SmsFilterData& filter = aRequest.filter();
|
||||
|
||||
rv = dbService->CreateMessageCursor(filter, reverse, this,
|
||||
const nsTArray<nsString>& numbers = filter.numbers();
|
||||
nsAutoArrayPtr<const char16_t*> ptrNumbers;
|
||||
uint32_t numbersCount = numbers.Length();
|
||||
if (numbersCount) {
|
||||
uint32_t index;
|
||||
|
||||
ptrNumbers = new const char16_t* [numbersCount];
|
||||
for (index = 0; index < numbersCount; index++) {
|
||||
ptrNumbers[index] = numbers[index].get();
|
||||
}
|
||||
}
|
||||
|
||||
rv = dbService->CreateMessageCursor(filter.hasStartDate(),
|
||||
filter.startDate(),
|
||||
filter.hasEndDate(),
|
||||
filter.endDate(),
|
||||
ptrNumbers, numbersCount,
|
||||
filter.delivery(),
|
||||
filter.hasRead(),
|
||||
filter.read(),
|
||||
filter.threadId(),
|
||||
aRequest.reverse(),
|
||||
this,
|
||||
getter_AddRefs(mContinueCallback));
|
||||
}
|
||||
|
||||
|
@ -77,11 +77,14 @@ union MobileMessageData
|
||||
|
||||
struct SmsFilterData
|
||||
{
|
||||
bool hasStartDate;
|
||||
uint64_t startDate;
|
||||
bool hasEndDate;
|
||||
uint64_t endDate;
|
||||
nsString[] numbers;
|
||||
DeliveryState delivery;
|
||||
ReadState read;
|
||||
nsString delivery;
|
||||
bool hasRead;
|
||||
bool read;
|
||||
uint64_t threadId;
|
||||
};
|
||||
|
||||
|
@ -40,7 +40,6 @@ EXPORTS.mozilla.dom += [
|
||||
'DOMMobileMessageError.h',
|
||||
'MmsMessage.h',
|
||||
'MobileMessageManager.h',
|
||||
'SmsFilter.h',
|
||||
'SmsMessage.h',
|
||||
]
|
||||
|
||||
@ -57,7 +56,6 @@ UNIFIED_SOURCES += [
|
||||
'MobileMessageManager.cpp',
|
||||
'MobileMessageService.cpp',
|
||||
'MobileMessageThread.cpp',
|
||||
'SmsFilter.cpp',
|
||||
'SmsMessage.cpp',
|
||||
'SmsServicesFactory.cpp',
|
||||
]
|
||||
|
@ -243,18 +243,17 @@ function getMessage(aId) {
|
||||
* Reject params:
|
||||
* event -- a DOMEvent
|
||||
*
|
||||
* @param aFilter an optional MozSmsFilter instance.
|
||||
* @param aReverse a boolean value indicating whether the order of the messages
|
||||
* should be reversed.
|
||||
* @param aFilter [optional]
|
||||
* A MobileMessageFilter object.
|
||||
* @param aReverse [optional]
|
||||
* A boolean value indicating whether the order of the message should be
|
||||
* reversed. Default: false.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function getMessages(aFilter, aReverse) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
if (!aFilter) {
|
||||
aFilter = new MozSmsFilter;
|
||||
}
|
||||
let messages = [];
|
||||
let cursor = manager.getMessages(aFilter, aReverse || false);
|
||||
cursor.onsuccess = function(aEvent) {
|
||||
|
@ -328,8 +328,21 @@ function createMmdbCursor(aMmdb, aMethodName) {
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function createMessageCursor(aMmdb, aFilter, aReverse) {
|
||||
return createMmdbCursor(aMmdb, "createMessageCursor", aFilter, aReverse);
|
||||
function createMessageCursor(aMmdb, aStartDate = null, aEndDate = null,
|
||||
aNumbers = null, aDelivery = null, aRead = null,
|
||||
aThreadId = null, aReverse = false) {
|
||||
return createMmdbCursor(aMmdb, "createMessageCursor",
|
||||
aStartDate !== null,
|
||||
aStartDate || 0,
|
||||
aEndDate !== null,
|
||||
aEndDate || 0,
|
||||
aNumbers || null,
|
||||
aNumbers && aNumbers.length || 0,
|
||||
aDelivery || null,
|
||||
aRead !== null,
|
||||
aRead || false,
|
||||
aThreadId || 0,
|
||||
aReverse || false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,11 +24,11 @@ function simulateIncomingSms() {
|
||||
}
|
||||
|
||||
function test(aStartDate, aEndDate, aExpectedMessages) {
|
||||
let filter = new MozSmsFilter();
|
||||
if (aStartDate) {
|
||||
let filter = {};
|
||||
if (aStartDate !== null) {
|
||||
filter.startDate = aStartDate;
|
||||
}
|
||||
if (aEndDate) {
|
||||
if (aEndDate !== null) {
|
||||
filter.endDate = aEndDate;
|
||||
}
|
||||
|
||||
@ -64,16 +64,16 @@ startTestCommon(function testCaseMain() {
|
||||
// Should return all messages.
|
||||
//
|
||||
.then(() => log("Testing [startTime, )"))
|
||||
.then(() => test(new Date(startTime), null, allMessages))
|
||||
.then(() => test(startTime, null, allMessages))
|
||||
.then(() => log("Testing (, endTime]"))
|
||||
.then(() => test(null, new Date(endTime), allMessages))
|
||||
.then(() => test(null, endTime, allMessages))
|
||||
.then(() => log("Testing [startTime, endTime]"))
|
||||
.then(() => test(new Date(startTime), new Date(endTime), allMessages))
|
||||
.then(() => test(startTime, endTime, allMessages))
|
||||
|
||||
// Should return only messages with timestamp <= startTime.
|
||||
//
|
||||
.then(() => log("Testing [, startTime)"))
|
||||
.then(() => test(null, new Date(startTime),
|
||||
.then(() => test(null, startTime,
|
||||
reduceMessages(allMessages,
|
||||
(function(a, b) {
|
||||
return b <= a;
|
||||
@ -82,7 +82,7 @@ startTestCommon(function testCaseMain() {
|
||||
// Should return only messages with timestamp <= startTime + 1.
|
||||
//
|
||||
.then(() => log("Testing [, startTime + 1)"))
|
||||
.then(() => test(null, new Date(startTime + 1),
|
||||
.then(() => test(null, startTime + 1,
|
||||
reduceMessages(allMessages,
|
||||
(function(a, b) {
|
||||
return b <= a;
|
||||
@ -91,7 +91,7 @@ startTestCommon(function testCaseMain() {
|
||||
// Should return only messages with timestamp >= endTime.
|
||||
//
|
||||
.then(() => log("Testing [endTime, )"))
|
||||
.then(() => test(new Date(endTime), null,
|
||||
.then(() => test(endTime, null,
|
||||
reduceMessages(allMessages,
|
||||
(function(a, b) {
|
||||
return b >= a;
|
||||
@ -100,7 +100,7 @@ startTestCommon(function testCaseMain() {
|
||||
// Should return only messages with timestamp >= endTime - 1.
|
||||
//
|
||||
.then(() => log("Testing [endTime - 1, )"))
|
||||
.then(() => test(new Date(endTime - 1), null,
|
||||
.then(() => test(endTime - 1, null,
|
||||
reduceMessages(allMessages,
|
||||
(function(a, b) {
|
||||
return b >= a;
|
||||
@ -109,11 +109,11 @@ startTestCommon(function testCaseMain() {
|
||||
// Should return none.
|
||||
//
|
||||
.then(() => log("Testing [endTime + 1, )"))
|
||||
.then(() => test(new Date(endTime + 1), null, []))
|
||||
.then(() => test(endTime + 1, null, []))
|
||||
.then(() => log("Testing [endTime + 1, endTime + 86400000]"))
|
||||
.then(() => test(new Date(endTime + 1), new Date(endTime + 86400000), []))
|
||||
.then(() => test(endTime + 1, endTime + 86400000, []))
|
||||
.then(() => log("Testing (, startTime - 1]"))
|
||||
.then(() => test(null, new Date(startTime - 1), []))
|
||||
.then(() => test(null, startTime - 1, []))
|
||||
.then(() => log("Testing [startTime - 86400000, startTime - 1]"))
|
||||
.then(() => test(new Date(startTime - 86400000), new Date(startTime - 1), []));
|
||||
.then(() => test(startTime - 86400000, startTime - 1, []));
|
||||
});
|
||||
|
@ -59,9 +59,6 @@ let tasks = {
|
||||
};
|
||||
|
||||
function getAllMessages(callback, filter, reverse) {
|
||||
if (!filter) {
|
||||
filter = new MozSmsFilter;
|
||||
}
|
||||
let messages = [];
|
||||
let request = manager.getMessages(filter, reverse || false);
|
||||
request.onsuccess = function(event) {
|
||||
@ -182,9 +179,10 @@ tasks.push(function assignInvalidThreadID() {
|
||||
|
||||
tasks.push(function testDeliveryAndNumber() {
|
||||
log("Checking delivery == sent && number == 5555315550");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.delivery = "sent";
|
||||
filter.numbers = ["5555315550"];
|
||||
let filter = {
|
||||
delivery: "sent",
|
||||
numbers: ["5555315550"],
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
// Only { delivery: "sent", receiver: "+15555315550", read: true }
|
||||
is(messages.length, 1, "message count");
|
||||
@ -209,9 +207,10 @@ tasks.push(function testDeliveryAndNumber() {
|
||||
|
||||
tasks.push(function testDeliveryAndNumberNotFound() {
|
||||
log("Checking delivery == sent && number == INVALID_NUMBER");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.delivery = "sent";
|
||||
filter.numbers = [INVALID_NUMBER];
|
||||
let filter = {
|
||||
delivery: "sent",
|
||||
numbers: [INVALID_NUMBER],
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
is(messages.length, 0, "message count");
|
||||
|
||||
@ -221,9 +220,10 @@ tasks.push(function testDeliveryAndNumberNotFound() {
|
||||
|
||||
tasks.push(function testDeliveryAndRead() {
|
||||
log("Checking delivery == received && read == true");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.delivery = "received";
|
||||
filter.read = true;
|
||||
let filter = {
|
||||
delivery: "received",
|
||||
read: true,
|
||||
}
|
||||
getAllMessages(function(messages) {
|
||||
// { delivery: "received", sender: "5555315550", read: true },
|
||||
// { delivery: "received", sender: "5555315552", read: true },
|
||||
@ -250,9 +250,10 @@ tasks.push(function testDeliveryAndRead() {
|
||||
|
||||
tasks.push(function testDeliveryAndReadNotFound() {
|
||||
log("Checking delivery == sent && read == false");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.delivery = "sent";
|
||||
filter.read = false;
|
||||
let filter = {
|
||||
delivery: "sent",
|
||||
read: false,
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
is(messages.length, 0, "message count");
|
||||
|
||||
@ -262,9 +263,10 @@ tasks.push(function testDeliveryAndReadNotFound() {
|
||||
|
||||
tasks.push(function testDeliveryAndThreadId() {
|
||||
log("Checking delivery == received && threadId == " + threadIds[0]);
|
||||
let filter = new MozSmsFilter();
|
||||
filter.delivery = "sent";
|
||||
filter.threadId = threadIds[0];
|
||||
let filter = {
|
||||
delivery: "sent",
|
||||
threadId: threadIds[0],
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
// { delivery: "sent", receiver: "+15555315550", threadId: threadIds[0]}
|
||||
is(messages.length, 1, "message count");
|
||||
@ -287,9 +289,10 @@ tasks.push(function testDeliveryAndThreadId() {
|
||||
|
||||
tasks.push(function testDeliveryAndThreadIdNotFound() {
|
||||
log("Checking delivery == sent && threadId == INVALID_THREAD_ID");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.delivery = "sent";
|
||||
filter.threadId = INVALID_THREAD_ID;
|
||||
let filter = {
|
||||
delivery: "sent",
|
||||
threadId: INVALID_THREAD_ID,
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
is(messages.length, 0, "message count");
|
||||
|
||||
@ -299,9 +302,10 @@ tasks.push(function testDeliveryAndThreadIdNotFound() {
|
||||
|
||||
tasks.push(function testNumberAndRead() {
|
||||
log("Checking number == 5555315550 && read == true");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.numbers = ["5555315550"];
|
||||
filter.read = true;
|
||||
let filter = {
|
||||
numbers: ["5555315550"],
|
||||
read: true,
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
// { delivery: "sent", receiver: "+15555315550", read: true }
|
||||
// { delivery: "received", sender: "5555315550", read: true }
|
||||
@ -327,9 +331,10 @@ tasks.push(function testNumberAndRead() {
|
||||
|
||||
tasks.push(function testNumberAndReadNotFound() {
|
||||
log("Checking number == INVALID_NUMBER && read == true");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.numbers = [INVALID_NUMBER];
|
||||
filter.read = true;
|
||||
let filter = {
|
||||
numbers: [INVALID_NUMBER],
|
||||
read: true,
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
is(messages.length, 0, "message count");
|
||||
|
||||
@ -339,9 +344,10 @@ tasks.push(function testNumberAndReadNotFound() {
|
||||
|
||||
tasks.push(function testNumberAndThreadId() {
|
||||
log("Checking number == 5555315550 && threadId == " + threadIds[0]);
|
||||
let filter = new MozSmsFilter();
|
||||
filter.numbers = ["5555315550"];
|
||||
filter.threadId = threadIds[0];
|
||||
let filter = {
|
||||
numbers: ["5555315550"],
|
||||
threadId: threadIds[0],
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
// { delivery: "sent", receiver: "+15555315550", read: true }
|
||||
// { delivery: "received", sender: "5555315550", read: true }
|
||||
@ -367,9 +373,10 @@ tasks.push(function testNumberAndThreadId() {
|
||||
|
||||
tasks.push(function testNumberAndThreadIdNotFound() {
|
||||
log("Checking number == INVALID_NUMBER && threadId == INVALID_THREAD_ID");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.numbers = [INVALID_NUMBER];
|
||||
filter.threadId = INVALID_THREAD_ID;
|
||||
let filter = {
|
||||
numbers: [INVALID_NUMBER],
|
||||
threadId: INVALID_THREAD_ID,
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
is(messages.length, 0, "message count");
|
||||
|
||||
@ -379,8 +386,9 @@ tasks.push(function testNumberAndThreadIdNotFound() {
|
||||
|
||||
tasks.push(function testMultipleNumbers() {
|
||||
log("Checking number == 5555315550 || number == 5555315551");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.numbers = ["5555315550", "5555315551"];
|
||||
let filter = {
|
||||
numbers: ["5555315550", "5555315551"],
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
// { delivery: "sent", receiver: "+15555315550", read: true }
|
||||
// { delivery: "received", sender: "5555315550", read: true }
|
||||
@ -401,8 +409,9 @@ tasks.push(function testMultipleNumbers() {
|
||||
|
||||
tasks.push(function testMultipleNumbersNotFound() {
|
||||
log("Checking number == INVALID_NUMBER || number == INVALID_NUMBER2");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.numbers = [INVALID_NUMBER, INVALID_NUMBER2];
|
||||
let filter = {
|
||||
numbers: [INVALID_NUMBER, INVALID_NUMBER2],
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
is(messages.length, 0, "message count");
|
||||
|
||||
@ -412,9 +421,10 @@ tasks.push(function testMultipleNumbersNotFound() {
|
||||
|
||||
tasks.push(function testDeliveryAndMultipleNumbers() {
|
||||
log("Checking delivery == sent && (number == 5555315550 || number == 5555315551)");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.delivery = "sent";
|
||||
filter.numbers = ["5555315550", "5555315551"];
|
||||
let filter = {
|
||||
delivery: "sent",
|
||||
numbers: ["5555315550", "5555315551"],
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
// { delivery: "sent", receiver: "+15555315550", read: true }
|
||||
// { delivery: "sent", receiver: "+15555315551", read: true }
|
||||
@ -434,9 +444,10 @@ tasks.push(function testDeliveryAndMultipleNumbers() {
|
||||
|
||||
tasks.push(function testMultipleNumbersAndRead() {
|
||||
log("Checking (number == 5555315550 || number == 5555315551) && read == true");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.numbers = ["5555315550", "5555315551"];
|
||||
filter.read = true;
|
||||
let filter = {
|
||||
numbers: ["5555315550", "5555315551"],
|
||||
read: true,
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
// { delivery: "sent", receiver: "+15555315550", read: true }
|
||||
// { delivery: "received", sender: "5555315550", read: true }
|
||||
@ -457,9 +468,10 @@ tasks.push(function testMultipleNumbersAndRead() {
|
||||
|
||||
tasks.push(function testMultipleNumbersAndThreadId() {
|
||||
log("Checking (number == 5555315550 || number == 5555315551) && threadId == " + threadIds[0]);
|
||||
let filter = new MozSmsFilter();
|
||||
filter.numbers = ["5555315550", "5555315551"];
|
||||
filter.threadId = threadIds[0];
|
||||
let filter = {
|
||||
numbers: ["5555315550", "5555315551"],
|
||||
threadId: threadIds[0],
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
// { delivery: "sent", receiver: "+15555315550", read: true }
|
||||
// { delivery: "received", sender: "5555315550", read: true }
|
||||
@ -479,8 +491,9 @@ tasks.push(function testMultipleNumbersAndThreadId() {
|
||||
|
||||
tasks.push(function testNationalNumber() {
|
||||
log("Checking number = 5555315550");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.numbers = ["5555315550"];
|
||||
let filter = {
|
||||
numbers: ["5555315550"],
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
// { delivery: "sent", receiver: "+15555315550", read: true }
|
||||
// { delivery: "received", sender: "5555315550", read: true }
|
||||
@ -498,8 +511,9 @@ tasks.push(function testNationalNumber() {
|
||||
|
||||
tasks.push(function testInternationalNumber() {
|
||||
log("Checking number = +15555315550");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.numbers = ["+15555315550"];
|
||||
let filter = {
|
||||
numbers: ["+15555315550"],
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
// { delivery: "sent", receiver: "+15555315550", read: true }
|
||||
// { delivery: "received", sender: "5555315550", read: true }
|
||||
@ -517,9 +531,10 @@ tasks.push(function testInternationalNumber() {
|
||||
|
||||
tasks.push(function testReadAndThreadId() {
|
||||
log("Checking read == true && threadId == " + threadIds[0]);
|
||||
let filter = new MozSmsFilter();
|
||||
filter.read = true;
|
||||
filter.threadId = threadIds[0];
|
||||
let filter = {
|
||||
read: true,
|
||||
threadId: threadIds[0],
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
// { delivery: "sent", receiver: "+15555315550", read: true }
|
||||
// { delivery: "received", sender: "5555315550", read: true }
|
||||
@ -543,9 +558,10 @@ tasks.push(function testReadAndThreadId() {
|
||||
|
||||
tasks.push(function testReadAndThreadIdNotFound() {
|
||||
log("Checking read == true && threadId == INVALID_THREAD_ID");
|
||||
let filter = new MozSmsFilter();
|
||||
filter.read = true;
|
||||
filter.threadId = INVALID_THREAD_ID;
|
||||
let filter = {
|
||||
read: true,
|
||||
threadId: INVALID_THREAD_ID,
|
||||
};
|
||||
getAllMessages(function(messages) {
|
||||
is(messages.length, 0, "message count");
|
||||
|
||||
|
@ -28,8 +28,7 @@ function genFailingMms(aReceivers) {
|
||||
function checkMessage(aNeedle, aValidNumbers) {
|
||||
log(" Verifying " + aNeedle);
|
||||
|
||||
let filter = new MozSmsFilter();
|
||||
filter.numbers = [aNeedle];
|
||||
let filter = { numbers: [aNeedle] };
|
||||
return getMessages(filter)
|
||||
.then(function(messages) {
|
||||
// Check the messages are sent to/received from aValidNumbers.
|
||||
|
@ -20,9 +20,8 @@ function verifyInitialState() {
|
||||
|
||||
function deleteAllMsgs(nextFunction) {
|
||||
let msgList = new Array();
|
||||
let filter = new MozSmsFilter;
|
||||
|
||||
let cursor = manager.getMessages(filter, false);
|
||||
let cursor = manager.getMessages();
|
||||
ok(cursor instanceof DOMCursor,
|
||||
"cursor is instanceof " + cursor.constructor);
|
||||
|
||||
@ -162,11 +161,10 @@ function markMsgRead(smsMsgs) {
|
||||
}
|
||||
|
||||
function getMsgs() {
|
||||
var filter = new MozSmsFilter();
|
||||
let foundSmsList = new Array();
|
||||
|
||||
// Set filter for read messages
|
||||
filter.read = true;
|
||||
let filter = { read: true };
|
||||
|
||||
log("Getting the read SMS messages.");
|
||||
let cursor = manager.getMessages(filter, false);
|
||||
|
@ -20,9 +20,8 @@ function verifyInitialState() {
|
||||
|
||||
function deleteAllMsgs(nextFunction) {
|
||||
let msgList = new Array();
|
||||
let filter = new MozSmsFilter;
|
||||
|
||||
let cursor = manager.getMessages(filter, false);
|
||||
let cursor = manager.getMessages();
|
||||
ok(cursor instanceof DOMCursor,
|
||||
"cursor is instanceof " + cursor.constructor);
|
||||
|
||||
@ -174,11 +173,10 @@ function sendSms() {
|
||||
}
|
||||
|
||||
function getMsgs() {
|
||||
var filter = new MozSmsFilter();
|
||||
let foundSmsList = new Array();
|
||||
|
||||
// Set filter for received messages
|
||||
filter.delivery = "received";
|
||||
let filter = { delivery: "received" };
|
||||
|
||||
log("Getting the received SMS messages.");
|
||||
let cursor = manager.getMessages(filter, false);
|
||||
|
@ -20,9 +20,8 @@ function verifyInitialState() {
|
||||
|
||||
function deleteAllMsgs(nextFunction) {
|
||||
let msgList = new Array();
|
||||
let filter = new MozSmsFilter;
|
||||
|
||||
let cursor = manager.getMessages(filter, false);
|
||||
let cursor = manager.getMessages();
|
||||
ok(cursor instanceof DOMCursor,
|
||||
"cursor is instanceof " + cursor.constructor);
|
||||
|
||||
@ -171,11 +170,10 @@ manager.onreceived = function onreceived(event) {
|
||||
};
|
||||
|
||||
function getMsgs() {
|
||||
var filter = new MozSmsFilter();
|
||||
let foundSmsList = new Array();
|
||||
|
||||
// Set filter for sent messages
|
||||
filter.delivery = "sent";
|
||||
let filter = { delivery: "sent" };
|
||||
|
||||
log("Getting the sent SMS messages.");
|
||||
let cursor = manager.getMessages(filter, false);
|
||||
|
@ -20,9 +20,8 @@ function verifyInitialState() {
|
||||
|
||||
function deleteAllMsgs(nextFunction) {
|
||||
let msgList = new Array();
|
||||
let filter = new MozSmsFilter;
|
||||
|
||||
let cursor = manager.getMessages(filter, false);
|
||||
let cursor = manager.getMessages();
|
||||
ok(cursor instanceof DOMCursor,
|
||||
"cursor is instanceof " + cursor.constructor);
|
||||
|
||||
@ -156,11 +155,10 @@ function markMsgRead() {
|
||||
}
|
||||
|
||||
function getMsgs() {
|
||||
var filter = new MozSmsFilter();
|
||||
let foundSmsList = new Array();
|
||||
|
||||
// Set filter for read messages
|
||||
filter.read = false;
|
||||
let filter = { read: false };
|
||||
|
||||
log("Getting the unread SMS messages.");
|
||||
let cursor = manager.getMessages(filter, false);
|
||||
|
@ -56,9 +56,6 @@ let tasks = {
|
||||
};
|
||||
|
||||
function getAllMessages(callback, filter, reverse) {
|
||||
if (!filter) {
|
||||
filter = new MozSmsFilter;
|
||||
}
|
||||
let messages = [];
|
||||
let request = manager.getMessages(filter, reverse || false);
|
||||
request.onsuccess = function(event) {
|
||||
@ -154,8 +151,7 @@ function checkThread(bodies, lastBody, unreadCount, participants,
|
||||
}
|
||||
|
||||
// Check whether the thread does contain all the messages it supposed to have.
|
||||
let filter = new MozSmsFilter;
|
||||
filter.threadId = thread.id;
|
||||
let filter = { threadId: thread.id };
|
||||
getAllMessages(function(messages) {
|
||||
is(messages.length, bodies.length, "messages.length and bodies.length");
|
||||
|
||||
|
@ -44,9 +44,6 @@ let tasks = {
|
||||
let manager;
|
||||
|
||||
function getAllMessages(callback, filter, reverse) {
|
||||
if (!filter) {
|
||||
filter = new MozSmsFilter;
|
||||
}
|
||||
let messages = [];
|
||||
let request = manager.getMessages(filter, reverse || false);
|
||||
request.onsuccess = function(event) {
|
||||
|
@ -76,7 +76,7 @@ function test_message_class_0() {
|
||||
"Message's sentTimestamp should be equal to SENT_TIMESTAMP");
|
||||
|
||||
// Make sure the message is not stored.
|
||||
let cursor = manager.getMessages(null, false);
|
||||
let cursor = manager.getMessages();
|
||||
cursor.onsuccess = function onsuccess() {
|
||||
if (cursor.result) {
|
||||
// Here we check whether there is any message of the same sender.
|
||||
|
@ -165,7 +165,7 @@ function testCreateMessageCursor(aMmdb) {
|
||||
log("testCreateMessageCursor()");
|
||||
|
||||
setStorageFull(true);
|
||||
return createMessageCursor(aMmdb, {}, false)
|
||||
return createMessageCursor(aMmdb)
|
||||
.then(() => setStorageFull(false));
|
||||
}
|
||||
|
||||
|
@ -630,7 +630,7 @@ function doVerifyDatabase(aMmdb, aExpected) {
|
||||
is(aExpected.length, 0, "remaining unmatched threads");
|
||||
|
||||
// 5) retrieve all messages.
|
||||
return createMessageCursor(aMmdb, {})
|
||||
return createMessageCursor(aMmdb)
|
||||
.then(function(aValues) {
|
||||
let [errorCode, domMessages] = aValues;
|
||||
is(errorCode, 0, "errorCode");
|
||||
|
@ -44,9 +44,6 @@ let tasks = {
|
||||
let manager;
|
||||
|
||||
function getAllMessages(callback, filter, reverse) {
|
||||
if (!filter) {
|
||||
filter = new MozSmsFilter;
|
||||
}
|
||||
let messages = [];
|
||||
let request = manager.getMessages(filter, reverse || false);
|
||||
request.onsuccess = function(event) {
|
||||
|
@ -52,9 +52,6 @@ let tasks = {
|
||||
};
|
||||
|
||||
function getAllMessages(callback, filter, reverse) {
|
||||
if (!filter) {
|
||||
filter = new MozSmsFilter;
|
||||
}
|
||||
let messages = [];
|
||||
let request = manager.getMessages(filter, reverse || false);
|
||||
request.onsuccess = function(event) {
|
||||
|
@ -60,9 +60,6 @@ let tasks = {
|
||||
};
|
||||
|
||||
function getAllMessages(callback, filter, reverse) {
|
||||
if (!filter) {
|
||||
filter = new MozSmsFilter;
|
||||
}
|
||||
let messages = [];
|
||||
let cursor = manager.getMessages(filter, reverse || false);
|
||||
cursor.onsuccess = function(event) {
|
||||
|
@ -3,4 +3,3 @@ skip-if = e10s
|
||||
|
||||
[test_sms_basics.html]
|
||||
skip-if = toolkit == 'android' #Bug 909036
|
||||
[test_smsfilter.html]
|
||||
|
@ -50,7 +50,6 @@ function checkInterface(aInterface) {
|
||||
function test() {
|
||||
checkInterface("SmsMessage");
|
||||
checkInterface("SmsEvent");
|
||||
checkInterface("SmsFilter");
|
||||
|
||||
// If sms is disabled and permission is removed, sms is disabled.
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.sms.enabled", false]]}, function() {
|
||||
|
@ -1,90 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test SmsFilter</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test SmsFilter **/
|
||||
|
||||
function throwingCheck(aFilter, aProperty, disallowedValue)
|
||||
{
|
||||
disallowedValue.forEach(function(v) {
|
||||
var exception = false;
|
||||
try {
|
||||
aFilter[aProperty] = v;
|
||||
} catch (e) {
|
||||
exception = true;
|
||||
}
|
||||
ok(exception, "An exception should have been thrown");
|
||||
});
|
||||
}
|
||||
|
||||
var filter = new MozSmsFilter();
|
||||
|
||||
isnot(filter, null, "filter should be set");
|
||||
|
||||
is(filter.startDate, null, "Parameters shouldn't be initialized");
|
||||
is(filter.endDate, null, "Parameters shouldn't be initialized");
|
||||
is(filter.numbers, null, "Parameters shouldn't be initialized");
|
||||
is(filter.delivery, null, "Parameters shouldn't be initialized");
|
||||
is(filter.read, null, "Parameters shouldn't be initialized");
|
||||
is(filter.threadId, null, "Parameters shouldn't be initialized");
|
||||
|
||||
var date = new Date();
|
||||
filter.startDate = date;
|
||||
is(filter.startDate, "" + date, "Setters and getters should work!");
|
||||
filter.startDate = null;
|
||||
is(filter.startDate, null, "null should revert the value to default");
|
||||
throwingCheck(filter, 'startDate', [ "foo", 42, [1, 2], function () {}, undefined ]);
|
||||
|
||||
filter.endDate = date;
|
||||
is(filter.endDate, "" + date, "Setters and getters should work!");
|
||||
filter.endDate = null;
|
||||
is(filter.endDate, null, "null should revert the value to default");
|
||||
throwingCheck(filter, 'endDate', [ "foo", 42, [1, 2], function () {}, undefined ]);
|
||||
|
||||
var numbers = [ "foo", "bar" ];
|
||||
filter.numbers = numbers;
|
||||
is(filter.numbers, "" + numbers, "Setters and getters should work!");
|
||||
filter.numbers = null;
|
||||
is(filter.numbers, null, "null should revert the value to default");
|
||||
throwingCheck(filter, 'numbers', [ "foo", 42, function () {}, new Date(), undefined ]);
|
||||
|
||||
filter.delivery = "sent";
|
||||
is(filter.delivery, "sent", "Setters and getters should work!");
|
||||
filter.delivery = "received";
|
||||
is(filter.delivery, "received", "Setters and getters should work!");
|
||||
filter.delivery = "";
|
||||
is(filter.delivery, null, "The empty string should revert the value to default.");
|
||||
filter.delivery = null;
|
||||
is(filter.delivery, null, "'null' should revert the value to default.");
|
||||
throwingCheck(filter, 'delivery', [ "foo", 42, [1, 2], function () {}, new Date(), undefined ]);
|
||||
|
||||
filter.read = true;
|
||||
is(filter.read, true, "Setters and getters should work!");
|
||||
filter.read = false;
|
||||
is(filter.read, false, "Setters and getters should work!");
|
||||
filter.read = null;
|
||||
is(filter.read, null, "'null' should revert the value to default");
|
||||
throwingCheck(filter, 'read', [ "foo", 0, [1, 2], function () {}, new Date(), undefined ]);
|
||||
|
||||
filter.threadId = 1;
|
||||
is(filter.threadId, 1, "Setters and getters should work!");
|
||||
filter.threadId = null;
|
||||
is(filter.threadId, null, "'null' should revert the value to default");
|
||||
throwingCheck(filter, 'threadId', [ "foo", 0, 1.5, [1, 2], function () {}, new Date(), undefined ]);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -37,6 +37,7 @@ function doTest() {
|
||||
"profileEnd": "function",
|
||||
"assert": "function",
|
||||
"count": "function",
|
||||
"table": "function",
|
||||
"__noSuchMethod__": "function"
|
||||
};
|
||||
|
||||
|
@ -702,8 +702,6 @@ var interfaceNamesInGlobalScope =
|
||||
"MozSettingsEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"MozSmsEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"MozSmsFilter",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"MozSmsMessage",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -13,6 +13,7 @@ interface Console {
|
||||
void error(any... data);
|
||||
void _exception(any... data);
|
||||
void debug(any... data);
|
||||
void table(any... data);
|
||||
void trace();
|
||||
void dir(any... data);
|
||||
void group(any... data);
|
||||
|
@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
interface MozMmsMessage;
|
||||
interface MozSmsFilter;
|
||||
interface MozSmsMessage;
|
||||
|
||||
dictionary SmsSegmentInfo {
|
||||
@ -51,6 +50,31 @@ dictionary MmsSendParameters {
|
||||
// specified under the multi-sim scenario.
|
||||
};
|
||||
|
||||
enum MobileMessageFilterDelivery { "sent", "received" };
|
||||
|
||||
dictionary MobileMessageFilter
|
||||
{
|
||||
// Close lower bound range for filtering by the message timestamp.
|
||||
// Time in milliseconds since Epoch.
|
||||
[EnforceRange] DOMTimeStamp? startDate = null;
|
||||
|
||||
// Close upper bound range for filtering by the message timestamp.
|
||||
// Time in milliseconds since Epoch.
|
||||
[EnforceRange] DOMTimeStamp? endDate = null;
|
||||
|
||||
// An array of string message participant addresses that any of which
|
||||
// appears or matches a message's sendor or recipients addresses.
|
||||
sequence<DOMString>? numbers = null;
|
||||
|
||||
MobileMessageFilterDelivery? delivery = null;
|
||||
|
||||
// Filtering by whether a message has been read or not.
|
||||
boolean? read = null;
|
||||
|
||||
// Filtering by a message's threadId attribute.
|
||||
[EnforceRange] unsigned long long? threadId = 0;
|
||||
};
|
||||
|
||||
[Pref="dom.sms.enabled"]
|
||||
interface MozMobileMessageManager : EventTarget
|
||||
{
|
||||
@ -111,7 +135,7 @@ interface MozMobileMessageManager : EventTarget
|
||||
|
||||
// Iterates through Moz{Mms,Sms}Message.
|
||||
[Throws]
|
||||
DOMCursor getMessages(optional MozSmsFilter? filter = null,
|
||||
DOMCursor getMessages(optional MobileMessageFilter filter,
|
||||
optional boolean reverse = false);
|
||||
|
||||
[Throws]
|
||||
|
@ -761,6 +761,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
||||
WriteParam(aMsg, aParam.mCompositionBounds);
|
||||
WriteParam(aMsg, aParam.mRootCompositionSize);
|
||||
WriteParam(aMsg, aParam.mScrollId);
|
||||
WriteParam(aMsg, aParam.mScrollParentId);
|
||||
WriteParam(aMsg, aParam.mResolution);
|
||||
WriteParam(aMsg, aParam.mCumulativeResolution);
|
||||
WriteParam(aMsg, aParam.mZoom);
|
||||
@ -787,6 +788,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
||||
ReadParam(aMsg, aIter, &aResult->mCompositionBounds) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mRootCompositionSize) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollId) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollParentId) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mResolution) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mCumulativeResolution) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mZoom) &&
|
||||
|
@ -71,6 +71,7 @@ public:
|
||||
static const ViewID NULL_SCROLL_ID; // This container layer does not scroll.
|
||||
static const ViewID START_SCROLL_ID = 2; // This is the ID that scrolling subframes
|
||||
// will begin at.
|
||||
static const FrameMetrics sNullMetrics; // We often need an empty metrics
|
||||
|
||||
FrameMetrics()
|
||||
: mCompositionBounds(0, 0, 0, 0)
|
||||
@ -86,6 +87,7 @@ public:
|
||||
, mIsRoot(false)
|
||||
, mHasScrollgrab(false)
|
||||
, mScrollId(NULL_SCROLL_ID)
|
||||
, mScrollParentId(NULL_SCROLL_ID)
|
||||
, mScrollOffset(0, 0)
|
||||
, mZoom(1)
|
||||
, mUpdateScrollOffset(false)
|
||||
@ -117,6 +119,7 @@ public:
|
||||
mPresShellId == aOther.mPresShellId &&
|
||||
mIsRoot == aOther.mIsRoot &&
|
||||
mScrollId == aOther.mScrollId &&
|
||||
mScrollParentId == aOther.mScrollParentId &&
|
||||
mScrollOffset == aOther.mScrollOffset &&
|
||||
mHasScrollgrab == aOther.mHasScrollgrab &&
|
||||
mUpdateScrollOffset == aOther.mUpdateScrollOffset;
|
||||
@ -404,6 +407,16 @@ public:
|
||||
mScrollId = scrollId;
|
||||
}
|
||||
|
||||
ViewID GetScrollParentId() const
|
||||
{
|
||||
return mScrollParentId;
|
||||
}
|
||||
|
||||
void SetScrollParentId(ViewID aParentId)
|
||||
{
|
||||
mScrollParentId = aParentId;
|
||||
}
|
||||
|
||||
void SetRootCompositionSize(const CSSSize& aRootCompositionSize)
|
||||
{
|
||||
mRootCompositionSize = aRootCompositionSize;
|
||||
@ -467,6 +480,9 @@ private:
|
||||
// A unique ID assigned to each scrollable frame.
|
||||
ViewID mScrollId;
|
||||
|
||||
// The ViewID of the scrollable frame to which overscroll should be handed off.
|
||||
ViewID mScrollParentId;
|
||||
|
||||
// The position of the top-left of the CSS viewport, relative to the document
|
||||
// (or the document relative to the viewport, if that helps understand it).
|
||||
//
|
||||
|
406
gfx/layers/LayerMetricsWrapper.h
Normal file
406
gfx/layers/LayerMetricsWrapper.h
Normal file
@ -0,0 +1,406 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* 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 GFX_LAYERMETRICSWRAPPER_H
|
||||
#define GFX_LAYERMETRICSWRAPPER_H
|
||||
|
||||
#include "Layers.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* A wrapper class around a target Layer with that allows user code to
|
||||
* walk through the FrameMetrics objects on the layer the same way it
|
||||
* would walk through a ContainerLayer hierarchy. Consider the following
|
||||
* layer tree:
|
||||
*
|
||||
* +---+
|
||||
* | A |
|
||||
* +---+
|
||||
* / | \
|
||||
* / | \
|
||||
* / | \
|
||||
* +---+ +-----+ +---+
|
||||
* | B | | C | | D |
|
||||
* +---+ +-----+ +---+
|
||||
* | FMn |
|
||||
* | . |
|
||||
* | . |
|
||||
* | . |
|
||||
* | FM1 |
|
||||
* | FM0 |
|
||||
* +-----+
|
||||
* / \
|
||||
* / \
|
||||
* +---+ +---+
|
||||
* | E | | F |
|
||||
* +---+ +---+
|
||||
*
|
||||
* In this layer tree, there are six layers with A being the root and B,D,E,F
|
||||
* being leaf nodes. Layer C is in the middle and has n+1 FrameMetrics, labelled
|
||||
* FM0...FMn. FM0 is the FrameMetrics you get by calling c->GetFrameMetrics(0)
|
||||
* and FMn is the FrameMetrics you can obtain by calling
|
||||
* c->GetFrameMetrics(c->GetFrameMetricsCount() - 1). This layer tree is
|
||||
* conceptually equivalent to this one below:
|
||||
*
|
||||
* +---+
|
||||
* | A |
|
||||
* +---+
|
||||
* / | \
|
||||
* / | \
|
||||
* / | \
|
||||
* +---+ +-----+ +---+
|
||||
* | B | | Cn | | D |
|
||||
* +---+ +-----+ +---+
|
||||
* |
|
||||
* .
|
||||
* .
|
||||
* .
|
||||
* |
|
||||
* +-----+
|
||||
* | C1 |
|
||||
* +-----+
|
||||
* |
|
||||
* +-----+
|
||||
* | C0 |
|
||||
* +-----+
|
||||
* / \
|
||||
* / \
|
||||
* +---+ +---+
|
||||
* | E | | F |
|
||||
* +---+ +---+
|
||||
*
|
||||
* In this layer tree, the layer C has been expanded into a stack of container
|
||||
* layers C1...Cn, where C1 has FrameMetrics FM1 and Cn has FrameMetrics Fn.
|
||||
* Although in this example C (in the first layer tree) and C0 (in the second
|
||||
* layer tree) are both ContainerLayers (because they have children), they
|
||||
* do not have to be. They may just be ThebesLayers or ColorLayers, for example,
|
||||
* which do not have any children. However, the type of C will always be the
|
||||
* same as the type of C0.
|
||||
*
|
||||
* The LayerMetricsWrapper class allows client code to treat the first layer
|
||||
* tree as though it were the second. That is, instead of client code having
|
||||
* to iterate through the FrameMetrics objects directly, it can use a
|
||||
* LayerMetricsWrapper to encapsulate that aspect of the layer tree and just
|
||||
* walk the tree as if it were a stack of ContainerLayers.
|
||||
*
|
||||
* The functions on this class do different things depending on which
|
||||
* simulated ContainerLayer is being wrapped. For example, if the
|
||||
* LayerMetricsWrapper is pretending to be C0, the GetNextSibling() function
|
||||
* will return null even though the underlying layer C does actually have
|
||||
* a next sibling. The LayerMetricsWrapper pretending to be Cn will return
|
||||
* D as the next sibling.
|
||||
*
|
||||
* Implementation notes:
|
||||
*
|
||||
* The AtTopLayer() and AtBottomLayer() functions in this class refer to
|
||||
* Cn and C0 in the second layer tree above; that is, they are predicates
|
||||
* to test if the LayerMetricsWrapper is simulating the topmost or bottommost
|
||||
* layer, as those will have special behaviour.
|
||||
*
|
||||
* It is possible to wrap a nullptr in a LayerMetricsWrapper, in which case
|
||||
* the IsValid() function will return false. This is required to allow
|
||||
* LayerMetricsWrapper to be a MOZ_STACK_CLASS (desirable because it is used
|
||||
* in loops and recursion).
|
||||
*
|
||||
* This class purposely does not expose the wrapped layer directly to avoid
|
||||
* user code from accidentally calling functions directly on it. Instead
|
||||
* any necessary functions should be wrapped in this class. It does expose
|
||||
* the wrapped layer as a void* for printf purposes.
|
||||
*
|
||||
* The implementation may look like it special-cases mIndex == 0 and/or
|
||||
* GetFrameMetricsCount() == 0. This is an artifact of the fact that both
|
||||
* mIndex and GetFrameMetricsCount() are uint32_t and GetFrameMetricsCount()
|
||||
* can return 0 but mIndex cannot store -1. This seems better than the
|
||||
* alternative of making mIndex a int32_t that can store -1, but then having
|
||||
* to cast to uint32_t all over the place.
|
||||
*/
|
||||
class MOZ_STACK_CLASS LayerMetricsWrapper {
|
||||
public:
|
||||
enum StartAt {
|
||||
TOP,
|
||||
BOTTOM,
|
||||
};
|
||||
|
||||
LayerMetricsWrapper()
|
||||
: mLayer(nullptr)
|
||||
, mIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit LayerMetricsWrapper(Layer* aRoot, StartAt aStart = StartAt::TOP)
|
||||
: mLayer(aRoot)
|
||||
, mIndex(0)
|
||||
{
|
||||
if (!mLayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aStart) {
|
||||
case StartAt::TOP:
|
||||
mIndex = mLayer->GetFrameMetricsCount();
|
||||
if (mIndex > 0) {
|
||||
mIndex--;
|
||||
}
|
||||
break;
|
||||
case StartAt::BOTTOM:
|
||||
mIndex = 0;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown startAt value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
explicit LayerMetricsWrapper(Layer* aLayer, uint32_t aMetricsIndex)
|
||||
: mLayer(aLayer)
|
||||
, mIndex(aMetricsIndex)
|
||||
{
|
||||
MOZ_ASSERT(mLayer);
|
||||
MOZ_ASSERT(mIndex == 0 || mIndex < mLayer->GetFrameMetricsCount());
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return mLayer != nullptr;
|
||||
}
|
||||
|
||||
MOZ_EXPLICIT_CONVERSION operator bool() const
|
||||
{
|
||||
return IsValid();
|
||||
}
|
||||
|
||||
bool IsScrollInfoLayer() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
// If we are not at the bottommost layer then it's
|
||||
// a stack of container layers all the way down to
|
||||
// mLayer, which we can ignore. We only care about
|
||||
// non-container descendants.
|
||||
return Metrics().IsScrollable()
|
||||
&& mLayer->AsContainerLayer()
|
||||
&& !mLayer->GetFirstChild();
|
||||
}
|
||||
|
||||
LayerMetricsWrapper GetParent() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (!AtTopLayer()) {
|
||||
return LayerMetricsWrapper(mLayer, mIndex + 1);
|
||||
}
|
||||
if (mLayer->GetParent()) {
|
||||
return LayerMetricsWrapper(mLayer->GetParent(), StartAt::BOTTOM);
|
||||
}
|
||||
return LayerMetricsWrapper(nullptr);
|
||||
}
|
||||
|
||||
LayerMetricsWrapper GetFirstChild() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (!AtBottomLayer()) {
|
||||
return LayerMetricsWrapper(mLayer, mIndex - 1);
|
||||
}
|
||||
return LayerMetricsWrapper(mLayer->GetFirstChild());
|
||||
}
|
||||
|
||||
LayerMetricsWrapper GetLastChild() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (!AtBottomLayer()) {
|
||||
return LayerMetricsWrapper(mLayer, mIndex - 1);
|
||||
}
|
||||
return LayerMetricsWrapper(mLayer->GetLastChild());
|
||||
}
|
||||
|
||||
LayerMetricsWrapper GetPrevSibling() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (AtTopLayer()) {
|
||||
return LayerMetricsWrapper(mLayer->GetPrevSibling());
|
||||
}
|
||||
return LayerMetricsWrapper(nullptr);
|
||||
}
|
||||
|
||||
LayerMetricsWrapper GetNextSibling() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (AtTopLayer()) {
|
||||
return LayerMetricsWrapper(mLayer->GetNextSibling());
|
||||
}
|
||||
return LayerMetricsWrapper(nullptr);
|
||||
}
|
||||
|
||||
const FrameMetrics& Metrics() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (mIndex >= mLayer->GetFrameMetricsCount()) {
|
||||
return FrameMetrics::sNullMetrics;
|
||||
}
|
||||
return mLayer->GetFrameMetrics(mIndex);
|
||||
}
|
||||
|
||||
AsyncPanZoomController* GetApzc() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (mIndex >= mLayer->GetFrameMetricsCount()) {
|
||||
return nullptr;
|
||||
}
|
||||
return mLayer->GetAsyncPanZoomController(mIndex);
|
||||
}
|
||||
|
||||
void SetApzc(AsyncPanZoomController* aApzc) const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (mLayer->GetFrameMetricsCount() == 0) {
|
||||
MOZ_ASSERT(mIndex == 0);
|
||||
MOZ_ASSERT(aApzc == nullptr);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mIndex < mLayer->GetFrameMetricsCount());
|
||||
mLayer->SetAsyncPanZoomController(mIndex, aApzc);
|
||||
}
|
||||
|
||||
const char* Name() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (AtBottomLayer()) {
|
||||
return mLayer->Name();
|
||||
}
|
||||
return "DummyContainerLayer";
|
||||
}
|
||||
|
||||
LayerManager* Manager() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
return mLayer->Manager();
|
||||
}
|
||||
|
||||
gfx::Matrix4x4 GetTransform() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (AtBottomLayer()) {
|
||||
return mLayer->GetTransform();
|
||||
}
|
||||
return gfx::Matrix4x4();
|
||||
}
|
||||
|
||||
RefLayer* AsRefLayer() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (AtBottomLayer()) {
|
||||
return mLayer->AsRefLayer();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIntRegion GetVisibleRegion() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (AtBottomLayer()) {
|
||||
return mLayer->GetVisibleRegion();
|
||||
}
|
||||
nsIntRegion region = mLayer->GetVisibleRegion();
|
||||
region.Transform(gfx::To3DMatrix(mLayer->GetTransform()));
|
||||
return region;
|
||||
}
|
||||
|
||||
const nsIntRect* GetClipRect() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
return mLayer->GetClipRect();
|
||||
}
|
||||
|
||||
const std::string& GetContentDescription() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
return mLayer->GetContentDescription();
|
||||
}
|
||||
|
||||
// Expose an opaque pointer to the layer. Mostly used for printf
|
||||
// purposes. This is not intended to be a general-purpose accessor
|
||||
// for the underlying layer.
|
||||
const void* GetLayer() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
return (void*)mLayer;
|
||||
}
|
||||
|
||||
bool operator==(const LayerMetricsWrapper& aOther) const
|
||||
{
|
||||
return mLayer == aOther.mLayer
|
||||
&& mIndex == aOther.mIndex;
|
||||
}
|
||||
|
||||
bool operator!=(const LayerMetricsWrapper& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
static const FrameMetrics& TopmostScrollableMetrics(Layer* aLayer)
|
||||
{
|
||||
for (uint32_t i = aLayer->GetFrameMetricsCount(); i > 0; i--) {
|
||||
if (aLayer->GetFrameMetrics(i - 1).IsScrollable()) {
|
||||
return aLayer->GetFrameMetrics(i - 1);
|
||||
}
|
||||
}
|
||||
return FrameMetrics::sNullMetrics;
|
||||
}
|
||||
|
||||
static const FrameMetrics& BottommostScrollableMetrics(Layer* aLayer)
|
||||
{
|
||||
for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
|
||||
if (aLayer->GetFrameMetrics(i).IsScrollable()) {
|
||||
return aLayer->GetFrameMetrics(i);
|
||||
}
|
||||
}
|
||||
return FrameMetrics::sNullMetrics;
|
||||
}
|
||||
|
||||
static const FrameMetrics& BottommostMetrics(Layer* aLayer)
|
||||
{
|
||||
if (aLayer->GetFrameMetricsCount() > 0) {
|
||||
return aLayer->GetFrameMetrics(0);
|
||||
}
|
||||
return FrameMetrics::sNullMetrics;
|
||||
}
|
||||
|
||||
private:
|
||||
bool AtBottomLayer() const
|
||||
{
|
||||
return mIndex == 0;
|
||||
}
|
||||
|
||||
bool AtTopLayer() const
|
||||
{
|
||||
return mLayer->GetFrameMetricsCount() == 0 || mIndex == mLayer->GetFrameMetricsCount() - 1;
|
||||
}
|
||||
|
||||
private:
|
||||
Layer* mLayer;
|
||||
uint32_t mIndex;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* GFX_LAYERMETRICSWRAPPER_H */
|
@ -27,6 +27,7 @@
|
||||
#include "mozilla/layers/Compositor.h" // for Compositor
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
||||
#include "mozilla/layers/LayersMessages.h" // for TransformFunction, etc
|
||||
#include "nsAString.h"
|
||||
#include "nsCSSValue.h" // for nsCSSValue::Array, etc
|
||||
@ -47,16 +48,51 @@ FILEOrDefault(FILE* aFile)
|
||||
|
||||
typedef FrameMetrics::ViewID ViewID;
|
||||
const ViewID FrameMetrics::NULL_SCROLL_ID = 0;
|
||||
const FrameMetrics FrameMetrics::sNullMetrics;
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
//--------------------------------------------------
|
||||
// LayerManager
|
||||
Layer*
|
||||
LayerManager::GetPrimaryScrollableLayer()
|
||||
FrameMetrics::ViewID
|
||||
LayerManager::GetRootScrollableLayerId()
|
||||
{
|
||||
if (!mRoot) {
|
||||
return nullptr;
|
||||
return FrameMetrics::NULL_SCROLL_ID;
|
||||
}
|
||||
|
||||
nsTArray<LayerMetricsWrapper> queue;
|
||||
queue.AppendElement(LayerMetricsWrapper(mRoot));
|
||||
while (queue.Length()) {
|
||||
LayerMetricsWrapper layer = queue[0];
|
||||
queue.RemoveElementAt(0);
|
||||
|
||||
const FrameMetrics& frameMetrics = layer.Metrics();
|
||||
if (frameMetrics.IsScrollable()) {
|
||||
return frameMetrics.GetScrollId();
|
||||
}
|
||||
|
||||
LayerMetricsWrapper child = layer.GetFirstChild();
|
||||
while (child) {
|
||||
queue.AppendElement(child);
|
||||
child = child.GetNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
return FrameMetrics::NULL_SCROLL_ID;
|
||||
}
|
||||
|
||||
void
|
||||
LayerManager::GetRootScrollableLayers(nsTArray<Layer*>& aArray)
|
||||
{
|
||||
if (!mRoot) {
|
||||
return;
|
||||
}
|
||||
|
||||
FrameMetrics::ViewID rootScrollableId = GetRootScrollableLayerId();
|
||||
if (rootScrollableId == FrameMetrics::NULL_SCROLL_ID) {
|
||||
aArray.AppendElement(mRoot);
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<Layer*> queue;
|
||||
@ -65,21 +101,15 @@ LayerManager::GetPrimaryScrollableLayer()
|
||||
Layer* layer = queue[0];
|
||||
queue.RemoveElementAt(0);
|
||||
|
||||
const FrameMetrics& frameMetrics = layer->GetFrameMetrics();
|
||||
if (frameMetrics.IsScrollable()) {
|
||||
return layer;
|
||||
if (LayerMetricsWrapper::TopmostScrollableMetrics(layer).GetScrollId() == rootScrollableId) {
|
||||
aArray.AppendElement(layer);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ContainerLayer* containerLayer = layer->AsContainerLayer()) {
|
||||
Layer* child = containerLayer->GetFirstChild();
|
||||
while (child) {
|
||||
queue.AppendElement(child);
|
||||
child = child->GetNextSibling();
|
||||
}
|
||||
for (Layer* child = layer->GetFirstChild(); child; child = child->GetNextSibling()) {
|
||||
queue.AppendElement(child);
|
||||
}
|
||||
}
|
||||
|
||||
return mRoot;
|
||||
}
|
||||
|
||||
void
|
||||
@ -95,18 +125,13 @@ LayerManager::GetScrollableLayers(nsTArray<Layer*>& aArray)
|
||||
Layer* layer = queue.LastElement();
|
||||
queue.RemoveElementAt(queue.Length() - 1);
|
||||
|
||||
const FrameMetrics& frameMetrics = layer->GetFrameMetrics();
|
||||
if (frameMetrics.IsScrollable()) {
|
||||
if (layer->HasScrollableFrameMetrics()) {
|
||||
aArray.AppendElement(layer);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ContainerLayer* containerLayer = layer->AsContainerLayer()) {
|
||||
Layer* child = containerLayer->GetFirstChild();
|
||||
while (child) {
|
||||
queue.AppendElement(child);
|
||||
child = child->GetNextSibling();
|
||||
}
|
||||
for (Layer* child = layer->GetFirstChild(); child; child = child->GetNextSibling()) {
|
||||
queue.AppendElement(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -170,7 +195,6 @@ Layer::Layer(LayerManager* aManager, void* aImplData) :
|
||||
mPrevSibling(nullptr),
|
||||
mImplData(aImplData),
|
||||
mMaskLayer(nullptr),
|
||||
mScrollHandoffParentId(FrameMetrics::NULL_SCROLL_ID),
|
||||
mPostXScale(1.0f),
|
||||
mPostYScale(1.0f),
|
||||
mOpacity(1.0),
|
||||
@ -449,20 +473,28 @@ Layer::SetAnimations(const AnimationArray& aAnimations)
|
||||
}
|
||||
|
||||
void
|
||||
Layer::SetAsyncPanZoomController(AsyncPanZoomController *controller)
|
||||
Layer::SetAsyncPanZoomController(uint32_t aIndex, AsyncPanZoomController *controller)
|
||||
{
|
||||
mAPZC = controller;
|
||||
MOZ_ASSERT(aIndex < GetFrameMetricsCount());
|
||||
mApzcs[aIndex] = controller;
|
||||
}
|
||||
|
||||
AsyncPanZoomController*
|
||||
Layer::GetAsyncPanZoomController() const
|
||||
Layer::GetAsyncPanZoomController(uint32_t aIndex) const
|
||||
{
|
||||
MOZ_ASSERT(aIndex < GetFrameMetricsCount());
|
||||
#ifdef DEBUG
|
||||
if (mAPZC) {
|
||||
MOZ_ASSERT(GetFrameMetrics().IsScrollable());
|
||||
if (mApzcs[aIndex]) {
|
||||
MOZ_ASSERT(GetFrameMetrics(aIndex).IsScrollable());
|
||||
}
|
||||
#endif
|
||||
return mAPZC;
|
||||
return mApzcs[aIndex];
|
||||
}
|
||||
|
||||
void
|
||||
Layer::FrameMetricsChanged()
|
||||
{
|
||||
mApzcs.SetLength(GetFrameMetricsCount());
|
||||
}
|
||||
|
||||
void
|
||||
@ -663,6 +695,33 @@ Layer::CalculateScissorRect(const RenderTargetIntRect& aCurrentScissorRect,
|
||||
return currentClip.Intersect(scissor);
|
||||
}
|
||||
|
||||
const FrameMetrics&
|
||||
Layer::GetFrameMetrics(uint32_t aIndex) const
|
||||
{
|
||||
MOZ_ASSERT(aIndex < GetFrameMetricsCount());
|
||||
return mFrameMetrics[aIndex];
|
||||
}
|
||||
|
||||
bool
|
||||
Layer::HasScrollableFrameMetrics() const
|
||||
{
|
||||
for (uint32_t i = 0; i < GetFrameMetricsCount(); i++) {
|
||||
if (GetFrameMetrics(i).IsScrollable()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Layer::IsScrollInfoLayer() const
|
||||
{
|
||||
// A scrollable container layer with no children
|
||||
return AsContainerLayer()
|
||||
&& HasScrollableFrameMetrics()
|
||||
&& !GetFirstChild();
|
||||
}
|
||||
|
||||
const Matrix4x4
|
||||
Layer::GetTransform() const
|
||||
{
|
||||
@ -1461,11 +1520,11 @@ Layer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
if (mMaskLayer) {
|
||||
aStream << nsPrintfCString(" [mMaskLayer=%p]", mMaskLayer.get()).get();
|
||||
}
|
||||
if (!mFrameMetrics.IsDefault()) {
|
||||
AppendToString(aStream, mFrameMetrics, " [metrics=", "]");
|
||||
}
|
||||
if (mScrollHandoffParentId != FrameMetrics::NULL_SCROLL_ID) {
|
||||
aStream << nsPrintfCString(" [scrollParent=%llu]", mScrollHandoffParentId).get();
|
||||
for (uint32_t i = 0; i < mFrameMetrics.Length(); i++) {
|
||||
if (!mFrameMetrics[i].IsDefault()) {
|
||||
aStream << nsPrintfCString(" [metrics%d=", i).get();
|
||||
AppendToString(aStream, mFrameMetrics[i], "", "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,7 @@ class AsyncPanZoomController;
|
||||
class ClientLayerManager;
|
||||
class CommonLayerAttributes;
|
||||
class Layer;
|
||||
class LayerMetricsWrapper;
|
||||
class ThebesLayer;
|
||||
class ContainerLayer;
|
||||
class ImageLayer;
|
||||
@ -336,10 +337,20 @@ public:
|
||||
|
||||
/**
|
||||
* Does a breadth-first search from the root layer to find the first
|
||||
* scrollable layer.
|
||||
* scrollable layer, and returns its ViewID. Note that there may be
|
||||
* other layers in the tree which share the same ViewID.
|
||||
* Can be called any time.
|
||||
*/
|
||||
Layer* GetPrimaryScrollableLayer();
|
||||
FrameMetrics::ViewID GetRootScrollableLayerId();
|
||||
|
||||
/**
|
||||
* Does a breadth-first search from the root layer to find the first
|
||||
* scrollable layer, and returns all the layers that have that ViewID
|
||||
* as the first scrollable metrics in their ancestor chain. If no
|
||||
* scrollable layers are found it just returns the root of the tree if
|
||||
* there is one.
|
||||
*/
|
||||
void GetRootScrollableLayers(nsTArray<Layer*>& aArray);
|
||||
|
||||
/**
|
||||
* Returns a list of all descendant layers for which
|
||||
@ -818,29 +829,44 @@ public:
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
* Set the (sub)document metrics used to render the Layer subtree
|
||||
* rooted at this.
|
||||
* rooted at this. Note that a layer may have multiple FrameMetrics
|
||||
* objects; calling this function will remove all of them and replace
|
||||
* them with the provided FrameMetrics. See the documentation for
|
||||
* SetFrameMetrics(const nsTArray<FrameMetrics>&) for more details.
|
||||
*/
|
||||
void SetFrameMetrics(const FrameMetrics& aFrameMetrics)
|
||||
{
|
||||
if (mFrameMetrics != aFrameMetrics) {
|
||||
if (mFrameMetrics.Length() != 1 || mFrameMetrics[0] != aFrameMetrics) {
|
||||
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) FrameMetrics", this));
|
||||
mFrameMetrics = aFrameMetrics;
|
||||
mFrameMetrics.ReplaceElementsAt(0, mFrameMetrics.Length(), aFrameMetrics);
|
||||
FrameMetricsChanged();
|
||||
Mutated();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
* Set the ViewID of the ContainerLayer to which overscroll should be handed
|
||||
* off. A value of NULL_SCROLL_ID means that the default handoff-parent-finding
|
||||
* behaviour should be used (i.e. walk up the layer tree to find the next
|
||||
* scrollable ancestor layer).
|
||||
* Set the (sub)document metrics used to render the Layer subtree
|
||||
* rooted at this. There might be multiple metrics on this layer
|
||||
* because the layer may, for example, be contained inside multiple
|
||||
* nested scrolling subdocuments. In general a Layer having multiple
|
||||
* FrameMetrics objects is conceptually equivalent to having a stack
|
||||
* of ContainerLayers that have been flattened into this Layer.
|
||||
* See the documentation in LayerMetricsWrapper.h for a more detailed
|
||||
* explanation of this conceptual equivalence.
|
||||
*
|
||||
* Note also that there is actually a many-to-many relationship between
|
||||
* Layers and FrameMetrics, because multiple Layers may have identical
|
||||
* FrameMetrics objects. This happens when those layers belong to the
|
||||
* same scrolling subdocument and therefore end up with the same async
|
||||
* transform when they are scrolled by the APZ code.
|
||||
*/
|
||||
void SetScrollHandoffParentId(FrameMetrics::ViewID aScrollParentId)
|
||||
void SetFrameMetrics(const nsTArray<FrameMetrics>& aMetricsArray)
|
||||
{
|
||||
if (mScrollHandoffParentId != aScrollParentId) {
|
||||
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ScrollHandoffParentId", this));
|
||||
mScrollHandoffParentId = aScrollParentId;
|
||||
if (mFrameMetrics != aMetricsArray) {
|
||||
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) FrameMetrics", this));
|
||||
mFrameMetrics = aMetricsArray;
|
||||
FrameMetricsChanged();
|
||||
Mutated();
|
||||
}
|
||||
}
|
||||
@ -1173,8 +1199,11 @@ public:
|
||||
const nsIntRect* GetClipRect() { return mUseClipRect ? &mClipRect : nullptr; }
|
||||
uint32_t GetContentFlags() { return mContentFlags; }
|
||||
const nsIntRegion& GetVisibleRegion() const { return mVisibleRegion; }
|
||||
const FrameMetrics& GetFrameMetrics() const { return mFrameMetrics; }
|
||||
FrameMetrics::ViewID GetScrollHandoffParentId() const { return mScrollHandoffParentId; }
|
||||
const FrameMetrics& GetFrameMetrics(uint32_t aIndex) const;
|
||||
uint32_t GetFrameMetricsCount() const { return mFrameMetrics.Length(); }
|
||||
const nsTArray<FrameMetrics>& GetAllFrameMetrics() { return mFrameMetrics; }
|
||||
bool HasScrollableFrameMetrics() const;
|
||||
bool IsScrollInfoLayer() const;
|
||||
const EventRegions& GetEventRegions() const { return mEventRegions; }
|
||||
ContainerLayer* GetParent() { return mParent; }
|
||||
Layer* GetNextSibling() { return mNextSibling; }
|
||||
@ -1474,9 +1503,16 @@ public:
|
||||
|
||||
// These functions allow attaching an AsyncPanZoomController to this layer,
|
||||
// and can be used anytime.
|
||||
// A layer has an APZC only-if GetFrameMetrics().IsScrollable()
|
||||
void SetAsyncPanZoomController(AsyncPanZoomController *controller);
|
||||
AsyncPanZoomController* GetAsyncPanZoomController() const;
|
||||
// A layer has an APZC at index aIndex only-if GetFrameMetrics(aIndex).IsScrollable();
|
||||
// attempting to get an APZC for a non-scrollable metrics will return null.
|
||||
// The aIndex for these functions must be less than GetFrameMetricsCount().
|
||||
void SetAsyncPanZoomController(uint32_t aIndex, AsyncPanZoomController *controller);
|
||||
AsyncPanZoomController* GetAsyncPanZoomController(uint32_t aIndex) const;
|
||||
// The FrameMetricsChanged function is used internally to ensure the APZC array length
|
||||
// matches the frame metrics array length.
|
||||
private:
|
||||
void FrameMetricsChanged();
|
||||
public:
|
||||
|
||||
void ApplyPendingUpdatesForThisTransaction();
|
||||
|
||||
@ -1580,8 +1616,7 @@ protected:
|
||||
nsRefPtr<Layer> mMaskLayer;
|
||||
gfx::UserData mUserData;
|
||||
nsIntRegion mVisibleRegion;
|
||||
FrameMetrics mFrameMetrics;
|
||||
FrameMetrics::ViewID mScrollHandoffParentId;
|
||||
nsTArray<FrameMetrics> mFrameMetrics;
|
||||
EventRegions mEventRegions;
|
||||
gfx::Matrix4x4 mTransform;
|
||||
// A mutation of |mTransform| that we've queued to be applied at the
|
||||
@ -1601,7 +1636,7 @@ protected:
|
||||
nsIntRect mClipRect;
|
||||
nsIntRect mTileSourceRect;
|
||||
nsIntRegion mInvalidRegion;
|
||||
nsRefPtr<AsyncPanZoomController> mAPZC;
|
||||
nsTArray<nsRefPtr<AsyncPanZoomController> > mApzcs;
|
||||
uint32_t mContentFlags;
|
||||
bool mUseClipRect;
|
||||
bool mUseTileSourceRect;
|
||||
|
@ -125,6 +125,9 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m,
|
||||
AppendToString(aStream, m.mCriticalDisplayPort, " cdp=");
|
||||
if (!detailed) {
|
||||
AppendToString(aStream, m.GetScrollId(), " scrollId=");
|
||||
if (m.GetScrollParentId() != FrameMetrics::NULL_SCROLL_ID) {
|
||||
AppendToString(aStream, m.GetScrollParentId(), " scrollParent=");
|
||||
}
|
||||
aStream << nsPrintfCString(" z=%.3f }", m.GetZoom().scale).get();
|
||||
} else {
|
||||
AppendToString(aStream, m.GetDisplayPortMargins(), " dpm=");
|
||||
@ -137,6 +140,7 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m,
|
||||
m.mTransformScale.scale).get();
|
||||
aStream << nsPrintfCString(" u=(%d %lu)",
|
||||
m.GetScrollOffsetUpdated(), m.GetScrollGeneration()).get();
|
||||
AppendToString(aStream, m.GetScrollParentId(), " p=");
|
||||
aStream << nsPrintfCString(" i=(%ld %lld) }",
|
||||
m.GetPresShellId(), m.GetScrollId()).get();
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/gfx/Point.h" // for Point
|
||||
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
|
||||
#include "mozilla/layers/AsyncPanZoomController.h"
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/mozalloc.h" // for operator new
|
||||
#include "mozilla/TouchEvents.h"
|
||||
@ -160,7 +161,8 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
|
||||
if (aRoot) {
|
||||
mApzcTreeLog << "[start]\n";
|
||||
UpdatePanZoomControllerTree(state, aRoot,
|
||||
LayerMetricsWrapper root(aRoot);
|
||||
UpdatePanZoomControllerTree(state, root,
|
||||
// aCompositor is null in gtest scenarios
|
||||
aCompositor ? aCompositor->RootLayerTreeId() : 0,
|
||||
Matrix4x4(), nullptr, nullptr, nsIntRegion());
|
||||
@ -205,13 +207,13 @@ ComputeTouchSensitiveRegion(GeckoContentController* aController,
|
||||
}
|
||||
|
||||
AsyncPanZoomController*
|
||||
APZCTreeManager::PrepareAPZCForLayer(const Layer* aLayer,
|
||||
APZCTreeManager::PrepareAPZCForLayer(const LayerMetricsWrapper& aLayer,
|
||||
const FrameMetrics& aMetrics,
|
||||
uint64_t aLayersId,
|
||||
const gfx::Matrix4x4& aAncestorTransform,
|
||||
const nsIntRegion& aObscured,
|
||||
AsyncPanZoomController*& aOutParent,
|
||||
AsyncPanZoomController*& aOutNextSibling,
|
||||
AsyncPanZoomController* aNextSibling,
|
||||
TreeBuildingState& aState)
|
||||
{
|
||||
if (!aMetrics.IsScrollable()) {
|
||||
@ -237,13 +239,13 @@ APZCTreeManager::PrepareAPZCForLayer(const Layer* aLayer,
|
||||
if (!insertResult.second) {
|
||||
apzc = insertResult.first->second;
|
||||
}
|
||||
APZCTM_LOG("Found APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer, guid.mLayersId, guid.mScrollId);
|
||||
APZCTM_LOG("Found APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer.GetLayer(), guid.mLayersId, guid.mScrollId);
|
||||
|
||||
// If we haven't encountered a layer already with the same metrics, then we need to
|
||||
// do the full reuse-or-make-an-APZC algorithm, which is contained inside the block
|
||||
// below.
|
||||
if (apzc == nullptr) {
|
||||
apzc = aLayer->GetAsyncPanZoomController();
|
||||
apzc = aLayer.GetApzc();
|
||||
|
||||
// If the content represented by the scrollable layer has changed (which may
|
||||
// be possible because of DLBI heuristics) then we don't want to keep using
|
||||
@ -290,11 +292,10 @@ APZCTreeManager::PrepareAPZCForLayer(const Layer* aLayer,
|
||||
apzc->SetPrevSibling(nullptr);
|
||||
apzc->SetLastChild(nullptr);
|
||||
}
|
||||
APZCTM_LOG("Using APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer, aLayersId, aMetrics.GetScrollId());
|
||||
APZCTM_LOG("Using APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer.GetLayer(), aLayersId, aMetrics.GetScrollId());
|
||||
|
||||
apzc->NotifyLayersUpdated(aMetrics,
|
||||
aState.mIsFirstPaint && (aLayersId == aState.mOriginatingLayersId));
|
||||
apzc->SetScrollHandoffParentId(aLayer->GetScrollHandoffParentId());
|
||||
|
||||
nsIntRegion unobscured = ComputeTouchSensitiveRegion(state->mController, aMetrics, aObscured);
|
||||
apzc->SetLayerHitTestData(unobscured, aAncestorTransform);
|
||||
@ -304,13 +305,13 @@ APZCTreeManager::PrepareAPZCForLayer(const Layer* aLayer,
|
||||
mApzcTreeLog << "APZC " << guid
|
||||
<< "\tcb=" << aMetrics.mCompositionBounds
|
||||
<< "\tsr=" << aMetrics.mScrollableRect
|
||||
<< (aLayer->GetVisibleRegion().IsEmpty() ? "\tscrollinfo" : "")
|
||||
<< (aLayer.GetVisibleRegion().IsEmpty() ? "\tscrollinfo" : "")
|
||||
<< (apzc->HasScrollgrab() ? "\tscrollgrab" : "")
|
||||
<< "\t" << aLayer->GetContentDescription();
|
||||
<< "\t" << aLayer.GetContentDescription();
|
||||
|
||||
// Bind the APZC instance into the tree of APZCs
|
||||
if (aOutNextSibling) {
|
||||
aOutNextSibling->SetPrevSibling(apzc);
|
||||
if (aNextSibling) {
|
||||
aNextSibling->SetPrevSibling(apzc);
|
||||
} else if (aOutParent) {
|
||||
aOutParent->SetLastChild(apzc);
|
||||
} else {
|
||||
@ -377,7 +378,8 @@ APZCTreeManager::PrepareAPZCForLayer(const Layer* aLayer,
|
||||
|
||||
AsyncPanZoomController*
|
||||
APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
|
||||
Layer* aLayer, uint64_t aLayersId,
|
||||
const LayerMetricsWrapper& aLayer,
|
||||
uint64_t aLayersId,
|
||||
const gfx::Matrix4x4& aAncestorTransform,
|
||||
AsyncPanZoomController* aParent,
|
||||
AsyncPanZoomController* aNextSibling,
|
||||
@ -385,12 +387,12 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
|
||||
{
|
||||
mTreeLock.AssertCurrentThreadOwns();
|
||||
|
||||
mApzcTreeLog << aLayer->Name() << '\t';
|
||||
mApzcTreeLog << aLayer.Name() << '\t';
|
||||
|
||||
AsyncPanZoomController* apzc = PrepareAPZCForLayer(aLayer,
|
||||
aLayer->GetFrameMetrics(), aLayersId, aAncestorTransform,
|
||||
aLayer.Metrics(), aLayersId, aAncestorTransform,
|
||||
aObscured, aParent, aNextSibling, aState);
|
||||
aLayer->SetAsyncPanZoomController(apzc);
|
||||
aLayer.SetApzc(apzc);
|
||||
|
||||
mApzcTreeLog << '\n';
|
||||
|
||||
@ -401,13 +403,13 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
|
||||
// transform to layer L when we recurse into the children below. If we are at a layer
|
||||
// with an APZC, such as P, then we reset the ancestorTransform to just PC, to start
|
||||
// the new accumulation as we go down.
|
||||
Matrix4x4 transform = aLayer->GetTransform();
|
||||
Matrix4x4 transform = aLayer.GetTransform();
|
||||
Matrix4x4 ancestorTransform = transform;
|
||||
if (!apzc) {
|
||||
ancestorTransform = ancestorTransform * aAncestorTransform;
|
||||
}
|
||||
|
||||
uint64_t childLayersId = (aLayer->AsRefLayer() ? aLayer->AsRefLayer()->GetReferentId() : aLayersId);
|
||||
uint64_t childLayersId = (aLayer.AsRefLayer() ? aLayer.AsRefLayer()->GetReferentId() : aLayersId);
|
||||
|
||||
nsIntRegion obscured;
|
||||
if (aLayersId == childLayersId) {
|
||||
@ -429,7 +431,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
|
||||
// If there's no APZC at this level, any APZCs for our child layers will
|
||||
// have our siblings as siblings.
|
||||
AsyncPanZoomController* next = apzc ? nullptr : aNextSibling;
|
||||
for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
|
||||
for (LayerMetricsWrapper child = aLayer.GetLastChild(); child; child = child.GetPrevSibling()) {
|
||||
gfx::TreeAutoIndent indent(mApzcTreeLog);
|
||||
next = UpdatePanZoomControllerTree(aState, child, childLayersId,
|
||||
ancestorTransform, aParent, next,
|
||||
@ -437,10 +439,10 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
|
||||
|
||||
// Each layer obscures its previous siblings, so we augment the obscured
|
||||
// region as we loop backwards through the children.
|
||||
nsIntRegion childRegion = child->GetVisibleRegion();
|
||||
childRegion.Transform(gfx::To3DMatrix(child->GetTransform()));
|
||||
if (child->GetClipRect()) {
|
||||
childRegion.AndWith(*child->GetClipRect());
|
||||
nsIntRegion childRegion = child.GetVisibleRegion();
|
||||
childRegion.Transform(gfx::To3DMatrix(child.GetTransform()));
|
||||
if (child.GetClipRect()) {
|
||||
childRegion.AndWith(*child.GetClipRect());
|
||||
}
|
||||
|
||||
obscured.OrWith(childRegion);
|
||||
|
@ -44,6 +44,7 @@ class AsyncPanZoomController;
|
||||
class CompositorParent;
|
||||
class APZPaintLogHelper;
|
||||
class OverscrollHandoffChain;
|
||||
class LayerMetricsWrapper;
|
||||
|
||||
/**
|
||||
* ****************** NOTE ON LOCK ORDERING IN APZ **************************
|
||||
@ -378,13 +379,13 @@ private:
|
||||
void UpdateZoomConstraintsRecursively(AsyncPanZoomController* aApzc,
|
||||
const ZoomConstraints& aConstraints);
|
||||
|
||||
AsyncPanZoomController* PrepareAPZCForLayer(const Layer* aLayer,
|
||||
AsyncPanZoomController* PrepareAPZCForLayer(const LayerMetricsWrapper& aLayer,
|
||||
const FrameMetrics& aMetrics,
|
||||
uint64_t aLayersId,
|
||||
const gfx::Matrix4x4& aAncestorTransform,
|
||||
const nsIntRegion& aObscured,
|
||||
AsyncPanZoomController*& aOutParent,
|
||||
AsyncPanZoomController*& aOutNextSibling,
|
||||
AsyncPanZoomController* aNextSibling,
|
||||
TreeBuildingState& aState);
|
||||
|
||||
/**
|
||||
@ -397,7 +398,8 @@ private:
|
||||
* code.
|
||||
*/
|
||||
AsyncPanZoomController* UpdatePanZoomControllerTree(TreeBuildingState& aState,
|
||||
Layer* aLayer, uint64_t aLayersId,
|
||||
const LayerMetricsWrapper& aLayer,
|
||||
uint64_t aLayersId,
|
||||
const gfx::Matrix4x4& aAncestorTransform,
|
||||
AsyncPanZoomController* aParent,
|
||||
AsyncPanZoomController* aNextSibling,
|
||||
|
@ -739,7 +739,6 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
|
||||
mAsyncScrollTimeoutTask(nullptr),
|
||||
mTouchBlockBalance(0),
|
||||
mTreeManager(aTreeManager),
|
||||
mScrollParentId(FrameMetrics::NULL_SCROLL_ID),
|
||||
mAPZCId(sAsyncPanZoomControllerCount++),
|
||||
mSharedLock(nullptr)
|
||||
{
|
||||
@ -2414,6 +2413,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
||||
|
||||
mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
|
||||
mFrameMetrics.mMayHaveTouchCaret = aLayerMetrics.mMayHaveTouchCaret;
|
||||
mFrameMetrics.SetScrollParentId(aLayerMetrics.GetScrollParentId());
|
||||
APZC_LOG_FM(aLayerMetrics, "%p got a NotifyLayersUpdated with aIsFirstPaint=%d", this, aIsFirstPaint);
|
||||
|
||||
LogRendertraceRect(GetGuid(), "page", "brown", aLayerMetrics.mScrollableRect);
|
||||
|
@ -896,12 +896,8 @@ private:
|
||||
* including handing off scroll to another APZC, and overscrolling.
|
||||
*/
|
||||
public:
|
||||
void SetScrollHandoffParentId(FrameMetrics::ViewID aScrollParentId) {
|
||||
mScrollParentId = aScrollParentId;
|
||||
}
|
||||
|
||||
FrameMetrics::ViewID GetScrollHandoffParentId() const {
|
||||
return mScrollParentId;
|
||||
return mFrameMetrics.GetScrollParentId();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -935,8 +931,6 @@ public:
|
||||
bool SnapBackIfOverscrolled();
|
||||
|
||||
private:
|
||||
FrameMetrics::ViewID mScrollParentId;
|
||||
|
||||
/**
|
||||
* A helper function for calling APZCTreeManager::DispatchScroll().
|
||||
* Guards against the case where the APZC is being concurrently destroyed
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "gfxPrefs.h"
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
#include "AndroidBridge.h"
|
||||
#include "LayerMetricsWrapper.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
@ -641,30 +642,26 @@ ClientLayerManager::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
|
||||
bool aDrawingCritical)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
Layer* primaryScrollable = GetPrimaryScrollableLayer();
|
||||
if (primaryScrollable) {
|
||||
const FrameMetrics& metrics = primaryScrollable->GetFrameMetrics();
|
||||
|
||||
// This is derived from the code in
|
||||
// gfx/layers/ipc/CompositorParent.cpp::TransformShadowTree.
|
||||
CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel();
|
||||
const CSSRect& metricsDisplayPort =
|
||||
(aDrawingCritical && !metrics.mCriticalDisplayPort.IsEmpty()) ?
|
||||
metrics.mCriticalDisplayPort : metrics.mDisplayPort;
|
||||
LayerRect displayPort = (metricsDisplayPort + metrics.GetScrollOffset()) * paintScale;
|
||||
|
||||
ScreenPoint scrollOffset;
|
||||
CSSToScreenScale zoom;
|
||||
bool ret = AndroidBridge::Bridge()->ProgressiveUpdateCallback(
|
||||
aHasPendingNewThebesContent, displayPort, paintScale.scale, aDrawingCritical,
|
||||
scrollOffset, zoom);
|
||||
aMetrics.SetScrollOffset(scrollOffset / zoom);
|
||||
aMetrics.SetZoom(zoom);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
MOZ_ASSERT(aMetrics.IsScrollable());
|
||||
// This is derived from the code in
|
||||
// gfx/layers/ipc/CompositorParent.cpp::TransformShadowTree.
|
||||
CSSToLayerScale paintScale = aMetrics.LayersPixelsPerCSSPixel();
|
||||
const CSSRect& metricsDisplayPort =
|
||||
(aDrawingCritical && !aMetrics.mCriticalDisplayPort.IsEmpty()) ?
|
||||
aMetrics.mCriticalDisplayPort : aMetrics.mDisplayPort;
|
||||
LayerRect displayPort = (metricsDisplayPort + aMetrics.GetScrollOffset()) * paintScale;
|
||||
|
||||
ScreenPoint scrollOffset;
|
||||
CSSToScreenScale zoom;
|
||||
bool ret = AndroidBridge::Bridge()->ProgressiveUpdateCallback(
|
||||
aHasPendingNewThebesContent, displayPort, paintScale.scale, aDrawingCritical,
|
||||
scrollOffset, zoom);
|
||||
aMetrics.SetScrollOffset(scrollOffset / zoom);
|
||||
aMetrics.SetZoom(zoom);
|
||||
return ret;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
ClientLayer::~ClientLayer()
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/gfx/Rect.h" // for Rect, RectTyped
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
||||
#include "mozilla/layers/LayersMessages.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
@ -63,28 +64,30 @@ ApplyParentLayerToLayerTransform(const gfx::Matrix4x4& aTransform, const ParentL
|
||||
}
|
||||
|
||||
static gfx::Matrix4x4
|
||||
GetTransformToAncestorsParentLayer(Layer* aStart, Layer* aAncestor)
|
||||
GetTransformToAncestorsParentLayer(Layer* aStart, const LayerMetricsWrapper& aAncestor)
|
||||
{
|
||||
gfx::Matrix4x4 transform;
|
||||
Layer* ancestorParent = aAncestor->GetParent();
|
||||
for (Layer* iter = aStart; iter != ancestorParent; iter = iter->GetParent()) {
|
||||
transform = transform * iter->GetTransform();
|
||||
const LayerMetricsWrapper& ancestorParent = aAncestor.GetParent();
|
||||
for (LayerMetricsWrapper iter(aStart, LayerMetricsWrapper::StartAt::BOTTOM);
|
||||
ancestorParent ? iter != ancestorParent : iter.IsValid();
|
||||
iter = iter.GetParent()) {
|
||||
transform = transform * iter.GetTransform();
|
||||
// If the layer has a non-transient async transform then we need to apply it here
|
||||
// because it will get applied by the APZ in the compositor as well
|
||||
const FrameMetrics& metrics = iter->GetFrameMetrics();
|
||||
const FrameMetrics& metrics = iter.Metrics();
|
||||
transform = transform * gfx::Matrix4x4().Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1.f);
|
||||
}
|
||||
return transform;
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledThebesLayer::GetAncestorLayers(Layer** aOutScrollAncestor,
|
||||
Layer** aOutDisplayPortAncestor)
|
||||
ClientTiledThebesLayer::GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncestor,
|
||||
LayerMetricsWrapper* aOutDisplayPortAncestor)
|
||||
{
|
||||
Layer* scrollAncestor = nullptr;
|
||||
Layer* displayPortAncestor = nullptr;
|
||||
for (Layer* ancestor = this; ancestor; ancestor = ancestor->GetParent()) {
|
||||
const FrameMetrics& metrics = ancestor->GetFrameMetrics();
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
LayerMetricsWrapper displayPortAncestor;
|
||||
for (LayerMetricsWrapper ancestor(this, LayerMetricsWrapper::StartAt::BOTTOM); ancestor; ancestor = ancestor.GetParent()) {
|
||||
const FrameMetrics& metrics = ancestor.Metrics();
|
||||
if (!scrollAncestor && metrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID) {
|
||||
scrollAncestor = ancestor;
|
||||
}
|
||||
@ -120,8 +123,8 @@ ClientTiledThebesLayer::BeginPaint()
|
||||
|
||||
// Get the metrics of the nearest scrollable layer and the nearest layer
|
||||
// with a displayport.
|
||||
Layer* scrollAncestor = nullptr;
|
||||
Layer* displayPortAncestor = nullptr;
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
LayerMetricsWrapper displayPortAncestor;
|
||||
GetAncestorLayers(&scrollAncestor, &displayPortAncestor);
|
||||
|
||||
if (!displayPortAncestor || !scrollAncestor) {
|
||||
@ -135,10 +138,10 @@ ClientTiledThebesLayer::BeginPaint()
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Found scrollAncestor %p and displayPortAncestor %p\n", this,
|
||||
scrollAncestor, displayPortAncestor);
|
||||
scrollAncestor.GetLayer(), displayPortAncestor.GetLayer());
|
||||
|
||||
const FrameMetrics& scrollMetrics = scrollAncestor->GetFrameMetrics();
|
||||
const FrameMetrics& displayportMetrics = displayPortAncestor->GetFrameMetrics();
|
||||
const FrameMetrics& scrollMetrics = scrollAncestor.Metrics();
|
||||
const FrameMetrics& displayportMetrics = displayPortAncestor.Metrics();
|
||||
|
||||
// Calculate the transform required to convert ParentLayer space of our
|
||||
// display port ancestor to the Layer space of this layer.
|
||||
@ -183,7 +186,13 @@ ClientTiledThebesLayer::BeginPaint()
|
||||
bool
|
||||
ClientTiledThebesLayer::UseFastPath()
|
||||
{
|
||||
const FrameMetrics& parentMetrics = GetParent()->GetFrameMetrics();
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
GetAncestorLayers(&scrollAncestor, nullptr);
|
||||
if (!scrollAncestor) {
|
||||
return true;
|
||||
}
|
||||
const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
|
||||
|
||||
bool multipleTransactionsNeeded = gfxPrefs::UseProgressiveTilePainting()
|
||||
|| gfxPrefs::UseLowPrecisionBuffer()
|
||||
|| !parentMetrics.mCriticalDisplayPort.IsEmpty();
|
||||
|
@ -77,8 +77,8 @@ public:
|
||||
* scroll and have a displayport. The parameters are out-params
|
||||
* which hold the return values; the values passed in may be null.
|
||||
*/
|
||||
void GetAncestorLayers(Layer** aOutScrollAncestor,
|
||||
Layer** aOutDisplayPortAncestor);
|
||||
void GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncestor,
|
||||
LayerMetricsWrapper* aOutDisplayPortAncestor);
|
||||
|
||||
private:
|
||||
ClientLayerManager* ClientManager()
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "mozilla/gfx/Rect.h" // for Rect
|
||||
#include "mozilla/gfx/Tools.h" // for BytesPerPixel
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h"
|
||||
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
|
||||
#include "TextureClientPool.h"
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
@ -159,7 +160,7 @@ ComputeViewTransform(const FrameMetrics& aContentMetrics, const FrameMetrics& aC
|
||||
|
||||
bool
|
||||
SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
|
||||
Layer* aLayer,
|
||||
const LayerMetricsWrapper& aLayer,
|
||||
bool aHasPendingNewThebesContent,
|
||||
bool aLowPrecision,
|
||||
ViewTransform& aViewTransform)
|
||||
@ -167,16 +168,16 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
|
||||
MOZ_ASSERT(aLayer);
|
||||
|
||||
CompositorChild* compositor = nullptr;
|
||||
if (aLayer->Manager() &&
|
||||
aLayer->Manager()->AsClientLayerManager()) {
|
||||
compositor = aLayer->Manager()->AsClientLayerManager()->GetCompositorChild();
|
||||
if (aLayer.Manager() &&
|
||||
aLayer.Manager()->AsClientLayerManager()) {
|
||||
compositor = aLayer.Manager()->AsClientLayerManager()->GetCompositorChild();
|
||||
}
|
||||
|
||||
if (!compositor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const FrameMetrics& contentMetrics = aLayer->GetFrameMetrics();
|
||||
const FrameMetrics& contentMetrics = aLayer.Metrics();
|
||||
FrameMetrics compositorMetrics;
|
||||
|
||||
if (!compositor->LookupCompositorFrameMetrics(contentMetrics.GetScrollId(),
|
||||
@ -1361,13 +1362,13 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
||||
* for the compositor state.
|
||||
*/
|
||||
static LayerRect
|
||||
GetCompositorSideCompositionBounds(Layer* aScrollAncestor,
|
||||
GetCompositorSideCompositionBounds(const LayerMetricsWrapper& aScrollAncestor,
|
||||
const Matrix4x4& aTransformToCompBounds,
|
||||
const ViewTransform& aAPZTransform)
|
||||
{
|
||||
Matrix4x4 nonTransientAPZUntransform = Matrix4x4().Scale(
|
||||
aScrollAncestor->GetFrameMetrics().mResolution.scale,
|
||||
aScrollAncestor->GetFrameMetrics().mResolution.scale,
|
||||
aScrollAncestor.Metrics().mResolution.scale,
|
||||
aScrollAncestor.Metrics().mResolution.scale,
|
||||
1.f);
|
||||
nonTransientAPZUntransform.Invert();
|
||||
|
||||
@ -1381,7 +1382,7 @@ GetCompositorSideCompositionBounds(Layer* aScrollAncestor,
|
||||
transform.Invert();
|
||||
|
||||
return TransformTo<LayerPixel>(transform,
|
||||
aScrollAncestor->GetFrameMetrics().mCompositionBounds);
|
||||
aScrollAncestor.Metrics().mCompositionBounds);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1412,7 +1413,7 @@ ClientTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInval
|
||||
|
||||
TILING_LOG("TILING %p: Progressive update stale region %s\n", mThebesLayer, Stringify(staleRegion).c_str());
|
||||
|
||||
Layer* scrollAncestor = nullptr;
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
mThebesLayer->GetAncestorLayers(&scrollAncestor, nullptr);
|
||||
|
||||
// Find out the current view transform to determine which tiles to draw
|
||||
@ -1420,16 +1421,18 @@ ClientTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInval
|
||||
// caused by there being an incoming, more relevant paint.
|
||||
ViewTransform viewTransform;
|
||||
#if defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_ANDROID_APZ)
|
||||
FrameMetrics compositorMetrics = scrollAncestor->GetFrameMetrics();
|
||||
FrameMetrics contentMetrics = scrollAncestor.Metrics();
|
||||
bool abortPaint = false;
|
||||
// On Android, only the primary scrollable layer is async-scrolled, and the only one
|
||||
// that the Java-side code can provide details about. If we're tiling some other layer
|
||||
// then we already have all the information we need about it.
|
||||
if (scrollAncestor == mManager->GetPrimaryScrollableLayer()) {
|
||||
if (contentMetrics.GetScrollId() == mManager->GetRootScrollableLayerId()) {
|
||||
FrameMetrics compositorMetrics = contentMetrics;
|
||||
// The ProgressiveUpdateCallback updates the compositorMetrics
|
||||
abortPaint = mManager->ProgressiveUpdateCallback(!staleRegion.Contains(aInvalidRegion),
|
||||
compositorMetrics,
|
||||
!drawingLowPrecision);
|
||||
viewTransform = ComputeViewTransform(scrollAncestor->GetFrameMetrics(), compositorMetrics);
|
||||
viewTransform = ComputeViewTransform(contentMetrics, compositorMetrics);
|
||||
}
|
||||
#else
|
||||
MOZ_ASSERT(mSharedFrameMetricsHelper);
|
||||
|
@ -354,7 +354,7 @@ public:
|
||||
* is useful for slow-to-render pages when the display-port starts lagging
|
||||
* behind enough that continuing to draw it is wasted effort.
|
||||
*/
|
||||
bool UpdateFromCompositorFrameMetrics(Layer* aLayer,
|
||||
bool UpdateFromCompositorFrameMetrics(const LayerMetricsWrapper& aLayer,
|
||||
bool aHasPendingNewThebesContent,
|
||||
bool aLowPrecision,
|
||||
ViewTransform& aViewTransform);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor
|
||||
#include "mozilla/layers/AsyncPanZoomController.h"
|
||||
#include "mozilla/layers/Compositor.h" // for Compositor
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
||||
#include "nsCSSPropList.h"
|
||||
#include "nsCoord.h" // for NSAppUnitsToFloatPixels, etc
|
||||
#include "nsDebug.h" // for NS_ASSERTION, etc
|
||||
@ -242,6 +243,7 @@ IntervalOverlap(gfxFloat aTranslation, gfxFloat aMin, gfxFloat aMax)
|
||||
void
|
||||
AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
||||
Layer* aTransformedSubtreeRoot,
|
||||
FrameMetrics::ViewID aTransformScrollId,
|
||||
const Matrix4x4& aPreviousTransformForRoot,
|
||||
const Matrix4x4& aCurrentTransformForRoot,
|
||||
const LayerMargin& aFixedLayerMargins)
|
||||
@ -249,110 +251,107 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
||||
bool isRootFixed = aLayer->GetIsFixedPosition() &&
|
||||
!aLayer->GetParent()->GetIsFixedPosition();
|
||||
bool isStickyForSubtree = aLayer->GetIsStickyPosition() &&
|
||||
aLayer->GetStickyScrollContainerId() ==
|
||||
aTransformedSubtreeRoot->GetFrameMetrics().GetScrollId();
|
||||
if (aLayer != aTransformedSubtreeRoot && (isRootFixed || isStickyForSubtree)) {
|
||||
// Insert a translation so that the position of the anchor point is the same
|
||||
// before and after the change to the transform of aTransformedSubtreeRoot.
|
||||
// This currently only works for fixed layers with 2D transforms.
|
||||
aLayer->GetStickyScrollContainerId() == aTransformScrollId;
|
||||
bool isFixedOrSticky = (isRootFixed || isStickyForSubtree);
|
||||
|
||||
// Accumulate the transforms between this layer and the subtree root layer.
|
||||
Matrix ancestorTransform;
|
||||
if (!AccumulateLayerTransforms2D(aLayer->GetParent(), aTransformedSubtreeRoot,
|
||||
ancestorTransform)) {
|
||||
return;
|
||||
// We want to process all the fixed and sticky children of
|
||||
// aTransformedSubtreeRoot. Also, once we do encounter such a child, we don't
|
||||
// need to recurse any deeper because the fixed layers are relative to their
|
||||
// nearest scrollable layer.
|
||||
if (aLayer == aTransformedSubtreeRoot || !isFixedOrSticky) {
|
||||
// ApplyAsyncContentTransformToTree will call this function again for
|
||||
// nested scrollable layers, so we don't need to recurse if the layer is
|
||||
// scrollable.
|
||||
if (aLayer == aTransformedSubtreeRoot || !aLayer->HasScrollableFrameMetrics()) {
|
||||
for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) {
|
||||
AlignFixedAndStickyLayers(child, aTransformedSubtreeRoot, aTransformScrollId,
|
||||
aPreviousTransformForRoot,
|
||||
aCurrentTransformForRoot, aFixedLayerMargins);
|
||||
}
|
||||
}
|
||||
|
||||
Matrix oldRootTransform;
|
||||
Matrix newRootTransform;
|
||||
if (!aPreviousTransformForRoot.Is2D(&oldRootTransform) ||
|
||||
!aCurrentTransformForRoot.Is2D(&newRootTransform)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the cumulative transforms between the subtree root with the
|
||||
// old transform and the current transform.
|
||||
Matrix oldCumulativeTransform = ancestorTransform * oldRootTransform;
|
||||
Matrix newCumulativeTransform = ancestorTransform * newRootTransform;
|
||||
if (newCumulativeTransform.IsSingular()) {
|
||||
return;
|
||||
}
|
||||
Matrix newCumulativeTransformInverse = newCumulativeTransform;
|
||||
newCumulativeTransformInverse.Invert();
|
||||
|
||||
// Now work out the translation necessary to make sure the layer doesn't
|
||||
// move given the new sub-tree root transform.
|
||||
Matrix layerTransform;
|
||||
if (!GetBaseTransform2D(aLayer, &layerTransform)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate any offset necessary, in previous transform sub-tree root
|
||||
// space. This is used to make sure fixed position content respects
|
||||
// content document fixed position margins.
|
||||
LayerPoint offsetInOldSubtreeLayerSpace = GetLayerFixedMarginsOffset(aLayer, aFixedLayerMargins);
|
||||
|
||||
// Add the above offset to the anchor point so we can offset the layer by
|
||||
// and amount that's specified in old subtree layer space.
|
||||
const LayerPoint& anchorInOldSubtreeLayerSpace = aLayer->GetFixedPositionAnchor();
|
||||
LayerPoint offsetAnchorInOldSubtreeLayerSpace = anchorInOldSubtreeLayerSpace + offsetInOldSubtreeLayerSpace;
|
||||
|
||||
// Add the local layer transform to the two points to make the equation
|
||||
// below this section more convenient.
|
||||
Point anchor(anchorInOldSubtreeLayerSpace.x, anchorInOldSubtreeLayerSpace.y);
|
||||
Point offsetAnchor(offsetAnchorInOldSubtreeLayerSpace.x, offsetAnchorInOldSubtreeLayerSpace.y);
|
||||
Point locallyTransformedAnchor = layerTransform * anchor;
|
||||
Point locallyTransformedOffsetAnchor = layerTransform * offsetAnchor;
|
||||
|
||||
// Transforming the locallyTransformedAnchor by oldCumulativeTransform
|
||||
// returns the layer's anchor point relative to the parent of
|
||||
// aTransformedSubtreeRoot, before the new transform was applied.
|
||||
// Then, applying newCumulativeTransformInverse maps that point relative
|
||||
// to the layer's parent, which is the same coordinate space as
|
||||
// locallyTransformedAnchor again, allowing us to subtract them and find
|
||||
// out the offset necessary to make sure the layer stays stationary.
|
||||
Point oldAnchorPositionInNewSpace =
|
||||
newCumulativeTransformInverse * (oldCumulativeTransform * locallyTransformedOffsetAnchor);
|
||||
Point translation = oldAnchorPositionInNewSpace - locallyTransformedAnchor;
|
||||
|
||||
if (aLayer->GetIsStickyPosition()) {
|
||||
// For sticky positioned layers, the difference between the two rectangles
|
||||
// defines a pair of translation intervals in each dimension through which
|
||||
// the layer should not move relative to the scroll container. To
|
||||
// accomplish this, we limit each dimension of the |translation| to that
|
||||
// part of it which overlaps those intervals.
|
||||
const LayerRect& stickyOuter = aLayer->GetStickyScrollRangeOuter();
|
||||
const LayerRect& stickyInner = aLayer->GetStickyScrollRangeInner();
|
||||
|
||||
translation.y = IntervalOverlap(translation.y, stickyOuter.y, stickyOuter.YMost()) -
|
||||
IntervalOverlap(translation.y, stickyInner.y, stickyInner.YMost());
|
||||
translation.x = IntervalOverlap(translation.x, stickyOuter.x, stickyOuter.XMost()) -
|
||||
IntervalOverlap(translation.x, stickyInner.x, stickyInner.XMost());
|
||||
}
|
||||
|
||||
// Finally, apply the 2D translation to the layer transform.
|
||||
TranslateShadowLayer2D(aLayer, ThebesPoint(translation));
|
||||
|
||||
// The transform has now been applied, so there's no need to iterate over
|
||||
// child layers.
|
||||
return;
|
||||
}
|
||||
|
||||
// Fixed layers are relative to their nearest scrollable layer, so when we
|
||||
// encounter a scrollable layer, bail. ApplyAsyncContentTransformToTree will
|
||||
// have already recursed on this layer and called AlignFixedAndStickyLayers
|
||||
// on it with its own transforms.
|
||||
if (aLayer->GetFrameMetrics().IsScrollable() &&
|
||||
aLayer != aTransformedSubtreeRoot) {
|
||||
// Insert a translation so that the position of the anchor point is the same
|
||||
// before and after the change to the transform of aTransformedSubtreeRoot.
|
||||
// This currently only works for fixed layers with 2D transforms.
|
||||
|
||||
// Accumulate the transforms between this layer and the subtree root layer.
|
||||
Matrix ancestorTransform;
|
||||
if (!AccumulateLayerTransforms2D(aLayer->GetParent(), aTransformedSubtreeRoot,
|
||||
ancestorTransform)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Layer* child = aLayer->GetFirstChild();
|
||||
child; child = child->GetNextSibling()) {
|
||||
AlignFixedAndStickyLayers(child, aTransformedSubtreeRoot,
|
||||
aPreviousTransformForRoot,
|
||||
aCurrentTransformForRoot, aFixedLayerMargins);
|
||||
Matrix oldRootTransform;
|
||||
Matrix newRootTransform;
|
||||
if (!aPreviousTransformForRoot.Is2D(&oldRootTransform) ||
|
||||
!aCurrentTransformForRoot.Is2D(&newRootTransform)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the cumulative transforms between the subtree root with the
|
||||
// old transform and the current transform.
|
||||
Matrix oldCumulativeTransform = ancestorTransform * oldRootTransform;
|
||||
Matrix newCumulativeTransform = ancestorTransform * newRootTransform;
|
||||
if (newCumulativeTransform.IsSingular()) {
|
||||
return;
|
||||
}
|
||||
Matrix newCumulativeTransformInverse = newCumulativeTransform;
|
||||
newCumulativeTransformInverse.Invert();
|
||||
|
||||
// Now work out the translation necessary to make sure the layer doesn't
|
||||
// move given the new sub-tree root transform.
|
||||
Matrix layerTransform;
|
||||
if (!GetBaseTransform2D(aLayer, &layerTransform)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate any offset necessary, in previous transform sub-tree root
|
||||
// space. This is used to make sure fixed position content respects
|
||||
// content document fixed position margins.
|
||||
LayerPoint offsetInOldSubtreeLayerSpace = GetLayerFixedMarginsOffset(aLayer, aFixedLayerMargins);
|
||||
|
||||
// Add the above offset to the anchor point so we can offset the layer by
|
||||
// and amount that's specified in old subtree layer space.
|
||||
const LayerPoint& anchorInOldSubtreeLayerSpace = aLayer->GetFixedPositionAnchor();
|
||||
LayerPoint offsetAnchorInOldSubtreeLayerSpace = anchorInOldSubtreeLayerSpace + offsetInOldSubtreeLayerSpace;
|
||||
|
||||
// Add the local layer transform to the two points to make the equation
|
||||
// below this section more convenient.
|
||||
Point anchor(anchorInOldSubtreeLayerSpace.x, anchorInOldSubtreeLayerSpace.y);
|
||||
Point offsetAnchor(offsetAnchorInOldSubtreeLayerSpace.x, offsetAnchorInOldSubtreeLayerSpace.y);
|
||||
Point locallyTransformedAnchor = layerTransform * anchor;
|
||||
Point locallyTransformedOffsetAnchor = layerTransform * offsetAnchor;
|
||||
|
||||
// Transforming the locallyTransformedAnchor by oldCumulativeTransform
|
||||
// returns the layer's anchor point relative to the parent of
|
||||
// aTransformedSubtreeRoot, before the new transform was applied.
|
||||
// Then, applying newCumulativeTransformInverse maps that point relative
|
||||
// to the layer's parent, which is the same coordinate space as
|
||||
// locallyTransformedAnchor again, allowing us to subtract them and find
|
||||
// out the offset necessary to make sure the layer stays stationary.
|
||||
Point oldAnchorPositionInNewSpace =
|
||||
newCumulativeTransformInverse * (oldCumulativeTransform * locallyTransformedOffsetAnchor);
|
||||
Point translation = oldAnchorPositionInNewSpace - locallyTransformedAnchor;
|
||||
|
||||
if (aLayer->GetIsStickyPosition()) {
|
||||
// For sticky positioned layers, the difference between the two rectangles
|
||||
// defines a pair of translation intervals in each dimension through which
|
||||
// the layer should not move relative to the scroll container. To
|
||||
// accomplish this, we limit each dimension of the |translation| to that
|
||||
// part of it which overlaps those intervals.
|
||||
const LayerRect& stickyOuter = aLayer->GetStickyScrollRangeOuter();
|
||||
const LayerRect& stickyInner = aLayer->GetStickyScrollRangeInner();
|
||||
|
||||
translation.y = IntervalOverlap(translation.y, stickyOuter.y, stickyOuter.YMost()) -
|
||||
IntervalOverlap(translation.y, stickyInner.y, stickyInner.YMost());
|
||||
translation.x = IntervalOverlap(translation.x, stickyOuter.x, stickyOuter.XMost()) -
|
||||
IntervalOverlap(translation.x, stickyInner.x, stickyInner.XMost());
|
||||
}
|
||||
|
||||
// Finally, apply the 2D translation to the layer transform.
|
||||
TranslateShadowLayer2D(aLayer, ThebesPoint(translation));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -506,15 +505,15 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint)
|
||||
}
|
||||
|
||||
static bool
|
||||
SampleAPZAnimations(Layer* aLayer, TimeStamp aPoint)
|
||||
SampleAPZAnimations(const LayerMetricsWrapper& aLayer, TimeStamp aPoint)
|
||||
{
|
||||
bool activeAnimations = false;
|
||||
for (Layer* child = aLayer->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
for (LayerMetricsWrapper child = aLayer.GetFirstChild(); child;
|
||||
child = child.GetNextSibling()) {
|
||||
activeAnimations |= SampleAPZAnimations(child, aPoint);
|
||||
}
|
||||
|
||||
if (AsyncPanZoomController* apzc = aLayer->GetAsyncPanZoomController()) {
|
||||
if (AsyncPanZoomController* apzc = aLayer.GetApzc()) {
|
||||
activeAnimations |= apzc->AdvanceAnimations(aPoint);
|
||||
}
|
||||
|
||||
@ -553,9 +552,21 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
|
||||
ApplyAsyncContentTransformToTree(child);
|
||||
}
|
||||
|
||||
if (AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController()) {
|
||||
LayerComposite* layerComposite = aLayer->AsLayerComposite();
|
||||
Matrix4x4 oldTransform = aLayer->GetTransform();
|
||||
LayerComposite* layerComposite = aLayer->AsLayerComposite();
|
||||
Matrix4x4 oldTransform = aLayer->GetTransform();
|
||||
|
||||
Matrix4x4 combinedAsyncTransformWithoutOverscroll;
|
||||
Matrix4x4 combinedAsyncTransform;
|
||||
bool hasAsyncTransform = false;
|
||||
LayerMargin fixedLayerMargins(0, 0, 0, 0);
|
||||
|
||||
for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
|
||||
AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(i);
|
||||
if (!controller) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hasAsyncTransform = true;
|
||||
|
||||
ViewTransform asyncTransformWithoutOverscroll, overscrollTransform;
|
||||
ScreenPoint scrollOffset;
|
||||
@ -563,12 +574,13 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
|
||||
scrollOffset,
|
||||
&overscrollTransform);
|
||||
|
||||
const FrameMetrics& metrics = aLayer->GetFrameMetrics();
|
||||
const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
|
||||
CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel();
|
||||
CSSRect displayPort(metrics.mCriticalDisplayPort.IsEmpty() ?
|
||||
metrics.mDisplayPort : metrics.mCriticalDisplayPort);
|
||||
LayerMargin fixedLayerMargins(0, 0, 0, 0);
|
||||
ScreenPoint offset(0, 0);
|
||||
// XXX this call to SyncFrameMetrics is not currently being used. It will be cleaned
|
||||
// up as part of bug 776030 or one of its dependencies.
|
||||
SyncFrameMetrics(scrollOffset, asyncTransformWithoutOverscroll.mScale.scale,
|
||||
metrics.mScrollableRect, mLayersUpdated, displayPort,
|
||||
paintScale, mIsFirstPaint, fixedLayerMargins, offset);
|
||||
@ -579,8 +591,12 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
|
||||
// Apply the render offset
|
||||
mLayerManager->GetCompositor()->SetScreenRenderOffset(offset);
|
||||
|
||||
Matrix4x4 transform = AdjustAndCombineWithCSSTransform(
|
||||
asyncTransformWithoutOverscroll * overscrollTransform, aLayer);
|
||||
combinedAsyncTransformWithoutOverscroll *= asyncTransformWithoutOverscroll;
|
||||
combinedAsyncTransform *= (asyncTransformWithoutOverscroll * overscrollTransform);
|
||||
}
|
||||
|
||||
if (hasAsyncTransform) {
|
||||
Matrix4x4 transform = AdjustAndCombineWithCSSTransform(combinedAsyncTransform, aLayer);
|
||||
|
||||
// GetTransform already takes the pre- and post-scale into account. Since we
|
||||
// will apply the pre- and post-scale again when computing the effective
|
||||
@ -597,9 +613,14 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
|
||||
NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
|
||||
"overwriting animated transform!");
|
||||
|
||||
const FrameMetrics& bottom = LayerMetricsWrapper::BottommostScrollableMetrics(aLayer);
|
||||
MOZ_ASSERT(bottom.IsScrollable()); // must be true because hasAsyncTransform is true
|
||||
|
||||
// Apply resolution scaling to the old transform - the layer tree as it is
|
||||
// doesn't have the necessary transform to display correctly.
|
||||
LayoutDeviceToLayerScale resolution = metrics.mCumulativeResolution;
|
||||
// doesn't have the necessary transform to display correctly. We use the
|
||||
// bottom-most scrollable metrics because that should have the most accurate
|
||||
// cumulative resolution for aLayer.
|
||||
LayoutDeviceToLayerScale resolution = bottom.mCumulativeResolution;
|
||||
oldTransform.Scale(resolution.scale, resolution.scale, 1);
|
||||
|
||||
// For the purpose of aligning fixed and sticky layers, we disregard
|
||||
@ -607,41 +628,29 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
|
||||
// parameter. This ensures that the overscroll transform is not unapplied,
|
||||
// and therefore that the visual effect applies to fixed and sticky layers.
|
||||
Matrix4x4 transformWithoutOverscroll = AdjustAndCombineWithCSSTransform(
|
||||
asyncTransformWithoutOverscroll, aLayer);
|
||||
AlignFixedAndStickyLayers(aLayer, aLayer, oldTransform,
|
||||
combinedAsyncTransformWithoutOverscroll, aLayer);
|
||||
// Since fixed/sticky layers are relative to their nearest scrolling ancestor,
|
||||
// we use the ViewID from the bottommost scrollable metrics here.
|
||||
AlignFixedAndStickyLayers(aLayer, aLayer, bottom.GetScrollId(), oldTransform,
|
||||
transformWithoutOverscroll, fixedLayerMargins);
|
||||
|
||||
appliedTransform = true;
|
||||
}
|
||||
|
||||
if (aLayer->AsContainerLayer() && aLayer->GetScrollbarDirection() != Layer::NONE) {
|
||||
ApplyAsyncTransformToScrollbar(aLayer->AsContainerLayer());
|
||||
if (aLayer->GetScrollbarDirection() != Layer::NONE) {
|
||||
ApplyAsyncTransformToScrollbar(aLayer);
|
||||
}
|
||||
return appliedTransform;
|
||||
}
|
||||
|
||||
static bool
|
||||
LayerHasNonContainerDescendants(ContainerLayer* aContainer)
|
||||
LayerIsScrollbarTarget(const LayerMetricsWrapper& aTarget, Layer* aScrollbar)
|
||||
{
|
||||
for (Layer* child = aContainer->GetFirstChild();
|
||||
child; child = child->GetNextSibling()) {
|
||||
ContainerLayer* container = child->AsContainerLayer();
|
||||
if (!container || LayerHasNonContainerDescendants(container)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
LayerIsScrollbarTarget(Layer* aTarget, ContainerLayer* aScrollbar)
|
||||
{
|
||||
AsyncPanZoomController* apzc = aTarget->GetAsyncPanZoomController();
|
||||
AsyncPanZoomController* apzc = aTarget.GetApzc();
|
||||
if (!apzc) {
|
||||
return false;
|
||||
}
|
||||
const FrameMetrics& metrics = aTarget->GetFrameMetrics();
|
||||
const FrameMetrics& metrics = aTarget.Metrics();
|
||||
if (metrics.GetScrollId() != aScrollbar->GetScrollbarTargetContainerId()) {
|
||||
return false;
|
||||
}
|
||||
@ -649,21 +658,21 @@ LayerIsScrollbarTarget(Layer* aTarget, ContainerLayer* aScrollbar)
|
||||
}
|
||||
|
||||
static void
|
||||
ApplyAsyncTransformToScrollbarForContent(ContainerLayer* aScrollbar,
|
||||
Layer* aContent, bool aScrollbarIsChild)
|
||||
ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
|
||||
const LayerMetricsWrapper& aContent,
|
||||
bool aScrollbarIsDescendant)
|
||||
{
|
||||
// We only apply the transform if the scroll-target layer has non-container
|
||||
// children (i.e. when it has some possibly-visible content). This is to
|
||||
// avoid moving scroll-bars in the situation that only a scroll information
|
||||
// layer has been built for a scroll frame, as this would result in a
|
||||
// disparity between scrollbars and visible content.
|
||||
if (aContent->AsContainerLayer() &&
|
||||
!LayerHasNonContainerDescendants(aContent->AsContainerLayer())) {
|
||||
if (aContent.IsScrollInfoLayer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const FrameMetrics& metrics = aContent->GetFrameMetrics();
|
||||
AsyncPanZoomController* apzc = aContent->GetAsyncPanZoomController();
|
||||
const FrameMetrics& metrics = aContent.Metrics();
|
||||
AsyncPanZoomController* apzc = aContent.GetApzc();
|
||||
|
||||
Matrix4x4 asyncTransform = apzc->GetCurrentAsyncTransform();
|
||||
Matrix4x4 nontransientTransform = apzc->GetNontransientAsyncTransform();
|
||||
@ -698,7 +707,7 @@ ApplyAsyncTransformToScrollbarForContent(ContainerLayer* aScrollbar,
|
||||
|
||||
Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
|
||||
|
||||
if (aScrollbarIsChild) {
|
||||
if (aScrollbarIsDescendant) {
|
||||
// If the scrollbar layer is a child of the content it is a scrollbar for, then we
|
||||
// need to do an extra untransform to cancel out the transient async transform on
|
||||
// the content. This is needed because otherwise that transient async transform is
|
||||
@ -711,47 +720,50 @@ ApplyAsyncTransformToScrollbarForContent(ContainerLayer* aScrollbar,
|
||||
// GetTransform already takes the pre- and post-scale into account. Since we
|
||||
// will apply the pre- and post-scale again when computing the effective
|
||||
// transform, we must apply the inverses here.
|
||||
transform.Scale(1.0f/aScrollbar->GetPreXScale(),
|
||||
1.0f/aScrollbar->GetPreYScale(),
|
||||
1);
|
||||
if (ContainerLayer* container = aScrollbar->AsContainerLayer()) {
|
||||
transform.Scale(1.0f/container->GetPreXScale(),
|
||||
1.0f/container->GetPreYScale(),
|
||||
1);
|
||||
}
|
||||
transform = transform * Matrix4x4().Scale(1.0f/aScrollbar->GetPostXScale(),
|
||||
1.0f/aScrollbar->GetPostYScale(),
|
||||
1);
|
||||
aScrollbar->AsLayerComposite()->SetShadowTransform(transform);
|
||||
}
|
||||
|
||||
static Layer*
|
||||
FindScrolledLayerForScrollbar(ContainerLayer* aLayer, bool* aOutIsAncestor)
|
||||
static LayerMetricsWrapper
|
||||
FindScrolledLayerForScrollbar(Layer* aScrollbar, bool* aOutIsAncestor)
|
||||
{
|
||||
// XXX: once bug 967844 is implemented there might be multiple scrolled layers
|
||||
// that correspond to the scrollbar's scrollId. Verify that we deal with those
|
||||
// cases correctly.
|
||||
|
||||
// Search all siblings of aLayer and of its ancestors.
|
||||
for (Layer* ancestor = aLayer; ancestor; ancestor = ancestor->GetParent()) {
|
||||
for (Layer* scrollTarget = ancestor;
|
||||
// Search all siblings of aScrollbar and of its ancestors.
|
||||
LayerMetricsWrapper scrollbar(aScrollbar, LayerMetricsWrapper::StartAt::BOTTOM);
|
||||
for (LayerMetricsWrapper ancestor = scrollbar; ancestor; ancestor = ancestor.GetParent()) {
|
||||
for (LayerMetricsWrapper scrollTarget = ancestor;
|
||||
scrollTarget;
|
||||
scrollTarget = scrollTarget->GetPrevSibling()) {
|
||||
if (scrollTarget != aLayer &&
|
||||
LayerIsScrollbarTarget(scrollTarget, aLayer)) {
|
||||
scrollTarget = scrollTarget.GetPrevSibling()) {
|
||||
if (scrollTarget != scrollbar &&
|
||||
LayerIsScrollbarTarget(scrollTarget, aScrollbar)) {
|
||||
*aOutIsAncestor = (scrollTarget == ancestor);
|
||||
return scrollTarget;
|
||||
}
|
||||
}
|
||||
for (Layer* scrollTarget = ancestor->GetNextSibling();
|
||||
for (LayerMetricsWrapper scrollTarget = ancestor.GetNextSibling();
|
||||
scrollTarget;
|
||||
scrollTarget = scrollTarget->GetNextSibling()) {
|
||||
if (LayerIsScrollbarTarget(scrollTarget, aLayer)) {
|
||||
scrollTarget = scrollTarget.GetNextSibling()) {
|
||||
if (LayerIsScrollbarTarget(scrollTarget, aScrollbar)) {
|
||||
*aOutIsAncestor = false;
|
||||
return scrollTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return LayerMetricsWrapper();
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCompositionManager::ApplyAsyncTransformToScrollbar(ContainerLayer* aLayer)
|
||||
AsyncCompositionManager::ApplyAsyncTransformToScrollbar(Layer* aLayer)
|
||||
{
|
||||
// If this layer corresponds to a scrollbar, then there should be a layer that
|
||||
// is a previous sibling or a parent that has a matching ViewID on its FrameMetrics.
|
||||
@ -761,7 +773,7 @@ AsyncCompositionManager::ApplyAsyncTransformToScrollbar(ContainerLayer* aLayer)
|
||||
// this case we don't need to do anything because there can't be an async
|
||||
// transform on the content.
|
||||
bool isAncestor = false;
|
||||
Layer* scrollTarget = FindScrolledLayerForScrollbar(aLayer, &isAncestor);
|
||||
const LayerMetricsWrapper& scrollTarget = FindScrolledLayerForScrollbar(aLayer, &isAncestor);
|
||||
if (scrollTarget) {
|
||||
ApplyAsyncTransformToScrollbarForContent(aLayer, scrollTarget, isAncestor);
|
||||
}
|
||||
@ -772,7 +784,15 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
|
||||
{
|
||||
LayerComposite* layerComposite = aLayer->AsLayerComposite();
|
||||
|
||||
const FrameMetrics& metrics = aLayer->GetFrameMetrics();
|
||||
FrameMetrics metrics = LayerMetricsWrapper::TopmostScrollableMetrics(aLayer);
|
||||
if (!metrics.IsScrollable()) {
|
||||
// On Fennec it's possible that the there is no scrollable layer in the
|
||||
// tree, and this function just gets called with the root layer. In that
|
||||
// case TopmostScrollableMetrics will return an empty FrameMetrics but we
|
||||
// still want to use the actual non-scrollable metrics from the layer.
|
||||
metrics = LayerMetricsWrapper::BottommostMetrics(aLayer);
|
||||
}
|
||||
|
||||
// We must apply the resolution scale before a pan/zoom transform, so we call
|
||||
// GetTransform here.
|
||||
Matrix4x4 oldTransform = aLayer->GetTransform();
|
||||
@ -892,7 +912,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
|
||||
|
||||
// Make sure fixed position layers don't move away from their anchor points
|
||||
// when we're asynchronously panning or zooming
|
||||
AlignFixedAndStickyLayers(aLayer, aLayer, oldTransform,
|
||||
AlignFixedAndStickyLayers(aLayer, aLayer, metrics.GetScrollId(), oldTransform,
|
||||
aLayer->GetLocalTransform(), fixedLayerMargins);
|
||||
}
|
||||
|
||||
@ -940,11 +960,11 @@ AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame)
|
||||
// code also includes Fennec which is rendered async. Fennec uses
|
||||
// its own platform-specific async rendering that is done partially
|
||||
// in Gecko and partially in Java.
|
||||
wantNextFrame |= SampleAPZAnimations(root, aCurrentFrame);
|
||||
wantNextFrame |= SampleAPZAnimations(LayerMetricsWrapper(root), aCurrentFrame);
|
||||
if (!ApplyAsyncContentTransformToTree(root)) {
|
||||
nsAutoTArray<Layer*,1> scrollableLayers;
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
scrollableLayers.AppendElement(mLayerManager->GetPrimaryScrollableLayer());
|
||||
mLayerManager->GetRootScrollableLayers(scrollableLayers);
|
||||
#else
|
||||
mLayerManager->GetScrollableLayers(scrollableLayers);
|
||||
#endif
|
||||
|
@ -130,7 +130,7 @@ private:
|
||||
* Update the shadow transform for aLayer assuming that is a scrollbar,
|
||||
* so that it stays in sync with the content that is being scrolled by APZ.
|
||||
*/
|
||||
void ApplyAsyncTransformToScrollbar(ContainerLayer* aLayer);
|
||||
void ApplyAsyncTransformToScrollbar(Layer* aLayer);
|
||||
|
||||
void SetFirstPaintViewport(const LayerIntPoint& aOffset,
|
||||
const CSSToLayerScale& aZoom,
|
||||
@ -169,6 +169,7 @@ private:
|
||||
* zooming.
|
||||
*/
|
||||
void AlignFixedAndStickyLayers(Layer* aLayer, Layer* aTransformedSubtreeRoot,
|
||||
FrameMetrics::ViewID aTransformScrollId,
|
||||
const gfx::Matrix4x4& aPreviousTransformForRoot,
|
||||
const gfx::Matrix4x4& aCurrentTransformForRoot,
|
||||
const LayerMargin& aFixedLayerMargins);
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "mozilla/layers/TextureHost.h" // for CompositingRenderTarget
|
||||
#include "mozilla/layers/AsyncPanZoomController.h" // for AsyncPanZoomController
|
||||
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
@ -120,21 +121,13 @@ static void PrintUniformityInfo(Layer* aLayer)
|
||||
return;
|
||||
}
|
||||
|
||||
FrameMetrics frameMetrics = aLayer->GetFrameMetrics();
|
||||
if (!frameMetrics.IsScrollable()) {
|
||||
Matrix4x4 transform = aLayer->AsLayerComposite()->GetShadowTransform();
|
||||
if (!transform.Is2D()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncPanZoomController* apzc = aLayer->GetAsyncPanZoomController();
|
||||
if (apzc) {
|
||||
ViewTransform asyncTransform, overscrollTransform;
|
||||
ScreenPoint scrollOffset;
|
||||
apzc->SampleContentTransformForFrame(&asyncTransform,
|
||||
scrollOffset,
|
||||
&overscrollTransform);
|
||||
printf_stderr("UniformityInfo Layer_Move %llu %p %f, %f\n",
|
||||
TimeStamp::Now(), aLayer, scrollOffset.x.value, scrollOffset.y.value);
|
||||
}
|
||||
Point translation = transform.As2D().GetTranslation();
|
||||
printf_stderr("UniformityInfo Layer_Move %llu %p %f, %f\n",
|
||||
TimeStamp::Now(), aLayer, translation.x.value, translation.y.value);
|
||||
}
|
||||
|
||||
/* all of the per-layer prepared data we need to maintain */
|
||||
@ -264,10 +257,18 @@ RenderLayers(ContainerT* aContainer,
|
||||
// composited area. If the layer has a background color, fill these areas
|
||||
// with the background color by drawing a rectangle of the background color
|
||||
// over the entire composited area before drawing the container contents.
|
||||
if (AsyncPanZoomController* apzc = aContainer->GetAsyncPanZoomController()) {
|
||||
// Make sure not to do this on a "scrollinfo" layer (one with an empty visible
|
||||
// region) because it's just a placeholder for APZ purposes.
|
||||
if (apzc->IsOverscrolled() && !aContainer->GetVisibleRegion().IsEmpty()) {
|
||||
// Make sure not to do this on a "scrollinfo" layer because it's just a
|
||||
// placeholder for APZ purposes.
|
||||
if (aContainer->HasScrollableFrameMetrics() && !aContainer->IsScrollInfoLayer()) {
|
||||
bool overscrolled = false;
|
||||
for (uint32_t i = 0; i < aContainer->GetFrameMetricsCount(); i++) {
|
||||
AsyncPanZoomController* apzc = aContainer->GetAsyncPanZoomController(i);
|
||||
if (apzc && apzc->IsOverscrolled()) {
|
||||
overscrolled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (overscrolled) {
|
||||
gfxRGBA color = aContainer->GetBackgroundColor();
|
||||
// If the background is completely transparent, there's no point in
|
||||
// drawing anything for it. Hopefully the layers behind, if any, will
|
||||
@ -430,8 +431,11 @@ ContainerRender(ContainerT* aContainer,
|
||||
}
|
||||
aContainer->mPrepared = nullptr;
|
||||
|
||||
if (aContainer->GetFrameMetrics().IsScrollable()) {
|
||||
const FrameMetrics& frame = aContainer->GetFrameMetrics();
|
||||
for (uint32_t i = 0; i < aContainer->GetFrameMetricsCount(); i++) {
|
||||
if (!aContainer->GetFrameMetrics(i).IsScrollable()) {
|
||||
continue;
|
||||
}
|
||||
const FrameMetrics& frame = aContainer->GetFrameMetrics(i);
|
||||
LayerRect layerBounds = frame.mCompositionBounds * ParentLayerToLayerScale(1.0);
|
||||
gfx::Rect rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height);
|
||||
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "mozilla/layers/Compositor.h" // for Compositor
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
||||
#include "mozilla/layers/LayersTypes.h" // for etc
|
||||
#include "ipc/CompositorBench.h" // for CompositorBench
|
||||
#include "ipc/ShadowLayerUtils.h"
|
||||
@ -796,7 +797,13 @@ LayerManagerComposite::ComputeRenderIntegrity()
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
const FrameMetrics& rootMetrics = root->GetFrameMetrics();
|
||||
FrameMetrics rootMetrics = LayerMetricsWrapper::TopmostScrollableMetrics(root);
|
||||
if (!rootMetrics.IsScrollable()) {
|
||||
// The root may not have any scrollable metrics, in which case rootMetrics
|
||||
// will just be an empty FrameMetrics. Instead use the actual metrics from
|
||||
// the root layer.
|
||||
rootMetrics = LayerMetricsWrapper(root).Metrics();
|
||||
}
|
||||
ParentLayerIntRect bounds = RoundedToInt(rootMetrics.mCompositionBounds);
|
||||
nsIntRect screenRect(bounds.x,
|
||||
bounds.y,
|
||||
@ -809,12 +816,14 @@ LayerManagerComposite::ComputeRenderIntegrity()
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// Use the transform on the primary scrollable layer and its FrameMetrics
|
||||
// to find out how much of the viewport the current displayport covers
|
||||
Layer* primaryScrollable = GetPrimaryScrollableLayer();
|
||||
if (primaryScrollable) {
|
||||
nsTArray<Layer*> rootScrollableLayers;
|
||||
GetRootScrollableLayers(rootScrollableLayers);
|
||||
if (rootScrollableLayers.Length() > 0) {
|
||||
// This is derived from the code in
|
||||
// AsyncCompositionManager::TransformScrollableLayer
|
||||
const FrameMetrics& metrics = primaryScrollable->GetFrameMetrics();
|
||||
Matrix4x4 transform = primaryScrollable->GetEffectiveTransform();
|
||||
Layer* rootScrollable = rootScrollableLayers[0];
|
||||
const FrameMetrics& metrics = LayerMetricsWrapper::TopmostScrollableMetrics(rootScrollable);
|
||||
Matrix4x4 transform = rootScrollable->GetEffectiveTransform();
|
||||
transform.ScalePost(metrics.mResolution.scale, metrics.mResolution.scale, 1);
|
||||
|
||||
// Clip the screen rect to the document bounds
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user