зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
1ebb197830
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="f47964c89a9c34d9a2e77afa3608d9ec604c3d20">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8c7865486a1b11076b849bbf8f7fccbaffbfafe7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="462a2ef9e98134255c144e373c7392440e3ee03b"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -134,9 +134,9 @@
|
|||
<project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
|
||||
<project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
|
||||
<project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
|
||||
<project name="kernel/common" path="kernel" revision="b1b623fcc5c8a22f4e9cb30470378496e03c9404"/>
|
||||
<project name="kernel/common" path="kernel" revision="0b4249f88cb8faadfbf80be207af14198dec08e3"/>
|
||||
<project name="platform/system/core" path="system/core" revision="53d584d4a4b4316e4de9ee5f210d662f89b44e7e"/>
|
||||
<project name="u-boot" path="u-boot" revision="64b93dbec64421a05bc7ffdbc03917700d171570"/>
|
||||
<project name="u-boot" path="u-boot" revision="6980cf8f8cf9c1d43ff92b7af13425a5ed531d12"/>
|
||||
<project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="6974f8e771d4d8e910357a6739ab124768891e8f"/>
|
||||
<project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="f56ab768cb9f1ad42fb0809ffec1424b1e693369"/>
|
||||
<project name="vendor/sprd/partner" path="vendor/sprd/partner" revision="8649c7145972251af11b0639997edfecabfc7c2e"/>
|
||||
|
|
|
@ -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="8c7865486a1b11076b849bbf8f7fccbaffbfafe7"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="462a2ef9e98134255c144e373c7392440e3ee03b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eb1795a9002eb142ac58c8d68f8f4ba094af07ca"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8c7865486a1b11076b849bbf8f7fccbaffbfafe7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="462a2ef9e98134255c144e373c7392440e3ee03b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="f47964c89a9c34d9a2e77afa3608d9ec604c3d20">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8c7865486a1b11076b849bbf8f7fccbaffbfafe7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="462a2ef9e98134255c144e373c7392440e3ee03b"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -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="8c7865486a1b11076b849bbf8f7fccbaffbfafe7"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="462a2ef9e98134255c144e373c7392440e3ee03b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eb1795a9002eb142ac58c8d68f8f4ba094af07ca"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="f47964c89a9c34d9a2e77afa3608d9ec604c3d20">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8c7865486a1b11076b849bbf8f7fccbaffbfafe7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="462a2ef9e98134255c144e373c7392440e3ee03b"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8c7865486a1b11076b849bbf8f7fccbaffbfafe7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="462a2ef9e98134255c144e373c7392440e3ee03b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "8c7865486a1b11076b849bbf8f7fccbaffbfafe7",
|
||||
"git_revision": "462a2ef9e98134255c144e373c7392440e3ee03b",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "c97ae9ec825f591d669e8b7128b81493b88dcf3f",
|
||||
"revision": "e6a1cfc70305b3695b694d7e66b03c51f2a45b1f",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8c7865486a1b11076b849bbf8f7fccbaffbfafe7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="462a2ef9e98134255c144e373c7392440e3ee03b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="7f2ee9f4cb926684883fc2a2e407045fd9db2199">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8c7865486a1b11076b849bbf8f7fccbaffbfafe7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="462a2ef9e98134255c144e373c7392440e3ee03b"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -24,6 +24,7 @@ support-files =
|
|||
[browser_perf-details-01.js]
|
||||
[browser_perf-details-02.js]
|
||||
[browser_perf-details-03.js]
|
||||
[browser_perf-details-04.js]
|
||||
[browser_perf-events-calltree.js]
|
||||
[browser_perf-front-basic-profiler-01.js]
|
||||
[browser_perf-front-basic-timeline-01.js]
|
||||
|
|
|
@ -1,30 +1,31 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let MEMORY_PREF = "devtools.performance.ui.enable-memory";
|
||||
|
||||
/**
|
||||
* Tests that the details view hides the memory buttons when `enable-memory` is toggled,
|
||||
* and that it switches to default panel if toggling while a memory panel is selected.
|
||||
*/
|
||||
function spawnTest () {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, DetailsView } = panel.panelWin;
|
||||
let { EVENTS, PerformanceController, OverviewView, DetailsView } = panel.panelWin;
|
||||
let { $, WaterfallView, MemoryCallTreeView, MemoryFlameGraphView } = panel.panelWin;
|
||||
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, false);
|
||||
|
||||
ok(DetailsView.isViewSelected(WaterfallView),
|
||||
"The waterfall view is selected by default in the details view.");
|
||||
|
||||
// The toolbar buttons will always be hidden when a recording isn't available,
|
||||
// so make sure we have one that's finished.
|
||||
yield startRecording(panel);
|
||||
yield stopRecording(panel);
|
||||
|
||||
let flameBtn = $("toolbarbutton[data-view='memory-flamegraph']");
|
||||
let callBtn = $("toolbarbutton[data-view='memory-calltree']");
|
||||
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, false);
|
||||
is(flameBtn.hidden, true, "memory-flamegraph button hidden when enable-memory=false");
|
||||
is(callBtn.hidden, true, "memory-calltree button hidden when enable-memory=false");
|
||||
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
|
||||
is(flameBtn.hidden, false, "memory-flamegraph button shown when enable-memory=true");
|
||||
is(callBtn.hidden, false, "memory-calltree button shown when enable-memory=true");
|
||||
|
||||
|
@ -33,6 +34,17 @@ function spawnTest () {
|
|||
DetailsView.selectView("memory-calltree");
|
||||
yield Promise.all([selected, notified]);
|
||||
|
||||
ok(DetailsView.isViewSelected(MemoryCallTreeView),
|
||||
"The memory call tree view can now be selected.");
|
||||
|
||||
selected = DetailsView.whenViewSelected(MemoryFlameGraphView);
|
||||
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
|
||||
DetailsView.selectView("memory-flamegraph");
|
||||
yield Promise.all([selected, notified]);
|
||||
|
||||
ok(DetailsView.isViewSelected(MemoryFlameGraphView),
|
||||
"The memory flamegraph view can now be selected.");
|
||||
|
||||
selected = DetailsView.whenViewSelected(WaterfallView);
|
||||
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, false);
|
||||
|
@ -43,16 +55,30 @@ function spawnTest () {
|
|||
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
|
||||
selected = DetailsView.whenViewSelected(MemoryCallTreeView);
|
||||
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
|
||||
DetailsView.selectView("memory-calltree");
|
||||
yield Promise.all([selected, notified]);
|
||||
|
||||
ok(DetailsView.isViewSelected(MemoryCallTreeView),
|
||||
"The memory call tree view can be selected again after re-enabling memory.");
|
||||
|
||||
selected = DetailsView.whenViewSelected(MemoryFlameGraphView);
|
||||
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
|
||||
DetailsView.selectView("memory-flamegraph");
|
||||
yield Promise.all([selected, notified]);
|
||||
|
||||
ok(DetailsView.isViewSelected(MemoryFlameGraphView),
|
||||
"The memory flamegraph view can be selected again after re-enabling memory.");
|
||||
|
||||
selected = DetailsView.whenViewSelected(WaterfallView);
|
||||
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, false);
|
||||
yield Promise.all([selected, notified]);
|
||||
|
||||
ok(DetailsView.isViewSelected(WaterfallView),
|
||||
"The waterfall view is now selected when toggling off enable-memory when a memory panel is selected.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the details view hides the toolbar buttons when a recording
|
||||
* doesn't exist or is in progress.
|
||||
*/
|
||||
function spawnTest () {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, $, $$, PerformanceController, RecordingsView, DetailsView } = panel.panelWin;
|
||||
|
||||
let waterfallBtn = $("toolbarbutton[data-view='waterfall']");
|
||||
let jsFlameBtn = $("toolbarbutton[data-view='js-flamegraph']");
|
||||
let jsCallBtn = $("toolbarbutton[data-view='js-calltree']");
|
||||
let memFlameBtn = $("toolbarbutton[data-view='memory-flamegraph']");
|
||||
let memCallBtn = $("toolbarbutton[data-view='memory-calltree']");
|
||||
|
||||
is(waterfallBtn.hidden, true, "waterfall button hidden when tool starts.");
|
||||
is(jsFlameBtn.hidden, true, "js-flamegraph button hidden when tool starts.");
|
||||
is(jsCallBtn.hidden, true, "js-calltree button hidden when tool starts.");
|
||||
is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when tool starts.");
|
||||
is(memCallBtn.hidden, true, "memory-calltree button hidden when tool starts.");
|
||||
|
||||
yield startRecording(panel);
|
||||
|
||||
is(waterfallBtn.hidden, true, "waterfall button hidden when recording starts.");
|
||||
is(jsFlameBtn.hidden, true, "js-flamegraph button hidden when recording starts.");
|
||||
is(jsCallBtn.hidden, true, "js-calltree button hidden when recording starts.");
|
||||
is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when recording starts.");
|
||||
is(memCallBtn.hidden, true, "memory-calltree button hidden when recording starts.");
|
||||
|
||||
yield stopRecording(panel);
|
||||
|
||||
is(waterfallBtn.hidden, false, "waterfall button visible when recording ends.");
|
||||
is(jsFlameBtn.hidden, false, "js-flamegraph button visible when recording ends.");
|
||||
is(jsCallBtn.hidden, false, "js-calltree button visible when recording ends.");
|
||||
is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when recording ends.");
|
||||
is(memCallBtn.hidden, true, "memory-calltree button hidden when recording ends.");
|
||||
|
||||
yield startRecording(panel);
|
||||
|
||||
is(waterfallBtn.hidden, true, "waterfall button hidden when another recording starts.");
|
||||
is(jsFlameBtn.hidden, true, "js-flamegraph button hidden when another recording starts.");
|
||||
is(jsCallBtn.hidden, true, "js-calltree button hidden when another recording starts.");
|
||||
is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when another recording starts.");
|
||||
is(memCallBtn.hidden, true, "memory-calltree button hidden when another recording starts.");
|
||||
|
||||
let select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
|
||||
mousedown(panel.panelWin, $$(".recording-item")[0]);
|
||||
yield select;
|
||||
|
||||
is(RecordingsView.selectedIndex, 0,
|
||||
"The first recording was selected again.");
|
||||
|
||||
is(waterfallBtn.hidden, false, "waterfall button visible when first recording selected.");
|
||||
is(jsFlameBtn.hidden, false, "js-flamegraph button visible when first recording selected.");
|
||||
is(jsCallBtn.hidden, false, "js-calltree button visible when first recording selected.");
|
||||
is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when first recording selected.");
|
||||
is(memCallBtn.hidden, true, "memory-calltree button hidden when first recording selected.");
|
||||
|
||||
select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
|
||||
mousedown(panel.panelWin, $$(".recording-item")[1]);
|
||||
yield select;
|
||||
|
||||
is(RecordingsView.selectedIndex, 1,
|
||||
"The second recording was selected again.");
|
||||
|
||||
is(waterfallBtn.hidden, true, "waterfall button still hidden when second recording selected.");
|
||||
is(jsFlameBtn.hidden, true, "js-flamegraph button still hidden when second recording selected.");
|
||||
is(jsCallBtn.hidden, true, "js-calltree button still hidden when second recording selected.");
|
||||
is(memFlameBtn.hidden, true, "memory-flamegraph button still hidden when second recording selected.");
|
||||
is(memCallBtn.hidden, true, "memory-calltree button still hidden when second recording selected.");
|
||||
|
||||
yield stopRecording(panel);
|
||||
|
||||
is(RecordingsView.selectedIndex, 1,
|
||||
"The second recording is still selected.");
|
||||
|
||||
is(waterfallBtn.hidden, false, "waterfall button visible when second recording finished.");
|
||||
is(jsFlameBtn.hidden, false, "js-flamegraph button visible when second recording finished.");
|
||||
is(jsCallBtn.hidden, false, "js-calltree button visible when second recording finished.");
|
||||
is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when second recording finished.");
|
||||
is(memCallBtn.hidden, true, "memory-calltree button hidden when second recording finished.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
|
@ -8,6 +8,9 @@ function spawnTest () {
|
|||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, DetailsView, MemoryCallTreeView } = panel.panelWin;
|
||||
|
||||
// Enable memory to test.
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
|
||||
yield DetailsView.selectView("memory-calltree");
|
||||
ok(DetailsView.isViewSelected(MemoryCallTreeView), "The call tree is now selected.");
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ function spawnTest () {
|
|||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
|
||||
|
||||
// Enable memory to test.
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
|
||||
yield DetailsView.selectView("memory-flamegraph");
|
||||
ok(DetailsView.isViewSelected(MemoryFlameGraphView), "The flamegraph is now selected.");
|
||||
|
||||
|
|
|
@ -262,6 +262,10 @@ function click (win, button) {
|
|||
EventUtils.sendMouseEvent({ type: "click" }, button, win);
|
||||
}
|
||||
|
||||
function mousedown (win, button) {
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, button, win);
|
||||
}
|
||||
|
||||
function* startRecording(panel) {
|
||||
let win = panel.panelWin;
|
||||
let clicked = panel.panelWin.PerformanceView.once(win.EVENTS.UI_START_RECORDING);
|
||||
|
|
|
@ -29,6 +29,7 @@ let DetailsView = {
|
|||
this.toolbar = $("#performance-toolbar-controls-detail-views");
|
||||
|
||||
this._onViewToggle = this._onViewToggle.bind(this);
|
||||
this._onRecordingStoppedOrSelected = this._onRecordingStoppedOrSelected.bind(this);
|
||||
this.setAvailableViews = this.setAvailableViews.bind(this);
|
||||
|
||||
for (let button of $$("toolbarbutton[data-view]", this.toolbar)) {
|
||||
|
@ -36,8 +37,10 @@ let DetailsView = {
|
|||
}
|
||||
|
||||
yield this.selectView(DEFAULT_DETAILS_SUBVIEW);
|
||||
this.setAvailableViews();
|
||||
yield this.setAvailableViews();
|
||||
|
||||
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStoppedOrSelected);
|
||||
PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
|
||||
PerformanceController.on(EVENTS.PREF_CHANGED, this.setAvailableViews);
|
||||
}),
|
||||
|
||||
|
@ -53,6 +56,8 @@ let DetailsView = {
|
|||
component.initialized && (yield component.view.destroy());
|
||||
}
|
||||
|
||||
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStoppedOrSelected);
|
||||
PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
|
||||
PerformanceController.off(EVENTS.PREF_CHANGED, this.setAvailableViews);
|
||||
}),
|
||||
|
||||
|
@ -61,21 +66,21 @@ let DetailsView = {
|
|||
* buttons that select them and going to default view if currently selected.
|
||||
* Called when a preference changes in `devtools.performance.ui.`.
|
||||
*/
|
||||
setAvailableViews: function () {
|
||||
setAvailableViews: Task.async(function* () {
|
||||
for (let [name, { view, pref }] of Iterator(this.components)) {
|
||||
if (!pref) {
|
||||
continue;
|
||||
}
|
||||
let value = PerformanceController.getPref(pref);
|
||||
$(`toolbarbutton[data-view=${name}]`).hidden = !value;
|
||||
let recording = PerformanceController.getCurrentRecording();
|
||||
|
||||
let isRecorded = recording && !recording.isRecording();
|
||||
let isEnabled = !pref || PerformanceController.getPref(pref);
|
||||
$(`toolbarbutton[data-view=${name}]`).hidden = !isRecorded || !isEnabled;
|
||||
|
||||
// If the view is currently selected and not enabled, go back to the
|
||||
// default view.
|
||||
if (!value && this.isViewSelected(view)) {
|
||||
this.selectView(DEFAULT_DETAILS_SUBVIEW);
|
||||
if (!isEnabled && this.isViewSelected(view)) {
|
||||
yield this.selectView(DEFAULT_DETAILS_SUBVIEW);
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
/**
|
||||
* Select one of the DetailView's subviews to be rendered,
|
||||
|
@ -159,6 +164,13 @@ let DetailsView = {
|
|||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Called when recording stops or is selected.
|
||||
*/
|
||||
_onRecordingStoppedOrSelected: function(_, recording) {
|
||||
this.setAvailableViews();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a view button is clicked.
|
||||
*/
|
||||
|
|
|
@ -397,7 +397,7 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
nsIDOMEvent* aDOMEvent,
|
||||
nsEventStatus* aEventStatus,
|
||||
EventDispatchingCallback* aCallback,
|
||||
nsCOMArray<EventTarget>* aTargets)
|
||||
nsTArray<EventTarget*>* aTargets)
|
||||
{
|
||||
PROFILER_LABEL("EventDispatcher", "Dispatch",
|
||||
js::ProfileEntry::Category::EVENTS);
|
||||
|
@ -476,7 +476,7 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!nsContentUtils::IsSafeToRunScript()) {
|
||||
if (aEvent->message != NS_EVENT_NULL && !nsContentUtils::IsSafeToRunScript()) {
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
if (target->GetContextForEventHandlers(&rv) ||
|
||||
NS_FAILED(rv)) {
|
||||
|
@ -625,7 +625,7 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
aTargets->Clear();
|
||||
aTargets->SetCapacity(chain.Length());
|
||||
for (uint32_t i = 0; i < chain.Length(); ++i) {
|
||||
aTargets->AppendObject(chain[i].CurrentTarget()->GetTargetForDOMEvent());
|
||||
aTargets->AppendElement(chain[i].CurrentTarget()->GetTargetForDOMEvent());
|
||||
}
|
||||
} else {
|
||||
// Event target chain is created. Handle the chain.
|
||||
|
|
|
@ -255,7 +255,7 @@ public:
|
|||
nsIDOMEvent* aDOMEvent = nullptr,
|
||||
nsEventStatus* aEventStatus = nullptr,
|
||||
EventDispatchingCallback* aCallback = nullptr,
|
||||
nsCOMArray<dom::EventTarget>* aTargets = nullptr);
|
||||
nsTArray<dom::EventTarget*>* aTargets = nullptr);
|
||||
|
||||
/**
|
||||
* Dispatches an event.
|
||||
|
|
|
@ -171,11 +171,11 @@ EventListenerService::GetEventTargetChainFor(nsIDOMEventTarget* aEventTarget,
|
|||
*aOutArray = nullptr;
|
||||
NS_ENSURE_ARG(aEventTarget);
|
||||
WidgetEvent event(true, NS_EVENT_NULL);
|
||||
nsCOMArray<EventTarget> targets;
|
||||
nsTArray<EventTarget*> targets;
|
||||
nsresult rv = EventDispatcher::Dispatch(aEventTarget, nullptr, &event,
|
||||
nullptr, nullptr, nullptr, &targets);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
int32_t count = targets.Count();
|
||||
int32_t count = targets.Length();
|
||||
if (count == 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -134,12 +134,51 @@ function defineLazyRegExp(obj, name, pattern) {
|
|||
});
|
||||
}
|
||||
|
||||
function NetworkInterfaceLinks()
|
||||
{
|
||||
this.resetLinks();
|
||||
}
|
||||
NetworkInterfaceLinks.prototype = {
|
||||
linkRoutes: null,
|
||||
gateways: null,
|
||||
interfaceName: null,
|
||||
extraRoutes: null,
|
||||
|
||||
setLinks: function(linkRoutes, gateways, interfaceName) {
|
||||
this.linkRoutes = linkRoutes;
|
||||
this.gateways = gateways;
|
||||
this.interfaceName = interfaceName;
|
||||
},
|
||||
|
||||
resetLinks: function() {
|
||||
this.linkRoutes = [];
|
||||
this.gateways = [];
|
||||
this.interfaceName = "";
|
||||
this.extraRoutes = [];
|
||||
},
|
||||
|
||||
compareGateways: function(gateways) {
|
||||
if (this.gateways.length != gateways.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.gateways.length; i++) {
|
||||
if (this.gateways[i] != gateways[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This component watches for network interfaces changing state and then
|
||||
* adjusts routes etc. accordingly.
|
||||
*/
|
||||
function NetworkManager() {
|
||||
this.networkInterfaces = {};
|
||||
this.networkInterfaceLinks = {};
|
||||
Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false);
|
||||
Services.obs.addObserver(this, TOPIC_MOZSETTINGS_CHANGED, false);
|
||||
|
||||
|
@ -303,6 +342,7 @@ NetworkManager.prototype = {
|
|||
Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
this.networkInterfaces[networkId] = network;
|
||||
this.networkInterfaceLinks[networkId] = new NetworkInterfaceLinks();
|
||||
|
||||
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
|
||||
debug("Force setting " + SETTINGS_DUN_REQUIRED + " to true.");
|
||||
|
@ -320,7 +360,10 @@ NetworkManager.prototype = {
|
|||
for (let i = 0; i < length; i++) {
|
||||
debug('Adding subnet routes: ' + ips.value[i] + '/' + prefixLengths.value[i]);
|
||||
gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_ADD,
|
||||
network.name, ips.value[i], prefixLengths.value[i]);
|
||||
network.name, ips.value[i], prefixLengths.value[i])
|
||||
.catch((aError) => {
|
||||
debug("_addSubnetRoutes error: " + aError);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -346,8 +389,16 @@ NetworkManager.prototype = {
|
|||
gNetworkService.createNetwork(network.name, () => {
|
||||
// Add host route for data calls
|
||||
if (this.isNetworkTypeMobile(network.type)) {
|
||||
gNetworkService.removeHostRoutes(network.name);
|
||||
this.setHostRoutes(network);
|
||||
let currentInterfaceLinks = this.networkInterfaceLinks[networkId];
|
||||
let newLinkRoutes = network.getDnses().concat(network.httpProxyHost);
|
||||
// If gateways have changed, remove all old routes first.
|
||||
this._handleGateways(networkId, network.getGateways())
|
||||
.then(() => this._updateRoutes(currentInterfaceLinks.linkRoutes,
|
||||
newLinkRoutes,
|
||||
network.getGateways(), network.name))
|
||||
.then(() => currentInterfaceLinks.setLinks(newLinkRoutes,
|
||||
network.getGateways(),
|
||||
network.name));
|
||||
}
|
||||
|
||||
// Remove pre-created default route and let setAndConfigureActive()
|
||||
|
@ -386,7 +437,7 @@ NetworkManager.prototype = {
|
|||
case Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED:
|
||||
// Remove host route for data calls
|
||||
if (this.isNetworkTypeMobile(network.type)) {
|
||||
this.removeHostRoutes(network);
|
||||
this._cleanupAllHostRoutes(networkId);
|
||||
}
|
||||
// Remove secondary default route for dun.
|
||||
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
|
||||
|
@ -435,6 +486,13 @@ NetworkManager.prototype = {
|
|||
throw Components.Exception("No network with that type registered.",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
|
||||
// This is for in case a network gets unregistered without being
|
||||
// DISCONNECTED.
|
||||
if (this.isNetworkTypeMobile(network.type)) {
|
||||
this._cleanupAllHostRoutes(networkId);
|
||||
}
|
||||
|
||||
delete this.networkInterfaces[networkId];
|
||||
|
||||
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
|
||||
|
@ -450,6 +508,8 @@ NetworkManager.prototype = {
|
|||
|
||||
networkInterfaces: null,
|
||||
|
||||
networkInterfaceLinks: null,
|
||||
|
||||
_dataDefaultServiceId: null,
|
||||
|
||||
_preferredNetworkType: DEFAULT_PREFERRED_NETWORK_TYPE,
|
||||
|
@ -477,7 +537,24 @@ NetworkManager.prototype = {
|
|||
this.setAndConfigureActive();
|
||||
},
|
||||
|
||||
_updateRoutes: function(doAdd, ipAddresses, networkName, gateways) {
|
||||
_updateRoutes: function(oldLinks, newLinks, gateways, interfaceName) {
|
||||
// Returns items that are in base but not in target.
|
||||
function getDifference(base, target) {
|
||||
return base.filter(function(i) { return target.indexOf(i) < 0; });
|
||||
}
|
||||
|
||||
let addedLinks = getDifference(newLinks, oldLinks);
|
||||
let removedLinks = getDifference(oldLinks, newLinks);
|
||||
|
||||
if (addedLinks.length === 0 && removedLinks.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this._setHostRoutes(false, removedLinks, interfaceName, gateways)
|
||||
.then(this._setHostRoutes(true, addedLinks, interfaceName, gateways));
|
||||
},
|
||||
|
||||
_setHostRoutes: function(doAdd, ipAddresses, networkName, gateways) {
|
||||
let getMaxPrefixLength = (aIp) => {
|
||||
return aIp.match(this.REGEXP_IPV4) ? IPV4_MAX_PREFIX_LENGTH : IPV6_MAX_PREFIX_LENGTH;
|
||||
}
|
||||
|
@ -517,10 +594,20 @@ NetworkManager.prototype = {
|
|||
}
|
||||
|
||||
return this.resolveHostname(network, host)
|
||||
.then((ipAddresses) => this._updateRoutes(true,
|
||||
ipAddresses,
|
||||
network.name,
|
||||
network.getGateways()));
|
||||
.then((ipAddresses) => {
|
||||
let promises = [];
|
||||
let networkId = this.getNetworkId(network);
|
||||
|
||||
ipAddresses.forEach((aIpAddress) => {
|
||||
let promise =
|
||||
this._setHostRoutes(true, [aIpAddress], network.name, network.getGateways())
|
||||
.then(() => this.networkInterfaceLinks[networkId].extraRoutes.push(aIpAddress));
|
||||
|
||||
promises.push(promise);
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
});
|
||||
},
|
||||
|
||||
removeHostRoute: function(network, host) {
|
||||
|
@ -529,10 +616,29 @@ NetworkManager.prototype = {
|
|||
}
|
||||
|
||||
return this.resolveHostname(network, host)
|
||||
.then((ipAddresses) => this._updateRoutes(false,
|
||||
ipAddresses,
|
||||
network.name,
|
||||
network.getGateways()));
|
||||
.then((ipAddresses) => {
|
||||
let promises = [];
|
||||
let networkId = this.getNetworkId(network);
|
||||
|
||||
ipAddresses.forEach((aIpAddress) => {
|
||||
let found = this.networkInterfaceLinks[networkId].extraRoutes.indexOf(aIpAddress);
|
||||
if (found < 0) {
|
||||
return; // continue
|
||||
}
|
||||
|
||||
let promise =
|
||||
this._setHostRoutes(false, [aIpAddress], network.name, network.getGateways())
|
||||
.then(() => {
|
||||
this.networkInterfaceLinks[networkId].extraRoutes.splice(found, 1);
|
||||
}, () => {
|
||||
// We should remove it even if the operation failed.
|
||||
this.networkInterfaceLinks[networkId].extraRoutes.splice(found, 1);
|
||||
});
|
||||
promises.push(promise);
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
});
|
||||
},
|
||||
|
||||
isNetworkTypeSecondaryMobile: function(type) {
|
||||
|
@ -547,16 +653,46 @@ NetworkManager.prototype = {
|
|||
this.isNetworkTypeSecondaryMobile(type));
|
||||
},
|
||||
|
||||
setHostRoutes: function(network) {
|
||||
let hosts = network.getDnses().concat(network.httpProxyHost);
|
||||
_handleGateways: function(networkId, gateways) {
|
||||
let currentNetworkLinks = this.networkInterfaceLinks[networkId];
|
||||
if (currentNetworkLinks.gateways.length == 0 ||
|
||||
currentNetworkLinks.compareGateways(gateways)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this._updateRoutes(true, hosts, network.name, network.getGateways());
|
||||
let currentExtraRoutes = currentNetworkLinks.extraRoutes;
|
||||
return this._cleanupAllHostRoutes(networkId)
|
||||
.then(() => {
|
||||
// If gateways have changed, re-add extra host routes with new gateways.
|
||||
if (currentExtraRoutes.length > 0) {
|
||||
this._setHostRoutes(true,
|
||||
currentExtraRoutes,
|
||||
currentNetworkLinks.interfaceName,
|
||||
gateways)
|
||||
.then(() => {
|
||||
currentNetworkLinks.extraRoutes = currentExtraRoutes;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeHostRoutes: function(network) {
|
||||
let hosts = network.getDnses().concat(network.httpProxyHost);
|
||||
_cleanupAllHostRoutes: function(networkId) {
|
||||
let currentNetworkLinks = this.networkInterfaceLinks[networkId];
|
||||
let hostRoutes = currentNetworkLinks.linkRoutes.concat(
|
||||
currentNetworkLinks.extraRoutes);
|
||||
|
||||
return this._updateRoutes(false, hosts, network.name, network.getGateways());
|
||||
if (hostRoutes.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this._setHostRoutes(false,
|
||||
hostRoutes,
|
||||
currentNetworkLinks.interfaceName,
|
||||
currentNetworkLinks.gateways)
|
||||
.catch((aError) => {
|
||||
debug("Error (" + aError + ") on _cleanupAllHostRoutes, keep proceeding.");
|
||||
})
|
||||
.then(() => currentNetworkLinks.resetLinks());
|
||||
},
|
||||
|
||||
selectGateway: function(gateways, host) {
|
||||
|
|
|
@ -56,6 +56,66 @@ function debug(msg) {
|
|||
dump("-*- NetworkService: " + msg + "\n");
|
||||
}
|
||||
|
||||
function Task(id, params, setupFunction) {
|
||||
this.id = id;
|
||||
this.params = params;
|
||||
this.setupFunction = setupFunction;
|
||||
}
|
||||
|
||||
function NetworkWorkerRequestQueue(networkService) {
|
||||
this.networkService = networkService;
|
||||
this.tasks = [];
|
||||
}
|
||||
NetworkWorkerRequestQueue.prototype = {
|
||||
runQueue: function() {
|
||||
if (this.tasks.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let task = this.tasks[0];
|
||||
if (DEBUG) debug("run task id: " + task.id);
|
||||
|
||||
if (typeof task.setupFunction === 'function') {
|
||||
// If setupFunction returns false, skip sending to Network Worker but call
|
||||
// handleWorkerMessage() directly with task id, as if the response was
|
||||
// returned from Network Worker.
|
||||
if (!task.setupFunction()) {
|
||||
this.networkService.handleWorkerMessage({id: task.id});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gNetworkWorker.postMessage(task.params);
|
||||
},
|
||||
|
||||
enqueue: function(id, params, setupFunction) {
|
||||
if (DEBUG) debug("enqueue id: " + id);
|
||||
this.tasks.push(new Task(id, params, setupFunction));
|
||||
|
||||
if (this.tasks.length === 1) {
|
||||
this.runQueue();
|
||||
}
|
||||
},
|
||||
|
||||
dequeue: function(id) {
|
||||
if (DEBUG) debug("dequeue id: " + id);
|
||||
|
||||
if (!this.tasks.length || this.tasks[0].id != id) {
|
||||
if (DEBUG) debug("Id " + id + " is not on top of the queue");
|
||||
return;
|
||||
}
|
||||
|
||||
this.tasks.shift();
|
||||
if (this.tasks.length > 0) {
|
||||
// Run queue on the next tick.
|
||||
Services.tm.currentThread.dispatch(() => {
|
||||
this.runQueue();
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This component watches for network interfaces changing state and then
|
||||
* adjusts routes etc. accordingly.
|
||||
|
@ -76,6 +136,8 @@ function NetworkService() {
|
|||
// Callbacks to invoke when a reply arrives from the net_worker.
|
||||
this.controlCallbacks = Object.create(null);
|
||||
|
||||
this.addedRoutes = new Map();
|
||||
this.netWorkerRequestQueue = new NetworkWorkerRequestQueue(this);
|
||||
this.shutdown = false;
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
}
|
||||
|
@ -90,17 +152,26 @@ NetworkService.prototype = {
|
|||
|
||||
// Helpers
|
||||
|
||||
addedRoutes: null,
|
||||
idgen: 0,
|
||||
controlMessage: function(params, callback) {
|
||||
controlMessage: function(params, callback, setupFunction) {
|
||||
if (this.shutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
let id = this.idgen++;
|
||||
params.id = id;
|
||||
if (callback) {
|
||||
let id = this.idgen++;
|
||||
params.id = id;
|
||||
this.controlCallbacks[id] = callback;
|
||||
}
|
||||
|
||||
// For now, we use setupFunction to determine if this command needs to be
|
||||
// queued or not.
|
||||
if (setupFunction) {
|
||||
this.netWorkerRequestQueue.enqueue(id, params, setupFunction);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gNetworkWorker) {
|
||||
gNetworkWorker.postMessage(params);
|
||||
}
|
||||
|
@ -118,6 +189,8 @@ NetworkService.prototype = {
|
|||
callback.call(this, response);
|
||||
delete this.controlCallbacks[id];
|
||||
}
|
||||
|
||||
this.netWorkerRequestQueue.dequeue(id);
|
||||
},
|
||||
|
||||
// nsINetworkService
|
||||
|
@ -307,6 +380,10 @@ NetworkService.prototype = {
|
|||
this.controlMessage(options);
|
||||
},
|
||||
|
||||
_routeToString: function(interfaceName, host, prefixLength, gateway) {
|
||||
return host + "-" + prefixLength + "-" + gateway + "-" + interfaceName;
|
||||
},
|
||||
|
||||
modifyRoute: function(action, interfaceName, host, prefixLength, gateway) {
|
||||
let command;
|
||||
|
||||
|
@ -322,8 +399,22 @@ NetworkService.prototype = {
|
|||
return Promise.reject();
|
||||
}
|
||||
|
||||
let route = this._routeToString(interfaceName, host, prefixLength, gateway);
|
||||
let setupFunc = () => {
|
||||
let count = this.addedRoutes.get(route);
|
||||
if (DEBUG) debug(command + ": " + route + " -> " + count);
|
||||
|
||||
// Return false if there is no need to send the command to network worker.
|
||||
if ((action == Ci.nsINetworkService.MODIFY_ROUTE_ADD && count) ||
|
||||
(action == Ci.nsINetworkService.MODIFY_ROUTE_REMOVE &&
|
||||
(!count || count > 1))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (DEBUG) debug(command + " " + host + " on " + interfaceName);
|
||||
let deferred = Promise.defer();
|
||||
let options = {
|
||||
cmd: command,
|
||||
ifname: interfaceName,
|
||||
|
@ -331,23 +422,32 @@ NetworkService.prototype = {
|
|||
prefixLength: prefixLength,
|
||||
ip: host
|
||||
};
|
||||
this.controlMessage(options, function(data) {
|
||||
if (data.error) {
|
||||
deferred.reject(data.reason);
|
||||
return;
|
||||
}
|
||||
deferred.resolve();
|
||||
});
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
removeHostRoutes: function(ifname) {
|
||||
if(DEBUG) debug("Going to remove all host routes on " + ifname);
|
||||
let options = {
|
||||
cmd: "removeHostRoutes",
|
||||
ifname: ifname,
|
||||
};
|
||||
this.controlMessage(options);
|
||||
return new Promise((aResolve, aReject) => {
|
||||
this.controlMessage(options, (data) => {
|
||||
let count = this.addedRoutes.get(route);
|
||||
|
||||
// Remove route from addedRoutes on success or failure.
|
||||
if (action == Ci.nsINetworkService.MODIFY_ROUTE_REMOVE) {
|
||||
if (count > 1) {
|
||||
this.addedRoutes.set(route, count - 1);
|
||||
} else {
|
||||
this.addedRoutes.delete(route);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.error) {
|
||||
aReject(data.reason);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action == Ci.nsINetworkService.MODIFY_ROUTE_ADD) {
|
||||
this.addedRoutes.set(route, count ? count + 1 : 1);
|
||||
}
|
||||
|
||||
aResolve();
|
||||
}, setupFunc);
|
||||
});
|
||||
},
|
||||
|
||||
addSecondaryRoute: function(ifname, route) {
|
||||
|
|
|
@ -1485,7 +1485,6 @@ void NetworkUtils::ExecuteCommand(NetworkParams aOptions)
|
|||
BUILD_ENTRY(removeDefaultRoute),
|
||||
BUILD_ENTRY(addHostRoute),
|
||||
BUILD_ENTRY(removeHostRoute),
|
||||
BUILD_ENTRY(removeHostRoutes),
|
||||
BUILD_ENTRY(addSecondaryRoute),
|
||||
BUILD_ENTRY(removeSecondaryRoute),
|
||||
BUILD_ENTRY(setNetworkInterfaceAlarm),
|
||||
|
@ -1955,6 +1954,11 @@ CommandResult NetworkUtils::addHostRoute(NetworkParams& aOptions)
|
|||
*/
|
||||
CommandResult NetworkUtils::addHostRouteLegacy(NetworkParams& aOptions)
|
||||
{
|
||||
if (aOptions.mGateway.IsEmpty()) {
|
||||
ERROR("addHostRouteLegacy does not support empty gateway.");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
|
||||
NS_ConvertUTF16toUTF8 autoHostname(aOptions.mIp);
|
||||
NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateway);
|
||||
|
@ -2026,27 +2030,6 @@ CommandResult NetworkUtils::removeHostRouteLegacy(NetworkParams& aOptions)
|
|||
prefix, autoGateway.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the routes associated with the named interface.
|
||||
*/
|
||||
CommandResult NetworkUtils::removeHostRoutes(NetworkParams& aOptions)
|
||||
{
|
||||
if (SDK_VERSION < 20) {
|
||||
return removeHostRoutesLegacy(aOptions);
|
||||
}
|
||||
|
||||
NU_DBG("Don't know how to remove host routes on a interface");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the routes associated with the named interface.
|
||||
*/
|
||||
CommandResult NetworkUtils::removeHostRoutesLegacy(NetworkParams& aOptions)
|
||||
{
|
||||
return mNetUtils->do_ifc_remove_host_routes(GET_CHAR(mIfname));
|
||||
}
|
||||
|
||||
CommandResult NetworkUtils::removeNetworkRoute(NetworkParams& aOptions)
|
||||
{
|
||||
if (SDK_VERSION < 20) {
|
||||
|
|
|
@ -291,7 +291,6 @@ private:
|
|||
CommandResult addHostRoute(NetworkParams& aOptions);
|
||||
CommandResult removeDefaultRoute(NetworkParams& aOptions);
|
||||
CommandResult removeHostRoute(NetworkParams& aOptions);
|
||||
CommandResult removeHostRoutes(NetworkParams& aOptions);
|
||||
CommandResult removeNetworkRoute(NetworkParams& aOptions);
|
||||
CommandResult setDNS(NetworkParams& aOptions);
|
||||
CommandResult addSecondaryRoute(NetworkParams& aOptions);
|
||||
|
@ -310,7 +309,6 @@ private:
|
|||
|
||||
CommandResult addHostRouteLegacy(NetworkParams& aOptions);
|
||||
CommandResult removeHostRouteLegacy(NetworkParams& aOptions);
|
||||
CommandResult removeHostRoutesLegacy(NetworkParams& aOptions);
|
||||
CommandResult setDefaultRouteLegacy(NetworkParams& aOptions);
|
||||
CommandResult removeDefaultRouteLegacy(NetworkParams& aOptions);
|
||||
CommandResult removeNetworkRouteLegacy(NetworkParams& aOptions);
|
||||
|
|
|
@ -159,7 +159,7 @@ interface nsIDhcpRequestCallback : nsISupports
|
|||
/**
|
||||
* Provide network services.
|
||||
*/
|
||||
[scriptable, uuid(138ab267-0007-4c3e-8bfc-a7e1be0b5a6f)]
|
||||
[scriptable, uuid(e40dd966-cb04-4dc7-ac4b-6382769c00b9)]
|
||||
interface nsINetworkService : nsISupports
|
||||
{
|
||||
const long MODIFY_ROUTE_ADD = 0;
|
||||
|
@ -345,14 +345,6 @@ interface nsINetworkService : nsISupports
|
|||
in long prefixLength,
|
||||
[optional] in DOMString gateway);
|
||||
|
||||
/**
|
||||
* Remove all host routes.
|
||||
*
|
||||
* @param interfaceName
|
||||
* The interface name we want remove from the routing table.
|
||||
*/
|
||||
void removeHostRoutes(in DOMString interfaceName);
|
||||
|
||||
/**
|
||||
* Add route to secondary routing table.
|
||||
*
|
||||
|
|
|
@ -82,138 +82,6 @@ let RILQUIRKS_DATA_REGISTRATION_ON_DEMAND;
|
|||
// Ril quirk to control the uicc/data subscription.
|
||||
let RILQUIRKS_SUBSCRIPTION_CONTROL;
|
||||
|
||||
function BufObject(aContext) {
|
||||
this.context = aContext;
|
||||
}
|
||||
BufObject.prototype = {
|
||||
context: null,
|
||||
|
||||
mToken: 0,
|
||||
mTokenRequestMap: null,
|
||||
|
||||
init: function() {
|
||||
this._init();
|
||||
|
||||
// This gets incremented each time we send out a parcel.
|
||||
this.mToken = 1;
|
||||
|
||||
// Maps tokens we send out with requests to the request type, so that
|
||||
// when we get a response parcel back, we know what request it was for.
|
||||
this.mTokenRequestMap = new Map();
|
||||
},
|
||||
|
||||
/**
|
||||
* Process one parcel.
|
||||
*/
|
||||
processParcel: function() {
|
||||
let response_type = this.readInt32();
|
||||
|
||||
let request_type, options;
|
||||
if (response_type == RESPONSE_TYPE_SOLICITED) {
|
||||
let token = this.readInt32();
|
||||
let error = this.readInt32();
|
||||
|
||||
options = this.mTokenRequestMap.get(token);
|
||||
if (!options) {
|
||||
if (DEBUG) {
|
||||
this.context.debug("Suspicious uninvited request found: " +
|
||||
token + ". Ignored!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.mTokenRequestMap.delete(token);
|
||||
request_type = options.rilRequestType;
|
||||
|
||||
options.rilRequestError = error;
|
||||
if (DEBUG) {
|
||||
this.context.debug("Solicited response for request type " + request_type +
|
||||
", token " + token + ", error " + error);
|
||||
}
|
||||
} else if (response_type == RESPONSE_TYPE_UNSOLICITED) {
|
||||
request_type = this.readInt32();
|
||||
if (DEBUG) {
|
||||
this.context.debug("Unsolicited response for request type " + request_type);
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
this.context.debug("Unknown response type: " + response_type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.RIL.handleParcel(request_type, this.readAvailable, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Start a new outgoing parcel.
|
||||
*
|
||||
* @param type
|
||||
* Integer specifying the request type.
|
||||
* @param options [optional]
|
||||
* Object containing information about the request, e.g. the
|
||||
* original main thread message object that led to the RIL request.
|
||||
*/
|
||||
newParcel: function(type, options) {
|
||||
if (DEBUG) {
|
||||
this.context.debug("New outgoing parcel of type " + type +
|
||||
", token " + this.mToken);
|
||||
}
|
||||
|
||||
// We're going to leave room for the parcel size at the beginning.
|
||||
this.outgoingIndex = this.PARCEL_SIZE_SIZE;
|
||||
this.writeInt32(this._reMapRequestType(type));
|
||||
this.writeInt32(this.mToken);
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
options.rilRequestType = type;
|
||||
options.rilRequestError = null;
|
||||
this.mTokenRequestMap.set(this.mToken, options);
|
||||
this.mToken++;
|
||||
return this.mToken;
|
||||
},
|
||||
|
||||
simpleRequest: function(type, options) {
|
||||
this.newParcel(type, options);
|
||||
this.sendParcel();
|
||||
},
|
||||
|
||||
onSendParcel: function(parcel) {
|
||||
postRILMessage(this.context.clientId, parcel);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remapping the request type to different values based on RIL version.
|
||||
* We only have to do this for SUBSCRIPTION right now, so I just make it
|
||||
* simple. A generic logic or structure could be discussed if we have more
|
||||
* use cases, especially the cases from different partners.
|
||||
*/
|
||||
_reMapRequestType: function(type) {
|
||||
let newType = type;
|
||||
switch (type) {
|
||||
case REQUEST_SET_UICC_SUBSCRIPTION:
|
||||
case REQUEST_SET_DATA_SUBSCRIPTION:
|
||||
if (this.context.RIL.version < 9) {
|
||||
// Shift the CAF's proprietary parcels. Please see
|
||||
// https://www.codeaurora.org/cgit/quic/la/platform/hardware/ril/tree/include/telephony/ril.h?h=b2g_jb_3.2
|
||||
newType = type - 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return newType;
|
||||
}
|
||||
};
|
||||
|
||||
(function() {
|
||||
let base = require("resource://gre/modules/workers/worker_buf.js").Buf;
|
||||
for (let p in base) {
|
||||
BufObject.prototype[p] = base[p];
|
||||
}
|
||||
})();
|
||||
|
||||
const TELEPHONY_REQUESTS = [
|
||||
REQUEST_GET_CURRENT_CALLS,
|
||||
REQUEST_ANSWER,
|
||||
|
|
|
@ -338,6 +338,15 @@ public:
|
|||
return mLayer->GetClipRect();
|
||||
}
|
||||
|
||||
bool GetForceDispatchToContentRegion() const {
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (mLayer->AsContainerLayer()) {
|
||||
return mLayer->AsContainerLayer()->GetForceDispatchToContentRegion();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -924,7 +924,8 @@ ContainerLayer::ContainerLayer(LayerManager* aManager, void* aImplData)
|
|||
mUseIntermediateSurface(false),
|
||||
mSupportsComponentAlphaChildren(false),
|
||||
mMayHaveReadbackChild(false),
|
||||
mChildrenChanged(false)
|
||||
mChildrenChanged(false),
|
||||
mForceDispatchToContentRegion(false)
|
||||
{
|
||||
mContentFlags = 0; // Clear NO_TEXT, NO_TEXT_OVER_TRANSPARENT
|
||||
}
|
||||
|
@ -1081,6 +1082,7 @@ ContainerLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
|
|||
aAttrs = ContainerLayerAttributes(mPreXScale, mPreYScale,
|
||||
mInheritedXScale, mInheritedYScale,
|
||||
mPresShellResolution, mScaleToResolution,
|
||||
mForceDispatchToContentRegion,
|
||||
reinterpret_cast<uint64_t>(mHMDInfo.get()));
|
||||
}
|
||||
|
||||
|
@ -1748,6 +1750,9 @@ ContainerLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
|||
if (mScaleToResolution) {
|
||||
aStream << nsPrintfCString(" [presShellResolution=%g]", mPresShellResolution).get();
|
||||
}
|
||||
if (mForceDispatchToContentRegion) {
|
||||
aStream << " [force-dtc]";
|
||||
}
|
||||
if (mHMDInfo) {
|
||||
aStream << nsPrintfCString(" [hmd=%p]", mHMDInfo.get()).get();
|
||||
}
|
||||
|
|
|
@ -916,6 +916,10 @@ public:
|
|||
* outside the dispatch-to-content region, we can initiate a gesture without
|
||||
* consulting the content thread. Otherwise we must dispatch the event to
|
||||
* content.
|
||||
* Note that if a layer or any ancestor layer returns true for
|
||||
* GetForceDispatchToContentRegion() then we must treat the dispatch-to-content
|
||||
* region as encompassing the hit region, and therefore must consult the
|
||||
* content thread before initiating a gesture.
|
||||
*/
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
|
@ -1967,6 +1971,20 @@ public:
|
|||
mChildrenChanged = aVal;
|
||||
}
|
||||
|
||||
void SetForceDispatchToContentRegion(bool aVal) {
|
||||
if (mForceDispatchToContentRegion == aVal) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ForceDispatchToContentRegion", this));
|
||||
mForceDispatchToContentRegion = aVal;
|
||||
Mutated();
|
||||
}
|
||||
|
||||
bool GetForceDispatchToContentRegion() const {
|
||||
return mForceDispatchToContentRegion;
|
||||
}
|
||||
|
||||
/**
|
||||
* VR
|
||||
*/
|
||||
|
@ -2023,6 +2041,7 @@ protected:
|
|||
// This is updated by ComputeDifferences. This will be true if we need to invalidate
|
||||
// the intermediate surface.
|
||||
bool mChildrenChanged;
|
||||
bool mForceDispatchToContentRegion;
|
||||
nsRefPtr<gfx::VRHMDInfo> mHMDInfo;
|
||||
};
|
||||
|
||||
|
|
|
@ -320,6 +320,20 @@ APZCTreeManager::RecycleOrCreateNode(TreeBuildingState& aState,
|
|||
return node.forget();
|
||||
}
|
||||
|
||||
static bool
|
||||
ShouldForceDispatchToContent(HitTestingTreeNode* aParent,
|
||||
const LayerMetricsWrapper& aLayer)
|
||||
{
|
||||
// Make it so that if the flag is set on the layer tree, it automatically
|
||||
// propagates to all the nodes in the corresponding subtree rooted at that
|
||||
// layer in the hit-test tree. This saves having to walk up the tree every
|
||||
// we want to see if a hit-test node is affected by this flag.
|
||||
if (aParent && aParent->GetForceDispatchToContent()) {
|
||||
return true;
|
||||
}
|
||||
return aLayer.GetForceDispatchToContentRegion();
|
||||
}
|
||||
|
||||
HitTestingTreeNode*
|
||||
APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
||||
const FrameMetrics& aMetrics,
|
||||
|
@ -344,7 +358,8 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
|||
node = RecycleOrCreateNode(aState, nullptr);
|
||||
AttachNodeToTree(node, aParent, aNextSibling);
|
||||
node->SetHitTestData(GetEventRegions(aLayer), aLayer.GetTransform(),
|
||||
aLayer.GetClipRect() ? Some(nsIntRegion(*aLayer.GetClipRect())) : Nothing());
|
||||
aLayer.GetClipRect() ? Some(nsIntRegion(*aLayer.GetClipRect())) : Nothing(),
|
||||
ShouldForceDispatchToContent(aParent, aLayer));
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -440,7 +455,8 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
|||
MOZ_ASSERT(node->IsPrimaryHolder() && node->GetApzc() && node->GetApzc()->Matches(guid));
|
||||
|
||||
nsIntRegion clipRegion = ComputeClipRegion(state->mController, aLayer);
|
||||
node->SetHitTestData(GetEventRegions(aLayer), aLayer.GetTransform(), Some(clipRegion));
|
||||
node->SetHitTestData(GetEventRegions(aLayer), aLayer.GetTransform(), Some(clipRegion),
|
||||
ShouldForceDispatchToContent(aParent, aLayer));
|
||||
apzc->SetAncestorTransform(aAncestorTransform);
|
||||
|
||||
PrintAPZCInfo(aLayer, apzc);
|
||||
|
@ -494,7 +510,8 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
|||
MOZ_ASSERT(aAncestorTransform == apzc->GetAncestorTransform());
|
||||
|
||||
nsIntRegion clipRegion = ComputeClipRegion(state->mController, aLayer);
|
||||
node->SetHitTestData(GetEventRegions(aLayer), aLayer.GetTransform(), Some(clipRegion));
|
||||
node->SetHitTestData(GetEventRegions(aLayer), aLayer.GetTransform(), Some(clipRegion),
|
||||
ShouldForceDispatchToContent(aParent, aLayer));
|
||||
}
|
||||
|
||||
return node;
|
||||
|
|
|
@ -21,6 +21,7 @@ HitTestingTreeNode::HitTestingTreeNode(AsyncPanZoomController* aApzc,
|
|||
bool aIsPrimaryHolder)
|
||||
: mApzc(aApzc)
|
||||
, mIsPrimaryApzcHolder(aIsPrimaryHolder)
|
||||
, mForceDispatchToContent(false)
|
||||
{
|
||||
if (mIsPrimaryApzcHolder) {
|
||||
MOZ_ASSERT(mApzc);
|
||||
|
@ -155,11 +156,13 @@ HitTestingTreeNode::IsPrimaryHolder() const
|
|||
void
|
||||
HitTestingTreeNode::SetHitTestData(const EventRegions& aRegions,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const Maybe<nsIntRegion>& aClipRegion)
|
||||
const Maybe<nsIntRegion>& aClipRegion,
|
||||
bool aForceDispatchToContent)
|
||||
{
|
||||
mEventRegions = aRegions;
|
||||
mTransform = aTransform;
|
||||
mClipRegion = aClipRegion;
|
||||
mForceDispatchToContent = aForceDispatchToContent;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -210,20 +213,29 @@ HitTestingTreeNode::HitTest(const ParentLayerPoint& aPoint) const
|
|||
if (!mEventRegions.mHitRegion.Contains(point.x, point.y)) {
|
||||
return HitTestResult::HitNothing;
|
||||
}
|
||||
if (mEventRegions.mDispatchToContentHitRegion.Contains(point.x, point.y)) {
|
||||
if (mForceDispatchToContent ||
|
||||
mEventRegions.mDispatchToContentHitRegion.Contains(point.x, point.y))
|
||||
{
|
||||
return HitTestResult::HitDispatchToContentRegion;
|
||||
}
|
||||
return HitTestResult::HitLayer;
|
||||
}
|
||||
|
||||
bool
|
||||
HitTestingTreeNode::GetForceDispatchToContent() const
|
||||
{
|
||||
return mForceDispatchToContent;
|
||||
}
|
||||
|
||||
void
|
||||
HitTestingTreeNode::Dump(const char* aPrefix) const
|
||||
{
|
||||
if (mPrevSibling) {
|
||||
mPrevSibling->Dump(aPrefix);
|
||||
}
|
||||
printf_stderr("%sHitTestingTreeNode (%p) APZC (%p) g=(%s) r=(%s) t=(%s) c=(%s)\n",
|
||||
printf_stderr("%sHitTestingTreeNode (%p) APZC (%p) g=(%s) %sr=(%s) t=(%s) c=(%s)\n",
|
||||
aPrefix, this, mApzc.get(), mApzc ? Stringify(mApzc->GetGuid()).c_str() : "",
|
||||
mForceDispatchToContent ? "fdtc " : "",
|
||||
Stringify(mEventRegions).c_str(), Stringify(mTransform).c_str(),
|
||||
mClipRegion ? Stringify(mClipRegion.ref()).c_str() : "none");
|
||||
if (mLastChild) {
|
||||
|
|
|
@ -81,7 +81,8 @@ public:
|
|||
|
||||
void SetHitTestData(const EventRegions& aRegions,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const Maybe<nsIntRegion>& aClipRegion);
|
||||
const Maybe<nsIntRegion>& aClipRegion,
|
||||
bool aForceDispatchToContent);
|
||||
bool IsOutsideClip(const ParentLayerPoint& aPoint) const;
|
||||
/* Convert aPoint into the LayerPixel space for the layer corresponding to
|
||||
* this node. */
|
||||
|
@ -89,6 +90,8 @@ public:
|
|||
/* Assuming aPoint is inside the clip region for this node, check which of the
|
||||
* event region spaces it falls inside. */
|
||||
HitTestResult HitTest(const ParentLayerPoint& aPoint) const;
|
||||
/* Returns the mForceDispatchToContent flag. */
|
||||
bool GetForceDispatchToContent() const;
|
||||
|
||||
/* Debug helpers */
|
||||
void Dump(const char* aPrefix = "") const;
|
||||
|
@ -122,6 +125,11 @@ private:
|
|||
* because we may use the composition bounds of the layer if the clip is not
|
||||
* present. This value is in L's ParentLayerPixels. */
|
||||
Maybe<nsIntRegion> mClipRegion;
|
||||
|
||||
/* If this flag is set, then events to this node and the entire subtree under
|
||||
* should always be treated as dispatch-to-content.
|
||||
*/
|
||||
bool mForceDispatchToContent;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -386,6 +386,7 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
|
|||
containerLayer->SetInheritedScale(attrs.inheritedXScale(), attrs.inheritedYScale());
|
||||
containerLayer->SetScaleToResolution(attrs.scaleToResolution(),
|
||||
attrs.presShellResolution());
|
||||
containerLayer->SetForceDispatchToContentRegion(attrs.forceDispatchToContentRegion());
|
||||
|
||||
if (attrs.hmdInfo()) {
|
||||
if (!IsSameProcess()) {
|
||||
|
|
|
@ -234,6 +234,7 @@ struct ContainerLayerAttributes {
|
|||
float inheritedYScale;
|
||||
float presShellResolution;
|
||||
bool scaleToResolution;
|
||||
bool forceDispatchToContentRegion;
|
||||
// This is a bare pointer; LayerTransactionParent::RecvUpdate prevents this
|
||||
// from being used when !IsSameProcess(), but we should make this truly
|
||||
// cross process at some point by passing the HMDConfig
|
||||
|
|
|
@ -587,8 +587,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
|||
mIsPaintingToWindow(false),
|
||||
mIsCompositingCheap(false),
|
||||
mContainsPluginItem(false),
|
||||
mAncestorHasTouchEventHandler(false),
|
||||
mAncestorHasScrollEventHandler(false),
|
||||
mAncestorHasApzAwareEventHandler(false),
|
||||
mHaveScrollableDisplayPort(false),
|
||||
mWindowDraggingAllowed(false),
|
||||
mIsBuildingForPopup(nsLayoutUtils::IsPopup(aReferenceFrame))
|
||||
|
@ -1630,6 +1629,9 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
|
|||
1.0f/containerParameters.mYScale);
|
||||
root->SetScaleToResolution(presShell->ScaleToResolution(),
|
||||
containerParameters.mXScale);
|
||||
root->SetForceDispatchToContentRegion(
|
||||
aBuilder->IsBuildingLayerEventRegions() &&
|
||||
nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell));
|
||||
|
||||
if (gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
bool isRoot = presContext->IsRootContentDocument();
|
||||
|
@ -3151,9 +3153,7 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
|
|||
} else {
|
||||
mHitRegion.Or(mHitRegion, borderBox);
|
||||
}
|
||||
if (aBuilder->GetAncestorHasTouchEventHandler() ||
|
||||
aBuilder->GetAncestorHasScrollEventHandler())
|
||||
{
|
||||
if (aBuilder->GetAncestorHasApzAwareEventHandler()) {
|
||||
mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, borderBox);
|
||||
}
|
||||
}
|
||||
|
@ -4064,6 +4064,9 @@ nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder* aBuilder,
|
|||
, mScrollParentId(aBuilder->GetCurrentScrollParentId())
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsDisplaySubDocument);
|
||||
mForceDispatchToContentRegion =
|
||||
aBuilder->IsBuildingLayerEventRegions() &&
|
||||
nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(aFrame->PresContext()->PresShell());
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
|
@ -4085,7 +4088,9 @@ nsDisplaySubDocument::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
params.mInLowPrecisionDisplayPort = true;
|
||||
}
|
||||
|
||||
return nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, params);
|
||||
nsRefPtr<Layer> layer = nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, params);
|
||||
layer->AsContainerLayer()->SetForceDispatchToContentRegion(mForceDispatchToContentRegion);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
UniquePtr<FrameMetrics>
|
||||
|
|
|
@ -345,15 +345,10 @@ public:
|
|||
return CurrentPresShellState()->mInsidePointerEventsNoneDoc;
|
||||
}
|
||||
|
||||
bool GetAncestorHasTouchEventHandler() { return mAncestorHasTouchEventHandler; }
|
||||
void SetAncestorHasTouchEventHandler(bool aValue)
|
||||
bool GetAncestorHasApzAwareEventHandler() { return mAncestorHasApzAwareEventHandler; }
|
||||
void SetAncestorHasApzAwareEventHandler(bool aValue)
|
||||
{
|
||||
mAncestorHasTouchEventHandler = aValue;
|
||||
}
|
||||
bool GetAncestorHasScrollEventHandler() { return mAncestorHasScrollEventHandler; }
|
||||
void SetAncestorHasScrollEventHandler(bool aValue)
|
||||
{
|
||||
mAncestorHasScrollEventHandler = aValue;
|
||||
mAncestorHasApzAwareEventHandler = aValue;
|
||||
}
|
||||
|
||||
bool HaveScrollableDisplayPort() const { return mHaveScrollableDisplayPort; }
|
||||
|
@ -578,8 +573,7 @@ public:
|
|||
mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame),
|
||||
mPrevDirtyRect(aBuilder->mDirtyRect),
|
||||
mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext),
|
||||
mPrevAncestorHasTouchEventHandler(aBuilder->mAncestorHasTouchEventHandler),
|
||||
mPrevAncestorHasScrollEventHandler(aBuilder->mAncestorHasScrollEventHandler)
|
||||
mPrevAncestorHasApzAwareEventHandler(aBuilder->mAncestorHasApzAwareEventHandler)
|
||||
{
|
||||
if (aForChild->IsTransformed()) {
|
||||
aBuilder->mCurrentOffsetToReferenceFrame = nsPoint();
|
||||
|
@ -624,8 +618,7 @@ public:
|
|||
mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset;
|
||||
mBuilder->mDirtyRect = mPrevDirtyRect;
|
||||
mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext;
|
||||
mBuilder->mAncestorHasTouchEventHandler = mPrevAncestorHasTouchEventHandler;
|
||||
mBuilder->mAncestorHasScrollEventHandler = mPrevAncestorHasScrollEventHandler;
|
||||
mBuilder->mAncestorHasApzAwareEventHandler = mPrevAncestorHasApzAwareEventHandler;
|
||||
mBuilder->mCurrentAnimatedGeometryRoot = mPrevAnimatedGeometryRoot;
|
||||
}
|
||||
private:
|
||||
|
@ -637,8 +630,7 @@ public:
|
|||
nsPoint mPrevOffset;
|
||||
nsRect mPrevDirtyRect;
|
||||
bool mPrevIsAtRootOfPseudoStackingContext;
|
||||
bool mPrevAncestorHasTouchEventHandler;
|
||||
bool mPrevAncestorHasScrollEventHandler;
|
||||
bool mPrevAncestorHasApzAwareEventHandler;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -920,8 +912,7 @@ private:
|
|||
bool mIsPaintingToWindow;
|
||||
bool mIsCompositingCheap;
|
||||
bool mContainsPluginItem;
|
||||
bool mAncestorHasTouchEventHandler;
|
||||
bool mAncestorHasScrollEventHandler;
|
||||
bool mAncestorHasApzAwareEventHandler;
|
||||
// True when the first async-scrollable scroll frame for which we build a
|
||||
// display list has a display port. An async-scrollable scroll frame is one
|
||||
// which WantsAsyncScroll().
|
||||
|
@ -3045,6 +3036,7 @@ public:
|
|||
|
||||
protected:
|
||||
ViewID mScrollParentId;
|
||||
bool mForceDispatchToContentRegion;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsFrameList.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsHtml5Atoms.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
|
@ -7851,3 +7852,34 @@ nsLayoutUtils::SetBSizeFromFontMetrics(const nsIFrame* aFrame,
|
|||
aFramePadding.BStart(aFrameWM));
|
||||
aMetrics.BSize(aLineWM) += aFramePadding.BStartEnd(aFrameWM);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsLayoutUtils::HasApzAwareListeners(EventListenerManager* aElm)
|
||||
{
|
||||
if (!aElm) {
|
||||
return false;
|
||||
}
|
||||
return aElm->HasListenersFor(nsGkAtoms::ontouchstart) ||
|
||||
aElm->HasListenersFor(nsGkAtoms::ontouchmove) ||
|
||||
aElm->HasListenersFor(nsGkAtoms::onwheel) ||
|
||||
aElm->HasListenersFor(nsGkAtoms::onDOMMouseScroll) ||
|
||||
aElm->HasListenersFor(nsHtml5Atoms::onmousewheel);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(nsIPresShell* aShell)
|
||||
{
|
||||
if (nsIDocument* doc = aShell->GetDocument()) {
|
||||
WidgetEvent event(true, NS_EVENT_NULL);
|
||||
nsTArray<EventTarget*> targets;
|
||||
nsresult rv = EventDispatcher::Dispatch(doc, nullptr, &event, nullptr,
|
||||
nullptr, nullptr, &targets);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
for (size_t i = 0; i < targets.Length(); i++) {
|
||||
if (HasApzAwareListeners(targets[i]->GetExistingListenerManager())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ struct nsStyleImageOrientation;
|
|||
struct nsOverflowAreas;
|
||||
|
||||
namespace mozilla {
|
||||
class EventListenerManager;
|
||||
class SVGImageContext;
|
||||
struct IntrinsicSize;
|
||||
struct ContainerLayerParameters;
|
||||
|
@ -2555,6 +2556,9 @@ public:
|
|||
mozilla::WritingMode aLineWM,
|
||||
mozilla::WritingMode aFrameWM);
|
||||
|
||||
static bool HasApzAwareListeners(mozilla::EventListenerManager* aElm);
|
||||
static bool HasDocumentLevelListenersForApzAwareEvents(nsIPresShell* aShell);
|
||||
|
||||
private:
|
||||
static uint32_t sFontSizeInflationEmPerLine;
|
||||
static uint32_t sFontSizeInflationMinTwips;
|
||||
|
|
|
@ -1909,18 +1909,8 @@ CheckForApzAwareEventHandlers(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
|
|||
return;
|
||||
}
|
||||
EventListenerManager* elm = nsContentUtils::GetExistingListenerManagerForNode(content);
|
||||
if (!elm) {
|
||||
return;
|
||||
}
|
||||
if (elm->HasListenersFor(nsGkAtoms::ontouchstart) ||
|
||||
elm->HasListenersFor(nsGkAtoms::ontouchmove)) {
|
||||
aBuilder->SetAncestorHasTouchEventHandler(true);
|
||||
}
|
||||
if (elm->HasListenersFor(nsGkAtoms::onwheel) ||
|
||||
elm->HasListenersFor(nsGkAtoms::onDOMMouseScroll) ||
|
||||
elm->HasListenersFor(nsHtml5Atoms::onmousewheel))
|
||||
{
|
||||
aBuilder->SetAncestorHasScrollEventHandler(true);
|
||||
if (nsLayoutUtils::HasApzAwareListeners(elm)) {
|
||||
aBuilder->SetAncestorHasApzAwareEventHandler(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -487,8 +487,7 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
? nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame->GetContent())
|
||||
: aBuilder->GetCurrentScrollParentId());
|
||||
|
||||
aBuilder->SetAncestorHasTouchEventHandler(false);
|
||||
aBuilder->SetAncestorHasScrollEventHandler(false);
|
||||
aBuilder->SetAncestorHasApzAwareEventHandler(false);
|
||||
subdocRootFrame->
|
||||
BuildDisplayListForStackingContext(aBuilder, dirty, &childItems);
|
||||
}
|
||||
|
|
|
@ -615,6 +615,17 @@ RenderFrameParent::TakeFocusForClick()
|
|||
} // namespace layout
|
||||
} // namespace mozilla
|
||||
|
||||
nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame,
|
||||
RenderFrameParent* aRemoteFrame)
|
||||
: nsDisplayItem(aBuilder, aFrame)
|
||||
, mRemoteFrame(aRemoteFrame)
|
||||
{
|
||||
mForceDispatchToContentRegion =
|
||||
aBuilder->IsBuildingLayerEventRegions() &&
|
||||
nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(aFrame->PresContext()->PresShell());
|
||||
}
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
|
@ -624,6 +635,9 @@ nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
nsIntRect visibleRect = GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel);
|
||||
visibleRect += aContainerParameters.mOffset;
|
||||
nsRefPtr<Layer> layer = mRemoteFrame->BuildLayer(aBuilder, mFrame, aManager, visibleRect, this, aContainerParameters);
|
||||
if (layer && layer->AsContainerLayer()) {
|
||||
layer->AsContainerLayer()->SetForceDispatchToContentRegion(mForceDispatchToContentRegion);
|
||||
}
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -166,10 +166,7 @@ class nsDisplayRemote : public nsDisplayItem
|
|||
|
||||
public:
|
||||
nsDisplayRemote(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
RenderFrameParent* aRemoteFrame)
|
||||
: nsDisplayItem(aBuilder, aFrame)
|
||||
, mRemoteFrame(aRemoteFrame)
|
||||
{}
|
||||
RenderFrameParent* aRemoteFrame);
|
||||
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
|
@ -187,6 +184,7 @@ public:
|
|||
|
||||
private:
|
||||
RenderFrameParent* mRemoteFrame;
|
||||
bool mForceDispatchToContentRegion;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1698,7 +1698,7 @@ public class BrowserApp extends GeckoApp
|
|||
Telemetry.addToHistogram("PLACES_BOOKMARKS_COUNT", db.getCount(cr, "bookmarks"));
|
||||
Telemetry.addToHistogram("FENNEC_FAVICONS_COUNT", db.getCount(cr, "favicons"));
|
||||
Telemetry.addToHistogram("FENNEC_THUMBNAILS_COUNT", db.getCount(cr, "thumbnails"));
|
||||
Telemetry.addToHistogram("FENNEC_READING_LIST_COUNT", db.getCount(getContentResolver(), "readinglist"));
|
||||
Telemetry.addToHistogram("FENNEC_READING_LIST_COUNT", db.getReadingListAccessor().getCount(cr));
|
||||
Telemetry.addToHistogram("BROWSER_IS_USER_DEFAULT", (isDefaultBrowser(Intent.ACTION_VIEW) ? 1 : 0));
|
||||
if (Versions.feature16Plus) {
|
||||
Telemetry.addToHistogram("BROWSER_IS_ASSIST_DEFAULT", (isDefaultBrowser(Intent.ACTION_ASSIST) ? 1 : 0));
|
||||
|
|
|
@ -398,11 +398,7 @@ public class BrowserLocaleManager implements LocaleManager {
|
|||
*/
|
||||
public static Collection<String> getPackagedLocaleTags(final Context context) {
|
||||
final String resPath = "res/multilocale.json";
|
||||
final String apkPath = context.getPackageResourcePath();
|
||||
|
||||
final String jarURL = "jar:jar:" + new File(apkPath).toURI() + "!/" +
|
||||
AppConstants.OMNIJAR_NAME + "!/" +
|
||||
resPath;
|
||||
final String jarURL = GeckoJarReader.getJarURL(context, resPath);
|
||||
|
||||
final String contents = GeckoJarReader.getText(jarURL);
|
||||
if (contents == null) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.json.JSONObject;
|
|||
import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.DBUtils;
|
||||
import org.mozilla.gecko.db.ReadingListAccessor;
|
||||
import org.mozilla.gecko.favicons.Favicons;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.NativeEventListener;
|
||||
|
@ -30,18 +31,17 @@ public final class ReadingListHelper implements NativeEventListener {
|
|||
|
||||
protected final Context context;
|
||||
private final BrowserDB db;
|
||||
|
||||
private final Uri readingListUriWithProfile;
|
||||
private final ReadingListAccessor readingListAccessor;
|
||||
private final ContentObserver contentObserver;
|
||||
|
||||
public ReadingListHelper(Context context, GeckoProfile profile) {
|
||||
this.context = context;
|
||||
this.db = profile.getDB();
|
||||
this.readingListAccessor = db.getReadingListAccessor();
|
||||
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener((NativeEventListener) this,
|
||||
"Reader:AddToList", "Reader:UpdateList", "Reader:FaviconRequest", "Reader:ListStatusRequest", "Reader:RemoveFromList");
|
||||
|
||||
readingListUriWithProfile = DBUtils.appendProfile(profile.getName(), ReadingListItems.CONTENT_URI);
|
||||
|
||||
contentObserver = new ContentObserver(null) {
|
||||
@Override
|
||||
|
@ -50,7 +50,7 @@ public final class ReadingListHelper implements NativeEventListener {
|
|||
}
|
||||
};
|
||||
|
||||
context.getContentResolver().registerContentObserver(readingListUriWithProfile, false, contentObserver);
|
||||
this.readingListAccessor.registerContentObserver(context, contentObserver);
|
||||
}
|
||||
|
||||
public void uninit() {
|
||||
|
@ -104,11 +104,11 @@ public final class ReadingListHelper implements NativeEventListener {
|
|||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (db.isReadingListItem(cr, url)) {
|
||||
if (readingListAccessor.isReadingListItem(cr, url)) {
|
||||
showToast(R.string.reading_list_duplicate, Toast.LENGTH_SHORT);
|
||||
callback.sendError("URL already in reading list: " + url);
|
||||
} else {
|
||||
db.addReadingListItem(cr, values);
|
||||
readingListAccessor.addReadingListItem(cr, values);
|
||||
showToast(R.string.reading_list_added, Toast.LENGTH_SHORT);
|
||||
callback.sendSuccess(url);
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ public final class ReadingListHelper implements NativeEventListener {
|
|||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
db.updateReadingListItem(cr, values);
|
||||
readingListAccessor.updateReadingListItem(cr, values);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ public final class ReadingListHelper implements NativeEventListener {
|
|||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
db.removeReadingListItemWithURL(context.getContentResolver(), url);
|
||||
readingListAccessor.removeReadingListItemWithURL(context.getContentResolver(), url);
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:Removed", url));
|
||||
showToast(R.string.page_removed, Toast.LENGTH_SHORT);
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ public final class ReadingListHelper implements NativeEventListener {
|
|||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final int inReadingList = db.isReadingListItem(context.getContentResolver(), url) ? 1 : 0;
|
||||
final int inReadingList = readingListAccessor.isReadingListItem(context.getContentResolver(), url) ? 1 : 0;
|
||||
|
||||
final JSONObject json = new JSONObject();
|
||||
try {
|
||||
|
@ -239,7 +239,7 @@ public final class ReadingListHelper implements NativeEventListener {
|
|||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Cursor c = db.getReadingListUnfetched(context.getContentResolver());
|
||||
final Cursor c = readingListAccessor.getReadingListUnfetched(context.getContentResolver());
|
||||
try {
|
||||
while (c.moveToNext()) {
|
||||
JSONObject json = new JSONObject();
|
||||
|
|
|
@ -16,7 +16,6 @@ import org.mozilla.gecko.favicons.decoders.LoadFaviconResult;
|
|||
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
|
@ -43,6 +42,7 @@ public interface BrowserDB {
|
|||
public abstract Searches getSearches();
|
||||
public abstract TabsAccessor getTabsAccessor();
|
||||
public abstract URLMetadata getURLMetadata();
|
||||
public abstract ReadingListAccessor getReadingListAccessor();
|
||||
|
||||
/**
|
||||
* Add default bookmarks to the database.
|
||||
|
@ -118,17 +118,6 @@ public interface BrowserDB {
|
|||
*/
|
||||
public abstract Cursor getBookmarksInFolder(ContentResolver cr, long folderId);
|
||||
|
||||
/**
|
||||
* Can return <code>null</code>.
|
||||
*/
|
||||
public abstract Cursor getReadingList(ContentResolver cr);
|
||||
public abstract Cursor getReadingListUnfetched(ContentResolver cr);
|
||||
public abstract boolean isReadingListItem(ContentResolver cr, String uri);
|
||||
public abstract void addReadingListItem(ContentResolver cr, ContentValues values);
|
||||
public abstract void updateReadingListItem(ContentResolver cr, ContentValues values);
|
||||
public abstract void removeReadingListItemWithURL(ContentResolver cr, String uri);
|
||||
|
||||
|
||||
/**
|
||||
* Get the favicon from the database, if any, associated with the given favicon URL. (That is,
|
||||
* the URL of the actual favicon image, not the URL of the page with which the favicon is associated.)
|
||||
|
|
|
@ -98,11 +98,11 @@ public class LocalBrowserDB implements BrowserDB {
|
|||
private final Uri mUpdateHistoryUriWithProfile;
|
||||
private final Uri mFaviconsUriWithProfile;
|
||||
private final Uri mThumbnailsUriWithProfile;
|
||||
private final Uri mReadingListUriWithProfile;
|
||||
|
||||
private LocalSearches searches;
|
||||
private LocalTabsAccessor tabsAccessor;
|
||||
private LocalURLMetadata urlMetadata;
|
||||
private LocalReadingListAccessor readingListAccessor;
|
||||
|
||||
private static final String[] DEFAULT_BOOKMARK_COLUMNS =
|
||||
new String[] { Bookmarks._ID,
|
||||
|
@ -123,7 +123,6 @@ public class LocalBrowserDB implements BrowserDB {
|
|||
mCombinedUriWithProfile = DBUtils.appendProfile(profile, Combined.CONTENT_URI);
|
||||
mFaviconsUriWithProfile = DBUtils.appendProfile(profile, Favicons.CONTENT_URI);
|
||||
mThumbnailsUriWithProfile = DBUtils.appendProfile(profile, Thumbnails.CONTENT_URI);
|
||||
mReadingListUriWithProfile = DBUtils.appendProfile(profile, ReadingListItems.CONTENT_URI);
|
||||
|
||||
mUpdateHistoryUriWithProfile =
|
||||
mHistoryUriWithProfile.buildUpon()
|
||||
|
@ -134,6 +133,7 @@ public class LocalBrowserDB implements BrowserDB {
|
|||
searches = new LocalSearches(mProfile);
|
||||
tabsAccessor = new LocalTabsAccessor(mProfile);
|
||||
urlMetadata = new LocalURLMetadata(mProfile);
|
||||
readingListAccessor = new LocalReadingListAccessor(mProfile);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -151,6 +151,11 @@ public class LocalBrowserDB implements BrowserDB {
|
|||
return urlMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadingListAccessor getReadingListAccessor() {
|
||||
return readingListAccessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not thread safe. A helper to allocate new IDs for arbitrary strings.
|
||||
*/
|
||||
|
@ -468,18 +473,13 @@ public class LocalBrowserDB implements BrowserDB {
|
|||
* compatible with the favicon decoder (most probably a PNG or ICO file).
|
||||
*/
|
||||
private static ConsumedInputStream getDefaultFaviconFromPath(Context context, String name) {
|
||||
int faviconId = getFaviconId(name);
|
||||
final int faviconId = getFaviconId(name);
|
||||
if (faviconId == FAVICON_ID_NOT_FOUND) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String path = context.getString(faviconId);
|
||||
|
||||
String apkPath = context.getPackageResourcePath();
|
||||
File apkFile = new File(apkPath);
|
||||
String bitmapPath = "jar:jar:" + apkFile.toURI() + "!/" + AppConstants.OMNIJAR_NAME + "!/" + path;
|
||||
|
||||
InputStream iStream = GeckoJarReader.getStream(bitmapPath);
|
||||
final String bitmapPath = GeckoJarReader.getJarURL(context, context.getString(faviconId));
|
||||
final InputStream iStream = GeckoJarReader.getStream(bitmapPath);
|
||||
|
||||
return IOUtils.readFully(iStream, DEFAULT_FAVICON_BUFFER_SIZE);
|
||||
}
|
||||
|
@ -581,9 +581,6 @@ public class LocalBrowserDB implements BrowserDB {
|
|||
} else if ("favicons".equals(database)) {
|
||||
uri = mFaviconsUriWithProfile;
|
||||
columns = new String[] { Favicons._ID };
|
||||
} else if ("readinglist".equals(database)) {
|
||||
uri = mReadingListUriWithProfile;
|
||||
columns = new String[] { ReadingListItems._ID };
|
||||
}
|
||||
|
||||
if (uri != null) {
|
||||
|
@ -824,26 +821,6 @@ public class LocalBrowserDB implements BrowserDB {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadingListItem(ContentResolver cr, String uri) {
|
||||
final Cursor c = cr.query(mReadingListUriWithProfile,
|
||||
new String[] { ReadingListItems._ID },
|
||||
ReadingListItems.URL + " = ? ",
|
||||
new String[] { uri },
|
||||
null);
|
||||
|
||||
if (c == null) {
|
||||
Log.e(LOGTAG, "Null cursor in isReadingListItem");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return c.getCount() > 0;
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrlForKeyword(ContentResolver cr, String keyword) {
|
||||
final Cursor c = cr.query(mBookmarksUriWithProfile,
|
||||
|
@ -973,70 +950,6 @@ public class LocalBrowserDB implements BrowserDB {
|
|||
cr.delete(contentUri, urlEquals, urlArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor getReadingList(ContentResolver cr) {
|
||||
return cr.query(mReadingListUriWithProfile,
|
||||
ReadingListItems.DEFAULT_PROJECTION,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor getReadingListUnfetched(ContentResolver cr) {
|
||||
return cr.query(mReadingListUriWithProfile,
|
||||
new String[] { ReadingListItems._ID, ReadingListItems.URL },
|
||||
ReadingListItems.CONTENT_STATUS + " = " + ReadingListItems.STATUS_UNFETCHED,
|
||||
null,
|
||||
null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReadingListItem(ContentResolver cr, ContentValues values) {
|
||||
// Check that required fields are present.
|
||||
for (String field: ReadingListItems.REQUIRED_FIELDS) {
|
||||
if (!values.containsKey(field)) {
|
||||
throw new IllegalArgumentException("Missing required field for reading list item: " + field);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear delete flag if necessary
|
||||
values.put(ReadingListItems.IS_DELETED, 0);
|
||||
|
||||
// Restore deleted record if possible
|
||||
final Uri insertUri = mReadingListUriWithProfile
|
||||
.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true")
|
||||
.build();
|
||||
|
||||
final int updated = cr.update(insertUri,
|
||||
values,
|
||||
ReadingListItems.URL + " = ? ",
|
||||
new String[] { values.getAsString(ReadingListItems.URL) });
|
||||
|
||||
debug("Updated " + updated + " rows to new modified time.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateReadingListItem(ContentResolver cr, ContentValues values) {
|
||||
if (!values.containsKey(ReadingListItems._ID)) {
|
||||
throw new IllegalArgumentException("Cannot update reading list item without an ID");
|
||||
}
|
||||
|
||||
final int updated = cr.update(mReadingListUriWithProfile,
|
||||
values,
|
||||
ReadingListItems._ID + " = ? ",
|
||||
new String[] { values.getAsString(ReadingListItems._ID) });
|
||||
|
||||
debug("Updated " + updated + " reading list rows.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeReadingListItemWithURL(ContentResolver cr, String uri) {
|
||||
cr.delete(mReadingListUriWithProfile, ReadingListItems.URL + " = ? ", new String[] { uri });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBookmarkObserver(ContentResolver cr, ContentObserver observer) {
|
||||
cr.registerContentObserver(mBookmarksUriWithProfile, false, observer);
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.db;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
public class LocalReadingListAccessor implements ReadingListAccessor {
|
||||
private static final String LOG_TAG = "GeckoReadingListAcc";
|
||||
|
||||
private final Uri mReadingListUriWithProfile;
|
||||
|
||||
public LocalReadingListAccessor(final String profile) {
|
||||
mReadingListUriWithProfile = DBUtils.appendProfile(profile, BrowserContract.ReadingListItems.CONTENT_URI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount(ContentResolver cr) {
|
||||
final String[] columns = new String[]{BrowserContract.ReadingListItems._ID};
|
||||
final Cursor cursor = cr.query(mReadingListUriWithProfile, columns, null, null, null);
|
||||
int count = 0;
|
||||
|
||||
try {
|
||||
count = cursor.getCount();
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
Log.d(LOG_TAG, "Got count " + count + " for reading list.");
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor getReadingList(ContentResolver cr) {
|
||||
return cr.query(mReadingListUriWithProfile,
|
||||
BrowserContract.ReadingListItems.DEFAULT_PROJECTION,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor getReadingListUnfetched(ContentResolver cr) {
|
||||
return cr.query(mReadingListUriWithProfile,
|
||||
new String[] { BrowserContract.ReadingListItems._ID, BrowserContract.ReadingListItems.URL },
|
||||
BrowserContract.ReadingListItems.CONTENT_STATUS + " = " + BrowserContract.ReadingListItems.STATUS_UNFETCHED,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadingListItem(ContentResolver cr, String uri) {
|
||||
final Cursor c = cr.query(mReadingListUriWithProfile,
|
||||
new String[] { BrowserContract.ReadingListItems._ID },
|
||||
BrowserContract.ReadingListItems.URL + " = ? ",
|
||||
new String[] { uri },
|
||||
null);
|
||||
|
||||
if (c == null) {
|
||||
Log.e(LOG_TAG, "Null cursor in isReadingListItem");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return c.getCount() > 0;
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addReadingListItem(ContentResolver cr, ContentValues values) {
|
||||
// Check that required fields are present.
|
||||
for (String field: BrowserContract.ReadingListItems.REQUIRED_FIELDS) {
|
||||
if (!values.containsKey(field)) {
|
||||
throw new IllegalArgumentException("Missing required field for reading list item: " + field);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear delete flag if necessary
|
||||
values.put(BrowserContract.ReadingListItems.IS_DELETED, 0);
|
||||
|
||||
// Restore deleted record if possible
|
||||
final Uri insertUri = mReadingListUriWithProfile
|
||||
.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true")
|
||||
.build();
|
||||
|
||||
final int updated = cr.update(insertUri,
|
||||
values,
|
||||
BrowserContract.ReadingListItems.URL + " = ? ",
|
||||
new String[] { values.getAsString(BrowserContract.ReadingListItems.URL) });
|
||||
|
||||
Log.d(LOG_TAG, "Updated " + updated + " rows to new modified time.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateReadingListItem(ContentResolver cr, ContentValues values) {
|
||||
if (!values.containsKey(BrowserContract.ReadingListItems._ID)) {
|
||||
throw new IllegalArgumentException("Cannot update reading list item without an ID");
|
||||
}
|
||||
|
||||
final int updated = cr.update(mReadingListUriWithProfile,
|
||||
values,
|
||||
BrowserContract.ReadingListItems._ID + " = ? ",
|
||||
new String[] { values.getAsString(BrowserContract.ReadingListItems._ID) });
|
||||
|
||||
Log.d(LOG_TAG, "Updated " + updated + " reading list rows.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeReadingListItemWithURL(ContentResolver cr, String uri) {
|
||||
cr.delete(mReadingListUriWithProfile, BrowserContract.ReadingListItems.URL + " = ? ", new String[]{uri});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerContentObserver(Context context, ContentObserver observer) {
|
||||
context.getContentResolver().registerContentObserver(mReadingListUriWithProfile, false, observer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.db;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
|
||||
public interface ReadingListAccessor {
|
||||
/**
|
||||
* Can return <code>null</code>.
|
||||
*/
|
||||
Cursor getReadingList(ContentResolver cr);
|
||||
|
||||
int getCount(ContentResolver cr);
|
||||
|
||||
Cursor getReadingListUnfetched(ContentResolver cr);
|
||||
|
||||
boolean isReadingListItem(ContentResolver cr, String uri);
|
||||
|
||||
void addReadingListItem(ContentResolver cr, ContentValues values);
|
||||
|
||||
void updateReadingListItem(ContentResolver cr, ContentValues values);
|
||||
|
||||
void removeReadingListItemWithURL(ContentResolver cr, String uri);
|
||||
|
||||
void registerContentObserver(Context context, ContentObserver observer);
|
||||
}
|
|
@ -26,6 +26,48 @@ import android.database.ContentObserver;
|
|||
import android.database.Cursor;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
|
||||
class StubReadingListAccessor implements ReadingListAccessor {
|
||||
@Override
|
||||
public Cursor getReadingList(ContentResolver cr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount(ContentResolver cr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor getReadingListUnfetched(ContentResolver cr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadingListItem(ContentResolver cr, String uri) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReadingListItem(ContentResolver cr, ContentValues values) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateReadingListItem(ContentResolver cr, ContentValues values) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeReadingListItemWithURL(ContentResolver cr, String uri) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerContentObserver(Context context, ContentObserver observer) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class StubSearches implements Searches {
|
||||
public StubSearches() {
|
||||
}
|
||||
|
@ -91,6 +133,7 @@ public class StubBrowserDB implements BrowserDB {
|
|||
private final StubSearches searches = new StubSearches();
|
||||
private final StubTabsAccessor tabsAccessor = new StubTabsAccessor();
|
||||
private final StubURLMetadata urlMetadata = new StubURLMetadata();
|
||||
private final StubReadingListAccessor readingListAccessor = new StubReadingListAccessor();
|
||||
|
||||
@Override
|
||||
public Searches getSearches() {
|
||||
|
@ -107,6 +150,11 @@ public class StubBrowserDB implements BrowserDB {
|
|||
return urlMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadingListAccessor getReadingListAccessor() {
|
||||
return readingListAccessor;
|
||||
}
|
||||
|
||||
protected static final Integer FAVICON_ID_NOT_FOUND = Integer.MIN_VALUE;
|
||||
|
||||
public StubBrowserDB(String profile) {
|
||||
|
|
|
@ -498,10 +498,7 @@ public class Favicons {
|
|||
* "jar:jar:file:///data/app/org.mozilla.firefox-1.apk!/assets/omni.ja!/chrome/chrome/content/branding/favicon64.png"
|
||||
*/
|
||||
private static String getBrandingBitmapPath(Context context, String name) {
|
||||
final String apkPath = context.getPackageResourcePath();
|
||||
return "jar:jar:" + new File(apkPath).toURI() + "!/" +
|
||||
AppConstants.OMNIJAR_NAME + "!/" +
|
||||
"chrome/chrome/content/branding/" + name;
|
||||
return GeckoJarReader.getJarURL(context, "chrome/chrome/content/branding/" + name);
|
||||
}
|
||||
|
||||
private static Bitmap loadBrandingBitmap(Context context, String name) {
|
||||
|
|
|
@ -363,7 +363,7 @@ public abstract class HomeFragment extends Fragment {
|
|||
break;
|
||||
|
||||
case READING_LIST:
|
||||
mDB.removeReadingListItemWithURL(cr, mUrl);
|
||||
mDB.getReadingListAccessor().removeReadingListItemWithURL(cr, mUrl);
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:Removed", mUrl));
|
||||
break;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.mozilla.gecko.TelemetryContract;
|
|||
import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
|
||||
import org.mozilla.gecko.db.BrowserContract.URLColumns;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.ReadingListAccessor;
|
||||
import org.mozilla.gecko.home.HomeContextMenuInfo.RemoveItemType;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
|
||||
|
@ -164,16 +165,16 @@ public class ReadingListPanel extends HomeFragment {
|
|||
* Cursor loader for the list of reading list items.
|
||||
*/
|
||||
private static class ReadingListLoader extends SimpleCursorLoader {
|
||||
private final BrowserDB mDB;
|
||||
private final ReadingListAccessor accessor;
|
||||
|
||||
public ReadingListLoader(Context context) {
|
||||
super(context);
|
||||
mDB = GeckoProfile.get(context).getDB();
|
||||
accessor = GeckoProfile.get(context).getDB().getReadingListAccessor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor loadCursor() {
|
||||
return mDB.getReadingList(getContext().getContentResolver());
|
||||
return accessor.getReadingList(getContext().getContentResolver());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -159,12 +159,14 @@ gbjar.sources += [
|
|||
'db/FormHistoryProvider.java',
|
||||
'db/HomeProvider.java',
|
||||
'db/LocalBrowserDB.java',
|
||||
'db/LocalReadingListAccessor.java',
|
||||
'db/LocalSearches.java',
|
||||
'db/LocalTabsAccessor.java',
|
||||
'db/LocalURLMetadata.java',
|
||||
'db/PasswordsProvider.java',
|
||||
'db/PerProfileDatabaseProvider.java',
|
||||
'db/PerProfileDatabases.java',
|
||||
'db/ReadingListAccessor.java',
|
||||
'db/ReadingListProvider.java',
|
||||
'db/RemoteClient.java',
|
||||
'db/RemoteTab.java',
|
||||
|
|
|
@ -34,7 +34,7 @@ public class AddToReadingList extends ShareMethod {
|
|||
values.put(Bookmarks.TITLE, shareData.title);
|
||||
values.put(Bookmarks.URL, shareData.url);
|
||||
|
||||
browserDB.addReadingListItem(resolver, values);
|
||||
browserDB.getReadingListAccessor().addReadingListItem(resolver, values);
|
||||
|
||||
return Result.SUCCESS;
|
||||
}
|
||||
|
|
|
@ -261,7 +261,7 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
|
|||
final ContentResolver contentResolver = getApplicationContext().getContentResolver();
|
||||
|
||||
isBookmark = browserDB.isBookmark(contentResolver, pageURL);
|
||||
isReadingListItem = browserDB.isReadingListItem(contentResolver, pageURL);
|
||||
isReadingListItem = browserDB.getReadingListAccessor().isReadingListItem(contentResolver, pageURL);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,13 @@ import org.mozilla.gecko.util.GeckoJarReader;
|
|||
* as loading some invalid jar urls.
|
||||
*/
|
||||
public class testJarReader extends BaseTest {
|
||||
public void testGetJarURL() {
|
||||
// Invalid characters are escaped.
|
||||
final String s = GeckoJarReader.computeJarURI("some[1].apk", "something/else");
|
||||
mAsserter.ok(!s.contains("["), "Illegal characters are escaped away.", null);
|
||||
mAsserter.ok(!s.toLowerCase().contains("%2f"), "Path characters aren't escaped.", null);
|
||||
}
|
||||
|
||||
public void testJarReader() {
|
||||
String appPath = getActivity().getApplication().getPackageResourcePath();
|
||||
mAsserter.isnot(appPath, null, "getPackageResourcePath is non-null");
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
package org.mozilla.gecko.util;
|
||||
|
||||
import android.content.Context;
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.mozglue.NativeZip;
|
||||
|
||||
import android.content.res.Resources;
|
||||
|
@ -13,6 +15,7 @@ import android.util.Log;
|
|||
import org.mozilla.gecko.mozglue.RobocopTarget;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -171,4 +174,23 @@ public final class GeckoJarReader {
|
|||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getJarURL(Context context, String pathInsideJAR) {
|
||||
// We need to encode the package resource path, because it might contain illegal characters. For example:
|
||||
// /mnt/asec2/[2]org.mozilla.fennec-1/pkg.apk
|
||||
// The round-trip through a URI does this for us.
|
||||
final String resourcePath = context.getPackageResourcePath();
|
||||
return computeJarURI(resourcePath, pathInsideJAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes its resource path correctly.
|
||||
*/
|
||||
@RobocopTarget
|
||||
public static String computeJarURI(String resourcePath, String pathInsideJAR) {
|
||||
final String resURI = new File(resourcePath).toURI().toString();
|
||||
|
||||
// TODO: do we need to encode the file path, too?
|
||||
return "jar:jar:" + resURI + "!/" + AppConstants.OMNIJAR_NAME + "!/" + pathInsideJAR;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import android.content.Context;
|
|||
import android.content.SharedPreferences;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
|
@ -16,20 +15,18 @@ import org.mozilla.gecko.GeckoProfile;
|
|||
import org.mozilla.gecko.GeckoSharedPrefs;
|
||||
import org.mozilla.gecko.Locales;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.distribution.Distribution;
|
||||
import org.mozilla.gecko.util.FileUtils;
|
||||
import org.mozilla.gecko.util.GeckoJarReader;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
import org.mozilla.gecko.util.RawResource;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.distribution.Distribution;
|
||||
import org.mozilla.search.Constants;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -37,8 +34,6 @@ import java.io.OutputStream;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class SearchEngineManager implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
@ -532,7 +527,7 @@ public class SearchEngineManager implements SharedPreferences.OnSharedPreference
|
|||
return engine;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, "Error creating earch engine from name: " + name, e);
|
||||
Log.e(LOG_TAG, "Error creating search engine from name: " + name, e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -573,7 +568,7 @@ public class SearchEngineManager implements SharedPreferences.OnSharedPreference
|
|||
|
||||
// First, try a file path for the full locale.
|
||||
final String languageTag = Locales.getLanguageTag(locale);
|
||||
String url = getSearchPluginsJarURL(languageTag, fileName);
|
||||
String url = getSearchPluginsJarURL(context, languageTag, fileName);
|
||||
|
||||
InputStream in = GeckoJarReader.getStream(url);
|
||||
if (in != null) {
|
||||
|
@ -583,7 +578,7 @@ public class SearchEngineManager implements SharedPreferences.OnSharedPreference
|
|||
// If that doesn't work, try a file path for just the language.
|
||||
final String language = Locales.getLanguage(locale);
|
||||
if (!languageTag.equals(language)) {
|
||||
url = getSearchPluginsJarURL(language, fileName);
|
||||
url = getSearchPluginsJarURL(context, language, fileName);
|
||||
in = GeckoJarReader.getStream(url);
|
||||
if (in != null) {
|
||||
return in;
|
||||
|
@ -591,7 +586,7 @@ public class SearchEngineManager implements SharedPreferences.OnSharedPreference
|
|||
}
|
||||
|
||||
// Finally, fall back to default locale defined in chrome registry.
|
||||
url = getSearchPluginsJarURL(getFallbackLocale(), fileName);
|
||||
url = getSearchPluginsJarURL(context, getFallbackLocale(), fileName);
|
||||
return GeckoJarReader.getStream(url);
|
||||
}
|
||||
|
||||
|
@ -606,7 +601,7 @@ public class SearchEngineManager implements SharedPreferences.OnSharedPreference
|
|||
return fallbackLocale;
|
||||
}
|
||||
|
||||
final InputStream in = GeckoJarReader.getStream(getJarURL("!/chrome/chrome.manifest"));
|
||||
final InputStream in = GeckoJarReader.getStream(GeckoJarReader.getJarURL(context, "chrome/chrome.manifest"));
|
||||
final BufferedReader br = getBufferedReader(in);
|
||||
|
||||
try {
|
||||
|
@ -638,13 +633,9 @@ public class SearchEngineManager implements SharedPreferences.OnSharedPreference
|
|||
* @param fileName The name of the file to read.
|
||||
* @return URL for jar file.
|
||||
*/
|
||||
private String getSearchPluginsJarURL(String locale, String fileName) {
|
||||
final String path = "!/chrome/" + locale + "/locale/" + locale + "/browser/searchplugins/" + fileName;
|
||||
return getJarURL(path);
|
||||
}
|
||||
|
||||
private String getJarURL(String path) {
|
||||
return "jar:jar:file://" + context.getPackageResourcePath() + "!/" + AppConstants.OMNIJAR_NAME + path;
|
||||
private static String getSearchPluginsJarURL(Context context, String locale, String fileName) {
|
||||
final String path = "chrome/" + locale + "/locale/" + locale + "/browser/searchplugins/" + fileName;
|
||||
return GeckoJarReader.getJarURL(context, path);
|
||||
}
|
||||
|
||||
private BufferedReader getBufferedReader(InputStream in) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM quay.io/mozilla/builder:0.0.29
|
||||
FROM quay.io/mozilla/builder:0.2.6
|
||||
MAINTAINER Wander Lairson Costa <wcosta@mozilla.com>
|
||||
|
||||
# Add utilities and configuration
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.0.7
|
||||
0.0.8
|
||||
|
|
|
@ -29,6 +29,8 @@ if [ ! -d $OBJDIR ]; then
|
|||
mkdir -p $OBJDIR
|
||||
fi
|
||||
|
||||
# Figure out where the remote manifest is so we can use caches for it.
|
||||
MANIFEST=$(repository-url.py $GECKO_HEAD_REPOSITORY $GECKO_HEAD_REV b2g/config/$TARGET/sources.xml)
|
||||
tc-vcs repo-checkout $OBJDIR/B2G https://git.mozilla.org/b2g/B2G.git $MANIFEST
|
||||
|
||||
debug_flag=""
|
||||
|
|
|
@ -315,6 +315,10 @@ class Graph(object):
|
|||
test_parameters['total_chunks'] = test['chunks']
|
||||
|
||||
for chunk in range(1, test_parameters['total_chunks'] + 1):
|
||||
if 'only_chunks' in test and \
|
||||
chunk not in test['only_chunks']:
|
||||
continue;
|
||||
|
||||
test_parameters['chunk'] = chunk
|
||||
test_task = templates.load(test['task'], test_parameters)
|
||||
test_task['taskId'] = slugid()
|
||||
|
|
|
@ -3,13 +3,15 @@
|
|||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
import shlex
|
||||
import argparse
|
||||
import functools
|
||||
import copy
|
||||
import functools
|
||||
import re
|
||||
import shlex
|
||||
from try_test_parser import parse_test_opts
|
||||
|
||||
TRY_DELIMITER='try:'
|
||||
TRY_DELIMITER = 'try:'
|
||||
TEST_CHUNK_SUFFIX = re.compile('(.*)-([0-9]+)$')
|
||||
|
||||
# The build type aliases are very cryptic and only used in try flags these are
|
||||
# mappings from the single char alias to a longer more recognizable form.
|
||||
|
@ -59,9 +61,41 @@ def normalize_test_list(all_tests, job_list):
|
|||
if 'platforms' in all_entry:
|
||||
entry['platforms'] = list(all_entry['platforms'])
|
||||
results.append(entry)
|
||||
return results
|
||||
return parse_test_chunks(results)
|
||||
else:
|
||||
return tests
|
||||
return parse_test_chunks(tests)
|
||||
|
||||
def parse_test_chunks(tests):
|
||||
'''
|
||||
Test flags may include parameters to narrow down the number of chunks in a
|
||||
given push. We don't model 1 chunk = 1 job in taskcluster so we must check
|
||||
each test flag to see if it is actually specifying a chunk.
|
||||
|
||||
:param list tests: Result from normalize_test_list
|
||||
:returns: List of jobs
|
||||
'''
|
||||
|
||||
results = []
|
||||
seen_chunks = {}
|
||||
for test in tests:
|
||||
matches = TEST_CHUNK_SUFFIX.match(test['test'])
|
||||
|
||||
if not matches:
|
||||
results.append(test)
|
||||
continue
|
||||
|
||||
name = matches.group(1)
|
||||
chunk = int(matches.group(2))
|
||||
|
||||
if name in seen_chunks:
|
||||
seen_chunks[name].add(chunk)
|
||||
else:
|
||||
seen_chunks[name] = set([chunk])
|
||||
test['test'] = name
|
||||
test['only_chunks'] = seen_chunks[name]
|
||||
results.append(test)
|
||||
|
||||
return results;
|
||||
|
||||
def extract_tests_from_platform(test_jobs, build_platform, build_task, tests):
|
||||
'''
|
||||
|
@ -104,7 +138,18 @@ def extract_tests_from_platform(test_jobs, build_platform, build_task, tests):
|
|||
|
||||
# Add the job to the list and ensure to copy it so we don't accidentally
|
||||
# mutate the state of the test job in the future...
|
||||
results.append(copy.deepcopy(test_job))
|
||||
specific_test_job = copy.deepcopy(test_job)
|
||||
|
||||
# Update the task configuration for all tests in the matrix...
|
||||
for build_name in specific_test_job:
|
||||
for test_task_name in specific_test_job[build_name]:
|
||||
test_task = specific_test_job[build_name][test_task_name]
|
||||
# Copy over the chunk restrictions if given...
|
||||
if 'only_chunks' in test_entry:
|
||||
test_task['only_chunks'] = \
|
||||
copy.copy(test_entry['only_chunks'])
|
||||
|
||||
results.append(specific_test_job)
|
||||
|
||||
return results
|
||||
|
||||
|
|
|
@ -343,6 +343,62 @@ class TestCommitParser(unittest.TestCase):
|
|||
result = parse_commit(commit, jobs)
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_specific_chunks(self):
|
||||
'''
|
||||
This test covers specifying specific chunks for a given test suite.
|
||||
'''
|
||||
commit = 'try: -b o -p linux -u mochitest-1,mochitest-2 -t none'
|
||||
jobs = {
|
||||
'flags': {
|
||||
'builds': ['linux'],
|
||||
'tests': ['mochitest'],
|
||||
},
|
||||
'builds': {
|
||||
'linux': {
|
||||
'types': {
|
||||
'opt': {
|
||||
'task': 'task/linux',
|
||||
},
|
||||
'debug': {
|
||||
'task': 'task/linux-debug'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
'tests': {
|
||||
'mochitest': {
|
||||
'allowed_build_tasks': {
|
||||
'task/linux': {
|
||||
'task': 'task/mochitest',
|
||||
'chunks': 5
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expected = [
|
||||
{
|
||||
'task': 'task/linux',
|
||||
'dependents': [
|
||||
{
|
||||
'allowed_build_tasks': {
|
||||
'task/linux': {
|
||||
'task': 'task/mochitest',
|
||||
'chunks': 5,
|
||||
'only_chunks': set([1, 2])
|
||||
},
|
||||
}
|
||||
}
|
||||
],
|
||||
'additional-parameters': {}
|
||||
}
|
||||
]
|
||||
result = parse_commit(commit, jobs)
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
|
||||
|
||||
def test_commit_with_builds_and_tests(self):
|
||||
'''
|
||||
This test covers the broad case of a commit which has both builds and
|
||||
|
|
|
@ -950,9 +950,12 @@ nsBaseWidget::DispatchEventForAPZ(WidgetGUIEvent* aEvent,
|
|||
= &APZCTreeManager::SetTargetAPZC;
|
||||
APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
|
||||
mAPZC.get(), setTargetApzcFunc, aInputBlockId, aGuid));
|
||||
bool defaultPrevented = aEvent->AsTouchEvent()
|
||||
? (nsIPresShell::gPreventMouseEvents || aEvent->mFlags.mMultipleActionsPrevented)
|
||||
: aEvent->mFlags.mDefaultPrevented;
|
||||
APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
|
||||
mAPZC.get(), &APZCTreeManager::ContentReceivedInputBlock, aInputBlockId,
|
||||
aEvent->mFlags.mDefaultPrevented));
|
||||
defaultPrevented));
|
||||
}
|
||||
|
||||
return status;
|
||||
|
|
Загрузка…
Ссылка в новой задаче